#!/usr/bin/env python

"""
    File name: plot_triplet_parameters.py
    Author: Halla Sigurthorsdottir, Christoph Blattgerste, Giorgia Dellaferrera
    Date created: 06/10/2016
    Date last modified: 18/09/2018
    Python Version: 2.7
"""

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

def plot_triplet_p(m, title=None):
    plt.subplot(221)
    plt.plot(m['syn_monitor'].t, m['syn_monitor'].o_1[0])
    plt.ylabel('o_1')

    plt.subplot(222)
    plt.plot(m['syn_monitor'].t, m['syn_monitor'].o_2[0])
    plt.ylabel('o_2')

    plt.subplot(223)
    plt.plot(m['syn_monitor'].t, m['syn_monitor'].r_1[0])
    plt.ylabel('r_1')
    plt.xlabel('t (s)')

    plt.subplot(224)
    plt.plot(m['syn_monitor'].t, m['syn_monitor'].r_2[0])
    plt.ylabel('r_2')
    plt.xlabel('t (s)')

    plt.title(title)

    plt.show()

def plot_prepost_spikes(m, voltage=True, title=None):
    '''
    This function plots the pre- and postsynaptic spikes as well as the voltage of the postsynaptic neuron (if voltage is True).
    '''
    plt.plot(m['pre_spikes'].t, -0.07 * np.ones(len(m['pre_spikes'].t)), '*')
    leg = ['Presynaptic spikes']

    if len(m['post_spikes'].t) > 0:
        plt.plot(m['post_spikes'].t, -0.07 * np.ones(len(m['post_spikes'].t)), '*')
        leg += ['Postsynaptic_spikes']

    if voltage:
        for i in range(m['post_monitor'].v.shape[0]):
            plt.plot(m['post_monitor'].t, m['post_monitor'].v[i])
            leg += ['Voltage of neuron' + str(i)]
            plt.ylabel('Voltage (V)')

    plt.legend(leg, loc='upper right')
    plt.xlabel('Time (s)')
    if not title is None:
        plt.title(title)

    plt.show()

def plot_w(m, no_syn=None, title=None):
    '''
    This function plots the weight change over time.
    '''
    leg = [0] * m['syn_monitor'].w_ampa.shape[0]
    if no_syn == None:
        no_syn = m['syn_monitor'].w_ampa.shape[0]
    else:
        no_syn = no_syn

    for i in range(no_syn):
        plt.figure()
        plt.plot(m['syn_monitor'].t, m['syn_monitor'].w_ampa[i])
        leg[i] = 'Synapse ' + str(i)

        plt.xlabel('Time (s)')
        plt.ylabel('Weight')
        plt.legend(leg)
        if not title is None:
            plt.title(title)

        plt.show()

def plot_rs_os(m, no_syn=None, title=None):
    '''
    This function plots the change of r_1, r_2, o_1, o_2 over time.
    '''
    leg = [0] * m['syn_monitor'].w_ampa.shape[0]
    if no_syn == None:
        no_syn = m['syn_monitor'].w_ampa.shape[0]
    else:
        no_syn = no_syn

    rs_and_os = True

    if rs_and_os == True:
        for i in range(no_syn):
            plt.figure()
            plt.plot(m['syn_monitor'].t, m['syn_monitor'].r_1[i], label='r_1')
            plt.plot(m['syn_monitor'].t, m['syn_monitor'].r_2[i], label='r_2')
            plt.plot(m['syn_monitor'].t, m['syn_monitor'].o_1[i], label='o_1')
            plt.plot(m['syn_monitor'].t, m['syn_monitor'].o_2[i], label='o_2')
            # leg[i] = 'Synapse ' + str(i)

            plt.xlabel('Time (s)')
            plt.ylabel('Weight')
            plt.legend()
            if not title is None:
                plt.title(title)

            plt.show()

def plot_spikes(m, save_in_path=False, path=None, show=False, title=None, no_poisson_spikes=15, poisson_pop=False):
    '''
    This function plots 20 (or input) pre spike arrivals and 10 (or input) post spike times.
    '''

    if len(m['post_spikes'].spike_trains()) < 10:
        no_post_spikes = len(m['post_spikes'].spike_trains())
    else:
        no_post_spikes = 10
    if len(m['pre_spikes'].spike_trains()) < 10:
        no_pre_spikes = len(m['pre_spikes'].spike_trains())
    else:
        no_pre_spikes = 10

    no_spikes = no_pre_spikes + no_post_spikes
    print('number of pre spike trains: {}'.format(no_pre_spikes))
    print('number of post spike trains: {}'.format(no_post_spikes))

    if poisson_pop == True:
        no_spikes += no_poisson_spikes

    # Prepare pre spike list
    pre_ids = random.sample(range(len(m['pre_spikes'].spike_trains())), no_pre_spikes)
    pre_spikes = [0] * no_pre_spikes
    for i in range(no_pre_spikes):
        pre_spikes[i] = m['pre_spikes'].spike_trains()[pre_ids[i]]

    # Prepare post spike list
    print(len(m['post_spikes'].spike_trains()), no_post_spikes)

    post_ids = random.sample(range(len(m['post_spikes'].spike_trains())), no_post_spikes)
    post_spikes = [0] * no_post_spikes
    for i in range(no_post_spikes):
        post_spikes[i] = m['post_spikes'].spike_trains()[post_ids[i]]

    if poisson_pop:
        # Prepare poisson spike list
        poisson_ids = random.sample(range(len(m['poisson_spikes'].spike_trains())), no_poisson_spikes)
        poisson_spikes = [0] * no_poisson_spikes
        for i in range(no_poisson_spikes):
            poisson_spikes[i] = m['poisson_spikes'].spike_trains()[poisson_ids[i]]

    # For the legend
    plt.plot(pre_spikes[0], no_spikes * np.ones(len(pre_spikes[0])), '|k')
    plt.plot(post_spikes[0], (no_spikes - no_pre_spikes) * np.ones(len(post_spikes[0])), '|r')
    if poisson_pop:
        plt.plot(poisson_spikes[0], (no_spikes - no_pre_spikes - no_poisson_spikes) * np.ones(len(poisson_spikes[0])),
                 '*b')

    for i in range(len(pre_spikes)):
        plt.plot(pre_spikes[i], (no_spikes - i) * np.ones(len(pre_spikes[i])), '|k', linewidth=3)

    for i in range(len(post_spikes)):
        plt.plot(post_spikes[i], (no_spikes - i - no_pre_spikes) * np.ones(len(post_spikes[i])), '|r', linewidth=3)

    if poisson_pop:
        for i in range(len(poisson_spikes)):
            plt.plot(poisson_spikes[i],
                     (no_spikes - i - no_pre_spikes - no_poisson_spikes) * np.ones(len(poisson_spikes[i])), '*b',
                     linewidth=3)

        # added by GD to monitor spike times
        # print('one train of pre spikes',pre_spikes[0])
        # print('one train of pre spikes',pre_spikes[1])
        # print('one train of pre spikes',pre_spikes[2])
        # print('one train of pre spikes',pre_spikes[3])
        # print('one train of post spikes',post_spikes[0])
        # print('one train of post spikes',post_spikes[1])
        # print('one train of post spikes',post_spikes[2])
        # print('one train of post spikes',post_spikes[3])
        # if poisson_pop:
        # print('one train of poisson spikes',poisson_spikes[0])
        # print('one train of poisson spikes',poisson_spikes[1])
        # print('one train of poisson spikes',poisson_spikes[2])

    # save the result to a text file
    # path = '../GD/fill_the_grid/sLFS/varyingNb/hippoplasticity/added_poisson_input/Clopath_long_tau_refract/'
    # path = '../GD/fill_the_grid/sLFS/varyingNb/visualplast/withpoisson_long_tau_refract/'
    # path = '../GD/puppet/100pulses_08Hz/'

    path = '../data/'
    name = 'Spike trains'
    out_name = path + name
    # save pre spikes
    np.savetxt(out_name + 'pre0.txt', pre_spikes[0])
    np.savetxt(out_name + 'pre1.txt', pre_spikes[1])
    np.savetxt(out_name + 'pre2.txt', pre_spikes[2])
    np.savetxt(out_name + 'pre3.txt', pre_spikes[3])
    # save post spikes
    np.savetxt(out_name + 'post0.txt', post_spikes[0])
    np.savetxt(out_name + 'post1.txt', post_spikes[1])
    np.savetxt(out_name + 'post2.txt', post_spikes[2])
    np.savetxt(out_name + 'post3.txt', post_spikes[3])
    # save poisson spikes
    if poisson_pop:
        np.savetxt(out_name + 'poisson0.txt', poisson_spikes[0])
        np.savetxt(out_name + 'poisson1.txt', poisson_spikes[1])
        np.savetxt(out_name + 'poisson2.txt', poisson_spikes[2])
        np.savetxt(out_name + 'poisson3.txt', poisson_spikes[3])

    plt.legend(['Presynaptic spikes', 'Postsynaptic spikes'], loc='upper right', fontsize=14)
    plt.xlabel('Time (s)', fontsize=20)
    plt.ylabel('Neuron index', fontsize=20)  # added by GD
    plt.savefig('../fig/spike_train.pdf', format='PDF')

    if not title is None:
        plt.title(title, fontsize=20)
    plt.tight_layout()
    if show:
        plt.show()
    if save_in_path and path is not None:
        plt.savefig(path + "spike_plot.pdf", format="PDF")

def plot_mean_weight(m, filename=None, path=None, title=None, show=False):
    """
    This function plots the mean synaptic weight over time.
    :param m:
    :param filename:
    :param path:
    :param title:
    :param show:
    :return:
    """

    plt.plot(m['syn_monitor'].t, np.mean(m['syn_monitor'].w_ampa, 0))
    plt.ylabel('mean weight', fontsize=18)
    plt.xlabel('time $[s]$', fontsize=18)

    if title is not None:
        plt.title(title, fontsize=18)
    plt.tight_layout()
    if show:
        plt.show()

    if filename != None and path != None:
        try:
            plt.savefig(path + filename + '.pdf', format='PDF')
        except:
            print("Wrong combination of path and filename - image not saved")

def visualize_connectivity(S, save_in_path=False):  # S is a Synapses object
    '''
    Plot a two different graps to visualize connectivity between each pre- and postsynaptic neuron.
    '''

    Ns = len(S.source)  # number of source neurons
    Nt = len(S.target)  # number of target neurons
    plt.figure(figsize=(10, 4))
    plt.subplot(121)
    plt.plot(np.zeros(Ns), np.arange(Ns), 'ok', ms=10)  # draw source neurons
    plt.plot(np.ones(Nt), np.arange(Nt), 'ok', ms=10)  # draw target neurons
    for i, j in zip(S.i, S.j):
        plt.plot([0, 1], [i, j], '-k')  # draw lines between them
        plt.xticks([0, 1], ['Source', 'Target'])
    plt.ylabel('Neuron index')
    plt.xlim(-0.1, 1.1)
    plt.ylim(-1, max(Ns, Nt))
    plt.title('Connectivity: Source to Target')

    print(S.i)
    for n in range(max(S.j)):
        indizes = np.where(S.j == n)
        print('Synapses at post neuron {} - {}'.format(n, len(indizes[0])))
    plt.subplot(122)
    plt.plot(S.i, S.j, 'ok')
    plt.xlim(-1, Ns)
    plt.ylim(-1, Nt)
    plt.xlabel('Source neuron index')
    plt.ylabel('Target neuron index')
    plt.title('Connectivity Matrix')
    if save_in_path:
        plt.savefig('../fig/pre:{}_post:{}_connect.pdf'.format(max(S.i), max(S.j)), format='PDF')
    plt.show()


#[Trees - Ex4] Exercise: Implement a binary search tree
#Implement the insert() and find() methods in the following simple binary search tree class:

from logging import root

class Node:
    def __init__(self, key):
        self.key = key
        self.left = None
        self.right = None

