import numpy
import types
from abc import ABCMeta, abstractmethod
from bisect import bisect_left
from collections import Counter
from pandas import DataFrame
from .core import check

class FeaturesHandler(object):
    __metaclass__ = ABCMeta

    def __init__(self, in_feature_names):
        self.in_feature_names = in_feature_names
        self.out_feature_names = None

    def size(self):
        return len(self.out_feature_names)

    @abstractmethod
    def apply(self, input_generator):
        """
        :param input_generator: sequence of feature values corresponding to in_feature_names
        :return sequence of (index,value)
        """
        return enumerate(input_generator)

    def learn(self, df):
        """
        Train the handler from data
        :param df: data frame
        """
        assert isinstance(df, DataFrame)

class NoHandler(FeaturesHandler):
    def __init__(self, in_feature_names):
        super(NoHandler, self).__init__(in_feature_names)
        self.out_feature_names = in_feature_names

    def apply(self, input_generator):
        return enumerate(input_generator)

class BoolHandler(NoHandler):
    """
    This is nothing but a NoHandler with a different name
    """

# Mapper handler maps input features to output features via a function (e.g. a lambda)
class MapperHandler(FeaturesHandler):
    def __init__(self, in_feature_names, out_feature_names, mapper):
        """
        :param in_feature_names: list of input feature names
        :param out_feature_names: list of output feature names
        :param mapper: a function that takes a list and return another list
        """
        super(self.__class__, self).__init__(in_feature_names)
        self.out_feature_names = out_feature_names
        self._mapper = mapper

    def apply(self, input_generator):
        return enumerate(self._mapper(list(input_generator)))

class OneToOneMapperHandler(FeaturesHandler):
    def __init__(self, in_feature_name, out_feature_name, mapper):
        self.in_feature_names = [in_feature_name]
        self.out_feature_names = [out_feature_name]
        self._mapper = mapper

    def apply(self, input_generator):
        yield 0, self._mapper(input_generator.next())

class OneHotHandler(FeaturesHandler):
    def __init__(self, in_feature_names, cats={}, preprocessor=None):
        for in_feature_name in cats:
            if in_feature_name not in in_feature_names:
                raise ValueError('cats contains keys ({0}) not in feature names'.format(in_feature_name))
        super(self.__class__, self).__init__(in_feature_names)

        maps = [None] * len(in_feature_names)
        count = 0  # total number of unique values
        out_feature_names = []
        for in_feature_name in cats:
            _map = {}
            for value in cats[in_feature_name]:
                _map[value] = count
                out_feature_names.append(in_feature_name + '=' + str(value))
                count += 1
            maps[in_feature_names.index(in_feature_name)] = _map

        self.out_feature_names = out_feature_names
        self._maps = maps
        self._count = count
        self._preprocessor = lambda x: x if preprocessor is None else preprocessor

    def learn(self, df):
        maps = self._maps
        preprocessor = self._preprocessor
        out_feature_names = self.out_feature_names
        for i, in_feature_name in enumerate(self.in_feature_names):
            if maps[i] is not None:
                continue
            _map = {}
            for value in df[in_feature_name]:
                value = preprocessor(value)
                if value not in _map:
                    _map[value] = self._count
                    out_feature_names.append(in_feature_name + '=' + str(value))
                    self._count += 1
            maps[i] = _map

    def apply(self, input_generator):
        preprocessor = self._preprocessor
        for i, value in enumerate(input_generator):
            index = self._maps[i].get(preprocessor(value))
            if index is not None:
                yield index, 1

class BinNormalizer(FeaturesHandler):
    def __init__(self, in_feature_names, n_bins=32, thresholds_groups=None):
        """
        :param in_feature_names: names of input features
        :param n_bins: number of bins for each input feature
            A small number of bins (10-20) is typically sufficient for tree learners.
            For other learners (e.g. linear or NN), use a larger number of bins (100-1000).
        :param thresholds_groups: thresholds for each group
            If provided, n_bins will be ignored.
        """
        super(self.__class__, self).__init__(in_feature_names)
        self.out_feature_names = [name + '_bin' for name in in_feature_names]
        check(thresholds_groups is None
              or (len(thresholds_groups) == len(in_feature_names) and n_bins > 1))
        self._threshold_groups = thresholds_groups
        self._n_bins = n_bins

    def learn(self, df):
        if self._threshold_groups is not None:
            return

        self._threshold_groups = []
        for col in self.in_feature_names:
            f_values = df[col].dropna()
            assert numpy.issubdtype(f_values, numpy.number)
            histogram = sorted(Counter(f_values).items())
            if len(histogram) <= self._n_bins:
                self._threshold_groups.append(None)
                continue

            thresholds = []
            n_bins = self._n_bins
            n_items = float(len(f_values))
            ih = 0
            ih_lim = len(histogram)
            while n_bins > 1:
                expected_bin_size = n_items / n_bins
                count = 0
                while count < expected_bin_size:
                    count += histogram[ih][1]
                    ih += 1
                last_addition = histogram[ih-1][1]
                if count - expected_bin_size > expected_bin_size - (count - last_addition) \
                        and count != last_addition:
                    ih -= 1
                    count -= last_addition
                if ih == ih_lim:  # reaching the end before fulfilling the number of bins
                    break
                thresholds.append((histogram[ih-1][0] + histogram[ih][0])/2)
                n_items -= count
                n_bins -= 1
            self._threshold_groups.append(thresholds)

    def apply(self, input_generator):
        for i, value in enumerate(input_generator):
            thresholds = self._threshold_groups[i]
            yield i, (bisect_left(thresholds, value) if thresholds else value)

class MinMaxNormalizer(FeaturesHandler):
    def __init__(self, in_feature_names):
        super(MinMaxNormalizer, self).__init__(in_feature_names)
        raise RuntimeError('Not yet implemented')

    def learn(self, df):
        pass

    def apply(self, input_generator):
        pass

class PredicatesHandler(FeaturesHandler):
    """
    The predicates handler computes predicate features
    Those predicates are defined as normal functions in a module
    For each predicate:
        - The function name is treated as output feature name
        - The function argument variables are treated as input feature names
    """

    def __init__(self, module):
        predicates = []
        features_set = set()
        out_feature_names = []
        for f in dir(module):
            if (not isinstance(module.__dict__.get(f), types.FunctionType)) or f.startswith('_'):
                continue  # filter out elements that are not public functions
            predicate = module.__dict__.get(f)
            predicates.append(predicate)
            out_feature_names.append(f)
            features_set |= set(predicate.func_code.co_varnames)
        in_feature_names = list(features_set)
        name_to_idx = {name: idx for idx, name in enumerate(in_feature_names)}
        self._indices = [[name_to_idx[name] for name in predicate.func_code.co_varnames]
                         for predicate in predicates]
        self._predicates = predicates
        self.in_feature_names = in_feature_names
        self.out_feature_names = out_feature_names

    def apply(self, input_generator):
        values = list(input_generator)
        indices = self._indices
        return enumerate(predicate(*[values[j] for j in indices[i]])
                         for i, predicate in enumerate(self._predicates))

class IdEncodingHandler(FeaturesHandler):
    def __init__(self, in_feature_names, preprocessor=None):
        super(self.__class__, self).__init__(in_feature_names)

        maps = [None] * len(in_feature_names)
        self.out_feature_names = [name + '_ide' for name in in_feature_names]
        self._maps = maps
        self._count = 0
        self._preprocessor = lambda x: x if preprocessor is None else preprocessor

    def learn(self, df):
        maps = self._maps
        preprocessor = self._preprocessor
        for i, in_feature_name in enumerate(self.in_feature_names):
            if maps[i] is not None:
                continue
            _map = {}
            count = 0
            for value in df[in_feature_name]:
                value = preprocessor(value)
                if value not in _map:
                    _map[value] = count # self._count
                    count += 1
            maps[i] = _map

    def apply(self, input_generator):
        preprocessor = self._preprocessor
        for i, value in enumerate(input_generator):
            index = self._maps[i].get(preprocessor(value))
            if index is not None:
                yield i, index

