import pandas as pd
import numpy as np
# Módulo para referenciar tipagens
from typing import List, Any, Tuple
import os

if (os.system("pip install multipledispatch") == 0):
    print("------------------------------------------------")
    print("   multipledispatch instalado com sucesso!")
    print("------------------------------------------------")
else:
    print("------------------------------------------------\n")
    print("Não foi possível instalar o multipledispatch.")
    print("\n------------------------------------------------")

# Módulo externo para criar sobrecargas de funções
from multipledispatch import dispatch

class ExtratorDeProbabilidades:
    # Letra a
    def __init__(self, path: str) -> None:
        # Seta o path como um atributo da classe; não será usado1

        self.path = path
        try:
            # Cria o dataframe a partir do path passado
            self.df = pd.read_csv(path, sep=',', encoding="iso-8859-1")

        except:
            self.df = pd.DataFrame({})
            print("------------------------------------------------")
            print("    Ocorreu um erro ao carregar o arquivo.")
            print("------------------------------------------------")
            os.system("pause")
            os.system("cls")

    # Letra b
    def carregar_colunas(self, lista_colunas: List[str], quantidade: int) -> pd.DataFrame:
        try:
            # Tenta carregar as colunas baseado no limite que o usuário desejar;
            return self.df[lista_colunas][:quantidade]
        except:
            print("------------------------------------------------")
            print("    Ocoreu um erro ao carregar as colunas")
            print("------------------------------------------------")
            os.system("pause")
            os.system("cls")
    # Letra c
    def descarregar_colunas(self) -> None:
        self.df = pd.DataFrame({})

    # Letra d
    def probabilidade_apriori(self, caracteristica: str, valor: Any) -> float or None:
        try:
            # Filtra o dataframe pela coluna desejada da tabela e calcula o tamanho
            num_espec = len(self.df[self.df[caracteristica] == valor])
            # Retorna o tamanho do tabela filtrada dividido pela tabela total
            return num_espec/len(self.df)
        except:
            print("------------------------------------------------")
            print("  Ocorreu um erro ao calcular a porcentagem.")
            print("------------------------------------------------")
            os.system("cls")

    # Letra e
    @dispatch(str, tuple) # Decorator usado para utilizar a sobrecarga; como definido na questão, a função deve possuir mesmo nome
    def probabilidade_apriori_intervalo(self, caracteristica: str, intervalo: Tuple[int, int]) -> float or None:
        try:

            inicio, fim = intervalo
            num_espec = len(self.df[caracteristica][inicio:fim])
            return num_espec / len(self.df[caracteristica])

        except:
            print("------------------------------------------------")
            print("  Ocorreu um erro ao calcular a porcentagem.")
            print("------------------------------------------------")
            os.system("pause")
            os.system("cls")

    # Letra f
    def probabilidade_condicional(self, cond_a: Tuple[str, str], cond_b: Tuple[str, str]) -> float or None:
        try:
            # Recebe duas colunas e valores a serem filtrados
            carac_a, val_a = cond_a
            carac_b, val_b = cond_b
            # Cria duas condições que serão utilizadas para gerar o filtro no dataframe
            filter_a = self.df[carac_a] == val_a
            filter_b = self.df[carac_b] == val_b
            # Retorna o tamanho das duas condições a e b aplicadas no dataframe dividido pelo tamanho do dataframe aplicado à condição b
            return len(self.df[filter_a & filter_b])/len(self.df[filter_b])
        except:
            print("------------------------------------------------")
            print("  Ocorreu um erro ao calcular a porcentagem.")
            print("------------------------------------------------")
            os.system("pause")
            os.system("cls")

    # Letra g
    @dispatch(tuple, tuple)
    def probabilidade_apriori_intervalo(self, a: Tuple[str, str], b: Tuple[str, Tuple[int, int]]):
        try:
            carac, valor = a
            _, (inicio, fim) = b

            try:
                qtd_filtro = (self.df[carac][inicio:fim] == valor).value_counts()[True]
            except KeyError:
                qtd_filtro = 0

            qtd_total = len(self.df[carac] == valor)
            return qtd_filtro/qtd_total

        except ZeroDivisionError:
            return 0

    # Desafios
    def desafio_a(self, a: Tuple[str, str], b: Tuple[str, str], column=str, percentage: float = 0.9):
        try:
            carac_a, valor_a = a
            carac_b, valor_b = b
            modelos = self.df[(self.df[carac_a] == valor_a) & (self.df[carac_b] < valor_b)][column].value_counts(normalize=True) > percentage
            # Cria um conjunto que irá guardar o valor dos carros
            carros = set()
            # Itera sobre os valores verdade da tabela criada pelo filtro, junto aos índices, que nesse caso
            for modelo, valor in zip(modelos.index, modelos):
                # Caso o valor seja true, adiciona o modelo do carro no conjunto
                if valor == True: carros.add(modelo)
            # Retorna o conjunto de carros caso exista pelo menos um, caso contrário retorna "{}"
            return carros if carros else "{}"
        except:
            print("Ocorreu um erro ao resolver o desafio.")

    def desafio_b(self, a: Tuple[str, str], b: Tuple[str, str], pct: float):
        try:
            # Gera um dataframe com os filtros passados
            carac_a, valor_a = a
            carac_b, valor_b = b
            valores = self.df[(self.df[carac_a] == valor_a) & (self.df[carac_b] == valor_b)]
            # Caso o índice seja maior que 2, iremos receber o primeiro e último índice
            if len(valores.index) >= 2:
                # Retorna o primeiro e o último índice, representando os limites
                val = len(valores.index)
                for i in range(val):
                    if (i/val) > pct: break
                return (valores.index[0], valores.index[i])
            # Caso haja apenas um valor, não faz sentido querer enviar um range, pois qualquer range contendo o valor
            # satisfaz a condição; nesse caso enviamos apenas o índice do valor que satisfaz a condição
            elif len(valores.index) == 1:
                return {valores.index[0]}
            else:
                # Caso não exista, retorna None
                return None
        except:
            print("Ocorreu um erro ao resolver o desafio.")

    def menu(self):
        print(" __________________________________________________")
        print("|1 - Carregar Arquivo                              |")
        print("|2 - Mostrar DataFrame                             |")
        print("|3 - Carregar Colunas                              |")
        print("|4 - Probabilidade à Priori                        |")
        print("|5 - Probabilidade à Priori - Intervalo            |")
        print("|6 - Probabilidade Condicional                     |")
        print("|7 - Probabilidade à Priori - Intervalo (Tipo 2)   |")
        print("|8 - Desafio                                       |")
        print("|9 - Descarregar Arquivo                           |")
        print("|10- Créditos                                      |")
        print("|0 - Sair                                          |")
        print("|__________________________________________________|")
        print()

        opt = int(input("Insira o número relativo à operação desejada: "))
        if (opt == 1):

            filename = input("\nInsira o filename: ")
            self.__init__(filename)
            print("<<<------------------------------------------>>>")
            print("     BASE DE DADOS CARREGADA COM SUCESSO!")
            print("<<<------------------------------------------>>>")
            os.system("pause")
            os.system("cls")
            return True

        elif (opt == 2):
            os.system("cls")
            print(self.df)
            os.system("pause")
            os.system("cls")
            return True

        elif (opt == 3):
            print("------------------------------------------------")
            colunas = input("Insira o nome das colunas que deseja verificar, separadas por espaço: ").split()
            lim = int(input("Insira a quantidade de elementos desejada: "))
            print(self.carregar_colunas(colunas, lim))
            os.system("pause")
            os.system("cls")
            return True

        elif (opt == 4):
            print("------------------------------------------------")
            carac = input("Insira a coluna: ")
            val = input("Insira o valor")
            print(self.probabilidade_apriori(carac, val))
            os.system("pause")
            os.system("cls")
            return True

        elif (opt == 5):
            print("------------------------------------------------")
            carac = input("Insira a coluna desejada: ")
            inf = input("Insira o limite inferior: ")
            sup = input("Insira o limite superior: ")
            print(self.probabilidade_apriori_intervalo(carac, (inf, sup)))
            os.system("pause")
            os.system("cls")
            return True

        elif (opt == 6):
            print("------------------------------------------------")
            cond_a, valor_a = input("Insira a coluna e o valor seguidos por espaço: ").split()
            cond_b, valor_b = input("Insira a segunda coluna e o valor seguidos por espaço: ").split()
            print(self.probabilidade_condicional((cond_a, valor_a), (cond_b, valor_b)))
            os.system("pause")
            os.system("cls")
            return True

        elif (opt == 7):
            print("------------------------------------------------")
            os.system("cls")
            cond, valor = input("Insira a coluna e o valor seguidos por espaço: ").split()
            inf = input("Insira o limite inferior: ")
            sup = input("Insira o limite superior: ")
            print(self.probabilidade_apriori_intervalo((cond, valor), (cond, (inf, sup))))
            os.system("pause")
            os.system("cls")
            return True

            print(self.desafio_a((cond_a, valor_a), (cond_b, valor_b), col, pct))

        elif (opt == 8):
            print("------------------------------------------------")
            cond_a, valor_a = input("Insira a coluna e o valor seguidos por espaço: ").split()
            cond_b, valor_b = input("Insira a segunda coluna e o valor seguidos por espaço: ").split()
            pct = float(input("Insira a porcentagem entre 0 e 1: "))
            print(self.desafio_b((cond_a, valor_a), (cond_b, valor_b), pct))
            os.system("pause")
            os.system("cls")

        elif (opt == 9):
            os.system("cls")
            self.descarregar_colunas()
            print("------------------------------------------------")
            print("     Dataframe limpo com sucesso!")
            print("------------------------------------------------")
            os.system("pause")
            os.system("cls")
            return True

        elif (opt == 10):
            os.system("cls")
            print("  ______________________________________________ ")
            print(" |                                              |")
            print(" |     2º Projeto de IP - PYTHON                |")
            print(" | Prof. Dr. Luis Filipe Alves Pereira          |")
            print(" |----------------------------------------------|")
            print(" |                                              |")
            print(" |  Aluno1: Claudierio Baltazar Barra Nova      |")
            print(" |  Aluno2: Filipe Alencar Andrade Amorim Gomes |")
            print(" |______________________________________________|\n")
            os.system("pause")
            os.system("cls")

        elif (opt == 0):
            print("\n------------------------------------------------")
            print("     O programa foi encerrado com sucesso.")
            print("------------------------------------------------\n")
            os.system("pause")
            os.system("cls")
            return

"""### Testes com o csv vehicles-light"""

t = ExtratorDeProbabilidades('vehicles-light.csv')
t.probabilidade_apriori(caracteristica='region', valor='birmingham')

t.probabilidade_apriori_intervalo('region', (1, 10))

t.probabilidade_condicional(cond_a=('region', 'birmingham'), cond_b=('transmission', 'other'))

t.probabilidade_apriori_intervalo(("transmission", "manual"), ("transmission", (29, 150)))

"""### Main Loop"""

while t.menu() != None:
    continue


import time
from rq import get_current_job
from app.app import create_app
from app.models import Task
from app.extensions import db
from flask import current_app
from cron import run
import sys
import traceback
import datetime

app = create_app()
app.app_context()

def launch_task(name, description, *args, **kwargs):
    rq_job = current_app.task_queue.enqueue('app.tasks.' + name,
                                            *args, **kwargs)
    task = Task(id=rq_job.get_id(), name=name, description=description)
    db.session.add(task)
    return task