class BST:
    def __init__(self, root:Node):
        self.root = root

    # Inserts a key into this binary search tree.
    # If there are n nodes in the tree, then the average runtime of this method should be log(n).
    # @param key The key to insert.
    # normally if i'd do this in c++, i would use find as a subroutine for insert because i can use take the mem address and assign a variable value.
    def insert(self, subroot, key):
        if subroot == None:
            return Node(key) #deciding to return the new root
        else:
            if key < subroot.key:
                print(subroot.key)
                return self.insert(subroot.left, key)
            elif key >= subroot.key:
                print(subroot.key)
                return self.insert(subroot.right, key)
            return self.subroot

    # Checks whether or not a key exists in this binary search tree.
    # If there are n nodes in the tree, then the average runtime of this method should be log(n).

    # @param key The key to check for.
    # @return true if the key is present in this binary search tree, false otherwise.
    def find(self, subroot, key):
        if self.root == None or key == self.root.key:
            return True
        if subroot == None:
            return False
        if subroot.key == key:
            return True
        elif key < subroot.key:
            return self.find(subroot.left, key)
        elif key >= subroot.key:
            return self.find(subroot.right, key)

# TESTING
sixteen = Node(16)
sixteen.left = Node(10)
sixteen.right = Node(21)
tree = BST(sixteen)

# Test Find
# print(tree.find(sixteen, 16))
# print(tree.find(sixteen, 10))
# print(tree.find(sixteen, 21))
# print(tree.find(sixteen, 15))

# Expected
# True
# True
# True
# False

# Actual
# True
# True
# True
# False

# Test Insert -- i did this kinda janky where I just print what node we are
# recursing thru so i know where it inserts
# tree.insert(sixteen, 15) #insert on left
# should print 16, 10
# tree.insert(sixteen, 150) #insert on right
# should print 16, 21


import ujson
from tornado import gen

import chatbot.services.facebook.msg as facebook_msg
from chatbot.intents import Reply, Intent, TextReply

from chatbot.misc.router import url_for

class PromotionsReply(Reply):

    def __init__(self, promotions=None):
        self.promotions = promotions or []

    def to_dict(self):
        return self.promotions

    def to_facebook(self):
        elements = [self._to_facebook_card(promotion) for promotion in self.promotions]
        template = facebook_msg.GenericTemplate(elements)
        attachment = facebook_msg.TemplateAttachment(template)
        message = facebook_msg.Message(attachment=attachment)
        return message

    def _to_facebook_card(self, promotion):
        if promotion['type'] == 'sumo_promotion':
            view_promotion_url = url_for('web.view_promo', promotion_id=promotion['id'])
            claim_promotion_url = url_for('web.claim_promo', promotion_id=promotion['id'])
        elif promotion['type'] == 'internet_deal':
            view_promotion_url = url_for('web.view_deal', promotion_id=promotion['id'])
            claim_promotion_url = url_for('web.claim_deal', promotion_id=promotion['id'])

        default_action = facebook_msg.WebUrlButton('', view_promotion_url)
        view_button = facebook_msg.WebUrlButton('View', view_promotion_url)
        claim_button = facebook_msg.WebUrlButton('Claim', claim_promotion_url)

        element = facebook_msg.Element(title=promotion['name'],
                                       subtitle=promotion['business']['name'][:80],
                                       image_url=promotion['business']['logo'],
                                       default_action=default_action,
                                       buttons=[view_button, claim_button])

        return element

class SearchIntent(Intent):

    name = 'search'

    def __init__(self, *args, **kwargs):
        super(SearchIntent, self).__init__(*args, **kwargs)

    @gen.coroutine
    def process(self, query=''):
        search_url = url_for('api.search', query=query)
        resp = yield self.fetch(search_url)
        data = ujson.loads(resp.body)
        promotions = data['promotions']

        if promotions:
            return [PromotionsReply(promotions)]
        else:
            return [TextReply(text="Sorry we can't interpret your message:( Please try again!")]


"""checking object is passed to help() (not a string)"""
help(list)
help(dict)
help(print)
help([1,2])
"""string is passed as an argument to help()"""
help('random thing')
help('print')
help('def')
help('math.pow')

"""no argument is passed to help()"""
#help()

"""__import()__:
In general, pow() is a method defined in math module.
You can call this function using the following syntax: math.pow
However, using __import__() changed the way to access fabs()"""

mathematics = __import__('math', globals(), locals(), [], 0)

print(mathematics.pow(2,5))


# ! ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
# ! ┃                                 IMPORTS                                  ┃
# ! ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛

import os
import csv
import subprocess
import pandas as pd

from dotenv import load_dotenv
from datetime import datetime, time, timedelta
from dateutil.relativedelta import relativedelta

# ! ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
# ! ┃                              GLOBAL VAR`s                                ┃
# ! ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛

# * Carrega as variáveis de ambiente do arquivo .env
load_dotenv()

NOME_DIRETORIO_RAIZ = str(os.getenv('NOME_DIRETORIO_RAIZ'))
FIRST_WORKING_DAY_OF_THE_MONTH = int(os.getenv('FIRST_WORKING_DAY_OF_THE_MONTH'))
LAST_WORKING_DAY_OF_THE_MONTH = int(os.getenv('LAST_WORKING_DAY_OF_THE_MONTH'))
VALUE_PER_HOUR = float(os.getenv('VALUE_PER_HOUR'))

# Diretório do executavel
dir_path = os.path.dirname(os.path.realpath(__file__))

# obter a data atual
data_atual = datetime.today()
dia = data_atual.strftime("%d")
# dia = data_atual.day+1
ano = data_atual.year
# mes = data_atual.strftime('%B')
mes = data_atual.month
GLOBAL_HORA_ATUAL = datetime.now().strftime('%H:%M:%S')

# nome do diretório correspondente ao ano atual
nome_diretorio = f'{NOME_DIRETORIO_RAIZ}/{ano}'

# nome do arquivo csv correspondente a este mês
nome_arquivo = f'{nome_diretorio}/{mes}.csv'

# diretorios
diretorio_anos = f'{dir_path}/{NOME_DIRETORIO_RAIZ}'
diretorio_atual = f'{dir_path}/{nome_diretorio}'
diretorio_file = f'{dir_path}/{nome_diretorio}/{mes}.csv'

executar_novamente = ''

meses_extenso = {
    1: "janeiro",
    2: "fevereiro",
    3: "março",
    4: "abril",
    5: "maio",
    6: "junho",
    7: "julho",
    8: "agosto",
    9: "setembro",
    10: "outubro",
    11: "novembro",
    12: "dezembro"
}

with open(nome_arquivo, 'r') as f:
    reader = csv.reader(f)
    linhas = list(reader)

# ! ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
# ! ┃                            GENERAL FUNCTIONS                             ┃
# ! ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛

def send_notification(title, message):
    subprocess.run(["notify-send", title, message])

def open_directory_in_file_manager(path):
    if os.name == 'posix': # Verifica se o sistema operacional é Unix-based (Linux, macOS, etc.)
        os.system(f'xdg-open {path}')
    elif os.name == 'nt': # Verifica se o sistema operacional é Windows
        os.system(f'explorer {path}')

def calcular_total_horas(data_atual):
    print(f'╭─┴{str("".center(47, "─"))}╮')
    arquivo_não_encontrado = False
    total_horas = timedelta()

    if data_atual.day > FIRST_WORKING_DAY_OF_THE_MONTH:
        data_atual = data_atual + relativedelta(months=1)

    ano_atual = data_atual.year
    mes_atual = data_atual.month

    # Definir o intervalo de datas a serem consideradas
    data_inicio_mes_anterior = data_atual.replace(day=LAST_WORKING_DAY_OF_THE_MONTH)

    if data_inicio_mes_anterior.day > FIRST_WORKING_DAY_OF_THE_MONTH:
        if mes_atual == 1:  # Se for janeiro, volta para dezembro do ano anterior
            mes_anterior = 12
            ano_anterior = ano_atual - 1
        else:
            mes_anterior = mes_atual - 1
            ano_anterior = ano_atual
        data_inicio_mes_anterior = data_inicio_mes_anterior.replace(year=ano_anterior, month=mes_anterior)

    data_inicio_mes_atual = data_atual.replace(day=1)

    # Loop para percorrer os arquivos CSV
    for data_inicio in [data_inicio_mes_anterior, data_inicio_mes_atual]:
        nome_arquivo = f'{NOME_DIRETORIO_RAIZ}/{data_inicio.year}/{data_inicio.month}.csv'

        try:
            with open(nome_arquivo, 'r') as arquivo:
                reader = csv.reader(arquivo)
                next(reader)  # Ignorar a linha de cabeçalho

                for linha in reader:
                    dia = int(linha[0])
                    if data_inicio == data_inicio_mes_anterior and dia < LAST_WORKING_DAY_OF_THE_MONTH:  # Ignorar dias menores que {LAST_WORKING_DAY_OF_THE_MONTH} do mês anterior
                        continue
                    if data_inicio == data_inicio_mes_atual and dia > FIRST_WORKING_DAY_OF_THE_MONTH:  # Ignorar dias maiores que {FIRST_WORKING_DAY_OF_THE_MONTH} do mês atual
                        continue

                    total_dia = datetime.strptime(linha[-1], '%H:%M:%S')
                    total_horas += timedelta(hours=total_dia.hour, minutes=total_dia.minute, seconds=total_dia.second)

        except FileNotFoundError:
            arquivo_não_encontrado = True
            print(f'│{str(f"✘ Arquivo {nome_arquivo} não encontrado.".center(49))}│')

    # Exemplo de uso
    total = total_horas
    total_em_horas = total.total_seconds() / 3600
    total_em_horas = round(total_em_horas, 2)
    total_a_receber = total_em_horas * VALUE_PER_HOUR

    if(total_em_horas == 0):
        print(f'╰─┬{str("".center(47, "─"))}╯')
        return

    if(arquivo_não_encontrado):
        print(f'│{str("".center(49))}│')

    # Exibir a quantidade total de horas como número decimal
    print(f'│{str("".center(32))}╭─────────────╮  │')
    print(f'│{str(f" Total de horas  ╾".ljust(32, "─"))}┾ {str(f"{total_em_horas:.2f} Hrs").ljust(11)} │  │')
    print(f'│{str("".center(32))}├─────────────┤  │')
    if(total_em_horas < 160):
        total_horas_faltante = 160 - total_em_horas
        print(f'│{str(f" Carga horaria restante ╾".ljust(32, "─"))}┾ {str(f"{total_horas_faltante:.2f} Hrs").ljust(11)} │  │')
        print(f'│{str("".center(32))}├─────────────┤  │')

    print(f'│{str(f" Total aproximado a receber ╾".ljust(32, "─"))}┾ {str(f"R$: {total_a_receber:.2f}").ljust(11)} │  │')
    print(f'│{str("".center(32))}╰─────────────╯  │')

    # Exibir a quantidade total de horas no formato dias, horas e minutos
    dias = total.days
    horas, resto = divmod(total.seconds, 3600)
    minutos = resto // 60

    print(f'│{str("".center(49))}│')
    print(f'│{str(f" Total de horas (formato dias, horas e minutos)".center(49))}│')
    print(f'│{str(f" {dias} dia(s), {horas} hora(s) e {minutos} minuto(s)".center(49))}│')
    print(f'╰─┬{str("".center(47, "─"))}╯')
    send_notification(f"Total de horas: {total_em_horas:.2f} Hrs", f"No mês de {meses_extenso[mes_atual]}, {ano_atual}")

# ! ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
# ! ┃                              MENU FUNCTIONS                              ┃
# ! ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛

def option_1():
    print(f'╭─┴{str("".center(47, "─"))}╮')
    print(f'│{str(f"Abrindo: {dir_path}").center(49)}│')
    print(f'╰─┬{str("".center(47, "─"))}╯')

    subprocess.run(["code", dir_path])
    send_notification("Abrindo VS Code", dir_path)

def option_2():
    dataframe = pd.read_csv(diretorio_file)

    print(f'╭─┴{str("".center(71, "─"))}╮')
    print(dataframe.to_string(index=False, header=True, na_rep='  :  :  ', justify='center'))
    print(f'╰─┬{str("".center(71, "─"))}╯')

def option_3():
    print(f'╭─┴{str("".center(47, "─"))}╮')
    print(f'│{str(f"Abrindo: {diretorio_atual}").center(49)}│')
    print(f'╰─┬{str("".center(47, "─"))}╯')

    open_directory_in_file_manager(diretorio_atual)