"""
class IdEncodingHandler(FeaturesHandler):
    def __init__(self, in_feature_names, preprocessor=None):
        super(self.__class__, self).__init__(in_feature_names)
        maps = {}
        self.out_feature_names = [name + '_ide' for name in in_feature_names]
        self._maps = maps
        self._count = 0
        self._preprocessor = lambda x: x if preprocessor is None else preprocessor

    def learn(self, df):
        maps = self._maps
        preprocessor = self._preprocessor
        for i, in_feature_name in enumerate(self.in_feature_names):
            _map = {}
            for value in df[in_feature_name]:
                value = preprocessor(value)
                if value not in _map:
                    _map[value] = self._count
                    # out_feature_names.append(in_feature_name + '=' + str(value))
                    self._count += 1
            # maps[i] = _map
            maps[in_feature_name] = _map

    def apply(self, input_generator):
        preprocessor = self._preprocessor
        for i, value in enumerate(input_generator):
            col, val = value
            index = self._maps[col].get(preprocessor(val))
            if index is not None:
                yield i, index
"""


#%%
from tkinter import *
from tkinter.filedialog import askopenfile, asksaveasfile

from minisom import MiniSom
import numpy as np
from distinctipy import distinctipy

from PIL import Image, ImageTk

def get_image_features(image):
  """
    Devuelve un vector de dimensión 1 por cada banda (cuya longitud = alto x ancho)
    Cada posición tiene la intensidad de un píxel en una banda determinada, normalizada.
  """
  features = image.reshape((-1, image.shape[2]))
  return (features - np.mean(features, axis = 0)) / np.std(features, axis = 0)

def segment_image(image, labels, bit_depth = 8):
  """
    Función para segmentar una imágen dado una lista con labels por píxel.
    image: Imágen a segmentar.
    labels: Lista de labels por cada píxel.
    bit_depth: Profundidad de la imágen en bits.
  """
  n_clusters = len(np.unique(labels)) # El número de clusters es la cantidad de labels distintos.
  max_value = 2 ** bit_depth - 1 # Valor de intensidad máximo de la imágen según profundidad de bits

  # Obtengo una lista de colores al azar únicos y diferenciados rgb utilizando distinctipy, uno por cada cluster
  colors = (np.array(distinctipy.get_colors(n_clusters)) * max_value).astype(f"uint{bit_depth}")

  # Creo una matriz de resultados
  segmented = np.zeros((image.shape[0], image.shape[1], colors.shape[1]))
  # Reshape para que los labels tengan la forma de la imágen original
  labels = labels.reshape((image.shape[0], image.shape[1]))
  # Por cada píxel reemplazo el label por el color correspondiente para la clase obtenido de la lista colors.
  for i in range(labels.shape[0]):
    for j in range(labels.shape[1]):
      segmented[i, j] = colors[labels[i,j]]

  # Casteo imágen segmentada a uint segun profundidad de bits
  return segmented.astype(f"uint{bit_depth}")

def som_predict(som, features):
  """
    Devuelve los labels para cada feature realizando una predicción con una som entrenada, es decir, el número de cluster por cada fila.
    som: La red de Kohonen entrenada a usar.
    features: El vector de features a etiquetar.
  """
  winners = np.array([som.winner(f) for f in features]) # Obtengo coordenadas de la neurona ganadora por fila
  # Obtengo un diccionario de coordenada de neurona - clase, utilizando enumerate sobre las coordenadas posibles.
  winners_values = dict((tuple(k),v) for v,k in enumerate(np.unique(winners, axis=0)))
  # Por cada coordenada ganadora devuelvo la clase (label)
  return np.array([winners_values[tuple(w)] for w in winners])

def kohonen(image, n, m, sigma=1, learning_rate=.5, num_iterations=1000):
  """
    Entrena una red de Kohonen de n x m sobre una imágen y la segmenta segun los clusters encontrados.
    Muestra y grafica la matríz U de la red resultante.

    image: Imágen a segmentar mediante Kohonen.
    n: Cantidad de filas de la red de Kohonen.
    m: Cantidad de columnas de la red de Kohonen.
    sigma: Radio de vecindad inicial.
    learning_rate: Ratio inicial de aprendizaje. Determina cuan rápido se actualizan los pesos. A menor learning_rate, la magnitud de actualización de pesos en cada iteración es menor.
    num_iterations: Número máximo de iteraciones en caso de no llegar a una convergencia.
  """

  # Obtengo los features
  features = get_image_features(image)

  # Creo la red SOM y la entreno con los features
  som = MiniSom(n, m, features.shape[1], sigma=sigma, learning_rate=learning_rate, activation_distance='euclidean',
              topology='rectangular', neighborhood_function='gaussian', random_seed=8)
  som.train(features, num_iterations, verbose=True)

  # Obtengo los labels
  labels = som_predict(som, features)

  # Devuelvo la imágen segmentada
  return segment_image(image, labels)

