from biosimulators_utils.report.data_model import VariableResults
from biosimulators_utils.sedml.data_model import Variable  # noqa: F401
from biosimulators_utils.utils.core import validate_str_value, parse_value
import cobra  # noqa: F401
import libsbml
import numpy

__all__ = [
    'get_objective_sbml_fbc_ids',
    'set_simulation_method_arg',
    'apply_variables_to_simulation_method_args',
    'validate_variables',
    'get_results_paths_for_variables',
    'get_results_of_variables',
]

def get_objective_sbml_fbc_ids(model_source):
    """ Get the SBML-FBC id of the active objective

    Args:
        model_source (:obj:`str`): path to model

    Returns:
        :obj:`tuple`:

            * :obj:`str`: SBML-FBC id of the active objective
            * :obj:`list` of :obj:`str`: SBML-FBC id of the objectives
    """
    doc = libsbml.readSBMLFromFile(model_source)
    model = doc.getModel()
    model_fbc = model.getPlugin("fbc")
    return (
        model_fbc.getListOfObjectives().getActiveObjective(),
        [objective.getId() for objective in model_fbc.getListOfObjectives()],
    )

def set_simulation_method_arg(method_props, argument_change, model, model_method_kw_args):
    """ Set the value of an argument of a simulation method based on a SED
    algorithm parameter change

    Args:
        method_props (:obj:`dict`): properties of the simulation method
        argument_change (:obj:`AlgorithmParameterChange`): algorithm parameter change
        model (:obj:`cobra.core.model.Model`)
        model_method_kw_args (:obj:`dict`): keyword arguments for the simulation method
            for the model

    Raises:
        :obj:`NotImplementedError`: if the simulation method doesn't support the parameter
        :obj:`ValueError`: if the new value is not a valid value of the parameter
    """
    parameter_kisao_id = argument_change.kisao_id
    parameter = method_props['parameters'].get(parameter_kisao_id, None)
    if parameter is None:
        msg = "".join([
            "{} ({}) does not support parameter `{}`. ".format(
                method_props['name'], method_props['kisao_id'], argument_change.kisao_id),
            "The parameters of {} must have one of the following KiSAO ids:\n  - {}".format(
                method_props['name'],
                '\n  - '.join(
                    '{} ({}): {}'.format(kisao_id, parameter['name'], parameter['description'])
                    for kisao_id, parameter in method_props['parameters'].items())),
        ])
        raise NotImplementedError(msg)

    value = argument_change.new_value
    if not validate_str_value(value, parameter['type']):
        msg = "`{}` is not a valid value for parameter {} ({}) of {} ({})".format(
            value, parameter['name'], parameter_kisao_id,
            method_props['name'], method_props['kisao_id'])
        raise ValueError(msg)
    enum = parameter.get('enum', None)
    if enum:
        if value.lower() not in enum.__members__:
            msg = ("`{}` is not a valid value for parameter {} ({}) of {} ({}). "
                   "The value of {} must be one of the following:\n  - {}").format(
                value, parameter['name'], parameter_kisao_id,
                method_props['name'], method_props['kisao_id'],
                method_props['name'],
                '\n  - '.join(sorted('`' + value + '`' for value in enum.__members__.keys())))
            raise ValueError(msg)

    parsed_value = parse_value(value, parameter['type'])
    if enum:
        parsed_value = enum[value.lower()].value

    if 'alg_arg' in parameter:
        model_method_kw_args[parameter['alg_arg']] = parsed_value
    else:
        setattr(model, parameter['model_arg'], parsed_value)

def apply_variables_to_simulation_method_args(target_x_paths_ids, method_props, variables, model_method_kw_args):
    """ Encode the desired output variables into arguments to simulation methods

    Args:
        target_x_paths_ids (:obj:`dict` of :obj:`str` to :obj:`str`): dictionary that maps each XPath to the
            SBML id of the corresponding model object
        method_props (:obj:`dict`): properties of the simulation method
        variables (:obj:`list` of :obj:`Variable`): variables that should be recorded
        model_method_kw_args (:obj:`dict`): keyword arguments for the simulation method
            for the model
    """
    if method_props['kisao_id'] == 'KISAO_0000526':
        reaction_list = set()
        for variable in variables:
            reaction_id = target_x_paths_ids[variable.target]
            reaction_list.add(reaction_id[2:] if reaction_id.startswith('R_') else reaction_id)
        model_method_kw_args['reaction_list'] = sorted(reaction_list)

def validate_variables(model, active_objective_sbml_fbc_id, objective_sbml_fbc_ids,
                       method, variables, target_sbml_id_map, target_sbml_fbc_id_map, sbml_fbc_uri):
    """ Validate the desired output variables of a simulation

    Args:
        model (:obj:`cobra.core.model.Model`): model
        active_objective_sbml_fbc_id (:obj:`str`): SBML-FBC id of the active objective
        objective_sbml_fbc_ids (:obj:`list` of :obj:`str`): SBML-FBC id of the objectives
        method (:obj:`dict`): properties of desired simulation method
        variables (:obj:`list` of :obj:`Variable`): variables that should be recorded
        target_sbml_id_map (:obj:`dict` of :obj:`str` to :obj:`str`): dictionary that maps each XPath to the
            SBML id of the corresponding model object
        target_sbml_fbc_id_map (:obj:`dict` of :obj:`str` to :obj:`str`): dictionary that maps each XPath to the
            SBML-FBC id of the corresponding model object
        sbml_fbc_uri (:obj:`str`): URI for SBML FBC package
    """
    possible_target_results_path_map = set()
    for variable_pattern in method['variables']:
        for sbml_id, fbc_id, attr, result_type, result_name in variable_pattern['get_target_results_paths'](
                model, active_objective_sbml_fbc_id, objective_sbml_fbc_ids):
            possible_target_results_path_map.add((sbml_id, fbc_id, attr))

    invalid_symbols = set()
    invalid_targets = set()
    for variable in variables:
        if variable.symbol:
            invalid_symbols.add(variable.symbol)

        else:
            valid = True

            target = variable.target
            variable_target_id = target_sbml_id_map.get(target, None)
            variable_target_fbc_id = target_sbml_fbc_id_map.get(target, None)
            target_attr = target.partition('/@')[2] or None
            if target_attr:
                target_ns, _, target_attr = target_attr.rpartition(':')
                if target_ns and variable.target_namespaces.get(target_ns, None) != sbml_fbc_uri:
                    valid = False

            if not valid or (variable_target_id, variable_target_fbc_id, target_attr) not in possible_target_results_path_map:
                invalid_targets.add(variable.target)

    if invalid_symbols:
        raise NotImplementedError("{} ({}) doesn't support variables with symbols".format(
            method['name'], method['kisao_id']))

    if invalid_targets:
        msg = (
            "{} ({}) doesn't support variables with the following target XPaths:\n  - {}\n\n"
            "The targets of variables should match one of the following patterns of XPaths:\n  - {}"
        ).format(
            method['name'], method['kisao_id'],
            '\n  - '.join(sorted('`' + target + '`' for target in invalid_targets)),
            '\n  - '.join(sorted('{}: `{}`'.format(
                variable_pattern['description'], variable_pattern['target'])
                for variable_pattern in method['variables']))
        )
        raise ValueError(msg)

def get_results_paths_for_variables(model, active_objective_sbml_fbc_id, objective_sbml_fbc_ids,
                                    method, variables, target_sbml_id_map, target_sbml_fbc_id_map):
    """ Get the path to results for the desired variables

    Args:
        model (:obj:`cobra.core.model.Model`): model
        active_objective_sbml_fbc_id (:obj:`str`): SBML-FBC id of the active objective
        objective_sbml_fbc_ids (:obj:`list` of :obj:`str`): SBML-FBC id of the objectives
        method (:obj:`dict`): properties of desired simulation method
        variables (:obj:`list` of :obj:`Variable`): variables that should be recorded
        target_sbml_id_map (:obj:`dict` of :obj:`str` to :obj:`str`): dictionary that maps each XPath to the
            SBML id of the corresponding model object
        target_sbml_fbc_id_map (:obj:`dict` of :obj:`str` to :obj:`str`): dictionary that maps each XPath to the
            SBML-FBC id of the corresponding model object

    Returns:
        :obj:`dict`: path to results of desired variables
    """
    possible_target_results_path_map = {}
    for variable_pattern in method['variables']:
        for sbml_id, fbc_id, attr, result_type, result_name in variable_pattern['get_target_results_paths'](
                model, active_objective_sbml_fbc_id, objective_sbml_fbc_ids):
            possible_target_results_path_map[(sbml_id, fbc_id, attr)] = (result_type, result_name)

    target_results_path_map = {}
    for variable in variables:
        target = variable.target
        variable_target_id = target_sbml_id_map[target]
        variable_target_fbc_id = target_sbml_fbc_id_map[target]
        target_attr = target.partition('/@')[2].rpartition(':')[2] or None
        target_results_path_map[variable.target] = possible_target_results_path_map[(
            variable_target_id, variable_target_fbc_id, target_attr)]

    return target_results_path_map

def get_results_of_variables(target_results_path_map, variables, solution):
    """ Get the results of the desired variables

    Args:
        target_results_path_map (:obj:`dict`): path to results of desired variables
        variables (:obj:`list` of :obj:`Variable`): variables that should be recorded
        solution (:obj:`cobra.core.solution.Solution`): solution of method

    Returns:
        :obj:`VariableResults`: the results of desired variables
    """
    variable_results = VariableResults()
    for variable in variables:
        result_type, result_name = target_results_path_map[variable.target]
        if result_type:
            result = getattr(solution, result_type)
            if result_name:
                if hasattr(result, 'get'):
                    result = result.get(*result_name)
                else:
                    result = result[result_name]
        else:
            result = numpy.nan

        variable_results[variable.id] = numpy.array(result)

    return variable_results


import psycopg2
import json
# Leer las credenciales de un archivo JSON
# Recomendado: https://parzibyte.me/blog/2019/06/09/json-python-codificar-decodificar/
with open("credenciales.json") as archivo_credenciales:
    credenciales = json.load(archivo_credenciales)
# Como la conexión devuelve un diccionario podemos convertirlo fácilmente
# a "kwargs" o key arguments ;)
# Recomendado: https://parzibyte.me/blog/2018/12/20/args-kwargs-python/
try:
    conn = psycopg2.connect(**credenciales)
    print('yes')
except psycopg2.Error as e:
    print("Ocurrió un error al conectar a PostgreSQL: ", e)


'''
img.shape
img.size
img.dtype
'''

import cv2
import numpy as np

img = cv2.imread('D:/A LEARN/Image Processing/Program Youtube/Gambar/messi.jpg',1)

print(img.shape) #returns a tuple of rows, columns and chanels
print(img.size) #return total number of pixel (row*columns*chanell)
print(img.dtype) #return image datatype is obtained

b,g,r = cv2.split(img)  #ngesplit semua bgr dalam setiap pixel di gambar
img = cv2.merge((b,g,r)) #nyatuin semua bgr perpixel jadi gambar lagi

cv2.imshow('image', img)
cv2.waitKey()
cv2.destroyAllWindows()


#!/usr/bin/env python

import argparse
import logging
import os
import sys
from pytodo.utils import options, database, misc, exceptions
from pytodo.utils.database import Base, Task, Project

# The log.
log = logging.getLogger(__name__)

engine, session = database.open_db_session()

DESCRIPTION = "Add new task to todo"

def add_task(args):
    '''
    '''
    log.info('Adding new task in project: %s', args.project)

    detail = args.detail
    status = args.status
    priority = args.priority
    project = session.query(Project).filter_by(name=args.project).first()
    deadline = args.deadline
    new_task = Task(details=detail, status=status, deadline=deadline,
            priority=priority, project=project)
    session.add(new_task)
    session.commit()

