import tensorflow as tf
from models.modules import *
import numpy as np
import os

class BAGAN(tf.keras.Model):
    def __init__(self, hp):
        super(BAGAN, self).__init__()
        self.hp = hp
        self.embed_dims = hp.autoencoder.embed_dims
        self.key_word_num = 10  # number of keyword
        self.output_num = self.key_word_num + 1  # one for fake label

        self.commands = {"left":0, "down":1, "go":2, "off":3, "on":4, "right":5, "stop":6, "up":7, "yes":8, "no":9}

        # Set generator
        self.G = self.create_generator()

        # Set discriminator
        self.encoder = create_encoder(embed_dims=self.embed_dims)
        self.D = self.create_discriminator()

        # Set empty dictionary for embeddings
        self.embeddings = dict()

    def generate(self, embeddings):
        return self.G(embeddings)

    def discriminate(self, sample):
        if len(sample.shape) == 3:
            sample = tf.expand_dims(sample, -1)

        embed = self.encoder(sample)
        return self.D(embed)

    def create_generator(self):
        decoder = create_decoder(time_length=self.hp.audio.time_length, feat_dim=self.hp.audio.n_mels)
        return decoder

    def create_discriminator(self):
        discriminator = tf.keras.Sequential([
            tf.keras.layers.Flatten(),
            tf.keras.layers.Dense(self.output_num, activation='softmax')
        ])
        return discriminator

    def load_embeddings(self, key, embedding_path):
        mean_vector_path = os.path.join(embedding_path, key + '-mean.npy')
        mean = np.load(mean_vector_path)
        covariance_vector_path = os.path.join(embedding_path, key + '-variance.npy')
        cov = np.load(covariance_vector_path)
        self.embeddings[key] = {'mean': mean, 'cov': cov}

    def generate_noise(self, size):
        noise = []
        label = []
        for key in self.embeddings:
            mean = self.embeddings[key]['mean']
            cov = self.embeddings[key]['cov']
            #print(np.random.multivariate_normal(mean=mean, cov=cov).shape)
            noise += [np.random.multivariate_normal(mean=mean, cov=cov) for i in range(int(size))]
            _y = np.zeros(shape=[self.output_num], dtype=np.float32)
            _y[self.commands[key]] = 1
            for i in range(int(size)):
                label += [_y]
        noise = np.stack(noise, 0)
        label = np.stack(label, 0)
        return noise, label

    def train_on_batch(self, x_real, y):
        # Generate noise
        size = int(len(x_real) / self.key_word_num)
        noise, y_gen = self.generate_noise(size)

        # Generate fake samples
        x_fake = self.generate(noise)

        # Train discriminator
        with tf.GradientTape() as tape:
            # Discriminate fake samples
            y_fake = np.zeros_like(y)
            y_fake[:, -1] = 1  # labeled as fake
            D_loss_fake = self.loss_fn(y_pred=self.discriminate(x_fake), y_true=y_fake)

            # Discriminate real samples
            D_loss_real = self.loss_fn(y_pred=self.discriminate(x_real), y_true=y)

            # Calculate gradients & update discriminator
            D_loss = (D_loss_fake + D_loss_real) / 2
            grads = tape.gradient(D_loss, self.D.trainable_variables)
            self.D_optimizer.apply_gradients(zip(grads, self.D.trainable_variables))

        # Train generator
        G_loss_list = []
        for i in range(1):
            with tf.GradientTape() as tape:
                #noise, y_gen = self.generate_noise(size)
                x_fake = self.generate(noise)
                y_pred = self.discriminate(x_fake)
                G_loss = self.loss_fn(y_pred=y_pred, y_true=y_gen)

                # Calculate gradients & update discriminator
                grads = tape.gradient(G_loss, self.G.trainable_variables)
                self.G_optimizer.apply_gradients(zip(grads, self.G.trainable_variables))

                G_loss_list.append(G_loss)

        return D_loss, tf.reduce_mean(G_loss_list)

    def evaluate(self, x_real, y):
        # Generate noise
        size = len(x_real) / self.key_word_num
        noise, y_gen = self.generate_noise(size)

        # Generate fake samples
        x_fake = self.generate(noise)

        y_fake = np.zeros_like(y)
        y_fake[:, -1] = 1

        # Calculate D_loss
        D_fake = self.discriminate(x_fake)
        D_loss_fake = self.loss_fn(y_pred=D_fake, y_true=y_fake)
        D_real = self.discriminate(x_real)
        D_loss_real = self.loss_fn(y_pred=D_real, y_true=y)
        D_loss = (D_loss_fake + D_loss_real) / 2

        # Calculate D_acc
        D_acc_fake = tf.reduce_mean(tf.cast(tf.equal(tf.argmax(D_fake, axis=1), tf.argmax(y_fake, axis=1)), tf.float32))
        D_acc_real = tf.reduce_mean(tf.cast(tf.equal(tf.argmax(D_real, axis=1), tf.argmax(y, axis=1)), tf.float32))
        D_acc = (D_acc_fake + D_acc_real) / 2

        # Calculate G_loss
        G_loss = self.loss_fn(y_pred=D_fake, y_true=y_gen)

        # Calculate G_acc
        G_acc = tf.reduce_mean(tf.cast(tf.equal(tf.argmax(D_fake, axis=1), tf.argmax(y, axis=1)), tf.float32))

        return D_loss, D_acc, G_loss, G_acc

    def compile(self, D_optimizer, G_optimizer, loss_fn):
        self.D_optimizer = D_optimizer
        self.G_optimizer = G_optimizer
        self.loss_fn = loss_fn

    def save(self, D_path, G_path):
        self.D.save_weights(D_path)
        self.G.save_weights(G_path)


import sys
# 문제는 그리디 알고리즘을 사용하여 크레인이 옮길 수 있는
# 최대한의 무게의 박스부터 옮겨서 최소의 소요시간을 탐색한다.

# 크레인의 수와 무게제한 입력 및 정렬(내림차순)
N = int(sys.stdin.readline())
cranes = list()
cranes = list(map(int, sys.stdin.readline().split()))
cranes.sort(reverse=True)

# 박스의 수와 무게 입력 및 정렬(내림차순)
M = int(sys.stdin.readline())
boxs = list()
boxs = list(map(int, sys.stdin.readline().split()))
boxs.sort(reverse=True)

# 크레인의 최대 무게제한보다 박스의 최대 무게가 큰 경우, -1 출력
if cranes[0] < boxs[0]:
    print(-1)
else:
    c_num = 0
    num = 0
    result = 0
    while len(boxs):
        if c_num == len(cranes):
            num = 0
            c_num = 0
            result += 1
        if num == len(boxs):
            cranes.remove(cranes[c_num])
            num = 0
        elif cranes[c_num] >= boxs[num]:
            boxs.remove(boxs[num])
            c_num += 1
        else:
            num += 1

    result += 1
    print(result)


#  Adapted from https://github.com/libAtoms/silicon-testing-framework

import os
from io import StringIO

from ase.io import read, write
from ase.calculators.singlepoint import SinglePointCalculator
from ase.optimize import FIRE
from ase.constraints import UnitCellFilter, voigt_6_to_full_3x3_stress, full_3x3_to_voigt_6_stress

from ase import Atoms
import numpy as np

def read_bulk_reference(model_name, test_name):
    log_file = 'model-{0}-test-{1}.txt'.format(model_name, test_name)
    log_lines = open(os.path.join('..', log_file), 'r').readlines()
    start_idx = log_lines.index('relaxed bulk\n')
    n_atoms = int(log_lines[start_idx+1])
    xyz_lines = log_lines[start_idx+1:start_idx+n_atoms+3]
    fh = StringIO.StringIO(''.join(xyz_lines))
    bulk = read(fh, format='extxyz')
    return bulk

def relax_atoms(atoms, tol=1e-3, method='lbfgs_precon', max_steps=1000, traj_file=None, **kwargs):
    if method.startswith('lbfgs') or method == 'fire' or method == 'cg_n':
        if method == 'lbfgs_ASE':
            from ase.optimize import LBFGS
            opt = LBFGS(atoms, **kwargs)
        from ase.optimize.precon.precon import Exp
        from ase.optimize.precon.lbfgs import PreconLBFGS
        precon = None
        if method.endswith('precon'):
            precon = Exp(3.0, reinitialize=True)

        if method.startswith('lbfgs'):
            opt = PreconLBFGS(atoms, precon=precon, **kwargs)
        else:
            opt = FIRE(atoms, **kwargs)
        if traj_file is not None and method != 'cg_n':
            traj = open(traj_file, 'w')
            def write_trajectory():
                write(traj, atoms, format='extxyz')
            opt.attach(write_trajectory)
        opt.run(tol, max_steps)
        try:
            traj.close()
        except:
            pass
    else:
        raise ValueError('unknown method %s!' % method)

    return atoms

from .symmetrize import prep,forces, stress
from ase.calculators.calculator import Calculator
class SymmetrizedCalculator(Calculator):
   implemented_properties = ['energy','forces','stress','free_energy']
   def __init__(self, calc, atoms, *args, **kwargs):
      Calculator.__init__(self, *args, **kwargs)
      self.calc = calc
      (self.rotations, self.translations, self.symm_map) = prep(atoms, symprec=0.01)

   def calculate(self, atoms, properties, system_changes):
        Calculator.calculate(self, atoms, properties, system_changes)
        if system_changes:
            self.results = {}
        if 'energy' in properties and 'energy' not in self.results:
            self.results['energy'] = self.calc.get_potential_energy(atoms)
            self.results['free_energy'] = self.results['energy']
        if 'forces' in properties and 'forces' not in self.results:
            raw_forces = self.calc.get_forces(atoms)
            self.results['forces'] = forces(atoms.get_cell(), atoms.get_reciprocal_cell().T, raw_forces,
                self.rotations, self.translations, self.symm_map)
        if 'stress' in properties and 'stress' not in self.results:
            raw_stress = self.calc.get_stress(atoms)
            if len(raw_stress) == 6: # Voigt
                raw_stress = voigt_6_to_full_3x3_stress(raw_stress)
            symmetrized_stress = stress(atoms.get_cell(), atoms.get_reciprocal_cell().T, raw_stress, self.rotations)
            self.results['stress'] = full_3x3_to_voigt_6_stress(symmetrized_stress)

def relax_atoms_cell(atoms, tol=1e-3, stol=None, method='lbfgs_precon', max_steps=100, mask=None, traj_file=None,
                     hydrostatic_strain=False, constant_volume=False, precon_apply_positions=True,
                     precon_apply_cell=True, symmetrize = False, **kwargs):
    if symmetrize:
        calc = atoms.get_calculator()
        scalc = SymmetrizedCalculator(calc, atoms)
        atoms.set_calculator(scalc)

    if method != 'cg_n':
        atoms = UnitCellFilter(atoms, mask=mask,
                               hydrostatic_strain=hydrostatic_strain,
                               constant_volume=constant_volume)
    if method.startswith('lbfgs') or method == 'fire' or method == 'cg_n':
        from ase.optimize.precon.precon import Exp
        from ase.optimize.precon.lbfgs import PreconLBFGS
        precon = None
        if method.endswith('precon'):
            precon = Exp(3.0, apply_positions=precon_apply_positions,
                            apply_cell=precon_apply_cell, reinitialize=True)
        if method.startswith('lbfgs'):
            opt = PreconLBFGS(atoms, precon=precon, **kwargs)
        else:
            opt = FIRE(atoms, **kwargs)
        if traj_file is not None:
            traj = open(traj_file, 'w')
            def write_trajectory():
                try:
                    write(traj, atoms.atoms, format='extxyz')
                except:
                    write(traj, atoms, format='extxyz')
            opt.attach(write_trajectory)
        if method != 'cg_n' and isinstance(opt, PreconLBFGS):
            opt.run(tol, max_steps, smax=stol)
        else:
            opt.run(tol, max_steps)
        if traj_file is not None:
            traj.close()
    else:
        raise ValueError('unknown method %s!' % method)

    if isinstance(atoms, UnitCellFilter):
        return atoms.atoms
    else:
        return atoms

def evaluate(atoms, do_energy=True, do_forces=True, do_stress=True):
    energy = None
    if do_energy:
        energy = atoms.get_potential_energy()

    forces = None
    if do_forces:
        forces = atoms.get_forces()

    stress = None
    if do_stress:
        stress = atoms.get_stress()

    spc = SinglePointCalculator(atoms,
                                energy=energy,
                                forces=forces,
                                stress=stress)
    atoms.set_calculator(spc)
    return atoms


from skimage.filters import threshold_otsu
from skimage.measure import label as connected_compos_labeling
from skimage.measure import regionprops
import numpy as np
from skimage.segmentation import find_boundaries, clear_border
from scipy.ndimage import binary_erosion, binary_dilation
from termcolor import colored
import sys
import matplotlib.pyplot as plt
from skimage.io import imshow, imsave
from matplotlib.colors import ListedColormap