class Interface():
    """
        Ésta clase se encarga de construir la interfaz de la aplicación y
        manejar los eventos producidos al interactuar con ella.
    """

    def __init__(self):
        """
            Crea e inicializa la ventana y los elementos de la aplicación.
        """
        self.bg = "#99CCFF" # Color de fondo de toda la app

        self.interface = Tk()
        self.interface.title("Trabajo Práctico N1: Rodrigo Fondato")
        self.interface.configure(bg=self.bg)
        self.image = None
        self.image_path = None
        self.original_image = None
        self._create_elements()

    def _create_elements(self):
        """
            Crea los elementos visuales de la aplicación
        """
        # Título principal
        self.title_lbl = Label(self.interface, bg=self.bg, font=("Arial", 25), text="Segmentación por Kohonen")
        self.title_lbl.pack(pady=10)

        # Etiqueta de estado: Inicialmente vacía
        self.status_lbl = Label(self.interface, bg=self.bg, fg="red", font=("Arial", 14))
        self.status_lbl.pack(pady=5)

        self._create_img_container()
        self._create_parameters()
        self._create_buttons()

    def _create_img_container(self):
        """
            Crea el marco para contener imágenes a segmentar
        """
        # Marco con bordes para contener la imágen
        self.img_container_frame = Frame(self.interface, bg=self.bg, relief="groove", borderwidth=2)
        # El contenedor de la imágen es un label que inicialmente tiene el texto "NO HAY IMAGEN"
        self.img_container = Label(self.img_container_frame,
                                   bg=self.bg,
                                   text="NO HAY IMAGEN",
                                   padx=50,
                                   pady=50)
        self.img_container.pack()
        self.img_container_frame.pack(pady=10)

    def _create_parameters(self):
        """
            Crea la sección de parámetros para configurar la red de Kohonen.
        """
        # Marco para contener a los parámetros
        self.parameters_frame = Frame(self.interface, bg=self.bg)

        # Los parámetros se configurarán en una grilla horizontal (1 row, múltiples columnas)

        # Label para el parámetro Ancho SOM
        self.grid_x_lbl = Label(self.parameters_frame, bg=self.bg, text="Ancho SOM: ")
        self.grid_x_lbl.grid(row=0, column=0, padx=10)

        # Slider para Ancho SOM, inicializado en 1. Admite valores de 1 a 5.
        self.grid_x = Scale(self.parameters_frame, from_=1, to=5, orient=HORIZONTAL, bg=self.bg)
        self.grid_x.set(1)
        self.grid_x.grid(row=0, column=1, padx=10)

        # Label para el parámetro Alto SOM
        self.grid_y_lbl = Label(self.parameters_frame, bg=self.bg, text="Alto SOM: ")
        self.grid_y_lbl.grid(row=0, column=2, padx=10)

        # Slider para Alto SOM, inicializado en 1. Admite valores de 1 a 5.
        self.grid_y = Scale(self.parameters_frame, from_=1, to=5, orient=HORIZONTAL, bg=self.bg)
        self.grid_y.set(1)
        self.grid_y.grid(row=0, column=3, padx=10)

        self.parameters_frame.pack(pady=10)

    def _create_buttons(self):
        """
            Crea la botonera con todas las acciones posibles: Abrir, Segmentar, Restaurar y Grabar.
        """

        # Marco para la botonera
        self.buttons_frame = Frame(self.interface, bg=self.bg)

        # Los botones se configurarán en una grilla horizontal (1 row, múltiples columnas)

        # Botón de abrir archivo
        self.open_btn = Button(self.buttons_frame, text="Abrir", command=self._open_file)
        self.open_btn.grid(row=0, column=0, padx=10)

        # Botón de segmentar imágen
        self.segment_btn = Button(self.buttons_frame, text="Segmentar", command=self._segment)
        self.segment_btn.grid(row=0, column=1, padx=10)

        # Botón de recuperar imágen
        self.restore_btn = Button(self.buttons_frame, text="Restaurar", command=self._restore)
        self.restore_btn.grid(row=0, column=2, padx=10)

        # Botón de grabar imágen
        self.save_btn = Button(self.buttons_frame, text="Grabar", command=self._save)
        self.save_btn.grid(row=0, column=3, padx=10)

        self.buttons_frame.pack(pady=10)

    def _open_file(self):
        """
            Ejecuta el comando de abrir imágen. Muestra un diálogo donde el usuario debe elegir un archivo de imágen
            a abrir. Si no elige ninguno muestra un mensaje de estado de "Ninguna imágen fue seleccionada"
            Si elige una imágen válida, la misma es cargada en el contenedor de imágenes en pantalla.
        """
        try:
            # Abre diálogo y obtiene un archivo a cargar
            file = askopenfile(mode ='r', filetypes =[('Image Files', ['*.png', '*.jpg', '*.jpeg', '*.tiff', '*.bmp'])])
            if file is not None:
                # Si el usuario eligió un archivo válido carga la imágen y la dibuja
                self.image_path = file.name
                self.image = Image.open(file.name)
                self.original_image = self.image.copy()
                self._draw_image()
                self.status_lbl.config(text="") # Vacía el mensaje de estado
                file.close()
            else: # Sino muestra un mensaje que informa que nada fue seleccionado
                self.status_lbl.config(text="Ninguna imágen fue seleccionada")
        except Exception as e:
            # Si hay un error imprime el mensaje por consola y actualiza el estado
            print(e)
            self.status_lbl.config(text="Hubo un error al abrir la imágen")

    def _segment(self):
        """
            Ejecuta el comando de segmentar la imágen elegida.
            Valida que haya una imágen o arroja un error en la barra de estado.
            Segmenta la imágen utiizando la red de Kohonen con los parámetros elegidos.
            Dibuja la imágen segmentada.
        """
        # Si la validacion falla, no hace nada
        if not self._validate():
           return

        # Actualiza el estado con el mensaje que indica que está procesando
        self.status_lbl.config(text=f"Segmentando utilizando Kohonen ({self.grid_x.get()}x{self.grid_y.get()}), por favor aguardar...")
        self.interface.update() # Para forzar un refresh de la pantalla
        # Realiza la segmentación con la red de Kohonen
        segmented = kohonen(image=np.array(self.original_image), n=self.grid_x.get(), m=self.grid_y.get())
        # Convierte el array segmentado en una imágen y la dibuja en la app
        self.image = Image.fromarray(segmented)
        self._draw_image()
        # Informa que la imágen ya fue segmentada
        self.status_lbl.config(text="Imágen Segmentada")

    def _validate(self):
        """
            Si no hay ninguna imágen seleccionada pide al usuario que lo haga,
            utilizando la barra de estado.
        """
        if self.image is None:
           self.status_lbl.config(text="Por favor elija una imágen antes de segmentar")
           return False

        return True

    def _draw_image(self):
        """
            Dibuja una imágen en el contenedor de imágenes (UI)
            Si la imágen tiene un alto mayor a 600 píxeles, la reduce para que tenga como máximo ese alto,
            modificando en la misma proporción el ancho.
        """
        im = self.image
        # Como máximo admitir 600px de alto y sino hacer un resize manteniendo proporciones.
        if im.size[1] > 600:
           proportion = im.size[0] / im.size[1]
           im = self.image.resize((int(proportion * 600), 600))

        # Convertir a una imágen de TK, y actualizar el label de img_container poniendo la imágen.
        ph = ImageTk.PhotoImage(im)
        self.img_container.config(image=ph, text=None, padx=0, pady=0)
        self.img_container.image = ph # Para mantener la referencia a ph

    def _restore(self):
       """
            Recupera la imágen original, descartando la segmentada.
            Si ninguna imágen fue seleccionada, no hace nada.
       """
       if self.original_image is None:
          return

       # Utiliza la referencia a la imágen original para recuperarla.
       self.image = self.original_image.copy()
       self._draw_image()
       self.status_lbl.config(text="Imágen Restaurada") # Actualiza la barra de estado

    def _save(self):
       """
            Ejecuta el comando de grabar una imágen. Muestra un cuadro de diálogo donde el usuario puede elegir
            el archivo destino y luego graba la imágen actualmente mostrada en la UI en disco.
            Si ninguna imágen fue seleccionada, no hace nada.
       """
       if self.image is None:
          return

       try:
          # Abre diálogo y obtiene un archivo en modo escritura para grabar la imágen
          file = asksaveasfile(mode='w', filetypes =[('Image Files', ['*.png', '*.jpg', '*.jpeg', '*.tiff', '*.bmp'])], defaultextension='*.png')

          if file is not None:
            # Si el usuario eligió un path válido, escribe el archivo con la imágen actual
            self.image.save(file.name)
            file.close() # Cierra el archivo
            self.status_lbl.config(text="Imágen grabada") # Actualiza el estado
       except Exception as e: # Si hay un error imprimo el mismo por consola y actualizo el estado
          print(e)
          self.status_lbl.config(text="Hubo un error al grabar la imágen")

    def start(self):
        """
            Inicia la aplicación. Muestra la interfaz.
        """
        self.interface.mainloop()

#  Creo la interfaz gráfica y la inicio.
interface = Interface()
interface.start()

# %%


import time
from tkinter import *
from tkinter import filedialog
from tkinter import ttk
from tkinter.ttk import Progressbar
import numpy as np
import trimesh
import os
from tkinter import messagebox
from PIL import Image, ImageTk

root=Tk()
root.title("STL Maker")
root.geometry("450x550")
root.resizable(False,False)
root.config(bg='#f4fdfe')#82ccdd
photo=PhotoImage(file='images/stllogo.png')
root.iconphoto(False,photo)

Label1=Label(root, text="Convert STEP, IGS ,BREP ,Nastran ,Abaqus 3D Model into STL Model", font="New 10 bold", bg="#f4fdfe")
Label1.grid(row=1, column=0,pady=20)
label2=Label(root, text='Browse 3D Model',font="Ariel 10 bold",bg='#f4fdfe')
label2.grid(row=4,column=0)
label2=Label(root, text='Convert To STL',font="Ariel 10 bold",bg='#f4fdfe')
label2.grid(row=7,column=0)
Browse_entry=Entry(root,font="Ariel 15 bold",bg='white')
Browse_entry.grid(row=2,column=0,columnspan=3, pady=10)

