import socket
import time
import numpy as np
import cv2

class CameraClient(object):

    def __init__(self):
        self.initSocketClient()

    def initSocketClient(self):
        host = "raspberrypi"
        port = 2222
        clientSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        clientSocket.connect((host, port))
        streamSocket = clientSocket.makefile('rb')
        print("Connected to camera server")
        try:
            print("Streaming...")
            stream_bytes = " "

            while True:
                stream_bytes += streamSocket.read(1024)
                first = stream_bytes.find('\xff\xd8')
                last  = stream_bytes.find('\xff\xd9')
                if first != -1 and last != -1:
                    jpg = stream_bytes[first:last + 2]
                    stream_bytes = stream_bytes[last + 2:]
                    image = cv2.imdecode(np.fromstring(jpg, dtype=np.uint8), cv2.CV_LOAD_IMAGE_UNCHANGED)

                    #cv2.namedWindow("window", cv2.WND_PROP_FULLSCREEN)
                    #cv2.setWindowProperty("window",cv2.WND_PROP_FULLSCREEN,cv2.WINDOW_FULLSCREEN)
                    cv2.imshow('Camera', image)

                    if cv2.waitKey(1) & 0xFF == ord('q'):
                        break
        finally:
            clientSocket.close()
            streamSocket.close()

#Main Function
if __name__ == '__main__':
    CameraClient()


#boas vindas
print('Bem vindo(a) ao Simulador de SISU (por enquanto só da UFG - Campus Samambaia).')
print('\nSua média final será calculada de acordo com os pesos atualizados de 2023 oficiais disponibilizados pela UFG. \nVocê pode acessar o PDF com os pesos aqui: https://showrtner.com/lninIyh')
print('\nIMPORTANTE: Separe as casas decimais das notas que você inserir a seguir por um ponto, e não por vírgula.')
input('\nAperte ENTER para prosseguir. ')

#inputs de nota
nota_linguagens = float(input('\nInsira sua nota na área de Linguagens: '))
nota_matematica = float(input('Insira sua nota na área de Matemática: '))
nota_natureza = float(input('Insira sua nota na área de Ciências da Natureza: '))
nota_humanas = float(input('Insira sua nota na área de Ciências Humanas: '))
nota_redacao = float(input('Insira sua nota na Redação: '))

#input do curso
cursoinserido = input('\nInsira o curso de desejo: ').lower()

#cursos listados por grupo
grupo1 = ['engenharia ambiental','engenharia civil','engenharia da computação',
'engenharia da computacao','engenharia da computaçao','engenharia de minas','engenharia de producao',
'engenharia de produção','engenharia de produçao','engenharia de transportes','engenharia eletrica',
'engenharia elétrica','engenharia fisica','engenharia física','engenharia mecanica','engenharia mecânica',
'engenharia quimica','engenharia química','estatistica','estatística','física','fisica','fisica medica',
'física médica','fisica médica','física medica','geologia','química','quimica']

grupo2 = ['matematica', 'matemática', 'matematica industrial', 'matemática industrial']

grupo3 = ['ciencia da computacao', 'ciência da computacao', 'ciência da computação',
 'ciencia da computaçao', 'ciência da computação', 'engenharia de software',
 'sistema de informacao', 'sistemas de informação', 'sistemas de informaçao']

grupo4 = ['biomedicina', 'biotecnologia', 'ciencias ambientais', 'ciências ambientais', 'ciencias biologicas',
'ciências biologicas', 'ciencias biológicas', 'ciências biológicas', 'ecologia e analise ambiental',
'ecologia e análise ambiental', 'enfermagem', 'farmacia', 'farmácia','fisioterapia', 'medicina', 'nutrição', 'nutricao', 'nutriçao', 'odontologia']

grupo5 = ['agronomia', 'engenharia de alimentos', 'engenharia florestal', 'medicina veterinaria', 'veterinaria', 'medicina veterinária', 'zootecnia']

grupo6 = ['filosofia', 'geografia', 'historia', 'história', 'pedagogia', 'psicologia', 'relacoes internacionais', 'relaçoes internacionais', 'relações internacionais']

grupo7 = ['administracao', 'administraçao', 'administração', 'arquitetura', 'arquitetura e urbanismo', 'biblioteconomia', 'ciencias contabeis', 'ciências contábeis',
'ciencias contábeis', 'ciências contabeis', 'ciencias economicas', 'ciências economicas', 'ciencias econômicas', 'ciências econômicas',
'ciencias sociais', 'ciências sociais', 'ciências sociais politicas publicas', 'ciências sociais políticas publicas', 'ciências sociais políticas públicas',
'ciencias sociais políticas publicas', 'ciencias sociais politicas publicas', 'comunicação social', 'comunicacao social', 'comunicaçao social', 'publicidade e propaganda',
'publicidade', 'direito', 'gestao da informacao', 'gestao da informação', 'gestão da informacao', 'gestão da informação', 'jornalismo', 'museologia', 'relacoes publicas', 'relações publicas',
'relaçoes publicas', 'relacoes públicas', 'relações públicas', 'relações publicas', 'serviço social', 'servico social',]

grupo8 = ['artes cenicas', 'artes cênicas', 'artes visuais', 'dança', 'design de ambientes', 'design de moda', 'design gráfico', 'design grafico', 'direção de arte', 'direcao de arte',
 'direçao de arte', 'letras espanhol', 'letras estudos literarios','letras frances', 'letras francês', 'letras ingles',
'letras inglês', 'letras libras', 'letras lingua portuguesa', 'letras portugues','letras linguistica', 'letras linguística'
'letras português', 'letras português/inglês', 'letras portugues/ingles',
'letras traducao e interpretacao de libras', 'letras tradução e interpretação de libras', 'letras libras/português', 'música', 'musica', 'musicoterapia']

#PESOS GRUPO 1
pesoling1=2.0
pesohum1=1.0
pesonatu1=2.5
pesomat1=3.0
pesored1=1.5

#PESOS GRUPO 2
pesoling2=2.0
pesohum2=1.0
pesonatu2=1.5
pesomat2=4.0
pesored2=1.5

#PESOS GRUPO 3
pesoling3=2.0
pesohum3=1.0
pesonatu3=1.0
pesomat3=4.0
pesored3=2.0

#PESOS GRUPO 4
pesoling4=2.0
pesohum4=1.5
pesonatu4=3.0
pesomat4=1.5
pesored4=2.0

#PESOS GRUPO 5
pesoling5=2.0
pesohum5=1.0
pesonatu5=3.0
pesomat5=2.0
pesored5=2.0

#PESOS GRUPO 6
pesoling6=2.5
pesohum6=3.0
pesonatu6=1.0
pesomat6=1.0
pesored6=2.5

#PESOS GRUPO 7
pesoling7=2.5
pesohum7=2.0
pesonatu7=1.0
pesomat7=2.0
pesored7=2.5

#PESOS GRUPO 8
pesoling8=3.0
pesohum8=2.5
pesonatu8=1.0
pesomat8=1.0
pesored8=2.5

#criando excecao pra ed fisica (bacharel/licenciatura)
educacoesfisicas = ['educacao fisica', 'educacao fisica', 'educação física', 'educaçao fisica','educação fisica']

letrass = []

if cursoinserido in educacoesfisicas:

 input2 = input('Licenciatura ou bacharelado?\n[L] Licenciatura\n[B] Bacharelado\n')

 if input == 'L':  #NOTA PRA LICENCIATURA

    notacompesoling6=(pesoling6*nota_linguagens)
    notacompesohum6=(pesohum6*nota_humanas)
    notacompesonatu6=(pesonatu6*nota_natureza)
    notacompesomat6=(pesomat6*nota_matematica)
    notacompesored6=(pesored6*nota_redacao)

    print('Segundo a divisão oficial da UFG, seu curso está contido no GRUPO 2.')
    print('\nNOTAS COM PESO DO GRUPO 2')
    print('\nLinguagens: {}'.format(round(notacompesoling6, 2)))
    print('Matemática: {}'.format(round(notacompesomat6, 2)))
    print('C. Natureza: {}'.format(round(notacompesonatu6, 2)))
    print('C. Humanas: {}'.format(round(notacompesohum6, 2)))
    print('Redação: {}'.format(round(notacompesored6, 2)))

    mediafinal = ((notacompesoling6+notacompesohum6+notacompesonatu6+notacompesomat6+notacompesored6)/10)
    print('\nA sua média final é de {}'.format(round(mediafinal, 2)))

 elif input == 'B':  #NOTA PRA BACHARELADO
    notacompesoling4=(pesoling4*nota_linguagens)
    notacompesohum4=(pesohum4*nota_humanas)
    notacompesonatu4=(pesonatu4*nota_natureza)
    notacompesomat4=(pesomat4*nota_matematica)
    notacompesored4=(pesored4*nota_redacao)

    print('Segundo a divisão oficial da UFG, seu curso está contido no GRUPO 4.')
    print('\nNOTAS COM PESO DO GRUPO 4')
    print('\nLinguagens: {}'.format(round(notacompesoling4, 2)))
    print('Matemática: {}'.format(round(notacompesomat4, 2)))
    print('C. Natureza: {}'.format(round(notacompesonatu4, 2)))
    print('C. Humanas: {}'.format(round(notacompesohum4, 2)))
    print('Redação: {}'.format(round(notacompesored4, 2)))

    mediafinal = ((notacompesoling4+notacompesohum4+notacompesonatu4+notacompesomat4+notacompesored4)/10)
    print('\nA sua média final é de {}'.format(round(mediafinal, 2)))

 else:
    print('Você não inseriu uma resposta válida.')

elif cursoinserido in grupo1:

    notacompesoling1=(pesoling1*nota_linguagens)
    notacompesohum1=(pesohum1*nota_humanas)
    notacompesonatu1=(pesonatu1*nota_natureza)
    notacompesomat1=(pesomat1*nota_matematica)
    notacompesored1=(pesored1*nota_redacao)

    print('\nSegundo a divisão oficial da UFG, seu curso está contido no GRUPO 1.')
    print('\nNOTAS COM PESO DO GRUPO 1')
    print('\nLinguagens: {}'.format(round(notacompesoling1, 2)))
    print('Matemática: {}'.format(round(notacompesomat1, 2)))
    print('C. Natureza: {}'.format(round(notacompesonatu1, 2)))
    print('C. Humanas: {}'.format(round(notacompesohum1, 2)))
    print('Redação: {}'.format(round(notacompesored1, 2)))

    mediafinal = ((notacompesoling1+notacompesohum1+notacompesonatu1+notacompesomat1+notacompesored1)/10)
    print('\nA sua média final é de {}'.format(round(mediafinal, 2)))

elif cursoinserido in grupo2:

    notacompesoling2=(pesoling2*nota_linguagens)
    notacompesohum2=(pesohum2*nota_humanas)
    notacompesonatu2=(pesonatu2*nota_natureza)
    notacompesomat2=(pesomat2*nota_matematica)
    notacompesored2=(pesored2*nota_redacao)

    print('Segundo a divisão oficial da UFG, seu curso está contido no GRUPO 2.')
    print('\nNOTAS COM PESO DO GRUPO 2')
    print('\nLinguagens: {}'.format(round(notacompesoling2, 2)))
    print('Matemática: {}'.format(round(notacompesomat2, 2)))
    print('C. Natureza: {}'.format(round(notacompesonatu2, 2)))
    print('C. Humanas: {}'.format(round(notacompesohum2, 2)))
    print('Redação: {}'.format(round(notacompesored2, 2)))

    mediafinal = ((notacompesoling2+notacompesohum2+notacompesonatu2+notacompesomat2+notacompesored2)/10)
    print('\nA sua média final é de {}'.format(round(mediafinal, 2)))

elif cursoinserido in grupo3:

    notacompesoling3=(pesoling3*nota_linguagens)
    notacompesohum3=(pesohum3*nota_humanas)
    notacompesonatu3=(pesonatu3*nota_natureza)
    notacompesomat3=(pesomat3*nota_matematica)
    notacompesored3=(pesored3*nota_redacao)

    print('Segundo a divisão oficial da UFG, seu curso está contido no GRUPO 3.')
    print('\nNOTAS COM PESO DO GRUPO 3')
    print('\nLinguagens: {}'.format(round(notacompesoling3, 2)))
    print('Matemática: {}'.format(round(notacompesomat3, 2)))
    print('C. Natureza: {}'.format(round(notacompesonatu3, 2)))
    print('C. Humanas: {}'.format(round(notacompesohum3, 2)))
    print('Redação: {}'.format(round(notacompesored3, 2)))

    mediafinal = ((notacompesoling3+notacompesohum3+notacompesonatu3+notacompesomat3+notacompesored3)/10)
    print('\nA sua média final é de {}'.format(round(mediafinal, 2)))

elif cursoinserido in grupo4:

    notacompesoling4=(pesoling4*nota_linguagens)
    notacompesohum4=(pesohum4*nota_humanas)
    notacompesonatu4=(pesonatu4*nota_natureza)
    notacompesomat4=(pesomat4*nota_matematica)
    notacompesored4=(pesored4*nota_redacao)

    print('Segundo a divisão oficial da UFG, seu curso está contido no GRUPO 4.')
    print('\nNOTAS COM PESO DO GRUPO 4')
    print('\nLinguagens: {}'.format(round(notacompesoling4, 2)))
    print('Matemática: {}'.format(round(notacompesomat4, 2)))
    print('C. Natureza: {}'.format(round(notacompesonatu4, 2)))
    print('C. Humanas: {}'.format(round(notacompesohum4, 2)))
    print('Redação: {}'.format(round(notacompesored4, 2)))

    mediafinal = ((notacompesoling4+notacompesohum4+notacompesonatu4+notacompesomat4+notacompesored4)/10)
    print('\nA sua média final é de {}'.format(round(mediafinal, 2)))