_coordinates = {
    (-1, -1),
    (-1, 0),
    (-1, 1),
    (0, -1),
    (0, 1),
    (1, -1),
    (1, 0),
    (1, 1)
}

def remove_labels(image, labels):
    lbls = np.array([l for l in labels])
    mask = np.isin(image, lbls)
    image[mask] = 0

def fill_holes(image):
    """
    A hole is a background area surrounded by a unique label and from which we can't reach the image's border.
    No in-place editing.

    Args:
        image: A labeled image on black background

    Returns:
        The same image as input but without holes in labels.
    """
    bg_mask = clear_border(connected_compos_labeling(binary_dilation(image == 0))).astype(np.uint16)
    props   = regionprops(bg_mask, intensity_image=image)

    lut = {}
    for region in props:
        if region.label == 0:
            continue
        data = region['image_intensity']
        data[np.logical_not(region['image'])] = 0
        values = set(np.unique(data)).difference({0})
        lut[region.label] = 0 if len(values) > 1 else values.pop()

    def replace_with_dict(x):
        return lut.get(x, 0)

    vfunc = np.vectorize(replace_with_dict)
    new_array = vfunc(bg_mask).astype(np.uint16)

    return np.maximum(image, new_array)

def generate_random_color(alpha=1.0):
    """ Generates a random color expressed as its hexadecimal notation. """
    r = randrange(0, 256)
    g = randrange(0, 256)
    b = randrange(0, 256)
    a = int(255 * alpha) if (alpha >= 0.0 and alpha <= 1.0) else 255
    return "#{:02x}{:02x}{:02x}{:02x}".format(r,g,b,a)

class YeastsPartitionGraph(object):
    def __init__(self, o_graph, cell_to_nuclei, nucleus_to_cells, labeled_yeasts, labeled_nuclei):
        self.graph      = dict()
        self.partitions = {1, 2}

        for cell_lbl, neighbor_cells in o_graph.items():
            ppts = self.graph.get(cell_lbl)
            if ppts is not None:
                continue
            vertices = self.find_partition(cell_lbl, cell_to_nuclei, nucleus_to_cells, o_graph)
            for (vertex, partition, bound, coords) in vertices:
                self.graph[vertex] = {
                    'neighbors'  : o_graph[vertex]['neighbors'].copy(),
                    'partition'  : partition,
                    'bound_to'   : bound if (bound > 0) else None,
                    'coordinates': coords,
                    'dist'       : 0
                }

        self.launch_hopcroft_karp()
        self.make_new_labels(labeled_yeasts, labeled_nuclei, cell_to_nuclei)
        self.remove_borders(labeled_yeasts, labeled_nuclei)

    def remove_borders(self, labeled_yeasts, labeled_nuclei):
        mask = binary_erosion(np.zeros(labeled_yeasts.shape) == 0)
        working_copy = np.copy(labeled_yeasts)
        working_copy[mask] = 0

        discarded   = np.array([i for i in set(np.unique(working_copy)).difference({0})])
        remove_labels(labeled_yeasts, discarded)
        remove_labels(labeled_nuclei, discarded)

    def find_partition(self, vertex, cell_to_nuclei, nucleus_to_cells, o_graph):
        nucleus_lbl = cell_to_nuclei[vertex]['owner']

        if nucleus_lbl == 0: # 0 means that this cell doesn't have a nucleus.
            return [(vertex, 2, 0, o_graph[vertex]['coordinates'])] # Vertices with no nuclei are stored in the partition 2.
        else:
            n_usage = nucleus_to_cells[nucleus_lbl]['used']

            if n_usage == 2:
                c1, c2 = [cell_lbl for cell_lbl, cell_props in enumerate(cell_to_nuclei) if (cell_props is not None) and (cell_props['owner'] == nucleus_lbl)]
                return [(c1, 1, c2, o_graph[c1]['coordinates']), (c2, 1, c1, o_graph[c2]['coordinates'])]

            if n_usage == 1:
                return [(vertex, 1, 0, o_graph[vertex]['coordinates'])]

            raise ValueError(f"This case is not handled. (n_usage={n_usage} for cell {vertex})")

    def make_cells_lut(self):
        current = 1
        lut = {}
        # partition 2: pas de nucleus, partition 1: a un nucleus
        for key, props in self.graph.items():
            if props['bound_to'] is None:
                if props['partition'] == 1:
                    # If the cell is bound to nobody but has a nucleus (independent cell)
                    lut[key] = current
                    current += 1
                else:
                    lut[key] = 0 # discarding the cell. Bound to nodoby and no nucleus.
            else:
                n = props['bound_to']
                label = lut.get(key)
                if label is None:
                    lut[key] = current
                    lut[n] = current
                    current += 1

        return lut

    def make_nuclei_lut(self, cell_to_nuclei, cells_lut):
        lut = {}
        for cell_lbl, cell_props in enumerate(cell_to_nuclei):
            if cell_props['owner'] <= 0:
                continue
            lut[cell_props['owner']] = cells_lut[cell_lbl]
        return lut

    def make_new_labels(self, old_labels, old_nuclei, cell_to_nuclei):
        # Cells part
        lut_cells  = self.make_cells_lut()
        lut_nuclei = self.make_nuclei_lut(cell_to_nuclei, lut_cells)

        def replace_cells_labels(x):
            return lut_cells.get(x, 0)

        vfunc = np.vectorize(replace_cells_labels)
        new_labels = vfunc(old_labels)
        new_labels = fill_holes(new_labels)

        old_labels[:] = new_labels.astype(np.int32)

        # Nuclei part (we want nuclei labels to mach their cell)
        def replace_nuclei_labels(x):
            return lut_nuclei.get(x, 0)

        vfunc = np.vectorize(replace_nuclei_labels)
        new_nuclei = vfunc(old_nuclei)
        old_nuclei[:] = new_nuclei.astype(np.int32)

    def show(self):
        from pprint import pprint
        pprint(self.graph, stream=out_descr)

    # mode in {'partition', 'bound_to'}
    def draw_graph(self, width_pixels, height_pixels, mode='partition', path=None):
        import networkx as nx
        import matplotlib.pyplot as plt
        from skimage.io import imshow, imsave

        plt.clf()
        plt.close()

        G = nx.Graph()
        if mode == 'partition':
            G.add_nodes_from([(key, {'pos': (props['coordinates'][0], height_pixels-props['coordinates'][1]), 'color': '#eb4034' if props['partition'] == 1 else '#4287f5'}) for key, props in self.graph.items() if key is not None])
        elif mode == 'bound_to':
            lut = {}
            for key, props in self.graph.items():
                color = lut.get(key)
                if color is None:
                    color = generate_random_color()
                    lut[key] = color
                    lut[props['bound_to']] = color
                position = props['coordinates']
                G.add_node(
                    key,
                    pos=(position[0], height_pixels-position[1]),
                    color=color
                )
        else:
            raise ValueError(mode + ' is not a valid value.')

        for key, ppts in self.graph.items():
            for n in ppts['neighbors']:
                G.add_edge(key, n)

        pos = nx.get_node_attributes(G, 'pos')
        color = list(nx.get_node_attributes(G, 'color').values())

        dpi = 100

        # Convertir les pixels en pouces
        width_inches = width_pixels / dpi
        height_inches = height_pixels / dpi

        # Créer la figure avec la taille spécifiée
        fig = plt.figure(figsize=(width_inches, height_inches), dpi=dpi)

        if mode == 'partition':
            labels = {i: i for i in self.graph.keys()}
        elif mode == 'bound_to':
            labels = {i: ("" if b['bound_to'] is None else b['bound_to']) for i, b in self.graph.items()}

        nx.draw(G, pos, with_labels=True, edge_color='#000000', labels=labels, node_color=color, node_size=650)
        plt.axhline(y=0, color='black', linewidth=5)
        plt.axhline(y=height_pixels, color='black', linewidth=5)
        plt.axvline(x=0, color='black', linewidth=5)
        plt.axvline(x=width_pixels, color='black', linewidth=5)

        if path is None:
            plt.show()
        else:
            plt.savefig(path)

    def bfs(self):
        queue = []
        for node, ppts in self.graph.items():
            if ppts['partition'] != 1:
                continue
            if ppts['bound_to'] == None:
                ppts['dist'] = 0
                queue.append(node)
            else:
                ppts['dist'] = float('inf')

        self.graph[None]['dist'] = float('inf')
        while queue:
            node = queue.pop(0)
            if self.graph[node]['dist'] < self.graph[None]['dist']:
                for v in self.graph[node]['neighbors']:
                    if self.graph[v]['partition'] == 2:
                        if self.graph[self.graph[v]['bound_to']]['dist'] == float('inf'):
                            self.graph[self.graph[v]['bound_to']]['dist'] = self.graph[node]['dist'] + 1
                            queue.append(self.graph[v]['bound_to'])

        return self.graph[None]['dist'] != float('inf')

    def dfs(self, node):
        if node is None:
            return True

        for v in self.graph[node]['neighbors']:
            if self.graph[v]['partition'] == 1:
                continue
            if self.graph[self.graph[v]['bound_to']]['dist'] == self.graph[node]['dist'] + 1:
                if self.dfs(self.graph[v]['bound_to']):
                    self.graph[node]['bound_to'] = v
                    self.graph[v]['bound_to'] = node
                    return True

        self.graph[node]['dist'] = float('inf')
        return False

    def launch_hopcroft_karp(self):
        matching = 0

        self.graph[None] = {
                'neighbors' : set(),
                'partition'  : 2,
                'coordinates': [0, 0],
                'bound_to': None,
                'dist'    : 0
            }

        while self.bfs():
            for node in self.graph:
                if self.graph[node]['partition'] != 1:
                    continue
                if self.graph[node]['bound_to'] == None and self.dfs(node):
                    matching += 1

        del self.graph[None]

        return matching

def nuclei_from_fluo(stack_fluo_nuclei):
    """
    Produces a segmentation of nuclei based on the nuclei marking (either a single slice or a stack).

    Args:
        An image or a stack representing the nuclei marking.

    Results:
        The MIP of the provided image and a labeled version of nuclei.
    """
    # Opening fluo spots stack
    stack_sz    = stack_fluo_nuclei.shape
    fluo_nuclei = None

    # Max projection of the stack
    if len(stack_sz) > 2: # We have a stack, not a single image.
        fluo_nuclei = np.max(stack_fluo_nuclei, axis=0)
    else:
        fluo_nuclei = np.squeeze(stack_fluo_nuclei)

    # Creating a basic mask representing nuclei.
    t = threshold_otsu(fluo_nuclei)
    mask_nuclei = fluo_nuclei > t
    lbl_nuclei = connected_compos_labeling(mask_nuclei)

    return fluo_nuclei, lbl_nuclei

def is_undirected(graph):
    for key, ns in graph.items():
        for n in ns:
            if key not in graph[n]:
                return False
    return True

def get_neighbors(l, c, height, width):
    global _coordinates
    new_coordinates = [(l+y, c+x) for (y, x) in _coordinates]
    return np.array([(y, x) for (y, x) in new_coordinates if (y >= 0) and (x >= 0) and (y < height) and (x < width)]).T

def adjacency_graph(labeled_cells, check_undirected=False):
    """
    Creates the adjacency graph of the segmented cells.
    Two cells are called "adjacent" if their labels are touching one another in 8-connectivity.

    Args:
        labeled_cells: The labeled image representing segmented cells.
        check_undirected: Activate the cheking of the graph essential properties (only for debug purposes).

    Returns:
        A dictionary representing the cells as a graph, indexed by cells' labels.
        For each label, gives: its location and its neighbors
    """

    height, width = labeled_cells.shape
    graph    = {}
    contacts = {}

    for (l, c), cell_label in np.ndenumerate(labeled_cells):
        if cell_label == 0:
            continue
        graph.setdefault(cell_label, set())
        ys, xs = get_neighbors(l, c, height, width)
        labels = labeled_cells[ys, xs]

        for lbl in labels:
            if (lbl > 0) and (lbl != cell_label):
                tpl = (lbl, cell_label) if (lbl < cell_label) else (cell_label, lbl)
                contacts.setdefault(tpl, 0)
                contacts[tpl] += 1
                graph[cell_label].add(lbl)

    for (a, b), count in contacts.items(): # We cut the edge if the contact surface is too small.
        if count < 50:
            graph[a].remove(b)
            graph[b].remove(a)

    with open("/home/benedetti/Bureau/dump.txt", 'w') as f:
        f.write(str(graph)+"\n\n")
        f.write(str(contacts)+"\n\n")

    if check_undirected:
        if is_undirected(graph):
            print(colored("The graph is undirected.", 'green'))
        else:
            print(colored("Error. The graph is not undirected.", 'red'))

    regions = regionprops(labeled_cells)
    cleaned = {}
    for cell in regions:
        cleaned[cell.label] = {'neighbors': graph[cell.label], 'coordinates': [i for i in cell.centroid]}

    return cleaned