def main():
    '''
    '''
    with exceptions.log():
        # create the parser
        parser = argparse.ArgumentParser(DESCRIPTION)
        options.loglevel(parser)
        options._add_task(parser)

        # add the task
        args=parser.parse_args()
        misc.set_log_level(args.loglevel)
        add_task(args)


#!/usr/bin/python
# -*- coding: utf-8 -*-
"""
Author: Stéphan Pissot
A minimalistic launcher to start the tools
"""
import sys
from PyQt5.Qt import qApp
from PyQt5.QtWidgets import QApplication, QWidget, QPushButton, QLabel
from octavvs import preprocessing, clustering, mcr_als

def start_preprocessing():
    preprocessing.MyMainWindow.run_octavvs_application(isChild=True)
def start_clustering():
    clustering.MyMainWindow.run_octavvs_application(isChild=True)
def start_mcrals():
    mcr_als.MyMainWindow.run_octavvs_application(isChild=True)

def main():
   app = QApplication(sys.argv)
   widget = QWidget()

   label=QLabel(widget)
   label.setText('OCTAVVS')
   label.move(10,10)

   button1 = QPushButton(widget)
   button1.setText("Preprocessing")
   button1.move(10,42)
   button1.clicked.connect(start_preprocessing)

   button2 = QPushButton(widget)
   button2.setText("Clustering")
   button2.move(10,72)
   button2.clicked.connect(start_clustering)

   button3 = QPushButton(widget)
   button3.setText("MCR-ALS")
   button3.move(10,102)
   button3.clicked.connect(start_mcrals)

   widget.setWindowTitle("OCTAVVS Launcher")
   widget.show()
   qApp.lastWindowClosed.connect(qApp.quit);
   sys.exit(app.exec_())

#if __name__ == '__main__':
#    main()


import torch
import torch.nn as nn

from models.modules import *

class LRCM(nn.Module):

    def __init__(
        self,
        bb_name,
        backbone_pretrained_path,
        in_channels_list,
        embedding_dim,
        rlow_pool_size,
        rmid_pool_size,
        rhig_pool_size,
        vlow_pool_size,
        vmid_pool_size,
        vhig_pool_size,
        low_patch_num,
        mid_patch_num,
        hig_patch_num,
        n_head,
        reduced_dim,
        atte_hidden_unit,
        dropout,
        num_class = 200,
        pretrained_model_path = None
    ):
        super(LRCM,self).__init__()

        latent_features = embedding_dim // 4

        self.r_module = RepresentationModule(
            bb_name = bb_name,
            bb_weight_path = backbone_pretrained_path,
            channels_list = in_channels_list,
            rlow_pool_size = rlow_pool_size,
            rmid_pool_size = rmid_pool_size,
            rhig_pool_size = rhig_pool_size,
            embedding_dim = embedding_dim,
            atte_hidden_unit = atte_hidden_unit,
            latent_features = latent_features,
            num_class = num_class
        )

        self.v_module = VectorsEmbeddingModule(
            low_pool_size = vlow_pool_size,
            mid_pool_size = vmid_pool_size,
            hig_pool_size = vhig_pool_size,
            low_patch_num = low_patch_num,
            mid_patch_num = mid_patch_num,
            hig_patch_num = hig_patch_num,
            embedding_dim = embedding_dim,
            dropout = dropout
        )

        self.c_module = ComprehensionModule(
            embedding_dim = embedding_dim,
            reduced_dim = reduced_dim,
            n_head = n_head,
            atte_hidden_unit = atte_hidden_unit,
            dropout = dropout,
            num_class = num_class
        )

        if pretrained_model_path is not None:
            self.load_state_dict(torch.load(pretrained_model_path))

    def forward(self,img,low_patch_indices = None,mid_patch_indices = None,hig_patch_indices = None,step = "final"):

        if step == "coarse":
            return self.r_module(img,low_patch_indices,mid_patch_indices,hig_patch_indices,step)
        elif step == "fine":
            return self.c_module(*self.v_module(*self.r_module(img,low_patch_indices,mid_patch_indices,hig_patch_indices,step)))
        else:
            low_fea,mid_fea,hig_fea,\
            low_coarse_vectors,mid_coarse_vectors,hig_coarse_vectors,\
            low_logits,mid_logits,hig_logits = self.r_module(img,low_patch_indices,mid_patch_indices,hig_patch_indices,step)
            coarse_logits,com_logits = self.c_module(*self.v_module(low_fea,mid_fea,hig_fea,low_coarse_vectors,mid_coarse_vectors,hig_coarse_vectors))
            return low_logits,mid_logits,hig_logits,coarse_logits,com_logits


#!/usr/bin/python
import Adafruit_BBIO.GPIO as GPIO
import logging
from control import send
import time
import socket

# create log file handler and set to debug
log = logging.getLogger('')
log_format = logging.Formatter('%(asctime)s - %(levelname)-8s - %(message)s')
fh = logging.FileHandler('button.log')
fh.setFormatter(log_format)
log.addHandler(fh)

# button connected to this pin and +3.3v, with pulldown
# so if high, button is pressed
pin = "P9_12"
GPIO.setup(pin, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)

# wait for bipod process to start
log.warning("waiting for bipod process to start")
while True:
    try:
        send('programs')
        break
    except socket.error:
        pass
    time.sleep(1)

def wait_for_button():
    log.warning("waiting for button press")
    while True:
        GPIO.wait_for_edge(pin, GPIO.RISING)
        # try to avoid noise issues that cause false triggers
        time.sleep(0.25)
        # if button still pressed
        if GPIO.input(pin):
            break

# first button we will send start
wait_for_button()
log.warning("button pressed, starting")
send('start')

# second button press will halt
wait_for_button()
log.warning("button pressed, halting")
send('halt')

GPIO.cleanup()


import pickle
import tensorflow as tf
import numpy as np
import tf_utils as U

"""Implementation of Behavioral Cloning on supervised data (state, action) collected
by performing rollouts with an expert policy.
Those rollouts are contained in pickle files available in the `trajectories/` folder.
Trajectories are pickled by running the `run_expert` script with the appropriate environment.
"""

def train(ob_dim, act_dim, hid_size, lr, niter, obs, acts, ops, ckpt):
    # Initialize the seesion and variables
    U.single_threaded_session().__enter__()
    U.initialize()

    # Unpack the operators
    train_step, compute_loss, predict = ops

    for i in range(int(niter)):
        train_step(obs, acts)
        l = compute_loss(obs, acts)
        # For reference, usual way of training and obtaining the loss
        # _, l = sess.run([train_op, loss], feed_dict={
        #     ob: obs,
        #     act: acts
        # })
        if i % 100 == 0:
            print("--- Loss: {0} ---".format(l))

    # Save the variables to disk
    U.save_state(ckpt)
    print("Model saved in file: {0}.".format(ckpt))

def roll(nepisodes, maxnsteps, ops, envname, ckpt):
    # Initialize the session and variables
    U.single_threaded_session().__enter__()
    U.initialize()
    U.load_state(ckpt)
    print("Model loaded.")

    # Unpack the operators
    _, _, predict = ops

    import gym
    env = gym.make(envname)
    print(env.action_space)
    print(env.observation_space)
    for e in range(nepisodes):
        print("--- Episode #{0} ---".format(e))
        observ = env.reset()
        done = False
        steps = 0
        while not done and steps < maxnsteps:
            if steps % 100 == 0:
                print("--- Step #{0} ---".format(steps))
            action = predict(np.reshape(observ, (1, 11)))
            observ, r, done, _ = env.step(action)
            steps += 1
            env.render()

def main():
    import argparse
    parser = argparse.ArgumentParser()
    parser.add_argument("--envname", type=str)
    parser.add_argument("--expert_trajectories_file", type=str)
    parser.add_argument("--model_storage_file", type=str)
    parser.add_argument("--train", action="store_true")
    args = parser.parse_args()

    # Unpickle the expert trajectories
    with open(args.expert_trajectories_file, "rb") as f:
        expert_trajectories = pickle.loads(f.read())
    obs = expert_trajectories["observations"]
    print("--- OBS shape: {0} ---".format(obs.shape))
    print("First row of observations: {0}".format(obs[0, :]))
    acts = expert_trajectories["actions"].reshape(
        (expert_trajectories["actions"].shape[0], expert_trajectories["actions"].shape[2]))
    print("--- ACTS shape: {0} ---".format(acts.shape))
    print("First row of actions: {0}".format(acts[0, :]))

    # Hyperparameters
    # Behavioral Cloning (regression)
    ob_dim = 11
    act_dim = 3
    hid_size = 64
    lr = 1e-3
    niter = 1e4
    # Rollouts
    nepisodes = 100
    maxnsteps = 5000

    # Define the regression model
    ob = U.get_placeholder(name="ob", dtype=tf.float32, shape=[None, ob_dim])
    act = U.get_placeholder(name="act", dtype=tf.float32, shape=[None, act_dim])
    last_out = ob
    last_out = U.leaky_relu(
        U.dense(last_out, hid_size, "dense0", weight_init=U.normc_initializer(1.0)),
        leak=0.2)
    pred_act = U.dense(last_out, act_dim, "dense1", weight_init=U.normc_initializer(1.0))

    loss = 0.5 * U.sum(tf.square(pred_act - act))  # could also use Huber loss
    optimizer = tf.train.AdamOptimizer(learning_rate=lr)
    train_op = optimizer.minimize(loss)

    # Create the operators
    train_step = U.function([ob, act], train_op)
    compute_loss = U.function([ob, act], loss)
    predict = U.function([ob], pred_act)
    # Pack the operators
    ops = [train_step, compute_loss, predict]

    # Train the regression model (only if the flag is up)
    if args.train:
        train(ob_dim, act_dim, hid_size, lr, niter, obs, acts, ops, args.model_storage_file)

    # Do some rollouts with the policy learned via regression (BC)
    roll(nepisodes, maxnsteps, ops, args.envname, args.model_storage_file)

if __name__ == "__main__":
    # executes only if run as a script
    main()


# -*- coding: utf-8 -*-

import tornado.web

from sems.monitors import monitors as list_monitors
from sems.repository.monitor import Monitor
from sems.settings import WEB_POLLING_INTERVAL

from sems import VERSION

class Dashboard(tornado.web.RequestHandler):

    def get(self):

        monitor_types = [
            ('Select...', '')
        ]

        for monitor in list_monitors:
            item = (list_monitors[monitor]['description'], monitor)
            monitor_types.append(item)

        monitors = {}
        for monitor in Monitor().ordered_by_position():
            if hasattr(monitor, "group"):
                group = monitor.group
            else:
                group = ""

            if group not in monitors:
                monitors[group] = []
            monitors[group].append(monitor)

        groups = set([monitor for monitor in monitors])

        self.render("dashboard.slim.html",
                    monitor_types=monitor_types,
                    groups_monitors=monitors,
                    groups=groups,
                    polling_interval=WEB_POLLING_INTERVAL,
                    version=VERSION)


'''
Created on 07 ott 2016

@author: Alejandro
'''

import collections

import pandas as pd
from utils.TextUtils import TextUtils
import csv

class DataUtils(object):

    def csvReader(self,fname,limit,del_char):
        '''leggo il file csv con limite e delimitatore,e lo carico come dataframe'''
        print("stampo fname",fname)
        df = pd.read_csv(fname,nrows=limit,delimiter=del_char,error_bad_lines=False,encoding = "latin",quoting=csv.QUOTE_NONE,dtype={"PIVA_CODFISCALE_SOG_TITOLARE":str})
        return df

    def gen_XandY(self,df,nsample,X_column,y_columns):

        sample = df.sample(n=nsample)

        matrix = sample.as_matrix()

        X = matrix[:,X_column]

        #  natura intervento 34 - tipologia_intervento 36 - area_intervento 37 - settore_intervento 39 - sottosettore_intervento 41 - categoria_intervento 43
        y_dict = collections.OrderedDict()
        for y_column in y_columns:
            y_dict[y_column] = sample.loc[:,y_column]

        X = TextUtils().norm_str_array(X)

        return X,y_dict

    def genCategory(self,fname,del_char,col_cat):
        insieme = set()
        with open(fname,'r') as f:
            for line in f:
                insieme.add(line.split(del_char)[col_cat])
        alpha_category = list(insieme).sort()
        return alpha_category

    def fileReaderRanged(self,fname,start,end):
        with open(fname,'r') as f:
            c=0
            lista=[]
            for line in f:
                if start<c<=end:
                    lista.append(line)
                c+=1
        return lista