elif cursoinserido in grupo5:

    notacompesoling5=(pesoling5*nota_linguagens)
    notacompesohum5=(pesohum5*nota_humanas)
    notacompesonatu5=(pesonatu5*nota_natureza)
    notacompesomat5=(pesomat5*nota_matematica)
    notacompesored5=(pesored5*nota_redacao)

    print('Segundo a divisão oficial da UFG, seu curso está contido no GRUPO 5.')
    print('\nNOTAS COM PESO DO GRUPO 5')
    print('\nLinguagens: {}'.format(round(notacompesoling5, 2)))
    print('Matemática: {}'.format(round(notacompesomat5, 2)))
    print('C. Natureza: {}'.format(round(notacompesonatu5, 2)))
    print('C. Humanas: {}'.format(round(notacompesohum5, 2)))
    print('Redação: {}'.format(round(notacompesored5, 2)))

    mediafinal = ((notacompesoling5+notacompesohum5+notacompesonatu5+notacompesomat5+notacompesored5)/10)
    print('\nA sua média final é de {}'.format(round(mediafinal, 2)))

elif cursoinserido in grupo6:

    notacompesoling6=(pesoling6*nota_linguagens)
    notacompesohum6=(pesohum6*nota_humanas)
    notacompesonatu6=(pesonatu6*nota_natureza)
    notacompesomat6=(pesomat6*nota_matematica)
    notacompesored6=(pesored6*nota_redacao)

    print('Segundo a divisão oficial da UFG, seu curso está contido no GRUPO 2.')
    print('\nNOTAS COM PESO DO GRUPO 2')
    print('\nLinguagens: {}'.format(round(notacompesoling6, 2)))
    print('Matemática: {}'.format(round(notacompesomat6, 2)))
    print('C. Natureza: {}'.format(round(notacompesonatu6, 2)))
    print('C. Humanas: {}'.format(round(notacompesohum6, 2)))
    print('Redação: {}'.format(round(notacompesored6, 2)))

    mediafinal = ((notacompesoling6+notacompesohum6+notacompesonatu6+notacompesomat6+notacompesored6)/10)
    print('\nA sua média final é de {}'.format(round(mediafinal, 2)))

elif cursoinserido in grupo7:

    notacompesoling7=(pesoling7*nota_linguagens)
    notacompesohum7=(pesohum7*nota_humanas)
    notacompesonatu7=(pesonatu7*nota_natureza)
    notacompesomat7=(pesomat7*nota_matematica)
    notacompesored7=(pesored7*nota_redacao)

    print('Segundo a divisão oficial da UFG, seu curso está contido no GRUPO 7.')
    print('\nNOTAS COM PESO DO GRUPO 7')
    print('\nLinguagens: {}'.format(round(notacompesoling7, 2)))
    print('Matemática: {}'.format(round(notacompesomat7, 2)))
    print('C. Natureza: {}'.format(round(notacompesonatu7, 2)))
    print('C. Humanas: {}'.format(round(notacompesohum7, 2)))
    print('Redação: {}'.format(round(notacompesored7, 2)))

    mediafinal = ((notacompesoling7+notacompesohum7+notacompesonatu7+notacompesomat7+notacompesored7)/10)
    print('\nA sua média final é de {}'.format(round(mediafinal, 2)))

elif cursoinserido in grupo8:

    notacompesoling8=(pesoling8*nota_linguagens)
    notacompesohum8=(pesohum8*nota_humanas)
    notacompesonatu8=(pesonatu8*nota_natureza)
    notacompesomat8=(pesomat8*nota_matematica)
    notacompesored8=(pesored8*nota_redacao)

    print('Segundo a divisão oficial da UFG, seu curso está contido no GRUPO 8.')
    print('\nNOTAS COM PESO DO GRUPO 8')
    print('\nLinguagens: {}'.format(round(notacompesoling8, 2)))
    print('Matemática: {}'.format(round(notacompesomat8, 2)))
    print('C. Natureza: {}'.format(round(notacompesonatu8, 2)))
    print('C. Humanas: {}'.format(round(notacompesohum8, 2)))
    print('Redação: {}'.format(round(notacompesored8, 2)))

    mediafinal = ((notacompesoling8+notacompesohum8+notacompesonatu8+notacompesomat8+notacompesored8)/10)
    print('\nA sua média final é de {}'.format(round(mediafinal, 2)))


from flask import Flask, jsonify, request
app = Flask(__name__)
contacts = [{'Name':'Ram', 'Number':'2123'}, {'Name':'Geeta','Number':'9034'},{'Name':'Mukesh','Number':'3139'}]

@app.route('/get-contact')

def getContacts():
    return jsonify({'contact':contacts})

@app.route('/add-contact', methods = ['POST'])

def addContacts():
    if not request.json:
        return jsonify({'status':'error', 'message':'Please provide the data'}, 400)
    contact = {'Name':request.json['Name'], 'Number':request.json['Number']}
    contacts.append(contact)
    return jsonify({'status':'Success', 'message':'Contact Added Sucessfully'})
if __name__ == '__main__':
    app.run(debug = True)
print(contacts)


#Barbaric approach at /r/place timelapese program using pygame for visualization

import pygame, sys

#I could've put everything into a single list, but idk, this feels cleaner
time = []
coord = []
color = []
color_list = [
    (255, 255, 255),
    (228, 228, 228),
    (136, 136, 136),
    (34, 34, 34),
    (255, 167, 209),
    (229, 0, 0),
    (229, 149, 0),
    (160, 106, 66),
    (229, 217, 0),
    (148, 224, 68),
    (2, 190, 1),
    (0, 229, 240),
    (0, 131, 199),
    (0, 0, 234),
    (224, 74, 255),
    (130, 0, 128),
    ]

running = True
length = 0
speed = 10000
current_time = 0

#Loading the file and seperating it into different lists
path = "data/place.csv"
with open(path) as f:
    content = f.readlines()
    for x in content:
        temp = x.strip() #remove unnecessary things from string
        temp = temp.split(",") #seperate the string by ","
        #Adding the seperated string into the lists
        time.append(int(temp[0]))
        coord.append((int(temp[1]), int(temp[2])))
        color.append(int(temp[3]))
        length += 1

#Pygame initialisation stuff
pygame.init()
window = pygame.display.set_mode((1200,1000))
pygame.display.set_caption("/r/place")
font = pygame.font.SysFont('Arial', 30)
pygame.key.set_repeat(1,1)

#Function for writing text on screen
def text(string, coords):
    string = str(string) + "          "
    temp = font.render(string, True, (0,0,0), (255,255,255))
    window.blit(temp, coords)

#Fill the screen with white once at start
window.fill((255, 255, 255))

#Recalculates frame, insanely slow, probably going to add some key frames
def recalculate():
    window.fill((255, 255, 255))
    for i in range(0, current_time):
        window.set_at(coord[i], color_list[color[i]])

#Main loop
while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_KP_PLUS: speed += 2
            if event.key == pygame.K_KP_MINUS: speed -= 2
            if event.key == pygame.K_KP1: speed = 1000
            if event.key == pygame.K_KP2: speed = 20000
            if event.key == pygame.K_KP0: #Resets to zero
                current_time = 0
                recalculate()
            if event.key == pygame.K_LEFT: #If you go backwards it has to recalculate everything
                current_time -= speed
                if current_time < 0: current_time = 0
                recalculate()
            if event.key == pygame.K_RIGHT: #Going forwards
                current_time += speed
                if current_time > length: current_time = length
                for i in range(current_time - speed, current_time):
                    window.set_at(coord[i], color_list[color[i]])

    text("Time:", (1020,20))
    text(current_time, (1020,60))
    text("Speed:", (1020, 120))
    text(speed, (1020, 160))

    pygame.display.update()


# SQLite_Database.py
import sqlite3

# Step 1: create 'connection object' representing the database:
conn = sqlite3.connect('example.db')        #Do the same for accessing the database later on

# Step 2: create Cursor object to be able to perform SQL commands on the database:
c = conn.cursor()

# Step 3: adding data to the database:
    # Create table
#c.execute('''CREATE TABLE stocks
#             (date text, trans text, symbol text, qty real, price real)''')
    # Insert a row of data
#c.execute("INSERT INTO stocks VALUES ('2006-01-05','BUY','RHAT',100,35.14)")
    # Always have to save (commit) the changes
#conn.commit()

# Step 4: querying the database:
    # Put the query in an execute statement
    # fetchall() returns a list [] of tuples (rows)
a = c.execute("SELECT * FROM stocks WHERE symbol = 'RHAT'").fetchall()     #Use "" (double) so you can use '' (single) in query
    # To use variables from Python in the query, use ? as placeholder
    # and provide tuple as second argument to placeholder:
symbol = ('RHAT',) #Tuple with only one value here
print(c.execute('SELECT * FROM stocks WHERE symbol=?', symbol).fetchall())

# Step 5: inserting multiple rows at once: c.executemany:
purchases = [('2006-03-28', 'BUY', 'IBM', 1000, 45.00),
             ('2006-04-05', 'BUY', 'MSFT', 1000, 72.00),
             ('2006-04-06', 'SELL', 'IBM', 500, 53.00),
            ]
#c.executemany("INSERT INTO stocks VALUES (?,?,?,?,?)", purchases) #Executemany takes list of tuples as second argument
#conn.commit()      #Don't forget commit!
try:  # Deal with last part of the data: general data without publishIndex
    publish_index = sensor['publishIndex']
except:
    publish_index = 17  # Last element on the device list is the 'general element'
# Step 5: close the connection (changes are lost if not commited before closing)
#conn.close()


# Serafeim Themistokleous 4555

import histograms
import random

def experiments(csv_path, csv_attribute, n):

    accuracy_equiwidth_list = list()
    accuracy_equidepth_list = list()

    histogram = histograms.Histogram(csv_path, csv_attribute)
    min_max = histogram.read_income_data()
    histogram.equiwidth()
    histogram.equidepth()
    histogram.print_result()

    min = min_max[0]
    max = min_max[1]

    for i in range(1, n):
        a = random.randint(min, max)
        b = random.randint(min, max)
        while a > b:
            a = random.randint(min, max)

        act_result = histogram.actual_result(a, b)
        est_equiwidth_result = histogram.equiwidth_estimated_result(a, b)
        est_equidepth_result = histogram.equidepth_estimated_result(a, b)

        # calculate the accuracy of the two histograms to the actual results
        if act_result > 0:
            error_rate_equiwidth = (abs((est_equiwidth_result - act_result)) / act_result) * 100
            accuracy_equiwidth = 100 - error_rate_equiwidth

            error_rate_equidepth = (abs((est_equidepth_result - act_result)) / act_result) * 100
            accuracy_equidepth = 100 - error_rate_equidepth
        else:
            accuracy_equiwidth = 0
            accuracy_equidepth = 0
        accuracy_equiwidth_list.append(accuracy_equiwidth)
        accuracy_equidepth_list.append(accuracy_equidepth)

    # Metrics
    mo_equiwidth = sum(accuracy_equiwidth_list) / len(accuracy_equiwidth_list)
    mo_equidepth = sum(accuracy_equidepth_list) / len(accuracy_equidepth_list)
    print("\nAccuracy of histograms")
    print("equiwidth accuracy = ", round(mo_equiwidth, 2), "%")
    print("equidepth accuracy = ", round(mo_equidepth, 2), "%")


# 2차원 배열
import sys
sys.stdin = open("4836.txt", "r")

T = int(input())
for tc in range(1, T+1):
    arr = [[0]*10 for _ in range(10)]
    # 10x10 2차원 배열
    # 카운팅 정렬
    N = int(input())
    for _ in range(N):
    # color 1 혹은 2의 사각형 개수
        x1, y1, x2, y2, color = map(int, input().split())
        # N번만큼 순회하면서 값을 입력
        if color == 1:
        # color 1
            for x in range(x1, x2+1):
                for y in range(y1, y2+1):
                    arr[x][y] += 1
                    # 주어진 정보에서 같은 색인 영역은 겹치지 않는다
                    # 같은 색으로 인해 1이 여러번 더해질 경우는 없다

        else:
        # color 2
            for x in range(x1, x2+1):
                for y in range(y1, y2+1):
                    arr[x][y] += 1
                    # 주어진 정보에서 같은 색인 영역은 겹치지 않는다
                    # 같은 색으로 인해 1이 여러번 더해질 경우는 없다
        # print(arr)

    cnt = 0
    for i in range(10):
        for j in range(10):
            if arr[i][j] == 2:
            # color 1과 color 2가 겹쳐서 [0]에서 1이 두 번 더해진 경우
                cnt += 1
                # 보라색이 된 칸 수를 구하는 프로그램

    print("#{} {}".format(tc, cnt))