def loadfile():

    global openfile

    openfile=filedialog.askopenfilename(initialdir="os.getcwd()",title="Please Select Model", filetypes=[("IGS",".igs"),("STEP",".STEP"),("BREP",".brep"),("Nastran",".bdf"),("Gmsh",".msh"),("Abaqus",".inp"),("Diffpack ",".diff"),("Inria Medit",".mesh"),("All Files","*.*")])

    if openfile:
        global Browse_entry
        try:
            Browse_entry.insert(0,openfile)
            messagebox.showinfo("Imported","File is imported Successfully, Now Click on Convert")
        except:
            messagebox.showinfo('Select 3D Model','3D Model is not selected')
    else:
        Browse_entry.delete(0,END)
def convert():
    global openfile
    global mesh
    global exportfile

    exportfile=filedialog.asksaveasfile(initialdir="os.getcwd()",defaultextension=".stl", title="Save As")

    if exportfile:
        try:
            global Browse_entry
            for i in range(5):
                root.update_idletasks()
                Progressbar1['value'] += 20
                time.sleep(1)
            mesh = trimesh.Trimesh(**trimesh.interfaces.gmsh.load_gmsh(file_name=openfile, gmsh_args = [
                ("Mesh.Algorithm", 1), #Different algorithm types, check them out
                ("Mesh.CharacteristicLengthFromCurvature", 50), #Tuning the smoothness, + smothness = + time
                ("General.NumThreads", 20), #Multithreading capability
                ("Mesh.MinimumCirclePoints", 74)]))
            mesh.export(exportfile.name)
            messagebox.showinfo("Success","File is Successfully Converted and Saved into\n"+str(exportfile.name))
            Browse_entry.delete(0,END)
            Progressbar1.stop()
        except:
            messagebox.showinfo('Alert','unexpected things happened Please follow the sequence')
            Progressbar1.stop()
def quit():
    root.quit()

def help():
    messagebox.showinfo('help','Step(1) Browse, Step(2) Convert and Enjoy')

def thanks():
    messagebox.showinfo('Thanks',"This Version v1.0 of This Tool is Under Construction Thanks For Using STL Maker")

Progressbar1=ttk.Progressbar(root,orient=HORIZONTAL,length=300,mode="determinate")
Progressbar1.grid(row=8,column=0,pady=20)

img1= (Image.open("images/browse.png"))
resized_image1= img1.resize((120,100))
new_image1= ImageTk.PhotoImage(resized_image1)

img2= (Image.open("images/convert.png"))
resized_image2= img2.resize((120,100))
new_image2= ImageTk.PhotoImage(resized_image2)

filebrowse=Button(root,image=new_image1,command=loadfile,font="Ariel 10 bold", pady=10)
filebrowse.grid(row=3, column=0, pady=10)
fileconvert=Button(root, image=new_image2, command=convert,font="Ariel 10 bold",pady=10)
fileconvert.grid(row=6, column=0, pady=10)
fileexit=Button(root, text="Close", command=quit ,font="Ariel 10 bold", padx=38, pady=10)
fileexit.grid(row=9, column=0, pady=10)

submenu=Menu(root)
m1=Menu(submenu,tearoff=0)
m1.add_command(label='Browse',command=loadfile)
m1.add_command(label='Convert',command=convert)
m1.add_command(label='Exit',command=quit)
root.config(menu=submenu)
submenu.add_cascade(label='File',menu=m1)
submenu.add_cascade(label='Help',command=help)
submenu.add_cascade(label='About',command=thanks)

root.mainloop()


"""
A module implementing this package's stateful information that persists across
invocations.
"""

# built-in
from contextlib import ExitStack, contextmanager
from io import StringIO
from logging import getLogger
from pathlib import Path
from typing import Any, Dict, Iterator, List, cast

# third-party
from jinja2 import Template
from vcorelib.dict import merge
from vcorelib.dict.cache import FileCache
from vcorelib.io import ARBITER
from vcorelib.io.types import DataStream
from vcorelib.io.types import JsonObject as _JsonObject
from vcorelib.paths import Pathlike, normalize, rel

# internal
from rcmpy.paths import default_config_directory, default_state_directory
from rcmpy.schemas import RcmpyDictCodec as _RcmpyDictCodec

LOG = getLogger(__name__)

class State(_RcmpyDictCodec):
    """The top-level configuration object for the package."""

    directory: Path
    variant: str
    variables_new: bool
    configs_new: bool
    manifest: Dict[str, Any]
    manifest_new: bool

    def init(self, data: _JsonObject) -> None:
        """Perform implementation-specific initialization."""

        self.logger = LOG

        self.directory = normalize(
            cast(str, data.get("directory", default_config_directory()))
        ).resolve()

        self.logger.info("Using directory '%s'.", rel(self.directory))

        self.variant: str = cast(str, data["variant"])
        if self.variant:
            self.logger.info("Using variant '%s'.", self.variant)

        data.setdefault("previous", {})
        self.previous: Dict[str, Any] = data["previous"]  # type: ignore
        self.previous.setdefault("variant", "default")

        # Variables.
        self.variables: Dict[str, Any] = {}
        self.variables_new = False
        self.previous.setdefault("variables", {})
        self._load_variables()

        # Configs.
        self.configs: Dict[str, Any] = {}
        self.configs_new = False
        self.previous.setdefault("configs", {})
        self._load_configs()

        # Manifest configuration.
        self.manifest: Dict[str, Any] = cast(
            Dict[str, Any], data.get("manifest", {})
        )
        self.manifest_new: bool = False

    def is_new(self) -> bool:
        """Determine if state has changed."""
        return (
            self.variant != self.previous["variant"]
            or self.variables_new
            or self.configs_new
            or self.manifest_new
        )

    def update_manifest(self, data: Dict[str, Any]) -> None:
        """Set new manifest data."""
        self.manifest_new = self.manifest != data
        self.manifest = data

    def root_directories(
        self, subdir: str, common_first: bool = True
    ) -> List[Path]:
        """
        Get up to a pair of directories from some sub-directory of the current
        root.
        """

        root = self.directory.joinpath(subdir)

        candidates = [root.joinpath("common")]
        if self.variant:
            if common_first:
                candidates.append(root.joinpath(self.variant))
            else:
                candidates.insert(0, root.joinpath(self.variant))

        return [x for x in candidates if x.is_dir()]

    def _load_configs(self) -> None:
        """Load data for configs."""

        with ExitStack() as stack:

            def preprocessor(stream: DataStream) -> DataStream:
                """Render the variable file as a template."""

                return stack.enter_context(
                    StringIO(Template(stream.read()).render(self.variables))
                )

            for path in self.root_directories("configs"):
                merge(
                    self.configs,
                    ARBITER.decode_directory(
                        path,
                        logger=self.logger,
                        require_success=True,
                        recurse=True,
                        includes_key="includes",
                        expect_overwrite=True,
                        preprocessor=preprocessor,
                    ).data,
                    expect_overwrite=True,
                    logger=self.logger,
                )

        self.configs_new = self.configs != self.previous["configs"]
        self.previous["configs"] = self.configs

        if self.configs_new:
            self.logger.info("Configuration data is updated.")

    def _load_variables(self) -> None:
        """Load data for variables."""

        for path in self.root_directories("variables"):
            merge(
                self.variables,
                ARBITER.decode_directory(
                    path,
                    logger=self.logger,
                    require_success=True,
                    recurse=True,
                    includes_key="includes",
                    expect_overwrite=True,
                ).data,
                expect_overwrite=True,
                logger=self.logger,
            )

        self.variables_new = self.variables != self.previous["variables"]
        self.previous["variables"] = self.variables

        if self.variables_new:
            self.logger.info("Variable data is updated.")

    def set_directory(self, path: Pathlike) -> None:
        """Set a new directory to use as the data repository."""

        new_dir = normalize(path).resolve()

        if new_dir == self.directory:
            self.logger.info(
                "New directory '%s' same as current.", rel(new_dir)
            )
            return

        self.directory = new_dir
        self.logger.info("Set directory to '%s'.", rel(new_dir))

    def set_variant(self, variant: str = None) -> None:
        """Set a new variant value."""

        if not variant:
            self.logger.info("Current variant: '%s'.", self.variant)
        elif variant != self.variant:
            self.previous["variant"] = self.variant
            self.variant = variant
            self.logger.info("Updating variant to '%s'.", variant)

    def asdict(self) -> _JsonObject:
        """Obtain a dictionary representing this instance."""

        return {
            "directory": str(self.directory),
            "variant": self.variant,
            "previous": self.previous,
            "manifest": self.manifest,
        }