def _set_task_progress(progress, status=None):
    job = get_current_job()
    if job:
        job.meta['progress'] = progress
        job.save_meta()
        task = Task.query.get(job.get_id())
        if status:
            task.status = status
        if progress >= 100:
            task.complete = True
            task.completed_at = db.func.current_timestamp()
        db.session.commit()

def full_sync():
    try:
        _set_task_progress(0, "job started")
        run()
    except Exception as e:
        _set_task_progress(100, f"The following error ocurred, check the logs for more information: {e}")
        traceback.format_exception(*sys.exc_info())
        raise
    _set_task_progress(100, "The sync completed successfully.")
    print('Task Completed')


from django.shortcuts import render
from .models import City
# Create your views here.

def get_html_content(city):
    import requests
    USER_AGENT = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.157 Safari/537.36"
    LANGUAGE = "en-US,en;q=0.5"
    session = requests.Session()
    session.headers['User-Agent'] = USER_AGENT
    session.headers['Accept-Language'] = LANGUAGE
    session.headers['Content-Language'] = LANGUAGE
    city = city.replace(" ", "+")
    html_content = session.get(f'https://www.google.co.uk/search?q=weather+in+{city}').text
    return html_content

def home(request):
    import requests
    import json
    from datetime import datetime, timedelta
    import calendar

    #time date
    tl=datetime.today()
    td=tl
    #default location delhi
    city='New Delhi'
    resp=requests.get('https://api.openweathermap.org/data/2.5/weather?q='+city+'&appid=a286d2cdc0d8a14c153ed08bf2339c1d')
    data= resp.json()
    diff=data['timezone']
    currt= td.hour*3600 + td.minute*60 + td.second+diff #-19800 commented
    dtlist=adjuster(currt,td)
    _hour=dtlist[1]
    _mint=dtlist[2]
    _date=dtlist[0]
    wekday = calendar.day_name[_date.weekday()]
    month=_date.strftime("%b")
    result={'region':data['name'],'winder':int(3.6*data['wind']['speed'] + 0.5),'temp_now':int(data['main']['temp'])-273,'weather_now':data['weather'][0]['description'],'cuntry':data['sys']['country'],'humid':data['main']['humidity'],'visible':data['visibility']/100,'rel':0,'hours':_hour,'minutes':_mint,'weekday':wekday,'mon':month,'day':_date.day}
    if 'city' in request.GET:
       city =request.GET.get('city')
       temp = saver(request)
       resp = requests.get('https://api.openweathermap.org/data/2.5/weather?q='+city+'&appid=a286d2cdc0d8a14c153ed08bf2339c1d')
       data = resp.json()

       if data['cod']=='404':
          city='New Delhi'
          resp=requests.get('https://api.openweathermap.org/data/2.5/weather?q='+city+'&appid=a286d2cdc0d8a14c153ed08bf2339c1d')
          data= resp.json()
          result={'region':data['name'],'winder':int(3.6*data['wind']['speed'] + 0.5),'temp_now':int(data['main']['temp'])-273,'weather_now':data['weather'][0]['description'],'cuntry':data['sys']['country'],'humid':data['main']['humidity'],'visible':data['visibility']/100,'rel':1,'hours':_hour,'minutes':_mint,'weekday':wekday,'mon':month,'day':_date.day}

       else:
           diff=data['timezone']
          # tarik=td
           currt= td.hour*3600 + td.minute*60 + td.second+diff #-19800 commented
           dtlist=adjuster(currt,td)
           _hour=dtlist[1]
           _mint=dtlist[2]
           _date=dtlist[0]
           wekday = calendar.day_name[_date.weekday()]
           month=_date.strftime("%b")
           result={'region':data['name'],'winder':int(3.6*data['wind']['speed'] + 0.5),'temp_now':int(data['main']['temp'])-273,'weather_now':data['weather'][0]['description'],'cuntry':data['sys']['country'],'humid':data['main']['humidity'],'visible':data['visibility']/100,'rel':0,'hours':_hour,'minutes':_mint,'weekday':wekday,'mon':month,'day':_date.day}

    if data['weather'][0]['main']=='Clouds':
        return render(request, 'core/cloudy.html', {'result': result})

    if (data['weather'][0]['main']=='Rain') or (data['weather'][0]['main']=='Drizzle'):
        result={'region':data['name'],'winder':int(3.6*data['wind']['speed'] + 0.5),'temp_now':int(data['main']['temp'])-273,'weather_now':data['weather'][0]['description'],'cuntry':data['sys']['country'],'humid':data['main']['humidity'],'visible':data['visibility']/100,'precip':data['rain']['1h'],'rel':0,'hours':_hour,'minutes':_mint,'weekday':wekday,'mon':month,'day':_date.day}
        return render(request, 'core/rainy.html', {'result': result})

    if data['weather'][0]['main']=='Clear':
        return render(request, 'core/sunny.html', {'result': result})

    if (data['weather'][0]['main']=='Haze') or (data['weather'][0]['main']=='Mist') or (data['weather'][0]['main']=='Fog'):
        return render(request, 'core/haze.html', {'result': result})

    if data['weather'][0]['main']=='Snow':
        result={'region':data['name'],'winder':int(3.6*data['wind']['speed'] + 0.5),'temp_now':int(data['main']['temp'])-273,'weather_now':data['weather'][0]['description'],'cuntry':data['sys']['country'],'humid':data['main']['humidity'],'visible':data['visibility']/100,'precip':data['snow']['1h'],'rel':0,'hours':_hour,'minutes':_mint,'weekday':wekday,'mon':month,'day':_date.day}
        return render(request, 'core/snowy.html', {'result': result})

    if (data['weather'][0]['main']=='Thunderstorm') or (data['weather'][0]['main']=='Squall') or (data['weather'][0]['main']=='Tornado'):
        return render(request, 'core/windy.html', {'result': result})

    if (data['weather'][0]['main']=='Dust') or (data['weather'][0]['main']=='Sand') or (data['weather'][0]['main']=='Ash') or (data['weather'][0]['main']=='Smoke'):
        return render(request, 'core/dusty.html', {'result': result})

    return render(request, 'core/sunny.html', {'result': result})

def saver(request):
    city=request.GET.get('city')
    town = City(name=city)
    town.save()
    return 10

def history(request):
    return render(request,'core/history.html',{'cities':City.objects.all()})

def adjuster(currt,tarik):
    from datetime import datetime, timedelta
    import calendar

    if(currt<0):
        tarik=tarik-timedelta(1)
        currt+=86400
        ghante=currt/3600
        ghante=int(ghante)
        currt=currt%3600
        mint=currt/60
        mint=int(mint)

    elif(currt>86400):
        tarik=tarik+timedelta(1)
        currt=currt-86400
        ghante=currt/3600
        ghante=int(ghante)
        currt=currt%3600
        mint= currt/60
        mint=int(mint)

    else:
        ghante=currt/3600
        ghante=int(ghante)
        currt=currt%3600
        mint=currt/60
        mint=int(mint)

    if ghante<10 :
        ghante='0'+str(ghante)

    if mint<10 :
        mint='0'+str(mint)
    datime = [tarik,ghante,mint]
    return(datime)


"""
Program:    Chap8Lab7-TidbitGUI.py
Author:     Brian Moye
Date:       July 16, 2020
Purpose:    This program displays a payment plan given an annual interest
            rate and a purchase price.
"""

from breezypythongui import EasyFrame

class TidbitGUI(EasyFrame):

    def __init__(self):
        #Set up window and widgets
        EasyFrame.__init__(self, title = "Tidbit Payment Schedule")

        #Add input fields
        self.addLabel(text = "Purchase Price:", row = 0, column = 0)
        self.priceField = self.addFloatField(value = 0.0, row = 0, column = 1)
        self.addLabel(text = "Annual Interest Rate:", row = 1, column = 0)
        self.rateField = self.addFloatField(value = 0.0, row = 1, column = 1)

        #Add command button
        self.button = self.addButton(text = "Compute", row = 2, column = 0,
                                        columnspan = 2,
                                        command = self.computeSchedule)

        #Add output textbox
        self.outputArea = self.addTextArea(text = "", row = 3, column = 0,
                                           columnspan = 2, width = 85,
                                           height = 20)

    def computeSchedule(self):
        #Event handler for Compute button
        purchasePrice = self.priceField.getNumber()
        monthlyPayment = 0.05 * purchasePrice
        annualRate = self.rateField.getNumber()
        monthlyRate = annualRate / 12
        month = 1
        balance = purchasePrice
        schedule = "Month  Starting Balance  Interest to Pay  "
        schedule += "Principal to Pay  Payment  Ending Balance\n"

        #Loop to calculate individual payments
        while balance > 0:
            if monthlyPayment > balance:
                monthlyPayment = balance
                interest = 0
            else:
                interest = balance * monthlyRate

            principal = monthlyPayment - interest
            remaining = balance - monthlyPayment
            schedule += "%2d%15.2f%17.2f%17.2f%17.2f%17.2f\n" % \
                        (month, balance, interest, principal,
                         monthlyPayment, remaining)
            balance = remaining
            month += 1
            self.outputArea.setText(schedule)

def main():
    TidbitGUI().mainloop()

if __name__ == "__main__":
    main()


import pika

connection = pika.BlockingConnection(pika.ConnectionParameters(host='localhost'))

ch = connection.channel()

ch.exchange_declare(exchange='direct_logs', exchange_type='direct')
result = ch.queue_declare(queue='', exclusive=True)
qname = result.method.queue

severity = 'ERROR'
ch.queue_bind(queue='', exchange='direct_logs', routing_key=severity)
print('waiting...')

def callback(ch, method, properties, body):
    with open('error_log.log', 'a') as f:
        f.write(f'str({body}) \n')
    ch.basic_ack(delivery_tag=method.delivery_tag)

ch.basic_consume(queue=qname, on_message_callback=callback)
ch.start_consuming()


'''
TP1 LRSO - Sockets / Threads

Matheus Teixeira Alves
Rafael de Paula Maia
'''

# SERVIDOR

import socket
from _thread import start_new_thread

poltronas_reservadas = []

def threaded(c):
    while True:

        # poltrona selecionada pelo cliente
        poltrona = c.recv(1024)

        if not poltrona:
            c.send("AMARELO Linhas -- Obrigado pela preferencia!".encode('ascii'))
            break

        # enviar resposta ao cliente
        if(poltrona not in poltronas_reservadas):
            poltronas_reservadas.append(poltrona)
            c.send("Poltrona reservada com sucesso!".encode('ascii'))
        else:
            c.send("Essa poltrona ja foi reservada. Selecione outra.".encode('ascii'))

    # conexao encerrada
    print("Encerrando Thread e Conexao com cliente.")
    c.close()

def Main():
    host = ""
    port = 12345

    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.bind((host, port))
    print("Socket criado na porta: ", port)

    s.listen(5)
    print("socket is listening")

    # loop ate o cliente sair
    while True:

        # establish connection with client
        c, addr = s.accept()

        print('Cliente conectado em: ', addr[0], ':', addr[1])

        # inicio de uma thread com novo cliente
        print("Criando uma thread com novo cliente...")
        start_new_thread(threaded, (c,))

    # encerramento do socket e programa
    s.close()