# 함수로 변형
def coloring(arr, r1, c1, r2, c2, color):
    for i in range(r1, r2+1):
        for j in range(c1, c2+1):
            if arr[i][j] == 0 or arr[i][j] == color:
                arr[i][j] = color
                # 1 혹은 2
            else:
                arr[i][j] = 3

T = int(input())
for tc in range(1, T + 1):
    N = int(input())
    arr = [[0 for _ in range(10)] for _ in range(10)]
    for i in range(N):
        info = list(map(int, input().split()))
        coloring(arr, info[0], info[1], info[2], info[3], info[4])

    cnt = 0
    for r in range(len(arr)):
        for c in range(len(arr[r])):
            if arr[r][c] == 3:
                cnt += 1

    print("#{} {}".format(tc, cnt))


"""
mnist_average_darkness
~~~~~~~~~~~~~~~~~~~~~~

A naive classifier for recognizing handwritten digits from the MNIST
data set.  The program classifies digits based on how dark they are
--- the idea is that digits like "1" tend to be less dark than digits
like "8", simply because the latter has a more complex shape.  When
shown an image the classifier returns whichever digit in the training
data had the closest average darkness.

The program works in two steps: first it trains the classifier, and
then it applies the classifier to the MNIST test data to see how many
digits are correctly classified.

Needless to say, this isn't a very good way of recognizing handwritten
digits!  Still, it's useful to show what sort of performance we get
from naive ideas."""

#### Libraries
# Standard library
from collections import defaultdict

# My libraries
import mnist_loader

def main():

    # On charge les datasets
    print("\n>> 1. DATASETS <<\n")
    training_data, validation_data, test_data = mnist_loader.load_data()

    # On compte les moyennes d'obscurité des images pour chaque nombre a prédire pour le dataset d'apprentissage
    print("\n>> 2. \"TRAINING\" <<\n")
    print("\"Training\"...")
    avgs = avg_darknesses(training_data)
    print("\"Trained\"...")

    # On compte le nombre de chiffres correctement prédits pour le dataset de test
    print("\n>> 3. \"TESTING\" <<\n")
    print("Testing...")
    num_correct = sum(int(guess_digit(image, avgs) == digit) for image, digit in zip(test_data[0], test_data[1]))
    print("Tested...")

    n_test_data = len(test_data[1])
    print("Baseline classifier using average darkness of image.")
    print("{0} of {1} ({2}%) values are correct.".format(num_correct, n_test_data, num_correct * 100.0 / n_test_data))
    print("Tested...")

def avg_darknesses(training_data):
    """ Return a defaultdict whose keys are the digits 0 through 9.
    For each digit we compute a value which is the average darkness of
    training images containing that digit.  The darkness for any
    particular image is just the sum of the darknesses for each pixel."""

    digit_counts = defaultdict(int)
    darknesses = defaultdict(float)

    # Pour chaque couple, image / nombre à prédire
    for image, digit in zip(training_data[0], training_data[1]):

        # On compte le nombre d'images pour chaque chiffre
        digit_counts[digit] += 1

        # On compte l'obscurité de l'image pour chaque chiffre
        darknesses[digit] += sum(image)

    avgs = defaultdict(float)

    # Pour chaque chiffre
    for digit, n in digit_counts.items():

        # On associe chaque chiffre à une moyenne d'obscurité d'image
        avgs[digit] = darknesses[digit] / n

    return avgs

def guess_digit(image, avgs):
    """Return the digit whose average darkness in the training data is
    closest to the darkness of ``image``.  Note that ``avgs`` is
    assumed to be a defaultdict whose keys are 0...9, and whose values
    are the corresponding average darknesses across the training data."""

    # On calcule l'obscurité de l'image
    darkness = sum(image)

    # On calcule les différences entre l'obscurité de l'image et la moyenne d'obscurité de chaque chiffre
    distances = {k: abs(v-darkness) for k, v in avgs.items()}

    # On retourne le chiffre correspondant à une obscurité la plus proche de celle calculée
    return min(distances, key=distances.get)

if __name__ == "__main__":
    main()


file = open("lights.in", "r")
out = open("lights.out", "w")

n, m = [int(i) for i in file.readline().split()]
string = file.readline()
arr = [0] * n
while string:
    start, end = [(int(i) - 1) for i in string.split()]
    arr[start] += 1
    arr[end] += 1
    string = file.readline()
print(*arr, file=out)

file.close()
out.close()


import pandas as pd
from pandas import DataFrame
import numpy as np
# import groupbytime
from math import *

def Missing(cell, drive):
    Drive_Test_File = pd.read_csv(drive)
    # Drive_Test_File = Drive_Test_File.iloc[ : 200 , :].reset_index()
    File_size = Drive_Test_File.shape[0]
    if File_size > 300:
        step = 300
        end = int(File_size / step) * step
        remaining = File_size % step
        for i in range(0, end, step):
            drive_test = Drive_Test_File.iloc[i: i + step, :].reset_index()  # get all data
            A1, A2, A3, D1, D2, D3, D4, D5, D6, M1, M2, M3, M4, M5, M6 = calc(cell, drive_test)
        if remaining > 0:
            drive_test = Drive_Test_File.iloc[File_size - remaining:, :].reset_index()  # get all data
            A1, A2, A3, D1, D2, D3, D4, D5, D6, M1, M2, M3, M4, M5, M6 = calc(cell, drive_test)
    else:
        drive_test = Drive_Test_File.iloc[:, :].reset_index()  # get all data
        A1, A2, A3, D1, D2, D3, D4, D5, D6, M1, M2, M3, M4, M5, M6 = calc(cell, drive_test)

    A1['Distance'] = CalcDistanceKM(A1['Lat_Cell'], A1['Lon_Cell'], A1['drive_lat'], A1['drive_lon'])
    A2['Distance'] = CalcDistanceKM(A2['Lat_Cell'], A2['Lon_Cell'], A2['drive_lat'], A2['drive_lon'])
    A3['Distance'] = CalcDistanceKM(A3['Lat_Cell'], A3['Lon_Cell'], A3['drive_lat'], A3['drive_lon'])
    D1['Distance'] = CalcDistanceKM(D1['Lat_Cell'], D1['Lon_Cell'], D1['drive_lat'], D1['drive_lon'])
    D2['Distance'] = CalcDistanceKM(D2['Lat_Cell'], D2['Lon_Cell'], D2['drive_lat'], D2['drive_lon'])
    D3['Distance'] = CalcDistanceKM(D3['Lat_Cell'], D3['Lon_Cell'], D3['drive_lat'], D3['drive_lon'])
    D4['Distance'] = CalcDistanceKM(D4['Lat_Cell'], D4['Lon_Cell'], D4['drive_lat'], D4['drive_lon'])
    D5['Distance'] = CalcDistanceKM(D5['Lat_Cell'], D5['Lon_Cell'], D5['drive_lat'], D5['drive_lon'])
    D6['Distance'] = CalcDistanceKM(D6['Lat_Cell'], D6['Lon_Cell'], D6['drive_lat'], D6['drive_lon'])
    M1['Distance'] = CalcDistanceKM(M1['Lat_Cell'], M1['Lon_Cell'], M1['drive_lat'], M1['drive_lon'])
    M2['Distance'] = CalcDistanceKM(M2['Lat_Cell'], M2['Lon_Cell'], M2['drive_lat'], M2['drive_lon'])
    M3['Distance'] = CalcDistanceKM(M3['Lat_Cell'], M3['Lon_Cell'], M3['drive_lat'], M3['drive_lon'])
    M4['Distance'] = CalcDistanceKM(M4['Lat_Cell'], M4['Lon_Cell'], M4['drive_lat'], M4['drive_lon'])
    M5['Distance'] = CalcDistanceKM(M5['Lat_Cell'], M5['Lon_Cell'], M5['drive_lat'], M5['drive_lon'])
    M6['Distance'] = CalcDistanceKM(M6['Lat_Cell'], M6['Lon_Cell'], M6['drive_lat'], M6['drive_lon'])

    # filter the lists of A, M & D and getting the index that has the min distance
    A1 = A1.loc[A1.groupby(['ref_Index'])['Distance'].idxmin()].reset_index()
    A2 = A2.loc[A2.groupby(['ref_Index'])['Distance'].idxmin()].reset_index()
    A3 = A3.loc[A3.groupby(['ref_Index'])['Distance'].idxmin()].reset_index()
    M1 = M1.loc[M1.groupby(['ref_Index'])['Distance'].idxmin()].reset_index()
    M2 = M2.loc[M2.groupby(['ref_Index'])['Distance'].idxmin()].reset_index()
    M3 = M3.loc[M3.groupby(['ref_Index'])['Distance'].idxmin()].reset_index()
    M4 = M4.loc[M4.groupby(['ref_Index'])['Distance'].idxmin()].reset_index()
    M5 = M5.loc[M5.groupby(['ref_Index'])['Distance'].idxmin()].reset_index()
    M6 = M6.loc[M6.groupby(['ref_Index'])['Distance'].idxmin()].reset_index()
    D1 = D1.loc[D1.groupby(['ref_Index'])['Distance'].idxmin()].reset_index()
    D2 = D2.loc[D2.groupby(['ref_Index'])['Distance'].idxmin()].reset_index()
    D3 = D3.loc[D3.groupby(['ref_Index'])['Distance'].idxmin()].reset_index()
    D4 = D4.loc[D4.groupby(['ref_Index'])['Distance'].idxmin()].reset_index()
    D5 = D5.loc[D5.groupby(['ref_Index'])['Distance'].idxmin()].reset_index()
    D6 = D6.loc[D6.groupby(['ref_Index'])['Distance'].idxmin()].reset_index()

    # "merge=concat", merging A1 to all cells
    # on= ref_Index, coloum on which I want to perfom merge
    # how= inner (default value), take the intersections only"coloums which have the same ref_Index"
    A1_A2 = pd.merge(A2, A1, on="ref_Index", how="inner")
    A1_A3 = pd.merge(A3, A1, on="ref_Index", how="inner")
    A1_M1 = pd.merge(M1, A1, on="ref_Index", how="inner")
    A1_M2 = pd.merge(M2, A1, on="ref_Index", how="inner")
    A1_M3 = pd.merge(M3, A1, on="ref_Index", how="inner")
    A1_M4 = pd.merge(M4, A1, on="ref_Index", how="inner")
    A1_M5 = pd.merge(M5, A1, on="ref_Index", how="inner")
    A1_M6 = pd.merge(M6, A1, on="ref_Index", how="inner")
    A1_D1 = pd.merge(D1, A1, on="ref_Index", how="inner")
    A1_D2 = pd.merge(D2, A1, on="ref_Index", how="inner")
    A1_D3 = pd.merge(D3, A1, on="ref_Index", how="inner")
    A1_D4 = pd.merge(D4, A1, on="ref_Index", how="inner")
    A1_D5 = pd.merge(D5, A1, on="ref_Index", how="inner")
    A1_D6 = pd.merge(D6, A1, on="ref_Index", how="inner")

    # define A2 as the 1st cell and repeat merging again
    A1 = A1.rename(columns={'Cell1': 'Cell2'})
    A2 = A2.rename(columns={'Cell2': 'Cell1'})

    A2_A3 = pd.merge(A2, A3, on="ref_Index", how="inner")
    A2_M1 = pd.merge(A2, M1, on="ref_Index", how="inner")
    A2_M2 = pd.merge(A2, M2, on="ref_Index", how="inner")
    A2_M3 = pd.merge(A2, M3, on="ref_Index", how="inner")
    A2_M4 = pd.merge(A2, M4, on="ref_Index", how="inner")
    A2_M5 = pd.merge(A2, M5, on="ref_Index", how="inner")
    A2_M6 = pd.merge(A2, M6, on="ref_Index", how="inner")
    A2_D1 = pd.merge(A2, D1, on="ref_Index", how="inner")
    A2_D2 = pd.merge(A2, D2, on="ref_Index", how="inner")
    A2_D3 = pd.merge(A2, D3, on="ref_Index", how="inner")
    A2_D4 = pd.merge(A2, D4, on="ref_Index", how="inner")
    A2_D5 = pd.merge(A2, D5, on="ref_Index", how="inner")
    A2_D6 = pd.merge(A2, D6, on="ref_Index", how="inner")

    # define A3 as the 1st cell and repeat merging again
    A2 = A2.rename(columns={'Cell1': 'Cell2'})
    A3 = A3.rename(columns={'Cell2': 'Cell1'})

    A3_M1 = pd.merge(M1, A3, on="ref_Index", how="inner")
    A3_M2 = pd.merge(M2, A3, on="ref_Index", how="inner")
    A3_M3 = pd.merge(M3, A3, on="ref_Index", how="inner")
    A3_M4 = pd.merge(M4, A3, on="ref_Index", how="inner")
    A3_M5 = pd.merge(M5, A3, on="ref_Index", how="inner")
    A3_M6 = pd.merge(M6, A3, on="ref_Index", how="inner")
    A3_D1 = pd.merge(D1, A3, on="ref_Index", how="inner")
    A3_D2 = pd.merge(D2, A3, on="ref_Index", how="inner")
    A3_D3 = pd.merge(D3, A3, on="ref_Index", how="inner")
    A3_D4 = pd.merge(D4, A3, on="ref_Index", how="inner")
    A3_D5 = pd.merge(D5, A3, on="ref_Index", how="inner")
    A3_D6 = pd.merge(D6, A3, on="ref_Index", how="inner")

    # list the neighbours  A&M
    Combination_NBR = pd.concat(
        [A1_A2, A1_A3, A2_A3, A1_M1, A1_M2, A1_M3, A1_M4, A1_M5, A1_M6, A2_M1, A2_M2, A2_M3, A2_M4, A2_M5, A2_M6,
         A3_M1, A3_M2, A3_M3, A3_M4, A3_M5, A3_M6], sort=False)

    # list the Missing     A&D
    Combination_Missing = pd.concat(
        [A1_D1, A1_D2, A1_D3, A1_D4, A1_D5, A1_D6, A2_D1, A2_D2, A2_D3, A2_D4, A2_D5, A2_D6, A3_D1,
         A3_D2, A3_D3, A3_D4, A3_D5, A3_D6], sort=False)

    Combination_NBR['State'] = 'Neighbour'
    Combination_Missing['State'] = 'Missed'

    # concat, bt7tohom wra ba3d coloum by coloum
    Combination = pd.concat([Combination_NBR, Combination_Missing], sort=False)
    Combination = Combination[['Cell1', 'Cell2', 'State']]

    #     print(Combination)

    Combination.to_csv('Combination.csv', index=True)
    Combination = pd.read_csv('Combination.csv')

    Combination = Combination.groupby(['Cell1', 'Cell2', 'State'])
    Combination = Combination.count().reset_index()
    Combination = Combination.rename(columns={'Unnamed: 0': 'Sum'})
    Combination.to_csv('Combination.csv', index=True)

    l = Combination.size
    Final = pd.DataFrame(columns=['Cell1', 'Cell2', 'Sum_NBR', 'SUM_Miss'])
    for i in range(Combination.shape[0]):  # loop on row
        Sum_NBR = 0
        Sum_Miss = 0
        for j in range(Combination.shape[0]):
            if (Combination['Cell1'][i] == Combination['Cell1'][j] and Combination['Cell2'][i] == Combination['Cell2'][
                j]) \
                    or (Combination['Cell1'][i] == Combination['Cell2'][j] and Combination['Cell2'][i] ==
                        Combination['Cell1'][j]):
                if Combination['State'][j] == 'Neighbour':
                    Sum_NBR += Combination['Sum'][j]
                else:
                    Sum_Miss += Combination['Sum'][j]
        Final = Final.append({'Cell1': Combination['Cell1'][i],
                              'Cell2': Combination['Cell2'][i],
                              'Sum_NBR': Sum_NBR, 'SUM_Miss': Sum_Miss}, ignore_index=True)

    # frozen set 34an amn3 edaft ay 7aga leha b3d kda
    Final = Final[~Final[['Cell1', 'Cell2']].apply(frozenset, axis=1).duplicated()]
    Final.to_csv('test.csv', index=True)
    Final = Final.reset_index()
    Final.to_csv('New.csv')

    Analysiss = pd.DataFrame(columns=['Cell1', 'Cell2', 'Sum_NBR', 'SUM_Miss', 'State'])

    for k in range(Final.shape[0]):
        if Final['SUM_Miss'][k] + Final['Sum_NBR'][k] < ceil(10):
            Analysiss = Analysiss.append({'Cell1': Final['Cell1'][k],
                                          'Cell2': Final['Cell2'][k],
                                          'Sum_NBR': Final['Sum_NBR'][k],
                                          'SUM_Miss': Final['SUM_Miss'][k],
                                          'State': "Can not decide"}, ignore_index=True)
        else:
            if Final['Sum_NBR'][k] == 0 and Final['SUM_Miss'][k] > 0:
                Analysiss = Analysiss.append({'Cell1': Final['Cell1'][k],
                                              'Cell2': Final['Cell2'][k],
                                              'Sum_NBR': Final['Sum_NBR'][k],
                                              'SUM_Miss': Final['SUM_Miss'][k],
                                              'State': "Missed Neighbour"}, ignore_index=True)

            elif Final['SUM_Miss'][k] / Final['Sum_NBR'][k] < 0.4:
                Analysiss = Analysiss.append({'Cell1': Final['Cell1'][k],
                                              'Cell2': Final['Cell2'][k],
                                              'Sum_NBR': Final['Sum_NBR'][k],
                                              'SUM_Miss': Final['SUM_Miss'][k],
                                              'State': "Normal Relation"}, ignore_index=True)
            else:
                Analysiss = Analysiss.append({'Cell1': Final['Cell1'][k],
                                              'Cell2': Final['Cell2'][k],
                                              'Sum_NBR': Final['Sum_NBR'][k],
                                              'SUM_Miss': Final['SUM_Miss'][k],
                                              'State': "Missed Neighbour"}, ignore_index=True)
    # print(Analysiss)
    Analysiss.to_csv('Missing_NBR_Analysis_test.csv')