@contextmanager
def load_state(
    root: Pathlike = None, name: str = "state.json"
) -> Iterator[State]:
    """This needs to be a context manager, so it get's written back to disk."""

    if root is None:
        root = default_state_directory()

    with FileCache(normalize(root, name)).loaded() as data:
        state = State.create(data, verify=False)
        yield state

        # Update the original dictionary with any changes to the state object.
        data.update(state.asdict())


import io

from .utils import print, PrintToFile
from . import apiwriter, apipatcher, wgpu_native_patcher, idlparser, hparser
from .files import file_cache

def main():
    """Codegen entry point. This will populate the file cache with the
    new code, but not write it to disk."""

    log = io.StringIO()
    with PrintToFile(log):
        print("# Code generatation report")
        prepare()
        update_api()
        update_wgpu_native()
        file_cache.write("resources/codegen_report.md", log.getvalue())

def prepare():
    """Force parsing (and caching) the IDL and C header."""
    print("## Preparing")
    file_cache.reset()
    idlparser.get_idl_parser(allow_cache=False)
    hparser.get_h_parser(allow_cache=False)

def update_api():
    """Update the public API and patch the public-facing API of the backends."""

    print("## Updating API")

    # Write the simple stuff
    apiwriter.write_flags()
    apiwriter.write_enums()
    apiwriter.write_structs()

    # Patch base API: IDL -> API
    code1 = file_cache.read("_classes.py")
    print("### Patching API for _classes.py")
    code2 = apipatcher.patch_base_api(code1)
    file_cache.write("_classes.py", code2)

    # Patch backend APIs: _classes.py -> API
    for fname in ["backends/wgpu_native/_api.py"]:
        code1 = file_cache.read(fname)
        print(f"### Patching API for {fname}")
        code2 = apipatcher.patch_backend_api(code1)
        file_cache.write(fname, code2)

def update_wgpu_native():
    """Update and check the wgpu-native backend."""

    print("## Validating backends/wgpu_native/_api.py")

    # Write the simple stuff
    wgpu_native_patcher.compare_flags()
    wgpu_native_patcher.write_mappings()

    # Patch wgpu_native api
    code1 = file_cache.read("backends/wgpu_native/_api.py")
    code2 = wgpu_native_patcher.patch_wgpu_native_backend(code1)
    file_cache.write("backends/wgpu_native/_api.py", code2)


#-*- coding: utf-8 -*-
import os
import sys
from os.path import abspath, dirname
sys.path.insert(0, dirname(dirname(abspath(__file__))))
import datetime
import traceback
import matplotlib
matplotlib.use('Agg')
import const as ct
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
from backlooking.cdoc import CDoc
from matplotlib import style
from climit import CLimit
from cindex import CIndex
from cmysql import CMySQL
from datetime import datetime
from rstock import RIndexStock
from base.clog import getLogger
from datamanager.margin import Margin
from industry_info import IndustryInfo
from datamanager.emotion import Emotion
from base.cdate import get_day_nday_ago
from rindustry import RIndexIndustryInfo
from datamanager.sexchange import StockExchange
from visualization.bull_ratio_plot import CBullRation
from common import create_redis_obj, get_chinese_font, get_tushare_client
class CReivew:
    def __init__(self, dbinfo = ct.DB_INFO, redis_host = None):
        self.dbinfo             = dbinfo
        self.logger             = getLogger(__name__)
        self.tu_client          = get_tushare_client()
        self.doc                = CDoc()
        self.redis              = create_redis_obj() if redis_host is None else create_redis_obj(redis_host)
        self.mysql_client       = CMySQL(dbinfo, iredis = self.redis)
        self.margin_client      = Margin(dbinfo = dbinfo, redis_host = redis_host)
        self.rstock_client      = RIndexStock(dbinfo = dbinfo, redis_host = redis_host)
        self.sh_market_client   = StockExchange(ct.SH_MARKET_SYMBOL)
        self.sz_market_client   = StockExchange(ct.SZ_MARKET_SYMBOL)
        self.emotion_client     = Emotion()
        self.bullration_client  = CBullRation(dbinfo, redis_host)

    def get_industry_data(self, cdate):
        ri = RIndexIndustryInfo()
        df = ri.get_k_data(cdate)
        if df.empty: return df
        df = df.reset_index(drop = True)
        df = df.sort_values(by = 'amount', ascending= False)
        df['money_change'] = (df['amount'] - df['preamount'])/1e8
        industry_info = IndustryInfo.get()
        df = pd.merge(df, industry_info, how='left', on=['code'])
        return df

    def get_index_data(self, cdate):
        df = pd.DataFrame()
        for code, name in ct.TDX_INDEX_DICT.items():
            data = CIndex(code).get_k_data(cdate)
            data['name'] = name
            data['code'] = code
            df = df.append(data)
        df = df.reset_index(drop = True)
        return df

    def get_market_data(self, market, start_date, end_date):
        if market == ct.SH_MARKET_SYMBOL:
            df = self.sh_market_client.get_k_data_in_range(start_date, end_date)
            df = df.loc[df.name == '上海市场']
        else:
            df = self.sz_market_client.get_k_data_in_range(start_date, end_date)
            df = df.loc[df.name == '深圳市场']
        df = df.round(2)
        df = df.drop_duplicates()
        df = df.reset_index(drop = True)
        df = df.sort_values(by = 'date', ascending= True)
        df.negotiable_value = (df.negotiable_value / 2).astype(int)
        return df

    def get_rzrq_info(self, market, start_date, end_date):
        df = self.margin_client.get_k_data_in_range(start_date, end_date)
        if market == ct.SH_MARKET_SYMBOL:
            df = df.loc[df.code == 'SSE']
            df['code'] = '上海市场'
        else:
            df = df.loc[df.code == 'SZSE']
            df['code'] = '深圳市场'
        df = df.round(2)
        df['rzye']   = df['rzye']/1e+8
        df['rzmre']  = df['rzmre']/1e+8
        df['rzche']  = df['rzche']/1e+8
        df['rqye']   = df['rqye']/1e+8
        df['rzrqye'] = df['rzrqye']/1e+8
        df = df.drop_duplicates()
        df = df.reset_index(drop = True)
        df = df.sort_values(by = 'date', ascending= True)
        return df

    def get_index_df(self, code, start_date, end_date):
        cindex_client = CIndex(code)
        df = cindex_client.get_k_data_in_range(start_date, end_date)
        df['time'] = df.index.tolist()
        df = df[['time', 'open', 'high', 'low', 'close', 'volume', 'amount', 'date']]
        return df

    def update(self, cdate = datetime.now().strftime('%Y-%m-%d')):
        start_date = get_day_nday_ago(cdate, 200, dformat = "%Y-%m-%d")
        end_date   = cdate
        try:
            self.doc.move_old_files()
            #market info
            sh_df = self.get_market_data(ct.SH_MARKET_SYMBOL, start_date, end_date)
            sz_df = self.get_market_data(ct.SZ_MARKET_SYMBOL, start_date, end_date)
            date_list = list(set(sh_df.date.tolist()).intersection(set(sz_df.date.tolist())))
            sh_df = sh_df[sh_df.date.isin(date_list)]
            sh_df = sh_df.reset_index(drop = True)
            sz_df = sz_df[sz_df.date.isin(date_list)]
            sz_df = sz_df.reset_index(drop = True)
            #rzrq info
            sh_rzrq_df = self.get_rzrq_info(ct.SH_MARKET_SYMBOL, start_date, end_date)
            sz_rzrq_df = self.get_rzrq_info(ct.SZ_MARKET_SYMBOL, start_date, end_date)
            date_list = list(set(sh_rzrq_df.date.tolist()).intersection(set(sz_rzrq_df.date.tolist())))
            sh_rzrq_df = sh_rzrq_df[sh_rzrq_df.date.isin(date_list)]
            sh_rzrq_df = sh_rzrq_df.reset_index(drop = True)
            sz_rzrq_df = sz_rzrq_df[sz_rzrq_df.date.isin(date_list)]
            sz_rzrq_df = sz_rzrq_df.reset_index(drop = True)
            #average price info
            av_df = self.get_index_df('880003', start_date, end_date)
            #limit up and down info
            limit_info = CLimit(self.dbinfo).get_data(cdate)
            stock_info = self.rstock_client.get_data(cdate)
            stock_info = stock_info[stock_info.volume > 0] #get volume > 0 stock list
            stock_info = stock_info.reset_index(drop = True)
            #index info
            index_info = self.get_index_data(end_date)
            #industry analysis
            industry_info = self.get_industry_data(cdate)
            #all stock info
            all_stock_info = self.rstock_client.get_k_data_in_range(start_date, end_date)
            #get bull ration data
            bull_ration_df = self.bullration_client.get_bull_ratios('000001', start_date, end_date)
            #gen review file and make dir for new data
            self.doc.generate(cdate, sh_df, sz_df, sh_rzrq_df, sz_rzrq_df, av_df, limit_info,
                        stock_info, industry_info, index_info, all_stock_info, bull_ration_df)
            ##gen review animation
            #self.gen_animation()
            return True
        except Exception as e:
            traceback.print_exc()
            self.logger.error(e)
            return False

    def gen_animation(self, sfile = None):
        import matplotlib.animation as animation
        style.use('fivethirtyeight')
        Writer = animation.writers['ffmpeg']
        writer = Writer(fps=1, metadata=dict(artist='biek'), bitrate=1800)
        fig = plt.figure()
        ax = fig.add_subplot(1,1,1)
        _today = datetime.now().strftime('%Y-%m-%d')
        cdata = self.mysql_client.get('select * from %s where date = "%s"' % (ct.ANIMATION_INFO, _today))
        if cdata is None: return None
        cdata = cdata.reset_index(drop = True)
        ctime_list = cdata.time.unique()
        name_list = cdata.name.unique()
        ctime_list = [datetime.strptime(ctime,'%H:%M:%S') for ctime in ctime_list]
        frame_num = len(ctime_list)
        if 0 == frame_num: return None
        def animate(i):
            ax.clear()
            ax.xaxis.set_major_formatter(mdates.DateFormatter('%H:%M:%S'))
            ax.xaxis.set_major_locator(mdates.DayLocator())
            ax.set_title('盯盘', fontproperties = get_chinese_font())
            ax.set_xlabel('时间', fontproperties = get_chinese_font())
            ax.set_ylabel('增长', fontproperties = get_chinese_font())
            ax.set_ylim((-6, 6))
            fig.autofmt_xdate()
            for name in name_list:
                pchange_list = list()
                price_list = cdata[cdata.name == name]['price'].tolist()
                pchange_list.append(0)
                for _index in range(1, len(price_list)):
                    pchange_list.append(10 * (price_list[_index] - price_list[_index - 1])/price_list[0])
                ax.plot(ctime_list[0:i], pchange_list[0:i], label = name, linewidth = 1.5)
                if pchange_list[i-1] > 1 or pchange_list[i-1] < -1:
                    ax.text(ctime_list[i-1], pchange_list[i-1], name, font_properties = get_chinese_font())
        ani = animation.FuncAnimation(fig, animate, frame_num, interval = 60000, repeat = False)
        sfile = '/data/animation/%s_animation.mp4' % _today if sfile is None else sfile
        ani.save(sfile, writer)
        plt.close(fig)