def option_4():
    GLOBAL_HORA_ATUAL = datetime.now().strftime('%H:%M:%S')
    print(f'  │')
    for i, row in enumerate(linhas):
        if row[0] == str(dia):
            if row[1] == '' and row[2] == '':
                print(f'╭─┴{str("".center(47, "─"))}╮')
                print(f'│{str(f"Ainda abriu o PRIMEIRO ponto").center(49)}│')
                print(f'╰─┬{str("".center(47, "─"))}╯')
                return
            elif row[1] != '' and row[2] == '':
                print(f'╭─┴{str("".center(47, "─"))}╮')
                print(f'│{str(f"Ainda NÃO fechou o PRIMEIRO ponto").center(49)}│')
                print(f'╰─┬{str("".center(47, "─"))}╯')
                inicio_str = row[1]
                total_str = '00:00:01'
            elif row[2] != '' and row[3] == '':
                inicio_str = GLOBAL_HORA_ATUAL
                total_str = row[-1]
                print(f'╭─┴{str("".center(47, "─"))}╮')
                print(f'│{str(f"Ainda NÃO iniciou o SEGUNDO ponto").center(49)}│')
                print(f'│{str(f"Mas se iniciar outro agora ás {GLOBAL_HORA_ATUAL}").center(49)}│')
                print(f'╰─┬{str("".center(47, "─"))}╯')
            elif row[3] != '' and row[4] == '':
                inicio_str = row[3]
                total_str = row[-1]
            elif row[4] != '' and row[5] == '':
                print(f'╭─┴{str("".center(47, "─"))}╮')
                print(f'│{str(f"Ainda NÃO iniciou o TERCEIRO ponto").center(49)}│')
                print(f'│{str(f"Mas se iniciar outro agora ás {GLOBAL_HORA_ATUAL}").center(49)}│')
                print(f'╰─┬{str("".center(47, "─"))}╯')
                inicio_str = GLOBAL_HORA_ATUAL
                total_str = row[-1]
            elif row[5] != '' and row[6] == '':
                inicio_str = row[5]
                total_str = row[-1]
            else:
                print(f'╭─┴{str("".center(47, "─"))}╮')
                print(f'│{str(f"Ja bateu os três pontos").center(49)}│')
                print(f'│{str(f"E trabalhou um total de {row[-1]} hoje").center(49)}│')
                print(f'╰─┬{str("".center(47, "─"))}╯')
                return
            break

    # Hora total no formato "HH:MM:SS"
    tempo_total_com_ponto = datetime.strptime(total_str, '%H:%M:%S').time()

    # Hora total no formato "HH:MM:SS"
    hora_atual = datetime.strptime(GLOBAL_HORA_ATUAL, '%H:%M:%S').time()

    # Hora de início no formato "HH:MM:SS"
    tempo_ultimo_ponto_entrada = datetime.strptime(inicio_str, '%H:%M:%S')

    # Duração de 8 horas em um objeto timedelta
    carga_dia_trabalho = timedelta(hours=8)

    # Subtrai o tempo total da duração de 8 horas
    tempo_restante_com_ponto = carga_dia_trabalho - timedelta(hours=tempo_total_com_ponto.hour, minutes=tempo_total_com_ponto.minute, seconds=tempo_total_com_ponto.second)

    # Soma o tempo restante com o intervalo entre a hora de início e a hora atual
    tempo_trabalhado_sem_ponto = timedelta(hours=tempo_total_com_ponto.hour, minutes=tempo_total_com_ponto.minute, seconds=tempo_total_com_ponto.second) + timedelta(hours=hora_atual.hour, minutes=hora_atual.minute, seconds=hora_atual.second) - timedelta(hours=tempo_ultimo_ponto_entrada.hour, minutes=tempo_ultimo_ponto_entrada.minute, seconds=tempo_ultimo_ponto_entrada.second)
    tempo_restante_sem_ponto = carga_dia_trabalho - tempo_trabalhado_sem_ponto

    print(f'  │')
    print(f'╭─┴{str("".center(47, "─"))}╮')

    if tempo_restante_sem_ponto < timedelta(0):
        print(f'│ ╭───╮{str("".center(43))}│')
        print(f'├─┤ ✘ ├╼ Trabalhado SEM ponto : {str(tempo_trabalhado_sem_ponto).center(8)}  hrs     │')
        print(f'│ ╰───╯{str("".center(43))}│')
    else:
        print(f'│ ╭───╮{str("".center(43))}│')
        print(f'├─┤ ✘ ├╼ Trabalhado SEM ponto : {str(tempo_trabalhado_sem_ponto).center(8)}  hrs     │')
        print(f'├─┤ ✘ ├╼ Restante   SEM ponto : {str(tempo_restante_sem_ponto).center(8)}  hrs     │')
        print(f'│ ╰───╯{str("".center(43))}│')

    if tempo_restante_com_ponto < timedelta(0):
        print(f'│ ╭───╮{str("".center(43))}│')
        print(f'├─┤ ✔ ├╼ Trabalhado COM ponto : {str(tempo_total_com_ponto).center(8)}  hrs     │')
        print(f'│ ╰───╯{str("".center(43))}│')
        print(f'╰─┬────{str("".center(43, "─"))}╯')
        send_notification(f"Hoje ja trabalho um total de", f"{tempo_total_com_ponto} hrs")
    else:
        fim = tempo_ultimo_ponto_entrada + tempo_restante_com_ponto
        print(f'│ ╭───╮{str("".center(43))}│')
        print(f'├─┤ ✔ ├╼ Trabalhado COM ponto : {str(tempo_total_com_ponto).center(8)}  hrs     │')
        print(f'├─┤ ✔ ├╼ Restante   COM ponto : {str(tempo_restante_com_ponto).center(8)}  hrs     │')
        print(f'│ ╰─┬─╯{str("".center(43))}│')
        print(f'│   ╰──────────────────────────────────────╮      │')
        print(f'│                                    ╭─────┴────╮ │')
        print(f'│     Deve fechar o ponto as ╾───────┤ {str(fim.time().strftime("%H:%M:%S")).center(8)} │ │')
        print(f'│  Finalizar o dia com {str(carga_dia_trabalho).center(8)} Hrs  ╰─────┬────╯ │')
        print(f'╰─┬────────────────────────────────────────┴──────╯')
        send_notification(f"Para finalizar o dia falta {tempo_restante_com_ponto} hrs", f"Deve fechar o ponto as {fim.time()} hrs")

def option_5():
    calcular_total_horas(data_atual)

def option_6():
    # Obter a data especifica
    while True:
        print(f'  │')
        data_atual_string = input("  ├──╼ Data (MM/AAAA): ")
        try:
            data_especifica = datetime.strptime("01/" + data_atual_string, "%d/%m/%Y").date()
            break
        except ValueError:
            print("  ├──╼ Formato de data inválido. Certifique-se de usar o formato MM/AAAA.")
    calcular_total_horas(data_especifica)

def option_day(day):
    print(f'╭─┴{str("".center(47, "─"))}╮')
    print(f'│{str(f"Pasta: {nome_arquivo}").center(49)}│')
    for i, row in enumerate(linhas):
        if row[0] == str(day):
            hora, minuto, segundo = row[-1].split(":")
            print(f'│{str(f"No dia {day}, teve um total de {hora} horas e {minuto} minutos").center(49)}│')
            print(f'╰─┬{str("".center(47, "─"))}╯')
            break
    else:
        print(f'│{str(f"Dia {day} não encontrado").center(49)}│')
        print(f'╰─┬{str("".center(47, "─"))}╯')

def option_year(year):
    diretorio_espc_ano = f'{diretorio_anos}/{option}'

    print(f'╭─┴{str("".center(47, "─"))}╮')
    print(f'│{str(f"Abrindo: {diretorio_espc_ano}").center(49)}│')
    if os.path.isdir(diretorio_espc_ano):
        open_directory_in_file_manager(diretorio_espc_ano)
        print(f'╰──{str("".center(47, "─"))}╯')

    print(f'│{str(f"Pasta não existe: {diretorio_espc_ano}").center(49)}│')
    print(f'╰─┬{str("".center(47, "─"))}╯')

options_functions = {
    '1': option_1,
    '2': option_2,
    '3': option_3,
    '4': option_4,
    '5': option_5,
    '6': option_6
}

while True:
    print(f'┏━━━┓')
    print(f'┃ 1 ╉╼ Abrir projeto no VS Code')
    print(f'┃ 2 ╉╼ Para print o {nome_arquivo}')
    print(f'┃ 3 ╉╼ Para pasta do ANO ATUAL')
    print(f'┃ 4 ╉╼ Para calcular qual horario de saida para um total de 8h')
    print(f'┃ 5 ╉╼ Somar as horas do mês de trabalho')
    print(f'┃ 6 ╉╼ Somar as horas do mês atual')
    print(f'┗━┯━┛')
    print(f'┏━┷━━━━┓')
    print(f'┃  01  ╉╼ Para print do DIA especifico no MÊS atual')
    print(f'┃ 2020 ╉╼ Para pasta do ANO ESPECIFICO')
    print(f'┗━┯━━━━┛')
    print(f'┏━┷━┓')
    print(f'┃ 0 ╉╼ Para terminar')
    print(f'┗━┯━┛')

    if executar_novamente != '0':
        option = executar_novamente

    if option in options_functions:
        options_functions[option]()
    elif option.isdigit() and len(option) == 2:
        option_day(option)
    elif option.isdigit() and len(option) == 4:
        option_year(option)
    else:
        pass

    # Pergunta se o usuário quer executar o código novamente
    executar_novamente = input("  ╰──╼ Opção: ").lower()

    # Se a resposta for 'n' ou 'não', encerra o loop e o programa
    if executar_novamente in ['n', 'não', 'nao', '0']:
        break
    else:
        os.system('clear')


from heva import read_ghcn, yearly_max
from heva import record_length_plot

data_path = "heva/aux_files/sample_station/"
station_list = [
    "ASN00023000",
    "CA006158350",
    "GM000004204",
    "GM000010962",
    "NLE00100499",
    "UK000056225",
]
ext = ".dly"

dict_max_val = dict()
for each_station in station_list:

    file_path = data_path + each_station + ext
    data_station = read_ghcn(file_path)
    max_val = yearly_max(data_station)
    dict_max_val[each_station] = max_val

record_length_plot(dict_max_val, "readme_plots/record_length.png")


import os
import sys
import json
import logging.config

# LOAD CONFIG FILE
with open('config.json') as config:
    json_data = json.load(config)

'''
------------------------------------------------
                CONFIG VARIABLES
------------------------------------------------
'''
bot = json_data["bot"]
event = json_data["eventsVars"]

# HiemSword: Yes, i know this loop is not the best method, but it works
for i in json_data["bot"]:
    bot_branch = i["branch"]
    bot_version = i["version"]
    bot_version_dev = i["dev"]
    bot_version_info = i["info"]
    bot_prefix = i["prefix"]
    bot_prefix_dev = i["prefix_dev"]

    extensionsEnabled = i["extensionsEnabled"]
    exts_dir = i["exts_dir"]

    bot_presence = i["playing_status"]

# ------------|  Join/Left event config variables  |-----

for i in json_data["eventsVars"]:
    for ii in i["join&leave"]:

        welcome_dm = ii["dm_msg"]

        welcome_ch_id = ii["ch_id"]
        welcome_ch_name = ii["ch_name"]

        join_msg = ii["hello_msg"]
        left_msg = ii["bye_msg"]
# ------------|  Extensions variables |-----

exts_list = [""] * 30 # please someone find a better way to do this

# ------------------------------------------------

def return_json():
    return json_data


import pymc as pm
import numpy as np
from pymc.sandbox import GibbsStepMethods
from pymc.sandbox.GibbsStepMethods import DirichletMultinomial
from numpy import *

__all__ = ['make_model', 'make_MCMC']

def find_age_bins(a, a_lo, a_hi):

    slices = []
    bin_ctrs = []

    for a_tup in zip(a_lo, a_hi):
        i_min = np.where(a<=a_tup[0])[0][-1]
        i_max = np.where(a>=a_tup[1])[0]
        if len(i_max)==0:
            i_max = len(a)-1
        else:
            i_max = i_max[0]
        slices.append(slice(i_min, i_max))

        local_a = a[i_min:i_max+1]
        bin_ctrs.append((a_tup[0] + a_tup[1])/2.)

    return slices, np.array(bin_ctrs)