def CalcDistanceKM(a_lat, a_lng, b_lat, b_lng):
    R = 6371  # earth radius in km
    a_lat = np.radians(a_lat)
    a_lng = np.radians(a_lng)
    b_lat = np.radians(b_lat)
    b_lng = np.radians(b_lng)
    d_lat = b_lat - a_lat
    d_lng = b_lng - a_lng
    d_lat_sq = np.sin(d_lat / 2) ** 2
    d_lng_sq = np.sin(d_lng / 2) ** 2
    a = d_lat_sq + np.cos(a_lat) * np.cos(b_lat) * d_lng_sq
    c = 2 * np.arctan2(np.sqrt(a), np.sqrt(1 - a))
    return R * c

def calc(x, Drive_Test_File):
    Cell_file = pd.read_csv(x)
    # Drive_Test_File = pd.read_csv(y)
    Cells = Cell_file[['Region', 'Cell', 'Lat', 'Lon', 'SC', 'UARFCN']]
    drive_test = Drive_Test_File[['Latitude', 'Longitude',
                                  'Categorized PSC:A1', 'Categorized UARFCN_DL:A1',
                                  'Categorized PSC:A2', 'Categorized UARFCN_DL:A2',
                                  'Categorized PSC:A3', 'Categorized UARFCN_DL:A3',
                                  'Categorized PSC:D1', 'Categorized UARFCN_DL:D1',
                                  'Categorized PSC:D2', 'Categorized UARFCN_DL:D2',
                                  'Categorized PSC:D3', 'Categorized UARFCN_DL:D3',
                                  'Categorized PSC:D4', 'Categorized UARFCN_DL:D4',
                                  'Categorized PSC:D5', 'Categorized UARFCN_DL:D5',
                                  'Categorized PSC:D6', 'Categorized UARFCN_DL:D6',
                                  'Categorized PSC:M1', 'Categorized UARFCN_DL:M1',
                                  'Categorized PSC:M2', 'Categorized UARFCN_DL:M2',
                                  'Categorized PSC:M3', 'Categorized UARFCN_DL:M3',
                                  'Categorized PSC:M4', 'Categorized UARFCN_DL:M4',
                                  'Categorized PSC:M5', 'Categorized UARFCN_DL:M5',
                                  'Categorized PSC:M6', 'Categorized UARFCN_DL:M6']]

    drive_test = drive_test.iloc[:, :].reset_index()  # get all data

    # Drop NAN columns#
    drive_test = drive_test[np.isfinite(drive_test['Latitude'])]
    drive_test = drive_test[np.isfinite(drive_test['Longitude'])]
    drive_test = drive_test.reset_index()

    # get data
    A1 = pd.DataFrame(columns=['ref_Index', 'Cell1', 'Distance', 'drive_lat', 'drive_lon', 'Lat_Cell', 'Lon_Cell'])
    A2 = pd.DataFrame(columns=['ref_Index', 'Cell2', 'Distance', 'drive_lat', 'drive_lon', 'Lat_Cell', 'Lon_Cell'])
    A3 = pd.DataFrame(columns=['ref_Index', 'Cell2', 'Distance', 'drive_lat', 'drive_lon', 'Lat_Cell', 'Lon_Cell'])
    D1 = pd.DataFrame(columns=['ref_Index', 'Cell2', 'Distance', 'drive_lat', 'drive_lon', 'Lat_Cell', 'Lon_Cell'])
    D2 = pd.DataFrame(columns=['ref_Index', 'Cell2', 'Distance', 'drive_lat', 'drive_lon', 'Lat_Cell', 'Lon_Cell'])
    D3 = pd.DataFrame(columns=['ref_Index', 'Cell2', 'Distance', 'drive_lat', 'drive_lon', 'Lat_Cell', 'Lon_Cell'])
    D4 = pd.DataFrame(columns=['ref_Index', 'Cell2', 'Distance', 'drive_lat', 'drive_lon', 'Lat_Cell', 'Lon_Cell'])
    D5 = pd.DataFrame(columns=['ref_Index', 'Cell2', 'Distance', 'drive_lat', 'drive_lon', 'Lat_Cell', 'Lon_Cell'])
    D6 = pd.DataFrame(columns=['ref_Index', 'Cell2', 'Distance', 'drive_lat', 'drive_lon', 'Lat_Cell', 'Lon_Cell'])
    M1 = pd.DataFrame(columns=['ref_Index', 'Cell2', 'Distance', 'drive_lat', 'drive_lon', 'Lat_Cell', 'Lon_Cell'])
    M2 = pd.DataFrame(columns=['ref_Index', 'Cell2', 'Distance', 'drive_lat', 'drive_lon', 'Lat_Cell', 'Lon_Cell'])
    M3 = pd.DataFrame(columns=['ref_Index', 'Cell2', 'Distance', 'drive_lat', 'drive_lon', 'Lat_Cell', 'Lon_Cell'])
    M4 = pd.DataFrame(columns=['ref_Index', 'Cell2', 'Distance', 'drive_lat', 'drive_lon', 'Lat_Cell', 'Lon_Cell'])
    M5 = pd.DataFrame(columns=['ref_Index', 'Cell2', 'Distance', 'drive_lat', 'drive_lon', 'Lat_Cell', 'Lon_Cell'])
    M6 = pd.DataFrame(columns=['ref_Index', 'Cell2', 'Distance', 'drive_lat', 'drive_lon', 'Lat_Cell', 'Lon_Cell'])
    # Region filter
    cell = Cells[['Region', 'Lat', 'Lon']]
    drive1 = pd.DataFrame(columns=['Latitude', 'Longitude'])
    drive1 = Drive_Test_File[['Latitude', 'Longitude']]
    drive1 = drive1.iloc[:200, :]
    Cells_size = cell.shape[0]
    drive1 = drive1.iloc[np.full(Cells_size, 0)].reset_index()
    cell['region'] = np.where(
        (abs(cell['Lat'] - drive1['Latitude']) < 0.1) & (abs(cell['Lon'] - drive1['Longitude']) < 0.1), 'True', 'False')
    cell = cell[cell['region'] == 'True']
    cell_region = cell.iloc[0, 0]
    Cells = Cells[Cells['Region'] == cell_region].reset_index()
    Cells_size = Cells.shape[0]
    ##

    #
    for i in range(0, drive_test.shape[0], 1):
        drive_sample = pd.DataFrame({'drive_lat': drive_test['Latitude'][i],
                                     'drive_lon': drive_test['Longitude'][i],
                                     'PSC_A1': drive_test['Categorized PSC:A1'][i],
                                     'UARFCN_A1': drive_test['Categorized UARFCN_DL:A1'][i],
                                     'PSC_A2': drive_test['Categorized PSC:A2'][i],
                                     'UARFCN_A2': drive_test['Categorized UARFCN_DL:A2'][i],
                                     'PSC_A3': drive_test['Categorized PSC:A3'][i],
                                     'UARFCN_A3': drive_test['Categorized UARFCN_DL:A3'][i],
                                     'PSC_D1': drive_test['Categorized PSC:D1'][i],
                                     'UARFCN_D1': drive_test['Categorized UARFCN_DL:D1'][i],
                                     'PSC_D2': drive_test['Categorized PSC:D2'][i],
                                     'UARFCN_D2': drive_test['Categorized UARFCN_DL:D2'][i],
                                     'PSC_D3': drive_test['Categorized PSC:D3'][i],
                                     'UARFCN_D3': drive_test['Categorized UARFCN_DL:D3'][i],
                                     'PSC_D4': drive_test['Categorized PSC:D4'][i],
                                     'UARFCN_D4': drive_test['Categorized UARFCN_DL:D4'][i],
                                     'PSC_D5': drive_test['Categorized PSC:D5'][i],
                                     'UARFCN_D5': drive_test['Categorized UARFCN_DL:D5'][i],
                                     'PSC_D6': drive_test['Categorized PSC:D6'][i],
                                     'UARFCN_D6': drive_test['Categorized UARFCN_DL:D6'][i],
                                     'PSC_M1': drive_test['Categorized PSC:M1'][i],
                                     'UARFCN_M1': drive_test['Categorized UARFCN_DL:M1'][i],
                                     'PSC_M2': drive_test['Categorized PSC:M2'][i],
                                     'UARFCN_M2': drive_test['Categorized UARFCN_DL:M2'][i],
                                     'PSC_M3': drive_test['Categorized PSC:M3'][i],
                                     'UARFCN_M3': drive_test['Categorized UARFCN_DL:M3'][i],
                                     'PSC_M4': drive_test['Categorized PSC:M4'][i],
                                     'UARFCN_M4': drive_test['Categorized UARFCN_DL:M4'][i],
                                     'PSC_M5': drive_test['Categorized PSC:M5'][i],
                                     'UARFCN_M5': drive_test['Categorized UARFCN_DL:M5'][i],
                                     'PSC_M6': drive_test['Categorized PSC:M6'][i],
                                     'UARFCN_M6': drive_test['Categorized UARFCN_DL:M6'][i]},
                                    columns=['drive_lat', 'drive_lon',
                                             'PSC_A1', 'UARFCN_A1', 'PSC_A2', 'UARFCN_A2', 'PSC_A3', 'UARFCN_A3',
                                             'PSC_D1', 'UARFCN_D1', 'PSC_D2', 'UARFCN_D2', 'PSC_D3', 'UARFCN_D3',
                                             'PSC_D4', 'UARFCN_D4', 'PSC_D5', 'UARFCN_D5', 'PSC_D6', 'UARFCN_D6',
                                             'PSC_M1', 'UARFCN_M1', 'PSC_M2', 'UARFCN_M2', 'PSC_M3', 'UARFCN_M3',
                                             'PSC_M4', 'UARFCN_M4', 'PSC_M5', 'UARFCN_M5', 'PSC_M6', 'UARFCN_M6'],
                                    index=[0])

        drive_sample = drive_sample.iloc[np.full(Cells_size, 0)]
        drive_sample = drive_sample.reset_index()
        Cells_A1 = Cells
        Cells_A2 = Cells
        Cells_A3 = Cells
        Cells_D1 = Cells
        Cells_D2 = Cells
        Cells_D3 = Cells
        Cells_D4 = Cells
        Cells_D5 = Cells
        Cells_D6 = Cells
        Cells_M1 = Cells
        Cells_M2 = Cells
        Cells_M3 = Cells
        Cells_M4 = Cells
        Cells_M5 = Cells
        Cells_M6 = Cells

        # get A1
        Cells_A1['Cond'] = np.where((abs(drive_sample['drive_lat'] - Cells['Lat']) < 0.1) & (
                    abs(drive_sample['drive_lon'] - Cells['Lon']) < 0.1) & (drive_sample['PSC_A1'] == Cells['SC']) & (
                                                drive_sample['UARFCN_A1'] == Cells['UARFCN']), 'True', 'False')
        Cells_A1 = Cells_A1[Cells_A1['Cond'] == "True"].reset_index()
        if Cells_A1.shape[0] > 0:
            A1 = A1.append({'ref_Index': int(i), 'Cell1': Cells_A1['Cell'][0],
                            'Lat_Cell': Cells_A1['Lat'][0],
                            'Lon_Cell': Cells_A1['Lon'][0],
                            'drive_lat': drive_sample['drive_lat'][0],
                            'drive_lon': drive_sample['drive_lon'][0]},
                           ignore_index=True)
            # get A2
        Cells_A2['Cond'] = np.where((abs(drive_sample['drive_lat'] - Cells['Lat']) < 0.1) & (
                    abs(drive_sample['drive_lon'] - Cells['Lon']) < 0.1) & (drive_sample['PSC_A2'] == Cells['SC']) & (
                                                drive_sample['UARFCN_A2'] == Cells['UARFCN']), 'True', 'False')
        Cells_A2 = Cells_A2[Cells_A2['Cond'] == "True"].reset_index()
        if Cells_A2.shape[0] > 0:
            A2 = A2.append({'ref_Index': int(i), 'Cell2': Cells_A2['Cell'][0],
                            'drive_lat': drive_sample['drive_lat'][0],
                            'drive_lon': drive_sample['drive_lon'][0],
                            'Lat_Cell': Cells_A2['Lat'][0],
                            'Lon_Cell': Cells_A2['Lon'][0]},
                           ignore_index=True)

        # get A3
        Cells_A3['Cond'] = np.where((abs(drive_sample['drive_lat'] - Cells['Lat']) < 0.1) & (
                    abs(drive_sample['drive_lon'] - Cells['Lon']) < 0.1) & (drive_sample['PSC_A3'] == Cells['SC']) & (
                                                drive_sample['UARFCN_A3'] == Cells['UARFCN']), 'True', 'False')
        Cells_A3 = Cells_A3[Cells_A3['Cond'] == "True"].reset_index()
        if Cells_A3.shape[0] > 0:
            A3 = A3.append({'ref_Index': int(i), 'Cell2': Cells_A3['Cell'][0],
                            'drive_lat': drive_sample['drive_lat'][0],
                            'drive_lon': drive_sample['drive_lon'][0],
                            'Lat_Cell': Cells_A3['Lat'][0],
                            'Lon_Cell': Cells_A3['Lon'][0]},
                           ignore_index=True)

        # get D1
        Cells_D1['Cond'] = np.where((abs(drive_sample['drive_lat'] - Cells['Lat']) < 0.1) & (
                    abs(drive_sample['drive_lon'] - Cells['Lon']) < 0.1) & (drive_sample['PSC_D1'] == Cells['SC']) & (
                                                drive_sample['UARFCN_D1'] == Cells['UARFCN']), 'True', 'False')
        Cells_D1 = Cells_D1[Cells_D1['Cond'] == "True"].reset_index()
        if Cells_D1.shape[0] > 0:
            D1 = D1.append({'ref_Index': int(i), 'Cell2': Cells_D1['Cell'][0],
                            'drive_lat': drive_sample['drive_lat'][0],
                            'drive_lon': drive_sample['drive_lon'][0],
                            'Lat_Cell': Cells_D1['Lat'][0],
                            'Lon_Cell': Cells_D1['Lon'][0]},
                           ignore_index=True)

            # get D2
        Cells_D2['Cond'] = np.where((abs(drive_sample['drive_lat'] - Cells['Lat']) < 0.1) & (
                    abs(drive_sample['drive_lon'] - Cells['Lon']) < 0.1) & (drive_sample['PSC_D2'] == Cells['SC']) & (
                                                drive_sample['UARFCN_D2'] == Cells['UARFCN']), 'True', 'False')
        Cells_D2 = Cells_D2[Cells_D2['Cond'] == "True"].reset_index()
        if Cells_D2.shape[0] > 0:
            D2 = D2.append({'ref_Index': int(i), 'Cell2': Cells_D2['Cell'][0],
                            'drive_lat': drive_sample['drive_lat'][0],
                            'drive_lon': drive_sample['drive_lon'][0],
                            'Lat_Cell': Cells_D2['Lat'][0],
                            'Lon_Cell': Cells_D2['Lon'][0]},
                           ignore_index=True)

        # get D3
        Cells_D3['Cond'] = np.where((abs(drive_sample['drive_lat'] - Cells['Lat']) < 0.1) & (
                    abs(drive_sample['drive_lon'] - Cells['Lon']) < 0.1) & (drive_sample['PSC_D3'] == Cells['SC']) & (
                                                drive_sample['UARFCN_D3'] == Cells['UARFCN']), 'True', 'False')
        Cells_D3 = Cells_D3[Cells_D3['Cond'] == "True"].reset_index()
        if Cells_D3.shape[0] > 0:
            D3 = D3.append({'ref_Index': int(i), 'Cell2': Cells_D3['Cell'][0],
                            'drive_lat': drive_sample['drive_lat'][0],
                            'drive_lon': drive_sample['drive_lon'][0],
                            'Lat_Cell': Cells_D3['Lat'][0],
                            'Lon_Cell': Cells_D3['Lon'][0]},
                           ignore_index=True)
        # get D4
        Cells_D4['Cond'] = np.where((abs(drive_sample['drive_lat'] - Cells['Lat']) < 0.1) & (
                    abs(drive_sample['drive_lon'] - Cells['Lon']) < 0.1) & (drive_sample['PSC_D4'] == Cells['SC']) & (
                                                drive_sample['UARFCN_D4'] == Cells['UARFCN']), 'True', 'False')
        Cells_D4 = Cells_D4[Cells_D4['Cond'] == "True"].reset_index()
        if Cells_D4.shape[0] > 0:
            D4 = D4.append({'ref_Index': int(i), 'Cell2': Cells_D4['Cell'][0],
                            'drive_lat': drive_sample['drive_lat'][0],
                            'drive_lon': drive_sample['drive_lon'][0],
                            'Lat_Cell': Cells_D4['Lat'][0],
                            'Lon_Cell': Cells_D4['Lon'][0]},
                           ignore_index=True)

            # get D5
        Cells_D5['Cond'] = np.where((abs(drive_sample['drive_lat'] - Cells['Lat']) < 0.1) & (
                    abs(drive_sample['drive_lon'] - Cells['Lon']) < 0.1) & (drive_sample['PSC_D5'] == Cells['SC']) & (
                                                drive_sample['UARFCN_D5'] == Cells['UARFCN']), 'True', 'False')
        Cells_D5 = Cells_D5[Cells_D5['Cond'] == "True"].reset_index()
        if Cells_D5.shape[0] > 0:
            D5 = D5.append({'ref_Index': int(i), 'Cell2': Cells_D5['Cell'][0],
                            'drive_lat': drive_sample['drive_lat'][0],
                            'drive_lon': drive_sample['drive_lon'][0],
                            'Lat_Cell': Cells_D5['Lat'][0],
                            'Lon_Cell': Cells_D5['Lon'][0]},
                           ignore_index=True)

        # get D6
        Cells_D6['Cond'] = np.where((abs(drive_sample['drive_lat'] - Cells['Lat']) < 0.1) & (
                    abs(drive_sample['drive_lon'] - Cells['Lon']) < 0.1) & (drive_sample['PSC_D6'] == Cells['SC']) & (
                                                drive_sample['UARFCN_D6'] == Cells['UARFCN']), 'True', 'False')
        Cells_D6 = Cells_D6[Cells_D6['Cond'] == "True"].reset_index()
        if Cells_D6.shape[0] > 0:
            D6 = D6.append({'ref_Index': int(i), 'Cell2': Cells_D6['Cell'][0],
                            'drive_lat': drive_sample['drive_lat'][0],
                            'drive_lon': drive_sample['drive_lon'][0],
                            'Lat_Cell': Cells_D6['Lat'][0],
                            'Lon_Cell': Cells_D6['Lon'][0]},
                           ignore_index=True)

        # get M1
        Cells_M1['Cond'] = np.where((abs(drive_sample['drive_lat'] - Cells['Lat']) < 0.1) & (
                    abs(drive_sample['drive_lon'] - Cells['Lon']) < 0.1) & (drive_sample['PSC_M1'] == Cells['SC']) & (
                                                drive_sample['UARFCN_M1'] == Cells['UARFCN']), 'True', 'False')
        Cells_M1 = Cells_M1[Cells_M1['Cond'] == "True"].reset_index()
        if Cells_M1.shape[0] > 0:
            M1 = M1.append({'ref_Index': int(i), 'Cell2': Cells_M1['Cell'][0],
                            'drive_lat': drive_sample['drive_lat'][0],
                            'drive_lon': drive_sample['drive_lon'][0],
                            'Lat_Cell': Cells_M1['Lat'][0],
                            'Lon_Cell': Cells_M1['Lon'][0]},
                           ignore_index=True)

            # get M2
        Cells_M2['Cond'] = np.where((abs(drive_sample['drive_lat'] - Cells['Lat']) < 0.1) & (
                    abs(drive_sample['drive_lon'] - Cells['Lon']) < 0.1) & (drive_sample['PSC_M2'] == Cells['SC']) & (
                                                drive_sample['UARFCN_M2'] == Cells['UARFCN']), 'True', 'False')
        Cells_M2 = Cells_M2[Cells_M2['Cond'] == "True"].reset_index()
        if Cells_M2.shape[0] > 0:
            M2 = M2.append({'ref_Index': int(i), 'Cell2': Cells_M2['Cell'][0],
                            'drive_lat': drive_sample['drive_lat'][0],
                            'drive_lon': drive_sample['drive_lon'][0],
                            'Lat_Cell': Cells_M2['Lat'][0],
                            'Lon_Cell': Cells_M2['Lon'][0]},
                           ignore_index=True)

        # get M3
        Cells_M3['Cond'] = np.where((abs(drive_sample['drive_lat'] - Cells['Lat']) < 0.1) & (
                    abs(drive_sample['drive_lon'] - Cells['Lon']) < 0.1) & (drive_sample['PSC_M3'] == Cells['SC']) & (
                                                drive_sample['UARFCN_M3'] == Cells['UARFCN']), 'True', 'False')
        Cells_M3 = Cells_M3[Cells_M3['Cond'] == "True"].reset_index()
        if Cells_M3.shape[0] > 0:
            M3 = M3.append({'ref_Index': int(i), 'Cell2': Cells_M3['Cell'][0],
                            'drive_lat': drive_sample['drive_lat'][0],
                            'drive_lon': drive_sample['drive_lon'][0],
                            'Lat_Cell': Cells_M3['Lat'][0],
                            'Lon_Cell': Cells_M3['Lon'][0]},
                           ignore_index=True)

        # get M4
        Cells_M4['Cond'] = np.where((abs(drive_sample['drive_lat'] - Cells['Lat']) < 0.1) & (
                    abs(drive_sample['drive_lon'] - Cells['Lon']) < 0.1) & (drive_sample['PSC_M4'] == Cells['SC']) & (
                                                drive_sample['UARFCN_M4'] == Cells['UARFCN']), 'True', 'False')
        Cells_M4 = Cells_M4[Cells_M4['Cond'] == "True"].reset_index()
        if Cells_M4.shape[0] > 0:
            M4 = M4.append({'ref_Index': int(i), 'Cell2': Cells_M4['Cell'][0],
                            'drive_lat': drive_sample['drive_lat'][0],
                            'drive_lon': drive_sample['drive_lon'][0],
                            'Lat_Cell': Cells_M4['Lat'][0],
                            'Lon_Cell': Cells_M4['Lon'][0]},
                           ignore_index=True)

        # get M5
        Cells_M5['Cond'] = np.where((abs(drive_sample['drive_lat'] - Cells['Lat']) < 0.1) & (
                    abs(drive_sample['drive_lon'] - Cells['Lon']) < 0.1) & (drive_sample['PSC_M5'] == Cells['SC']) & (
                                                drive_sample['UARFCN_M5'] == Cells['UARFCN']), 'True', 'False')
        Cells_M5 = Cells_M5[Cells_M5['Cond'] == "True"].reset_index()
        if Cells_M5.shape[0] > 0:
            M5 = M5.append({'ref_Index': int(i), 'Cell2': Cells_M5['Cell'][0],
                            'drive_lat': drive_sample['drive_lat'][0],
                            'drive_lon': drive_sample['drive_lon'][0],
                            'Lat_Cell': Cells_M5['Lat'][0],
                            'Lon_Cell': Cells_M5['Lon'][0]},
                           ignore_index=True)
        # get M6
        Cells_M6['Cond'] = np.where((abs(drive_sample['drive_lat'] - Cells['Lat']) < 0.1) & (
                    abs(drive_sample['drive_lon'] - Cells['Lon']) < 0.1) & (drive_sample['PSC_M6'] == Cells['SC']) & (
                                                drive_sample['UARFCN_M6'] == Cells['UARFCN']), 'True', 'False')
        Cells_M6 = Cells_M6[Cells_M6['Cond'] == "True"].reset_index()
        if Cells_M6.shape[0] > 0:
            M6 = M6.append({'ref_Index': int(i), 'Cell2': Cells_M6['Cell'][0],
                            'drive_lat': drive_sample['drive_lat'][0],
                            'drive_lon': drive_sample['drive_lon'][0],
                            'Lat_Cell': Cells_M6['Lat'][0],
                            'Lon_Cell': Cells_M6['Lon'][0]},
                           ignore_index=True)

    return A1, A2, A3, D1, D2, D3, D4, D5, D6, M1, M2, M3, M4, M5, M6