"""Threading Executor
=====================
"""

from typing import Tuple, AsyncGenerator, Union, Callable, Optional, Dict, \
    List, Iterable, Any, AsyncContextManager
import threading
import math
import queue as stdlib_queue
import importlib
from asyncio import iscoroutinefunction
from queue import Empty
import contextlib
from async_generator import aclosing
import trio
from trio import TASK_STATUS_IGNORED
import outcome
import time
import logging
from tree_config import read_config_from_object, apply_config

from pymoa_remote.executor import NO_CALLBACK
from pymoa_remote.client import Executor
from pymoa_remote.utils import asynccontextmanager

__all__ = (
    'ThreadExecutor', 'SyncThreadExecutor', 'AsyncThreadExecutor',
    'TrioPortal')

class ThreadExecutor(Executor):

    # todo: check that methods cannot be canceled in a weird state

    is_remote = False

    _obj_executor: Dict[
        int,
        List[Union[None, 'SyncThreadExecutor', 'AsyncThreadExecutor']]] = {}

    _sync_executor: Optional['SyncThreadExecutor'] = None

    _async_executor: Optional['AsyncThreadExecutor'] = None

    def __init__(self, **kwargs):
        super(ThreadExecutor, self).__init__(**kwargs)
        self._obj_executor = {}

    async def start_executor(self):
        if self._sync_executor is not None:
            raise TypeError('Executor already started')

        self._sync_executor = SyncThreadExecutor()
        self._async_executor = AsyncThreadExecutor()
        await self._sync_executor.start()
        await self._async_executor.start()

    async def stop_executor(self):
        items = list(self._obj_executor.values())
        self._obj_executor.clear()

        with trio.CancelScope(shield=True):
            for sync_exec, async_exec in items:
                if sync_exec is not None:
                    await sync_exec.stop()
                if async_exec is not None:
                    await async_exec.stop()

            if self._sync_executor is not None:
                await self._sync_executor.stop()
                self._sync_executor = None

            if self._async_executor is not None:
                await self._async_executor.stop()
                self._async_executor = None

    async def execute(
            self, obj, fn: Union[Callable, str], args=(), kwargs=None,
            callback: Union[Callable, str] = None):
        if callback is not None and not isinstance(callback, str):
            callback = callback.__name__

        executors = self._obj_executor[id(obj)]
        if iscoroutinefunction(fn):
            executor = executors[1]
            if executor is None:
                executor = executors[1] = AsyncThreadExecutor()
                await executor.start()
        else:
            executor = executors[0]
            if executor is None:
                executor = executors[0] = SyncThreadExecutor()
                await executor.start()

        return await executor.execute(obj, fn, args, kwargs, callback)

    async def execute_generator(
            self, obj, gen: Union[Callable, str], args=(), kwargs=None,
            callback: Union[Callable, str] = None,
            task_status=TASK_STATUS_IGNORED) -> AsyncGenerator:
        task_status.started()

        if callback is not None and not isinstance(callback, str):
            callback = callback.__name__

        executors = self._obj_executor[id(obj)]
        if iscoroutinefunction(gen):
            executor = executors[1]
            if executor is None:
                executor = executors[1] = AsyncThreadExecutor()
                await executor.start()
        else:
            executor = executors[0]
            if executor is None:
                executor = executors[0] = SyncThreadExecutor()
                await executor.start()

        async with aclosing(
                executor.execute_generator(obj, gen, args, kwargs, callback)
        ) as aiter:
            async for value in aiter:
                yield value

    async def get_echo_clock(self) -> Tuple[int, int, int]:
        return await self._sync_executor.get_echo_clock()

    async def sleep(self, duration=None, deadline=None) -> int:
        return await self._sync_executor.sleep(duration, deadline)

    async def _get_async_echo_clock(self) -> Tuple[int, int, int]:
        return await self._async_executor.get_echo_clock()

    async def remote_import(self, module):
        if not isinstance(module, str):
            module = module.__name__
        importlib.import_module(module)

    async def register_remote_class(self, cls):
        mod = importlib.import_module(cls.__module__)
        if cls.__name__ != cls.__qualname__:
            raise TypeError(f'Cannot register {cls}. Can only register module '
                            f'level classes')
        self.registry.register_class(getattr(mod, cls.__name__))

    async def ensure_remote_instance(
            self, obj, hash_name, *args, auto_register_class=True, **kwargs
    ) -> bool:
        # todo: except parameter whether it uses a lock for execute
        if id(obj) in self._obj_executor:
            return False

        cls = obj.__class__
        if auto_register_class and not self.registry.is_class_registered(
                class_to_register=cls):
            self.registry.register_class(cls)

        self._obj_executor[id(obj)] = [None, None]
        self.registry.add_instance(obj, hash_name)
        return True

    async def delete_remote_instance(self, obj):
        if id(obj) not in self._obj_executor:
            return

        self.registry.delete_instance(obj)
        sync_executor, async_executor = self._obj_executor.pop(id(obj))
        if sync_executor is not None:
            await sync_executor.stop()
        if async_executor is not None:
            await async_executor.stop()

    async def get_remote_objects(self):
        return list(self.registry.hashed_instances.keys())

    async def get_remote_object_config(self, obj: Optional[Any]):
        if obj is not None:
            return read_config_from_object(obj)
        return {h: read_config_from_object(o)
                for h, o in self.registry.hashed_instances.items()}

    async def apply_config_from_remote(self, obj):
        raise NotImplementedError

    async def get_remote_object_property_data(
            self, obj: Any, properties: List[str]) -> dict:
        return {k: getattr(obj, k) for k in properties}

    async def apply_property_data_from_remote(
            self, obj: Any, properties: List[str]):
        raise NotImplementedError

    @asynccontextmanager
    async def get_data_from_remote(
            self, obj, trigger_names: Iterable[str] = (),
            triggered_logged_names: Iterable[str] = (),
            logged_names: Iterable[str] = (),
            initial_properties: Iterable[str] = (),
            task_status=TASK_STATUS_IGNORED
    ) -> AsyncContextManager[AsyncGenerator]:
        raise NotImplementedError

    async def apply_data_from_remote(
            self, obj, trigger_names: Iterable[str] = (),
            triggered_logged_names: Iterable[str] = (),
            logged_names: Iterable[str] = (),
            initial_properties: Iterable[str] = (),
            task_status=TASK_STATUS_IGNORED):
        raise NotImplementedError

    @asynccontextmanager
    async def get_channel_from_remote(
            self, hash_name: str, channel: str,
            task_status=TASK_STATUS_IGNORED
    ) -> AsyncContextManager[AsyncGenerator]:
        raise NotImplementedError

    async def apply_execute_from_remote(
            self, obj, exclude_self=True, task_status=TASK_STATUS_IGNORED):
        raise NotImplementedError

class SyncThreadExecutor:
    """Executor that executes functions in a secondary thread.
    """

    _thread: Optional[threading.Thread] = None

    _exec_queue: Optional[stdlib_queue.Queue] = None

    eof = object()

    _limiter: Optional[trio.Lock] = None

    max_queue_size = 10

    _thread_done_event: Optional[trio.Event] = None

    def __del__(self):
        if self._thread is not None:
            logging.warning(f'stop_executor was not called for "{self}"')

    async def start(self, name='ThreadExecutor'):
        queue = self._exec_queue = stdlib_queue.Queue()
        event = self._thread_done_event = trio.Event()
        self._limiter = trio.Lock()

        thread = self._thread = threading.Thread(
            target=self._worker_thread_fn, name=name,
            args=(queue, event, trio.lowlevel.current_trio_token()))
        thread.start()

    async def stop(self):
        if self._thread is None:
            return

        await self.execute(self.eof, None, callback=NO_CALLBACK)
        await self._thread_done_event.wait()

        self._thread = self._exec_queue = self._limiter = None
        self._thread_done_event = None

    def _worker_thread_fn(self, queue, event, start_token):
        eof = self.eof
        try:
            while True:
                obj, sync_fn, args, kwargs, task, token, gen_queue, \
                    gen_do_eof = queue.get(block=True)

                if obj is eof:
                    try:
                        token.run_sync_soon(trio.lowlevel.reschedule, task)
                    except trio.RunFinishedError:
                        pass
                    return

                if gen_queue is None:
                    # not a generator
                    result = outcome.capture(sync_fn, obj, *args, **kwargs)
                    try:
                        token.run_sync_soon(
                            trio.lowlevel.reschedule, task, result)
                    except trio.RunFinishedError:
                        # The entire run finished, so our particular tasks are
                        # certainly long gone - it must have cancelled.
                        # Continue eating the queue. Currently we cannot cancel
                        pass
                else:
                    # generator
                    send_channel, std_queue = gen_queue

                    def send_nowait():
                        try:
                            send_channel.send_nowait(None)
                        except trio.WouldBlock:
                            pass

                    put = std_queue.put
                    # we send to queue followed by ping on memory channel. We
                    # cannot deadlock, because the ping will result in removing
                    # at least one item, ensuring there will always be at least
                    # one item space free eventually, so put will only block
                    # for a short time until then. And then put will ping again
                    result = outcome.capture(sync_fn, obj, *args, **kwargs)
                    try:
                        # did the gen instantiation fail?
                        if isinstance(result, outcome.Error):
                            put(result, block=True)
                            token.run_sync_soon(send_nowait)
                            continue

                        gen = result.unwrap()  # get the actual gen
                        caught_error = False
                        while gen_do_eof[0] is not eof:
                            result = outcome.capture(next, gen)
                            if isinstance(result, outcome.Error):
                                caught_error = True
                                # stop iteration is signaled with None
                                if isinstance(result.error, StopIteration):
                                    result = None

                                put(result, block=True)
                                token.run_sync_soon(send_nowait)
                                break

                            put(result, block=True)
                            token.run_sync_soon(send_nowait)

                        # we exited because of eof not exception/StopIteration
                        # send either None, or closing error
                        if not caught_error:
                            result = outcome.capture(gen.close)
                            if not isinstance(result, outcome.Error):
                                result = None

                            put(result, block=True)
                            token.run_sync_soon(send_nowait)
                    except trio.RunFinishedError:
                        pass
        finally:
            try:
                start_token.run_sync_soon(event.set)
            except trio.RunFinishedError:
                pass

    @trio.lowlevel.enable_ki_protection
    async def execute(self, obj, sync_fn, args=(), kwargs=None, callback=None):
        """It's guaranteed sequential.
        TODO: if called after stop or thread exited it may block forever.
        """
        async with self._limiter:
            await trio.lowlevel.checkpoint_if_cancelled()
            self._exec_queue.put(
                (obj, sync_fn, args, kwargs or {}, trio.lowlevel.current_task(),
                 trio.lowlevel.current_trio_token(), None, None))

            def abort(raise_cancel):
                # cannot be canceled
                return trio.lowlevel.Abort.FAILED
            res = await trio.lowlevel.wait_task_rescheduled(abort)

            # we must execute under the lock to ensure ordered callbacks by
            # order of thread execution when execute is called from multiple
            # tasks
            if callback is not NO_CALLBACK:
                ThreadExecutor.call_execute_callback(obj, res, callback)
        return res

    async def execute_generator(
            self, obj, sync_gen, args=(), kwargs=None, callback=None
    ) -> AsyncGenerator:
        """Last items may be dropped after getting them.
        TODO: if called after stop is called it may block forever.
        """
        send_channel, receive_channel = trio.open_memory_channel(1)
        # we use this queue for back-pressure
        queue = stdlib_queue.Queue(maxsize=max(self.max_queue_size, 2))
        callback = ThreadExecutor.get_execute_callback_func(obj, callback)
        call_callback = ThreadExecutor.call_execute_callback_func
        do_eof = [None]
        token = trio.lowlevel.current_trio_token()

        async with self._limiter:
            await trio.lowlevel.checkpoint_if_cancelled()

            self._exec_queue.put(
                (obj, sync_gen, args, kwargs or {}, None, token,
                 (send_channel, queue), do_eof))

            result = None
            try:
                # wait until signalled
                async for _ in receive_channel:
                    # get all items from the queue
                    while True:
                        try:
                            result = queue.get(block=False)
                        except Empty:
                            # wait for the next signal
                            break

                        # None means generator is done
                        if result is None:
                            return

                        ret = result.unwrap()

                        call_callback(ret, callback)
                        yield ret
            finally:
                # if we are canceled, notify thread
                do_eof[0] = self.eof

                if result is not None and not isinstance(
                        result, outcome.Error):
                    # we need to wait for last result in case closing returned
                    # an error
                    done = False
                    with trio.CancelScope(shield=True):
                        async for _ in receive_channel:
                            while True:
                                try:
                                    result = queue.get(block=False)
                                except Empty:
                                    break

                                # None means generator is done
                                if result is None:
                                    done = True
                                    break
                                # if not None, unwrap to raise any exception
                                result.unwrap()

                            if done:
                                break

    async def get_echo_clock(self) -> Tuple[int, int, int]:
        def get_time(*args):
            return time.perf_counter_ns()

        ts = time.perf_counter_ns()
        t = await self.execute(None, get_time, callback=NO_CALLBACK)
        return ts, t, time.perf_counter_ns()

    async def sleep(self, duration=None, deadline=None) -> int:
        if duration is not None:
            await trio.sleep(duration)
        elif deadline is not None:
            await trio.sleep(max(0, deadline - time.perf_counter_ns()) / 1e9)
        else:
            raise ValueError('Either deadline or duration must be a number')

        return time.perf_counter_ns()