def remove_excessive_coverage(labeled_cells, labeled_nuclei, covering_threshold):
    """
    Removing cells in which the nucleus occupies too much surface (dead cell).
    """

    #
    # Principle:
    #     1. Transform nuclei into mask
    #     2. Create a new image which is a copy of the cells from which we subtract our mask
    #     3. Measure the area of cells labels in both images
    #     4. Make the ratio to determine what was the region occupied by the nucleus in each cell.
    #

    mask_nuclei = labeled_nuclei > 0
    remaining_cells = np.copy(labeled_cells)
    remaining_cells[mask_nuclei] = 0 # We punch holes in cells.
    regions_before = {r['label']: (
        r['area'],
        r['centroid'],
        sorted([(count, unq) for unq, count in zip(*np.unique(r['image_intensity'], return_counts=True)) if (unq != 0)])
        ) for r in regionprops(labeled_cells, intensity_image=labeled_nuclei)}

    regions_after    = {r['label']: (r['area'], r['centroid']) for r in regionprops(remaining_cells)}
    discarded_cells  = set()
    discarded_nuclei = set()

    for cell_lbl, cell_props in regions_before.items():
        c = regions_after.get(cell_lbl)
        if c is None: # The cell was completly obliterated and doesn't exist anymore.
            discarded_cells.add(cell_lbl)
            continue
        ratio = c[0] / cell_props[0] # area_after / area_before
        if ratio < covering_threshold:
            discarded_cells.add(cell_lbl)
            if len(cell_props[2]) > 0:
                discarded_nuclei.add(cell_props[2][-1][1])

    print(f"{len(discarded_cells)} cells were discarded due to their nucleus covering them.")
    remove_labels(labeled_cells, discarded_cells)
    remove_labels(labeled_nuclei, discarded_nuclei)

    return discarded_cells, discarded_nuclei

def assign_nucleus(labeled_cells, labeled_nuclei, covering_threshold=0.7, graph=None):

    # 1. We remove cells covered too much by some nuclei.
    discarded_cells, discarded_nuclei = remove_excessive_coverage(labeled_cells, labeled_nuclei, covering_threshold)

    # 2. Defining variables.
    nucleus_to_cells = [None for _ in range(max(max(discarded_nuclei), np.max(labeled_nuclei))+1)]
    cell_to_nuclei   = [{
                    'users' : set(), # Nuclei overlaping with this cell.
                    'valid' : True,  # Boolean indicating if the cell will be discarded.
                    'owner' : 0,     # Nucleus owning this cell.
                    'stable': False, # True if we found a nucleus belonging ONLY to this cell (not shared with another).
                    'center': False  # True if the centroid of a nucleus was found in this cell.
                } for _ in range(max(max(discarded_cells), np.max(labeled_cells))+1)]

    # 3. Building an association table in both ways (nucleus -> cells & cell -> nuclei)
    nuclei_props  = regionprops(labeled_nuclei, intensity_image=labeled_cells)
    for nucleus in nuclei_props: # In this loop, we iterate through nuclei to find by how many cells it's being used.
        nucleus_lbl = nucleus.label
        l, c        = [int(k) for k in nucleus.centroid]
        cell_lbl    = labeled_cells[l, c]

        mask = np.logical_not(nucleus['image'])
        data = nucleus['intensity_image']
        data[mask]  = 0
        unq, counts = np.unique(data, return_counts=True)
        cell_labels = set([(i, c) for i, c in zip(unq, counts) if (i != 0 and c >= 15)]) # Labels of all the cells this nucleus intersects with.

        # Recording which cells the nucleus participates in
        nucleus_to_cells[nucleus_lbl] = {
            'users'   : cell_labels,
            'centroid': (l, c),
            'at'      : cell_lbl,
            'valid'   : True,
            'used'    : 0
        }

        # Recording which nuclei a given cell uses.
        for lbl, count in cell_labels:
            cell_to_nuclei[lbl]['users'].add(nucleus_lbl)

    # 4. Validation phase
    # /!\ Penser à check à chq fois si l'owner est déjà pris ailleurs, à dicrease le compteur
    for nucleus_lbl, nucleus_props in enumerate(nucleus_to_cells):

        # No nucleus with this label or nucleus already discarded.
        if (nucleus_props is None) or (nucleus_props['valid'] == False):
            continue

        # An isolated nucleus (falling in the background) can be discarded.
        if len(nucleus_props['users']) == 0:
            nucleus_props['valid'] = False
            continue

        # Nucleus that participates in only one cell (fragmented nucleus, stable cell, ...)
        if len(nucleus_props['users']) == 1:
            cell_lbl  = list(nucleus_props['users'])[0][0]
            cell_ppts = cell_to_nuclei[cell_lbl]

            if not cell_ppts['valid']: # The only cell it participates in is not valid.
                nucleus_props['valid'] = False
                continue

            if (cell_ppts['owner'] != 0):
                if (cell_ppts['stable']): # The cell already has an owner: we are on a fragmented nucleus
                    cell_ppts['valid']  = False
                    cell_ppts['stable'] = False
                    continue
                else: # There was simply another nucleus intersecting before
                    nucleus_to_cells[cell_ppts['owner']]['used'] -= 1

            cell_ppts['owner']  = nucleus_lbl
            cell_ppts['stable'] = True
            cell_ppts['center'] = True
            nucleus_props['used'] += 1

        # There are several cells overlaping with this nucleus
        else:
            main_cell = nucleus_props['at']
            for cell_lbl, count in nucleus_props['users']:
                cell_ppts = cell_to_nuclei[cell_lbl]

                if cell_ppts['stable'] or cell_ppts['center']:
                    continue

                if cell_ppts['owner'] > 0:
                    nucleus_to_cells[cell_ppts['owner']]['used'] -= 1

                cell_ppts['owner']  = nucleus_lbl
                nucleus_props['used'] += 1
                cell_ppts['center'] = (cell_lbl == main_cell)

    for nucleus_lbl, nucleus_props in enumerate(nucleus_to_cells): # Droping nuclei participating in 0 or more than 2 cells.
        if nucleus_props is None:
            continue
        if nucleus_props['used'] > 2:
            for user, count in nucleus_props['users']:
                if cell_to_nuclei[user]['owner'] == nucleus_lbl:
                    cell_to_nuclei[user]['owner'] = 0

            nucleus_props['used'] = 0
            usages = sorted(list(nucleus_props['users']), key=lambda x: x[1])

            cell1, count1 = usages[0]
            cell_to_nuclei[cell1]['owner'] = nucleus_lbl
            nucleus_props['used'] += 1

            cell2, count2 = usages[1]
            if count2 >= 0.5 * count1:
                cell_to_nuclei[cell2]['owner'] = nucleus_lbl
                nucleus_props['used'] += 1
            # nucleus_props['valid'] = False

    return labeled_cells, labeled_nuclei, graph, cell_to_nuclei, nucleus_to_cells

def segment_nuclei(labeled_yeasts, stack_fluo_nuclei, threshold_coverage):
    # Segmentation of nuclei
    flattened_nuclei, labeled_nuclei = nuclei_from_fluo(stack_fluo_nuclei)
    # Adjacency graph of cells
    graph = adjacency_graph(labeled_yeasts)
    # Attributing each nucleus to a cell, and cleaning non-senses (cell with several nuclei, ...).
    labeled_cells, labeled_nuclei, graph, cell_to_nuclei, nucleus_to_cells = assign_nucleus(labeled_yeasts, labeled_nuclei, threshold_coverage, graph)
    # Merging cells in division phase and cleaning
    ypg = YeastsPartitionGraph(graph, cell_to_nuclei, nucleus_to_cells, labeled_yeasts, labeled_nuclei)

    # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    # viewer.layers['labeled-cells-test'].data  = labeled_yeasts
    # viewer.layers['labeled-nuclei-test'].data = labeled_nuclei

def main():
    print("It works!")

import time

stamps = []
for i in range(1):
    start = time.time()
    main()
    stamps.append(time.time() - start)

"""
TODO

- [ ] Retirer tout ce qui touche les bordures de l'image (cellules plus les noyaux associés).
- [ ] Intégrer le code expérimental dans l'application.
- [ ] Fonction de vérification de la non-orientation d'un graphe.
- [ ] Calculer la distance entre chaque spot et le noyau.
- [ ] Écrire les tests unitaires.
- [ ] Retirer les cellules qui n'ont toujours pas de noyau après la phase de couplage.
- [ ] Dans l'export de graphe, afficher en faible alpha les cellules qui vont être discarded.
- [ ] Rajouter des labels qui se touchent que par des diagonales dans les "mock-labeled-cells".
- [ ] Essayer d'ajouter une heuristique sur les edges pour déterminer le meilleur candidat s'il y a plusieurs choix possibles (aire de contact, changement du profil de couleur, ...) ?
- [ ] Ajouter une image de Florence et une image de Kseniya au testing set pour check que les 2 workflows fonctionnent.
- [ ] Comment le thresholding avec Otsu varie selon la densité des cellules sur la lame ?
- [ ] Est-ce que remplir les trous du masque de base des noyaux ne pourrait pas être utile à la sortie de 'nuclei_from_fluo' ?
- [ ] Il doit être possible d'accélérer la création du graphe en faisant la moyenne des pixels de chaque intensité vus plutôt qu'en utilisant les regionprops.
- [ ] Est-ce qu'il existe des cas où l'érosion peut modifier le résultat du graphe ?
- [ ] (voir 'problem_01') Certains noyaux peuvent chevaucher plusieurs cellules, qu'en faire ?
- [ ] Garder dans une variable caché la segmentation des cellules à chaque étape pour ne pas avoir à resegmenter si l'utilisateur veut tester les settings.

"""

"""
NOTE

- Nuclei shouldn't (can't?) be agregated together, so a simple thresholding is enough to distinguish them. In the case several of them could
  be bunched togethern, the "typical workflow" (LoG > maxima > watershed) can't be used since divising cells' nuclei are butterfly-shaped.

"""


import quart.flask_patch
from flask_wtf import FlaskForm
from flask_bootstrap import Bootstrap
from wtforms import StringField, SubmitField, TextAreaField, HiddenField, IntegerField, SelectField, BooleanField, SelectMultipleField
from wtforms.validators import DataRequired, NumberRange
from quart import Quart, render_template, send_file, safe_join, url_for, redirect, flash, request, abort

import asyncio
from pathlib import Path
import os
from hashlib import shake_128
import random

from heavenly.host import Host
from heavenly.notify import DiscordNotifier
from heavenly.config.app import APP_NAME, SERVER_ADDRESS, MOTD, HOST_ROOT_PATH, HOST_PORT_RANGE, SECRET_KEY, SRC_REPO_URL
from heavenly.maps import MAP_THUMBNAIL_DIR
from heavenly.mods import MOD_ICON_DIR

bootstrap = Bootstrap()
app = Quart(__name__)
bootstrap.init_app(app)

app.config.update({
  "APP_NAME": APP_NAME,
  "SERVER_ADDRESS": SERVER_ADDRESS,
  "MOTD": MOTD,
  "map_choices": [("random", "Random")],
  "mod_choices": [],
  "SECRET_KEY": SECRET_KEY,
  "SRC_REPO_URL": SRC_REPO_URL
})

app.jinja_env.globals.update(app.config)

@app.errorhandler(404)
async def page_not_found(error):
  return "404 - page not found"

@app.route("/")
async def index():
  host = app.config.get('host_instance')
  game_info = []
  for game in host.games:
    game_info.append(dict(
      name = game.name,
      state = game.state,
      turn = game.turn,
      finished = game.finished,
      port = game.settings["port"]
    )
  )
  return await render_template("home.html", game_info = game_info)