class Solution:
    def letterCombinations(self, digits: str) -> List[str]:
        dictionary = {
            '2':'abc',
            '3':'def',
            '4':'ghi',
            '5':'jkl',
            '6':'mno',
            '7':'pqrs',
            '8':'tuv',
            '9':'wxyz'
        }

        # if input is empty return empty list
        if not digits :
            return []

        # function to generate combination
        def fun(index, path) :
            if len(path) == len(digits) :
                combinations.append(path)
                return

            # current digit
            current_digit = digits[index]

            # take the letters associated with current digit
            letters = dictionary[current_digit]

            # take next digit and update path
            for letter in letters :
                fun(index+1, path+letter)

        combinations = []
        fun(0, '')
        return combinations


import torch
from torch.utils.data import DataLoader

class VariableLengthLoader:
    def __init__(self, loader, num_iters):
        self.loader = loader
        self.num_iters = num_iters
        self._cur_iters = 0

    def __iter__(self):
        while True:
            for elem in self.loader:
                yield elem
                self._cur_iters += 1
                if self._cur_iters == self.num_iters:
                    self._cur_iters = 0
                    return

    def __len__(self):
        return self.num_iters

def get_dataloaders(train_ds, val_ds, config):
    train_loader = None
    if train_ds is not None:
        train_loader = DataLoader(
            train_ds, config.train_batch_size, shuffle=True,
            num_workers=config.train_num_workers, collate_fn=id_collator
        )
        train_loader = VariableLengthLoader(train_loader,
                                            config.epoch_num_iters)

    val_loader = None
    if val_ds is not None:
        val_loader = DataLoader(
            val_ds, config.val_batch_size, shuffle=True,
            num_workers=config.val_num_workers, collate_fn=id_collator
        )
    return train_loader, val_loader