class AsyncThreadExecutor:
    """Executor that executes async functions in a trio event loop in a
    secondary thread.
    """

    to_thread_portal: Optional['TrioPortal'] = None

    _thread: Optional[threading.Thread] = None

    _limiter: Optional[trio.Lock] = None

    cancel_nursery: Optional[trio.Nursery] = None

    _thread_done_event: Optional[trio.Event] = None

    def __del__(self):
        if self._thread is not None:
            logging.warning(f'stop_executor was not called for "{self}"')

    async def start(self, name='AsyncThreadExecutor'):
        # daemon=True because it might get left behind if we cancel, and in
        # this case shouldn't block process exit.
        event = trio.Event()
        from_thread_portal = TrioPortal()
        self._limiter = trio.Lock()
        done_event = self._thread_done_event = trio.Event()

        thread = self._thread = threading.Thread(
            target=self._worker_thread_fn, name=name,
            args=(event, from_thread_portal, done_event,
                  trio.lowlevel.current_trio_token()))
        thread.start()
        # wait until class variables are set
        await event.wait()

    async def stop(self):
        if not self._thread:
            return

        async def cancel(*args):
            self.cancel_nursery.cancel_scope.cancel()

        await self.execute(None, cancel, callback=NO_CALLBACK)
        await self._thread_done_event.wait()

        self._thread = self._limiter = self.to_thread_portal = None
        self.cancel_nursery = self._thread_done_event = None

    def _worker_thread_fn(
            self, event, from_thread_portal: 'TrioPortal', done_event,
            start_token):
        # This is the function that runs in the worker thread to do the actual
        # work
        async def runner():
            async with trio.open_nursery() as nursery:
                self.to_thread_portal = TrioPortal()
                self.cancel_nursery = nursery
                await from_thread_portal.run_sync(event.set)

                await trio.sleep(math.inf)

        try:
            trio.run(runner)
        finally:
            try:
                start_token.run_sync_soon(done_event.set)
            except trio.RunFinishedError:
                pass

    async def _execute_function(self, obj, async_fn, args, kwargs):
        return await async_fn(obj, *args, **kwargs)

    async def execute(
            self, obj, async_fn, args=(), kwargs=None, callback=None):
        # TODO: if called after stop or thread exited it may block forever.
        async with self._limiter:
            res = await self.to_thread_portal.run(
                self._execute_function, obj, async_fn, args, kwargs or {})

            if callback is not NO_CALLBACK:
                ThreadExecutor.call_execute_callback(obj, res, callback)
        return res

    async def execute_generator(
            self, obj, sync_gen, args=(), kwargs=None, callback=None
    ) -> AsyncGenerator:
        raise NotImplementedError

    async def get_echo_clock(self) -> Tuple[int, int, int]:
        async def get_time(*args):
            return time.perf_counter_ns()

        ts = time.perf_counter_ns()
        t = await self.execute(None, get_time, callback=NO_CALLBACK)
        return ts, t, time.perf_counter_ns()

class TrioPortal(object):
    """Portal for communicating with trio from a different thread.
    """

    trio_token: trio.lowlevel.TrioToken = None

    def __init__(self, trio_token=None):
        if trio_token is None:
            trio_token = trio.lowlevel.current_trio_token()
        self.trio_token = trio_token

    # This is the part that runs in the trio thread
    def _run_cb_async(self, afn, args, task, token):
        @trio.lowlevel.disable_ki_protection
        async def unprotected_afn():
            return await afn(*args)

        async def await_in_trio_thread_task():
            result = await outcome.acapture(unprotected_afn)
            try:
                token.run_sync_soon(trio.lowlevel.reschedule, task, result)
            except trio.RunFinishedError:
                # The entire run finished, so our particular tasks are certainly
                # long gone - it must have cancelled.
                pass

        trio.lowlevel.spawn_system_task(await_in_trio_thread_task, name=afn)

    def _run_sync_cb_async(self, fn, args, task, token):
        @trio.lowlevel.disable_ki_protection
        def unprotected_fn():
            return fn(*args)

        result = outcome.capture(unprotected_fn)
        try:
            token.run_sync_soon(trio.lowlevel.reschedule, task, result)
        except trio.RunFinishedError:
            # The entire run finished, so our particular tasks are certainly
            # long gone - it must have cancelled.
            pass

    @trio.lowlevel.enable_ki_protection
    async def _do_it_async(self, cb, fn, args):
        await trio.lowlevel.checkpoint_if_cancelled()
        self.trio_token.run_sync_soon(
            cb, fn, args, trio.lowlevel.current_task(),
            trio.lowlevel.current_trio_token())

        def abort(raise_cancel):
            return trio.lowlevel.Abort.FAILED
        return await trio.lowlevel.wait_task_rescheduled(abort)

    async def run(self, afn, *args):
        return await self._do_it_async(self._run_cb_async, afn, args)

    async def run_sync(self, fn, *args):
        return await self._do_it_async(self._run_sync_cb_async, fn, args)


# coding=utf-8

from django.test import TestCase

from feedback.models import Person, Veranstaltung, Semester, Kommentar
from feedback.forms import BestellungModelForm, KommentarModelForm

class BestellungModelFormTest(TestCase):
    def setUp(self):
        self.p = []
        self.p.append(Person.objects.create(vorname='Eric', nachname='Idle'))
        self.p.append(Person.objects.create(vorname='John', nachname='Cleese'))
        self.s = Semester.objects.create(semester=20120)
        self.v = Veranstaltung.objects.create(typ='v', name='Life of Brian', semester=self.s,
                                              evaluieren=True, grundstudium=False)
        self.v.veranstalter.add(self.p[0])

        """Alle benötigten Felder wenn an der Evaluation teilgenommen wird mit einem Beispiel"""
        self.fullFormExample = {'anzahl': 100,
                                'sprache': 'de',
                                'verantwortlich': self.p[0].id, }

    def test_init(self):
        with self.assertRaises(KeyError):
            BestellungModelForm()

        form = BestellungModelForm(instance=self.v)
        self.assertItemsEqual(form.fields['verantwortlich'].queryset.all(), (self.p[0],))

    def test_evaluate_leere_bestellung(self):
        """Veranstaltung nimmt an der Evaluation teil. Es werden keine weiteren Felder übertragen"""
        form_data = {'evaluieren': 'on'}
        form = BestellungModelForm(instance=self.v, data=form_data)
        self.assertFalse(form.is_valid(), 'Form wurde als valide evaluiert obwohl Anzahl etc fehlen')

    def test_evaluieren_null_boegen_bestellung(self):
        """Veranstaltng nimmt an der Evaluation teil. Es werden aber 0 Bögen bestellt"""
        form_Data = self.fullFormExample
        form_Data.update({'evaluieren': 'on'})
        form_Data['anzahl'] = 0

        form = BestellungModelForm(instance=self.v, data=form_Data)
        self.assertFalse(form.is_valid(), 'Es wurden 0 Bögen bestellt, trotzdem ist die Bestellung gültig')

    def test_evaluate_partiel_complete_bestellung(self):
        """Veranstaltung nimmt an der Evaluation teil. Es werden nicht alle benötigen Daten übertragen. Alle Kombinationen werden getestet"""
        requiredFields = self.fullFormExample

        # ja es gibt 2^n - 2 kombinationen!
        iterationEnd = pow(2, len(requiredFields)) - 1
        noBits = len(requiredFields) + 2  # +2 für '0b'
        binFormat = "#0%db" % noBits

        for i in range(1, iterationEnd):
            # Wir nehmen immer an der Evaluation teil
            formData = {'evaluieren': 'on'}
            # Die aktuelle Auswahl als nBit String
            selection = format(i, binFormat).split('b')[1]

            # Teste das die Anzahl der Bits immer gleich der Felder ist
            self.assertEqual(len(requiredFields), len(selection),
                             'Die Anzahl Bits stimmt nicht mit der Anzahl der Felder überein')

            # iterriere über die Zeichen im String
            for bitNumber in range(0, len(requiredFields)):
                # Wenn das Bit gesetzt ist
                if selection[bitNumber] == '1':
                    # füge das Feld zum Form hinzu
                    formData.update({requiredFields.keys()[bitNumber]: requiredFields.values()[bitNumber]})

            form = BestellungModelForm(instance=self.v, data=formData)
            self.assertFalse(form.is_valid(),
                             'Form ist valide obwohl nicht alle Felder gesetzt sind. Daten: %s' % str(formData))

    def test_evaluieren_bestellung(self):
        """Veranstaltung nimmt an der Evalution teil. Es werden alle nötigen Daten angegeben"""
        form_data = self.fullFormExample
        form_data.update({'evaluieren': 'on', 'typ': 'vu', 'ergebnis_empfaenger': [self.p[0].id]})
        form = BestellungModelForm(instance=self.v, data=form_data)

        self.assertTrue(form.is_valid(),
                        'Form wurde als invalide evaluiert obwohl alle nötigen Felder angegeben sind. Prüfen ob wirklich alle nötigen Felder angegeben sind')

    def test_nicht_evaluieren_bestellung(self):
        """Veranstaltung nimmt nicht an der Evaluation teil. Jede Bestellung ist gültig."""
        # Aktuell wird eine nicht auswahl von evaluieren mit nicht übertragen
        # des Feldes dargestellt. Darum werden einfach keine Daten übertragen
        form_data = {'typ': 'vu'}
        form = BestellungModelForm(instance=self.v, data=form_data)

        self.assertTrue(form.is_valid(),
                        'Veranstaltung nimmt nicht an der Evaluation teil. Trotzdem ist das Form ungültig')