def make_model(datasets, a):
    "Datasets should be a list of record arrays with columns [a_lo,a_hi,pos,neg]"

    age_bin_ctrs = {}
    age_slices = {}
    for place in datasets.iterkeys():
        age_slices[place], age_bin_ctrs[place] = find_age_bins(a, datasets[place].a_lo, datasets[place].a_hi)

    N_pops = len(datasets)
    S_guess = exp(-a/20.)
    S_guess /= sum(S_guess)

    # Model for central tendency of age distribution.
    alph_pri = 10.

    scg = []
    for i in xrange(len(a)):
        asg_now = pm.Lambda('asg_%i'%i, lambda alpha=alph_pri, S=S_guess, i=i : alpha*S[i])
        scg.append(pm.Gamma('scg_%i'%i, alpha=asg_now, beta=1., value=asg_now.value))
    sc = pm.Lambda('sc',lambda gams=scg: array(gams)/sum(gams))

    # Model for age distributions of individual populations
    # alph = pm.Gamma('alph',2.,2./1000.)
    alph = pm.OneOverX('alph', value=50.)

    asc = pm.Lambda('asc',lambda alph=alph,S=sc: alph*S)

    S = []
    S_steps = []
    data_list = []
    for name in datasets.iterkeys():

        this_dataset = datasets[name]

        @pm.deterministic(trace=False)
        def this_asc_slice(asc=asc, slices = age_slices[name], dataset=this_dataset):
            out = []
            for i in xrange(len(dataset)):
                out.append(sum(asc[slices[i]]))
            out = array(out)
            return out

        S.append(pm.Dirichlet(('S_%s'%name).replace('.','_'), this_asc_slice))
        N = this_dataset.pos+this_dataset.neg
        data_list.append(pm.Multinomial('data',n=sum(N),p=S[-1],value=N,observed=True))

    S_pred = pm.Dirichlet('S_pred',asc)

    return locals()

def make_MCMC(datasets, a, dbname):
    M = pm.MCMC(make_model(datasets,a), db='hdf5',dbcomplevel=1, dbcomplib='zlib', dbname=dbname)

    M.use_step_method(pm.Metropolis, M.alph, proposal_sd=.05)

    for i in xrange(len(datasets)):
        M.use_step_method(DirichletMultinomial, M.S[i])

    return M


"""This module implements a serial bus class which talks to bioloid
devices through a serial port.

"""

import serial
from bioloid.bus import Bus

class SerialPort(serial.Serial):
    """Encapsulates serial port communicatons."""

    def __init__(self, *args, **kwargs):
        # Ensure that a reasonable timeout is set
        timeout = kwargs.get('timeout', 0.1)
        if timeout < 0.05:
            timeout = 0.05
        kwargs['timeout'] = timeout
        print("Using timeout of ", timeout)
        kwargs['bytesize'] = serial.EIGHTBITS
        kwargs['parity'] = serial.PARITY_NONE
        kwargs['stopbits'] = serial.STOPBITS_ONE
        kwargs['xonxoff'] = False
        kwargs['rtscts'] = False
        kwargs['dsrdtr'] = False
        serial.Serial.__init__(self, *args, **kwargs)

class SerialBus(Bus):
    """Implements a BioloidBus which sends commands to a bioloid device
    via a BioloidSerialPort.

    """

    def __init__(self, serial_port, show_packets=False):
        Bus.__init__(self, show_packets)
        self.serial_port = serial_port

    def read_byte(self):
        """Reads a byte from the bus. This function will return None if
        no character was read within the designated timeout.

        The max Return Delay time is 254 x 2 usec = 508 usec (the
        default is 500 usec). This represents the minimum time between
        receiving a packet and sending a response.

        """
        data = self.serial_port.read()
        if data:
            return ord(data[0])
        return None

    def write_packet(self, packet_data):
        """Function implemented by a derived class which actually writes
        the data to a device.

        """
        self.serial_port.write(packet_data)


# script principal para iniciar la ejecución del programa genético
import argparse, sys, os

## Importar el módulo principal del Programa Genético.
import gprogram as gp
from MoeaRegresion import MoeaRegresion

## Este módulo es que debemos cambiar para cada problema nuevo.
from ProblemaRegresion import *

# Esta función lee los argumentos pasados desde la consola.
def readArgs():
    parser = argparse.ArgumentParser(description='Parámetros para ejecutar el PG')

    parser.add_argument('-p', '--psize', type=int, required=True,
                        help='Population size')
    parser.add_argument('-g', '--ngens', type=int, required=True,
                        help='Number of generations')
    parser.add_argument('-x', '--pxover', type=float, required=False, default=0.9,
                        help='Probability for crossover')
    parser.add_argument('-m', '--pmut', type=float, required=False, default=0.1,
                        help='Probability for mutation')
    parser.add_argument('-d', '--depth', type=int, required=False, default=5,
                        help="Trees' maximum depth")
    parser.add_argument('-f', '--dFile', type=str, required=False, default='puntos_01.txt',
                        help="Archivo de entrada para el problema de regresión")

    args = parser.parse_args()
    return args

# La función que crea un objeto PG y realiza la optimización configurada.
def main():
    ### 1. Leer argumentos de la consola.
    args = readArgs()

    ### 2. Crear el problema que se resolverá con el PG
    ### En este ejemplo se crea el problema que define 2 cosas:
    ###    i) Cómo representar los polinomios que deberán ajustarse a nuestros puntos.
    ###   ii) Cómo evaluar cada uno de los árboles (polinomios) según la desviación a los puntos.
    archivoEntrada = args.dFile
    problema = MoeaRegresion(archivoEntrada)

    ### 3. Crear el objeto GP y optimizar el problema.
    myGP = gp.GeneticProgram(problema, args.psize, args.ngens, args.pxover, args.pmut, args.depth)
    myGP.optimize()

    ### La salida quedará en 3 archivos:
    # 1. fitness_history.txt: la aptitud y evaluación del MEJOR individuo en cada generación.
    # 2. lastPopFiteness.txt: la aptitud y evaluación de los N individuos de la población final.
    # 3. lastPopTrees.txt   : la representación en árbol de los N individuos de la población final.
    print("\n\nLa salida está en 3 archivos: fitness_history.txt, lastPopFitness.txt y lastPopTrees.txt\n\n")

if __name__ == "__main__":
    main()


from database.Disease import Disease as DiseaseDB
from models.Disease import Disease
from models.Plant import Plant
from repository.base import Base
from sqlalchemy import and_

class DiseaseRepository(Base):
    """
    Disease repository, dedicated to realize all functions related to diseases.
    """

    def __init__(self,
                 dbuser="",
                 dbpass="",
                 dbhost="",
                 port="",
                 dbname=""):
        super().__init__(dbuser, dbpass, dbhost, port, dbname)

    def create(self, disease=Disease()):
        """
        (Disease) -> (Disease)
        """
        diseaseDB = DiseaseDB(disease=disease)
        session = self.session_factory()
        session.add(diseaseDB)
        session.flush()
        session.refresh(diseaseDB)
        session.commit()
        return Disease(diseaseDB.id,
                       Plant(diseaseDB.plant.id,
                             diseaseDB.plant.scientificName,
                             diseaseDB.plant.commonName),
                       diseaseDB.scientificName,
                       diseaseDB.commonName)

    def update(self, disease=Disease()):
        """
        (Disease) -> (Disease)
        """
        session = self.session_factory()
        diseaseDB = session.query(DiseaseDB).filter_by(id=disease.id).first()
        dic = {}
        if (diseaseDB.plant.id != disease.plant.id):
            dic['idPlant'] = disease.plant.id
        if (diseaseDB.scientificName != disease.scientificName):
            dic['scientificName'] = disease.scientificName
        if (diseaseDB.commonName != disease.commonName):
            dic['commonName'] = disease.commonName
        if (dic != {}):
            session.query(DiseaseDB).filter_by(id=disease.id).update(dic)
            session.commit()
            session.flush()
            session.refresh(diseaseDB)
        return Disease(diseaseDB.id,
                       Plant(diseaseDB.plant.id,
                             diseaseDB.plant.scientificName,
                             diseaseDB.plant.commonName),
                       diseaseDB.scientificName,
                       diseaseDB.commonName)

    def delete(self, disease=Disease()):
        """
        (Plant) -> (Boolean)
        """
        status = False
        session = self.session_factory()
        diseaseDB = session.query(DiseaseDB).filter_by(id=disease.id).first()
        session.delete(diseaseDB)
        session.commit()
        session.flush()
        if (not session.query(DiseaseDB).filter_by(id=diseaseDB.id).count()):
            status = True
        session.close()
        return status

    def search(self, disease=Disease(), pageSize=10, offset=0):
        """
        (Disease, pageSize, offset) -> {'total': int, 'content':[Disease]}
        """
        session = self.session_factory()
        query = session.query(DiseaseDB).filter(and_(
                        DiseaseDB.scientificName.like(
                            '%'+disease.scientificName+'%'),
                        DiseaseDB.commonName.like('%'+disease.commonName+'%')))
        content = query.slice(offset, pageSize).all()
        total = query.count()
        diseases = []
        for diseaseDB in content:
            diseases.append(Disease(
                       diseaseDB.id,
                       Plant(diseaseDB.plant.id,
                             diseaseDB.plant.scientificName,
                             diseaseDB.plant.commonName),
                       diseaseDB.scientificName,
                       diseaseDB.commonName))
        dic = {'total': total, 'content': diseases}
        return dic

    def searchByID(self, id):
        """
        (Int) -> (Disease)
        """
        session = self.session_factory()
        diseaseDB = session.query(DiseaseDB).get(id)
        return Disease(diseaseDB.id,
                       Plant(diseaseDB.plant.id,
                             diseaseDB.plant.scientificName,
                             diseaseDB.plant.commonName),
                       diseaseDB.scientificName,
                       diseaseDB.commonName)


import streamlit as st
import openai

openai.api_key = st.secrets["OPENAI_TOKEN"]

def request_chat_completion(messages, stream=False):
    response = openai.ChatCompletion.create(
        model="gpt-3.5-turbo",
        messages=messages,
        stream=stream
    )
    return response

st.title("Streamlit Chat💬")

# session state에 대화 내용 저장할 messages list 생성
if "messages" not in st.session_state:
    st.session_state.messages = []

# avatar
user_avatar = "🧑💻"
system_avatar = "./images/profile_robot.png"

with st.chat_message(name="system", avatar=system_avatar):
    st.markdown("반갑습니다 휴먼")
    with st.spinner():
        st.image("./images/dance_robot.gif")

# 이전에 나눴던 대화들 차례대로 출력
for message in st.session_state.messages:
    role = message["role"]
    content = message["content"]
    avatar = user_avatar if role == "user" else system_avatar
    with st.chat_message(role, avatar=avatar):
        st.markdown(content)

# 유저의 입력 받아서 UI에 추가
prompt = st.chat_input("입력")
if prompt:
    # UI에 그려주기
    with st.chat_message("user", avatar=user_avatar):
        st.markdown(prompt)
    # 히스토리에 추가
    st.session_state.messages.append(
        {"role": "user", "content": prompt}
    )

    with st.chat_message(name="system", avatar=system_avatar):
        is_stream = True

        with st.spinner("AI는 고민중..."):
            # time.sleep(1)
            # response = "못알아듣겠습니다 휴먼"

            # chatGPT API
            chatgpt_response = request_chat_completion(
                st.session_state.messages,
                stream=is_stream
            )

        message_placeholder = st.empty()
        if not is_stream:
            response = chatgpt_response["choices"][0]["message"]["content"]
        else:
            response = ""
            for chunk in chatgpt_response:
                delta = chunk.choices[0]["delta"]
                if "content" in delta:
                    response += delta["content"]
                    message_placeholder.markdown(response + "▌")
                else:
                    break
        message_placeholder.markdown(response)
    # 히스토리에 추가
    st.session_state.messages.append(
        {"role": "system", "content": response}
    )


import os.path as op
import os
import numpy as np
from sklearn.model_selection import train_test_split
from functions import load_settings_params as lsp
from functions import model_fitting_and_evaluation as mfe
from functions import plot_results as pr
import sys
import pickle

# --------- Main script -----------
vector_type = 'hidden'
print('Vector type: ' + vector_type)
print('Load settings and parameters')
settings = lsp.settings()
params = lsp.params()
# os.chdir(settings.path2code)
# print(os.getcwd())

# Load LSTM data
print('Loading pre-trained LSTM data...')
# LSTM_data = np.load(op.join(settings.path2LSTMdata, settings.LSTM_file_name))
# print(LSTM_data.files)
# LSTM_data = LSTM_data['vectors']
# print(LSTM_data.shape)
#sys.exit('breaked by user in code')
with open(op.join(settings.path2LSTMdata, settings.LSTM_file_name), 'rb') as f:
	LSTM_data = pickle.load(f)

LSTM_data = np.asarray(LSTM_data[vector_type])