def id_collator(objects):
    '''
    stacks objects along batch axis
    '''
    x, y = list(zip(*objects))
    return torch.stack(x, dim=0), torch.stack(y, dim=0)


import csv

infile = open("customers.csv", "r")

outfile = open("customer_country.csv", "w")

countryfile = csv.reader(infile, delimiter=",")

counter = 0

for record in countryfile:
    outfile.write(record[1] + " " + record[2] + " , " + record[4] + "\n")
    counter += 1

print("There are " + str(counter) + " customers.")

outfile.close()


r"""
Pytorch Pipeline.
https://keras.io/api/models/
https://github.com/PyTorchLightning/pytorch-lightning
https://github.com/skorch-dev/skorch
https://pytorch.org/tutorials/beginner/saving_loading_models.html
https://discuss.pytorch.org/t/when-does-pytorch-dataset-or-dataloader-class-convert-numpy-array-to-tensor/63980
"""

import os
import time
from copy import deepcopy

import numpy as np
import torch
import torch.nn as nn
import torch.nn.functional as F
from torch.utils.data import TensorDataset, Subset
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter

from byob.utils import to_array, to_tensor, as_tensor

class Pipeline(object):

    def __init__(self, conf, model):
        super(Pipeline, self).__init__()

        self.ml_task = conf['ml_task']
        assert self.ml_task in ('BIN', 'MUL', 'CLS', 'REG', )
        self.dataset = conf['dataset']
        self.model = model
        self.model_name = type(model).__name__
        # self.model_name = model.__class__.__name__.lower()

        self.verbose = conf.get('verbose', False)
        self.log_steps = conf.get('log_steps', 100)
        self.ckpt_freq = conf.get('ckpt_freq', 1)
        self.output_dir = conf.get('output_dir', './output')

        self.model_dir = os.path.join(self.output_dir, 'models')
        if not os.path.exists(self.model_dir):
            os.makedirs(self.model_dir, exist_ok=True)
        self.ckpt_dir = os.path.join(self.output_dir, 'checkpoints')
        if not os.path.exists(self.ckpt_dir):
            os.makedirs(self.ckpt_dir, exist_ok=True)
        self.hist_dir = os.path.join(self.output_dir, 'historys')
        if not os.path.exists(self.hist_dir):
            os.makedirs(self.hist_dir, exist_ok=True)

        self.optimizer = torch.optim.Adam(model.parameters(), lr=conf['lr'], weight_decay=conf['weight_decay'])
        self.loss_fn = None
        self.metrics = {}

        self.history = {}
        self.best_epoch = None
        self.total_step = 0
        self.cur_epoch = 0  # current epoch
        self.cur_step = 0  # current step within the epoch
        self.loss = 0.0  # current epoch

        self.device = conf['device']
        # device = torch.device("cpu")
        # device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
        # self.device = torch.device(conf['device'])
        # if conf['device'] == 'cpu':
        #     device = torch.device('cpu')
        # else:
        #     device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
        # self.device = device

        if self.verbose:
            print('-' * 80)
            for idx, m in enumerate(model.modules()):
                print(idx, '->', m)
            print('-' * 80)
            for param in model.parameters():
                print(type(param.data), param.size())
            print('-' * 80)
            print(model.state_dict().keys())
            print('-' * 80)

    def compile(self, optimizer=None, loss_fn=None, metrics=None):
        r"""
        https://keras.io/api/models/model_training_apis/#compile-method
        model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])
        """
        if optimizer is not None:
            self.optimizer = optimizer
        if loss_fn is not None:
            self.loss_fn = loss_fn
        self.metrics = {} if metrics is None else metrics

    def fit(self, train_ds, valid_ds, batch_size=128, num_epochs=1):
        r"""
        https://keras.io/api/models/model_training_apis/#fit-method
        """
        self.history.clear()
        best_valid_loss = float("inf")
        for epoch in range(1, num_epochs + 1):
            self.cur_epoch += 1
            self.history.setdefault('epoch', []).append(self.cur_epoch)
            print('-' * 80)
            start_time = time.time()
            hist = self.train(train_ds, batch_size)
            elapsed = time.time() - start_time
            # mins, secs = elapsed // 60, elapsed % 60
            loss, acc = hist['loss'], hist['accuracy']
            # print(type(loss), type(acc), loss.shape, acc.shape, loss, acc)
            self.history.setdefault('train loss', []).append(float(loss))
            self.history.setdefault('train acc', []).append(float(acc))
            self.loss = loss
            print('-' * 80)
            if valid_ds is None:
                # print(f'\ttrain loss: {train_loss:.4f}\t|\ttrain acc: {train_acc * 100:.2f}%')
                print('| epoch {:3d}/{:3d} | time: {:5.2f}s | loss {:5.4f} | acc {:5.4f}'.format(
                    epoch, num_epochs, elapsed, hist['loss'], hist['accuracy'] * 100))
            else:
                start_time = time.time()
                valid_hist = self.evaluate(valid_ds, 2 * batch_size)
                valid_elapsed = int(time.time() - start_time)
                valid_loss, valid_acc = valid_hist['loss'], valid_hist['accuracy']
                self.history.setdefault('valid loss', []).append(float(valid_loss))
                self.history.setdefault('valid acc', []).append(float(valid_acc))
                if valid_hist['loss'] < best_valid_loss:
                    best_valid_loss = valid_hist['loss']
                    self.best_epoch = epoch
                # print(f'\tvalid loss: {valid_loss:.4f}\t|\tvalid acc: {valid_acc * 100:.2f}%')
                print('| epoch {:3d}/{:3d} | train time {:5.2f}s | train loss {:5.4f} | train acc {:5.4f} | '
                      'valid time {:5.2f}s | valid loss {:5.4f} | valid acc {:5.4f}'.format(
                       epoch, num_epochs, elapsed, hist['loss'], hist['accuracy'] * 100,
                       valid_elapsed, valid_hist['loss'], valid_hist['accuracy'] * 100))
            # print('-' * 80)
            # self.optimizer.scheduler.step()
            if epoch % self.ckpt_freq == 0:
                self.save_checkpoint()
        self.save_model()
        return deepcopy(self.history)  # NOT use self.history.copy()

    def predict(self, test_ds, batch_size=128):
        r"""Use model predict method for inference (predict).
        https://keras.io/api/models/model_training_apis/#predict-method
        """
        self.model.eval()  # Turn on the evaluation mode
        pred = []
        data_loader = DataLoader(test_ds, batch_size=batch_size, shuffle=False, num_workers=0)
        for step, batch in enumerate(data_loader):
            # a = batch; print(step, type(a), a.shape, a.ndim, a.dtype, a.size())
            y_hat = self.predict_batch(batch)
            pred.append(y_hat)
        pred = np.concatenate(pred, axis=0)
        # a = pred; print(type(a), a.shape, a.ndim, a.dtype, a.size, a.itemsize)
        return pred

    def predict_batch(self, batch):
        r"""Use model forward method for inference (predict).
        https://keras.io/api/models/model_training_apis/#predict_on_batch-method
        """
        self.model.eval()  # Turn on the evaluation mode
        x = batch
        x = x.to(self.device)
        with torch.no_grad():
            y_hat = self.model.predict(x)
        # y_hat.cpu() / y_hat.detach() / y_hat.cpu().detach()
        return y_hat

    def forward(self, test_ds, batch_size=128):
        r"""Use model forward method for inference (predict).
        https://keras.io/api/models/model_training_apis/#predict-method
        """
        self.model.eval()  # Turn on the evaluation mode
        preds = []
        data_loader = DataLoader(test_ds, batch_size=batch_size, shuffle=False, num_workers=0)
        for step, batch in enumerate(data_loader):
            y_hat = self.forward_batch(batch)
            preds.append(y_hat)
        preds = torch.cat(preds, dim=0)
        # preds.cpu().numpy() / preds.detach().numpy() / preds.cpu().detach().numpy()
        return preds.cpu().numpy()

    def forward_batch(self, batch):
        r"""Use model forward method for inference (predict).
        https://keras.io/api/models/model_training_apis/#predict_on_batch-method
        """
        self.model.eval()  # Turn on the evaluation mode
        x = batch
        x = x.to(self.device)
        with torch.no_grad():
            logits = self.model(x)
            y_hat = logits.argmax(1) + 1
            # proba = torch.sigmoid(logits)  # binary-class classification
            # proba = F.softmax(logits, dim=-1)  # multi-class classification
        # y_hat.cpu() / y_hat.detach() / y_hat.cpu().detach()
        return y_hat.detach()

    def train(self, train_ds, batch_size=128):
        r"""
        https://keras.io/api/models/model_training_apis/#fit-method
        """
        self.model.train()  # Turn on the train mode
        history = {}
        total_loss = 0.
        start_time = time.time()
        data_loader = DataLoader(train_ds, batch_size=batch_size, shuffle=True, num_workers=0)
        # steps_per_epoch = len(data_loader)
        steps_per_epoch = len(data_loader.dataset) // batch_size
        for step, batch in enumerate(data_loader):
            self.cur_step = step
            self.total_step += 1
            hist = self.train_batch(batch)
            total_loss += hist['loss']
            history.setdefault('loss', []).append(hist['loss'])
            for name, metric_fn in self.metrics.items():
                history.setdefault(name, []).append(hist[name])
            if step > 0 and step % self.log_steps == 0:
                train_loss = total_loss / self.log_steps
                elapsed = time.time() - start_time
                print('| {:5d}/{:d} steps | {:5.2f} ms/step | loss {:5.4f}'.format(
                    step, steps_per_epoch, elapsed * 1000 / self.log_steps, train_loss))
                total_loss = 0.
                start_time = time.time()
        # loss = train_loss / len(data_loader.dataset)
        # history['loss'] = np.mean(np.array(history['loss']))
        for name in history:
            history[name] = np.mean(np.array(history[name]))
        return history

    def train_batch(self, batch):
        r"""
        https://keras.io/api/models/model_training_apis/#train_on_batch-method
        """
        self.model.train()  # Turn on the train mode
        x, y = batch
        x, y = x.to(self.device), y.to(self.device)
        logits = self.model(x)
        loss = self.loss_fn(logits, y)
        self.optimizer.zero_grad()
        loss.backward()
        # torch.nn.utils.clip_grad_norm_(self.model.parameters(), 0.5)
        self.optimizer.step()
        # batch_loss = len(x) * loss.item()
        hist = {'loss': loss.item()}
        for name, metric_fn in self.metrics.items():
            hist[name] = metric_fn(y.cpu(), logits.cpu().detach())
            # hist[name] = metric_fn(y.cpu().numpy(), logits.cpu().detach().numpy())
        return hist

    def evaluate(self, valid_ds, batch_size=128):
        r"""
        https://keras.io/api/models/model_training_apis/#evaluate-method
        """
        self.model.eval()  # Turn on the evaluation mode
        history = {}
        valid_loss = 0.
        data_loader = DataLoader(valid_ds, batch_size=batch_size, shuffle=False, num_workers=0)
        for batch in data_loader:
            hist = self.evaluate_batch(batch)
            valid_loss += hist['loss']
            history.setdefault('loss', []).append(hist['loss'])
            for name, metric_fn in self.metrics.items():
                history.setdefault(name, []).append(hist[name])
        # loss = valid_loss / len(data_loader.dataset)
        # history['loss'] = np.mean(np.array(history['loss']))
        for name in history:
            history[name] = np.mean(np.array(history[name]))
        return history

    def evaluate_batch(self, batch):
        r"""
        https://keras.io/api/models/model_training_apis/#test_on_batch-method
        """
        self.model.eval()  # Turn on the evaluation mode
        x, y = batch
        x, y = x.to(self.device), y.to(self.device)
        with torch.no_grad():
            logits = self.model(x)
            loss = self.loss_fn(logits, y)
        hist = {'loss': loss.item()}
        for name, metric_fn in self.metrics.items():
            hist[name] = metric_fn(y.cpu(), logits.cpu().detach())
            # hist[name] = metric_fn(y.cpu().numpy(), logits.cpu().detach().numpy())
        return hist

    def validate(self, valid_ds, batch_size):
        return self.evaluate(valid_ds, batch_size)

    def test(self, test_ds, batch_size):
        return self.evaluate(test_ds, batch_size)

    def loss_collate(self, output, target):
        if self.ml_task == 'BIN':
            assert output.size(-1) == 1
            output = output.view(-1)
            target = target.view(-1).float()
        elif self.ml_task == 'MUL':
            assert output.size(-1) > 1
            target = target.view(-1).float()
        elif self.ml_task == 'REG':
            assert output.size(-1) == 1
            output = output.view(-1)
            target = target.view(-1).float()
        else:
            output = output.view(-1, output.size(-1))
            target = target.view(-1).float()
            pass
        return output, target

    def _initializer(self):
        """
        https://pytorch.org/docs/stable/nn.init
        https://keras.io/api/layers/initializers/
        """
        pass

    def _optimizer(self, optim='adam', lr=1e-3):
        """
        https://pytorch.org/docs/stable/optim.html
        """
        params = self.model.parameters()
        if optim == 'sgd':
            optimizer = torch.optim.SGD(params, lr=lr, momentum=0, weight_decay=0)
        else:
            optimizer = torch.optim.Adam(params, lr=lr, betas=(0.9, 0.999), eps=1e-08, weight_decay=0)
        return optimizer

    def save_model(self, path=None):
        if path is not None:
            if path[-3:] != '.pt' and path[-4:] != '.pth':
                path = path + '.pt'
        else:
            file_name = '%s-%s-%s.pt' % (self.dataset, self.model_name, str(self.cur_epoch))
            path = os.path.join(self.model_dir, file_name)
        torch.save(self.model.state_dict(), path)

    def load_model(self, path=None):
        if path is not None:
            if path[-3:] != '.pt' and path[-4:] != '.pth':
                path = path + '.pt'
        else:
            file_name = '%s-%s-%s.pt' % (self.dataset, self.model_name, str(self.cur_epoch))
            path = os.path.join(self.model_dir, file_name)
        self.model.load_state_dict(torch.load(path))
        self.model.eval()

    def save_checkpoint(self, path=None):
        if path is not None:
            path = path + '.tar' if path[-4:] != '.tar' else path
        else:
            file_name = '%s-%s-%s.tar' % (self.dataset, self.model_name, str(self.cur_epoch))
            path = os.path.join(self.ckpt_dir, file_name)
        state = {
            'epoch': self.cur_epoch,
            'model_state_dict': self.model.state_dict(),
            'optimizer_state_dict': self.optimizer.state_dict(),
            'loss': self.loss
        }
        torch.save(state, path)

    def load_checkpoint(self, path=None):
        if path is not None:
            path = path + '.tar' if path[-4:] != '.tar' else path
        else:
            file_name = '%s-%s-%s.tar' % (self.dataset, self.model_name, str(self.cur_epoch))
            path = os.path.join(self.ckpt_dir, file_name)
        checkpoint = torch.load(path)
        self.model.load_state_dict(checkpoint['model_state_dict'])
        self.optimizer.load_state_dict(checkpoint['optimizer_state_dict'])
        self.cur_epoch = checkpoint['epoch']
        self.loss = checkpoint['loss']
        self.model.eval()  # or self.model.train()