if __name__ == '__main__':
    Main()


# MIT License
#
# Copyright (c) [2020] [Antonio Domènech L., Daniela Tarzia]
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

from math import hypot
from Deteccion import *

########################################################################################################################
########################################################################################################################
##################################################### Ratio ############################################################

#La clase Ratio es para determinar los movimientos que hace la cara, los ojos y la boca.
class Ratio:

    #Crea el objeto detección
    def __init__(self):
        self.t = Deteccion()

    #Retorna el punto medio entre dos puntos
    def midpoint(self, point1, point2):
        mp = int((point1[0] + point2[0]) / 2), int((point1[1] + point2[1]) / 2)
        return(mp)

    #Retorna la distancia en valor absoluto entre dos puntos
    def distance(self, point1, point2):
        d = abs(hypot((point2[0] - point1[0]), (point2[1] - point1[1])))
        return(d)

    #Extrae puntos de interes a partir de una imagen
    def extraer_puntos(self, grayimage):
        # lista de puntos utiles
        points = [30,33,29,17,26,45,42,43,47,39,36,38,40,62,66,48,54,44,46,37,41]
        puntos = self.t.detect_landmarks(grayimage, points) #Obtenemos las coordenadas de cada punto

        #Puntos de la nariz
        self.nariz = puntos[0:2] #Punto 30
        self.nariz_inf = puntos[2:4] #Punto 33
        self.nariz_sup = puntos[4:6] #Punto 29
        self.nariz_derecha = puntos[6:8] #Punto 17
        self.nariz_izquierda = puntos[8:10] #Punto 26

        #Punto del ojo izquierdo
        self.ojo_izquierdo_izquierda = puntos[10:12] #Punto 45
        self.ojo_izquierdo_derecha = puntos[12:14] #Punto 42
        self.ojo_izquierdo_arriba1 = puntos[14:16] #Punto 43
        self.ojo_izquierdo_arriba2 = puntos[34:36] #Punto 44
        self.ojo_izquierdo_abajo1 = puntos[16:18] #Punto 47
        self.ojo_izquierdo_abajo2 = puntos[36:38] #Punto 46

        #Puntos del ojo derecho
        self.ojo_derecho_izquierda = puntos[18:20] #Punto 39
        self.ojo_derecho_derecha = puntos[20:22] #Punto 36
        self.ojo_derecho_arriba1 = puntos[22:24] #Punto 38
        self.ojo_derecho_arriba2 = puntos[38:40] #Punto 37
        self.ojo_derecho_abajo1 = puntos[24:26] #Punto 40
        self.ojo_derecho_abajo2 = puntos[40:] #Punto 41

        #Puntos de la boca
        self.labio_superior = puntos[26:28] #Punto 62
        self.labio_inferior = puntos[28:30] #Punto 66
        self.labio_derecha = puntos[30:32] #Punto 48
        self.labio_izquierda = puntos[32:34] #Punto 54

########################################################################################################################
################################################# Ratios ###############################################################
########################################################################################################################

    #Calcula un ratio que define la apertura de la boca
    def ratio_labios(self):
        # medimos la distancia entre puntos en horizontal y en vertical
        ver = Ratio.distance(self, self.labio_superior, self.labio_inferior)
        hor = Ratio.distance(self, self.labio_izquierda, self.labio_derecha)

        #Evitamos valores negativos para la distancia vertical
        if(ver < 0):
            ver = 0

        #Se dividen las distancias y obtenemos un ratio que nos indica la apertura de la boca
        ratio = (hor/ver)
        return(ratio)

    #Calcula el ratio horizontal de la cara
    def ratio_horizontal(self):
        #Medimos las distancias entre centro - derecha y centro - izquierda
        derecha = Ratio.distance(self, self.nariz, self.nariz_derecha)
        izquierda = Ratio.distance(self, self.nariz, self.nariz_izquierda)

        #Se dividen las distancias y obtenemos un ratio que nos indica el movimiento horizontal de la cara
        ratio = (derecha/izquierda)
        return(ratio)

    #Calcula el ratio vertical de la cara
    def ratio_vertical(self):
        #Medimos las distancias entre centro - arriba y centro - abajo
        arriba = Ratio.distance(self, self.nariz, self.nariz_sup)
        abajo = Ratio.distance(self, self.nariz, self.nariz_inf)

        #Se dividen las distancias y obtenemos un ratio que nos indica el movimiento vertical de la cara
        ratio = (arriba / abajo)
        return (ratio)

    #Calcula el ratio de apertura/cierre del ojo derecho
    def ratio_ojo_derecho(self):
        #Medimos la media entre los dos puntos superiores e inferiores del ojo
        centro_arriba = Ratio.midpoint(self, self.ojo_derecho_arriba1, self.ojo_derecho_arriba2)
        centro_abajo = Ratio.midpoint(self, self.ojo_derecho_abajo1, self.ojo_derecho_abajo2)

        #Medimos la distancia media superior - media inferior y derecha - izquierda
        horizontal = Ratio.distance(self, self.ojo_derecho_derecha, self.ojo_derecho_izquierda)
        vertical = Ratio.distance(self, centro_arriba, centro_abajo)

        #Se dividen las distancias y obtenemos un ratio que nos indica la apertura/cierre del ojo derecho
        ratio = (horizontal / vertical)
        return(ratio)

    #Calcula el ratio de apertura/cierre del ojo izquierdo
    def ratio_ojo_izquierdo(self):
        #Medimos la media entre los dos puntos superiores e inferiores del ojo
        centro_arriba = Ratio.midpoint(self, self.ojo_izquierdo_arriba1, self.ojo_izquierdo_arriba2)
        centro_abajo = Ratio.midpoint(self, self.ojo_izquierdo_abajo1, self.ojo_izquierdo_abajo2)

        #Medimos la distancia media superior - media inferior y derecha - izquierda
        horizontal = Ratio.distance(self, self.ojo_izquierdo_derecha, self.ojo_izquierdo_izquierda)
        vertical = Ratio.distance(self, centro_arriba, centro_abajo)

        #Se dividen las distancias y obtenemos un ratio que nos indica la apertura/cierre del ojo izquierdo
        ratio = (horizontal / vertical)
        return (ratio)

########################################################################################################################
############################################### Calibración ############################################################
########################################################################################################################

    #Calcula el valor exacto del ratio donde el ojo pasa de abierto a cerrado y viceversa
    def calibracion_ojo(self, lim_abierto, lim_cerrado):
        RatioOjo = (lim_cerrado + lim_abierto) / 2
        return(RatioOjo)

    #Calcula los valores del ratio que separan los estados de subir, bajar, o qudarse centrado
    def calibracion_cara_vertical(self, lim_up, lim_down, center):
        media_up = (lim_up + center) / 2
        media_down = (center + lim_down) / 2
        return(media_up, media_down)

    #Calcula los valores del ratio que separan los estados de derecha, izquierda o centro
    def calibracion_cara_horizontal(self, lim_right, lim_left, center):
        media_right = (center + lim_right) / 2
        media_left = (center + lim_left) / 2
        return (media_right, media_left)

##################################################### FIN ##############################################################
########################################################################################################################
########################################################################################################################

if __name__ == '__main__':
    import cv2
    from Deteccion import *
    capture = cv2.VideoCapture(0)

    _, frame = capture.read()  # obtenermos la captura
    grayimage = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)  # Escala de grises

    r = Ratio()
    r.extraer_puntos(grayimage)
    a = r.ratio_vertical()
    b = r.ratio_horizontal()
    c = r.ratio_ojo_derecho()
    e = r.ratio_ojo_izquierdo()

    print(a)
    print(b)
    print(c)
    print(e)


from slack_bolt import App
from slack_bolt.adapter.aws_lambda import SlackRequestHandler

app = App(process_before_response=True)

@app.message("hello")
def say_hello(message, say):
    user = message['user']
    say(f"Hello my friend, <@{user}>!")

def handler(event, context):
    slack_handler = SlackRequestHandler(app=app)
    return slack_handler.handle(event, context)


# practice for loop
# ask user name and count each character
# "Shubham Gupta"
# S : 1
# h : 2
# u : 2
# b : 1
# a : 2
# m : 1
#   : 1
# G : 1
# p : 1
# t : 1

name = input("enter your name : ")
temp = ""
for i in range(0, len(name)):
    if name[i] not in temp:
        print(f"{name[i]} : {name.count(name[i])}")
        temp += name[i]


class Solution:
    def isValid(self, A,N,M, mid):
        noOfStudent=1
        s=0
        for i in range(N):
            s=s+A[i]
            if s>mid:
                noOfStudent+=1
                s=A[i]
        if noOfStudent>M:
            return False
        return True
    #Function to find minimum number of pages.
    def findPages(self,A, N, M):
        #code here
        start=max(A)
        end=sum(A)
        res=-1
        if M>N:
            return -1
        while start<=end:
            mid=(start+end)//2
            if self.isValid(A, N, M, mid):
                res=mid
                end=mid-1
            else:
                start=mid+1
        return res


#importando as bibliotecas q iremos usar
import plotly.express as px
import pandas as pd
from dash import Dash, html, dcc

#iniciando um app
app = Dash(__name__)

#criando os dados que iremos usar como teste
df = pd.DataFrame({
    "Fruit":["Apples","Oragens","Bananas","Apples","Oragens","Bananas",],
    "Amount":[4,1,2,2,4,5],
    "City":["SF","SF","SF","Montreal","Montreal","Montreal"]
})

#criando o grafico que iremos usar os dados

fig = px.bar(df,x="Fruit",y="Amount",color="City",barmode="group",text_auto=True)

#adicionando os dados no app
app.layout = html.Div(children=[
    html.H1(children="Olá Dash"),

    html.Div(children='''Dash: A web de aplicações de dados para você, fiz uma alteração'''),

    dcc.Graph(
        id="Exemplo de grafico",
        figure=fig
    )
])

#finalizando o app

if __name__ == "__main__":
    app.run(debug=True)


"""A Demo script to take measurements from the SparkFun AS7262 Visible Spectral Sensor Breakout and display it on a
Pimoroni Unicorn HAT HD in a bar-graph like format.  Requires the AS7262_Pi.py file to be in the same directory.
Connect both the AS7262 and the Unicorn HAT HD to the Pi's GPIO header, I've found that a Pimoroni Pico HAT hacker works great for this."""

import unicornhathd
import time
import AS7262_Pi as spectro

"""Set up the spectrometer: reset it, set gain and integration time as per Sparkfun's default values in their Arduino script,
turn off the indicator LED (for some reason it sometimes comes on after resetting the spectrometer)."""
spectro.soft_reset()
spectro.set_gain(3)
spectro.set_integration_time(50)
spectro.disable_indicator_led()

#Set the brightness of the Unicorn HAT HD from 0.0 - 0.9, default 0.5
unicornhathd.brightness(0.5)

#Set the rotation of the Unicorn HAT HD in 90-degree increments
unicornhathd.rotation(0)

"""Create a dictionary called colours{}: each colour has an X value for the colour's starting column on the Unicorn HAT HD,
the X coordinate of the corresponding HAT column end, and a red, green and blue value in that order. """
colours = {"Red":[2,4,255,0,0], "Orange":[4,6,255,128,0], "Yellow":[6,8,192,192,0],
	"Green":[8,10,0,255,0], "Blue":[10,12,0,0,255], "Violet":[12,14,128,0,255]}