# Loop over channels and fit a regression model between LSTM units and MEG channel
if len(sys.argv) > 1:
    print('Channel ' + sys.argv[1])
    channel = int(sys.argv[1])
    if len(sys.argv) > 2:
        print('Time point ' + sys.argv[2])
        time_point = int(sys.argv[2])
else:
    channel = 1
    time_point = 1

# for channel in range(channel, channel+10, 1):
    # If using optimal bin so don't loop over each time point within SOA
step = 10
if settings.use_optimal_bin:
    time_points = [-1]
else:
    time_points = range(0, params.SOA+1, step)

for time_point in time_points:
	pkl_filename = 'Regression_models_' + settings.patient + '_channel_' + str(channel) + '_timepoint_' + str(time_point) + '_averaged_over_' + str(step) + '_' + settings.LSTM_file_name + '.pckl'
	if not op.exists(op.join(settings.path2output, pkl_filename)):
		# Load Data
		print('Loading MEG data for channel ' + str(channel) + ' time point ' + str(time_point) + '...')
		if settings.use_optimal_bin:
			MEG_file_name = 'MEG_data_sentences_averaged_over_optimal_bin_channel_' + str(channel) + '.npz'
			MEG_data = np.load(op.join(settings.path2output, MEG_file_name))
		else:
			if settings.use_sources_data:
				MEG_file_name = 'sources/sources_dat_' + settings.patient + '_vertex_' + str(channel) + '.pkl'
				with open(op.join(settings.path2MEGdata, MEG_file_name), 'rb') as f:
					MEG_data = pickle.load(f, encoding='latin1')
			else:
				MEG_file_name = 'patient_' + settings.patient +'_epochs_lock_to_beginning_of_sentence_anomaly_type_0.npy'
				MEG_data = np.load(op.join(settings.path2MEGdata, MEG_file_name))
			real_speed_sec = int(params.sfreq * params.real_speed / 1e3)
			st = int(params.sfreq * params.startTime / 1e3) + time_point
			ed = st + real_speed_sec*8 # the same time point at the 8^th words
			IX_timepoints = np.arange(st, ed, real_speed_sec)
			print('timepoints ' + str(IX_timepoints))
			if not settings.use_sources_data:
				MEG_data = MEG_data[:,channel-1, :]

		# Reshape data to num_trials X num_features
		print('Reshaping datasets')
		num_trials, num_hidden_units, num_timepoints = LSTM_data.shape
		X = np.empty([0, num_hidden_units]) # LSTM data
		y = np.empty([0]) # MEG data
		for word in range(8):
			X = np.vstack((X, LSTM_data[:,:, word]))
			if settings.use_optimal_bin:
				y = np.hstack((y, MEG_data['arr_0'][:, word]))
			else:
				st = IX_timepoints[word]
				ed = st + step - 1
				MEG_data_mean = np.mean(MEG_data[:, st:ed], axis=1)
				y = np.hstack((y, MEG_data_mean))

	    # ## Split data to train/test sets
		print('Splitting data to train/test sets')
		X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=1./params.CV_fold,
		                                                random_state=params.seed_split)

		models = {}
		# ############ Ridge Regression ############
		if settings.run_Ridge:
			print('Fitting a ridge model for channel ' + str(channel) + ' time point ' + str(time_point))
			settings.method = 'Ridge'
			# Train model
			model_ridge = mfe.train_model(X_train, y_train, settings, params)
			# Evaluate model on test set
			ridge_scores_test = mfe.evaluate_model(model_ridge, X_test, y_test, settings, params)
			# Generate and save figures
			plt = pr.regularization_path(model_ridge, settings, params)
			file_name = 'Ridge_coef_and_R_squared_vs_regularization_size_channel_' + \
						str(channel) + '.png'
			plt.savefig(op.join(settings.path2figures, file_name))
			plt.close()
			models['model_ridge'] = model_ridge
			models['ridge_scores_test'] = ridge_scores_test
		# ##########################################

	    # ############ Lasso Regression ############
		if settings.run_LASSO:
			print('Fitting a lasso model for channel ' + str(channel) + ' time point ' + str(time_point))
			settings.method = 'Lasso'
			# Train model
			model_lasso = mfe.train_model(X_train, y_train, settings, params)
			# Evaluate model on test set
			lasso_scores_test = mfe.evaluate_model(model_lasso, X_test, y_test, settings, params)
			# Generate and save figures
			plt = pr.regularization_path(model_lasso, settings, params)
			file_name = 'Lasso_coef_and_R_squared_vs_regularization_size_channel_' + \
						str(channel) + '_timepoint_' + str(time_point) + '.png'
			plt.savefig(op.join(settings.path2figures, file_name))
			plt.close()
			models['model_lasso'] = model_lasso
			models['lasso_scores_test'] = lasso_scores_test
			print('Done fitting')
	    # ##########################################

	    # ############ Elastic-net Regression #####
		if settings.run_ElasticNet:
			print('Fitting an elastic-net model for channel ' + str(channel))
			settings.method = 'Elastic_net'
			model_enet = mfe.train_model(X_train, y_train, settings, params)
			# Evaluate model on test set
			enet_scores_test = mfe.evaluate_model(model_enet, X_test, y_test, settings, params)
			# Generate and save figures
			plt = pr.regularization_path(model_enet, settings, params)
			file_name = 'Elastic_net_coef_and_R_squared_vs_regularization_size_channel_' + \
						str(channel) + '.png'
			plt.savefig(op.join(settings.path2figures, file_name))
			plt.close()
			models['model_enet'] = model_enet
			models['enet_scores_test'] = model_enet
	    # ##########################################

	    # ############# Save models and results #####
		import pickle
		with open(op.join(settings.path2output, pkl_filename), "wb") as f:
		    pickle.dump(models, f)
		    pickle.dump(settings, f)
		    pickle.dump(params, f)
		print('Models for channel ' + str(channel) + ' time point ' + str(time_point) + 'were saved to Output folder')


from django.contrib.auth.forms import UsernameField
from django.shortcuts import redirect, render
from django.http import HttpResponse, HttpResponseRedirect
from .models import *
from .forms import *
from django.views.decorators.cache import never_cache
from register import *

# Create your views here.

def index(response):
        if response.user.is_authenticated:
                logged_in_user = Profile.objects.get(username=response.user)
        else:
                logged_in_user = ""
        return render(response, "main/index.html", {"response":response, "logged_in_user":logged_in_user})

def profile(response):
        if response.user.is_authenticated:
                return HttpResponseRedirect('/profile/{}'.format(response.user.username))
        else:
                return HttpResponseRedirect('/')

@never_cache
def user(response, username):
        if Profile.objects.filter(username=username):
                user = Profile.objects.get(username=username)
                education = Education.objects.filter(owner=user).order_by('-start_year')
                work = Experience.objects.filter(owner=user).order_by('-start_year')
                language = Language.objects.filter(owner=user).order_by('-rating')
                hobby = Hobby.objects.filter(owner=user)
                skills = Skill.objects.filter(owner=user).order_by('-rating')
                certificate = Certificate.objects.filter(owner=user).order_by('-year')
                educationform = EducationForm()
                workform = WorkForm()
                certificateform = CertificateForm()
                hobbyform = HobbyForm()
                if response.user.is_authenticated:
                        logged_in_user = Profile.objects.get(username=response.user)
                else:
                        logged_in_user = ""
                edit_profile_form = EditProfileForm(initial={"username":user.username, "avatar" : user.avatar, "name" : user.name, "title" : user.title, "bio" : user.biography, "location" : user.location,})
                return render(response, "main/user.html", {
                        "logged_in_user":logged_in_user,
                        "response":response,"user":user,
                        "education":education, "work":work,
                        "language":language, "hobby":hobby,
                        "skills":skills,"certificate":certificate,
                        "edit_profile_form":edit_profile_form,
                        "educationform": educationform,
                        "workform": workform,
                        "hobbyform": hobbyform,
                        "certificateform" : certificateform,
                        })
        else:
                return HttpResponse("Profile Not Found")

def edit(response):
        if response.method == 'POST':
                if response.user.is_authenticated:
                        form = EditProfileForm(response.POST, response.FILES)
                        if 'submit-clear' in response.POST:
                                profile = Profile.objects.get(username=response.user.username)
                                profile.avatar.delete()
                                profile.save()
                                return HttpResponseRedirect('/profile/{}#editmodal'.format(response.user.username))
                        if form.is_valid():
                                profile = Profile.objects.get(username=response.user.username)
                                if response.FILES:
                                        profile.avatar = response.FILES['avatar']
                                profile.color = response.POST['form-color']
                                profile.name = form.cleaned_data['name'].strip()
                                profile.title = form.cleaned_data['title'].strip()
                                profile.biography = form.cleaned_data['bio'].strip()
                                profile.location = form.cleaned_data['location'].strip()
                                profile.save()
                                return HttpResponseRedirect('/profile/{}'.format(response.user.username))
                        else:
                                print(form.cleaned_data)
                                print(form.errors)
                                return HttpResponseRedirect('/one/{}'.format(response.user.username))
                else:
                        return HttpResponseRedirect('/two/{}'.format(response.user.username))
        else:
                return HttpResponseRedirect('/three/{}'.format(response.user.username))

def add(response):
         if response.method == 'POST':
                if response.user.is_authenticated:
                        if 'submit-addeducation' in response.POST:
                                form = EducationForm(response.POST)
                                if form.is_valid():
                                        print(form.cleaned_data)
                                        edu = Education()
                                        edu.owner = Profile.objects.get(username=response.user.username)
                                        edu.start_year = form.cleaned_data['start_year']
                                        edu.end_year = form.cleaned_data['end_year']
                                        edu.department = form.cleaned_data['department']
                                        edu.school = form.cleaned_data['school']
                                        edu.is_highschool = form.cleaned_data['is_highschool']
                                        edu.save()
                                        return HttpResponseRedirect('/profile/{}'.format(response.user.username))
                        if 'submit-addwork' in response.POST:
                                form = WorkForm(response.POST)
                                if form.is_valid():
                                        work = Experience()
                                        work.owner = Profile.objects.get(username=response.user.username)
                                        work.start_year = form.cleaned_data['start_year']
                                        work.end_year = form.cleaned_data['end_year']
                                        work.position = form.cleaned_data['position']
                                        work.firm = form.cleaned_data['firm']
                                        work.save()
                                        return HttpResponseRedirect('/profile/{}'.format(response.user.username))
                        if 'submit-addskill' in response.POST:
                                form = SkillForm(response.POST)
                                if form.is_valid():
                                        skill = Skill()
                                        skill.owner = Profile.objects.get(username=response.user.username)
                                        skill.name = form.cleaned_data['name']
                                        skill.rating = form.cleaned_data['rating']
                                        skill.save()
                                        return HttpResponseRedirect('/profile/{}'.format(response.user.username))
                        if 'submit-addlang' in response.POST:
                                form = LanguageForm(response.POST)
                                if form.is_valid():
                                        lang = Language()
                                        lang.owner = Profile.objects.get(username=response.user.username)
                                        lang.name = form.cleaned_data['name']
                                        lang.rating = form.cleaned_data['rating']
                                        lang.save()
                                        return HttpResponseRedirect('/profile/{}'.format(response.user.username))
                        if 'submit-addhobby' in response.POST:
                                form = HobbyForm(response.POST)
                                if form.is_valid():
                                        hobby = Hobby()
                                        hobby.owner = Profile.objects.get(username=response.user.username)
                                        hobby.name = form.cleaned_data['name']
                                        hobby.description = form.cleaned_data['description']
                                        hobby.save()
                                        return HttpResponseRedirect('/profile/{}'.format(response.user.username))
                        if 'submit-addcert' in response.POST:
                                form = CertificateForm(response.POST)
                                if form.is_valid():
                                        cert = Certificate()
                                        cert.owner = Profile.objects.get(username=response.user.username)
                                        cert.type = form.cleaned_data['type']
                                        cert.description = form.cleaned_data['description']
                                        cert.year = form.cleaned_data['year']
                                        cert.save()
                                        return HttpResponseRedirect('/profile/{}'.format(response.user.username))