if __name__ == '__main__':
    creview = CReivew(ct.DB_INFO)
    data = creview.update('2019-05-30')


import logging
from http import cookies
from os import environ
from urllib.parse import urlparse

from decouple import config
from fastapi import Request
from onelogin.saml2.auth import OneLogin_Saml2_Auth
from starlette.datastructures import FormData

SAML2 = {
    "strict": config("saml_strict", cast=bool, default=True),
    "debug": config("saml_debug", cast=bool, default=True),
    "sp": {
        "entityId": config("SITE_URL") + "/api/sso/saml2/metadata/",
        "assertionConsumerService": {
            "url": config("SITE_URL") + "/api/sso/saml2/acs/",
            "binding": "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
        },
        "singleLogoutService": {
            "url": config("SITE_URL") + "/api/sso/saml2/sls/",
            "binding": "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
        },
        "NameIDFormat": "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress",
        "x509cert": config("sp_crt", default=""),
        "privateKey": config("sp_key", default=""),
    },
    "security": {
        "requestedAuthnContext": False
    },
    "idp": None
}

# in case tenantKey is included in the URL
sp_acs = config("idp_tenantKey", default="")
if sp_acs is not None and len(sp_acs) > 0:
    SAML2["sp"]["assertionConsumerService"]["url"] += sp_acs + "/"

idp = None
# SAML2 config handler
if config("SAML2_MD_URL", default=None) is not None and len(config("SAML2_MD_URL")) > 0:
    print("SAML2_MD_URL provided, getting IdP metadata config")
    from onelogin.saml2.idp_metadata_parser import OneLogin_Saml2_IdPMetadataParser

    idp_data = OneLogin_Saml2_IdPMetadataParser.parse_remote(config("SAML2_MD_URL", default=None))
    idp = idp_data.get("idp")

if SAML2["idp"] is None:
    if len(config("idp_entityId", default="")) > 0 \
            and len(config("idp_sso_url", default="")) > 0 \
            and len(config("idp_x509cert", default="")) > 0:
        idp = {
            "entityId": config("idp_entityId"),
            "singleSignOnService": {
                "url": config("idp_sso_url"),
                "binding": "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
            },
            "x509cert": config("idp_x509cert")
        }
        if len(config("idp_sls_url", default="")) > 0:
            idp["singleLogoutService"] = {
                "url": config("idp_sls_url"),
                "binding": "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
            }

if idp is None:
    logging.info("No SAML2 IdP configuration found")
else:
    SAML2["idp"] = idp

def init_saml_auth(req):
    if idp is None:
        raise Exception("No SAML2 config provided")
    return OneLogin_Saml2_Auth(req, old_settings=SAML2)