@app.route("/new-game", methods = ["GET", "POST"])
async def new_game():
  form = NewGameForm()
  if form.validate_on_submit():
    host = app.config.get("host_instance")
    mapfile = None if form.mapfile.data == "random" else form.mapfile.data
    mods = form.mods.data
    thrones = [form.lvl1_thrones.data, form.lvl2_thrones.data, form.lvl3_thrones.data]

    config = {"era": form.era.data,
              "port": host.get_free_port(),
              "mapfile": mapfile,
              "enablemod": mods,
              "magicsites": form.magicsites.data,
              "indepstr": form.indepstr.data,
              "richness": form.richness.data,
              "resources": form.resources.data,
              "recruitment": form.recruitment.data,
              "supplies": form.supplies.data,
              "startprov": form.startprov.data,
              "eventrarity": form.eventrarity.data,
              "thrones": thrones,
              "globals": form.global_enchants.data,
              "requiredap": form.requiredap.data,
              "cataclysm": form.cataclysm.data,
              "hofsize": form.hofsize.data,
              "noartrest": not form.artrest.data,
              "research": form.research.data,
              "norandres": not form.randres.data,
              "nostoryevents": True if form.storyevents.data == "none" else False,
              "storyevents": True if form.storyevents.data == "some" else False,
              "allstoryevents": True if form.storyevents.data == "all" else False,
              "scoregraphs": True if form.scoregraphs.data == "always visible" else False,
              "nonationinfo": True if form.scoregraphs.data == "never visible" else False,
              "teamgame": form.teamgame.data,
              "nocheatdet": not form.cheatdet.data,
              "renaming": form.renaming.data
    }
    notifiers = ([DiscordNotifier(webhook_url = form.notifier.data)]
                if form.notifier.data else None
    )
    name = form.name.data.replace(" ", "_")
    if host.find_game_by_name(name):
      await flash("A game by that name already exists.")
      return redirect(url_for("index"))
    new_game = host.create_new_game(name, notifiers, **config)
    asyncio.create_task(new_game.run_until_cancelled())
    port = config["port"]
    address = f"{SERVER_ADDRESS}:{port}"
    await flash(
      "The Wheel has turned once again. "
      f"Your game will be available at {address} soon."
    )
    return redirect(url_for("index"))

  return await render_template("new_game.html", form = form)

@app.route("/games/<name>")
async def game_status(name):
  host = app.config.get('host_instance')
  game_instance = host.find_game_by_name(name)
  if not game_instance: abort(404)

  players = []
  for player in game_instance.players:
    if player["eliminated"]: turn = "eliminated"
    else:
      turn = "unknown"
      connected = False
      for _tuple in game_instance.who_played:
        if _tuple[0] == player["shortname"]:
          turn = _tuple[1]
          connected = _tuple[2]
    players.append((player["name"], turn, connected))

  time = Dom5Time(game_instance.turn)

  return await render_template(
    "game.html",
    game = game_instance,
    players = players,
    time = time
  )

@app.route("/games/<name>/<passcode>")
async def game_admin(name, passcode):
  host = app.config.get("host_instance")
  game_instance = host.find_game_by_name(name)
  if not game_instance: abort(404)
  if passcode == passcode(game_instance):
    return "Access granted!!"
  else:
    abort(404)

@app.route("/maps")
async def map_directory():
  host = app.config.get("host_instance")
  maps = host.maps
  return await render_template("maps.html", maps = maps)

@app.route("/mods")
async def mod_directory():
  host = app.config.get("host_instance")
  mods = host.mods
  return await render_template("mods.html", mods = mods)

@app.route("/thumb/<filename>")
async def get_map_thumb(filename):
  path = safe_join(MAP_THUMBNAIL_DIR, filename)
  return await send_file(path)

@app.route("/icon/<filename>")
async def get_mod_icon(filename):
  path = safe_join(MOD_ICON_DIR, filename)
  return await send_file(path)

@app.route("/rand")
async def random_nation():
  host = app.config.get("host_instance")
  era = int(request.args.get("era", default = 1))
  if not era or era not in (1, 2, 3): era = 1
  era_name = ("early", "middle", "late")[era-1]
  nation = random.choice(list(host.nations[era].values()))
  return await render_template(
    "random_nation.html",
    nation = nation,
    era_name = era_name
  )

@app.before_serving
async def startup():
  host = Host(HOST_ROOT_PATH, port_range = HOST_PORT_RANGE)
  host.restore_games()
  asyncio.create_task(host.startup())
  map_choices = app.config.get("map_choices")
  map_choices.extend([(_map.filename, _map.title) for _map in host.maps])
  mod_choices = app.config.get("mod_choices")
  mod_choices.extend([(mod.filename, mod.title) for mod in host.mods])
  app.config.update(host_instance = host, map_choices = map_choices)

@app.after_serving
async def shutdown():
  app.config["host_instance"].shutdown()

class NewGameForm(FlaskForm):
  map_choices = app.config.get("map_choices")
  mod_choices = app.config.get("mod_choices")

  int_style = dict(style = "width: 12%", maxlength = 3)
  select_style = dict(style = "width: 40%")
  string_style = dict(style = "width: 50%", maxlength = 24)

  # ??? why did i write this ???
  within_range = lambda lower, upper: NumberRange(
    min = lower, max = upper
    )

  # Game Settings
  name = StringField("Enter a game name:",
    render_kw = string_style, validators = [DataRequired()]
  )
  era = SelectField("Choose an era:", coerce = int, render_kw = select_style,
    choices = [
    ("1", "early"),
    ("2", "middle"),
    ("3", "late")
    ]
  )
  clustered = None
  closed = None

  mapfile = SelectField("Choose a map:",
    render_kw = select_style, choices = map_choices
    )

  mods = SelectMultipleField("Choose mods to enable:",
    render_kw = select_style, choices = mod_choices
    )

  randmap = IntegerField(
    "Provinces per player (only applicable to random maps):",
    default = 15, render_kw = int_style
    )

  # World Settings
  magicsites = IntegerField("Magic site frequency: (0-75)",
    default = 50, render_kw = int_style, validators = [within_range(0, 75)]
    )
  indepstr = IntegerField("Strength of independents: (0-9)",
    default = 5, render_kw = int_style, validators = [within_range(0, 9)]
    )
  richness = IntegerField("Province income multiplier: (50-300)",
    default = 100, render_kw = int_style, validators = [within_range(50, 300)]
    )
  resources = IntegerField("Resource multiplier: (50-300)",
    default = 100, render_kw = int_style, validators = [within_range(50, 300)]
    )
  recruitment = IntegerField("Recruitment points multiplier: (50-300)",
    default = 100, render_kw = int_style, validators = [within_range(50, 300)]
    )
  supplies = IntegerField("Supplies multiplier: (50-300)",
    default = 100, render_kw = int_style, validators = [within_range(50, 300)]
    )
  startprov = IntegerField("Starting provinces per player: (1-9)",
    default = 1, render_kw = int_style, validators = [within_range(1, 9)]
    )

  # Divine Rules
  eventrarity = SelectField("Event rarity:", render_kw = select_style,
    choices = [(1, "common"), (2, "rare")]
    )
  global_enchants = IntegerField("Global enchantment slots: (3-9)",
    default = 5, render_kw = int_style, validators = [within_range(3, 9)]
    )
  lvl1_thrones = IntegerField("Number of level 1 thrones: (0-20)",
    default = 3, render_kw = int_style, validators = [within_range(0, 20)]
    )
  lvl2_thrones = IntegerField("Number of level 2 thrones: (0-15)",
    default = 0, render_kw = int_style, validators = [within_range(0, 15)]
    )
  lvl3_thrones = IntegerField("Number of level 3 thrones: (0-10)",
    default = 0, render_kw = int_style, validators = [within_range(0, 10)]
    )
  requiredap = IntegerField(
    "Ascension points to win:", default = 3, render_kw = int_style
    )
  cataclysm = IntegerField("Turns until Cataclysm: (0-999) (0 disables)",
    default = 0, render_kw = int_style, validators = [within_range(0, 999)]
    )
  hofsize = IntegerField("Hall of fame size: (5-15)",
    default = 10, render_kw = int_style, validators = [within_range(5, 15)]
    )
  research = IntegerField("Research difficulty: (0-4)",
    default = 2, render_kw = int_style, validators = [within_range(0, 4)]
    )
  storyevents = SelectField("Story events:", render_kw = select_style,
    choices = ["all", "some", "none"]
    )
  scoregraphs = SelectField("Score graphs:", render_kw = select_style,
    default = "default behavior",
    choices = ["always visible", "default behavior", "never visible"]
    )
  teamgame = BooleanField("Disciple game")
  artrest = BooleanField("Restrict players to one artifact per turn",
    default = True
    )
  randres = BooleanField("Enable random starting research",
    default = True
    )
  cheatdet = BooleanField("Enable cheat detection", default=True)
  renaming = BooleanField("Enable renaming commanders")
  masterpass = None

  # Notifications
  notifier = StringField(
    "To enable Discord turn notifications, enter a Discord webhook URL:",
    render_kw = dict(maxlength = 200)
  )

  submit = SubmitField("Submit new game")