from sklearn.linear_model import LogisticRegression
from sklearn.neighbors import KNeighborsClassifier
import pandas as pd
import numpy as np
from sklearn.datasets import load_iris
import seaborn as sns
import matplotlib.pyplot as plt
import math
from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report, confusion_matrix
# 1. ประเภทของ ML  ?
#    - ดูจาก Input เป็น Supervised Learning เพราะข้อมูลมี labeled
#    - ดูจาก Output เป็น Classification problem เพราะ output ที่ได้เป็น class
# 2. ทำความเข้าใขกับข้อมูล
#    - Analyze the Data
#       - สถิติเชิงพรรณนา
#       - สร้างกราฟ
#    - Process the Data
#       - pre-processing (Feature Extraction) คัดเลือก Data ที่จะนำมาเป็น feature ตัด data ไม่ใช้หรือไม่มีประโยชน์ออกให้หมด
#       - profiling
#       - cleansing การตรวจสอบความถูกต้องของข้อมูลทั้งหมด
#    - Transform the data
#       - การแปลงข้อมูลดิบไปเป็นข้อมูลที่เราจะนำมาใช้สอน ml
# 3. หาอัลกอลิทึมที่ใช้ได้ดีกับข้อมูล
#    -  ตัดสินใจจาก
#       - The accuracy of the model  ความเเม่นยำของ model
#       - The interpretability of the model  ความสัมพันธ์กันของ data กับ model
#       - The complexity of the model  ความซับซ้อนของ model
#       - The scalability of the model  ความสามารถในการปรับขนาดของ model
#       - How long does it take to build, train, and test the model?  เวลาที่ใช้ไปในการสร้างเเละสอน model
#       - How long does it take to make predictions using the model?  เวลาที่ใช้ไปในทำนายของ model
#       - Does the model meet the business goal?  model ตอบโจทย์กับธุรกิจหรือป่าว
# 4. นำ machine learning มาใช้งาน
#    -  machine learning pipeline
# 5. เพิ่มประสทิธิภาพให้กับ Hyperparameter
#    - มีสามวิธีคือ grid search, random search, Bayesian optimization
#
# Machine Learning Task
#   - Supervised learning
#       - Regression
#       - Classification
#   - Unsupervused learning
#       - Cluster
#   - Reinforcement learning
#
# Machine Learning Algorithms
#   - Linear Regression
#       - ข้อมูลเชิงปริมาณ quantitative
#       - หาความสัมพันธ์ของตัวแปร X ที่เป็นตัวแปรอิสระกับ Y ที่เป็นตัวแปรตาม
#       - loss function ด้วย mean squared error (MSE) , mean absolute error (MAE)
#   - Logistic Regression
#       - เป็นประเภท classification เป็น subset ของ supervised learning
#       - output เป็น categorical หรือ binary
#   - K-means
#       - เป็นประเภท clustering เป็น subset ของ unsupervised learning
#       - จัดกลุ่มข้อมูลที่เข้ามาว่าจะอยู่ในกลุ่มไหนตามความเหมือนหรือคล้ายกัน
#       - K คือจำนวน cluster
#   - K-nearest-neigbors
#       - เป็นประเภท classification เป็น subset ของ supervised learning
#       - เป็นการจัดกลุ่มข้อมูลเมื่อมี data ใหม่เข้ามา data มีค่าใกล้เคียงกับค่าใดก็จะอยู่กลุ่มนั้น
#       - K คือค่าที่ใช้ในการหนดการ Vote
#   - Support Vector Machines
#       - เป็นประเภท classification
#       - เเบ่งเป็น 2 class ด้วยเส้นตรง
#   - Random Forest
#       - เป็นประเภท regression,classification ป็น subset ของ Supervised learning
#       - Rule base คือต้องสร้างกฏ if-else จาก feature ซิ่งมา decision tree หลายๆ อัน
#       - เป็น model แบบ ensemble คือใช้ model หลายๆ model มาประกอบกันเป็น model ที่ซับซ้อน
#   - Neural networks

iris = load_iris()
print(iris.keys())
# print(iris['DESCR'])
df = pd.DataFrame(data=iris['data'], columns=iris['feature_names'])
df['target'] = iris['target']

def getTargetNames(index):
    return iris['target_names'][index]

df['target_names'] = df['target'].apply(getTargetNames)
print(df.head(150))
print(iris['target_names'])
# print(df.info())
# print(iris['feature_names'])
# print(df.describe())

# print(pd.crosstab(index=df['sepal length (cm)'], columns='frequency').apply(
#     lambda n: (n / len(df['sepal length (cm)'])) * 100, axis=1))
# plt.hist(x='sepal length (cm)', bins=30, data=df,
#          label='sepal length (cm)', alpha=0.7)
# plt.hist(x='sepal width (cm)', bins=30, data=df,
#          label='sepal width (cm)', alpha=0.7)
# plt.hist(x='petal length (cm)', bins=30, data=df,
#          label='petal length (cm)', alpha=0.7)
# plt.hist(x='petal width (cm)', bins=30, data=df,
#          label='petal width (cm)', alpha=0.7)
# plt.legend(loc="upper right")
# plt.title("Histogram")
# plt.show()
# print("Mean ",df['sepal length (cm)'].mean())

def getMean(data):
    print("----- Mean -----")
    for c in data.columns:
        m = 0
        for value in data[c]:
            m += value
        print(f"{c} : {m/len(data[c])}")

def getMedian(data):
    print("----- Median -----")
    for c in data.columns:
        data[c] = data[c].sort_values()
        print(f"{c} : { (len(data[c]) +1) /2}")

def getMode(data):
    print("----- Mode -----")
    for c in data.columns:
        d = pd.crosstab(index=data[c], columns='Mode').sort_values(
            by='Mode', ascending=False)
        print(f"{c} : {d['Mode'].iloc[0]}")

def getRange(data):
    print("----- Range -----")
    for c in data.columns:
        data[c] = data[c].sort_values()
        print(f"{c} : { (df[c].max() - df[c].min() )}")

def getStandardDeviation(data):
    print("----- StandardDeviation -----")
    for c in data.columns:
        n = len(data[c])
        mean = data[c].mean()
        sum_x = ((data[c] - mean) ** 2).sum()
        x = sum_x / (n - 1)
        std = np.sqrt(x)
        print(f"{c} :  { (std) } ")

def getQuartileDeviation(data):
    print("----- QuartileDeviation -----")
    for c in data.columns:
        n = len(data[c])
        data[c] = data[c].sort_values()
        q1 = (1 * (n+1)) / 4
        q3 = (3 * (n+1)) / 4
        print(f'{q1} {q3}')
        if type(q1) == float:
            q1 = (data[c].loc[math.ceil(q1)-1] +
                  data[c].loc[math.floor(q1)]-1) / 2
        else:
            q1 = data[c].loc[q1]
        if type(q3) == float:
            q3 = (data[c].loc[math.ceil(q3)-1] +
                  data[c].loc[math.floor(q3)-1]) / 2
        else:
            q3 = data[c].loc[q3]
        print(f'{c} : {q1} {q3} =  {(q3-q1) / 2}')

# getMean(df)
# getMedian(df)
# getMode(df)
# getRange(df)
# getStandardDeviation(df)
# getQuartileDeviation(df)

# K-nearestn-neigbors

X = df.drop(columns=["target", "target_names"], axis=1)
y = df['target']
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.3, random_state=101)
# for i in np.arange(1, 20):
#     knn = KNeighborsClassifier(n_neighbors=i)
#     knn.fit(X_train, y_train)
#     prediction = knn.predict(X_test)
#     print(f"{i} : {knn.score(X_train, y_train)}")

knn = KNeighborsClassifier(n_neighbors=5)
knn.fit(X_train, y_train)
prediction = knn.predict(X_test)
print(knn.score(X_train, y_train))
print(confusion_matrix(y_test, prediction))
print(classification_report(y_test, prediction,
                            target_names=iris['target_names']))

print(y_train.iloc[[1]])
print(knn.predict(X_train.iloc[[1]]))

# # LogisticRegression

# log = LogisticRegression()

# log.fit(X_train, y_train)
# print(log.coef_)
# prediction_log = log.predict(X_test)
# print(confusion_matrix(y_test, prediction_log))
# print(classification_report(y_test, prediction_log,
#                             target_names=iris['target_names']))


from glob import glob
from os.path import join
from collections import defaultdict
import matplotlib.pyplot as plt
import json
from settings import BRIEFS_JSON_DIR, IMAGES_DIR

def count_matching_words(datadict, pattern):
    x = 0
    for word, wordcount in datadict['word_counts'].items():
        if pattern in word:
            x += wordcount
    return x

tally = defaultdict(int)
filenames = glob(join(BRIEFS_JSON_DIR, '*.json'))
for fn in filenames:
    with open(fn, 'r') as rf:
        data = json.load(rf)
    yr = data['date'][0:4]
    tally[yr] += count_matching_words(data, 'terror')

sorted_tally = sorted(tally.items(), key=lambda x: x[0])

years = [p[0] for p in sorted_tally]
words = [p[1] for p in sorted_tally]

plt.bar(years, words)
plt.savefig(join(IMAGES_DIR, 'terror-year.png'))


import pyautogui

w = pyautogui.getWindowsWithTitle('메모장')[0]
w.activate()

# 문자열
pyautogui.write('12345')
pyautogui.write('nadocoding', interval=0.25)
# 영문과 숫자만 가능

# 기타 키
pyautogui.write(['t', 'e', 's', 't', 'left', 'left', 'right', 'l', 'a', 'enter'], interval=0.25)
# https://automatetheboringstuff.com/2e/chapter20/
# keyboard attributes

# 특수문자
pyautogui.keyDown('shift')
pyautogui.press('4')
pyautogui.keyUp('shift')

# 조합키
pyautogui.hotkey('ctrl', 'a')

# 한글 처리
import pyperclip
pyperclip.copy('나도코딩') # 클립보드에 저장
pyautogui.hotkey('ctrl', 'v')


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Thu Aug  8 11:26:45 2019

@author: burr
"""

from sklearn.discriminant_analysis import LinearDiscriminantAnalysis

from sklearn.model_selection import KFold
from sklearn.ensemble import RandomForestClassifier
from sklearn.neighbors import KNeighborsClassifier
from sklearn.svm import SVC
import sklearn as sk

import pandas as pd
from matplotlib import pyplot as plt
from fileutils import labellist
from learningfunctions import Kfold_validation, evaluate, normalize, print_top5, plotfeatureimportance, decodelabels
from learningfunctions import extractdifffeaturevectors, changelabeltoeventbased
from features import columns
plt.close('all')

df = pd.DataFrame(columns=columns)
appliancesublist = ['laptop', 'heatbulb', 'fluorescentlight', 'kettle', 'fan2']

y5, df5 = extractdifffeaturevectors('data/5_MassiveSwitching/featurescomplete', appliancesublist)
y5 = changelabeltoeventbased(y5)

y2, df2 = extractdifffeaturevectors('data/2_WithSwitchingEvents/featurescomplete', appliancesublist)
y2 = changelabeltoeventbased(y2)

y5.extend(y2)
dfmodel = df5.append(df2, ignore_index=True)

y = y5

#X = dfmodel.drop(['label'], axis=1)
dfmodel = dfmodel[['apparent_power', 'real_power', 'nonactive_power',
'imag01', 'imag03', 'imag05', 'imag07', 'imag09',
'imag11', 'imag13', 'imag15', 'imag17', 'imag19',
#'imag21', 'imag23', 'imag25', 'imag27', 'imag29',
#'imag31', 'imag33', 'imag35', 'imag37', 'imag39',
#'imag41', 'imag43', 'imag45', 'imag47', 'imag49',
#'imag51', 'imag53', 'imag55', 'imag57', 'imag59',
#
#
'real01', 'real03', 'real05', 'real07', 'real09',
'real11', 'real13', 'real15', 'real17', 'real19',
#'real21', 'real23', 'real25', 'real27', 'real29',
#'real31', 'real33', 'real35', 'real37', 'real39',
#'real41', 'real43', 'real45', 'real47', 'real49',
#'real51', 'real53', 'real55', 'real57', 'real59',
#
]]
X = dfmodel
X = X.values

X_train = X
y_train = y
X_train, X_test, y_train, y_test = sk.model_selection.train_test_split(X, y, test_size=0.33, random_state=12)

model1 = RandomForestClassifier(n_estimators =1000,min_samples_leaf=1, max_leaf_nodes=10,random_state=10)
#model1 = KNeighborsClassifier(n_neighbors=1, leaf_size=10)
#model1 = SVC(C=0.001, gamma=0.0001, kernel='linear')

model1.fit(X_train, y_train)
y_pred = model1.predict(X_test)
print('On Model Dataset')
evaluate(y_test, y_pred, labellist, plotconfusionmatrix="2OnModel2")
#print_top5(dfmodel.columns, axis=1).columns, model1)
#plotfeatureimportance(model1, dfmodel)

#
yunseen1, dfunseen1 = extractdifffeaturevectors('data/3_MultipleDevices_Order10/featurescomplete', ['0order'])
yunseen2, dfunseen2 = extractdifffeaturevectors('data/3_MultipleDevices_Order10/featurescomplete', ['1order'])
yunseen3, dfunseen3 = extractdifffeaturevectors('data/3_MultipleDevices_Order11/featurescomplete', ['0order'])
yunseen4, dfunseen4 = extractdifffeaturevectors('data/3_MultipleDevices_Order11/featurescomplete', ['1order'])
yunseen1.extend(yunseen2)
yunseen1.extend(yunseen3)
yunseen1.extend(yunseen4)
yunseen=yunseen1

dfunseen1=dfunseen1.append(dfunseen2, ignore_index=True)#.append(dfunseen3, ignore_index=True).append(dfunseen4, ignore_index=True)
dfunseen1=dfunseen1.append(dfunseen3, ignore_index=True)
dfunseen1=dfunseen1.append(dfunseen4, ignore_index=True)
dfunseen=dfunseen1
#Xunseen = dfunseen.drop(['label'],axis=1)

dfunseen = dfunseen[['apparent_power', 'real_power', 'nonactive_power',
'imag01', 'imag03', 'imag05', 'imag07', 'imag09',
'imag11', 'imag13', 'imag15', 'imag17', 'imag19',
#'imag21', 'imag23', 'imag25', 'imag27', 'imag29',
#'imag31', 'imag33', 'imag35', 'imag37', 'imag39',
#'imag41', 'imag43', 'imag45', 'imag47', 'imag49',
#'imag51', 'imag53', 'imag55', 'imag57', 'imag59',
#
#
'real01', 'real03', 'real05', 'real07', 'real09',
'real11', 'real13', 'real15', 'real17', 'real19',
#'real21', 'real23', 'real25', 'real27', 'real29',
#'real31', 'real33', 'real35', 'real37', 'real39',
#'real41', 'real43', 'real45', 'real47', 'real49',
#'real51', 'real53', 'real55', 'real57', 'real59',
#
]]
Xunseen = dfunseen

Xunseen = Xunseen.values

y_unseenpred = model1.predict(Xunseen)
evaluate(yunseen, y_unseenpred, labellist, plotconfusionmatrix="2OnUnseen3")


"""
This file demonstrates writing tests using the unittest module. These will pass
when you run "manage.py test".