#Take a colour reading and display it as a bar on the Unicorn HAT HD
def updateColour(colour, value):
  #Print the colour name and value associated with it
	#print(str(colour) + " : " + str(value))
  #Get the X coordinate of the first bar for the colour
	xCoord1 = colours[colour][0]
  #Get the X coordinate of the second bar for the colour
	xCoord2 = colours[colour][1]
  #Get the R, G and B values for the colour
	r = colours[colour][2]
	g = colours[colour][3]
	b = colours[colour][4]

	#If the magnitude of a colour is >0, set that many pixels to that colour
  #Stop extreme values overrunning the size of the HAT
	if value > 16:
		value = 16
  #Set the two coloumns of the bar for the colour:
	for x in range(xCoord1, xCoord2):
    #Set the height of the bars
		for y in range (0,value):
			unicornhathd.set_pixel(x,y,r,g,b)
	#Blank unused pixels in those columns
	for x in range (xCoord1, xCoord2):
		for y in range (value, 16):
			unicornhathd.set_pixel(x,y,0,0,0)

print("Measuring rainbows!")

#Set to continuous ROYGBV measurements
spectro.set_measurement_mode(2)
#Enable the main LED
spectro.enable_main_led()
#Set the gain to x64
spectro.set_gain(3)
#Set the integration time to ~150 ms
spectro.set_integration_time(50)

try:
	while True:

    #Get the ROYGBV readings
		results = spectro.get_calibrated_values()

    #For each colour in results[], update the corresponding bar on the Unicorn HAT HD
		updateColour("Red", int(results[0]/3200))
		updateColour("Orange", int(results[1]/3200))
		updateColour("Yellow", int(results[2]/3200))
		updateColour("Green", int(results[3]/3200))
		updateColour("Blue", int(results[4]/3200))
		updateColour("Violet", int(results[5]/3200))

		#Display the new values on the Unicorn HAT HD
		unicornhathd.show()

#Clean Shutdown when stopped with Ctrl-C
except KeyboardInterrupt:
	unicornhathd.clear()
	unicornhathd.show()
	spectro.disable_main_led()
	spectro.set_measurement_mode(3)
	print("	Manually stopped.")


import pygame
import random
from tkinter import *
from tkinter import messagebox
from utils import *
from pygame import mixer

colors = [
    (0, 0, 0),
    (120, 37, 179),
    (100, 179, 179),
    (80, 34, 22),
    (80, 134, 22),
    (180, 34, 22),
    (180, 34, 122),
]

BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
GRAY = (128, 128, 128)

class Figure:
    figures = [
        [[1, 5, 9,13], [4, 5, 6, 7]],
        [[1, 2, 5, 9], [0, 4, 5, 6], [1, 5, 9, 8], [4, 5, 6,10]],
        [[1, 2, 6,10], [5, 6, 7, 9], [2, 6,10,11], [3, 5, 6, 7]],
        [[1, 4, 5, 6], [1, 4, 5, 9], [4, 5, 6, 9], [1, 5, 6, 9]],
        [[1, 2, 5, 6]],
    ]
    def __init__(self, x, y):
        self.x = x
        self.y = y
        self.type = random.randint(0, len(self.figures) - 1)
        self.color = random.randint(1, len(colors) - 1)
        self.rotation = 0

    def image(self):
        return self.figures[self.type][self.rotation]

    def rotate(self):
        self.rotation = (self.rotation + 1) % len(self.figures[self.type])

game_w = 10
game_h = 25

class Game:
    def __init__(self, x, y):
        self.x = x
        self.y = y
        self.block_size = 30
        self.state = "start"
        self.figure = None
        self.score = 0
        self.level = 1.25
        self.key_guess = -1
        self.field = [[0 for j in range(game_w)] for i in range(game_h)]

    def new_figure(self, x = 3, y = 0):
        self.figure = Figure(x, y)

    def intersects(self):
        intersection = False
        for i in range(4):
            for j in range(4):
                if i * 4 + j in self.figure.image():
                    if i + self.figure.y > game_h - 1 or \
                            j + self.figure.x > game_w - 1 or \
                            j + self.figure.x < 0 or \
                            self.field[i + self.figure.y][j + self.figure.x] > 0:
                        intersection = True
        return intersection

    def break_lines(self):
        lines = 0
        for i in range(1, game_h):
            zeros = 0
            for j in range(game_w):
                if self.field[i][j] == 0:
                    zeros += 1
            if zeros == 0:
                lines += 1
                for i1 in range(i, 1, -1):
                    for j in range(game_w):
                        self.field[i1][j] = self.field[i1 - 1][j]
        self.score += lines ** 2

    def go_space(self):
        while not self.intersects():
            self.figure.y += 1
        self.figure.y -= 1
        self.freeze()

    def go_down(self):
        self.figure.y += 1
        if self.intersects():
            self.figure.y -= 1
            self.freeze()

    def freeze(self):
        for i in range(4):
            for j in range(4):
                if i * 4 + j in self.figure.image():
                    self.field[i + self.figure.y][j + self.figure.x] = self.figure.color
        self.break_lines()
        self.new_figure()
        if self.intersects():
            self.state = "gameover"

    def go_side(self, dx):
        old_x = self.figure.x
        self.figure.x += dx
        if self.intersects():
            self.figure.x = old_x

    def rotate(self):
        old_rotation = self.figure.rotation
        self.figure.rotate()
        if self.intersects():
            self.figure.rotation = old_rotation

# Music part

song_names_path = 'link.csv'
val_data_path = 'val_data.csv'

val_data = pd.read_csv(val_data_path)
val_data.set_index('Index')
song_names = pd.read_csv(song_names_path)
song_names.set_index('Index')

p1 = Game(125, 50)
p2 = Game(675, 50)

counter = 0
fps = 60
zoom = 20
done = False
music_played = False

mixer.init()
mixer.music.set_volume(0.2)
pygame.init()
pygame.display.set_caption("Tetris")
clock = pygame.time.Clock()
screen = pygame.display.set_mode((1000, 600))
row, name, scale = get_song(val_data, song_names)