class KommentarModelFormTest(TestCase):
    def setUp(self):
        self.p = []
        self.p.append(Person.objects.create(vorname='Eric', nachname='Idle'))
        self.p.append(Person.objects.create(vorname='John', nachname='Cleese'))
        self.s = Semester.objects.create(semester=20120)
        self.v = Veranstaltung.objects.create(typ='v', name='Life of Brian', semester=self.s,
                                              evaluieren=True, grundstudium=False)
        self.v.veranstalter.add(self.p[0])
        self.k = Kommentar.objects.create(veranstaltung=self.v, autor=self.p[0], text='Great!')

    def test_init(self):
        with self.assertRaises(KeyError):
            KommentarModelForm(instance=self.k)

        forms = []
        forms.append(KommentarModelForm(veranstaltung=self.v))
        forms.append(KommentarModelForm(instance=self.k, veranstaltung=self.v))
        for f in forms:
            self.assertItemsEqual(f.fields['autor'].queryset.all(), (self.p[0],))


"""
Script containing custom dataset for training triplet classifier
"""
import torch
import numpy as np
from torch.utils.data import Dataset
from sklearn.preprocessing import OneHotEncoder
from collections import Counter
import SimpleITK as sitk

class threeChannelDataset(Dataset):
    def __init__(self, fname, transforms=None, normalise=True, singleLevel=False):
        """
        Custom dataset with Window Level settings instead of dataset-wide rescaling.
        """
        super(threeChannelDataset, self).__init__()
        self.data = np.load(fname, allow_pickle=True)
        self.transforms = transforms
        self.inputs = self.data['slices'][..., np.newaxis]
        self.in_tgts = self.data['targets']
        self.patient_ids = self.data['id']
        self.transforms = transforms
        self.normalise = normalise
        self.img_size = self.inputs.shape[1:3]
        self.ordered_verts = ['T4', 'T5', 'T6', 'T7', 'T8', 'T9',
                              'T10', 'T11', 'T12', 'L1', 'L2', 'L3', 'L4']
        self.norm_inputs = (self.inputs-self.inputs.min()) / \
            (self.inputs.max()-self.inputs.min())
        self.filter_mask = torch.tensor(
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0])
        if singleLevel:
            self.masks = self.single_level_prep(level='L3')
        else:
            self.masks = np.argmax(np.squeeze(self.data['masks'], axis=-1))# (252, ~600, ~400, 14)

    def __len__(self):
        return len(self.inputs)

    def __getitem__(self, index):
        if self.normalise:
            img = self.norm_inputs[index]
        else:
            img = self.inputs[index]
        targets = self.in_tgts[index]
        labels = [key for key in targets.keys()]
        # Order targets + convert to tensors
        targets = [tuple(val) for val in targets.values()]
        img = self.convert_threeChannel(img)
        if self.transforms:

            augmented = self.transforms(image=img, keypoints=targets, mask=self.masks[index], class_labels=labels)
            aug_img, aug_tgt, aug_mask, aug_labels = augmented[
                'image'], augmented['keypoints'], augmented['mask'], augmented['class_labels']
            # Normalise between [-1, 1]
            # Present_tnsr = binary vector showing presence of verts
            #aug_tgt, present_tnsr= self.norm_tgt(aug_tgt, aug_labels)
            aug_tgt = self.norm_tgt_singleLevel(aug_tgt, aug_labels, level='L3')
            aug_tgt = aug_tgt.unsqueeze(0)
            sample = {'inputs': aug_img, 'targets': aug_tgt,
                    'masks': aug_mask,
                    'class_labels': self.ordered_verts,
                    'present': self.filter_mask,
                    'id': self.patient_ids[index]}
        else:
            print('Need some transforms - minimum convert to Tensor')
            return
        return sample

    def single_level_prep(self, level='T12'):
        """
        Radius in mm
        Assumes inputs have been resampled to 0.3125 and downsampled by 1/4 i.e. pixel size = 1.25mm
        """
        channel = self.ordered_verts.index(level)
        masks = np.squeeze(self.data['masks'])[..., channel+1]
        return np.where(masks != 0, 1, 0)  # Out shape (batch, H, W, 1)

    def write_patient_info(self, filename):
        """
        Write patient ids to text file
        """
        with open(filename, 'w') as f:
            f.write(f'Training Set Size: {len(self.patient_ids)}\n')
            f.write('Patient IDs: \n')
            for i, id in enumerate(self.patient_ids):
                f.write(f'{i}: {id}\n')

    def convert_threeChannel(self, img):
        # Convert to list to enable index assignment
        img_shape_list = list(img.shape)
        img_shape_list[-1] = 3
        threeChannelImg = np.zeros((tuple(img_shape_list)))
        threeChannelImg[..., 0] = img[..., 0]
        threeChannelImg[..., 1] = img[..., 0]
        threeChannelImg[..., 2] = img[..., 0]
        return threeChannelImg

    def write_categories(self, filename):
        """
        Write mapping from triplet names to one hot encoding to a text file
        """
        arg_labels = [int(x) for x in np.asarray(self.targets)]
        counts = Counter(arg_labels)
        with open(filename, 'w') as f:
            f.write(f'Vert encoding: {self.categories}\n')
            for i, cat in enumerate(self.categories):
                f.write(f'{cat}: {counts[i]}\n')

    def norm_tgt(self, targets, labels):
        out_list = []
        presence_list = []
        for vert in self.ordered_verts:
            if vert in labels:
                idx = labels.index(vert)
                elem = targets[idx]
                coords = torch.tensor(elem)
                norm_coords = (coords * 2 + 1) / \
                    torch.Tensor(self.img_size) - 1
                out_list.append(norm_coords)
                presence_list.append(1)
            else:
                coords = torch.Tensor((0.0, 0.0))
                out_list.append(coords)
                presence_list.append(0)
        out_tensor = torch.stack(out_list, dim=0)
        out_present = torch.tensor(presence_list)
        return out_tensor, out_present

    def norm_tgt_singleLevel(self, targets, labels, level='T12'):

        if level in labels:
            idx = labels.index(level)
            elem = targets[idx]
            coords = torch.tensor(elem)
            norm_coords = (coords * 2 + 1) / \
                torch.Tensor(self.img_size) - 1
            return norm_coords
        else:
            return torch.Tensor((0.0, 0.0))


from sklearn.metrics import silhouette_samples, silhouette_score
import time
import numpy as np
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans
from util import getAdultData, getWineData
from sklearn import metrics
from scipy.spatial.distance import cdist

data = getWineData()

dataX = data.iloc[:,:-1]
dataY = data.iloc[:,-1]

clusters =  [2,3,4,5,6,7,8,9,10]

distortions = []
# time1 = []
# ARSk = []
# AMISk = []
# HSk = []
# CSk = []
# VMSk = []
Sil = []
SSE = []
for k in clusters:
    start_time = time.time()

    kmeanModel = KMeans(n_clusters=k, max_iter = 500, random_state=0,init="k-means++").fit(dataX)
    kmeanModel.fit(dataX)
    prediction = kmeanModel.fit_predict(dataX)
    end_time = time.time()

    sil_avg = silhouette_score(dataX, prediction)
    # ARS = metrics.adjusted_rand_score(dataY, prediction)
    # AMIS = metrics.adjusted_mutual_info_score(dataY, prediction)
    # HS = metrics.homogeneity_score(dataY, prediction)
    # CS = metrics.completeness_score(dataY, prediction)
    # VMS = metrics.v_measure_score(dataY, prediction)
    sse = (kmeanModel.score(dataX) * -1) / 100000000000000.0

    # ARSk.append(ARS)
    # AMISk.append(AMIS)
    # HSk.append(HS)
    # CSk.append(CS)
    # VMSk.append(VMS)
    Sil.append(sil_avg)
    SSE.append(sse)

    cls_time = end_time - start_time
    # time1.append(cls_time)
    distortions.append(sum(np.min(cdist(dataX, kmeanModel.cluster_centers_, 'euclidean'), axis=1)) / dataX.shape[0])

# print("time:", time1)
# print("Adjusted Random Score:", ARSk)
# print("AMIS:", AMISk)
# print("HS:", HSk)
# print("CS:", CSk)
# print("VMS:", VMSk)
print("Sil:", Sil)
print("SSE:", SSE)
# Plot the elbow
# plt.plot(clusters, AMISk, label = "Mutual info")
# plt.plot(clusters, ARSk, label = "Adjusted Random")
# plt.plot(clusters, HSk, label = "homogeneity")
# plt.plot(clusters, CSk, label = "completeness")
# plt.plot(clusters, VMSk, label = "v_measure")
# plt.plot(clusters, distortions, "bx-")

plt.plot(clusters,SSE, label = "Sum of squared error")
plt.plot(clusters,Sil, label = "Silhouette Average")

plt.xlabel('k')
# plt.ylabel('Distortion')
# plt.title('The Elbow Method showing the optimal k')
plt.ylabel('Score')
plt.title('Different score showing the optimal k')
plt.legend()
plt.grid()
plt.show()

plt.plot(clusters,distortions, label = "distortions Average")
plt.xlabel('k')
plt.ylabel('Distortion')
plt.title('The Elbow Method showing the optimal k')
plt.legend()
plt.grid()
plt.show()


"""
technical.py

A Flask Blueprint module for the technical site.
"""
from flask import Blueprint, render_template, current_app, g, abort
from .. import common as c
from meerkat_frontend import auth
from slugify import slugify
import meerkat_frontend
import json

technical = Blueprint('technical', __name__, url_prefix='/<language>')

@technical.before_request
def requires_auth():
    """
    Checks that the user has authenticated before returning any page from
    this Blueprint.
    """
    # We load the arguments for check_auth function from the config files.
    auth.check_auth(
        *current_app.config['AUTH'].get('technical', [['BROKEN'], ['']])
    )

@technical.route('/')
@technical.route('/<tab>')
@technical.route('/<tab>/loc_<int:locID>')
def index(tab=None, locID=None):
    """
    Serves a tab for the technical dashboard, filtered by the specified
    location.
    """
    # Initialise locID to allowed location
    # Can't be done during function declaration because outside app context
    locID = g.allowed_location if not locID else locID

    # If no tab is provided, load the first tab in the tab list the user
    # has access to.
    tabs = current_app.config['TECHNICAL_CONFIG']['tabs']
    if tab is None:
        for t in tabs:
            country = current_app.config['TECHNICAL_CONFIG']['auth_country']
            tab_access = t.get('access', False)
            in_arr = meerkat_frontend.in_array(
                tab_access,
                g.payload['acc'][country]
            )
            if in_arr or not tab_access:
                tab = t
                break
    else:
        try:
            tab = next(filter(lambda t: slugify(t['name']) == tab, tabs))
        except StopIteration:
            abort(404, '{} page does not exist'.format(tab))

    # Create a page state object defining the page to be shown
    page_state = {
        'type': 'tab',
        'dataID': slugify(tab['name']),
        'locID': str(locID),
        **tab
    }
    page_state.pop("access", None)
    page_state.pop("name", None)
    page_state = json.dumps(page_state)

    return render_template(
        'technical/index.html',
        content=g.config['TECHNICAL_CONFIG'],
        page=page_state,
        langauge=g.get("language", current_app.config["DEFAULT_LANGUAGE"]),
        week=c.api('/epi_week'),
        user=g.payload
    )

@technical.route('/alerts/<alertID>')
def alert(alertID=1):
    """
    Serves an individual alert investigation report for the given alert ID.
    """
    pageState = "{ type: 'alert', dataID: '" + alertID + "' }"
    return render_template(
        'technical/index.html',
        content=g.config['TECHNICAL_CONFIG'],
        page=pageState,
        langauge=g.get("language", current_app.config["DEFAULT_LANGUAGE"]),
        week=c.api('/epi_week')
    )