Replace this with more appropriate tests for your application.
"""

from django.test import TestCase
from forms import ContactForm
from models import Contact

class ContactFormTest(TestCase):

    def test_simple_test_modelform(self):
        data = {
            "name": "test",
            "email": "test@test.com",
            "message": "Message test",
            "category": "OUT",
        }
        form = ContactForm(data)
        self.assertTrue(form.is_valid())

    def test_return_from_model(self):
        data = {
            "name": "test",
            "email": "test@test.com",
            "message": "Message test",
            "category": "OUT",
        }

        contact = Contact.objects.create(**data)
        self.assertEquals(data['name'], str(contact))


from parse_sdf import IOPath, SetupHoldCheck
from os import path
import database
import sys, json, os, glob, pickle

def unescape_sdf_name(name):
    e = ""
    if name[0] == '"':
        assert name[-1] == '"'
        name = name[1:-1]
    for c in name:
        if c == '\\':
            continue
        e += c
    return e

# DSP cell types
dsp_celltypes = {
    "MULT9_CORE",
    "PREADD9_CORE",
    "MULT18_CORE",
    "REG18_CORE",
    "MULT18X36_CORE",
    "MULT36_CORE",
    "ACC54_CORE",
}

ebr_celltypes = {
    "SP16K_MODE",
    "DP16K_MODE",
    "PDP16K_MODE",
    "PDPSC16K_MODE",
    "FIFO16K_MODE",
}

# We strip off these prefices, as all delays to 'subports' are the same
dsp_prefixes = [
    "M9ADDSUB", "ADDSUB",
    "SFTCTRL", "DSPIN", "CINPUT", "DSPOUT", "CASCOUT", "CASCIN",
    "PML72", "PMH72", "SUM1", "SUM0",
    "BRS1", "BRS2", "BLS1", "BLS2", "BLSO", "BRSO", "PL18", "PH18", "PL36", "PH36", "PL72", "PH72",
    "P72", "P36", "P18", "AS1", "AS2", "ARL", "ARH", "BRL", "BRH",
    "AO", "BO", "AB", "AR", "BR", "PM", "PP",
    "A", "B", "C",
]
ebr_prefixes = [
    "DIA",
    "DIB",
    "DOA",
    "DOB",
    "CSA",
    "CSB",
    "ADA",
    "ADB",
]
lram_prefixes = [
    "DIA",
    "DIB",
    "DOA",
    "DOB",
    "CSA",
    "CSB",
    "ADA",
    "ADB",
    "BENA_N",
    "BENB_N",
    "ERRDECA",
    "ERRDECB",
]

# Which IOLOGIC signals are relevant for which purposes...
iol_input_sigs = ["SCLKIN", "CEIN", "LSRIN", "INFF", "DI", "WORDALIGN"] + ["RXDATA{}".format(i) for i in range(10)]
iol_output_sigs = ["SCLKOUT", "CEOUT", "LSROUT", "DOUT", "TOUT"] + ["TXDATA{}".format(i) for i in range(10)] + ["TSDATA{}".format(i) for i in range(4)]
iol_dly_sigs = ["INDD", "DIR", "LOAD_N", "MOVE", "CFLAG"]

subtracts = {}

def rewrite_path(modules, modtype, from_pin, to_pin):
    # Rewrite a (celltype, from_pin, to_pin) tuple given cell data, or returns None to drop the path
    # This looks at the JSON output by Yosys from the Lattice structural Verilog netlist in order
    # to determine what the cells in the SDF file are actually doing
    mod = modules["modules"][modtype]
    mod_cells = mod["cells"]

    def get_netid(name):
        if name not in mod["netnames"]:
            return -1
        return mod["netnames"][name]["bits"][0]

    for cellname, cell in mod_cells.items():
        # Go through each sub-cell inside the SDF-level cell module
        celltype = cell["type"]
        if celltype.startswith("UALUT4"):
            # Simple LUT4s
            if from_pin in ("A0", "A1", "B0", "B1", "C0", "C1", "D0", "D1") and to_pin in ("F0", "F1"):
                return ("OXIDE_COMB:LUT4", from_pin[0], to_pin[0])
        elif celltype.startswith("UACCU2"):
            # Carries
            if from_pin in ("A0", "A1", "B0", "B1", "C0", "C1", "D0", "D1", "FCI") and to_pin in ("F0", "F1", "FCO"):
                # TODO: split in half?
                return ("OXIDE_COMB:CCU2", from_pin, to_pin)
        elif celltype.startswith("UASLICEREG"):
            # Flipflops
            # We need to work if we are index 0 or 1 within the SLICE, use the connectivity of Q1 to determine this
            idx = 1 if cell["connections"]["Q"][0] == get_netid("Q1") else 0
            if from_pin in ("DI0", "DI1", "M0", "M1"):
                if int(from_pin[-1]) != idx:
                    continue
                from_pin = from_pin[:-1]
            elif from_pin not in ("LSR", "CE", "CLK"):
                continue
            if to_pin in ("Q0", "Q1"):
                if int(to_pin[-1]) != idx:
                    continue
                to_pin = to_pin[:-1]
            elif to_pin != "CLK":
                continue
            invstr = "N" if "CLK_INVERTERIN" in mod_cells else "P"
            invstr += "N" if "LSR_INVERTERIN" in mod_cells else "P"
            invstr += "N" if "CE_INVERTERIN" in mod_cells else "P"

            # Skip these, as they aren't actually different numerically so we can derive them later on and just clutter things up
            if invstr != "PPP":
                return None
            ffinst = modules["modules"][celltype]["cells"]["INST10"]
            synctype = "ASYNC" if ffinst["parameters"].get("ASYNC", "NO") == "YES" else "SYNC"
            return ("OXIDE_FF:{}:{}".format(invstr, synctype), from_pin, to_pin)
        elif celltype.startswith("UARAMW"):
            ramw_pins = (
                "A0", "A1", "B0", "B1", "C0", "C1", "D0", "D1", "CLK", "LSR",
                "WDO0", "WDO1", "WDO2", "WDO3", "WADO0", "WADO1", "WADO2", "WADO3", "WCKO", "WREO"
            )
            if from_pin in ramw_pins and to_pin in ramw_pins:
                return ("RAMW", from_pin, to_pin)
        elif celltype.startswith("UADPRAM"):
            if from_pin in ("A0", "A1", "B0", "B1", "C0", "C1", "D0", "D1", "WDI0", "WDI1"):
                return ("OXIDE_COMB:DPRAM", from_pin[:-1], to_pin[:-1])
        elif celltype.startswith("selmux2"):
            if to_pin == "OFX0":
                if from_pin in ("A0", "B0", "C0", "D0"):
                    return ("OXIDE_COMB:WIDEFN9", from_pin[:-1], to_pin[:-1])
                elif from_pin == "D1":
                    key = ("OXIDE_COMB:WIDEFN9", "F1", to_pin[:-1])
                    subtracts[key] = ("OXIDE_COMB:LUT4", "D", "F")
                    return key
                elif from_pin == "SEL":
                    return ("OXIDE_COMB:WIDEFN9", from_pin, to_pin[:-1])
        elif celltype.startswith("DCS"):
            if from_pin in ("CLK0", "CLK1", "SEL", "SELFORCE") and to_pin in ("DCSOUT", "CLK0", "CLK1"):
                return("DCS:DCS", from_pin, to_pin)
        elif "_INPUT" in modtype or "_OUTPUT" in modtype or "_INOUT" in modtype:
            # PIO config is encoded in name
            ct = modtype.split("__")
            new_type = "PIO:{}{}".format(
                ct[1], "".join(":{}".format(kv) for kv in ct[3:])
            )
            if "_INPUT" in from_pin or "_OUTPUT" in from_pin or "_INOUT" in from_pin:
                from_pin = "IOPAD"
            if "_INPUT" in to_pin or "_OUTPUT" in to_pin or "_INOUT" in to_pin:
                to_pin = "IOPAD"
            return (new_type, from_pin, to_pin)
        if "_S_IOB_" in modtype or "__IOB_" in modtype:

            def idelay_used():
                di_idx = get_netid("DI")
                for cellname2, cell2 in mod_cells.items():
                    if cell2["type"].startswith("DELAY") and cell2["connections"]["A"][0] == di_idx:
                        return True
                return False
            def odelay_used():
                dout_idx = get_netid("DOUT")
                for cellname2, cell2 in mod_cells.items():
                    if cell2["type"].startswith("DELAY") and cell2["connections"]["Z"][0] == dout_idx:
                        return True
                return False
            # For IOLOGIC, we encode in the buffer name (which becomes the IOL name)
            # whether this is a simple 'SIOLOGIC' or full 'IOLOGIC'
            s = "S" if "_S_IOB_" in modtype else ""
            if celltype.startswith("DELAY"):
                if from_pin in iol_dly_sigs or to_pin in iol_dly_sigs:
                    return ("{}IOLOGIC:DELAY".format(s), from_pin, to_pin)
            elif celltype.startswith("IOREG"):
                if from_pin in iol_input_sigs or to_pin in iol_input_sigs:
                    return ("{}IOLOGIC:IREG{}".format(s, ":DELAYED" if idelay_used() else ""), from_pin, to_pin)
                if from_pin in iol_output_sigs or to_pin in iol_output_sigs:
                    return ("{}IOLOGIC:OREG{}".format(s, ":DELAYED" if odelay_used() else ""), from_pin, to_pin)
            elif celltype.startswith("IDDR"):
                ddrtype = celltype[:6]
                if from_pin in iol_input_sigs or to_pin in iol_input_sigs:
                    if to_pin[-1].isdigit():
                        to_pin = to_pin[:-1]
                    return ("{}IOLOGIC:{}{}".format(s, ddrtype, ":DELAYED" if idelay_used() else ""), from_pin, to_pin)
            elif celltype.startswith("ODDR"):
                ddrtype = celltype[:6]
                if from_pin in iol_output_sigs or to_pin in iol_output_sigs:
                    if from_pin[-1].isdigit():
                        from_pin = from_pin[:-1]
                    return ("{}IOLOGIC:{}{}".format(s, ddrtype, ":DELAYED" if odelay_used() else ""), from_pin, to_pin)
        # Removing prefices as defined above; for buses that share delays
        def strip_prefix(x, p):
            for pr in p:
                if x.startswith(pr) and x[len(pr):].isdigit():
                    return pr
            return x
        def strip_prefix_ebr(x, p):
            for pr in p:
                if x.startswith(pr) and x[len(pr):].isdigit():
                    pin = pr
                    if pr in ("ADA", "ADB"):
                        i = int(x[len(pr):])
                        pin += "_13_5" if i > 4 else "_4_0"
                    return pin
            return x
        # Handle the special cases of DSP and EBR
        for dsp_type in dsp_celltypes:
            if not celltype.startswith(dsp_type):
                continue
            # Determine DSP cell programming
            dsp_postfix = set()
            for sub_cell in modules["modules"][celltype]["cells"].values():
                for k, v in sub_cell["parameters"].items():
                    if "REGBYPS" in k and v == "REGISTER":
                        dsp_postfix.add(k.replace("REGBYPS", "REG"))
                    if k == "BYPASS_PREADD9" and v == "BYPASS":
                        dsp_postfix.add("BYPASS")
            cell_type = dsp_type
            if len(dsp_postfix) > 0:
                cell_type += ":"
                cell_type += ",".join(sorted(dsp_postfix))
            return (cell_type, strip_prefix(from_pin, dsp_prefixes), strip_prefix(to_pin, dsp_prefixes))
        for ebr_type in ebr_celltypes:
            if not celltype.startswith(ebr_type):
                continue
            return (ebr_type, strip_prefix_ebr(from_pin, ebr_prefixes), strip_prefix_ebr(to_pin, ebr_prefixes))
        if celltype.startswith("LRAM_CORE"):
            return ("LRAM_CORE", strip_prefix(from_pin, lram_prefixes), strip_prefix(to_pin, lram_prefixes))
    return None

def main():
    folder = sys.argv[1]
    iopaths = {}
    setupholds = {}

    speedgrades = ["4", "5", "6", "10", "11", "12", "M"]
    for speed in speedgrades:
        iopaths[speed] = {}
        setupholds[speed] = {}

    # Import JSON netlists and SDF files
    for netlist in glob.glob(path.join(folder, "*.vo.json")):
        with open(netlist, "r") as jf:
            modules = json.load(jf)
        sdffile = netlist.replace(".vo.json", ".sdf.pickle")
        if not path.exists(sdffile):
            continue
        with open(sdffile, "rb") as sdff:
            sdf = pickle.load(sdff)

        speed = sdffile.replace(".sdf.pickle", "").split("_")[-1]
        assert speed in speedgrades
        for cell in sdf.cells.values():
            celltype = unescape_sdf_name(cell.type)
            for entry in cell.entries:
                if isinstance(entry, IOPath):
                    rewritten = rewrite_path(modules, celltype, entry.from_pin, entry.to_pin)
                    if rewritten is None:
                        continue
                    if rewritten in iopaths[speed]:
                        # If path appears multiple times; pick the worst case
                        iopaths[speed][rewritten] = (
                            min(iopaths[speed][rewritten][0], entry.rising.minv, entry.falling.minv),
                            max(iopaths[speed][rewritten][1], entry.rising.maxv, entry.falling.maxv),
                        )
                    else:
                        # Add to the list of paths
                        iopaths[speed][rewritten] = (
                            min(entry.rising.minv, entry.falling.minv),
                            max(entry.rising.maxv, entry.falling.maxv),
                        )
                elif isinstance(entry, SetupHoldCheck):
                    pin = entry.pin
                    if isinstance(entry.pin, list):
                        pin = pin[1]
                    rewritten = rewrite_path(modules, celltype, pin, entry.clock[1])
                    if rewritten is None:
                        continue
                    if rewritten in setupholds[speed]:
                        setupholds[speed][rewritten] = (
                            min(setupholds[speed][rewritten][0], entry.setup.minv),
                            max(setupholds[speed][rewritten][1], entry.setup.maxv),
                            min(setupholds[speed][rewritten][2], entry.hold.minv),
                            max(setupholds[speed][rewritten][3], entry.hold.maxv),
                        )
                    else:
                        setupholds[speed][rewritten] = (
                            entry.setup.minv, entry.setup.maxv,
                            entry.hold.minv, entry.hold.maxv,
                        )
    for speed in speedgrades:
        # Apply subtraction rules
        iopath_keys = sorted(iopaths[speed].keys())
        for key in iopath_keys:
            if key not in subtracts:
                continue
            sub_key = subtracts[key]
            sub_iopath = iopaths[speed][sub_key]
            # Compute all corner combinations
            cnr00 = iopaths[speed][key][0] - sub_iopath[0]
            cnr01 = iopaths[speed][key][0] - sub_iopath[1]
            cnr10 = iopaths[speed][key][1] - sub_iopath[0]
            cnr11 = iopaths[speed][key][1] - sub_iopath[1]
            iopaths[speed][key] = (
                min(cnr00, cnr01, cnr10, cnr11),
                max(cnr00, cnr01, cnr10, cnr11),
            )
        # Convert to the format that we save to JSON
        json_celltypes = {}
        for key, iopath in sorted(iopaths[speed].items()):
            if key[0] not in json_celltypes:
                json_celltypes[key[0]] = dict(iopaths=[], setupholds=[])
            json_celltypes[key[0]]["iopaths"].append(dict(from_pin=key[1], to_pin=key[2], minv=iopath[0], maxv=iopath[1]))
        for key, sh in sorted(setupholds[speed].items()):
            if key[0] not in json_celltypes:
                json_celltypes[key[0]] = dict(iopaths=[], setupholds=[])
            json_celltypes[key[0]]["setupholds"].append(dict(pin=key[1], clock=key[2],
                min_setup=sh[0], max_setup=sh[1],
                min_hold=sh[2], max_hold=sh[3])
            )
        timing_root = path.join(database.get_db_root(), "LIFCL", "timing")
        os.makedirs(timing_root, exist_ok=True)
        with open(path.join(timing_root, "cells_{}.json".format(speed)), 'w') as outf:
            json.dump(dict(celltypes=json_celltypes), outf, sort_keys=True, indent=4)
if __name__ == '__main__':
    main()


'''
river sizes
matrix traversal

count the adjacent rivers and their total sizes and return a list of the sizes
https://www.algoexpert.io/questions/River%20Sizes

my solution: calling the main function riverSizes returning the result
the result will be return from traversing the map whilst checking for
traversed river 'nodes' and marking them as checked. If a river node is a 1
then the traverseRiver function will algorithmically traverse the matrix
using the bounds set as conditions for when to stop increasing/decreasing row/col.

These bounds are established everytime the algorithm is called and returns an additional
length of 1 if that node is a river node. Returning the length of the total rivers counted
to each matrix cell (whilst recursively marking them as traversed and continue whilst the next iteration
touches on an already traversed node)'''

def riverSizes(matrix):
    # Write your code here.
    res = []
    checkedMatrix = [[False for value in row] for row in matrix]
    print(checkedMatrix)
    traverseMap(matrix, checkedMatrix, res)
    return res

def traverseMap(matrix, checkedMatrix, res):
    for row in range(len(matrix)):
        for col in range(len(matrix[row])):
            curLen = 0
            curLen = traverseRiver(row, col, checkedMatrix, matrix, curLen)
            if curLen:
                res.append(curLen)

def traversed(row, col, checkedMatrix):
    if checkedMatrix[row][col]:
        return True
    else:
        checkedMatrix[row][col] = True
        return False

def traverseRiver(row, col, checkedMatrix, matrix, curLen):
    leftbound, upperbound = 0, 0
    rightbound, lowerbound = len(matrix[0])-1, len(matrix)-1

    if not traversed(row, col, checkedMatrix):
        if matrix[row][col] != 1:
            return curLen
        curLen += 1
        #up
        if row-1 >= upperbound:
            curLen = traverseRiver(row-1, col, checkedMatrix, matrix, curLen)
        #down
        if row+1 <= lowerbound:
            curLen = traverseRiver(row+1, col, checkedMatrix, matrix, curLen)
        #left
        if col-1 >= leftbound:
            curLen = traverseRiver(row, col-1, checkedMatrix, matrix, curLen)
        #right
        if col+1 <= rightbound:
            curLen = traverseRiver(row, col+1, checkedMatrix, matrix, curLen)
    return curLen

mat = [
    [1, 0, 0, 1, 0],
    [1, 0, 1, 0, 0],
    [0, 0, 1, 0, 1],
    [1, 0, 1, 0, 1],
    [1, 0, 1, 1, 0]
  ]

# mat = [[1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0]]

# mat = [
#     [1, 1, 0, 0, 0, 0, 1, 1],
#     [1, 0, 1, 1, 1, 1, 0, 1],
#     [0, 1, 1, 0, 0, 0, 1, 1]
#   ]

ans = riverSizes(mat)
print('answer', ans)


# MENU
MENU = "MENU"
NAME = "NAME"
DESCRIPTION = "DESCRIPTION"
PARENT = "PARENT"
CHILD = "CHILD"

# FORM APPLICATION
FORM = "FORM"
MODEL = "MODEL"
DATA = "DATA"
SHOW_DATA = "SHOW_DATA"
FIELDS = "FIELDS"
FIELD_INDEX = "FIELD_INDEX"
FIELD_EDIT = "FIELD_EDIT"
COMPLETE = "COMPLETE"

# QUESTIONS
TITLE = "TITLE"
TEXT = "TEXT"
HINT = "HINT"


#Quick unoptimized prime factorization

primes = []

def is_prime(n):
    for i in range(2, n):
        if n % i == 0:
            return False
    return True

def prime_factorization(n):
    factors = [i for i in range(2, n+1) if n % i == 0]
    largest = max([i for i in factors if is_prime(i)])
    other = int(n/largest)
    if is_prime(other):
        primes.append(largest)
        primes.append(other)
        return
    primes.append(largest)
    prime_factorization(other)

def main():
    n = int(input('n: '))
    if is_prime(n):
        print('The number is prime')
        return
    else:
        prime_factorization(n)
        print(sorted(primes))

if __name__ == '__main__':
    main()


import re
for _ in range(int(input())):

    n,m=map(int,input().split())
    arr=str(input())
    for i in range(m):
        l,r=map(int,input().split())
        if l==r:
            print("No")
        else:

            string=arr[l-1:r]  #010
            #print(string)
            fin=string[-1] #0
            #print(fin)
            index=arr.find(string[:len(string)-1])  #1
            #print(index)
            another1=arr[:index]
            index+=(len(string)-1)  #3
            #print("up",index)
            another=arr[index+1:]
            #print(another)
            if another.find(fin)==-1 and another1.find(fin)==-1:
                print("No")
            else:
                print("Yes")

            '''
            string=arr[l-1:r]
            print(string)
            for i in range(len(string)):

                if i==(len(string)-1):
                    index = arr[prev + 1:].rfind(string[i])
                    if index-prev<=1:
                        print("No")
                    else:
                        print("Yes")

                print(arr[prev+1:])
                index=arr[prev+1:].find(string[i])
                prev=index
                print(prev,index)

                '''


import numpy as np
import csv
import pandas as pd
import plotly.express as px

with open("sample_data/coffee.csv") as file:
    data = csv.DictReader(file)
    x = []
    y = []
    for i in data:
        x.append(float(i['Sleep']))
        y.append(float(i['Coffee']))

    c = np.corrcoef(x, y)
    print("Correlation between sleep and coffee taken: " + str(c[0, 1]))

    df = pd.read_csv("sample_data/coffee.csv")
    d = px.scatter(df, x="Sleep", y="Coffee", title="graph", color="Week", size="Coffee")
    d.show()

with open("sample_data/marks.csv") as file:
    data = csv.DictReader(file)
    x = []
    y = []
    for i in data:
        x.append(float(i['Days Present']))
        y.append(float(i['Marks']))

    c = np.corrcoef(x, y)
    print("Correlation between days present and marks: " + str(c[0, 1]))

    df = pd.read_csv("sample_data/marks.csv")
    d = px.scatter(df, x="Days Present", y="Marks", title="graph", color="Roll No", size="Marks")
    d.show()