async def prepare_request(request: Request):
    request.args = dict(request.query_params).copy() if request.query_params else {}
    form: FormData = await request.form()
    request.form = dict(form)
    cookie_str = request.headers.get("cookie", "")
    if "session" in cookie_str:
        cookie = cookies.SimpleCookie()
        cookie.load(cookie_str)
        # Even though SimpleCookie is dictionary-like, it internally uses a Morsel object
        # which is incompatible with requests. Manually construct a dictionary instead.
        extracted_cookies = {}
        for key, morsel in cookie.items():
            extracted_cookies[key] = morsel.value
        if "session" not in extracted_cookies:
            logging.info("!!! session not found in extracted_cookies")
            logging.info(extracted_cookies)
        session = extracted_cookies.get("session", {})
    else:
        session = {}
    # If server is behind proxys or balancers use the HTTP_X_FORWARDED fields
    headers = request.headers
    proto = headers.get('x-forwarded-proto', 'http')
    url_data = urlparse('%s://%s' % (proto, headers['host']))
    path = request.url.path
    site_url = urlparse(config("SITE_URL"))
    # to support custom port without changing IDP config
    host_suffix = ""
    if site_url.port is not None and request.url.port is None:
        host_suffix = f":{site_url.port}"

    # add / to /acs
    if not path.endswith("/"):
        path = path + '/'
    if not path.startswith("/api"):
        path = "/api" + path

    return {
        'https': 'on' if proto == 'https' else 'off',
        'http_host': request.headers['host'] + host_suffix,
        'server_port': url_data.port,
        'script_name': path,
        'get_data': request.args.copy(),
        # Uncomment if using ADFS as IdP, https://github.com/onelogin/python-saml/pull/144
        # 'lowercase_urlencoding': True,
        'post_data': request.form.copy(),
        'cookie': {"session": session},
        'request': request
    }

def is_saml2_available():
    return idp is not None

def get_saml2_provider():
    return config("idp_name", default="saml2") if is_saml2_available() and len(
        config("idp_name", default="saml2")) > 0 else None

def get_landing_URL(jwt):
    return config("SITE_URL") + config("sso_landing", default="/login?jwt=%s") % jwt

environ["hastSAML2"] = str(is_saml2_available())


from django.shortcuts import render , redirect, get_object_or_404, reverse
from django.http import HttpResponse
from .models import Product, Filament
from .forms import UploadForm as Upload, UpdateForm as Update, fileUploadForm as fileUpload

from django.contrib.auth.decorators import login_required

# Create your views here.
@login_required
def index(request):
    products = Product.objects.filter(user = request.user)
    context = { "products": products }
    return render(request, "app/index.html", context)

def dice(request):
    products = Product.objects.all()
    context = { "products": products }
    return render(request, "app/dice.html", context)

def upload(request):
    if request.method == 'POST':
        form = Upload(request.POST, request.FILES)
        if form.is_valid():
            form.save()
            return render(request, 'app/index.html')
    else:
        form = Upload()
    return render(request, 'app/upload.html', {'form': form})

def filament(request):
    context = { "filaments": Filament.objects.all() }
    return render(request, "app/filaments.html", context)

def file_detail(request, name):

    product = Product.objects.get(name=name)
    if request.method == 'POST':
        form = Update(request.POST, instance=product, files=request.FILES)
        if form.is_valid():
            form.save()
            return redirect('app:file_detail', name=product.name)
        else:
            # if form is not valid, render the same page with the errors
            context = { "product": product, "form": form}
            return render(request, "app/file_detail.html", context)
    else:
        form = Update(instance=product)

        context = { "product": product, "form": form}
        return render(request, "app/file_detail.html", context)


from DB_entity import DB_Entity

class Article(DB_Entity):
    def __init__(self):
        super().__init__("article", "articles")

    def create(self, author_id, category_id, title, content, is_active, publish_date):
        "Create article"
        self.create_item(
            {
                "author_id": author_id,
                "category_id": category_id,
                "title": title,
                "content": content,
                "is_active": "true",
                "publish_date": publish_date,
            }
        )

    def update(
        self,
        author_id,
        category_id,
        title,
        content,
        is_active,
        publish_date,
        article_id,
    ):
        "update article"
        self.update_item(
            {
                "author_id": author_id,
                "category_id": category_id,
                "title": title,
                "content": content,
                "is_active": is_active,
                "publish_date": publish_date,
            },
            article_id,
        )

    def get_one(self, article_id):
        "Get one article by id"
        if not isinstance(article_id, (str, int, float)):
            raise TypeError("You need to provide a valid article_id")

        self.get_item_by_id(
            article_id,
        )

    def deactivate_articles(self, articles_id):
        "Deactivate a list of articles by id"
        if isinstance(articles_id, (list, tuple)):
            for article in articles_id:
                self.deactivate_article(article)

    def deactivate_article(self, article_id):
        "Deactivate one article by id"
        self.update_item(
            {
                "is_active": "false",
            },
            article_id,
        )

    def get_articles_by_foreign_key(self, table_name: str):
        "Get articles"
        self.get_items_with_join(
            "*",
            ("true", "is", "true"),
            {
                "type": "RIGHT JOIN",
                "table_name": table_name,
                "alias": f"{table_name[0]}{table_name[1]}",
                "fk": f"{table_name}_id",
                "pk": "article_id",
            },
            "article_id",
        )

    def get_articles_by_one_foreign_key(self, table_name: str, foreign_key_id: str):
        "Get articles"
        self.get_items_with_join(
            "*",
            (f"{table_name[0]}{table_name[1]}.{table_name}_id", "=", foreign_key_id),
            {
                "type": "RIGHT JOIN",
                "table_name": table_name,
                "alias": f"{table_name[0]}{table_name[1]}",
                "fk": f"{table_name}_id",
                "pk": "article_id",
            },
            "article_id",
        )


from dataclasses import dataclass
from typing import Any, Optional

@dataclass
class Breadcrumb:
    label: Optional[str]
    link: str
    icon: Optional[str] = None
    parent: Optional[Any] = None

_adapters = list()

def breadcrumb_adapter(func):
    _adapters.append(func)

def breadcrumb_path(obj, request):
    result = list()
    while obj is not None:
        for a in _adapters:
            brcr = a(obj, request)
            if brcr is not None:
                assert isinstance(brcr, Breadcrumb)
                result.insert(0, brcr)
                obj = brcr.parent
                break
        else:
            break
    return result


import requests

def github_cred_validator(creds):
    try:
        resp = requests.get(
            "https://api.github.com/user",
            auth=(
                creds["username"],
                creds["personal_access_token"],
            )
        )

        if resp.status_code not in range(200, 300):
            return False

        data = resp.json()

        if "login" in data.keys() and creds["username"] != data["login"]:
            return False

    except Exception as e:
        raise e

    return True

def dockerhub_cred_validator(creds):
    return True

def validate_by_type(_type, creds):
    try:
        if _type == "github":
            return github_cred_validator(creds)
        elif _type == "dockerhub":
            return dockerhub_cred_validator(creds)
        else:
            return True
    except Exception as e:
        raise e


"""
@File: utils.py

@Author: Jared Galloway

Some helpful functions for printing
"""

# dependencies
import pandas as pd
import numpy as np
import xarray as xr
import scipy.stats as st

# built-in python3
import os
import copy
import itertools
import io
from functools import reduce
from collections import defaultdict

from phippery.utils import get_annotation_table