class PipelineBPRSeq(Pipeline):

    def __init__(self, conf, model):
        super(PipelineBPRSeq, self).__init__(conf, model)

    def predict_batch(self, batch):
        self.model.eval()  # Turn on the evaluation mode
        u, i, seq = as_tensor(*batch, dtype=torch.int64, device=self.device)
        with torch.no_grad():
            y_hat = self.model.predict((u, i, seq))
        return y_hat

    def train_batch(self, batch):
        self.model.train()  # Turn on the train mode
        u, i, j, seq = as_tensor(*batch, dtype=torch.int64, device=self.device)
        p_ui, p_uj = self.model((u, i, j, seq))
        loss = self.loss_fn(p_ui, p_uj)
        self.optimizer.zero_grad()
        loss.backward()
        self.optimizer.step()
        hist = {'loss': loss.item()}
        for name, metric_fn in self.metrics.items():
            hist[name] = metric_fn(p_ui.cpu(), p_uj.cpu().detach())
            # hist[name] = metric_fn(p_ui.cpu().numpy(), p_uj.cpu().detach().numpy())
        return hist

    def evaluate_batch(self, batch):
        self.model.eval()  # Turn on the evaluation mode
        u, i, j, seq = as_tensor(*batch, dtype=torch.int64, device=self.device)
        with torch.no_grad():
            p_ui, p_uj = self.model((u, i, j, seq))
            loss = self.loss_fn(p_ui, p_uj)
        hist = {'loss': loss.item()}
        for name, metric_fn in self.metrics.items():
            hist[name] = metric_fn(p_ui.cpu(), p_uj.cpu().detach())
            # hist[name] = metric_fn(p_ui.cpu().numpy(), p_uj.cpu().detach().numpy())
        return hist

class PipelineUIYSeq(Pipeline):

    def __init__(self, conf, model):
        super(PipelineUIYSeq, self).__init__(conf, model)

    def predict_batch(self, batch):
        self.model.eval()  # Turn on the evaluation mode
        u, i, seq = as_tensor(*batch, dtype=torch.int64, device=self.device)
        with torch.no_grad():
            y_hat = self.model.predict((u, i, seq))
        return y_hat

    def train_batch(self, batch):
        self.model.train()  # Turn on the train mode
        u, i, y, seq = as_tensor(*batch, dtype=torch.int64, device=self.device)
        logits = self.model((u, i, seq))
        logits = logits.reshape(-1) if logits.size(-1) == 1 else logits.reshape(-1, logits.size(-1))
        y = y.view(-1).float()
        loss = self.loss_fn(logits, y)
        self.optimizer.zero_grad()
        loss.backward()
        self.optimizer.step()
        hist = {'loss': loss.item()}
        for name, metric_fn in self.metrics.items():
            hist[name] = metric_fn(y.cpu(), logits.cpu().detach())
            # hist[name] = metric_fn(y.cpu().numpy(), logits.cpu().detach().numpy())
        return hist

    def evaluate_batch(self, batch):
        self.model.eval()  # Turn on the evaluation mode
        u, i, y, seq = as_tensor(*batch, dtype=torch.int64, device=self.device)
        with torch.no_grad():
            logits = self.model((u, i, seq))
            logits = logits.reshape(-1) if logits.size(-1) == 1 else logits.reshape(-1, logits.size(-1))
            y = y.view(-1).float()
            loss = self.loss_fn(logits, y)
        hist = {'loss': loss.item()}
        for name, metric_fn in self.metrics.items():
            hist[name] = metric_fn(y.cpu(), logits.cpu().detach())
            # hist[name] = metric_fn(y.cpu().numpy(), logits.cpu().detach().numpy())
        return hist


import magic_box

def controller(string):
    try:
        string = int(string)
    except:
        string = string

    if isinstance(string, str):
        message = sign_choose(string)
        return message
    elif isinstance(string, int):
        message = tic_tac_toe(string)
    else:
        message = "Your input was incorrect, try again."

    return message

def sign_choose(user_string):
    lst = magic_box.take()
    print(lst, type(lst))

    if user_string == "X":
        lst[1] = "X"
        lst[2] = "O"
    else:
        lst[1] = "O"
        lst[2] = "X"
        tic_tac_toe("STRING")

    magic_box.put(lst)

    return "Got it!"

def tic_tac_toe(user_string):
    lst = magic_box.take()
    temp_board = [ch for ch in lst[0]]
    user_sign = lst[1]
    my_sign = lst[2]

    try:
        user_string = int(user_string)
    except:
        user_string = user_string

    if isinstance(user_string, int):
        lst[0] = temp_board.insert(user_string - 1, user_sign)
        won = win_check()
        if lst[3]:
            message = f"Congradulation! {won} has won!"
        else:
            for i in range(len(temp_board)):
                if isinstance(temp_board[i], int):
                    temp_board.insert(i, my_sign)
                else: continue
    else:
        temp_board.insert(4, my_sign)

    lst[0] = temp_board

    magic_box.put(lst)

    message = "Your turn"
    return message

def win_check():
    lst = magic_box.take()
    in_board = [ch for ch in lst[0]]

    if (in_board[0] == in_board[1] == in_board[2]) or (in_board[0] == in_board[3] == in_board[6]) or (in_board[0] == in_board[4] == in_board[8]):
        winning = True
        win_sign = in_board[0]
    elif (in_board[3] == in_board[4] == in_board[5]) or (in_board[1] == in_board[4] == in_board[7]) or (in_board[2] == in_board[4] == in_board[6]):
        winning = True
        win_sign = in_board[4]
    elif (in_board[6] == in_board[7] == in_board[8]) or (in_board[2] == in_board[5] == in_board[8]):
        winning = True
        win_sign = in_board[8]
    else:
        winning = False

    lst[3] = winning
    magic_box.put(lst)

    if winning:
        return win_sign
    else: "sorry"


name = "Global Codeforces Round 10"
date = (2020,8,16)
rank = 2203
educ = False

points = 2941
rating_change = 317

solutions = [
    {
        "problem": "A",
        "name": "Omkar and Password",
        "time": (0,12),
        "points": (484,500)
    }, {
        "problem": "B",
        "name": "Omkar and Infinity Clock",
        "time": (0,31),
        "points": (688,750),
    }, {
        "problem": "C",
        "name": "Omkar and Waterslide",
        "time": (0,41),
        "points": (891,1000),
    }, {
        "problem": "D",
        "name": "Omkar and Bed Wars",
        "time": (1,58),
        "points": (878,1500),
    }
]

submissions = [
    {
        "problem": "A",
        "id": 90099352,
        "status": verdict.accepted(),
    }, {
        "problem": "B",
        "id": 90114207,
        "status": verdict.accepted(),
    }, {
        "problem": "C",
        "id": 90120835,
        "status": verdict.accepted(),
    }, {
        "problem": "D",
        "id": 90135792,
        "status": verdict.wrong_ans(2, pre=True),
    }, {
        "problem": "D",
        "id": 90147918,
        "status": verdict.wrong_ans(2, pre=True),
    }, {
        "problem": "D",
        "id": 90149075,
        "status": verdict.wrong_ans(2, pre=True),
    }, {
        "problem": "D",
        "id": 90151859,
        "status": verdict.wrong_ans(1, pre=True),
    }, {
        "problem": "D",
        "id": 90152128,
        "status": verdict.accepted(),
    }
]