class Dom5Time:

  def __init__(self, turn):
    self.season = (("early", "", "late")[turn % 3], ("spring", "summer", "fall", "winter")[(turn // 3) % 4])
    self.year = turn // 12
    self.month = (turn + 1) % 12
    self.turn = turn

  def __str__(self):
    return f"{self.season[0]} {self.season[1]} in the year {self.year} of the Ascension Wars (turn {self.turn})"

def passcode(game):
  return shake_128((SECRET_KEY + game.name).encode("utf8")).hexdigest(8)


__author__ = 'Nyall Dawson'
__date__ = 'February 2019'
__copyright__ = '(C) 2019, Nyall Dawson'

from qgis.PyQt.QtCore import QCoreApplication
from qgis.core import QgsProcessingAlgorithm, QgsProcessing, QgsApplication
from qgis.utils import iface

from processing.gui.ContextAction import ContextAction
from processing.script.ScriptEditorDialog import ScriptEditorDialog

class ExportModelAsPythonScriptAction(ContextAction):

    def __init__(self):
        super().__init__()
        self.name = QCoreApplication.translate('ExportModelAsPythonScriptAction', 'Export Model as Python Algorithm…')

    def isEnabled(self):
        return isinstance(self.itemData, QgsProcessingAlgorithm) and self.itemData.provider().id() in ("model", "project")

    def icon(self):
        return QgsApplication.getThemeIcon('/mActionSaveAsPython.svg')

    def execute(self):
        alg = self.itemData
        dlg = ScriptEditorDialog(parent=iface.mainWindow())

        dlg.editor.setText('\n'.join(alg.asPythonCode(QgsProcessing.PythonQgsProcessingAlgorithmSubclass, 4)))
        dlg.show()


from json import load as json_load
import importlib.resources

成语数据 = None

def 初始化():
    global 成语数据
    with importlib.resources.open_text("chinese_characters_words.数据", "成语.json") as 文件:
        成语数据 = json_load(文件)

# API
def 查成语(词):
    if 成语数据 == None:
        初始化()

    for 词数据 in 成语数据:
        if 词 == 词数据['word']:
            信息 = {}
            信息['词'] = 词数据['word']
            信息['释义'] = 词数据['explanation']
            信息['例句'] = 词数据['example']
            信息['渊源'] = 词数据['derivation']
            信息['拼音'] = 词数据['pinyin']
            信息['缩写'] = 词数据['abbreviation']
            return 信息

def 包含(部分):
    if 成语数据 == None:
        初始化()

    所有成语 = []
    for 成语 in 成语数据:
        if (成语['word'].__contains__(部分)):
            所有成语.append(成语['word'])
    return 所有成语

# print(查成语('一石二鸟'))
# print(包含('精神'))


# PURPOSE: for test use, load data(output_data/each_object/output_test_1_1.csv) only once

from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, Activation
from tensorflow.keras.layers import LSTM
from tensorflow.keras.optimizers import Adam
from tensorflow.keras.callbacks import EarlyStopping
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd

import glob

N_TIME = 10
N_INPUT = 4
n_sample = 1024

datalist_tmp = glob.glob("output_data/each_object/output_test_1_1.csv")
# #### input data (m, 4)
df_input = pd.read_csv("output_data/each_object/output_test_1_1.csv", index_col=0)
df_input = df_input.drop(["time", 'id', 'class'], axis=1)
np_input = df_input.to_numpy()
np_input = np_input[1:]
n_sample_1_1 = np_input.shape[0] - N_TIME + 1
input_data_1_1 = np.zeros((n_sample_1_1, N_TIME, N_INPUT))

# print("np_input", np_input[0:0+N_TIME].shape)
# print("np_input", np_input.shape)
# print("input_data_1_1", input_data_1_1)
print("input_data_1_1", input_data_1_1.shape)
# #### correct data (m, 1)
df_correct = pd.read_csv("output_data/annotation/annotation_1_1.csv", index_col=0)
df_correct = pd.read_csv("output_data/annotation/annotation_1_1.csv", index_col=0)
np_correct = df_correct.to_numpy()
np_correct = np_correct[1:]
correct_data_1_1 = np.zeros((n_sample_1_1, 1))

for i in range(n_sample_1_1):
    input_data_1_1[i] = np_input[i:i+N_TIME]
    correct_data_1_1[i] = np_correct[i:i+1]

print("correct_data_1_1", correct_data_1_1.shape)

test= np.zeros((n_sample_1_1, N_TIME, N_INPUT))
test2 = np.concatenate([test, input_data_1_1])
print("test", test2.shape)

# n_sample = 1024
# n_time = 10
# input_data = np.zeros((n_sample, n_time, 1)) # 入力
# correct_data = np.zeros((n_sample, 1)) # 正解
# print("input_data", input_data.shape)
# print("correct_data", correct_data.shape)
# for i in range(n_sample):
#     input_data[i] = sin_y[i:i+n_time].reshape(-1, 1)
#     correct_data[i] = sin_y[i+n_time:i+n_time+1] # 正解は入力よりも一つ後


# 1043

# 특정 원소가 속한 집합 찾기
def find(parent, x):
    if parent[x] != x:
        parent[x] = find(parent, parent[x])
    return parent[x]

# 두 원소 합치기
def union(parent, a, b):
    a = find(parent, a)
    b = find(parent, b)
    if a < b:
        parent[b] = a
    else:
        parent[a] = b

n, m = map(int, input().split())    # n:사람수, m:파티수
true = list(map(int, input().split())) # 진실을 아는 사람수, 그 사람의 대한 번호
t = true[0] # 진실을 아는 사람수
del true[0]
result = 0

party = []  # 각 파티에 대한 정보 담을 리스트
for i in range(m):
    party.append(list(map(int, input().split())))
    del party[i][0]     # 각 파티에 첫 번째원소(사람수) 삭제

parent = [i for i in range(n + 1)]

for i in range(m):
    a = party[i][0]     # i번째 파티의 1번째 사람
    for j in range(1, len(party[i])):   # i번째 파티의 사람 수 만큼 반복(len(party[i]): 각각의 파티의 길이)
        union(parent, a, party[i][j])   # 각 파티에 참여한 사람들을 1개의 그룹으로 만들기

for i in range(m):
    check = True
    a = party[i][0]
    for j in range(len(true)):    # 진실을 아는 사람 수 만큼 반복
        # 각 파티의 루트 노드와 진실을 아는 사람들의 루트 노드가 같다면 과장 할 수 X
        if find(parent, a) == find(parent, true[j]):
            check = False
            break
    # 모두 다른 경우
    if check:
        result += 1

print(result)

"""
파티에 참석한 사람들을 1개의 집합으로 생각하고, 각각의 파티마다 union연산을 이용해 사람들을 연결
find연산을 이용해 각 파티의 루트 노드와 진실을 아는 사람들이 같은 그룹에 있는지 확인
"""


"""
https://leetcode.com/problems/binary-tree-level-order-traversal-ii/
"""

from typing import List

from test_helper import TreeNode

class Solution:
    def levelOrderBottom(self, root: TreeNode) -> List[List[int]]:
        if not root:  # Empty tree.
            return []

        nodes, rslt = [root], []
        while nodes:
            nextNodes, values = [], []
            for node in nodes:
                if node.left:
                    nextNodes.append(node.left)

                if node.right:
                    nextNodes.append(node.right)

                values.append(node.val)

            rslt.append(values)
            nodes = nextNodes

        return rslt[::-1]


#!/usr/bin/python3

import numpy as np
from scipy import interpolate

def FirstInperlotation(filename, a0, b0, index):
    #Load the impedance file
    Impedance = np.loadtxt(filename)

    #Gets the component for different poisson's ratio.
    K25 = np.transpose(Impedance[:, index[ 0: 5]])
    K35 = np.transpose(Impedance[:, index[ 5:10]])
    K45 = np.transpose(Impedance[:, index[10:15]])

    # Data axes
    x0 = Impedance[:, 0]
    y0 = np.array([0.1, 0.25, 0.50, 1.0, 2.0])

    #Create interpolator
    Fun_25 = interpolate.interp2d(x0, y0, K25, kind='linear')
    Fun_35 = interpolate.interp2d(x0, y0, K35, kind='linear')
    Fun_45 = interpolate.interp2d(x0, y0, K45, kind='linear')

    #Interpolate the values
    z0 = Fun_25(a0, b0)
    z1 = Fun_35(a0, b0)
    z2 = Fun_45(a0, b0)

    z = np.array([z0, z1, z2])

    return z

def SecondInterpolation(b, nu):
    #Solves a linear system.
    A = np.array([[1.0, 0.25, 0.25**2], [1.0, 0.35, 0.35**2], [1.0, 0.45, 0.45**2]]);
    x = np.linalg.solve(A, b)

    #Interpolate for Foisson's ratio.
    z = x[0] + x[1]*nu + x[2]*nu**2

    return z

def ComputeImpedance(filename, a0, b0, nu):
    #Computes real part
    index = range(1,30,2)
    zp    = FirstInperlotation(filename, a0, b0, index)
    kij   = SecondInterpolation(zp, nu)

    #Computes imaginary part
    index = range(2,31,2)
    zp    = FirstInperlotation(filename, a0, b0, index)
    cij   = SecondInterpolation(zp, nu)

    Impedance = np.array([kij, cij])

    return Impedance

#INPUTS
hb = 15.0
Tb = 0.50
B  = 40.0
D  = 27.0
Vs = 250
f0 = 2.0
nu = 0.4275

#DIMENSIONLESS VECTOR
PI = np.array([B/Vs/Tb, hb/B, D/B, nu, f0*B/Vs])
print(PI)

#DIMENIONLESS FREQUENCY
a0 = 1.111 #model.predict(PI)

kxx = ComputeImpedance("Normalized_Impedace_Functions/Kxx.txt", a0, PI[2], PI[3])
kxt = ComputeImpedance("Normalized_Impedace_Functions/Kxt.txt", a0, PI[2], PI[3])
ktt = ComputeImpedance("Normalized_Impedace_Functions/Ktt.txt", a0, PI[2], PI[3])

print(kxx)
print(kxt)
print(ktt)

#[[ 0.72240007]
# [ 1.70080473]]
#[[ 0.13824467]
# [ 0.48635204]]
#[[ 1.28825378]
# [ 1.02496305]]


import numpy as np
import matplotlib.pyplot as plt
from hw5 import *

def gradientDescentStep(f, g, x):
	delta_x = -g(x)
	t = 1.0
	alpha = 0.3
	beta = 0.5
	while (f(x + t * delta_x) > f(x) + alpha * t * np.dot(g(x), delta_x)):
		t = beta * t
	x_new = x + t * delta_x
	return x_new

def f(y):
	x = np.arange(-1.25, 1.5, 0.25)
	k_vel = 10.0
	k_obs = 0.1
	y1 = [0]+list(y)+[0]
	sumOfDiff = 0.0
	for i in range(1, 13):
	 	sumOfDiff += (y1[i] - y1[i-1])**2

	sumfObs = 0.0
	for i in range(1, 12):
	 	sumfObs += fObs([x[i-1], y1[i]])

	res = (k_vel * sumOfDiff / 2) + (k_obs * sumfObs)
	return res

def g(y):
	x = np.arange(-1.25, 1.5, 0.25)
	k_vel = 10
	k_obs = 0.1
	y1 = [0]+list(y)+[0]
	res = np.zeros(11)
	for i in range(1,12):
		res[i-1] = k_vel * (-1 * y1[i-1] + 2 * y1[i] - y1[i+1]) + k_obs * (gObs([x[i-1], y1[i]]))[1]

	return res

def Htilde():
	k_vel = 10
	H = np.zeros((11,11))
	for i in range(0, 11):
		if i == 10:
			H[i][i] = 2
		else:
			H[i][i] = 2
			H[i][i+1] = -1
			H[i+1][i] = -1
	return k_vel *  H

def steepestDescentStep(f, g, P, x):
	delta_x = - np.linalg.inv(P) @ g(x)
	t = 1.0
	alpha = 0.3
	beta = 0.5
	while (f(x + t * delta_x) > f(x) + alpha * t * np.dot(g(x), delta_x)):
		t = beta * t
	x_new = x + t * delta_x
	return x_new


'''
需求：

1. 要求将所有级别的所有日志都写入磁盘文件中
2. all.log文件中记录所有的日志信息，日志格式为：日期和时间 - 日志级别 - 日志信息
3. err.log文件单独记录error及以上级别的日志信息，日志格式为： 日期和时间 - 日志级别 - 文件名[:行号] - 日志信息
4 要求all.log在每天凌晨进行日志切割

分析：

1. 要记录所有级别的日志，因此日志器的有效level需要设置为最低级别-debug
2. 日志需要被发送到两个不同的目的地，因此需要为日志器设置两个handler，两个目的地都是磁盘文件，因此这两个handler都是与FileHandler
3. all.log要求按照时间进行日志分割，因此需要用logging.handler.TimeRotatingFileHandler;而error.log没有要求日志切割
4. 两个日志文件的格式不同，因此需要对这两个handler分别设置格式器
'''

import logging
import logging.handlers
import datetime

#定义logger
logger = logging.getLogger('log01')
logger.setLevel(logging.DEBUG)

rf_handler = logging.handlers.TimedRotatingFileHandler('all.log',when='midnight',interval=1, backupCount=7)
rf_handler.setFormatter(logging.Formatter('%(asctime)s - %(levelname)s - %(message)s'))

f_handler = logging.FileHandler('error.log')
f_handler.setLevel(logging.ERROR)
f_handler.setFormatter(logging.Formatter('%(asctime)s - %(levelname)s - %(filename)s[:%(lineno)d] - %(message)s'))

logger.addHandler(rf_handler)
logger.addHandler(f_handler)

logger.debug('我是debug')
logger.error('错误')


import logging
import threading
from flask import Flask

from app.config import Config as config_class, create_credentials_json, start_logger
from app.exceptions import CustomException, handle_custom_exception
from app.scrappers.company_csv.main import company_orchestrator
from app.scrappers.g2crowd.main import g2crowd_orchestrator
from app.scrappers.google_drive.main import google_drive_orchestrator

app = Flask(__name__)
app.config.from_object(config_class)
start_logger()
create_credentials_json()

logging.info("Starting application")

app.register_error_handler(CustomException, handle_custom_exception)

logging.info("Starting threads")

company_thread = threading.Thread(
    target=company_orchestrator,
    args=("united states", "companies_input.csv"),
    name="CompanyThread",
)
crowd2url_thread = threading.Thread(target=g2crowd_orchestrator, name="Crowd2UrlThread")
# Define your natural language query
NATURAL_QUERY = "FILENAME Currículo, TEXT Guedes"
google_drive_thread = threading.Thread(
    target=google_drive_orchestrator,
    args=(NATURAL_QUERY,),
    name="GoogleDriveThread",
)
company_thread.start()
crowd2url_thread.start()
google_drive_thread.start()


from sys import argv, exit
import csv

if len(argv) != 3:

    print("missing files, need cvs file and dna seq textfile")
    exit(1)

f = open(argv[1])
dna = argv[2]

seq = f.read()

if seq[0:4] == dna:
    print("found")

print(seq)


import numpy
import itertools
import math

def cost(leftarr, rightarr, numbs):
    N = len(leftarr)
    costs = 0
    for i in range(N):
        costleft = leftarr[numbs[i]]
        costright = rightarr[numbs[i]]
        for j in range(N):
            costs = costs + costleft * j + costright * (N - j - 1)
    return costs

T = int(input())
for tc in range(T):
    N = int(input())
    left = list(map(int, input().split()))
    right = list(map(int, input().split()))
    costs = numpy.zeros((N, N), int)
    for i in range(N):
        for j in range(N):
            costs[i][j] = left[i] * j + right[i] * (N - j - 1)
    i = 0
    mimim = math.inf
    for perm in itertools.permutations(list(range(N))):
        #print(perm)
        permutlist = list(perm)
        summat = 0
        for k in range(N):
            summat = summat + costs[permutlist[k]][k]
            if summat > mimim: break
        if mimim > summat: mimim = summat
        i = i + 1
    print(costs)
    print(mimim)


import html
from typing import Any, Callable, Dict, Hashable
from urllib.parse import urlparse

from loguru import logger

from eddrit import models
from eddrit.reddit.content_parser import video_parsers
from eddrit.utils.urls import get_domain_and_suffix_from_url

def _post_is_an_imgur_gif(api_post_data: Dict[Hashable, Any]) -> bool:
    """Check if a post is an imgur gif by checking domain and url file extension."""
    return (
        get_domain_and_suffix_from_url(api_post_data["domain"]) == "imgur.com"
        and ".gif" in api_post_data["url"]
    )

def post_has_video_content(api_post_data: Dict[Hashable, Any]) -> bool:
    """Check if a post is a video."""

    # Special case for imgur.com images as links
    if _post_is_an_imgur_gif(api_post_data):
        return True

    if api_post_data.get("secure_media"):
        return True

    if "preview" in api_post_data:
        if api_post_data["preview"].get("reddit_video_preview"):
            return True

        variants = api_post_data["preview"]["images"][0].get("variants")

        if variants and variants.get("mp4"):
            return True

    return False

def get_post_image_content(
    api_post_data: Dict[Hashable, Any]
) -> models.LinkPostContent | models.PicturePostContent:
    """
    Get the image content of a post.
    Fallback to link post if errors encountered in pictures.
    """
    try:
        picture_url = html.unescape(
            api_post_data["preview"]["images"][0]["source"]["url"]
        )
        return models.PicturePostContent(
            picture=models.PostPicture(
                url=picture_url,
                width=api_post_data["preview"]["images"][0]["source"]["width"],
                height=api_post_data["preview"]["images"][0]["source"]["height"],
            )
        )
    except Exception:
        return models.LinkPostContent()

def get_post_gallery_content(
    api_post_data: Dict[Hashable, Any]
) -> models.LinkPostContent | models.GalleryPostContent:
    """
    Get the gallery content of a post.
    Fallback to link post if errors encountered in pictures.
    """
    try:
        # Get pictures
        pictures = [
            _get_gallery_picture(item)
            for item in api_post_data["media_metadata"].values()
        ]

        return models.GalleryPostContent(pictures=pictures)
    except Exception:
        return models.LinkPostContent()

def _get_gallery_picture(picture_api_data: dict[str, Any]) -> models.PostPicture:
    # Get width and height
    width = picture_api_data["s"]["y"]
    height = picture_api_data["s"]["x"]

    # Get direct URL by switching domain and removing query parameters
    old_url = urlparse(picture_api_data["s"]["u"])
    new_url = f"{old_url.scheme}://i.redd.it{old_url.path}"

    return models.PostPicture(width=width, height=height, url=new_url)

def get_post_video_content(
    api_post_data: Dict[Hashable, Any]
) -> models.VideoPostContent | models.LinkPostContent | models.EmbedPostContent:
    """
    Get the video content of a post.
    Fallback to image or link post if errors encountered in videos.
    """
    try:
        # Check all parsers
        parsers: list[Callable[[dict], models.PostVideo | models.EmbedPostContent]] = [
            video_parsers.get_embed_content,
            video_parsers.get_external_video,
            video_parsers.get_secure_media_reddit_video,
            video_parsers.get_reddit_video_preview,
        ]

        post_domain = get_domain_and_suffix_from_url(api_post_data["domain"])

        # Special case for some embeds
        domains_with_special_embed_handling = (
            video_parsers.get_domains_with_special_embed_handling()
        )
        if post_domain in domains_with_special_embed_handling:
            parsers.append(domains_with_special_embed_handling[post_domain])

        parsed_results: list[models.PostVideo | models.EmbedPostContent] = []
        for parser in parsers:
            try:
                parsed_item = parser(api_post_data)
                parsed_results.append(parsed_item)
            except Exception:  # noqa: PERF203
                logger.debug(f"Cannot parse content with {parser}")
                continue

        # Sort: best resolution + non-embed first
        parsed_results.sort(
            key=lambda x: (x.width + x.height, type(x) != models.EmbedPostContent),
            reverse=True,
        )

        # If we cannot parse anything, put a link
        if not parsed_results:
            logger.debug(
                f"Couldn't find media for {api_post_data['permalink']}, fallbacking to link"
            )
            return models.LinkPostContent()

        # Pick best content
        logger.debug(
            f"Media parsed for {api_post_data['permalink']} : {parsed_results}"
        )

        # If the best content is an embed, just return it as the frontend
        # doesn't handle mix of embed and non embed sources
        best_content = parsed_results[0]
        if type(best_content) == models.EmbedPostContent:
            return best_content

        # Else return the list of non-embed sources
        return models.VideoPostContent(
            videos=[item for item in parsed_results if type(item) != models.EmbedPostContent]  # type: ignore
        )

    except Exception:
        logger.exception(
            f"Post \"{api_post_data['title']}\": could not parse video content, falling back to link"
        )
        return models.LinkPostContent()


test = int(input())
for i in range(test):
    case = input()
    arr = [int(char) for char in case.split()]
    new_arr = sorted(arr)
    largest = new_arr[len(new_arr) - 1]
    ans = []
    i = 0
    if(arr[0]== arr[1] == arr[2]):
        ans = ['1','1','1']
    elif(arr.count(largest)>1):
        while(i < len(arr)):
            if(arr[i] == largest):
                ans.append(str(1))
            else:
                ans.append(str((largest-arr[i])+1))
            i+=1
    else:
        while(i<len(arr)):
            if(arr[i]<largest):
                ans.append(str((largest-arr[i]) + 1))
            else:
                ans.append(str(0))
            i+=1
    printer = ' '.join(map(str, ans))
    print(printer)


import BoardsetUp
import turtle
import FileHandler
from inspect import currentframe, getframeinfo
import sys
cf = currentframe()
filename = getframeinfo(cf).filename
GameOver = False
Board, wn, Kl, Pieces,SquareSize,BoardSize = BoardsetUp.Run()
if Kl[0] ==[0,0,"white"] or [0,0,"black"] == Kl[1]:
    FileHandler.Logs.append(FileHandler.Log("Errors", filename + "/" + str(cf.f_lineno),("One of the Kings could not be located in the config file. Please place the king on a square")))

AnimatedSquares = []
PPM =[]
Selected = [0,0]
Turn = "white"

WhiteKingMove = False
WhiteRookLongMove = False
WhiteRookShortMove = False

BlackKingMove = False
BlackRookLongMove = False
BlackRookShortMove = False

Castle = False

def changeTurn():
    global Turn
    if Turn == "white":
        Turn = "black"
    else:
        Turn = "white"
"""
=======================

=======================
Check and check mate
=======================
"""
def checkCheckMate():
    global Turn
    if Turn == "white":
        KingLocation = [Kl[0][0],Kl[0][1]]
    else:
        KingLocation = [Kl[1][0],Kl[1][1]]
    KingMove = PossibleMoves(Board[Kl[0][0]][Kl[0][1]][1],KingLocation[0],KingLocation[1], "Mate")
    ePM = enemyPossibleMoves()
    toPop = []
    PiecesTakingKing = []
    for i in range(len(ePM)):
        for x in range(len(ePM[i][1])):
            if KingLocation == ePM[i][1][x]:
                PiecesTakingKing.append(ePM[i])
            for y in range(len(KingMove)):
                if ePM[i][1][x] == KingMove[y]:
                    toPop.append(KingMove[y])
    for i in range(len(toPop)):
        if toPop[i] in KingMove:
            KingMove.remove(toPop[i])
    toPop = []
    fPM = friendlyPossibleMoves()
    if len(KingMove) == 0 and len(PiecesTakingKing) >1:
        return True
    elif len(PiecesTakingKing) == 1:
        PTKCOORDS = PiecesTakingKing[0][0].getCoords()
        xx = -(PTKCOORDS[0]- KingLocation[0])
        yy = -(PTKCOORDS[1]- KingLocation[1])
        for x in range(len(PiecesTakingKing[0][1])):
            if (PiecesTakingKing[0][1][x][0] - PTKCOORDS[0] < 0 and not (xx < 0)) or (PiecesTakingKing[0][1][x][1] - PTKCOORDS[1] < 0 and not (yy < 0)) :
                toPop.append(PiecesTakingKing[0][1][x])
            elif (PiecesTakingKing[0][1][x][0] - PTKCOORDS[0] == 0 and not (xx == 0)) or (PiecesTakingKing[0][1][x][1] - PTKCOORDS[1] == 0 and not (yy == 0)) :
                toPop.append(PiecesTakingKing[0][1][x])
            elif (PiecesTakingKing[0][1][x][0] - PTKCOORDS[0] > 0 and not (xx > 0)) or (PiecesTakingKing[0][1][x][1] - PTKCOORDS[1] > 0 and not (yy > 0)) :
                toPop.append(PiecesTakingKing[0][1][x])
        for i in range(len(toPop)):
            if toPop[i] in PiecesTakingKing[0][1]:
                PiecesTakingKing[0][1].remove(toPop[i])
        toPop = []
        PiecesTakingKing[0][1].pop(len(PiecesTakingKing[0][1])-1)
        LengthPieceTakingKing = len(PiecesTakingKing[0][1])
        for x in range(len(PiecesTakingKing[0][1])):
            for y in range(len(fPM)):
                for p in range(len(fPM[y][1])):
                    if fPM[y][1][p] == PiecesTakingKing[0][1][x] and fPM[y][0].getType() !="King":
                        toPop.append(PiecesTakingKing[0][1][x])
        for i in range(len(toPop)):
            if toPop[i] in PiecesTakingKing[0][1]:
                PiecesTakingKing[0][1].remove(toPop[i])
        if LengthPieceTakingKing != len(PiecesTakingKing[0][1]):
            PiecesTakingKing = []
        if len(KingMove) == 0 and len(PiecesTakingKing) > 0:
            return True
        else:
            return False
    else:
        return False
def checkCheck():
    global Turn
    check = False
    if Turn == "white":
        KingLocation = [Kl[0][0],Kl[0][1]]
    else:
        KingLocation = [Kl[1][0],Kl[1][1]]
    PiecesTakingKing = []
    ePM = enemyPossibleMoves()
    for i in range(len(ePM)):
        for x in range(len(ePM[i][1])):
            if KingLocation == ePM[i][1][x]:
                PiecesTakingKing.append(ePM[i][1][x])
    if len(PiecesTakingKing) > 0:
        check = True
    return check
def enemyPossibleMoves():
    ePM = []
    for i in range(len(Pieces)):
        if Pieces[i].getColour() != Turn:
            Coords = Pieces[i].getCoords()
            ePM.append([Pieces[i], PossibleMoves(Pieces[i], Coords[0], Coords[1], False)])
    return ePM
def friendlyPossibleMoves():
    fPM = []
    for i in range(len(Pieces)):
        if Pieces[i].getColour() == Turn:
            Coords = Pieces[i].getCoords()
            fPM.append([Pieces[i], PossibleMoves(Pieces[i], Coords[0], Coords[1], "None")])
    return fPM
"""
=======================

=======================
Moves the pieces
=======================
"""
def MovePiece(From,Too, InputBoard):
    global phantomPiece
    global WhiteKingMove
    global BlackKingMove
    global WhiteRookShortMove
    global WhiteRookLongMove
    global BlackRookLongMove
    global BlackRookShortMove
    global GameOver
    global blackPieces
    global whitePieces
    pawnPassPawn = False
    if Too == phantomPiece:
        pawnPassPawn = True
    phantomPiece = [-1,-1]
    if InputBoard[From[0]][From[1]][1] != "PPH":
        if InputBoard[From[0]][From[1]][1].getType() == "King":
            if InputBoard[From[0]][From[1]][1].getColour() == "white":
                Kl[0][0] = Too[0]
                Kl[0][1] = Too[1]
                WhiteKingMove = True
            else:
                Kl[1][0] = Too[0]
                Kl[1][1] = Too[1]
                BlackKingMove = True
        elif InputBoard[From[0]][From[1]][1].getType() == "Pawn" and abs(From[1]-Too[1]) == 2:
            if InputBoard[From[0]][From[1]][1].getColour() == "white":
                phantomPiece = [From[0],Too[1]-1]
            else:
                phantomPiece = [From[0],Too[1]+1]
        elif InputBoard[From[0]][From[1]][1].getType() == "Rook":
            if InputBoard[From[0]][From[1]][1].getCoords() == [0,0]:
                WhiteRookShortMove = True
            elif InputBoard[From[0]][From[1]][1].getCoords() == [7,0]:
                WhiteRookLongMove = True
            elif InputBoard[From[0]][From[1]][1].getCoords() == [0,7]:
                BlackRookShortMove = True
            elif InputBoard[From[0]][From[1]][1].getCoords() == [7,7]:
                BlackRookLongMove = True
        toAdd = 0
        if pawnPassPawn == True:
            if InputBoard[From[0]][From[1]][1].getColour() == "white":
                toAdd = -1
            else:
                toAdd = 1
        PieceTaken = False
        TempPieceTaken = 'A'
        if InputBoard[Too[0]][Too[1]][1] == "PPH" and pawnPassPawn == False:
            InputBoard[From[0]][From[1]][1].getTurtle().goto((((Too[0]+1)*(SquareSize*2))-(SquareSize*8),(SquareSize*8)-(Too[1]*(SquareSize*2))))
            InputBoard[From[0]][From[1]][1].setCoords(Too)
            InputBoard[Too[0]][Too[1]][1] = InputBoard[From[0]][From[1]][1]
            InputBoard[From[0]][From[1]][1] = "PPH"
        else:
            PieceTaken = True
            Pieces.remove(InputBoard[Too[0]][Too[1]+toAdd][1])
            InputBoard[From[0]][From[1]][1].setCoords(Too)
            TempPieceTaken = InputBoard[Too[0]][Too[1]+toAdd][1]
            InputBoard[Too[0]][Too[1]+toAdd][1].getTurtle().goto(-400,0)
            InputBoard[From[0]][From[1]][1].getTurtle().goto((((Too[0]+1)*(SquareSize*2))-(SquareSize*8),(SquareSize*8)-(Too[1]*(SquareSize*2))))
            InputBoard[Too[0]][Too[1]+toAdd][1] = "PPH"
            InputBoard[Too[0]][Too[1]][1] = InputBoard[From[0]][From[1]][1]
            InputBoard[From[0]][From[1]][1] = "PPH"
        wn.update()
        check = checkCheck()
        if check == True:
            phantomPiece = Too
            penWrite("Attempted to move " + InputBoard[Too[0]][Too[1]][1].getName() + ": From: " + str(From) + ", Too: " + str(Too) + " However King is in check. Returning Pieces...","normal",penNormal)
            phantomPiece = [-1,-1]
            if InputBoard[Too[0]][Too[1]][1].getType() == "King":
                if InputBoard[Too[0]][Too[1]][1].getColour() == "white":
                    Kl[0][0] = From[0]
                    Kl[0][1] = From[1]
                else:
                    Kl[1][0] = From[0]
                    Kl[1][1] = From[1]
            elif InputBoard[Too[0]][Too[1]][1].getType() == "Rook":
                if From == [0,0]:
                    WhiteRookShortMove = False
                elif From == [7,0]:
                    WhiteRookLongMove =  False
                elif From == [0,7]:
                    BlackRookShortMove = False
                elif From == [7,7]:
                    BlackRookLongMove = False
            InputBoard[Too[0]][Too[1]][1].setCoords(From)
            InputBoard[Too[0]][Too[1]][1].getTurtle().goto((((From[0])*(SquareSize*2))-(SquareSize*6),(SquareSize*8)-(From[1]*(SquareSize*2))))
            InputBoard[From[0]][From[1]][1] = InputBoard[Too[0]][Too[1]][1]
            InputBoard[Too[0]][Too[1]][1] = "PPH"
            if PieceTaken != False:
                Pieces.append(TempPieceTaken)
                Coords =TempPieceTaken.getCoords()
                TempPieceTaken.getTurtle().goto((((Coords[0]+1)*(SquareSize*2))-(SquareSize*8),(SquareSize*8)-(Coords[1]*(SquareSize*2))))
                InputBoard[Too[0]][Too[1]+toAdd][1] = TempPieceTaken
            wn.update()
        else:
                    piece = InputBoard[Too[0]][Too[1]][1]
                    if piece.getType() == "Pawn":
                        if (piece.getColour() == "white" and Too[1] == 7) or (piece.getColour() == "black" and Too[1] == 0):
                            piece.setType("Queen", [[1.0, 0.0, 1.0],[0.0, 1.0, 1.0],[-1.0, 0.0, 1.0],[0.0, -1.0, 1.0],[1.0, 1.0, 1.0],[1.0, -1.0, 1.0],[-1.0, 1.0, 1.0],[-1.0, -1.0, 1.0]])
                            wn.update()
                    elif piece.getType() == "King" and abs(From[0]-Too[0]) == 2:
                        if From[0]-Too[0] == 2:
                            InputBoard[0][Too[1]][1].getTurtle().goto((((3)*(SquareSize*2))-(SquareSize*8),(SquareSize*8)-(Too[1]*(SquareSize*2))))
                            InputBoard[0][Too[1]][1].setCoords([2,Too[1]])
                            InputBoard[2][Too[1]][1] = InputBoard[0][From[1]][1]
                            InputBoard[From[0]][From[1]][1] = "PPH"
                        else:
                            InputBoard[7][Too[1]][1].getTurtle().goto((((5)*(SquareSize*2))-(SquareSize*8),(SquareSize*8)-(Too[1]*(SquareSize*2))))
                            InputBoard[7][Too[1]][1].setCoords([2,Too[1]])
                            InputBoard[4][Too[1]][1] = InputBoard[7][From[1]][1]
                            InputBoard[From[0]][From[1]][1] = "PPH"
                    if TempPieceTaken == "A":
                        penWrite(piece.getName() + ": From: " + str(From) + ", Too: " + str(Too),"normal",penNormal)
                    else:
                        penWrite(piece.getName() + ": From: " + str(From) + ", Too: " + str(Too) + ", And took the piece " +TempPieceTaken.getName(),"normal",penNormal)
                    changeTurn()
                    if Turn == "black":
                        wn.bgcolor("darkgray")
                    else:
                        wn.bgcolor("lightgray")
                    penWrite("Turn: " + Turn,"Head",penHead)
                    checkMate = checkCheckMate()
                    if checkMate == True:
                        penWrite("Check Mate","Head",penHead)
                    wn.update()

"""
=======================

=======================
Controls Animation of Squares
=======================
"""
def Animate(x,y, color):
    AnimatedSquares.append(Board[x][y][0])
    Board[x][y][0].getTurtle().color(color)
    wn.update()
def DeAnimate():
    for i in range(len(AnimatedSquares)):
        AnimatedSquares[i].setColour()
    wn.update()
"""
=======================

=======================
Works out possible Moves
=======================
"""
phantomPiece = [-1,-1]

def friendlyOnSquare(x,y):
    global Turn
    if Board[x][y][1] != "PPH":
        if Board[x][y][1].getColour() == Turn:
            return True
        else:
            return False
    else:
        return False
def enemyOnSquare(x,y):
    global Turn
    if Board[x][y][1] != "PPH":
        if Board[x][y][1].getColour() != Turn:
            return True
        else:
            return False
    else:
        return False
def PossibleMoves(piece,x,y, type):
    global phantomPiece
    global Turn
    pieceType = piece.getType()
    moves = piece.getMove()
    startingCoords = piece.getStartCoords()
    PM = []
    for i in range(len(moves)):
        xN = int(x +  moves[i][0])
        yN = int(y + moves[i][1])
        c = moves[i][2]
        if xN <= 7 and yN <= 7 and xN >= 0 and yN >=0:
            if Board[xN][yN][1] != "PPH":
                fOS = friendlyOnSquare(xN,yN)
                eOS = enemyOnSquare(xN,yN)
                nOS = False
            else:
                nOS = True
                fOS = False
                eOS = False
            if c == 0 and (fOS == False or type == False):
                if pieceType == "Knight" or pieceType == "King":
                    PM.append([xN,yN])
                    if pieceType == "King" and type != False and type != "Mate":
                        Short = False
                        Long = False
                        coords = piece.getCoords()
                        ePM = enemyPossibleMoves()
                        for p in range(len(ePM)):
                            for l in range(len(ePM[p][1])):
                                if [coords[0]-1,coords[1]] == ePM[p][1][l] or [coords[0]-2,coords[1]] == ePM[p][1][l]:
                                    Short = True
                                elif [coords[0]+1,coords[1]] == ePM[p][1][l] or [coords[0]+2,coords[1]] == ePM[p][1][l]:
                                    Long = True
                                elif  [coords[0],coords[1]] == ePM[p][1][l]:
                                    Long = True
                                    Short = True
                        if Turn == "white":
                            if WhiteRookLongMove == True:
                                Long = True
                            if WhiteRookShortMove == True:
                                Short = True
                        else:
                            if BlackRookLongMove == True:
                                Long = True
                            if BlackRookShortMove == True:
                                Short = True
                        if (WhiteKingMove == False and Turn == "white") or (BlackKingMove == False and Turn == "black"):
                            if Board[coords[0]-1][coords[1]][1] == "PPH" and Board[coords[0]-2][coords[1]][1] == "PPH" and Short == False:
                                PM.append([coords[0]-2,coords[1]])
                            if Board[coords[0]+1][coords[1]][1] == "PPH" and Board[coords[0]+2][coords[1]][1] == "PPH" and Board[coords[0]+3][coords[1]][1] == "PPH" and Long == False:
                                PM.append([coords[0]+2,coords[1]])

                elif type != "ePM" and eOS == False and type != False:
                    PM.append([xN,yN])
            elif c == 1:
                Blocked = False
                while xN <= 7 and yN <= 7 and xN >= 0 and yN >=0 and Blocked == False:
                    if Board[xN][yN][1] != "PPH":
                        fOS = friendlyOnSquare(xN,yN)
                        eOS = enemyOnSquare(xN,yN)
                        nOS = False
                    else:
                        nOS = True
                        fOS = False
                        eOS = False
                    if nOS == True:
                        PM.append([xN,yN])
                    elif fOS == True and type != False:
                        Blocked = True
                    elif eOS == True or type == False:
                        PM.append([xN,yN])
                        Blocked = True
                    xN = int(xN +  moves[i][0])
                    yN = int(yN +  moves[i][1])
            elif c == 2:
                if eOS == True or type == False:
                    PM.append([xN,yN])
                elif type == "ePM":
                    PM.append([xN,yN])
                elif phantomPiece != [-1,-1]:
                    if phantomPiece == [xN,yN]:
                        PM.append([xN,yN])
            elif c == 3:
                if pieceType == "Pawn":
                    if type != "ePM":
                        if piece.getColour() == "white":
                            if nOS == True and y == 1 and enemyOnSquare(xN,yN-int(moves[i][1]/2)) == False and friendlyOnSquare(xN,yN -int(moves[i][1]/2)) == False and type != False:
                                PM.append([xN,yN])
                        else:
                            if nOS == True and y == 6 and enemyOnSquare(xN,yN-int(moves[i][1]/2)) == False and friendlyOnSquare(xN,yN -int(moves[i][1]/2)) == False and type != False:
                                PM.append([xN,yN])

    return PM
"""
=======================

=======================
Save the current board
=======================
"""
def SaveBoard():
    saved = []
    for i in range(len(Pieces)):
        name  =  Pieces[i].getName() + ">"
        shape = Pieces[i].getType()
        colour = Pieces[i].getColour()
        coords = Pieces[i].getCoords()
        coords = str(coords[0]) + str(coords[1])
        moves = str(Pieces[i].getMove())
        moves = moves.replace("[[", "{[")
        moves = moves.replace("]]", "]}")
        moves = moves.replace("], [", "],[")
        saved.append([name,shape,colour,coords,moves])
    BoardsetUp.Save(saved)
"""
=======================

=======================
Runs When the board is clicked
=======================
"""
penNormal = turtle.Turtle()
penHead = turtle.Turtle()
penNormal.penup()
penHead.penup()
penNormal.hideturtle()
penHead.hideturtle()
penNormal.hideturtle()
penHead.hideturtle()
saveButton = turtle.Turtle()
saveButton.penup()
saveButton.shape("square")
try:
    saveButton.shapesize((SquareSize)/40.0, (SquareSize)/40.0, SquareSize/32.0)
except:
    FileHandler.Logs.append(FileHandler.Log("Errors", filename + "/" + str(cf.f_lineno),("The sub-root SqaureSize> was invalid. Please correct the error")))
    sys.exit()
saveButton.goto(SquareSize*11.6, SquareSize*0.8)
saveButton.write("Save", font=("Courier New", 15,"bold"))
saveButton.goto(SquareSize*12, 0)
saveButton.color("green")
wn.update()
FileHandler.Logs.append(FileHandler.Log("SetUp", filename + "/" + str(cf.f_lineno),("The Save Button has been created.")))
def ClearPen(pen):
    pen.undo()
def penWrite(Message, type, pen):
    ClearPen(pen)
    size = 15
    font = "normal"
    if type == "Head":
        size = 30
        font = "bold"
        pen.goto(-600, 250)
    elif type == "normal":
        pen.goto(-700, 200)
        if len(Message) > 40:
            for i in range(40):
                if Message[40-i] == " ":
                    Message = Message[:40-i] + "\n" +Message[41-i:]
                    break;
        if len(Message) > 80:
            for i in range(40):
                if Message[80-i] == " ":
                    Message = Message[:80-i] + "\n" +Message[81-i:]
                    break;
    pen.write(Message, font=("Courier New", size,font))
penWrite("Turn: white","Head",penHead)
def BoardClicked(x,y):
    global Turn
    global PPM
    global Selected
    global phantomPiece
    x = (int(x) + (SquareSize*15))// (SquareSize*2) - 4
    y = (-int((y-(SquareSize*2))) + (SquareSize*15)) // (SquareSize*2) -4
    if x == 9 and y == 4:
        penWrite("The Board Was saved.","normal",penNormal)
        FileHandler.Logs.append(FileHandler.Log("General", filename + "/" + str(cf.f_lineno),("[Player] The Board was saved.")))
        SaveBoard()
    if len(PPM) == 0:
        if x <= 7 and y <= 7 and x >= 0 and y >=0:
            if Board[x][y][1] != "PPH":
                if Board[x][y][1].getColour() == Turn:
                    FileHandler.Logs.append(FileHandler.Log("General", filename + "/" + str(cf.f_lineno),("[Player] (finding square) Square %s was clicked Piece %s was found, of the correct colour.") % (str([x,y]),Board[x][y][1].getName())))
                    penWrite("The Piece, " + Board[x][y][1].getName() + ", was selected.","normal",penNormal)
                    PPM = PossibleMoves(Board[x][y][1],x,y,"None")
                    Board[x][y][1].getTurtle().shapesize(1.2,1.2,1.2)
                    Animate(x, y, "gray")
                    for i in range(len(PPM)):
                        Animate(PPM[i][0],PPM[i][1],"green")
                    Selected = [x,y]
                else:
                    FileHandler.Logs.append(FileHandler.Log("General", filename + "/" + str(cf.f_lineno),("[Player] (finding square) Square %s was clicked Piece %s was found of the incorrect colour.") % (str([x,y]),Board[x][y][1].getName())))
                    penWrite("The Piece on this square is not of the correct colour. Pick a piece of the turn colour: " + Turn + ".","normal",penNormal)
            else:
                FileHandler.Logs.append(FileHandler.Log("General", filename + "/" + str(cf.f_lineno),("[Player] (finding square) Square %s was clicked, No piece was found") % (str([x,y]))))
                penWrite("There is no Piece on this square.","normal",penNormal)
        wn.update()
    else:
        DeAnimate()
        move = False
        Board[Selected[0]][Selected[1]][1].getTurtle().shapesize(1,1,1)
        if x <= 7 and y <= 7 and x >= 0 and y >=0:
            for i in range(len(PPM)):
                if PPM[i] == [x,y]:
                    move = True
                    pieceToMove = PPM[i]
        if move == True:
            FileHandler.Logs.append(FileHandler.Log("General", filename + "/" + str(cf.f_lineno),("[Player] (found square) The Square %s was clicked, The piece %s @ %s will be moved") % (str([x,y]), Board[Selected[0]][Selected[1]][1].getName(),Selected)))
            MovePiece(Selected,pieceToMove, Board)
        else:
            penWrite("Piece was unselected as this was an invalid move.","normal",penNormal)
            FileHandler.Logs.append(FileHandler.Log("General", filename + "/" + str(cf.f_lineno),("[Player] (found square) The Square %s was clicked, No piece was found") % (str([x,y]))))
        PPM = []
        Selected =[]
wn.tracer(0) #Reduces the lag seen on screen
wn.onclick(BoardClicked)

turtle.mainloop()


#==============================================================================
# Hilfsfunktion DatenListe
# Gibt eine Liste der xml-Dateien im Ordner DatenbankDaten
#==============================================================================
from os import getcwd, walk, chdir

def DatenListe():
    string = getcwd()
    string = string.replace('\Hilfsfunktionen', '')
    chdir(string)
    Liste = []

    for ordn in walk('DatenbankDaten'):
        for data in ordn[2]:
            if '.py' in data:
                data = data.replace(data, '')
            elif '.txt' in data:
                data = data.replace(data, '')
            else:
                if '.xml' in data:
                    Liste.append(data)
        break
    return Liste


from __future__ import print_function
from ipywidgets import *
import ipywidgets as wg
from IPython.display import display
import time
from datetime import datetime, timedelta

import matplotlib
import numpy as np
import matplotlib.pyplot as plt
import rpyc

from IPython.display import Javascript

#system parameters
OPENRESISTANCE = 20e3
timefmt = '%Y-%m-%d %H:%M:%S'

def messageBox(msg):
  pre="""require(["base/js/dialog"],
  function(dialog) {
     dialog.modal({
         title: 'Message',
         body: '"""
  post="""',
         buttons: {
            'Bye': {}
                     }
                 });
             }) """
  data = pre+msg+post
  display(Javascript(data))

info = {
          'isPaused': False,
          'channels': [],
          'freqs': [],
          'period': 0,
          'deadline': 0,
          'begintime':0
}

conn=rpyc.connect('localhost',18861,config={'allow_pickle': True})

file = open("images/blue.png","rb")
blueLed = file.read()
file.close()
file = open("images/green.png","rb")
greenLed = file.read()
file.close()
file = open("images/red.png","rb")
redLed = file.read()
file.close()
chk = []
led = []

# <setup> Box
for i in range(8):
    chk.append(wg.Checkbox(value=False))
    led.append(wg.Image(value=redLed,width=30,height=30))

marea = wg.Textarea(
    value='',
    placeholder='Calibration is needed',
    description='$Z$:',
    disabled=False, width='250px', height='200px'
)

checks=wg.HBox( [wg.VBox([wg.HBox([led[i],chk[i]], width='100px') for i in range (4)]),
wg.VBox([wg.HBox([led[i],chk[i]]) for i in range (4,8)], width='100px')] )
setupBtn = wg.Button(description = 'Set Up', diable=False, button_style='')
checkBtn = wg.Button(description = 'Check', diable=False, button_style='')

h_centering = Layout(display='flex',
                    flex_flow='row',
                    justify_content='center',
                    align_items='center',
                    width='100%')

v_centering = Layout(display='flex',
                    flex_flow='column',
                    align_items='center')

mdatastr = ''
marea = wg.Textarea(
    value=mdatastr,
    placeholder='Type something',
    description='$Z$:',
    disabled=False, width='250px', height='200px'
)
checkBox = wg.Box([marea,checkBtn], layout=v_centering)
freqs=wg.Text(value='',description='freq\'s:', width='80%')
period=wg.Text(value='',description='period:', width='50%')
deadline=wg.Text(value='',description='deadline:', width='50%')
inputBox = wg.VBox([freqs,period,deadline])
vchiparea = wg.Box([checks,inputBox], layout=h_centering)
setupBox = wg.Box([vchiparea,setupBtn], layout=v_centering)
initBox = wg.HBox([checkBox,setupBox])

display(initBox)
sline = wg.HTML(value='<hr>')
display(sline)

def onSetupBtnClicked(b):
    #setRecordingInfo
    status=conn.root.getStatus()
    if status['isRecording']==True:
        messageBox('Please finish first!!')
        return
    if freqs.value == '':
       messageBox('freqs should have at least 1 freq!!')
       return
    if period.value == '':
       messageBox('period is empty!!')
       return
    if deadline.value == '':
       messageBox('deadline is empty')
       return
    noChk = 0
    chs = []
    for i in range(8):
       if chk[i].value == True:
          noChk += 1
          chs.append(i)
    if noChk == 0:
       messageBox('at least 1 checkbox should be checked!!')
       return

    fr = (freqs.value).split(',')
    frs=[]
    for i in fr: frs.append(int(i)*1000) #frequencies in KHz when debug
    info['isPaused']=False
    info['channels']=chs
    info['freqs']=frs
    info['period']=int(period.value)
    info['deadline']=int(deadline.value)
    conn.root.setup(info)

def onCheckBtnClicked(b):
    status=conn.root.getStatus()
    if status['isRecording']==True:
        messageBox('Please finish first!!')
        return
    checkBtn.disabled=True
    #measure all channel and if imp < 100k change led to blueLed
    #and the measured R, C is written to marea
    Z=conn.root.checkChip()
    mdatastr = 'ch \t R \t \t C \n'
    for i in range(8):
       R=Z[i][0].real
       w=2*np.pi*4e3
       C=1/(w*Z[i][0].imag)*1e9
       if R < OPENRESISTANCE:
          led[i].value = blueLed
          chk[i].value = True
          Rs = '%.1f'%R
          Cs = '%.1f'%-C
       else:
          led[i].value = redLed
          chk[i].value = False
          Rs = '-'
          Cs = '-'
       mdatastr += str(i+1) +':\t'+Rs+'\t'+Cs+ '\n'
    marea.value=mdatastr
    checkBtn.disabled=False

checkBtn.on_click(onCheckBtnClicked)
setupBtn.on_click(onSetupBtnClicked)

# <control> Box
infoBtn = wg.Button(description = 'info', disabled=False, button_style='',width='50%')
recordingBtn = wg.Button(description = 'recording', disabled=False, button_style='',width='50%')
pauseBtn = wg.Button(description = 'pause', disabled=False, button_style='',width='50%')
finishBtn = wg.Button(description = 'finish', disabled=False, button_style='',width='50%')
statusLed = wg.Image(value=redLed,width=50,height=50)
elapse=wg.Text(value='',description='elapse:',width='100%')

controlBox = wg.Box([statusLed, infoBtn, recordingBtn, pauseBtn, finishBtn, elapse], layout=h_centering)
display(controlBox)
display(sline)

def btnsMode(mode):
    if mode == 'idle':
        checkBtn.disabled = False
        setupBtn.disabled = False
        recordingBtn.disabled = False
        pauseBtn.disabled = True
        finishBtn.disabled = True
    else:
        checkBtn.disabled = True
        setupBtn.disabled = True
        recordingBtn.disabled = True
        pauseBtn.disabled = False
        finishBtn.disabled = False

def onInfoBtnClicked(b):
    status = conn.root.getStatus()
    msgBox.value='%s\n'%status
    rinfo = info.copy()
    rinfo = conn.root.getRecordingInfo()
    msgBox.value += '%s\n'%rinfo
    if status['isRecording']==True:
        statusLed.value=blueLed
        cur = datetime.now()
        tdelta =datetime.strptime(cur.strftime(timefmt),timefmt)-datetime.strptime(rinfo['begintime'], timefmt)
        rsnds = tdelta.seconds
        hrs = rsnds/3600
        rsnds = rsnds - hrs*3600
        mins = rsnds/60
        rsnds = rsnds-mins*60
        estr=''
        if tdelta.days > 0: estr = str(tdelta.days)+' d '
        if hrs > 0: estr += str(hrs)+' h '
        if mins > 0: estr += str(mins)+' m'
        estr += str(rsnds)+' s'
        elapse.value = estr
        btnsMode('run')
    else:
        statusLed.value=redLed
        btnsMode('idle')
    if rinfo['isPaused']==True: statusLed.value=greenLed
    for i in rinfo['channels']:
       chk[i].value = True
    frstr =''
    for i in rinfo['freqs']:
        frstr += '%s,'%(i/1000) # freq's in kHz when debug
    freqs.value = frstr[0:-1]
    period.value = str(rinfo['period'])
    deadline.value = str(rinfo['deadline'])

def onRecordingBtnClicked(b):
    status = conn.root.getStatus()
    if status['isRecording']==True:
       messageBox('Please finish first!!')
       return
    #disable all btn's except 'pause' and 'finish'
    btnsMode('run')
    conn.root.recording()
    statusLed.value = blueLed

def onPauseBtnClicked(b):
    status = conn.root.getStatus()
    if status['isRecording']==False:
       messageBox('Culture Server is not on recording!!')
       return
    rinfo = conn.root.getRecordingInfo()
    if rinfo['isPaused'] == False:
        pauseBtn.description = 'resume'
        conn.root.pause()
        statusLed.value = greenLed
    else:
        pauseBtn.description = 'pause'
        conn.root.resume()
        statusLed.value = blueLed

def onFinishBtnClicked(b):
    status = conn.root.getStatus()
    if status['isRecording']==False:
       messageBox('Culture Server is not on recording!!')
       return
    #disable finish, pause
    conn.root.finish()
    statusLed.value=redLed
    btnsMode('idle')

infoBtn.on_click(onInfoBtnClicked)
recordingBtn.on_click(onRecordingBtnClicked)
pauseBtn.on_click(onPauseBtnClicked)
finishBtn.on_click(onFinishBtnClicked)

#<Message Box>
msgBox = wg.Textarea(value='',descrition='',disabled=False, width='100%')
display(msgBox)

#initize the control pannel
status=conn.root.getStatus()
rinfo= conn.root.getRecordingInfo()
if status['isRecording']==True:
    if rinfo['isPaused']==True: statusLed.value=greenLed
    else: statusLed.value=blueLed
    btnsMode('run')
else:
    statusLed.value=redLed
    btnsMode('idle')


'''Ex 2. Crie um programa que leia vários números inteiros pelo teclado. O programa só vai para quando o
usuário digitar o valor 999, que é a condição de parada. No final, mostre quantos números foram
digitados e qual foi a soma entre eles (desconsiderando o flag).'''

soma=0
qtd=0

while True:
    num=int(input('Digite um número inteiro: '))
    if num>0 and num<1000:
        soma+=num
        qtd+=1
    else:
        break
print('A soma dos {} numeros digitatdos é {} '.format(qtd, soma))