while not done:
    if p1.state == 'start' and p2.state == 'start':
        if p1.figure is None:
            p1.new_figure(3, 0)

        if p2.figure is None:
            p2.new_figure(3, 0)

        counter += 1
        if counter > 100000:
            counter = 0

        if counter % (fps // p1.level // 2) == 0:
            if p1.state == "start":
                p1.go_down()

            if p2.state == "start":
                p2.go_down()

        if not music_played:
            mixer.music.load("audio\\"+name)
            mixer.music.play()
            music_played = True

        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                done = True

            if event.type == pygame.KEYDOWN:
                # if event.key == pygame.K_w:
                #     p1.rotate()
                if event.key == pygame.K_s:
                    p1.go_space()
                if event.key == pygame.K_a:
                    p1.go_side(-1)
                if event.key == pygame.K_d:
                    p1.go_side(1)
                if event.key == pygame.K_e:
                    p1.key_guess = 1
                if event.key == pygame.K_q:
                    p1.key_guess = 0

                # if event.key == pygame.K_UP:
                #     p2.rotate()
                if event.key == pygame.K_k:
                    p2.go_space()
                if event.key == pygame.K_j:
                    p2.go_side(-1)
                if event.key == pygame.K_l:
                    p2.go_side(1)
                if event.key == pygame.K_u:
                    p2.key_guess = 1
                if event.key == pygame.K_o:
                    p2.key_guess = 0

                if p1.key_guess == scale:
                    p1.rotate()
                    row, name, scale = get_song(val_data, song_names)
                    p1.key_guess = -1
                    p2.key_guess = -1
                    music_played = False
                elif p2.key_guess == scale:
                    p2.rotate()
                    row, name, scale = get_song(val_data, song_names)
                    p1.key_guess = -1
                    p2.key_guess = -1
                    music_played = False

    screen.fill(WHITE)

    for i in range(game_h):
        for j in range(game_w):
            pygame.draw.rect(screen, GRAY, [p1.x + zoom * j, p1.y + zoom * i, zoom, zoom], 1)
            pygame.draw.rect(screen, GRAY, [p2.x + zoom * j, p2.y + zoom * i, zoom, zoom], 1)
            if p1.field[i][j] > 0:
                pygame.draw.rect(screen, colors[p1.field[i][j]],
                                [p1.x + zoom * j + 1, p1.y + zoom * i + 1, zoom - 2, zoom - 1])
            if p2.field[i][j] > 0:
                pygame.draw.rect(screen, colors[p2.field[i][j]],
                                [p2.x + zoom * j + 1, p2.y + zoom * i + 1, zoom - 2, zoom - 1])

    if p1.figure is not None:
        for i in range(4):
            for j in range(4):
                p = i * 4 + j
                if p in p1.figure.image():
                    pygame.draw.rect(screen, colors[p1.figure.color],
                                    [p1.x + zoom * (j + p1.figure.x) + 1,
                                    p1.y + zoom * (i + p1.figure.y) + 1,
                                    zoom - 2, zoom - 2])

    if p2.figure is not None:
        for i in range(4):
            for j in range(4):
                p = i * 4 + j
                if p in p2.figure.image():
                    pygame.draw.rect(screen, colors[p2.figure.color],
                                    [p2.x + zoom * (j + p2.figure.x) + 1,
                                    p2.y + zoom * (i + p2.figure.y) + 1,
                                    zoom - 2, zoom - 2])

    font = pygame.font.SysFont('Calibri', 25, True, False)
    font1 = pygame.font.SysFont('Calibri', 65, True, False)
    text = font.render("Score: " + str(p1.score), True, BLACK)
    text2 = font.render("Score: " + str(p2.score), True, BLACK)

    major_minor = font.render("Major" if scale == 1 else "Minor", True, BLACK)
    screen.blit(major_minor, [450, 500])
    screen.blit(text, [p1.x-100, p1.y-50])
    screen.blit(text2, [p2.x-100, p2.y-50])
    if p1.state == "gameover" or p2.state == "gameover":
        if p1.score == p2.score:
            text_winner = font1.render("Draw!", True, (180, 34, 22))
        else:
            if p1.score > p2.score:
                winner = "Player 1"
            else:
                winner = "Player 2"
            text_winner = font1.render(winner + " win!", True, (180, 34, 22))
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                quit()
        p1.state = "gameover"
        p2.state = "gameover"
        screen.blit(text_winner, [670, 200])
        pygame.display.flip()
        clock.tick(fps)
    pygame.display.flip()
    clock.tick(fps)


"""Collection of functions to compute model quantities.

This module is meant to collect functions computing quantities of interest to the model,
e.g. lcoe, maximum production for a given capacity, etc, especially where these
functions are used in different areas of the model.
"""
from typing import Callable, Optional, Sequence, Text, Tuple, Union, cast

import numpy as np
import xarray as xr

def supply(
    capacity: xr.DataArray,
    demand: xr.DataArray,
    technologies: Union[xr.Dataset, xr.DataArray],
    interpolation: Text = "linear",
    production_method: Optional[Callable] = None,
) -> xr.DataArray:
    """Production and emission for a given capacity servicing a given demand.

    Supply includes two components, end-uses outputs and environmental pollutants. The
    former consists of the demand that the current capacity is capable of servicing.
    Where there is excess capacity, then service is assigned to each asset a share of
    the maximum production (e.g. utilization across similar assets is the same in
    percentage). Then, environmental pollutants are computing as a function of
    commodity outputs.

    Arguments:
        capacity: number/quantity of assets that can service the demand
        demand: amount of each end-use required. The supply of each process will not
            exceed it's share of the demand.
        technologies: factors bindings the capacity of an asset with its production of
            commodities and environmental pollutants.

    Return:
        A data array where the commodity dimension only contains actual outputs (i.e. no
        input commodities).
    """
    from muse.commodities import CommodityUsage, check_usage, is_pollutant

    if production_method is None:
        production_method = maximum_production

    maxprod = production_method(technologies, capacity)
    size = np.array(maxprod.region).size
    # in presence of trade demand needs to map maxprod dst_region
    if (
        "region" in demand.dims
        and "region" in maxprod.coords
        and "dst_region" not in maxprod.dims
        and size == 1
    ):
        demand = demand.sel(region=maxprod.region)
        prodsum = set(demand.dims).difference(maxprod.dims)
        demsum = set(maxprod.dims).difference(demand.dims)
        expanded_demand = (demand * maxprod / maxprod.sum(demsum)).fillna(0)

    elif (
        "region" in demand.dims
        and "region" in maxprod.coords
        and "dst_region" not in maxprod.dims
        and size > 1
    ):
        prodsum = set(demand.dims).difference(maxprod.dims)
        demsum = set(maxprod.dims).difference(demand.dims)
        expanded_demand = (demand * maxprod / maxprod.sum(demsum)).fillna(0)

    elif (
        "region" in demand.dims
        and "region" in maxprod.coords
        and "dst_region" in maxprod.dims
    ):
        demand = demand.rename(region="dst_region")
        prodsum = {"timeslice"}
        demsum = {"asset"}
        expanded_demand = (demand * maxprod / maxprod.sum(demsum)).fillna(0)

    else:
        prodsum = set(demand.dims).difference(maxprod.dims)
        demsum = set(maxprod.dims).difference(demand.dims)
        expanded_demand = (demand * maxprod / maxprod.sum(demsum)).fillna(0)

    expanded_maxprod = (maxprod * demand / demand.sum(prodsum)).fillna(0)

    expanded_demand = expanded_demand.reindex_like(maxprod)

    result = expanded_demand.where(
        expanded_demand <= expanded_maxprod, expanded_maxprod
    )

    # add production of environmental pollutants
    env = is_pollutant(technologies.comm_usage)
    result[{"commodity": env}] = emission(result, technologies.fixed_outputs).transpose(
        *result.dims
    )
    result[
        {"commodity": ~check_usage(technologies.comm_usage, CommodityUsage.PRODUCT)}
    ] = 0

    return result

def emission(production: xr.DataArray, fixed_outputs: xr.DataArray):
    """Computes emission from current products.

    Emissions are computed as `sum(product) * fixed_outputs`.

    Arguments:
        production: Produced goods. Only those with non-environmental products are used
            when computing emissions.
        fixed_outputs: factor relating total production to emissions. For convenience,
            this can also be a `technologies` dataset containing `fixed_output`.

    Return:
        A data array containing emissions (and only emissions).
    """
    from muse.commodities import is_enduse, is_pollutant
    from muse.utilities import broadcast_techs

    # just in case we are passed a technologies dataset, like in other functions
    fouts = broadcast_techs(
        getattr(fixed_outputs, "fixed_outputs", fixed_outputs), production
    )
    envs = is_pollutant(fouts.comm_usage)
    enduses = is_enduse(fouts.comm_usage)
    return production.sel(commodity=enduses).sum("commodity") * fouts.sel(
        commodity=envs
    )

def gross_margin(
    technologies: xr.Dataset, capacity: xr.DataArray, prices: xr.Dataset
) -> xr.DataArray:
    """profit of increasing the production by one unit.

    - energy commodities INPUTS are related to fuel costs
    - environmental commodities OUTPUTS are related to environmental costs
    - variable costs is given as technodata inputs
    - non-environmental commodities OUTPUTS are related to revenues
    """
    from muse.commodities import is_enduse, is_pollutant
    from muse.timeslices import QuantityType, convert_timeslice
    from muse.utilities import broadcast_techs

    tech = broadcast_techs(  # type: ignore
        cast(
            xr.Dataset,
            technologies[
                [
                    "technical_life",
                    "interest_rate",
                    "var_par",
                    "var_exp",
                    "fixed_outputs",
                    "fixed_inputs",
                ]
            ],
        ),
        capacity,
    )

    var_par = tech.var_par
    var_exp = tech.var_exp
    fixed_outputs = tech.fixed_outputs
    fixed_inputs = tech.fixed_inputs

    # Hours ratio
    variable_costs = convert_timeslice(
        var_par * capacity**var_exp, prices.timeslice, QuantityType.EXTENSIVE
    )

    prices = prices.sel(region=capacity.region).interp(year=capacity.year)

    # Filters
    environmentals = is_pollutant(technologies.comm_usage)
    enduses = is_enduse(technologies.comm_usage)

    # The individual prices
    consumption_costs = (prices * fixed_inputs).sum("commodity")
    production_costs = prices * fixed_outputs
    environmental_costs = (production_costs.sel(commodity=environmentals)).sum(
        ("commodity")
    )

    revenues = (production_costs.sel(commodity=enduses)).sum("commodity")

    result = revenues - environmental_costs - variable_costs - consumption_costs
    return result

def decommissioning_demand(
    technologies: xr.Dataset,
    capacity: xr.DataArray,
    year: Optional[Sequence[int]] = None,
) -> xr.DataArray:
    r"""Computes demand from process decommissioning.

    If `year` is not given, it defaults to all years in capacity. If there are more than
    two years, then decommissioning is with respect to first (or minimum) year.

    Let :math:`M_t^r(y)` be the retrofit demand, :math:`^{(s)}\mathcal{D}_t^r(y)` be the
    decommissioning demand at the level of the sector, and :math:`A^r_{t, \iota}(y)` be
    the assets owned by the agent. Then, the decommissioning demand for agent :math:`i`
    is :

    .. math::

        \mathcal{D}^{r, i}_{t, c}(y) =
            \sum_\iota \alpha_{t, \iota}^r \beta_{t, \iota, c}^r
                \left(A^{i, r}_{t, \iota}(y) - A^{i, r}_{t, \iota, c}(y + 1) \right)

    given the utilization factor :math:`\alpha_{t, \iota}` and the fixed output factor
    :math:`\beta_{t, \iota, c}`.

    Furthermore, decommissioning demand is non-zero only for end-use commodities.

    ncsearch-nohlsearch).. SeeAlso:
        :ref:`indices`, :ref:`quantities`,
        :py:func:`~muse.quantities.maximum_production`
        :py:func:`~muse.commodities.is_enduse`
    """
    if year is None:
        year = capacity.year.values
    year = sorted(year)
    capacity = capacity.interp(year=year, kwargs={"fill_value": 0.0})
    baseyear = min(year)
    dyears = [u for u in year if u != baseyear]

    return maximum_production(
        technologies, capacity.sel(year=baseyear) - capacity.sel(year=dyears)
    ).clip(min=0)

def consumption(
    technologies: xr.Dataset,
    production: xr.DataArray,
    prices: Optional[xr.DataArray] = None,
    **kwargs,
) -> xr.DataArray:
    """Commodity consumption when fulfilling the whole production.

    Currently, the consumption is implemented for commodity_max == +infinity. If prices
    are not given, then flexible consumption is *not* considered.
    """
    from muse.commodities import is_enduse, is_fuel
    from muse.timeslices import QuantityType, convert_timeslice
    from muse.utilities import filter_with_template

    params = filter_with_template(
        technologies[["fixed_inputs", "flexible_inputs"]], production, **kwargs
    )

    # sum over end-use products, if the dimension exists in the input

    comm_usage = technologies.comm_usage.sel(commodity=production.commodity)

    production = production.sel(commodity=is_enduse(comm_usage)).sum("commodity")

    if prices is not None and "timeslice" in prices.dims:
        production = convert_timeslice(  # type: ignore
            production, prices, QuantityType.EXTENSIVE
        )

    params_fuels = is_fuel(params.comm_usage)
    consumption = production * params.fixed_inputs.where(params_fuels, 0)

    if prices is None:
        return consumption

    if not (params.flexible_inputs.sel(commodity=params_fuels) > 0).any():
        return consumption

    prices = filter_with_template(prices, production, installed_as_year=False, **kwargs)
    # technology with flexible inputs
    flexs = params.flexible_inputs.where(params_fuels, 0)
    # cheapest fuel for each flexible technology
    assert prices is not None
    flexprice = [i for i in flexs.commodity.values if i in prices.commodity.values]
    assert all(flexprice)
    priceflex = prices.loc[dict(commodity=flexs.commodity)]
    minprices = flexs.commodity[
        priceflex.where(flexs > 0, priceflex.max() + 1).argmin("commodity")
    ]
    # add consumption from cheapest fuel
    assert all(flexs.commodity.values == consumption.commodity.values)
    flex = flexs.where(minprices == flexs.commodity, 0)
    flex = flex / (flex > 0).sum("commodity").clip(min=1)
    return consumption + flex * production

def annual_levelized_cost_of_energy(
    prices: xr.DataArray,
    technologies: xr.Dataset,
    interpolation: Text = "linear",
    fill_value: Union[int, Text] = "extrapolate",
    **filters,
) -> xr.DataArray:
    """Undiscounted levelized cost of energy (LCOE) of technologies on each given year.

    It mostly follows the `simplified LCOE`_ given by NREL. In the argument description,
    we use the following:

    * [h]: hour
    * [y]: year
    * [$]: unit of currency
    * [E]: unit of energy
    * [1]: dimensionless

    Arguments:
        prices: [$/(Eh)] the price of all commodities, including consumables and fuels.
            This dataarray contains at least timeslice and commodity dimensions.

        technologies: Describe the technologies, with at least the following parameters:

            * cap_par: [$/E] overnight capital cost
            * interest_rate: [1]
            * fix_par: [$/(Eh)] fixed costs of operation and maintenance costs
            * var_par: [$/(Eh)] variable costs of operation and maintenance costs
            * fixed_inputs: [1] == [(Eh)/(Eh)] ratio indicating the amount of commodity
                consumed per units of energy created.
            * fixed_outputs: [1] == [(Eh)/(Eh)] ration indicating the amount of
                environmental pollutants produced per units of energy created.

        interpolation: interpolation method.
        fill_value: Fill value for values outside the extrapolation range.
        **filters: Anything by which prices can be filtered.

    Return:
        The lifetime LCOE in [$/(Eh)] for each technology at each timeslice.

    .. _simplified LCOE: https://www.nrel.gov/analysis/tech-lcoe-documentation.html
    """
    from muse.commodities import is_pollutant
    from muse.timeslices import QuantityType, convert_timeslice

    techs = technologies[
        [
            "technical_life",
            "interest_rate",
            "cap_par",
            "var_par",
            "fix_par",
            "fixed_inputs",
            "flexible_inputs",
            "fixed_outputs",
            "utilization_factor",
        ]
    ]
    if "year" in techs.dims:
        techs = techs.interp(
            year=prices.year, method=interpolation, kwargs={"fill_value": fill_value}
        )
    if filters is not None:
        prices = prices.sel({k: v for k, v in filters.items() if k in prices.dims})
        techs = techs.sel({k: v for k, v in filters.items() if k in techs.dims})

    assert {"timeslice", "commodity"}.issubset(prices.dims)

    life = techs.technical_life.astype(int)

    annualized_capital_costs = (
        convert_timeslice(
            techs.cap_par
            * techs.interest_rate
            / (1 - (1 + techs.interest_rate) ** (-life)),
            prices.timeslice,
            QuantityType.EXTENSIVE,
        )
        / techs.utilization_factor
    )

    o_and_e_costs = (
        convert_timeslice(
            (techs.fix_par + techs.var_par),
            prices.timeslice,
            QuantityType.EXTENSIVE,
        )
        / techs.utilization_factor
    )

    fuel_costs = (techs.fixed_inputs * prices).sum("commodity")

    fuel_costs += (techs.flexible_inputs * prices).sum("commodity")
    if "region" in techs.dims:
        env_costs = (
            (techs.fixed_outputs * prices)
            .sel(region=techs.region)
            .sel(commodity=is_pollutant(techs.comm_usage))
            .sum("commodity")
        )
    else:
        env_costs = (
            (techs.fixed_outputs * prices)
            .sel(commodity=is_pollutant(techs.comm_usage))
            .sum("commodity")
        )
    return annualized_capital_costs + o_and_e_costs + env_costs + fuel_costs

def maximum_production(technologies: xr.Dataset, capacity: xr.DataArray, **filters):
    r"""Production for a given capacity.

    Given a capacity :math:`\mathcal{A}_{t, \iota}^r`, the utilization factor
    :math:`\alpha^r_{t, \iota}` and the the fixed outputs of each technology
    :math:`\beta^r_{t, \iota, c}`, then the result production is:

    .. math::

        P_{t, \iota}^r =
            \alpha^r_{t, \iota}\beta^r_{t, \iota, c}\mathcal{A}_{t, \iota}^r

    The dimensions above are only indicative. The function should work with many
    different input values, e.g. with capacities expanded over time-slices :math:`t` or
    agents :math:`i`.

    Arguments:
        capacity: Capacity of each technology of interest. In practice, the capacity can
            refer to asset capacity, the max capacity, or the capacity-in-use.
        technologies: xr.Dataset describing the features of the technologies of
            interests.  It should contain `fixed_outputs` and `utilization_factor`. It's
            shape is matched to `capacity` using `muse.utilities.broadcast_techs`.
        filters: keyword arguments are used to filter down the capacity and
            technologies. Filters not relevant to the quantities of interest, i.e.
            filters that are not a dimension of `capacity` or `techologies`, are
            silently ignored.
    Return:
        `capacity * fixed_outputs * utilization_factor`, whittled down according to the
        filters and the set of technologies in `capacity`.
    """
    from muse.commodities import is_enduse
    from muse.utilities import broadcast_techs, filter_input

    capa = filter_input(
        capacity, **{k: v for k, v in filters.items() if k in capacity.dims}
    )
    btechs = broadcast_techs(  # type: ignore
        cast(xr.Dataset, technologies[["fixed_outputs", "utilization_factor"]]), capa
    )
    ftechs = filter_input(
        btechs, **{k: v for k, v in filters.items() if k in btechs.dims}
    )
    result = capa * ftechs.fixed_outputs * ftechs.utilization_factor
    return result.where(is_enduse(result.comm_usage), 0)

def demand_matched_production(
    demand: xr.DataArray,
    prices: xr.DataArray,
    capacity: xr.DataArray,
    technologies: xr.Dataset,
    **filters,
) -> xr.DataArray:
    """Production matching the input demand.

    Arguments:
        demand: demand to match.
        prices: price from which to compute the annual levelized cost of energy.
        capacity: capacity from which to obtain the maximum production constraints.
        **filters: keyword arguments with which to filter the input datasets and
            data arrays., e.g. region, or year.
    """
    from muse.demand_matching import demand_matching
    from muse.timeslices import QuantityType, convert_timeslice
    from muse.utilities import broadcast_techs

    technodata = cast(xr.Dataset, broadcast_techs(technologies, capacity))
    cost = annual_levelized_cost_of_energy(prices, technodata, **filters)
    max_production = maximum_production(technodata, capacity, **filters)
    assert ("timeslice" in demand.dims) == ("timeslice" in cost.dims)
    if "timeslice" in demand.dims and "timeslice" not in max_production.dims:
        max_production = convert_timeslice(
            max_production, demand.timeslice, QuantityType.EXTENSIVE
        )
    return demand_matching(demand, cost, max_production)

def capacity_in_use(
    production: xr.DataArray,
    technologies: xr.Dataset,
    max_dim: Optional[Union[Text, Tuple[Text]]] = "commodity",
    **filters,
):
    """Capacity-in-use for each asset, given production.

    Conceptually, this operation is the inverse of `production`.

    Arguments:
        production: Production from each technology of interest.
        technologies: xr.Dataset describing the features of the technologies of
            interests.  It should contain `fixed_outputs` and `utilization_factor`. It's
            shape is matched to `capacity` using `muse.utilities.broadcast_techs`.
        max_dim: reduces the given dimensions using `max`. Defaults to "commodity". If
            None, then no reduction is performed.
        filters: keyword arguments are used to filter down the capacity and
            technologies. Filters not relevant to the quantities of interest, i.e.
            filters that are not a dimension of `capacity` or `techologies`, are
            silently ignored.
    Return:
        Capacity-in-use for each technology, whittled down by the filters.
    """
    from muse.commodities import is_enduse
    from muse.utilities import broadcast_techs, filter_input

    prod = filter_input(
        production, **{k: v for k, v in filters.items() if k in production.dims}
    )

    techs = technologies[["fixed_outputs", "utilization_factor"]]
    assert isinstance(techs, xr.Dataset)
    btechs = broadcast_techs(techs, prod)
    ftechs = filter_input(
        btechs, **{k: v for k, v in filters.items() if k in technologies.dims}
    )

    factor = 1 / (ftechs.fixed_outputs * ftechs.utilization_factor)
    capa_in_use = (prod * factor).where(~np.isinf(factor), 0)

    capa_in_use = capa_in_use.where(
        is_enduse(technologies.comm_usage.sel(commodity=capa_in_use.commodity)), 0
    )
    if max_dim:
        capa_in_use = capa_in_use.max(max_dim)

    return capa_in_use

def supply_cost(
    production: xr.DataArray, lcoe: xr.DataArray, asset_dim: Optional[Text] = "asset"
) -> xr.DataArray:
    """Supply cost given production and the levelized cost of energy.

    In practice, the supply cost is the weighted average LCOE over assets (`asset_dim`),
    where the weights are the production.

    Arguments:
        production: Amount of goods produced. In practice, production can be obtained
            from the capacity for each asset via the method
            `muse.quantities.production`.
        lcoe: Levelized cost of energy for each good produced. In practice, it can be
            obtained from market prices via
            `muse.quantities.annual_levelized_cost_of_energy` or
            `muse.quantities.lifetime_levelized_cost_of_energy`.
        asset_dim: Name of the dimension(s) holding assets, processes or technologies.
    """
    data = xr.Dataset(dict(production=production, prices=production * lcoe))
    if asset_dim is not None:
        if "region" not in data.coords or len(data.region.dims) == 0:
            data = data.sum(asset_dim)

        else:
            data = data.groupby("region").sum(asset_dim)

    total = data.production.where(np.abs(data.production) > 1e-15, np.infty).sum(
        "timeslice"
    )
    return data.prices / total

def costed_production(
    demand: xr.Dataset,
    costs: xr.DataArray,
    capacity: xr.DataArray,
    technologies: xr.Dataset,
    with_minimum_service: bool = True,
) -> xr.DataArray:
    """Computes production from ranked assets.
    The assets are ranked according to their cost. The asset with least cost are allowed
    to service the demand first, up to the maximum production. By default, the mininum
    service is applied first.
    """

    from muse.quantities import maximum_production
    from muse.timeslices import QuantityType, convert_timeslice
    from muse.utilities import broadcast_techs

    technodata = cast(xr.Dataset, broadcast_techs(technologies, capacity))

    if len(capacity.region.dims) == 0:

        def group_assets(x: xr.DataArray) -> xr.DataArray:
            return x.sum("asset")

    else:

        def group_assets(x: xr.DataArray) -> xr.DataArray:
            return xr.Dataset(dict(x=x)).groupby("region").sum("asset").x

    ranking = costs.rank("asset")
    maxprod = convert_timeslice(
        maximum_production(technodata, capacity),
        demand.timeslice,
        QuantityType.EXTENSIVE,
    )
    commodity = (maxprod > 0).any([i for i in maxprod.dims if i != "commodity"])
    commodity = commodity.drop_vars(
        [u for u in commodity.coords if u not in commodity.dims]
    )
    demand = demand.sel(commodity=commodity).copy()

    constraints = (
        xr.Dataset(dict(maxprod=maxprod, ranking=ranking, has_output=maxprod > 0))
        .set_coords("ranking")
        .set_coords("has_output")
        .sel(commodity=commodity)
    )

    if not with_minimum_service:
        production = xr.zeros_like(constraints.maxprod)
    else:
        production = (
            getattr(technodata, "minimum_service_factor", 0) * constraints.maxprod
        )
        demand = np.maximum(demand - group_assets(production), 0)

    for rank in sorted(set(constraints.ranking.values.flatten())):
        condition = (constraints.ranking == rank) & constraints.has_output
        current_maxprod = constraints.maxprod.where(condition, 0)
        fullprod = group_assets(current_maxprod)
        if (fullprod <= demand + 1e-10).all():
            current_demand = fullprod
            current_prod = current_maxprod
        else:
            if "region" in demand.dims:
                demand_prod = demand.sel(region=production.region)
            else:
                demand_prod = demand
            demand_prod = (
                current_maxprod / current_maxprod.sum("asset") * demand_prod
            ).where(condition, 0)
            current_prod = np.minimum(demand_prod, current_maxprod)
            current_demand = group_assets(current_prod)
        demand -= np.minimum(current_demand, demand)
        production = production + current_prod

    result = xr.zeros_like(maxprod)
    result[dict(commodity=commodity)] = result[dict(commodity=commodity)] + production
    return result


# program reads individual files created by get_data_from_bloomberg.py and aggregates them
# compiled dataframe is stored in this csv
dataframe_csv_filename ="./data/compiled_dataframe.csv"
CREATE_NEW_CSV = True
# Write here the list of files to aggregate - to work, each file must first be individually processed by get_data_from_bloomberg.py
copypaste_files_list  = [
    "./data/copypastePaloAlto.xlsx",
    "./data/copypasteDAFNA",
    "./data/copypasteBakerBros",
    # "copypasteBVF.xlsx",
    # "copypastePerceptiveNew",
    # "copypasteRA",
    # "copypasteRTW",
    # "copypasteRedmile",
    # "copypasteEcoR1",
    # "copypasteOrbimed",
    # "copypasteAvoro",
    # "copypasteCormorant",
    # "copypasteBoxer",
    #
    ]

import openpyxl as xl  # openpyxl is an excel manipulation library
import pandas as pd
import numpy as np
import utils
import pickle
import os

if CREATE_NEW_CSV:
    try:
        os.remove(dataframe_csv_filename)
    except:
        pass

try:
    df = pd.read_csv(dataframe_csv_filename) #try reading an existing csv
except:
    df = pd.DataFrame(columns = ['Fund Name', 'Name', 'Date', 'Ticker', 'Market Cap', 'Market Val Wgt', 'Market Val',
                       'Position', 'PX Close', 'PX Last', 'Prev Date', 'PX Last Prev Date', 'PX Ratio', 'Next Date',
                       'PX Last Next Date', 'PX Ratio Next']) #...if it doesn't exist, create the dataframe df

# run through various raw and pickle files one at a time
for copypaste_file in copypaste_files_list:

    print(f"Processing {copypaste_file}")
    read_from_file = "./data/"+ copypaste_file.split('.')[1].split('/')[-1] + "_raw.xlsx"
    get_ranges_from_file =  "./data/"+ copypaste_file.split('.')[1].split('/')[-1]  + "_ranges.pickle"

    ranges = pickle.load(open(get_ranges_from_file,'rb'))

    # open an existing xlsx
    wb_in = xl.load_workbook(filename = read_from_file, read_only = True)
    wb_in_data = wb_in['Data']

    for idx,r in enumerate(ranges):
        int_start = r['report_row_start']
        int_stop = r['report_row_stop']
        print('New Range')

        df1 = utils.load_workbook_range(f'A{int_start}:P{int_stop}', wb_in_data)
        df1.columns = ['Name', 'tobedeleted', 'Date', 'Ticker', 'Market Cap', 'Market Val Wgt', 'Market Val',
                       'Position', 'PX Close', 'PX Last', 'Prev Date', 'PX Last Prev Date', 'PX Ratio', 'Next Date',
                       'PX Last Next Date', 'PX Ratio Next'] #define a preliminary dataframe, using existing columns
        df1 = df1.drop(columns=['tobedeleted'])

        df_fundname = utils.load_workbook_range(f'A{int_start-1}:A{int_start-1}', wb_in_data)    #for each raw copypaste file, the fundname is (-1,-1) relative to the data
        fundname = df_fundname['A'].values[0]   #

        df1['Fund Name'] = fundname #append 'Fund Name' to the preliminary df1

        df = df.append(df1) #add this column to the processed dataframe df, that we are going to use-- this will automatically add the data to the already existing 'Fund Name' column in df

    wb_in.close()

df.to_csv(dataframe_csv_filename, index = False)


import numpy as np
from catboost import CatBoostRegressor

from pyepal.pal.pal_catboost import PALCatBoost

def test_pal_catboost(binh_korn_points):
    models = [
        CatBoostRegressor(
            iterations=5000,
            learning_rate=0.05,
            loss_function="RMSEWithUncertainty",
            posterior_sampling=True,
            silent=True,
        )
        for _ in range(2)
    ]

    X_binh_korn, y_binh_korn = binh_korn_points  # pylint:disable=invalid-name

    sample_idx = np.array([0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80, 90, 95, 99])

    pal = PALCatBoost(
        X_binh_korn, models, 2, beta_scale=1 / 15, epsilon=0.05, coef_var_threshold=100
    )

    pal.cross_val_points = 0

    pal.update_train_set(sample_idx, y_binh_korn[sample_idx])
    _ = pal.run_one_step()
    assert pal.number_discarded_points == 0
    assert pal.number_unclassified_points < 100


import json
import os

import torch
import torch.nn.functional as F
from torch.utils import data

import urllib
import zipfile

PAD = ''
UNK = '<UNK>'
NO_SENSE = 'no_sense'

class Vocab:

    def __init__(self):
        self.padding_idx = 0
        self.unk_idx = 1
        self.running_id = 2
        self.index = {PAD: 0, UNK: 1}
        self.inverted_index = self.__invert_index()

    def __invert_index(self):
        return {v: k for k, v in self.index.items()}

    def size(self):
        return self.running_id

    def encode(self, string, generate_id=True):
        """
        Get or generate and index the integer id for the given string.

        :param string: string to get / generate integer id for
        :param generate_id: Whether to generate an id if string is not already indexed
        :return:
        """
        idx = self.index.get(string, self.unk_idx)
        if idx is self.unk_idx:
            if generate_id:
                idx = self.running_id
                self.index[string] = idx
                self.running_id += 1
        return idx

    def encode_list(self, strings, generate_id=True):
        return [self.encode(s, generate_id=generate_id) for s in strings]

    def decode(self, id):
        """
        :param id: integer id
        :return: string representation of given id
        """
        if len(self.inverted_index) != len(self.index):
            self.inverted_index = self.__invert_index()

        return self.inverted_index[id]

    def decode_list(self, ids):
        return [self.decode(i) for i in ids]

def load_train_dataset(sentence_count=None):
    """
    Downloads (if necessary) the datasets, vocabularizes and loads the training set.
    :param sentence_count: load only the first # senetnces
    :return:
        dataset: The training set; an instance of WSDDataset
        tokens_vocab: tokens vocabulary
        y_vocab: senses vocabulary
    """
    return __load('train', sentence_count=sentence_count)

def load_dev_dataset(tokens_vocab, y_vocab, sentence_count=None):
    """
    Loads the dev set using the given vocabularies for encoding. Unknown tokens will be encoded with UNK.
    :param tokens_vocab: Tokens vocabulary obtained form training set
    :param y_vocab: Senses vocabulary obtained form training set
    :param sentence_count: load only the first # senetnces
    :return:
        dataset: The dev set; an instance of WSDDataset
    """
    return __load('dev', tokens_vocab=tokens_vocab, y_vocab=y_vocab, sentence_count=sentence_count)[0]

def load_test_dataset(tokens_vocab, y_vocab, sentence_count=None):
    """
    Loads the test set using the given vocabularies for encoding. Unknown tokens will be encoded with UNK.
    :param tokens_vocab: Tokens vocabulary obtained form training set
    :param y_vocab: Senses vocabulary obtained form training set
    :param sentence_count: load only the first # senetnces
    :return:
        dataset: The test set; an instance of WSDDataset
    """
    return __load('test', tokens_vocab=tokens_vocab, y_vocab=y_vocab, sentence_count=sentence_count)[0]

def __load(dataset_type, tokens_vocab=None, y_vocab=None, sentence_count=None):
    """
    Downloads (if necessary) the datasets, vocabularizes and loads the requested types.
    :param dataset_type: one of ['train', 'dev', 'test']
    :param sentence_count: load only the first # senetnces
    :return:
        dataset: The requested dataset; an instance of WSDDataset
        tokens_vocab: tokens vocabulary
        y_vocab: senses vocabulary
    """
    gen_vocab_ids = None
    if y_vocab is None and tokens_vocab is None:
        gen_vocab_ids = True
        y_vocab = Vocab()
        tokens_vocab = Vocab()
    elif y_vocab is not None and tokens_vocab is not None:
        gen_vocab_ids = False
    else:
        raise ValueError("Vocabularies must either be both provided or both not")

    sentences_file = f'./data/sentences.{dataset_type}.jsonl'
    senses_file = f'./data/senses.{dataset_type}.jsonl'

    if not os.path.exists(sentences_file):
        print("Downloading tau_amnlp_semcor_dataset.zip...")
        urllib.request.urlretrieve(
            'https://docs.google.com/uc?export=download&id=1mxPS3neImDAq7BeTTQZRT4afpPU7gOge',
            "tau_amnlp_semcor_dataset.zip")
        with zipfile.ZipFile('tau_amnlp_semcor_dataset.zip', 'r') as zip_ref:
            zip_ref.extractall('./data')
        print('Dataset was downloaded successfully and extracted to ./data')

    raw_dataset = __load_from_files(sentences_file, senses_file, tokens_vocab, y_vocab,
                                    sentence_count=sentence_count, gen_vocab_ids=gen_vocab_ids)

    wsd_dataset = WSDDataset(raw_dataset, tokens_vocab, y_vocab)

    return wsd_dataset, tokens_vocab, y_vocab

def __load_from_files(sentences_file, senses_file, tokens_vocab, y_vocab,
                      sentence_count=None, gen_vocab_ids=True):
    raw_dataset = {
        'int_sentences': [],
        'str_sentences': [],
        'int_labels': [],
        'str_labels': []
    }

    with open(sentences_file, 'r') as data:
        for i, line in enumerate(data):
            if sentence_count is not None and i >= sentence_count:
                break
            tokenized_sentence = json.loads(line)
            raw_dataset['str_sentences'].append(tokenized_sentence)

    with open(senses_file, 'r') as data:
        for i, line in enumerate(data):
            if sentence_count is not None and i >= sentence_count:
                break
            labels = json.loads(line)
            raw_dataset['str_labels'].append(labels)

    for i, lbls in enumerate(raw_dataset['str_labels']):
        str_sentence = raw_dataset['str_sentences'][i]
        int_labels = y_vocab.encode_list(lbls, generate_id=gen_vocab_ids)
        raw_dataset['int_labels'].append(int_labels)
        int_sentence = tokens_vocab.encode_list(str_sentence, generate_id=gen_vocab_ids)
        raw_dataset['int_sentences'].append(int_sentence)

    return raw_dataset

class WSDDataset(data.Dataset):
    """
    An implementation of torch dataset in which a sample is single annotated query word.
    """

    def __init__(self, raw_dataset, tokens_vocab, y_vocab, include_no_sense=False):
        """
        :param raw_dataset: the dataset obtained from dictionary entry of the load finction
        :param tokens_vocab:
        :param y_vocab:
        :param include_no_sense: whether to consider NO_SENSE labeled words as legitimate samples
        """
        self.raw_dataset = raw_dataset
        self.tokens_vocab = tokens_vocab
        self.y_vocab = y_vocab
        self.include_no_sense = include_no_sense
        self.sample_type = 'word'

        # N holds max sentence length
        self.N = max(map(len, raw_dataset['int_sentences']))

        int_labels = raw_dataset['int_labels']
        str_labels = raw_dataset['str_labels']
        no_sense_count = 0
        idx_tuples = []
        for s_idx, s in enumerate(raw_dataset['int_sentences']):
            for q in range(len(s)):
                is_no_sense = str_labels[s_idx][q] == NO_SENSE
                if include_no_sense or not is_no_sense:
                    idx_tuples.append((s_idx, q, int_labels[s_idx][q]))
                    if is_no_sense:
                        no_sense_count += 1

        self.idx_tuples = idx_tuples
        self.no_sense_count = no_sense_count

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

    def __getitem__(self, index):
        sent_idx, q, lbl = self.idx_tuples[index]
        sentence = self.raw_dataset['int_sentences'][sent_idx]

        pad = self.N - len(sentence)
        sentence_tensor = torch.tensor(sentence)
        sentence_tensor = F.pad(sentence_tensor, (0, pad))

        return sentence_tensor, torch.tensor(q), torch.tensor(lbl)

    def __repr__(self):
        S = len(self.raw_dataset['int_labels'])
        return f'Samples: {len(self.idx_tuples)} (no_sense: {self.no_sense_count})\nSentences: {S} (N={self.N})\n' \
               f'Vocab:\n\tTokens:{self.tokens_vocab.size()}\n\tSenses:{self.y_vocab.size()}'

class WSDSentencesDataset(data.Dataset):

    @staticmethod
    def from_word_dataset(dataset):
        return WSDSentencesDataset(
            dataset.raw_dataset,
            dataset.tokens_vocab,
            dataset.y_vocab,
        )

    def __init__(self, raw_dataset, tokens_vocab, y_vocab):
        self.raw_dataset = raw_dataset
        self.tokens_vocab = tokens_vocab
        self.y_vocab = y_vocab
        self.sample_type = 'sentence'
        self.no_sense_label = y_vocab.encode(NO_SENSE)
        self.N = max(map(len, raw_dataset['int_sentences']))

    def __len__(self):
        return len(self.raw_dataset['int_sentences'])

    def __getitem__(self, index):
        sentence = self.raw_dataset['int_sentences'][index]
        labels = self.raw_dataset['int_labels'][index]

        pad = self.N - len(sentence)
        sentence_tensor = F.pad(torch.tensor(sentence), (0, pad), value=self.tokens_vocab.padding_idx)
        labels_tensor = F.pad(torch.tensor(labels), (0, pad), value=self.no_sense_label)

        return sentence_tensor, labels_tensor

    def __repr__(self):
        S = len(self.raw_dataset['int_labels'])
        return f'Samples: {S}\nSentences: {S} (N={self.N})\n' \
               f'Vocab:\n\tTokens:{self.tokens_vocab.size()}\n\tSenses:{self.y_vocab.size()}'


import argparse
import math

def output_periods(periods):
    start = 'It will take'
    joiner = 'and'
    end = 'to repay this loan!'

    years = periods // 12
    months = periods % 12

    years_str = str(f'{years} {"year" if years == 1 else "years"}')
    months_str = str(f'{months} {"month" if months == 1 else "months"}')

    if years > 0 and months > 0:
        return str(f'{start} {years_str} {joiner} {months_str} {end}')
    elif years == 0:
        return str(f'{start} {months_str} {end}')
    elif months == 0:
        return str(f'{start} {years_str} {end}')

def count_empty_args(arguments):
    count = 0
    for field in vars(arguments):
        if field is None:
            count += 1

    return count

def has_negative_args(arguments):
    is_negative = False
    args_array = [arguments.payment, arguments.periods, arguments.interest, arguments.principal]
    for arg in args_array:
        if arg is not None and float(arg) < 0:
            is_negative = True

    return is_negative

def check_input(arguments):
    count = count_empty_args(arguments)
    if count > 1 \
            or arguments.type is None \
            or arguments.type == 'diff' and arguments.payment \
            or arguments.interest is None \
            or has_negative_args(arguments):
        print('Incorrect parameters')
        return False
    return True

def calc_principal(periods, payment, interest_rate):
    principal = payment / ((interest_rate * math.pow(1 + interest_rate, periods)) / (math.pow(1 + interest_rate, periods) - 1))
    print(f'Your loan principal = {math.floor(principal)}!')
    calc_overpayment(periods * payment, math.floor(principal))

def calc_payment(periods, principal, interest_rate):
    payment = principal * interest_rate * math.pow(1 + interest_rate, periods) / (math.pow(1 + interest_rate, periods) - 1)
    print(f'Your annuity payment = {math.ceil(payment)}!')
    calc_overpayment(periods * math.ceil(payment), principal)

def calc_periods(principal, payment, interest_rate):
    periods = math.ceil(math.log(payment / (payment - interest_rate * principal), 1 + interest_rate))
    print(output_periods(periods))
    calc_overpayment(periods * payment, principal)

def calc_overpayment(result_payment, principal):
    print(f'Overpayment = {(result_payment - principal)}')

def calc_diff_payment(periods, principal, interest_rate, month):
    payment = math.ceil(principal / periods + interest_rate * (principal - principal * (month - 1) / periods))
    print(f'Month {month}: payment is {payment}')
    return payment

parser = argparse.ArgumentParser()
parser.add_argument('--type')
parser.add_argument('--payment')
parser.add_argument('--principal')
parser.add_argument('--periods')
parser.add_argument('--interest')

args = parser.parse_args()

if check_input(args):
    interest = float(args.interest) / 1200
    if args.type == 'annuity':
        if args.principal is None:
            calc_principal(int(args.periods), int(args.payment), interest)
        elif args.payment is None:
            calc_payment(int(args.periods), int(args.principal), interest)
        elif args.periods is None:
            calc_periods(int(args.principal), int(args.payment), interest)
    else:
        acc = 0
        for period in range(int(args.periods)):
            acc += calc_diff_payment(int(args.periods), int(args.principal), interest, period + 1)
        calc_overpayment(acc, int(args.principal))


from numpy import *
import matplotlib.pyplot as plt

data_infile = "train.csv"
test_infile = "test.csv"

IteraterTime = 490 #867
DIVIDE = (0.75, 0.25) #训练集和验证集的比例，四舍五入用round，返回浮点数

def Read_data(infile, Col, is_test = False) : # 读入数据集路径，列数，是否为测试集
    data = loadtxt(infile, dtype = float, usecols = range(Col) , delimiter=',')
    row = len(data)
    add = ones(row)
    if not is_test :
        label = data[:,-1]
        data = c_[add, data[:,:-1]]
        return data, label
    else :
        data = c_[add, data]
        return data

def sigmoid(v) : #logistics函数
    return 1.0 / (1.0 + exp(-v))

def pidDynamic(w, err, lastError, accumulateError) :
    errorDifferential = (err - lastError) / 0.0001
    lastError = err
    accumulateError = accumulateError + err
    kp = 0.5
    ki = 3
    kd = 0.012
    return w - (kp * err + ki * accumulateError + kd * errorDifferential), lastError, accumulateError

def LR(eta, trainDataSet, trainLabelSet, IteraterTime) :
    w = zeros(trainDataSet.shape[1])              #这里列数为维度数，行数为样本数
    wt = dot(trainDataSet, w)
    lastError = dot((sigmoid(wt) - trainLabelSet), trainDataSet)
    accumulateError = zeros(trainDataSet.shape[1])
    for i in range(IteraterTime) :
        wt = dot(trainDataSet,w)
        err = dot((sigmoid(wt) - trainLabelSet), trainDataSet)
        if sqrt(dot(err,err)) < 0.00001 :
            break
        else :
            w, lastError, accumulateError = pidDynamic(w, err, lastError, accumulateError)
            # w = w - eta * err
    return w

def regularLR(eta, trainDataSet, trainLabelSet, IteraterTime, Lambda) :
    w = ones(trainDataSet.shape[1])              #这里列数为维度数，行数为样本数
    for i in range(IteraterTime) :
        wt = dot(trainDataSet,w)
        err = dot((sigmoid(wt) - trainLabelSet), trainDataSet)
        err = err + Lambda * sum(w)
        err /= trainDataSet.shape[0]
        # if sqrt(dot(err,err)) < 0.00001 :
        #     break
        # else :
        w = w - eta * err
    return w

def LRSingle(eta, trainDataSet, trainLabelSet, IteraterTime) :
    w = ones(trainDataSet.shape[1])              #这里列数为维度数，行数为样本数
    for i in range(IteraterTime) :
        for j in range(trainDataSet.shape[0]) :
            wt = trainDataSet[j] * w
            err = (sigmoid(wt) - trainLabelSet[j]) * trainDataSet[j]
            if len(err.nonzero()) == 0 :
                break
            else :
                w = w - eta * err
    return w

def Classify(w, DataSet):
    valProbability = sigmoid(dot(DataSet, w))
    predictLabel = valProbability > 0.5
    return predictLabel

def Validation(w, valDataSet, valLabelSet) :
    result = Classify(w, valDataSet)
    TP = FP = TN = FN = 0
    for i in range(len(result)) :
        if result[i] == valLabelSet[i] and valLabelSet[i] == 1:
            TP = TP + 1
        elif result[i] != valLabelSet[i] and valLabelSet[i] == 0 :
            FP = FP + 1
        elif result[i] == valLabelSet[i] and valLabelSet[i] == 0 :
            TN = TN + 1
        else :
            FN = FN + 1
    # print(TP, FP, TN, FN)
    accuracy = (TP + TN) / (TP + FP + TN + FN)
    if TP == FP == 0 :
        recall = 0
    else:
        recall = 1.0 * TP / (TP + FN)
    if TP == FP == 0:
        precision = 0
    else:
        precision = 1.0 * TP / (TP + FP)
    if TP != 0 :
        f1 = 2.0 * precision * recall / (precision + recall)
    else:
        f1 = 0
    return accuracy, recall, precision, f1

if __name__ == '__main__' :
    data, label = Read_data(data_infile, 8)
    # test_data = Read_data(test_infile,40, True)
    #
    # ys_data, ys_label = Read_data(yanshou_tr, 7)
    # ys_te_data = Read_data(yanshou_te, 6, True)
    # ys_w = LR(1, ys_data,ys_label,1)
    # ys_pre_label = Classify(ys_w, ys_te_data)
    # print (ys_pre_label)

    # eta = [i for i in range(100,1000)]
    eta = [392]
    numberOfLine = int(round(DIVIDE[0] * data.shape[0])) #data.shape返回一个元组，值分别为行数和列数
    # re_w = regularLR(0.013, data[:numberOfLine], label[:numberOfLine], 200, 575)
    # predictLabel = Classify(re_w, test_data)
    # f = open("testResult.txt", 'w')
    # for i in predictLabel:
    #     if i :
    #         f.write(str(1))
    #     else:
    #         f.write(str(0))
    #     f.write('\n')
    best_w = []
    best_f1 = 0
    Result = [[],[],[],[]]
    for i in eta : #575 0.7855
        re_w = LR(0.013,data[:numberOfLine], label[:numberOfLine], i)
        accuracy, recall, precision, f1 = Validation(re_w, data[numberOfLine:data.shape[0]], label[numberOfLine:label.shape[0]])
        if f1 > best_f1:
            best_w = re_w
        Result[0].append(accuracy)
        Result[1].append(recall)
        Result[2].append(precision)
        Result[3].append(f1)
    # w = LR(eta, data[:numberOfLine], label[:numberOfLine], IteraterTime)#Batch Gradient
    # Validation(w, data[numberOfLine:data.shape[0]], label[numberOfLine:label.shape[0]])

    # for i in eta :
    #     w_single = LR(0, data[:numberOfLine], label[:numberOfLine], i)#Single Gradient
    #     accuracy, recall, precision, f1 = Validation(w_single, data[numberOfLine:data.shape[0]], label[numberOfLine:label.shape[0]])
    #     Result[0].append(accuracy)
    #     # Result[1].append(recall)
    #     # Result[2].append(precision)
    #     # Result[3].append(f1)

    print(re_w)
    print(eta[Result[0].index(max(Result[0]))])
    print("F1",max(Result[3]))
    print(Result)
    plt.plot(eta, Result[0], label="Accuracy",lw=1)
    plt.plot(eta, Result[1], label="Recall")
    plt.plot(eta, Result[2], label="Precision")
    plt.plot(eta, Result[3], label="F1")
    # plt.plot(eta, singleResult, label = "Single Gradient")
    plt.grid()
    plt.xlabel('Lambda')
    plt.ylabel('Accuracy')
    plt.legend()
    plt.show()

    test_data = Read_data(test_infile, 7, True)
    predictLabel = Classify(best_w, test_data)
    f = open("Result.csv", 'w')
    for i in predictLabel:
        if i :
            f.write(str(1))
        else:
            f.write(str(0))
        f.write('\n')