# pylint: disable=unused-argument,redefined-outer-name
"""Test all the modules related to data management"""
import os
import pytest
import yaml
from modules.data import Config

TEST_SETTINGS = {
    "string": "string",
    "int": 1,
    "float": 2.3,
    "bool": True,
    "list": ["a", "b", "c", "d"],
    "meme": {
        "key": "value",
        "key2": 1
    },
    "debug": {
        "logs": ["value1", "value2"],
        "key2": 1
    }
}
TEST_SETTINGS_TYPES = {
    "string": "string",
    "int": "int",
    "float": "float",
    "bool": "bool",
    "list": "list",
    "meme": {
        "key": "string",
        "key2": "int"
    },
    "debug": {
        "logs": "list",
        "key2": "int"
    }
}

@pytest.fixture(scope="function")
def config() -> Config:
    """Called at the beginning of the testing session.
    Makes sure the config object is initialized

    Yields:
        Iterator[dict]: dictionary containing the results for the test queries
    """
    old_path = Config.SETTINGS_PATH
    Config.SETTINGS_PATH = ("tests", "settings.yaml")
    with open("tests/settings.yaml", 'w', encoding='utf-8') as settings:
        yaml.safe_dump(TEST_SETTINGS, settings)
    with open("tests/settings.yaml.types", 'w', encoding='utf-8') as settings:
        yaml.safe_dump(TEST_SETTINGS_TYPES, settings)
    Config.reset_settings()

    yield Config

    os.remove("tests/settings.yaml")
    os.remove("tests/settings.yaml.types")
    Config.SETTINGS_PATH = old_path
    Config.reset_settings()

class TestConfig:
    """Test the Config class"""

    def assert_config(self, config: Config, base_key: str = None, exclude_keys: tuple = ()):
        """Tests the ability of the config object to load settings from a file"""
        settings_to_test = TEST_SETTINGS if base_key is None or base_key not in TEST_SETTINGS else TEST_SETTINGS[base_key]
        for key, value in settings_to_test.items():
            if key not in exclude_keys:
                if base_key is None:
                    assert config.settings_get(key) == value
                else:
                    assert config.settings_get(base_key, key) == value

    def test_load_flat_settings(self, config: Config):
        """Tests the ability of the config object to load settings from a file"""
        for key, value in TEST_SETTINGS.items():
            assert config.settings_get(key) == value

    def test_load_nested_settings(self, config: Config):
        """Tests the ability of the config object to load settings from a file with nested properties"""
        for key, value in TEST_SETTINGS['meme'].items():
            assert config.settings_get("meme", key) == value

    def test_default_flat_settings(self, config: Config):
        """Tests the ability of the config object to return the default value
        if the key is not found
        """
        assert Config.settings_get("invalid_key") is None
        assert Config.settings_get("invalid_key", default="value") == "value"

    def test_default_nested_settings(self, config: Config):
        """Tests the ability of the config object to return the default value
        if the nested key is not found
        """
        assert Config.settings_get("invalid_key", "nested") is None
        assert Config.settings_get("invalid_key", "nested", default="value") == "value"

        assert Config.settings_get("string", "nested") is None
        assert Config.settings_get("string", "nested", default="value") == "value"

    def test_load_env_flat_settings_new_setting(self, config: Config):
        """Tests the ability of the config object to load a new setting from the env vars,
        not present in the settings file.
        Only string values can be loaded this way
        """
        os.environ["new_setting"] = "new value"
        config.reset_settings()
        assert config.settings_get("new_setting") == "new value"
        self.assert_config(config) # Other settings are unchanged
        del os.environ["new_setting"]

    def test_load_env_flat_settings_int(self, config: Config):
        """Tests the ability of the config object to load int settings from the env vars"""
        os.environ["int"] = "2"
        config.reset_settings()
        assert config.settings_get("int") == 2
        self.assert_config(config, exclude_keys=("int",)) # Other settings are unchanged
        del os.environ["int"]

    def test_load_env_flat_settings_float(self, config: Config):
        """Tests the ability of the config object to load float settings from the env vars"""
        os.environ["float"] = "3.4"
        config.reset_settings()
        assert config.settings_get("float") == 3.4
        self.assert_config(config, exclude_keys=("float",)) # Other settings are unchanged
        del os.environ["float"]

    def test_load_env_flat_settings_bool(self, config: Config):
        """Tests the ability of the config object to load bool settings from the env vars"""
        os.environ["bool"] = "False"
        config.reset_settings()
        assert config.settings_get("bool") is False
        self.assert_config(config, exclude_keys=("bool",)) # Other settings are unchanged
        del os.environ["bool"]

    def test_load_env_flat_settings_list(self, config: Config):
        """Tests the ability of the config object to load list settings from the env vars"""
        os.environ["list"] = "e,f,g"
        config.reset_settings()
        assert config.settings_get("list") == ["e", "f", "g"]
        self.assert_config(config, exclude_keys=("list",)) # Other settings are unchanged
        del os.environ["list"]

    def test_load_env_flat_settings_str(self, config: Config):
        """Tests the ability of the config object to load str settings from the env vars"""
        os.environ["string"] = "another string"
        config.reset_settings()
        assert config.settings_get("string") == "another string"
        self.assert_config(config, exclude_keys=("string",)) # Other settings are unchanged
        del os.environ["string"]

    def test_load_env_nested_meme_settings(self, config: Config):
        """Tests the ability of the config object to load settings from the env vars
        with the nested meme key
        """
        os.environ["meme_key2"] = "2"
        config.reset_settings()
        assert config.settings_get("meme", "key2") == 2
        self.assert_config(config, exclude_keys=("meme",))  # Other settings are unchanged
        self.assert_config(config, base_key="meme", exclude_keys=("key2"))  # Other settings in meme are unchanged
        del os.environ["meme_key2"]

    def test_load_env_nested_debug_settings(self, config: Config):
        """Tests the ability of the config object to load settings from the env vars
        with the nested debug key
        """
        os.environ["debug_logs"] = "val1,val2,val3"
        config.reset_settings()
        assert config.settings_get("debug", "logs") == ["val1", "val2", "val3"]
        self.assert_config(config, exclude_keys=("debug",))  # Other settings are unchanged
        self.assert_config(config, base_key="debug", exclude_keys=("logs",))  # Other settings in meme are unchanged
        del os.environ["debug_logs"]

    def test_load_env_nested_test_settings(self, config: Config):
        """Tests the ability of the config object to load settings from the env vars
        with the nested test key
        """
        os.environ["test_key"] = "test"
        config.reset_settings()
        assert config.settings_get("test", "key") == "test"
        self.assert_config(config, exclude_keys=("test",))  # Other settings are unchanged
        del os.environ["test_key"]


import numpy as np
import matplotlib.pyplot as plt
from sklearn.linear_model import LinearRegression
x = np.array([5,7,8,7,2,17,2,9,4,11,12,9,6])
x=x.reshape(-1,1)
y = np.array([99,86,87,88,111,86,103,87,94,78,77,85,86])
y=y.reshape(-1,1)
model=LinearRegression()
model=model.fit(x,y)
x_test=np.array(np.linspace(0,20)).reshape(-1,1)
y_pred=model.predict(x_test)
plt.scatter(x,y)
plt.plot(x_test,y_pred)
plt.show()


from ase.calculators.espresso import Espresso
from ase.dft import DOS
import matplotlib.pyplot as plt
from ase.io import read

# Load structure
si = read('Opt.traj@-1')

# Set up calculator and calculation parameters
pseudopotentials = {'Si': 'Si.vbc.UPF'}
input_data = {
    'control': {
        'calculation': 'scf',
        'restart_mode': 'from_scratch',
        'prefix': 'si_scf',
        'outdir': './',
    },
    'system': {
        'ecutwfc': 50,
        'ecutrho': 200,
        'occupations': 'smearing',
        'smearing': 'gaussian',
        'degauss': 0.01,
        'input_dft': 'PBE',
    },
    'electrons': {
        'conv_thr': 1.0e-8,
    },
}

# Set up the Quantum ESPRESSO calculator
calc = Espresso(pseudopotentials=pseudopotentials,
                tstress=True, tprnfor=True, kpts=(6, 6, 6), input_data=input_data)

# Attach the calculator to the Silicon atoms
si.calc = calc

# Perform SCF calculation
si.get_potential_energy()

# Calculate DOS
dos = DOS(calc, width=0.2)
dos.get_dos()

# Get energies and DOS values
energies = dos.get_energies()
dos_values = dos.get_dos()

# Plot DOS
plt.figure(figsize=(8, 6))
plt.plot(energies, dos_values, color='red')
plt.xlabel('Energy (eV)')
plt.ylabel('Density of States')
plt.title('Electronic DOS of Silicon')

# Plot Fermi level line at 0 energy
fermi_level = calc.get_fermi_level()
# For testing
#print(fermi_level)
plt.axvline(x=0, color='k', linestyle='--', label=f'Fermi Level: {fermi_level:.2f} eV')

plt.legend()
plt.savefig('DOS.png')
plt.show()


import os
import numpy as np

def conditionalMkDir(path: str) -> None:
    """Creates a dir if not already existing.
    """
    path = os.path.abspath(path)
    if not os.path.isdir(path):
        os.mkdir(path)

def mkDirTreeFCDD(path: str) -> None:
    """Creates an FCDD-compatible dirtree.
    """
    path = os.path.abspath(path)
    conditionalMkDir(path)
    conditionalMkDir(os.path.join(path, "custom"))
    conditionalMkDir(os.path.join(path, "custom/test"))
    conditionalMkDir(os.path.join(path, "custom/train"))
    conditionalMkDir(os.path.join(path, "custom/test_maps"))
    conditionalMkDir(os.path.join(path, "custom/train_maps"))
    conditionalMkDir(os.path.join(path, "custom/test/tele"))
    conditionalMkDir(os.path.join(path, "custom/train/tele"))
    conditionalMkDir(os.path.join(path, "custom/test_maps/tele"))
    conditionalMkDir(os.path.join(path, "custom/train_maps/tele"))
    conditionalMkDir(os.path.join(path, "custom/test/tele/normal"))
    conditionalMkDir(os.path.join(path, "custom/test/tele/anomalous"))
    conditionalMkDir(os.path.join(path, "custom/train/tele/normal"))
    conditionalMkDir(os.path.join(path, "custom/train/tele/anomalous"))
    conditionalMkDir(os.path.join(path, "custom/test_maps/tele/normal"))
    conditionalMkDir(os.path.join(path, "custom/test_maps/tele/anomalous"))
    conditionalMkDir(os.path.join(path, "custom/train_maps/tele/normal"))
    conditionalMkDir(os.path.join(path, "custom/train_maps/tele/anomalous"))

def randomSplit(path: str, p_good: float = 0., p_anom: float = 0. ) -> None:
    """Randomly split a dataset of nominative and anomalous crops into train and test
    sets (requires a FCDD-compatible dirtree- i.e. custom/train/... , custom/test/... .
    Crops should be initially placed in the train directories).

    Parameters
    ----------
    path: path to root dir of a FCDD-compatible dirtree.
    p_good: fraction of good crops to move in the test set.
    p_anomalous: fraction of good crops to move in the test set.

    """
    path = os.path.abspath(path)

    gTrainpath = os.path.join(path, "custom/train/tele/normal")
    gTestpath = os.path.join(path, "custom/test/tele/normal")
    aTrainpath = os.path.join(path, "custom/train/tele/anomalous")
    aTestpath = os.path.join(path, "custom/test/tele/anomalous")

    gTrainpath_M = os.path.join(path, "custom/train_maps/tele/normal")
    gTestpath_M = os.path.join(path, "custom/test_maps/tele/normal")
    aTrainpath_M = os.path.join(path, "custom/train_maps/tele/anomalous")
    aTestpath_M = os.path.join(path, "custom/test_maps/tele/anomalous")

    # lists of crops abspaths

    good_crops = [ f for f in os.listdir(gTrainpath) if f.endswith(".png") ]
    anom_crops = [ f for f in os.listdir(aTrainpath) if f.endswith(".png") ]

    # random split

    n_good = int(len(good_crops)*p_good)
    n_anom = int(len(anom_crops)*p_anom)
    good_crops_C = np.random.choice(good_crops, n_good, replace = False)
    anom_crops_C = np.random.choice(anom_crops, n_anom, replace = False)

    # move files

    for f in good_crops_C:
        source = os.path.join(gTrainpath, f)
        destination = os.path.join(gTestpath, f)
        os.rename(source, destination)

        if os.path.isfile(os.path.join(gTrainpath_M, f)):
            source = os.path.join(gTrainpath_M, f)
            destination = os.path.join(gTestpath_M, f)
            os.rename(source, destination)

    for f in anom_crops_C:
        source = os.path.join(aTrainpath, f)
        destination = os.path.join(aTestpath, f)
        os.rename(source, destination)

        if os.path.isfile(os.path.join(aTrainpath_M, f)):
            source = os.path.join(aTrainpath_M, f)
            destination = os.path.join(aTestpath_M, f)
            os.rename(source, destination)