def string_feature(ds, feature: str, verbosity=0, dim="sample", numeric_dis=True):
    """
    Take in a single feature and returna formatted string
    that gives a basic descriptiton of that feature and it's values.

    """
    t = get_annotation_table(ds, dim)
    ser = t[feature]
    dt = ser.dtype
    descript = """"""

    non_null_ser = ser[ser.notnull()]
    null_flag = len(non_null_ser) < len(ser)
    levels = list(set(non_null_ser.values))
    num_levels = len(levels)

    if dt == pd.StringDtype():

        if num_levels >= 50:
            descript += f"""
Sorry, {feature} is a String feature with too many factor levels
(n = {num_levels}) to describe, here
"""

        elif num_levels < 50 and num_levels >= 2:
            descript += f"""
{feature}: {dt} Feature
-------------------------

Factor level counts df:

{non_null_ser.value_counts()}

Some example query statements:
------------------------------

{feature} in ['{levels[0]}', '{levels[1]}', ...]

{feature} not in ['{levels[0]}', '{levels[-1]}', ...]

{feature} != '{levels[-2]}'
"""

        else:
            descript += f"""
There's only a single factor level, {levels[0]}, across all samples.
"""

    elif dt == pd.BooleanDtype():
        descript += f"""
{feature}: {dt} Feature:
---------------------------

Factor level counts df:

{non_null_ser.value_counts()}

Some example query statements:
------------------------------

{feature} == True

{feature} == False
"""

    elif dt == pd.Int64Dtype() or dt == pd.Float64Dtype():
        if num_levels == 1:
            descript += f"""
There's only a single factor level, {levels[0]}, across all samples.
"""

        elif (num_levels > 1) and (not numeric_dis):
            descript += f"""
{feature}: {dt} Feature
-------------------------

Factor level counts df:

{non_null_ser.value_counts()}

Some example query statements:
------------------------------

{feature} in [{levels[0]}, {levels[1]}, ...]

{feature} not in [{levels[0]}, {levels[-1]}, ...]

{feature} != {levels[-2]}
"""
        else:
            des = ser.describe()
            descript += f"""
{feature}: {dt} Feature:
---------------------------

distribution of numerical feature:

{des}

Some example query statements:
------------------------------

{feature} >= {int(des[1])}

{feature} <= {int(des[1])}

({feature} >= {int(des[4])}) and ({feature} <= {int(des[5])})
"""

    else:
        descript += f"""
{feature}: {dt} Feature
-------------------------

Factor level counts df:

{non_null_ser.value_counts()}

Some example query statements:
------------------------------

{feature} in ['{levels[0]}', '{levels[1]}', ...]

{feature} not in ['{levels[0]}', '{levels[-1]}', ...]

{feature} != '{levels[-2]}'
"""

    if null_flag:
        descript += f"""
{feature}.isnull()

{feature}.notnull()
"""

    return descript

def string_ds(ds, verbosity: int):
    """
    Summarize the data in a given dataset

    If verbosity flag is set to zero, this will print the
    basic information about number of
    samples, peptides, and enrichment layers
    in a given dataset. With a verbosity of one (-v) you will
    get also information about annotations and available datatypes.
    If verbosity flag is set to two (-vv) - Print
    detailed information about all data tables including annotation
    feature types and distribution of enrichment values for each layer.
    A verbosity of three will basically loop through all features
    """

    # initialize formatting for each of the three major facets of a dataset
    table_strings = {
        "sample_table": """
Sample Table:
-------------\n""",
        "peptide_table": """
Peptide Table:
--------------\n""",
        #        'enrichments' : """
        # Enrichment Matrices:
        # --------------------\n"""
    }

    for dimension in ["sample", "peptide"]:

        df = get_annotation_table(ds, dim=dimension)
        num_dimensions = len(df)

        buffer = io.StringIO()
        df.info(buf=buffer)
        complete = buffer.getvalue()
        table_strings[f"{dimension}_table"] += f"""{complete}"""

    # initialize formatting strings for all enrichment layers
    # enr_layers = set(list(ds.data_vars)) - set(["sample_table", "peptide_table"])
    # enrichment_strings = {}
    # for enr in enr_layers:
    #    mat = ds[enr].to_pandas()
    #    enrichment_strings[enr] = f"""* {enr}\n{mat.describe()}"""

    # complete = """"""
    # for key, value in enrichment_strings.items():
    #    complete += value
    # table_strings['enrichments'] += complete

    final = """"""
    for key, value in table_strings.items():
        final += value

    return final


from vidgear.gears import VideoGear
import cv2

class SaveReadService:
    @classmethod
    def saveText(cls, text, file):
        with open(file, "w+", encoding="utf-8") as fichier:
            fichier.write(text)

    @classmethod
    def saveOther(cls, text, file):
        with open(file, "wb") as fichier:
            fichier.write(text)

    @classmethod
    def takeText(cls, file):
        text = ""
        with open(file, 'r', encoding="utf-8") as fichier:
            for line in fichier.readlines():
                text += line.strip() + '\n'
        return text

    @classmethod
    def takeOther(cls, file):
        f = []
        extension = ""
        with open(file, 'r+b') as fichier:
            for i in reversed(fichier.name):
                extension += i
                if i == ".":
                    break
            for line in fichier.readlines():
                f.append(line)
        return [f, extension[::-1]]

    @classmethod
    def TakeVide(cls, ficher, conversion):
        x = []
        cap = VideoGear(source=ficher).start()
        fps = cap.framerate
        print(fps)
        count = 0
        while True:
            frame = cap.read()
            if frame is None:
                break
            x.append(frame)
        cap.stop()
        return x, fps


import sys
from time import sleep
import board
import sparkfun_qwiictwist

# Create bus object using our board's I2C port
i2c = board.I2C()

# Create joystick object
twist = sparkfun_qwiictwist.Sparkfun_QwiicTwist(i2c)

# Check if connected
if twist.connected:
    print("Twist connected.")
else:
    print("Twist does not appear to be connected. Please check wiring.")
    sys.exit()

# Print firmware version and current status
print("Firmware version " + twist.version)

# Turn the relay on and off
print("Press Ctrl-C to exit program")

try:
    while True:
        print("Count: " + str(twist.count))
        if twist.pressed:
            print("Pressed!")
        sleep(0.5)

except KeyboardInterrupt:
    pass


import sys

sys.setrecursionlimit(10 ** 6)
input = sys.stdin.readline

# 방향 정의(상,하,좌,우)
dx = [-1, 1, 0, 0]
dy = [0, 0, -1, 1]

def dfs(x, y, house):
    ground[x][y] = 0  # 해당 지점은 확인

    for i in range(4):
        nx = x + dx[i]
        ny = y + dy[i]

        if 0 <= nx < N and 0 <= ny < N:
            if ground[nx][ny] == 1:
                house = dfs(nx, ny, house + 1)
    return house

N = int(input())
ground = [list(map(int, input().rstrip())) for _ in range(N)]
houses = []  # 각 단지내 집의 수

for i in range(N):
    for j in range(N):
        if ground[i][j] == 1:
            houses.append(dfs(i, j, 1))

print(len(houses))
for house in sorted(houses):
    print(house)

단지번호붙이기_DFS.py


from heapq import *
from collections import defaultdict
import sys
input = sys.stdin.readline
INF = sys.maxsize

N, M = map(int, input().split())
G = defaultdict(list)
for _ in range(M):
    A, B, C = map(int, input().split())
    G[A].append((C, B))
    G[B].append((C, A))

V = [False] * (N+1)
V[1] = True
Q = []
for cost, n2 in G[1]:
    heappush(Q, (cost, 1, n2))
ans = []

while Q:
    c, n1, n2 = heappop(Q)

    if V[n2]:
        continue
    ans.append((n1, n2))
    V[n2] = True

    for cost, n3 in G[n2]:
        if not V[n3]:
            heappush(Q, (c + cost, n2, n3))

print(len(ans))
for i in ans:
    print(*i)


"""
You are given an m * n matrix, mat, and an integer k, which has its rows sorted in non-decreasing order.

You are allowed to choose exactly 1 element from each row to form an array. Return the Kth smallest array sum among all possible arrays.
"""

class Solution:
    def kthSmallest(self, mat: List[List[int]], k: int) -> int:
        """
        T(n) = O(m*n^2log(n)) --- sort a n^2 list takes O(n^2logn) time, do it m times (n_rows)
        S(n) = O(n^2)
        """
        h = mat[0][:]
        for row in mat[1:]:
            sums = [i + j for i in row for j in h] #m^2
            h = sorted(sums)[:k]
        return h[k - 1]

1439. Find the Kth Smallest Sum of a Matrix With Sorted Rows/KthSmallest.py