@technical.route('/diseases/<diseaseID>/')
@technical.route('/diseases/<diseaseID>/loc_<int:locID>')
def disease(diseaseID='tot_1', locID=None):
    """
    Serves a disease report page for the given aggregation variable and
    lcoation ID.
    """
    # Initialise locID to allowed location
    # Can't be done during function declaration because outside app context
    locID = g.allowed_location if not locID else locID

    pageState = ("{ type: 'disease', dataID: '" + str(diseaseID) +
                 "', locID: " + str(locID) + " }")
    return render_template(
        'technical/index.html',
        content=g.config['TECHNICAL_CONFIG'],
        page=pageState,
        langauge=g.get("language", current_app.config["DEFAULT_LANGUAGE"]),
        week=c.api('/epi_week')
    )


import wx
import common
import wcodegen
from edit_windows import ManagedBase, EditStylesMixin
from tree import Node
import new_properties as np

class EditStaticLine(ManagedBase, EditStylesMixin):
    "Class to handle wxStaticLine objects"
    _PROPERTIES = ["Widget", "attribute"]
    PROPERTIES = ManagedBase.PROPERTIES + _PROPERTIES + ManagedBase.EXTRA_PROPERTIES
    PROPERTIES.remove("font")
    _PROPERTY_LABELS = {"attribute":'Store as attribute'}
    _PROPERTY_HELP={"attribute":'Store instance as attribute of window class; e.g. self.line_1 = wx.wxStaticLine(...)\n'
                                'Without this, you can not access the line from your program.'}
    def __init__(self, name, parent, id, style, sizer, pos):
        ManagedBase.__init__(self, name, 'wxStaticLine', parent, id, sizer, pos)
        EditStylesMixin.__init__(self)

        # initialise instance properties
        self.attribute = np.CheckBoxProperty(False, default_value=False)
        if style: self.properties["style"].set(style)

    def create_widget(self):
        self.widget = wx.StaticLine(self.parent.widget, self.id, style=self.style)
        wx.EVT_LEFT_DOWN(self.widget, self.on_set_focus)

    def finish_widget_creation(self):
        ManagedBase.finish_widget_creation(self)
        self.sel_marker.Reparent(self.parent.widget)
        #del self.properties['font']

    def __getitem__(self, key):
        if key != 'font':
            return ManagedBase.__getitem__(self, key)
        return lambda: "", lambda v: None

editor_class = EditStaticLine
editor_icon = 'static_line.xpm'
editor_name = 'EditStaticLine'
editor_style = ''

dlg_title = _('wxStaticLine')
box_title = _('Orientation')
choices = 'wxLI_HORIZONTAL|wxLI_VERTICAL'
tmpl_label = 'static_line'

def builder(parent, sizer, pos, number=[1]):
    "factory function for editor objects from GUI"
    dialog = wcodegen.WidgetStyleSelectionDialog(dlg_title, box_title, choices)
    res = dialog.ShowModal()
    style = dialog.get_selection()
    dialog.Destroy()
    if res != wx.ID_OK:
        return

    label = '%s_%d' % (tmpl_label, number[0])
    while common.app_tree.has_name(label):
        number[0] += 1
        label = '%s_%d' % (tmpl_label, number[0])
    widget = editor_class(label, parent, wx.ID_ANY, style, sizer, pos)
    node = Node(widget)
    widget.node = node
    if parent.widget: widget.create()
    common.app_tree.insert(node, sizer.node, pos-1)

def xml_builder(attrs, parent, sizer, sizeritem, pos=None):
    "Factory to build editor objects from a XML file"
    from xml_parse import XmlParsingError
    try:
        name = attrs['name']
    except KeyError:
        raise XmlParsingError(_("'name' attribute missing"))
    if sizer is None or sizeritem is None:
        raise XmlParsingError(_("sizer or sizeritem object cannot be None"))
    widget = editor_class(name, parent, wx.ID_ANY, editor_style, sizer, pos)
    sizer.set_item(widget.pos, proportion=sizeritem.proportion, flag=sizeritem.flag, border=sizeritem.border)
    node = Node(widget)
    widget.node = node
    if pos is None:
        common.app_tree.add(node, sizer.node)
    else:
        common.app_tree.insert(node, sizer.node, pos-1)
    return widget

def initialize():
    "initialization function for the module: returns a wxBitmapButton to be added to the main palette"
    common.widgets[editor_name] = builder
    common.widgets_from_xml[editor_name] = xml_builder
    return common.make_object_button(editor_name, editor_icon)


import torch
import torch.nn as nn
from torch.autograd import Variable
import math
import torch.nn.functional as F

def check_unitFraction(x):
    a = 1/x
    return a==int(a)

class S2Conv(nn.Module):
    # q is parameter that control output channel size.
    def __init__(self, c_in, shift_size, q=1, dilation=1):
        super(S2Conv, self).__init__()
        self.c_in = c_in
        self.shift_size = shift_size
        self.d = dilation
        self.q = q
        if q<1:
            self.conv = nn.Conv1d(int(self.shift_size*c_in*q), int(c_in*q), kernel_size=1, padding=0, stride=1, bias=False, groups=int(c_in*q))
        elif q>=1:
            self.conv = nn.Conv1d(self.shift_size*c_in, int(c_in*q), kernel_size=1, padding=0, stride=1, bias=False, groups=c_in)
        self.bn = nn.BatchNorm1d(int(c_in*q))

    def shift(self, x):
        out = torch.zeros_like(x)
        for k in range(self.c_in):
            sh_n = (k % self.shift_size) - (self.shift_size//2) # if shift_size=7, sh_n -> -3~3
            sh_n = sh_n * self.d
            if sh_n < 0:
                out[:, k, :sh_n] = x[:, k, -sh_n:]  # shift left
            elif sh_n >0:
                out[:, k, sh_n:] = x[:, k, :-sh_n]  # shift right
            else:
                out[:,k,:] = x[:,k,:] # not shift

        return out

    def forward(self, x):
        x = self.shift(x)
        n, c, t = x.size()
        pad = self.shift_size//2
        t_p = Variable(torch.zeros(n, pad, t))
        if self.shift_size % 2 ==0:
            pad = pad -1
        b_p = Variable(torch.zeros(n, pad, t))

        if next(self.parameters()).is_cuda:
            t_p = t_p.cuda()
            b_p = b_p.cuda()

        x = torch.cat((t_p, x, b_p), dim=1)
        if self.q <= 1:
            stride=int(1/self.q)
        else:
            stride = 1
        h = torch.cat([x[:,i*stride:i*stride+self.shift_size,:] for i in range((x.size(1)-self.shift_size+1)//stride)], dim=1)
        out = self.conv(h)
        out = self.bn(out)
        return F.relu_(out)

class BasicConv1d(nn.Module):
    def __init__(self, i_nc, o_nc, **kwargs):
        super(BasicConv1d, self).__init__()
        self.conv = nn.Sequential(
            nn.Conv1d(i_nc, o_nc, **kwargs),
            nn.BatchNorm1d(o_nc)
        )
    def forward(self, x):
        x = self.conv(x)
        return F.relu_(x)

class MTS_module(nn.Module):
    def __init__(self, i_nc, o_nc, n_b):
        super(MTS_module, self).__init__()
        self.o_ncs = self.split_branch(o_nc, n_b+1)
        self.l1 = BasicConv1d(i_nc, self.o_ncs[0], kernel_size=1, stride=1, padding=0, bias=False)
        self.ls = nn.ModuleList()
        for i in range(n_b):
            shift_size = i*2+3
            self.ls.append(S2Conv(self.o_ncs[i+1], shift_size))
    def forward(self, x):
        x1 = self.l1(x)
        tx = x1[:,:self.o_ncs[1],:]
        out = torch.cat([conv(tx) for conv in self.ls], dim=1)
        outputs = torch.cat([x1, out], dim=1)
        return outputs
    def split_branch(self, total_channels, num_groups):
        import numpy as np
        split = [int(np.floor(total_channels / num_groups)) for _ in range(num_groups)]
        split[0] += total_channels - sum(split)
        return split

class MTS_ConvNet(nn.Module):
    def __init__(self, in_nc, class_num, segment_size):
        super(MTS_ConvNet, self).__init__()
        n_fs = 64
        self.T = segment_size
        n_b = 3

        self.stem = BasicConv1d(in_nc, n_fs, kernel_size=1, stride=1, padding=1,bias=False)

        if in_nc == 113: # in case of OPPORTUNITY
            self.conv1 = MTS_module(n_fs, n_fs*2, n_b)
            self.conv2 = MTS_module(n_fs*2, n_fs, n_b)
        else:
            self.conv1 = MTS_module(n_fs, n_fs, n_b)
            self.conv2 = MTS_module(n_fs, n_fs, n_b)
        self.conv3 = MTS_module(n_fs, n_fs, n_b)
        self.conv4 = MTS_module(n_fs, n_fs*2, n_b)
        self.conv5 = MTS_module(n_fs*2, n_fs*4, n_b)

        self.fc = nn.Linear(n_fs*4, class_num)

    def forward(self, x):
        x = self.stem(x)

        x = self.conv1(x)
        x = self.conv2(x)
        x = self.conv3(x)
        x = F.adaptive_max_pool1d(x,self.T//2)
        x = self.conv4(x)
        x = F.adaptive_max_pool1d(x,self.T//4)
        x = self.conv5(x)
        x = F.adaptive_avg_pool1d(x,1)
        x = x.view(x.size(0), -1)

        x = self.fc(x)
        return x


import discord
import discord.utils
import asyncio
from discord.ext.commands import Bot
from discord.ext import commands
import platform
import sys
import sqlite3
import MySQLdb
import datetime
import os
import json
from pprint import pprint

client = Bot(description="Butler utility for AGC Server",
             command_prefix="*", pm_help=False)

@client.event
async def on_ready():
    await client.wait_until_ready()
    print('Current Discord.py Version: {} | Current Python Version: {}'.format(
        discord.__version__, platform.python_version()))
    print('--------')
    print('Use this link to invite {}:'.format(client.user.name))
    print('https://discordapp.com/oauth2/authorize?client_id={}&scope=bot&permissions=8'.format(client.user.id))
    print('--------')
    print('You are running AGC Butler[BETA]')
    print('Created by bot-steev0#0420')
    game = discord.Game("At your service, master")
    return await client.change_presence(status=discord.Status.idle, activity=game)

#! GLOBAL VARIABLES FOR SERVER

conn = MySQLdb.connect("localhost", "butler", "Zer045kin!", "agc_butler")
c = conn.cursor()

key_file = open('./api_key.txt', 'r')
if not key_file:
    print('File key.txt can\'t be found')
    sys.exit(0)

api_key = key_file.read().splitlines()[0]
if not api_key:
    print('No API key in discord_key.txt')
    sys.exit(0)

key_file.close()

msg_buffer = []
nadeko_lb = []

async def spin_db(message):
    await client.wait_until_ready()
    today = datetime.datetime.today().date().__format__("%Y-%m-%d")
    server_member_total = 0
    server = client.get_guild(458888334291369987)
    server_members = server.members
    spawn_date = datetime.datetime.today().date().__format__("%Y-%m-%d")
    dev_spam = client.get_channel(458904356016619521)
    print(server)
    c.execute('DELETE from user_information')
    for member in server_members:
        if member.bot == False:
            c.execute('INSERT INTO user_information(user_discord_id, user_nickname, user_total_xp, user_current_level, user_last_msg) VALUES(%s,%s,%s,%s,%s)', (member.id, member.name, 0, 0, today))
            server_member_total += 1
            print(member.id, today)
    conn.commit()
    c.execute('SELECT count("user_id") FROM user_information')
    db_count = c.fetchall()
    (user_id,) = db_count[0]
    await dev_spam.send('Database has been filled with members from Server: '+str(server)+'\nServer Member Count: '+str(server_member_total)+'\nDatabase Member Count: '+str(user_id))

# async def backup_db(message):

# async def spawn_webclient(message):
# https://discord.gg/tC4EedV

# async def clear_messages(message, user, num_msgs)

async def db_update(message, msg_buffer):

    await client.wait_until_ready()

    while not client.is_closed:

        await client.send_message(message.channel, msg_buffer)

        print('CURRENT BUFFER\n')
        de_duped_buffer = list(set(msg_buffer))
        print(de_duped_buffer)
        print('\n')
        msg_buffer.clear()
        if len(msg_buffer) == 0:
            print('Main Buffer Cleared')
        else:
            print('Failed to clear Main Buffer')

        for user_data in de_duped_buffer:

          # Message Buffer Info
            user_data = user_data.split('_')
            buffer_user_id = user_data[0]
            new_date = '2018-05-10'  # user_data[1]

            # SQL Info
            c.execute('SELECT * FROM user_info WHERE user_id == (?)',
                      (buffer_user_id,))
            user_entry = c.fetchall()

            if len(user_entry) == 0:
                c.execute('INSERT INTO user_info VALUES(?,?)',
                          (buffer_user_id, new_date))
                await client.send_message(message.channel, 'UserID: '+buffer_user_id+' has been inserted into the DB with the latest date of: ' + new_date)
                conn.commit()
            else:
                c.execute(
                    'UPDATE user_info SET date_time = (?) WHERE user_id == (?)', (new_date, buffer_user_id))
                await client.send_message(message.channel, 'UserID: '+buffer_user_id+' has been updated in the DB with the latest date of: '+new_date)
                conn.commit()

        de_duped_buffer.clear()

        if len(de_duped_buffer) == 0:
            print('Auxiliary Buffer Cleared')
        else:
            print('Failed to clear Auxiliary Buffer')

        await asyncio.sleep(120)

@client.event
async def on_message(message):
    await client.wait_until_ready()

    # if message.content.startswith('*'):
    #   pass
    # else
    #   msg_buffer.append(message.author.id+'_'+today)
    # if bool(server) == False:
    #    await client.send_message(dev_spam,'Apologies sir, but it would seem that you have not yet #configured the server parameters, please do so by executing the `*init` command.')
    #else:

    if message.content.startswith('*bot'):
        await client.send_message(message.channel, 'Beep Boop Beep')

    elif message.content.startswith('*update'):
        client.loop.create_task(db_update(message, msg_buffer))
        await client.send_message(message.channel, 'Database Update Task Initialised')

    elif message.author.id == 116275390695079945 and len(message.embeds)>0:
        #~ Piece of shit emojis to handle Nadeko's leaderboard interaction
        #~ U+2B05 	\xE2\xAC\x85 ⬅
        #~ U+27A1 	\xE2\x9E\xA1 ➡
        me = discord.utils.get(server_members, name='- bot steev -')
        await asyncio.sleep(4)
        nadeko_lb.append(message.embeds)
        print('page: 1')
        print(nadeko_lb)
        for x in range(10):
            await client.wait_for_reaction(emoji='\u27A1')
            await asyncio.sleep(2)
            nadeko_lb.append(message.embeds)
            print('page:'+str(x+x))
            print(message.embeds)
            await client.remove_reaction(message,'\u27A1',me)
            await asyncio.sleep(2)
            nadeko_lb.append(message.embeds)
            print('page:'+str((x+x)-1))
            print(message.embeds)

    elif message.content.startswith('*write'):
        print('\n\n\n')
        with open('AGC_Leaderboard_JSON.txt', 'a') as f:
            for nadeko_lb_page in nadeko_lb:
                for page_info in nadeko_lb_page:
                    f.write(json.dumps(page_info))
        f.close

    elif message.content.startswith('*parse'):
        with open('AGC_Leaderboard.JSON', 'r') as f:
            json_data = json.load(f)
            cntr = 0
            for x in json_data:
                raw_fields = json_data[cntr]['fields']
                cntr2 = 0
                for y in raw_fields:
                    raw_entry_value = raw_fields[cntr2]['value']
                    raw_entry_name = raw_fields[cntr2]['name']

                    split_entry_value = raw_entry_value.split('-')

                    final_entry_value = split_entry_value[1].lstrip()
                    final_entry_name = raw_entry_name[3:].lstrip()

                    print(final_entry_name + ' ' + final_entry_value)
                    cntr2 += 1
                cntr += 1
        f.close()

    elif message.content.startswith('*clfilelb'):
        with open('AGC_Leaderboard_JSON.txt', 'w') as f:
            f.write('')
        f.close()
        nadeko_lb.clear()

    elif message.content.startswith('*spindb'):
        await spin_db(message)

    #elif message.content.startswith('*test'):
    #    for member in server_members:
    #        if member.bot == False:
    #            mem_roles = server.get_member(member.id).roles
    #            for role in mem_roles:
    #                if role.id == '446281091603628033':
    #                    print(member, role, today)
    #                elif role.id == '446281026894037003':
    #                    print(member, role)
    #                elif role.id == '446280876658262017':
    #                    print(member, role)
    #                elif role.id == '446280757183512586':
    #                    print(member, role)
    #        else:
    #            pass
    #    conn.commit()
    #    await client.send_message(message.channel, 'Info to terminal')

client.run(str(api_key))


"""
This is the FIT2085 implementation of Binary Tree

"""
from linked_list import LinkedList
from typing import TypeVar, Generic, Callable, List
K = TypeVar('K')
I = TypeVar('I')

class BinarySearchTreeNode(Generic[K, I]):

    def __init__(self, key: K, item:I=None)->None:
        self.key = key
        self.item = item
        self.left = None
        self.right = None

    def __str__(self)->str:
        return "( " + str(self.key) + " , " + str(self.item) + " )"

class BinarySearchTree(Generic[K, I]):

    def __init__(self)->None:
        self.root = None

    def is_empty(self)->bool:
        return self.root is None

    def __len__(self):
        return self._len_aux(self.root)

    def _len_aux(self, current:BinarySearchTreeNode[K, I])->int:
        if current is None:
            return 0
        else:
            return 1+ self._len_aux(current.left) + self._len_aux(current.left)

    # def find(self, key:K)->bool:
    #     return self.find_aux(self.root, key)

    def find_aux(self, current: BinarySearchTreeNode[K, I], key, K)->bool:
        if current is None:
            return False
        elif current.key == key:
            return True
        elif key < current.key:
            return self.find_aux(current.left, key)
        else:
            return self.find_aux(current.right, key)

    def __contains__(self, key:K):
        return self.find_aux(self.root, key)

    def __getitem__(self, key: K) -> I:
        return self.getitem_aux(self.root, key)

    def getitem_aux(self, current: BinarySearchTreeNode[K, I], key: K) -> I:
        if current is None:  # base case: empty
            raise KeyError("Key not found")
        elif key == current.key:  # base case: found
            return current.item
        elif key < current.key:
            return self.getitem_aux(current.left, key)
        else:  # key > current.key
            return self.getitem_aux(current.right, key)

    def __setitem__(self, key: K, item: I) -> None:
        self.root = self.insert_aux(self.root, key, item)

    def insert_aux(self, current: BinarySearchTreeNode[K, I], key: K, item: I) -> None:
        if current is None:  # base case: at the leaf
            current = BinarySearchTreeNode(key, item)
        elif key < current.key:
            current.left = self.insert_aux(current.left, key, item)
        elif key > current.key:
            current.right = self.insert_aux(current.right, key, item)
        else:  # key == current.key
            current.item = item
        return current

    def height(self):
        return self.height_aux(self.root)

    def height_aux(self, current: BinarySearchTreeNode[K,I]):
        if current is None:
            return 0
        else:
            return 1 + max(self.height_aux(current.left), self.height_aux(current.right))

    def is_leaf(self, node: BinarySearchTreeNode[K,I])->bool:
        return node.left is None and node.right is None

    def get_leaves(self) -> LinkedList:
        a_list = LinkedList(len(self))
        self.get_leaves_aux(self.root, a_list)
        return a_list

    def get_leaves_aux(self, current: BinarySearchTreeNode[K, I], a_list: LinkedList) -> None:
        if current is not None:
            if self.is_leaf(current):
                a_list.append(current.item)
            else:
                self.get_leaves_aux(current.left, a_list)
                self.get_leaves_aux(current.right, a_list)

    def sum_leaves(self)->int:
        return self.sum_leaves_aux(self.root)

    def sum_leaves_aux(self, current:BinarySearchTreeNode[K,I])->int:
        if current is None:
            return 0
        elif self.is_leaf(current):
            return current.item
        else:
            return self.sum_leaves_aux(current.left) + self.sum_leaves_aux(current.right)

    def in_between(self, a: K, b:K)->List[I]:
        lst=[]
        self.in_between_aux(self.root, a,b,lst)
        return lst

    def in_between_aux(self, current: BinarySearchTreeNode[K,I], a: K, b:K, lst:List[I])->None:
        if current is not None:
            if current.key > a:
                self.in_between_aux(current.left,a,b,lst)
            # if current.key > a and current.key < b:
            if a <=  current.key <= b:
                lst.append(current.item)
            if current.key < b:
                self.in_between_aux(current.right,a,b,lst)

    def pre_order(self, f:Callable)->None:
        self.pre_order_aux(self.root, f)

    def pre_order_aux(self, current: BinarySearchTreeNode[K, I], f:Callable)->None:
        if current is not None:
            f(current.item)
            self.pre_order_aux(current.left)
            self.pre_order_aux(current.right)

    def k_largest(self,k:int)->I:
        lst = []
        self.k_largest_aux(self.root, k, lst)
        return lst[-1]

    def k_largest_aux(self, current: BinarySearchTreeNode[K,I],k,lst)->None:
        if current is not None:
            print(current.item)
            self.k_largest_aux(current.right,k,lst)
            if len(lst) < k:
                lst.append(current.item)
                self.k_largest_aux(current.left,k,lst)

    def find_min(self)->K:
        if self.root is None:
            return None
        else:
            return self.find_min_aux(self.root)

    def find_min_aux(self, current:BinarySearchTreeNode[K,I])->K:
        if current.left is None:
            return current.key
        else:
            self.find_min_aux(current.left)

if __name__=="__main__":
    b = BinarySearchTree()
    b[5] = 5
    b[1] = 1
    b[9] = 9
    b[8] = 8
    b[3] = 3
    b[4] = 4
    b[2] = 2
    b[10] = 10
    b[7] = 7
    b[6] = 6
    print("---", b.k_largest(3))


import os
import sys
import numpy as np
import cv2
import glob

# 카메라 캘리브레이션
def calibrate_camera(checkerboard_size, images_path):
    objp = np.zeros((checkerboard_size[0] * checkerboard_size[1], 3), np.float32)
    objp[:, :2] = np.mgrid[0:checkerboard_size[0], 0:checkerboard_size[1]].T.reshape(-1, 2)

    # 각 이미지에 대한 3D 포인트 및 이미지 포인트를 저장할 배열
    objpoints = [] # 3d 포인트
    imgpoints = [] # 2d 포인트

    # 체스보드 이미지 로드
    images = glob.glob(images_path)
    corner_criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001)

    for fname in images:
        print("이미지 :", fname)
        img = cv2.imread(fname)
        gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

        # 체스보드 코너 찾기
        isFind, corners = cv2.findChessboardCorners(gray, checkerboard_size, None)

        # 코너 찾은 경우
        if isFind:
            objpoints.append(objp)
            corners2 = cv2.cornerSubPix(gray, corners, (11,11), (-1,-1), corner_criteria)
            imgpoints.append(corners2)

    # cv2.destroyAllWindows()
    # 카메라 캘리브레이션
    ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(objpoints, imgpoints, gray.shape[::-1], None, None)
    return ret, mtx, dist

def android_camera():
    video = cv2.VideoCapture(1) # 0은 노트북 웹캠

    width = int(video.get(3)) # 가로 길이 가져오기
    height = int(video.get(4)) # 세로 길이 가져오기

    # video.set(cv2.CAP_PROP_FPS, 60)
    fps = video.get(cv2.CAP_PROP_FPS)
    print(f"W : {width}, H : {height}, fps : {fps}")

    return video

# 체스보드 코너 설정
checkerboard_size = (4, 4)
ret, mtx, dist = calibrate_camera(checkerboard_size, 'Images/*.png')
dist = np.zeros(5)

REF_DIR = f'Reference/'
if not os.path.exists(REF_DIR):
    os.makedirs(REF_DIR)

video = android_camera()

# 레퍼런스 영상 저장
while True:
    isValid, frame = video.read()
    if not isValid:
        print("Fail to read frame!")
        break

    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    cv2.imshow('frame', frame)

    key = cv2.waitKey(1)
    if key == ord(' '):
        # 체스보드 코너 찾기
        ret, corners = cv2.findChessboardCorners(gray, checkerboard_size, None)
        if ret == True:
            objp = np.zeros((checkerboard_size[0] * checkerboard_size[1], 3), np.float32)
            objp[:, :2] = np.mgrid[0:checkerboard_size[0], 0:checkerboard_size[1]].T.reshape(-1, 2)

            # 회전 및 변환 벡터를 계산
            _, tmp_rvec, tmp_tvec = cv2.solvePnP(objp, corners, mtx, dist)

            cv2.imwrite(f'{REF_DIR}ref.png', frame)

            # DB에 저장
            np.savez(f'{REF_DIR}ref_pose', ref_rvec=tmp_rvec, ref_tvec=tmp_tvec)
        break
    elif key == ord('q'):
        break

def triangulate_points(P1, P2, pts1, pts2):
    num_points = pts1.shape[0]
    X = np.zeros((num_points, 4))

    for i in range(num_points):
        A = np.zeros((4, 4))
        A[0] = pts1[i, 0] * P1[2] - P1[0]
        A[1] = pts1[i, 1] * P1[2] - P1[1]
        A[2] = pts2[i, 0] * P2[2] - P2[0]
        A[3] = pts2[i, 1] * P2[2] - P2[1]

        # 특이값 분해를 통해 최소 고유 벡터를 찾는다
        _, _, V = np.linalg.svd(A)
        X[i] = V[-1, :]

    X /= X[:, 3][:, np.newaxis]

    return X[:, :3]

# 투영 오차 계산
def calculate_reprojection_error(features_worldaxis, img_pts, rvec, tvec, mtx, dist):
    # img_pts_reprojected, _ = cv2.projectPoints(features_worldaxis, rvec, tvec, mtx, dist)
    img_pts_reprojected = project_points(features_worldaxis, rvec, tvec, mtx)
    img_pts_reprojected = img_pts_reprojected.reshape(-1, 2).astype(np.float32)
    img_pts = img_pts.astype(np.float32)
    errors = np.sqrt(np.sum((img_pts - img_pts_reprojected)**2, axis=1))
    return errors

def project_points(points_3d, rvecs, tvecs, camera_matrix):
    R, _ = cv2.Rodrigues(rvecs) # 회전 벡터 -> 회전 행렬
    RT = np.concatenate((R, tvecs), axis=1) # 외부 매개변수 행렬
    P = np.matmul(camera_matrix, RT) # 투영 행렬

    points_3d_homogeneous = np.concatenate((points_3d, np.ones((points_3d.shape[0], 1))), axis=1) # 동차 좌표로 변환
    points_2d = np.matmul(P, points_3d_homogeneous.T).T # 평면에 투영

    # 정규화한다
    for i in range(points_2d.shape[0]):
        points_2d[i, 0] /= points_2d[i, 2]
        points_2d[i, 1] /= points_2d[i, 2]
        points_2d[i, 2] = 1

    return points_2d[:, :2]

# 투영 및 렌더링
def project_points(points_3d, rvecs, tvecs, camera_matrix):
    R, _ = cv2.Rodrigues(rvecs) # 회전 벡터 -> 회전 행렬
    RT = np.concatenate((R, tvecs), axis=1) # 외부 매개변수 행렬
    P = np.matmul(camera_matrix, RT) # 투영 행렬

    points_3d_homogeneous = np.concatenate((points_3d, np.ones((points_3d.shape[0], 1))), axis=1) # 동차 좌표로 변환
    points_2d = np.matmul(P, points_3d_homogeneous.T).T # 평면에 투영

    # 정규화한다
    for i in range(points_2d.shape[0]):
        points_2d[i, 0] /= points_2d[i, 2]
        points_2d[i, 1] /= points_2d[i, 2]
        points_2d[i, 2] = 1

    return points_2d[:, :2]

video.release()
cv2.destroyAllWindows()

min_inlier_num = 100

fdetector = cv2.ORB_create()
fmatcher = cv2.DescriptorMatcher_create('BruteForce-Hamming')

obj_image = cv2.imread(f'{REF_DIR}ref.png')
assert obj_image is not None
obj_keypoints, obj_descriptors = fdetector.detectAndCompute(obj_image, None)
assert len(obj_keypoints) >= min_inlier_num
fmatcher.add(obj_descriptors)

video = android_camera()
points = []
fps_count = 0
data_count = 0
save_count = 0

if os.path.exists(f'{REF_DIR}features_worldaxis.npz'):
    os.remove(f'{REF_DIR}features_worldaxis.npz')

while True:
    isValid, img = video.read()
    if not isValid:
        break

    img_keypoints, img_descriptors = fdetector.detectAndCompute(img, None)
    match = fmatcher.match(img_descriptors, obj_descriptors)
    if len(match) < min_inlier_num:
        continue

    obj_pts, img_pts = [], []
    for m in match[:100]:
        obj_pts.append(obj_keypoints[m.trainIdx].pt)
        img_pts.append(img_keypoints[m.queryIdx].pt)
    obj_pts = np.array(obj_pts, dtype=np.float32)
    obj_pts = np.hstack((obj_pts, np.zeros((len(obj_pts), 1), dtype=np.float32))) # 2D -> 3D
    img_pts = np.array(img_pts, dtype=np.float32)

    _, _, _, inliers = cv2.solvePnPRansac(obj_pts, img_pts, mtx, dist, useExtrinsicGuess=False,
                                                 iterationsCount=500, reprojectionError=2., confidence=0.99)

    inlier_mask = np.zeros(len(match), dtype=np.uint8)
    inlier_mask[inliers] = 1
    img_result = cv2.drawMatches(img, img_keypoints, obj_image, obj_keypoints, match, None, (0, 0, 255), (0, 127, 0), inlier_mask)

    cv2.putText(img_result, f"Save Count {save_count} | Data Count {data_count}", (10, 25), cv2.FONT_HERSHEY_DUPLEX, 0.6, (0, 255, 0))
    cv2.imshow('Image', img_result)
    fps_count += 1

    # 3프레임마다 실행 (1초 동안 10번 실행)
    if fps_count % 3 == 0:
        fps_count = 0
        save_count += 1
        try:
            obj_pts = obj_pts[:, :2]

            # DB에 저장되어 있던 체커보드-레퍼런스 영상 [R|t] 로드
            ref_pose = np.load(f'{REF_DIR}ref_pose.npz')
            ref_rvec = ref_pose['ref_rvec']
            ref_tvec = ref_pose['ref_tvec']

            gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
            chess_ret, corners = cv2.findChessboardCorners(gray, checkerboard_size, None)

            if chess_ret:
                objp = np.zeros((checkerboard_size[0] * checkerboard_size[1], 3), np.float32)
                objp[:, :2] = np.mgrid[0:checkerboard_size[0], 0:checkerboard_size[1]].T.reshape(-1, 2)

                # 원점은 체커보드
                # 레퍼런스 카메라와의 [R|t]
                ref_R, _ = cv2.Rodrigues(ref_rvec)

                # 실시간 카메라와의 [R|t]
                _, cur_rvec, cur_tvec = cv2.solvePnP(objp, corners, mtx, dist)
                cur_R, _ = cv2.Rodrigues(cur_rvec)

                P0 = mtx @ np.hstack((ref_R, ref_tvec))
                P1 = mtx @ np.hstack((cur_R, cur_tvec))

                # 1. 라이브러리 사용
                # features_worldaxis = cv2.triangulatePoints(P0, P1, obj_pts.T, img_pts.T)
                # features_worldaxis /= features_worldaxis[3]
                # features_worldaxis = features_worldaxis.T
                # features_worldaxis = features_worldaxis[:, :3]

                # 2. 직접 구현
                features_worldaxis = triangulate_points(P0, P1, obj_pts, img_pts)

                # 월드 좌표 검증
                # 투영 오차를 계산하여 출력
                if len(features_worldaxis) > 0:
                    reprojection_errors = calculate_reprojection_error(features_worldaxis, img_pts, cur_rvec, cur_tvec, mtx, dist)
                    threshold = 0.25

                    # 임계값보다 큰 투영 오차를 가진 특징점 제외
                    mask = reprojection_errors < threshold
                    featuers_worldaxis_inliers = features_worldaxis[mask]
                    img_pts_inliers = img_pts[mask]

                    print(f"Number of inliers: {len(featuers_worldaxis_inliers)}")
                    features_worldaxis = featuers_worldaxis_inliers

                    # DB에 저장
                    try:
                        data = np.load(f'{REF_DIR}features_worldaxis.npz')
                        saved_worldaxis = data['worldaxis']
                    except FileNotFoundError:
                        saved_worldaxis = np.array([])

                    if saved_worldaxis.size == 0:
                        merged_worldaxis = features_worldaxis
                    else:
                        merged_worldaxis = np.vstack([saved_worldaxis, features_worldaxis])

                    # 새로 계산된 데이터와 기존 데이터를 합치고 중복 제거
                    # 소수점 6자리까지 동일한 월드 좌표는 제거
                    unique_indices = np.unique(np.round(merged_worldaxis, decimals=6), axis=0, return_index=True)[1]

                    # 중복 제거한 데이터 저장
                    unique_worldaxis = merged_worldaxis[unique_indices]
                    np.savez(f'{REF_DIR}features_worldaxis', worldaxis=unique_worldaxis)
                    data = np.load(f'{REF_DIR}features_worldaxis.npz')
                    print(f"Saved {len(data['worldaxis'])}")
                    data_count = len(data['worldaxis'])
        except Exception as e:
            print(e)
            import traceback
            print(traceback.format_exc())
            cv2.destroyAllWindows()
            sys.exit()

    key = cv2.waitKey(1)
    if key == ord(' '):
        break
    if key == ord('q'):
        video.release()
        cv2.destroyAllWindows()
        sys.exit()

data = np.load(f'{REF_DIR}features_worldaxis.npz')
features_worldaxis = data['worldaxis']

while True:
    if len(features_worldaxis) == 0:
        break

    isValid, img = video.read()
    if not isValid:
        break

    try:
        gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
        isFind, corners = cv2.findChessboardCorners(gray, checkerboard_size, None)
        if isFind:
            objp = np.zeros((checkerboard_size[0] * checkerboard_size[1], 3), np.float32)
            objp[:, :2] = np.mgrid[0:checkerboard_size[0], 0:checkerboard_size[1]].T.reshape(-1, 2)
            # 회전 및 변환 벡터를 계산
            _, rvec, tvec = cv2.solvePnP(objp, corners, mtx, dist)

            # impts, _ = cv2.projectPoints(X, rvec, tvec, mtx, dist)
            impts = project_points(features_worldaxis, rvec, tvec, mtx)
            impts = np.int32(impts).reshape(-1,2)

            impts = impts.squeeze()
            for p in impts:
                if p[0] > 640 or p[1] > 480 or p[0] < 0 or p[1] < 0:
                    continue
                cv2.circle(img, (int(p[0]), int(p[1])), 3, (0, 0, 255), -1)

        cv2.putText(img, f"Features Count : {len(features_worldaxis)}", (10, 25), cv2.FONT_HERSHEY_DUPLEX, 0.6, (0, 255, 0))
        cv2.imshow('Image', img)
        key = cv2.waitKey(1)
        if key == ord('q'):
            break
    except Exception as e:
        print(e)
        import traceback
        print(traceback.format_exc())
        break

video.release()
cv2.destroyAllWindows()