from tkinter import *
from tkinter import ttk as ttk
from tkinter import messagebox as mb
import datetime
import sqlite3
from tkcalendar import DateEntry

# list all the expenses
def listAllExpenses():

    # global variables
    global dbconnector, data_table

    data_table.delete(*data_table.get_children())

    all_data = dbconnector.execute('SELECT * FROM BUDGET')
    data = all_data.fetchall()

    # inserting the values in the tkinter data table
    for val in data:
        data_table.insert('', END, values = val)

# view an expense information
def viewExpenseInfo():

    # global variables
    global data_table
    global dateField, payee, description, amount, paymentMethod

    # error message box
    if not data_table.selection():
        mb.showerror('No expense record selected', 'Please select an expense record from the table to view')

    currentSelectedExpense = data_table.item(data_table.focus())
    val = currentSelectedExpense['values']
    expenditureDate = datetime.date(int(val[1][:4]), int(val[1][5:7]), int(val[1][8:]))

    dateField.set_date(expenditureDate) ; payee.set(val[2]) ; description.set(val[3]) ; amount.set(val[4]) ; paymentMethod.set(val[5])

# clear the entries from the entry fields
def clearFields():

    #global variable
    global description, payee, amount, paymentMethod, dateField, data_table

    todayDate = datetime.datetime.now().date()

    description.set('') ; payee.set('') ; amount.set(0.0) ; paymentMethod.set('Cash'), dateField.set_date(todayDate)
    data_table.selection_remove(*data_table.selection())

# remove the selected expense
def removeExpense():

    # error message box
    if not data_table.selection():
        mb.showerror('No expense record selected!', 'Please select a expense record to remove!', icon='warning')
        return

    currentSelectedExpense = data_table.item(data_table.focus())

    valuesSelected = currentSelectedExpense['values']

    # message box when the user hit the button
    confirmation = mb.askyesno('Confirmation', f'Are you sure that you want to remove the record of {valuesSelected[2]}')

    if confirmation:
        dbconnector.execute('DELETE FROM BUDGET WHERE ID=%d' % valuesSelected[0])
        dbconnector.commit()
        listAllExpenses()
        mb.showinfo('Expense removed successfully!', f'The record you wanted to remove has been removed successfully')

# delete all the entries
def removeAllExpenses():
    confirmation = mb.askyesno('Confirmation', 'Are you sure that you want to remove all the expense items from the database?', icon='warning')

    if confirmation:
        data_table.delete(*data_table.get_children())
        dbconnector.execute('DELETE FROM BUDGET')
        dbconnector.commit()
        clearFields()
        listAllExpenses()
        # message for successfullt remove the expense from database
        mb.showinfo('All Expenses has been removed!', 'All the expenses were successfully removed!')
    else:
        # message for cancel the request to remove all expenses
        mb.showinfo('Confirmation', 'Removed all expenses request has been cancelled!')

# add an expense
def addAnotherExpense():

    # global variables
    global dateField, payee, description, amount, paymentMethod
    global dbconnector

    # error message box
    if not dateField.get() or not payee.get() or not description.get() or not amount.get() or not paymentMethod.get():
        mb.showerror('Fields are empty!', "Please fill all the missing fields then hit the 'Add Expense' button!")
    else:
        dbconnector.execute(
            'INSERT INTO BUDGET (Date, Payee, Description, Amount, paymentMethod) VALUES (?, ?, ?, ?, ?)',
            (dateField.get_date(), payee.get(), description.get(), amount.get(), paymentMethod.get())
        )
        dbconnector.commit()
        clearFields()
        listAllExpenses()

        # message box when the user hit the button
        mb.showinfo('Expense added', 'The expense whose details you just entered has been added to the database')

# edit expense
def editExpense():
    # global variable
    global data_table

    def editExistingExpense():

        # global variable
        global dateField, amount, description, payee, paymentMethod
        global dbconnector, data_table

        currentSelectedExpense = data_table.item(data_table.focus())

        content = currentSelectedExpense['values']

        # update the information to database
        dbconnector.execute(
            'UPDATE BUDGET SET Date = ?, Payee = ?, Description = ?, Amount = ?, paymentMethod = ? WHERE ID = ?',
            (dateField.get_date(), payee.get(), description.get(), amount.get(), paymentMethod.get(), content[0])
        )
        dbconnector.commit()
        clearFields()
        listAllExpenses()

        mb.showinfo('Data edited', 'We have updated the data and stored in the database as you wanted')
        editSelectedButton.destroy()

    # if no expense is selectted, returning a error message box
    if not data_table.selection():
        mb.showerror('No expense selected!', 'You have not selected any expense in the table for us to edit; please do that!')
        return

    viewExpenseInfo()

    # edit button
    editSelectedButton = Button(
        frameL3,
        text = "Edit Expense",
        font = ("Bahnschrift Condensed", "13"),
        width = 30,
        bg = "#90EE90",
        fg = "#000000",
        relief = GROOVE,
        activebackground = "#008000",
        activeforeground = "#98FB98",
        command = editExistingExpense
        )

    editSelectedButton.grid(row = 0, column = 0, sticky = W, padx = 50, pady = 10)

# main function
if __name__ == "__main__":

    # connecting to the database
    dbconnector = sqlite3.connect("Budget Budget Budget.db")
    dbcursor = dbconnector.cursor()

    dbconnector.execute(
        'CREATE TABLE IF NOT EXISTS BUDGET (ID INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, Date DATETIME, Payee TEXT, Description TEXT, Amount FLOAT, paymentMethod TEXT)'
    )
    dbconnector.commit()

    # setting for the app pop up window
    main_win = Tk()
    main_win.title("BUDGET BUDGET BUDGET")
    main_win.geometry("1440x700+400+100")
    main_win.resizable(0, 0)
    main_win.config(bg = "#FFFAF0")

    # custom frames
    frameLeft = Frame(main_win, bg = "#80ced6")
    frameRight = Frame(main_win, bg = "#DEB887")
    frameL1 = Frame(frameLeft, bg = "#80ced6")
    frameL2 = Frame(frameLeft, bg = "#80ced6")
    frameL3 = Frame(frameLeft, bg = "#80ced6")
    frameR1 = Frame(frameRight, bg = "#3e4444")
    frameR2 = Frame(frameRight, bg = "#DEB887")

    frameLeft.pack(side=LEFT, fill = "both")
    frameRight.pack(side = RIGHT, fill = "both", expand = True)
    frameL1.pack(fill = "both")
    frameL2.pack(fill = "both")
    frameL3.pack(fill = "both")
    frameR1.pack(fill = "both")
    frameR2.pack(fill = "both", expand = True)

    # Heading lable
    headingLabel = Label(
        frameL1,
        text = "BUDGET BUDGET BUDGET",
        font = ("Bahnschrift Condensed", "25"),
        width = 20,
        bg = "#82b74b",
        fg = "#FFFAF0"
        )
    # second heading lable
    subheadingLabel = Label(
        frameL1,
        text = "SAVE MONEY    SAVE LIFE",
        font = ("Bahnschrift Condensed", "15"),
        width = 20,
        bg = "#405d27",
        fg = "#000000"
        )

    headingLabel.pack(fill = "both")
    subheadingLabel.pack(fill = "both")

    # input labels
    dateLabel = Label(
        frameL2,
        text = "Date:",
        font = ("consolas", "12", "bold"),
        bg = "#80ced6",
        fg = "#000000"
        )

    descriptionLabel = Label(
        frameL2,
        text = "Description:",
        font = ("consolas", "12", "bold"),
        bg = "#80ced6",
        fg = "#000000"
        )

    amountLabel = Label(
        frameL2,
        text = "Amount:",
        font = ("consolas", "12", "bold"),
        bg = "#80ced6",
        fg = "#000000"
        )

    payeeLabel = Label(
        frameL2,
        text = "Payee:",
        font = ("consolas", "12", "bold"),
        bg = "#80ced6",
        fg = "#000000"
        )

    paymentLabel = Label(
        frameL2,
        text = "Payment Method:",
        font = ("consolas", "12", "bold"),
        bg = "#80ced6",
        fg = "#000000"
        )

    dateLabel.grid(row = 0, column = 0, sticky = W, padx = 10, pady = 10)
    descriptionLabel.grid(row = 1, column = 0, sticky = W, padx = 10, pady = 10)
    amountLabel.grid(row = 2, column = 0, sticky = W, padx = 10, pady = 10)
    payeeLabel.grid(row = 3, column = 0, sticky = W, padx = 10, pady = 10)
    paymentLabel.grid(row = 4, column = 0, sticky = W, padx = 10, pady = 10)

    # input types
    description = StringVar()
    payee = StringVar()
    paymentMethod = StringVar(value = "Cash")
    amount = DoubleVar()

    # date input
    dateField = DateEntry(
        frameL2,
        date = datetime.datetime.now().date(),
        font = ("consolas", "11"),
        relief = GROOVE
        )
    # description input
    descriptionField = Entry(
        frameL2,
        text = description,
        width = 20,
        font = ("consolas", "11"),
        bg = "#FFFFFF",
        fg = "#000000",
        relief = GROOVE
        )
    # amount of money input
    amountField = Entry(
        frameL2,
        text = amount,
        width = 20,
        font = ("consolas", "11"),
        bg = "#FFFFFF",
        fg = "#000000",
        relief = GROOVE
        )
    # payee input
    payeeField = Entry(
        frameL2,
        text = payee,
        width = 20,
        font = ("consolas", "11"),
        bg = "#FFFFFF",
        fg = "#000000",
        relief = GROOVE
        )

    # payment input
    paymentField = OptionMenu(
        frameL2,
        paymentMethod,
        *['Cash', 'Credit Card', 'Debit Card', 'Google Pay', 'Apple Pay', 'PayPal']
        )
    paymentField.config(
        width = 15,
        font = ("consolas", "10"),
        relief = GROOVE,
        bg = "#FFFFFF"
        )

    dateField.grid(row = 0, column = 1, sticky = W, padx = 10, pady = 10)
    descriptionField.grid(row = 1, column = 1, sticky = W, padx = 10, pady = 10)
    amountField.grid(row = 2, column = 1, sticky = W, padx = 10, pady = 10)
    payeeField.grid(row = 3, column = 1, sticky = W, padx = 10, pady = 10)
    paymentField.grid(row = 4, column = 1, sticky = W, padx = 10, pady = 10)

    # function buttons under the inputs
    insertButton = Button(
        frameL3,
        text = "Add Expense",
        font = ("Bahnschrift Condensed", "13"),
        width = 30,
        bg = "#90EE90",
        fg = "#000000",
        relief = GROOVE,
        activebackground = "#008000",
        activeforeground = "#98FB98",
        command = addAnotherExpense
        )

    resetButton = Button(
        frameL3,
        text = "Clear The Fields",
        font = ("Bahnschrift Condensed", "13"),
        width = 30,
        bg = "#FF0000",
        fg = "#FFFFFF",
        relief = GROOVE,
        activebackground = "#8B0000",
        activeforeground = "#FFB4B4",
        command = clearFields
        )

    insertButton.grid(row = 0, column = 0, sticky = W, padx = 50, pady = 30)
    resetButton.grid(row = 1, column = 0, sticky = W, padx = 50, pady = 30)

    # function buttons on top of the table
    viewButton = Button(
        frameR1,
        text = "View Selected Expense",
        font = ("Bahnschrift Condensed", "14"),
        width = 30,
        bg = "#92a8d1",
        fg = "#000000",
        relief = GROOVE,
        activebackground = "#A0522D",
        activeforeground = "#FFF8DC",
        command = viewExpenseInfo
        )

    editButton = Button(
        frameR1,
        text = "Edit Selected Expense",
        font = ("Bahnschrift Condensed", "14"),
        width = 30,
        bg = "#92a8d1",
        fg = "#000000",
        relief = GROOVE,
        activebackground = "#A0522D",
        activeforeground = "#FFF8DC",
        command = editExpense
        )

    deleteButton = Button(
        frameR1,
        text = "Remove Selected Expense",
        font = ("Bahnschrift Condensed", "14"),
        width = 30,
        bg = "#92a8d1",
        fg = "#000000",
        relief = GROOVE,
        activebackground = "#A0522D",
        activeforeground = "#FFF8DC",
        command = removeExpense
        )

    deleteAllButton = Button(
        frameR1,
        text = "Remove All Expenses",
        font = ("Bahnschrift Condensed", "14"),
        width = 30,
        bg = "#92a8d1",
        fg = "#000000",
        relief = GROOVE,
        activebackground = "#A0522D",
        activeforeground = "#FFF8DC",
        command = removeAllExpenses
        )

    # set up UI for fucntion buttons
    viewButton.grid(row = 0, column = 0, sticky = W, padx = 10, pady = 10)
    editButton.grid(row = 0, column = 1, sticky = W, padx = 10, pady = 10)
    deleteButton.grid(row = 0, column = 2, sticky = W, padx = 10, pady = 10)
    deleteAllButton.grid(row = 0, column = 3, sticky = W, padx = 10, pady = 10)

    # data table column labels
    data_table = ttk.Treeview(
        frameR2,
        selectmode = BROWSE,
        columns = ('ID', 'Date', 'Payee', 'Description', 'Amount', 'Payment Method')
        )

    # scrollbar for horizontal
    Xaxis_Scrollbar = Scrollbar(
        data_table,
        orient = HORIZONTAL,
        command = data_table.xview
        )

    # scrollbar for vertical
    Yaxis_Scrollbar = Scrollbar(
        data_table,
        orient = VERTICAL,
        command = data_table.yview
        )

    Xaxis_Scrollbar.pack(side = BOTTOM, fill = X)
    Yaxis_Scrollbar.pack(side = RIGHT, fill = Y)

    data_table.config(yscrollcommand = Yaxis_Scrollbar.set, xscrollcommand = Xaxis_Scrollbar.set)

    # data table headings
    data_table.heading('ID', text = 'ID', anchor = CENTER)
    data_table.heading('Date', text = 'Date', anchor = CENTER)
    data_table.heading('Payee', text = 'Payee', anchor = CENTER)
    data_table.heading('Description', text = 'Description', anchor = CENTER)
    data_table.heading('Amount', text = 'Amount', anchor = CENTER)
    data_table.heading('Payment Method', text = 'Payment Method', anchor = CENTER)

    # data table column width for every elements
    data_table.column('#0', width = 0, stretch = NO)
    data_table.column('#1', width = 50, stretch = NO)
    data_table.column('#2', width = 95, stretch = NO)
    data_table.column('#3', width = 200, stretch = NO)
    data_table.column('#4', width = 450, stretch = NO)
    data_table.column('#5', width = 135, stretch = NO)
    data_table.column('#6', width = 140, stretch = NO)

    data_table.place(relx = 0, y = 0, relheight = 1, relwidth = 1)
    main_win.mainloop()


# USAGE
# python scripts/crop-to-object.py -i images/output/uss-freedom-original.jpg

# import necessary packages
import argparse
import cv2

# construct the argument parser
ap = argparse.ArgumentParser()
ap.add_argument("-i","--image", type=str,
                help="path to input image")
args = vars(ap.parse_args())

# load, crop, save and show
image = cv2.imread(args["image"])
cropped = image[700:1050, 300:1400]
(h, w, c) = image.shape[:3]
print("width: {} pixels".format(w))
print("height: {} pixels".format(h))
print("channels: {}".format(c))
cv2.imshow("Cropped", cropped)
cv2.imwrite("images/output/uss-freedom-cropped.jpg", cropped)
cv2.waitKey(0)


################################################### END ########################################################
################################################### SET PATH ########################################################
# Filter results of WGS
import glob
import os
from Bio import SeqIO
from Bio.Seq import Seq
import statistics
import itertools
import random
# set up path
import argparse
############################################ Arguments and declarations ##############################################
parser = argparse.ArgumentParser(formatter_class=argparse.RawDescriptionHelpFormatter)
required = parser.add_argument_group('required arguments')
optional = parser.add_argument_group('optional arguments')
required.add_argument("-i",
                      help="a folder to store all output",
                      type=str, default='/scratch/users/anniz44/genomes/donor_species/vcf_round2/merge/details/moredetails/BaFr_jay/',
                      metavar='WGS/')
required.add_argument("-fq",
                      help="file extension of WGS fastq #1 files",
                      type=str, default='_1.fastq',
                      metavar='_1.fastq')
required.add_argument("-s",
                      help="a folder to store all scripts",
                      type=str, default='/scratch/users/anniz44/scripts/1MG/donor_species/assembly/',
                      metavar='scripts/')

################################################## Definition ########################################################
args = parser.parse_args()
# set up path
input_script = args.s  + '/vcf_filter.sh'
output_dir = args.i
vcf_name = '*.raw.vcf'
ref_filename = '.noHM.fasta'
fastq_name = args.fq
Cov_dis_overall = 1000
MW_cov_dir = '/scratch/users/anniz44/genomes/donor_species/vcf_round2/merge/details/MV_cov'

def filter_vcfs(allvcfs,lineage):
    CHRPOS_withSNPs = os.path.join(output_dir,'%s.CHRPOS'%(lineage))
    for vcf in allvcfs:
        snp_file = vcf.replace('.raw.vcf', '.flt.snp.vcf')
        os.system('cat %s | cut -f 1,2 >> %s' % (snp_file, CHRPOS_withSNPs))
    os.system('cat %s | sort | uniq > %s.unique'%(CHRPOS_withSNPs,CHRPOS_withSNPs))
    cmds = '#!/bin/bash\nsource ~/.bashrc\npy39\n'
    for vcf in allvcfs:
        cmds += 'bcftools filter -T %s.unique %s > %s.filter\n' % (CHRPOS_withSNPs, vcf, vcf)
    f1 = open(os.path.join(input_script) , 'w')
    f1.write(cmds)
    f1.close()

def outputcovwindow(allvcfs,lineage):
    cov_genome = dict()
    i = 0
    sample_len = len(allvcfs)
    for vcf in allvcfs:
        for lines in open(vcf, 'r'):
            if not lines.startswith('#'):
                lines_set = lines.split('\n')[0].split('\t')
                CHR = lines_set[0]
                POS = int(lines_set[1])
                if POS % Cov_dis_overall == 500:
                    CHRPOS = '%s\t%s' % (CHR, POS)
                    cov_genome.setdefault(CHRPOS, [0] * sample_len)
                    # subset this CHR
                    Subdepth_all = lines_set[9]
                    Subdepth = Subdepth_all.split(':')[-1].replace('\n', '').split(',')
                    total_sub_depth = sum([int(Subdepth_sub) for Subdepth_sub in Subdepth])
                    cov_genome[CHRPOS][i] = total_sub_depth
        i += 1
    cov_output = []
    allCHRPOS = list(cov_genome.keys())
    allCHRPOS.sort()
    for CHRPOS in allCHRPOS:
        temp_cov = cov_genome[CHRPOS]
        cov_output.append('%s\t%s\t%s\n' % (CHRPOS, statistics.mean(temp_cov),
                                                            '\t'.join(str(cov) for cov in temp_cov)))
    vcf_file_filtered = open(MW_cov_dir + '/%s.all.donor.amnew.raw.vcf.filtered.cov.MW.txt' % (lineage), 'w')
    vcf_file_filtered.write('CHR\tPOS\tavg_depth\t%s\n' % ('\t'.join([os.path.basename(vcf).split(fastq_name)[0].split('.')[1] for vcf in allvcfs])) + ''.join(cov_output))
    vcf_file_filtered.close()

################################################### Main ########################################################
# run vcf filtering
all_vcf_file=glob.glob(os.path.join(output_dir,'*%s'%(vcf_name)))

# cluster donor species
all_vcf_file_set = dict()
for vcf_file in all_vcf_file:
    lineage = os.path.basename(vcf_file).split('.')[0]
    all_vcf_file_set.setdefault(lineage, [])
    all_vcf_file_set[lineage].append(vcf_file)

for lineage in all_vcf_file_set:
    allvcfs = all_vcf_file_set[lineage]
    allvcfs.sort()
    #filter_vcfs(allvcfs, lineage)
    outputcovwindow(allvcfs,lineage)


import io
import json
from dataclasses import dataclass

import avro
from avro.io import DatumWriter, DatumReader, BinaryDecoder

from kpong import PingPongMessage
from kpong.schema import PING_PONG_SCHEMA

def ping_pong_deserializer(message):
    return deserializer(message, PING_PONG_SCHEMA, PingPongMessage.from_dict)

def deserializer(datum, schema: str, mapper: callable):
    avro_schema = avro.schema.parse(json.dumps(schema))
    reader = DatumReader(avro_schema)
    message_bytes = io.BytesIO(datum)
    decoder = BinaryDecoder(message_bytes)
    msg = reader.read(decoder)

    return mapper(msg)

def serializer(message: dataclass, schema):
    avro_schema = avro.schema.parse(json.dumps(schema))

    writer = DatumWriter(avro_schema)
    bytes_writer = io.BytesIO()
    encoder = avro.io.BinaryEncoder(bytes_writer)
    writer.write(message.__dict__, encoder)
    bs = bytes_writer.getvalue()

    return bs


import pandas as pd
import requests
from bs4 import BeautifulSoup
from selenium import webdriver
from selenium.webdriver.support.ui import Select
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

def get_concelhos_name(id_concelho):
    link = 'https://agendamento.irn.mj.pt/steps/get_concelhos.php?id_distrito={0}'.format(str(id_concelho))
    result = requests.get(link)
    c = result.content
    soup = BeautifulSoup(c)

    options = soup.find_all('option')
    names = {x['value']: x.text for x in options}
    del names['']
    return names

def open_page_and_select_cc(query='cc'):
    DRIVER_PATH = 'data/chromedriver'
    driver = webdriver.Chrome(executable_path=DRIVER_PATH)
    driver.get('https://agendamento.irn.mj.pt/steps/step1.php')

    select_servico = Select(driver.find_element_by_xpath('//*[@id="servico"]'))
    if query == 'cc':
        select_servico.select_by_visible_text('Pedido / Renovação de Cartão de Cidadão')
        delay = 1
        button = WebDriverWait(driver, delay).until(EC.element_to_be_clickable((By.XPATH, '//*[@id="myModal"]/div/div/div[3]/button'))).click()

    elif query == 'passport':
        select_servico.select_by_visible_text('Pedido de Passaporte Electrónico')

    else:
        print ("query is cc or passport")

    return driver

def get_distritos_names():
    driver = open_page_and_select_cc()
    html_source = driver.page_source
    soup = BeautifulSoup(html_source)

    distritos = soup.find_all('select')[1].find_all('option')
    names = {x.text: x['value'] for x in distritos}
    del names['Selecione uma opção']

    driver.close()
    return names

def is_validated(distrito, concelho):
    today = pd.to_datetime('today').strftime("%Y-%m-%d")

    link = 'https://agendamento.irn.mj.pt/steps/get_aval.php?f=checkStep1&ids={0}&idc={1}&data={2}&sab=0'.format(str(distrito),
                                                                                str(concelho),
                                                                                str(today))

    result = requests.get(link)
    c = result.content
    soup = BeautifulSoup(c)

    return soup.text

def get_hours(distritos, query='cc'):
    from selenium.webdriver.support.ui import Select

    driver = open_page_and_select_cc(query)
    distrito_dict = get_distritos_names()
    result = pd.DataFrame()
    for distrito in distritos:
        print ("Distrito: {0}".format(distrito))
        concelhos = get_concelhos_name(distrito_dict[distrito])
        select_distrito = Select(driver.find_element_by_xpath('//*[@id="distrito"]'))
        select_distrito.select_by_visible_text(distrito)

        for concelho_id in concelhos.keys():
            print ("Concelho: {0}".format(concelhos[concelho_id]))
            WebDriverWait(driver, 5).until(EC.presence_of_element_located((By.XPATH, '//*[@id="concelho"]/option[2]')))
            select_concelho = Select(driver.find_element_by_xpath('//*[@id="concelho"]'))
            select_concelho.select_by_value(concelho_id)

            driver.find_element_by_xpath('//*[@id="btnSeguinte"]').click()

            try:
                new_page = WebDriverWait(driver, 5).until(EC.presence_of_element_located((By.XPATH, '//*[@id="divHorario"]/h4')))

                html_source = driver.page_source
                soup = BeautifulSoup(html_source)
                dates = soup.find_all('table')
                dates = [x.text[-10:] for x in dates]

                if len(dates) >= 1:
                    table_row = pd.DataFrame(columns=['dates', 'distrito', 'concelho'])
                    table_row['dates'] = dates
                    table_row['distrito'] = distrito
                    table_row['concelho'] = concelhos[concelho_id]

                    result = pd.concat([result, table_row])

                driver.find_element_by_xpath('//*[@id="divHorario"]/button[1]').click()
            except:
                print ("Error")
                button = WebDriverWait(driver, 5).until(EC.element_to_be_clickable((By.XPATH, '//*[@id="myModal_1"]/div/div/div[3]/button'))).click()

    driver.close()
    result = result.sort_values('dates')

    return result


import pickle
import argparse
import numpy as np
from keras.layers import Conv2D, Dense, Flatten, MaxPool2D, Dropout
from keras.layers import BatchNormalization, Activation, LeakyReLU
from keras.models import Model, Input, load_model
from keras.utils import to_categorical
from keras.callbacks import EarlyStopping, ModelCheckpoint

MAX_LEN = 200

def build():
    input_shape = Input([20, MAX_LEN, 1])

    out = Conv2D(32, [4, 10], padding='same')(input_shape)
    out = BatchNormalization()(out)
    out = LeakyReLU()(out)
    # out = MaxPool2D([2, 2])(out)
    # out = Dropout(0.4)(out)

    out = Conv2D(32, [4, 10], strides=[1, 2], padding='same')(out)
    out = BatchNormalization()(out)
    out = LeakyReLU()(out)
    out = MaxPool2D([2, 2])(out)
    out = Dropout(0.4)(out)

    out = Conv2D(64, [4, 10], strides=[1, 2], padding='same')(out)
    out = BatchNormalization()(out)
    out = LeakyReLU()(out)
    # out = MaxPool2D([2, 2])(out)
    # out = Dropout(0.4)(out)

    out = Conv2D(64, [4, 10], strides=[1, 2], padding='same')(out)
    out = BatchNormalization()(out)
    out = LeakyReLU()(out)
    out = MaxPool2D([2, 2])(out)
    out = Dropout(0.4)(out)

    out = Flatten()(out)

    out = Dense(64)(out)
    out = BatchNormalization()(out)
    out = Activation('relu')(out)
    out = Dropout(0.4)(out)
    #
    # out = Dense(32)(out)
    # out = BatchNormalization()(out)
    # out = Activation('relu')(out)
    # out = Dropout(0.7)(out)

    out = Dense(41)(out)
    out = Activation('softmax')(out)

    model = Model(inputs=input_shape, outputs=out)
    model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['acc'])

    return model

def datagen(x, y, batch_size):
    num = len(y)
    while True:
        xx = np.zeros([batch_size, 20, MAX_LEN, 1])
        ind = np.random.choice(num, batch_size, replace=False)
        for i, j, in enumerate(ind):
            # max_ind = np.argmax(x[j].sum(0))
            # left = max(0, max_ind - MAX_LEN//2)
            # piece = x[j][:, left:left+MAX_LEN].reshape([20, -1, 1])
            # xx[i, :, :piece.shape[1]] = piece
            xx[i, :, :x[j].shape[1]] = x[j][:, :MAX_LEN].reshape([20, -1, 1])
        yield xx, y[ind]

def score(y, preds):
    sc = np.zeros(41, dtype=np.float64)
    sc[:3] = np.array([1, 1/2, 1/3])
    count = 0
    for i in range(len(y)):
        ans = y[i]
        pred = preds[i]
        pred = np.argsort(pred)[::-1]
        count += np.sum((pred == ans) * sc)
    return count

def run(args):
    with open(args.xy, 'rb') as f:
        pk = pickle.load(f)
    data, labels = pk['data'], pk['labels']
    labels = to_categorical(labels, 41)

    idx = np.random.choice(len(data), len(data), replace=False)
    data = data[idx]
    labels = labels[idx]

    x_train = data[:args.train_num]
    x_valid = data[args.train_num:]
    y_train = labels[:args.train_num]
    y_valid = labels[args.train_num:]

    if args.semi:
        with open(args.semi, 'rb') as f:
            pk = pickle.load(f)
        s_data = pk['data']
        s_labels = to_categorical(pk['labels'], 41)
        idx = np.random.choice(len(s_data), 1000)
        s_data = s_data[idx]
        s_labels = s_labels[idx]
        x_train = np.concatenate([x_train, s_data])
        y_train = np.concatenate([y_train, s_labels])

    callbacks = [EarlyStopping(monitor='val_loss', patience=5),
                 ModelCheckpoint(args.model_path, monitor='val_loss', save_best_only=True)]

    model = build()
    # model.summary()
    model.fit_generator(
        datagen(x_train, y_train, args.batch_size),
        epochs=args.epochs,
        steps_per_epoch=100,
        validation_data=datagen(x_valid, y_valid, args.batch_size),
        validation_steps=10,
        callbacks=callbacks
    )
    # model.save(args.model_path)

def parse():
    parser = argparse.ArgumentParser()
    parser.add_argument('xy')
    parser.add_argument('model_path')
    parser.add_argument('-i', type=int, default=100, dest='epochs')
    parser.add_argument('-b', type=int, default=200, dest='batch_size')
    parser.add_argument('-n', type=int, default=8000, dest='train_num')
    parser.add_argument('-s', dest='semi')
    return parser.parse_args()

if __name__ == '__main__':
    run(parse())
    # f = lambda: None
    # for i in range(31, 40):
    #     setattr(f, 'xy', 'pickle/xy.pickle')
    #     setattr(f, 'model_path', 'mfcc/mfcc%d.mdn' % i)
    #     setattr(f, 'batch_size', 200)
    #     setattr(f, 'train_num', 8500)
    #     setattr(f, 'epochs', 100)
    #     setattr(f, 'semi', None)
    #     run(f)


from glob import glob
import time
import os.path
import os
import numpy as np
from .utils import return_diff_structures, create_output_file

def check_structure(user: str,
                    session: str,
                    movement: str,
                    warping_paths: np.ndarray,
                    output_path: str,
                    plot_path: str,
                    segment_divider: int = 25,
                    diff_max: int = 3,
                    diff_min: int = 0.13,
                    area_diff: int = 10,
                    output: bool = True,
                    excel: bool = True,
                    csv: bool = True,
                    debug: bool = True,
                    plotting: bool = False,
                    rewrite: bool = False):
    """
    Check the structure of audio recordings based on the slope of warping paths.

    Args:
        user:
        session:
        movement:
        warping_paths:
        output_path:
        plot_path:
        segment_divider:
        diff_max:
        diff_min:
        area_diff:
        output:
        excel:
        csv:
        debug:
        plotting:
        rewrite:
    """

    output_diff_filename = f'{user}_{session}_mov{movement}_diff_structure'
    output_same_filename = f'{user}_{session}_mov{movement}_same_structure'

    if not rewrite:
        if os.path.exists(f'{output_path}/xlsx/{output_same_filename}.xlsx'):
            return None

    # starts the time counter
    if debug:
        tcalcstart = time.time()

    # returns list of filenames with different structures and list of different areas from DTW
    diff_structure_list, same_structure_list = return_diff_structures(warping_paths=warping_paths,
                                                                      output_path=output_path,
                                                                      plot_path=plot_path,
                                                                      segment_divider=segment_divider,
                                                                      diff_max=diff_max,
                                                                      diff_min=diff_min,
                                                                      area_diff=area_diff,
                                                                      plotting=plotting,
                                                                      debug=debug)

    if not os.path.isdir(output_path):
        os.mkdir(output_path)

    if output:
        create_output_file(diff_structure_list=diff_structure_list, path_to_output=output_path,
                           output_filename=output_diff_filename,
                           excel=excel, csv=csv)
        create_output_file(diff_structure_list=same_structure_list, path_to_output=output_path,
                           output_filename=output_same_filename,
                           excel=excel, csv=csv)

    # stops the timer and writes output to console
    if debug:
        tcalcend = time.time()
        calctime = round(tcalcend - tcalcstart, 2)

    num_of_diff_structure = len(diff_structure_list)

    print("Calculation finished!")
    if debug:
        print(f"Total calculation time: {calctime}")
    print(f"Number of different structures found: {num_of_diff_structure}")
    print(f'List of recordings with different structures: {diff_structure_list}\n')

if __name__ == '__main__':

    from ..src.config import *

    chroma_style = 'chroma'  # chroma or beat

    for no_of_comp, user in enumerate(users):
        for session, reference_name in zip(sessions[no_of_comp], references[no_of_comp]):
            for movement in movements:

                ref_file = f'{reference_name}_{movement}'
                plot_path = f'{user}/{session}/mov{movement}'
                reference_CD = reference_name[:3]
                print(f'reference_CD: {reference_CD}, {user}, {session}, mov{movement}')

                warping_paths = glob(f'../data/{user}/{session}/mov{movement}/warping_paths/{chroma_style}/*')

                check_structure(user=user,
                                session=session,
                                movement=movement,
                                warping_paths=warping_paths,
                                plot_path=plot_path,
                                output_path=f'outputs',
                                plotting=True,
                                debug=False,
                                excel=True,
                                csv=True,
                                output=True,
                                rewrite=True)
                print('---segment done---')

    print('---done---')


from datetime import datetime
from pyelasticsearch import ElasticSearch
from dbconnect import *

import argparse
import json
import os

es = ElasticSearch()

ap = argparse.ArgumentParser()
ap.add_argument("-d", "--date", required = True, help = "date to index")
args = vars(ap.parse_args())

ad_mapping = {
    'ad': {
        'properties': {
            'channelId': {'type': 'integer'},
            'channelName': {'type': 'string'},
            'adId': {'type': 'integer'},
            'adUrl': {'type': 'string'},
            'adType': {'type': 'string'},
            'adSize': {'type': 'string'},
            'dateCreated': {'type': 'date', 'format' : 'YYYY-MM-dd HH:mm:ss'},
            'websiteId': {'type': 'integer'},
            'website': {'type': 'string', 'analyzer': 'simple'},
            'category': {'type': 'string'},
            'subCategory': {'type': 'string'}
        }
    }
}

es.health(wait_for_status='yellow')
es.delete_index('write-ads')
es.create_index('write-ads', settings={'mappings': ad_mapping})

dateYMD = args["date"]
prepareDataFromDB(dateYMD)

dir = DATA_FILES_JSON + '/' + dateYMD
for filename in os.listdir(dir):
    if filename.endswith('.json'):
        with open(dir + '/' + filename) as open_file:
            json_docs = json.load(open_file)
            es.bulk((es.index_op(doc) for doc in json_docs),
                index='write-ads',
                doc_type='ad')

es.refresh("write-ads")

res = es.search('website:com', index='write-ads')
print("Got %d Hits for .com websites" % res['hits']['total'])
for hit in res['hits']['hits']:
    print (hit["_source"])
res = es.search('website:in', index='write-ads')
print("Got %d Hits for .in websites" % res['hits']['total'])
res = es.search('category:entertainment', index='write-ads')
print("Got %d Hits for category:Entertainment" % res['hits']['total'])


from flask import Blueprint, render_template, request, jsonify, session
import random, json

views = Blueprint(__name__, "views")

the_score = 0

board_data = []
hand_data = []

vowels = ['a', 'e', 'i', 'o', 'u']

 # Define the letters with their corresponding values
letter_values = {
    'a': 1, 'b': 3, 'c': 3, 'd': 2, 'e': 1, 'f': 4, 'g': 2, 'h': 4,
    'i': 1, 'j': 8, 'k': 5, 'l': 1, 'm': 3, 'n': 1, 'o': 1, 'p': 3,
    'q': 10, 'r': 1, 's': 1, 't': 1, 'u': 1, 'v': 4, 'w': 4, 'x': 8,
    'y': 4, 'z': 10
}

# Define the weights of the high-value letters
# The weights determine how often the letter will appear
letter_weights = {
    'j': 0.1, 'q': 0.1, 'x': 0.2, 'z': 0.2
}

def generate_letters():
    letters = []
    vowel_count = 0

    for i in range(7):
        if i < 2 or vowel_count < 2:
            # Generate a random letter
            letter = chr(random.randint(ord('a'), ord('z')))

            # Check if it's a vowel
            if letter in vowels:
                vowel_count += 1
        else:
            # Generate a random consonant
            # Use letter_weights to determine the probability of selecting a high-value letter
            if random.random() < sum(letter_weights.values()):
                letter = random.choices(list(letter_weights.keys()), weights=list(letter_weights.values()))[0]
            else:
                letter = chr(random.randint(ord('b'), ord('y')))

        letters.append(letter)

    # Shuffle the letters to make the distribution more random
    random.shuffle(letters)

    return letters

def refresh_letters(word, hand):
    # Iterate through each active letter, replace them with a new letter
    for letter in word.lower():
        newletter = chr(random.randint(ord('a'), ord('z')))
        hand = hand.replace(letter, newletter, 1)
    return hand

def validate_word(word):
    # Load dictionary file
    # Credit: https://github.com/dwyl/english-words for dictionary
    with open('assets/words_alpha.txt', 'r') as f:
        dictionary = set([word.strip() for word in f.readlines()])

    # Check if string is in dictionary, then reformat and return it
    if word.lower() in dictionary:
        return True
    else:
        return '"%s" is not a valid word.' % word.lower().capitalize()

def register_slots(slots, word):
    #returns an array that maps active letters to their slots to fill board
    return []

def calculate_score(word):
    score = 0
    for letter in word.lower():
        if letter in letter_values:
            score += letter_values[letter]
    return score

@views.route("/")
def home():
    letters = generate_letters()

    return render_template('index.html', letters=letters, score=the_score, name="Scrabble!")

@views.route("/populate_board", methods=["POST"])
def populate_board():
    print("populate_board")

@views.route("/populate_hand", methods=["POST"])
def populate_hand():
    print("populate_hand")

@views.route("/submit-word", methods=["POST"])
def play_word():
    # handle the request data
    word = request.json.get("word")
    slots = request.json.get("slots")
    oldletters = request.json.get("old_letters")

    #regenerate more letters for empty slots
    letters = refresh_letters(word, oldletters)

    # validate the word given to the server
    result = validate_word(word)

    # calculate the total value of the word
    score = calculate_score(word)

    # return a JSON response
    return jsonify(message=result, score=score, letters=letters)


from requests import get
from bs4 import BeautifulSoup

def main():
    res = get(
        "https://medium.com/towards-data-science/the-5-basic-statistics-concepts-data-scientists-need-to-know-2c96740377ae"
    )

    soup = BeautifulSoup(res.content, "html.parser")
    h1s = soup.find_all(name="h1", recursive=True)
    print()

    for h1 in h1s:
        print(h1.getText())

if __name__ == "__main__":
    main()


import pandas as pd
from packaging import version
from typing import Union, List

is_deprecated_lexsorted_pandas = version.parse(pd.__version__) > version.parse("1.3.0")

def get_level_index(df: pd.DataFrame, level=Union[str, int]) -> int:
    if isinstance(level, str):
        try:
            return df.index.names.index(level)
        except (AttributeError, ValueError):
            return ("datetime", "instrument").index(level)
    elif isinstance(level, int):
        return level
    else:
        raise NotImplementedError(f"This type of input is not supported")

def lazy_sort_index(df: pd.DataFrame, axis=0) -> pd.DataFrame:
    idx = df.index if axis == 0 else df.columns
    if (
        not idx.is_monotonic_increasing
        or not is_deprecated_lexsorted_pandas
        and isinstance(idx, pd.MultiIndex)
        and not idx.is_lexsorted()
    ):  # this case is for the old version
        return df.sort_index(axis=axis)
    else:
        return df

def fetch_df_by_index(
    df: pd.DataFrame,
    selector: Union[pd.Timestamp, slice, str, list, pd.Index],
    level: Union[str, int],
    fetch_orig=True,
) -> pd.DataFrame:
    # level = None -> use selector directly
    if level is None or isinstance(selector, pd.MultiIndex):
        return df.loc(axis=0)[selector]
    # Try to get the right index
    idx_slc = (selector, slice(None, None))
    if get_level_index(df, level) == 1:
        idx_slc = idx_slc[1], idx_slc[0]
    if fetch_orig:
        for slc in idx_slc:
            if slc != slice(None, None):
                return df.loc[
                    pd.IndexSlice[idx_slc],
                ]
        else:  # pylint: disable=W0120
            return df
    else:
        return df.loc[
            pd.IndexSlice[idx_slc],
        ]

def fetch_df_by_col(df: pd.DataFrame, col_set: Union[str, List[str]]) -> pd.DataFrame:

    if not isinstance(df.columns, pd.MultiIndex) or col_set == '__raw':
        return df
    elif col_set =='__all':
        return df.droplevel(axis=1, level=0)
    else:
        return df.loc(axis=1)[col_set]


import argparse
import yaml
import os
import os.path as osp
from sklearn.model_selection import ParameterGrid
import shutil

class MyDumper(yaml.Dumper):
    def increase_indent(self, flow=False, indentless=False):
        return super(MyDumper, self).increase_indent(flow, False)

def parse_args():
    """Parses the arguments."""
    parser = argparse.ArgumentParser()
    parser.add_argument(
        '--config',
        dest='config',
        help='the base configuration file used for edit',
        default=None,
        type=str
    )
    parser.add_argument(
        '--grid',
        dest='grid',
        help='configuration file for grid search',
        required=True,
        type=str
    )
    parser.add_argument(
        '--out-dir',
        dest='out_dir',
        help='output directory for generated config files',
        default='configs',
        type=str
    )
    return parser.parse_args()

def generate_grid_configs(config, grid, out_dir):
    """Generate grid configs."""
    shutil.rmtree(out_dir, ignore_errors=True)
    os.makedirs(out_dir, exist_ok=True)
    keys = list(grid.keys())
    alias = {k: grid[k]['alias'] for k in keys}
    param_grid = {key: grid[key]['range'] for key in keys}
    grid_space = list(ParameterGrid(param_grid))
    for i, params in enumerate(grid_space):
        new_config = config.copy()
        title = ""
        for key in keys:
            key_path = key.split('.')
            d = new_config
            for k in key_path[:-1]:
                d = d[k]
            d[key_path[-1]] = params[key]
            title += '{}={}'.format(alias[key], params[key])
        new_config['title'] = '{}_{}'.format(config['title'], title)
        with open(osp.join(out_dir, f'{title}.yml'), 'w') as f:
            yaml.dump(new_config, f, Dumper=MyDumper, default_flow_style=False)

if __name__ == '__main__':
    args = parse_args()
    with open(args.config, 'r') as f:
        config = yaml.load(f, Loader=yaml.FullLoader)
    with open(args.grid, 'r') as f:
        grid = yaml.load(f, Loader=yaml.FullLoader)
    out_dir = os.path.join(args.out_dir, config['title'] + '_grid')
    generate_grid_configs(config, grid, out_dir)


"""migration_1

Revision ID: ccba048477df
Revises:
Create Date: 2022-11-05 09:54:52.229725

"""
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import postgresql

# revision identifiers, used by Alembic.
revision = 'ccba048477df'
down_revision = None
branch_labels = None
depends_on = None

def upgrade() -> None:
    # ### commands auto generated by Alembic - please adjust! ###
    op.add_column('quiz_result', sa.Column('mark', sa.Float(), nullable=True))
    op.drop_column('quiz_result', 'avarage_mark')
    # ### end Alembic commands ###

def downgrade() -> None:
    # ### commands auto generated by Alembic - please adjust! ###
    op.add_column('quiz_result', sa.Column('avarage_mark', postgresql.DOUBLE_PRECISION(precision=53), autoincrement=False, nullable=True))
    op.drop_column('quiz_result', 'mark')
    # ### end Alembic commands ###


#---------------------------------IMPORT MODULES----------------------------------
#user modules
import modules.common as common

#built-in modules
import random

#Assigning variables
mode=''
word=''
hidden_word=''
hint=''
rand=0
hintGiven=''

#Creating lists
Index=[]
hidden_word_list=[]
guessed=[]

#----------------------------------DEFINING FUNCTIONS----------------------------------
#--------------------------------------FUNCTION 1--------------------------------------
def game_mode():
    '''
    This function will get the game mode the user wishes to play

    returns:
        Mode : Mode is a string value which contains the game mode chosen by the user

    '''

    #Defining global variables
    global mode

    #Assigning it an empty string
    mode=''

    #Getting the mode from the user
    while mode == '' :
        print ('\nWhich mode would you like to play?')
        mode = input('Enter "E" for easy, "M" for medium and "H" for hard mode: ').upper()

        common.clearConsole()
        common.Exit(mode)

        if mode == 'E' or mode == 'M' or mode == 'H':
            if mode== 'E' :
                Mode = 'EASY'
            elif mode == 'M' :
                Mode = 'MEDIUM'
            elif mode == 'H' :
                Mode = 'HARD'
        else:
            mode = ''
            print ('\n\nInvalid input! Please try again\n')
    return Mode

#--------------------------------------FUNCTION 2--------------------------------------

def random_word(word_1,word_2,word_3):
    '''
    This function will get a random word from the lists according to the game mode

    Parameters:
        word_1: A list of words
        word_2: A list of words
        word_3: A list of words

    Returns:
        word: The string value which contains the random word
    '''

    #Defining global variables
    global mode,word,hidden_word,rand

    #getting a random number from 0-20
    rand=random.randrange(0,20)

    #getting the random word from the respective list
    if mode == 'E':
        word = word_1[rand].upper()
    if mode == 'M':
        word = word_2[rand].upper()
    if mode == 'H':
        word = word_3[rand].upper()

    return word

#--------------------------------------FUNCTION 3--------------------------------------

def hide_word():
    '''This function will hide the word with underscores'''

    #Defining global variables
    global hidden_word_list,word

    #Creating an empty list
    hidden_word_list=[]

    #Replaces the letter with underscores
    for i in range(len(word)):

        #checks if the character is space
        if ord(word[i]) == 32:
            hidden_word_list.append(' ')

        else:
            hidden_word_list.append('_')

#--------------------------------------FUNCTION 4--------------------------------------

def find_index(word,guess):
    '''
    This function will find the index of guess in word

    Parameters:
        word: The string value in which the index of guess should be found
        guess: The string value to get the index of

    Returns:
        Index: A list which contains the index/indexes of guess in word
    '''

    #Defining global variables
    global Index

    #Creating an empty list
    Index = []

    #Getting the index of guess
    for i in range(len(word)):

        if guess == word[i] :

            #Appending the index to the list
            Index.append(i)

    return Index

#--------------------------------------FUNCTION 5--------------------------------------

def get_hint(hint_1,hint_2,hint_3):
    '''
    This function will display  a hint for the respective word

    Parameters:
        hint_1: A list of hints
        hint_2: A list of hints
        hint_3: A list of hints
    '''

    #defining global variables
    global mode,hint_count,hintGiven,hint

    #checks if user has already taken a hint
    if hint_count==1:

        #asks the user if he/she needs a hint
        need_hint = input('If you need a hint, type "YES": ')

        common.Exit(need_hint)

        if need_hint.upper() == 'YES':
            hintGiven='YES'

            #makes hint_count=0, indicating the user has already taken a hint
            hint_count = 0

            #gets the hint according to the respective word
            if mode == 'E':
                hint = hint_1[rand].upper()
            if mode == 'M':
                hint = hint_2[rand].upper()
            if mode == 'H':
                hint = hint_3[rand].upper()

        else:
            hintGiven='NO'
            hint=''

        #if a hint is provided, prints the hint
        if hint:
            print('hint: ',hint)

    #if hint is already given, prints the hint
    elif hint_count==0:
        hintGiven='YES'
        print('hint: ',hint)

#--------------------------------------FUNCTION 6--------------------------------------

def find_word(hint_1,hint_2,hint_3):
    '''
    This function will allow the user to guess the word

    Parameters:
        hint_1: A list of hints
        hint_2: A list of hints
        hint_3: A list of hints

    Returns:
        Turns: Contains the number of turns provided
        TurnsUsed: Contains the number of turns used
        hintGiven: Contains a yes/no stating if a hint was provided or not
        result: Contains win/loss stating if the user won or lost in the game

    '''

    #Assigning global variables
    global Index,guessed,word,hidden_word_list,hint_count

    #Assigning variables
    tries = len(word)
    Turns=len(word)
    stop = 'no'
    guessed=[]
    hint_count=1
    hidden_word = ''.join(hidden_word_list)
    result=''

    print()

    #Prints the number of letters the word has
    print('The word has',len(word),'letters')

    while stop == 'no':

        #Checks if the word guessed by the user matches the exact word
        if hidden_word == word:

            #Turns used is the number of turns provided minus the tries remaining
            TurnsUsed=Turns-tries
            tries = 0
            print()

            #displays the congratulations message
            print('Congratulations!!\nYou have guessed the word\n\nThe word is: ',word)
            result = 'WIN'
            stop = 'yes'

        #checks if all the tries have exhausted
        elif tries == 0:
            print()

            #displays the message that the user has lost
            print('Sorry you have run out of tries!\n\nThe word is: ',word)
            result = 'LOSS'
            stop = 'yes'
            TurnsUsed=Turns-tries

        #if the user hasnt won or lost the game continues
        else:

            print()

            #the hidden word with underscores is displayed with a space
            print("  ",' '.join(hidden_word))
            print()

            get_hint(hint_1,hint_2,hint_3)

            #a letter is taken from the user as a guess
            guess=input('Enter the letter: ').upper()
            print()

            common.Exit(guess)

            #checks if the letter is already guessed
            if guess in guessed:
                print('You have already guessed this letter, letter: ',guess)

                #a try is exhausted
                tries -= 1
                print('You have',tries,'tries remaining')

            #checks if the input is not a letter, or if it is a blank value
            elif common.is_letter(guess) == False or guess == '' :
                print('Invalid input')

            #checks if the guessed letter is not in the word
            elif guess not in word:
                print('Wrong guess!')

                #the guessed letter is appended to the list of guessed letters
                guessed.append(guess)

                #a try is exhausted
                tries -= 1

                print('You have',tries,'tries remaining')

            #checks if the guessed letter is in the word
            elif guess in word:
                print('Correct guess!')

                #the guessed letter is appended to the list of guessed letters
                guessed.append(guess)

                #finds the index of the guessed letter in the word
                I=(find_index(word,guess))

                #replaces the underscore with the respective guessed letter
                for i in (I):
                    hidden_word_list[i]=guess
                hidden_word = ''.join(hidden_word_list)

                if hidden_word == word:
                    print()
                else:
                    print('You have',tries,'tries remaining')

    return Turns,TurnsUsed,hintGiven,result


import json
import os
import re

def read_json_file(file):
    if os.path.isfile(file):
        print(f'file {file}')
    else:
        exit()

    log = json.load(open(file, 'r'))

    return log

def flat_json_to_kv(an_object, key, kv_result, layer) -> object:
    '''

    :param key:
    :param layer:
    :param an_object:
    :param kv_result:
    :param json_object: a dict object with multiple layers
    :return: a flat dict
    '''

    if isinstance(an_object, dict):
        for key, value in an_object.items():
            flat_json_to_kv(value, key, kv_result, 0)
    elif isinstance(an_object, list):
        for item in an_object:
            flat_json_to_kv(item, key, kv_result, 0)
    else:
        if isinstance(an_object, int) or isinstance(an_object, float):
            an_object = str(an_object)
        if kv_result.get(key, None):
            kv_result[key] = kv_result[key] + " , " + an_object
        else:
            kv_result.update({key: an_object})

    return kv_result

if __name__ == "__main__":
    file = 'log.json'
    log = read_json_file(file)
    print(log)
    result = flat_json_to_kv(log, "", {}, 0)
    print(result)


import numpy as np
import matplotlib.pyplot as plt
from tqdm import tqdm
import arc as arc

import numpy as np
import scipy.constants as consts
from scipy.stats import maxwell
import os, sys
from functools import partialmethod

##############################################################################################################################

class HiddenPrints:
    """Class for suppressing stdout (print) for some part of the code"""
    def __enter__(self):
        self._original_stdout = sys.stdout
        sys.stdout = open(os.devnull, 'w')

    def __exit__(self):
        sys.stdout.close()
        sys.stdout = self._original_stdout

##############################################################################################################################

class LaserCooling:
    """ Class representation of 1D Optical Molasses laser cooling of Rubidium-87 in the
        |n1 = 5, l1 = 1, j1 = 3/2> to |n2 = 5, l2= 0, j2 = 1/2> transition """

    def __init__(self, initial_temperature = 0.001, nr_particles = 1000, I_of_I_sat = 1/100, dB_dx = 0):

        assert type(nr_particles) is int,         f"Nr_particles given as {type(nr_particles)}, but should be {int}."
        assert nr_particles >= 1,                 f"Nr_particles should be at least 1."
        assert initial_temperature  >  0,         f"Initial_temperature has to be > 0."
        assert I_of_I_sat < 1 and I_of_I_sat > 0, f"I_of_I_sat should be 0 < I_of_I_sat < 1."
        assert dB_dx >= 0,                        f"dB_dx should be >= 0."

        self.saturation_fraction = I_of_I_sat           # Fraction of saturation intensity used in laser.
        self.temperature         = initial_temperature  # In units of [K]
        self.nr_particles        = nr_particles
        self.magnetic_gradient   = dB_dx

        self.atom       = self.set_atom()
        self.mass       = self.set_mass()
        self.gamma      = self.set_gamma()
        self.omega_0    = self.set_omega0()

        self.initial_speeds   = self.set_initial_speeds()
        self.initial_positions = self.set_initial_position()

    def set_atom(self):
        """ Function for setting the mass of the Rubidium 87 atom

        Returns:
        --------
            atom: instance of arc.alkali_atom_data.Rubidium87 class

        """
        atom = arc.alkali_atom_data.Rubidium87()
        return atom

    def set_mass(self) -> float:
        """ Function for setting the mass of the Rubidium 87 atom

        Returns:
        --------
            mass: float

        """
        mass = arc.alkali_atom_data.Rubidium87.mass
        return mass

    def set_omega0(self) -> float:
        """ Function for computing the angular transition resonance frequncy ω0
        of the chosen transition

        Returns:
        --------
            omega_0: float

        """
        omega_0 = 2 * np.pi * self.atom.getTransitionFrequency(n1 = 5, l1= 0, j1 = 0.5, n2 = 5, l2 = 1, j2 = 3/2)

        return omega_0

    def set_gamma(self) -> float:
        """ Function for computing the natural linewidth Γ

        Returns:
        --------
            Natural_linewidth: float
        """
        Transition_rate   = self.atom.getTransitionRate(n2 = 5, l2= 0, j2 = 0.5, n1 = 5, l1 = 1, j1 = 3/2)
        Lifetime          = 1 / Transition_rate
        Natural_linewidth = 1 / (2 * np.pi * Lifetime) * 2 * np.pi
        return Natural_linewidth

    def set_initial_speeds(self) -> np.ndarray:
        """ Function for sampling initial speeds for the atoms
        from the maxwell-boltzman distribution. Here this is achieved
        by means of the 'Inverse CDF sampling' method where sampling
        N points from a given PDF is similar to evaluating its inverse CDF
        on N uniformly distributed points (in Uniform(0,1)).

        Returns:
        --------
            speeds: np.ndarray of shape (nr_particles,) containing floats
        """
        PARENT_SAMPLE_SIZE = 1000000
        u                  = np.random.uniform(low = 0, high = 1, size = PARENT_SAMPLE_SIZE)
        scale_factor       = np.sqrt(consts.k * self.temperature / (self.mass))      # sqrt(kT/m)
        speeds             = maxwell.ppf(q = u, scale = scale_factor)                # ppf is inverse cdf in scipy
        return speeds[:self.nr_particles]

    def set_initial_position(self) -> np.ndarray:
        """ Function for sampling initial positions of the atoms.
        here it is simply assumed that the atoms are gaussianly
        distributed around 0 with som chosen standard deviation.

        Returns:
        --------
            positions: np.ndarray of shape (nr_particles,) containing floats.
        """
        standard_deviation = 0.1
        expectation_value  = 0.0
        positions = np.random.normal(loc = expectation_value, scale = standard_deviation, size=self.nr_particles)
        return positions

##############################################################################################################################

class Simulation:
    """Class representation of a Monte Carlo simulation of given laser cooling setup."""

    def __init__(self, MyLaserCooling, stepsize = 0.001, tmax = 1, with_emission = True):

        assert stepsize <= 0.001 and stepsize > 0.0, f"Stepsize should be:  0 < stepsize < 0.001 ."
        assert tmax >= 10 * stepsize,                f"Tmax should be:  Tmax >= 10 * stepsize for any meaningfull simuation."
        assert type(with_emission) is bool,          f"With_emission given as {type(with_emission)}, but should be {bool}. "

        self.with_emission   = with_emission
        self.stepsize        = stepsize         # In units of [s]
        self.tmax            = tmax             # In units of [s]

        self.MyLaserCooling  = MyLaserCooling

        self.beta            = self.set_beta()

        self.ts                                             = None
        self.xs_with_emission, self.vxs_with_emission       = None, None
        self.xs_without_emission, self.vxs_without_emission = None, None

        self.Es_with_emission, self.Es_without_emission     = None, None
        self.Temperature_with_emission                      = None
        self.Temperature_without_emission                   = None

        self.omegas                                         = None
        self.multiple_temperatures_without_emission         = None
        self.multiple_temperatures_with_emission            = None

    def temperature_dependency(self,detuning) -> int or float:
        """ Function that computes the temperature for some chosen detuning
            accoring to eq. (9.27) in Christopher J. Foot - Atomic Physics, Oxford University Press 2005

        Parameters:
        -----------
            detuning: int or float or
                      1D np.ndarray of floats or 1D np.ndarray of ints

        Returns:
        --------
            temperature: same type as given detuning.

        """
        gamma       = self.MyLaserCooling.gamma
        temperature = (consts.hbar * gamma) / (4 * consts.k) * (1 + (2 * detuning / gamma)**2) / (-2 * detuning / gamma)
        return temperature

    def set_beta(self) -> float:
        """ Function for calculating the beta parameter from
            eq. (9.31) in Christopher J. Foot - Atomic Physics, Oxford University Press 2005

        Returns:
        --------

        """
        g    = self.MyLaserCooling.atom.getLandegjExact(s = 0.5, j = 1/2, l = 0)
        U_B  = consts.e * consts.hbar/(2 * consts.electron_mass)

        beta = (g * U_B / consts.hbar) * self.MyLaserCooling.magnetic_gradient
        return beta

    def nr_scattered_photons(self, dt, omega, seed) -> int:
        """ Function for computing a realistic estimate of the actual number
            scattered photons by first calculating the expectation value <N>
            according to eq. (9.4) in Christopher J. Foot - Atomic Physics, Oxford University Press 2005
            and the drawing the 'actual number' as a sample from a poissonian distributed around <N>.

        Parameters:
        -----------
            dt    : float or int - the time over which <N> is calculted

            omega : float or int - ω in δ = ω - ω0

            seed  : int - for insuring difference in the return of
                  the random functions for each call

        Returns:
        --------
            actual_nr : int - the number of scattered photons during dt.
        """
        I_Isat, gamma  = self.MyLaserCooling.saturation_fraction, self.MyLaserCooling.gamma

        expectation_nr = dt * (gamma / 2) * (I_Isat) / (1 + I_Isat + 4 * (omega - self.MyLaserCooling.omega_0)**2 / gamma**2)
        generator      = np.random.default_rng(seed=seed)
        actual_nr      = generator.poisson(lam=expectation_nr)
        return actual_nr

    def spherical_sampling(self,nr_photons) -> np.ndarray or float:
        """ Function for sampling the amount that nr_photons
            contributes with change in momentum along x-axis
            under the assumption of isotropic emission, i.e.
            that the photons ar uniformly emitted through a
            sphere.

            This is done first by means of 'Inverse CDF sampling'
            where sampling N points from a given PDF is similar to
            evaluating its inverse CDF on N uniformly distributed
            points (in Uniform(0,1)).

        Parameters:
        -----------
            nr_photons: int - the number of photons emitted.

        Returns:
        --------
            x: np.ndarray of shape (nr_photons,) containing floats
               or float
        """
        theta = np.random.uniform(0,np.pi,nr_photons)
        phi   = np.arccos(1 - 2 * np.random.uniform(0,1,nr_photons)) # This is the inverse CDF
        x     = np.sin(phi) * np.cos(theta)                          # Transforming to cartesian coordinates
        return x

    def set_wavenumber(self, omega) -> float:
        """ Function for computing the wavenumber 'k'
        of some wave, given its angular frequency.

        Parameters:
        -----------
            omega: float

        Returns:
        --------
            k: float
        """
        k = omega/consts.c
        return k

    def set_alpha(self, omega) -> float:
        """ Function for computing the alpha parameter according to
            eq. (9.17) in Christopher J. Foot - Atomic Physics, Oxford University Press 2005.

        Parameters:
        -----------
            omega: float

        Returns:
        --------
            alpha: float

        """
        omega_0    = self.MyLaserCooling.omega_0
        detuning   = omega - omega_0
        wavenumber = self.set_wavenumber(omega)
        gamma      = self.MyLaserCooling.gamma
        I_Isat     = self.MyLaserCooling.saturation_fraction

        alpha = 4. * consts.hbar * wavenumber**2 * I_Isat * (-2 * detuning / gamma)/(1 + (2 * detuning/gamma)**2)**2
        return alpha

    def simulate_one_detuning(self,omega):
        """ Function for simulating the laser cooling for a single detuning.
            stores results in class attributes seen in constructor.

        Parameters:
        -----------
            omega: float
        """
        alpha = self.set_alpha(omega=omega)
        k     = self.set_wavenumber(omega=omega)

        ts = None
        xs_with_emission, vxs_with_emission       = [], []
        xs_without_emission, vxs_without_emission = [], []

        print("-"*10+" Simulating cooling process "+"-"*10)

        for i in tqdm(range(len(self.MyLaserCooling.initial_speeds))):
            ts_i = [0]
            start_x, start_vx = self.MyLaserCooling.initial_positions[i], self.MyLaserCooling.initial_speeds[i]
            xs_i_with_emission, vxs_i_with_emission       = [start_x], [start_vx]
            xs_i_without_emission, vxs_i_without_emission = [start_x], [start_vx]
            time = 0

            while(time <= self.tmax):
                x_with_emission, vx_with_emission       = xs_i_with_emission[-1], vxs_i_with_emission[-1]
                x_without_emission, vx_without_emission = xs_i_without_emission[-1], vxs_i_without_emission[-1]

                step = self.stepsize
                time += step

                if self.with_emission:
                    # Calculating forces - with emission
                    seed1, seed2 = int((i + 1) * 1000 * time),  int(2 * (i + 1) * 1000 * time)
                    nr1_with_emission          = self.nr_scattered_photons(step, omega - k * vx_with_emission, seed1)
                    nr2_with_emission          = self.nr_scattered_photons(step, omega + k * vx_with_emission, seed2)

                    DP_absorbtion_with_emission = consts.hbar * k * (nr1_with_emission - nr2_with_emission)
                    DP_emmission = consts.hbar * k * np.sum(self.spherical_sampling(nr1_with_emission+nr2_with_emission))

                    DP_total_with_emission = DP_absorbtion_with_emission + DP_emmission - alpha * self.beta * x_with_emission * step / k

                # Calculating forces - without emission
                seed1, seed2 = int((i + 1) * 1000 * time),  int(2 * (i + 1) * 1000 * time)
                nr1_without_emission          = self.nr_scattered_photons(step, omega - k * vx_without_emission, seed1)
                nr2_without_emission          = self.nr_scattered_photons(step, omega + k * vx_without_emission, seed2)

                DP_absorbtion_without_emission = consts.hbar * k * (nr1_without_emission - nr2_without_emission)

                DP_total_without_emission = DP_absorbtion_without_emission - alpha * self.beta * x_without_emission * step / k

                # Updating vals
                xs_i_with_emission.append(x_with_emission + step * vx_with_emission)
                vxs_i_with_emission.append(vx_with_emission + DP_total_with_emission / self.MyLaserCooling.mass)

                xs_i_without_emission.append(x_without_emission + step * vx_without_emission)
                vxs_i_without_emission.append(vx_without_emission + DP_total_without_emission / self.MyLaserCooling.mass)

                ts_i.append(time)

            xs_without_emission.append(xs_i_without_emission)
            vxs_without_emission.append(vxs_i_without_emission)

            if self.with_emission:
                xs_with_emission.append(xs_i_with_emission)
                vxs_with_emission.append(vxs_i_with_emission)

            if i == 0:
                ts = ts_i

        self.ts                                             = ts
        self.xs_without_emission, self.vxs_without_emission = xs_without_emission, vxs_without_emission

        if self.with_emission:
            self.xs_with_emission, self.vxs_with_emission   = xs_with_emission, vxs_with_emission

        print("-"*10+" Calculating energies and temperatures "+"-"*10)

        Es_without_emission = np.zeros(len(ts))
        for i in tqdm(range(len(ts))):
            Es_without_emission[i] += np.sum(0.5 * self.MyLaserCooling.mass * (np.array(self.vxs_without_emission)[:,i])**2)
        self.Es_without_emission          = Es_without_emission
        self.Temperature_without_emission = 2 * self.Es_without_emission/(self.MyLaserCooling.nr_particles * consts.k)

        if self.with_emission:
            Es_with_emission = np.zeros(len(ts))
            for i in tqdm(range(len(ts))):
                Es_with_emission[i] += np.sum(0.5*self.MyLaserCooling.mass * (np.array(self.vxs_with_emission)[:,i])**2)
            self.Es_with_emission          = Es_with_emission
            self.Temperature_with_emission = 2 * self.Es_with_emission/(self.MyLaserCooling.nr_particles * consts.k)

    def simulate_multiple_detunings(self,omegas):
        """ Function for doing simulation for multiple values of detuning.
            stores results in class attributes seen in constructor.

        Parameters:
        -----------
            omegas: list of floats or list of ints
                    or np.ndarray of floats or np.ndarray of ints

        """

        self.omegas = omegas

        xs_with_emission, vxs_with_emission       = [], []
        xs_without_emission, vxs_without_emission = [], []

        print("-" * 10 + f" Simulating laser cooling for {len(omegas)} detunings " + 10 * "-")
        with HiddenPrints():
            for idx in tqdm(range(len(omegas))):
                tqdm.__init__ = partialmethod(tqdm.__init__, disable=True)
                self.simulate_one_detuning(omega=omegas[idx])

                xs_with_emission.append(self.xs_with_emission)
                vxs_with_emission.append(self.vxs_with_emission)

                xs_without_emission.append(self.xs_without_emission)
                vxs_without_emission.append(self.vxs_without_emission)
                tqdm.__init__ = partialmethod(tqdm.__init__, disable=False)

        print("-" * 10 + " Calculating energies and corresponding temperatures" + 10 * "-")
        Es_without_emission = []
        for j in tqdm(range(len(vxs_without_emission))):
            Es = np.zeros(len(self.ts))
            for i in range(len(self.ts)):
                Es[i] += np.sum(0.5*self.MyLaserCooling.mass*(np.array(vxs_without_emission[j])[:,i])**2)
            Es_without_emission.append(Es)
        Es_without_emission = np.array(Es_without_emission)

        FRACTION = len(Es_without_emission) // 20 ## Using mean of last 5% of energy vals

        Temperatures_without_emission = []
        for Es in Es_without_emission:
            Temperatures_without_emission.append(2 * np.mean(Es[len(Es) - FRACTION:]) / (self.MyLaserCooling.nr_particles * consts.k))

        self.multiple_temperatures_without_emission = Temperatures_without_emission
        if self.with_emission:
            Es_with_emission = []
            for j in tqdm(range(len(vxs_with_emission))):
                Es = np.zeros(len(self.ts))
                for i in range(len(self.ts)):
                    Es[i] += np.sum(0.5*self.MyLaserCooling.mass*(np.array(vxs_with_emission[j])[:,i])**2)
                Es_with_emission.append(Es)
            Es_with_emission = np.array(Es_with_emission)

            Temperatures_with_emission = []
            for Es in Es_with_emission:
                Temperatures_with_emission.append(2 * np.mean(Es[len(Es) - FRACTION:]) / (self.MyLaserCooling.nr_particles * consts.k))
            self.multiple_temperatures_with_emission = Temperatures_with_emission


from __future__ import print_function, division
import time
import torch
import numpy as np
import torch.nn.functional as F
from torch.autograd import Variable
from torchnet.meter import ConfusionMeter

use_cuda = torch.cuda.is_available()

# Compute log sum exp in a numerically stable way for the forward algorithm
def log_sum_exp(vec):
    """ Given a vector, return log_sum_exp with last dimension reduced.
    """
    last_dimension = len(vec.size()) - 1
    max_score, _ = torch.max(vec, last_dimension)
    if last_dimension > 0:
        _exp = torch.exp(vec - max_score.unsqueeze(last_dimension))
        _sum = torch.sum(_exp, last_dimension)
    else:
        _exp = torch.exp(vec - max_score)
        _sum = torch.sum(_exp)
    _log = max_score + torch.log(_sum)
    return _log

def cuda_var_wrapper(var, volatile=False):
    var = Variable(var, volatile=volatile)
    if use_cuda:
        var = var.cuda()
    return var

def cuda_tensor_wrapper(tensor):
    if use_cuda:
        tensor = tensor.cuda()
    return tensor

def timeit(method):
    def timed(*args, **kw):
        ts = time.time()
        result = method(*args, **kw)
        te = time.time()
        print('%r  %2.2f ms' % (method.__name__, (te - ts) * 1000))
        return result
    return timed

def parameter_summary(writer, name, param, global_step):
    if isinstance(param, Variable):
        param = param.data
    writer.add_scalars('Train/' + name,
        {name + '_mean': torch.mean(param),
        name + '_std': torch.std(param),
        name + '_max': torch.max(param),
        name + '_min': torch.min(param)}, global_step)
    writer.add_histogram(name, param.clone().cpu().numpy(), global_step, bins='doane')

def sequence_mask(sequence_length, max_len=None):
    if isinstance(sequence_length, Variable):
        sequence_length = sequence_length.data
    if max_len is None:
        max_len = sequence_length.max()
    batch_size = sequence_length.size(0)
    seq_range = torch.arange(0, max_len).long()
    seq_range_expand = seq_range.unsqueeze(0).expand(batch_size, max_len)
    if sequence_length.is_cuda:
        seq_range_expand = seq_range_expand.cuda()
    seq_length_expand = (sequence_length.unsqueeze(1).expand_as(seq_range_expand))
    return (seq_range_expand < seq_length_expand).float()

def precision_recall_f1(confusion_matrix, average=True):
    """Given confusion_matrix in numpy, calculate precision, recall and f1 score.
    """
    confusion_matrix = confusion_matrix.value()
    dim = confusion_matrix.shape[0]
    TP_FP = np.sum(confusion_matrix, 0)
    TP_FN = np.sum(confusion_matrix, 1)
    precision, recall, f1_score = np.zeros(dim), np.zeros(dim), np.zeros(dim)

    for i in range(dim):
        if confusion_matrix[i, i] == 0:
            precision[i] = 0
            recall[i] = 0
            f1_score[i] = 0
        else:
            precision[i] = (confusion_matrix[i, i] / TP_FP[i])
            recall[i] = (confusion_matrix[i, i] / TP_FN[i])
            f1_score[i] = 2 * precision[i] * recall[i] / (precision[i] + recall[i])
    if average:
        return np.mean(precision), np.mean(recall), np.mean(f1_score)
    else:
        return precision, recall, f1_score

def get_batch_accuracy(labels, output, lengths):
    correct = 0.0
    total = 0.0
    if len(output.size()) > 2:
        _, output = torch.max(F.softmax(output, 2), 2)
    if isinstance(output, Variable):
        output = output.data
    correct_matrix = torch.eq(output, labels.data).float()
    mask = sequence_mask(lengths)
    correct = torch.sum(correct_matrix * mask)
    total = torch.sum(lengths.data)
    return correct, total

def evaluate(model, dataloader, crf, criterion, f1=False):
    model.eval()
    if f1:
        confusion_matrix = ConfusionMeter(8)
        confusion_matrix.reset()
    correct, total = 0, 0
    loss_total = 0
    for i, (features, labels, _, lengths) in enumerate(dataloader):
        max_length = max(lengths)
        features = cuda_var_wrapper(features[:, :, :max_length], volatile=True)
        labels = cuda_var_wrapper(labels[:, :max_length], volatile=True)
        lengths = cuda_var_wrapper(lengths)
        if crf:
            _, output = model(features, lengths)
            loss = model.forward_alg(features, labels, lengths)
            preds = output
        else:
            output = model(features)
            loss = criterion(output.contiguous().view(-1, 8), labels.contiguous().view(-1))
            _, preds = torch.max(F.softmax(output, 2), 2)
        correct_batch, total_batch = get_batch_accuracy(labels, output, lengths)
        loss_total += loss.data[0] * features.size()[0]
        correct += correct_batch
        total += total_batch
        if f1:
            if isinstance(preds, Variable):
                preds = preds.data
            for pred, truth, length in zip(preds, labels.data, lengths.data):
                confusion_matrix.add(pred[:length], truth[:length])
    if f1:
        # print(confusion_matrix.value())
        precision, recall, f1 = precision_recall_f1(confusion_matrix)
        return correct / total, loss_total, precision, recall, f1
    return correct / total, loss_total

def eval(model, features, labels, lengths, crf, criterion):
    model.eval()
    if crf:
        _, output = model(features, lengths)
        loss = model.forward_alg(features, labels, lengths)
    else:
        output = model(features)
        loss = criterion(output.contiguous().view(-1, 8), labels.contiguous().view(-1))
    loss_batch = loss.data[0] * features.size()[0]
    correct_batch, total_batch = get_batch_accuracy(labels, output, lengths)
    return correct_batch, total_batch, loss_batch

def crf_param(model):
    """Given the model with CRF as the last layer, return the crf transition
    parameters without the START and STOP column and row.
    """
    crf_param = list(model.children())[-1].transitions.cpu().data.numpy()
    crf_param_2 = np.delete(crf_param, 8, 0)
    crf_param_2 = np.delete(crf_param_2, 9, 1)
    return torch.from_numpy(crf_param_2)


import rpyc
from rpyc.utils.server import OneShotServer
import unittest

class MyService(rpyc.Service):

    def exposed_foo(self):
        return "bar"

class Test_OneShotServer(unittest.TestCase):

    def setUp(self):
        self.server = OneShotServer(MyService, port=18878, auto_register=False)
        self.server.logger.quiet = False
        self.thd = self.server._start_in_thread()

    def tearDown(self):
        self.server.close()
        self.thd.join()

    def test_server_stops(self):
        conn = rpyc.connect("localhost", port=18878)
        self.assertEqual("bar", conn.root.foo())
        conn.close()
        while not self.server._closed:
            pass
        self.assertTrue(self.server._closed)
        self.assertTrue(self.server.listener._closed)
        self.assertEqual(len(self.server.clients), 0)

if __name__ == "__main__":
    unittest.main()


import numpy as np
from itertools import combinations
from math import *
import pdb

file = open('tsp.txt', 'r+')
i = -1
for line in file:
    if i == -1:
        n = int(line.rstrip('\t'))
        coor = np.empty((n, 2))
        i += 1
    else:
        [x, y] = line.rstrip('\t').split(' ')
        coor[i][:] = np.array([x, y])
        i += 1
file.close()

# No.vertex is zero-based
# S is a subset of size m that contains start
# j in set S and j != 0
# use TWO 2D array to save the values in the current & last round

eu_dist = np.zeros((n, n))
for k in range(0, n):
    for j in range(0, n):
        if k == j:
            eu_dist[k][j] = 0
        else:
            eu_dist[k][j] = sqrt((coor[k][0] - coor[j][0]) ** 2 + (coor[k][1] - coor[j][1]) ** 2)

# for quick reference to the factorial value
lookup_f = np.zeros(n + 1)
for i in range(0, n + 1):
    lookup_f[i] = factorial(i)

# choose #i from #j, save number of combinations in a 2d array
comb_table = np.zeros((n + 1, n + 1))
for i in range(0, n + 1):
    for j in range(0, n + 1):
        if i > j:
            comb_table[i][j] = 0
        elif i == j:
            comb_table[i][j] = 1
        elif i < j:
            comb_table[i][j] = lookup_f[j] / (lookup_f[i] * lookup_f[j - i])

# calculate the combinatorial number of this combination set
# N = sum(comb(set[i-1], i)), i = 1 to len(set), set in ascending sorted order
def encode(s):  # intput is a tuple/list of combination
    N = 0
    for x, y in enumerate(s, start=1):  # x is 1-based index
        N += comb_table[x][y]
    return int(N)

# #******test******
# vertices = list(range(0, n))
# x = list(combinations(vertices, 3))
# code = []
# for i in x:
#     code.append(encode(i))
# print(max(code), min(code), len(code))
# ****************

# initialization
# max_size = maximum possible number of combinations
max_size = int(comb_table[12][25])
A = np.full((max_size, 25), np.inf)  # indexed by [# set][k]
A[0][0] = 0
cache = np.empty((max_size, 25))

vertices = list(range(1, n))  # other vertices except 0
for m in range(1, n):  # size of set {s1 - 0}
    print('%d /24 proceeding' % m)
    # passby = a set of s WITHOUT 0
    passby = list(combinations(vertices, m))
    for s1 in passby:
        s1 = [0] + list(s1)
        # now add 0 to the front of s
        s1_code = encode(s1)
        for j in s1:
            if j == 0:
                continue
            else:
                choice = []
                for k in s1:
                    if k != j:
                        if k == 0 and m != 1:
                            continue  # i.e. this candidate A[set, 0]=inf
                        else:
                            dist_jk = eu_dist[j][k]
                            s_j = s1.copy()
                            s_j.remove(j)
                            # pdb.set_trace()
                            s_j_code = encode(s_j)
                            candidate = A[s_j_code][k] + dist_jk
                            choice.append(candidate)
                    else:
                        continue
                cache[s1_code][j] = min(choice)
    A, cache = cache, A

print(s1, s1_code)

temp = []
a = A[0][:]
print(a)
for j in range(1, n):
    temp.append(a[j] + eu_dist[0][j])
print(min(temp))


from AutomationToolsLib import Logging, AutomationPreferences, SlackNotification
from datetime import date
from xml.etree import ElementTree
from sys import exit

try:
    import requests
except:
    print(
        "The requests module is not installed. To install the request module, use the pip3 command: pip3 install requests"
    )
    exit

def GetUpdatedSoftwareVersion():
    logPrefs = AutomationPreferences("LOG_LOCATION")
    tDate = str(date.today())
    newPackageFile = open(logPrefs["LOG_LOCATION"] + "/newpackage.log", "r")
    softwareUpdates = {}
    for line in newPackageFile:
        if tDate in line:
            for software in newPackageFile:
                if "updated software:" in software:
                    software = software.strip("updated software: ")
                    software = software.rstrip("\n")
                    software = software.rsplit(sep=" ", maxsplit=1)
                    softwareUpdates[software[0]] = software[1]
    return softwareUpdates

def AddPackageToDefinition(updatedSoftware):
    logfile = "jamfPatchUpdate.log"
    jamfPrefs = AutomationPreferences("JSS_URL", "API_USERNAME", "API_PASSWORD")
    patchURL = jamfPrefs["JSS_URL"] + "/JSSResource/patchsoftwaretitles"
    pkgSuffix = ".pkg"
    pkgList = []
    for pkg in updatedSoftware:
        pkgList.append(pkg + "-" + updatedSoftware[pkg] + pkgSuffix)
    response = requests.get(
        patchURL,
        auth=(jamfPrefs["API_USERNAME"], jamfPrefs["API_PASSWORD"]),
        headers={"Accept": "application/xml"},
    )
    if response.status_code != 200:
        Logging(logfile, "Error connecting to Jamf: " + str(response.status_code))
        Logging(logfile, str(response.content))
        exit()
    responseTree = ElementTree.fromstring(response.content)
    for software in updatedSoftware:
        iterator = 1
        software_not_found = False
        while iterator <= int(responseTree[0].text):
            if software == responseTree[iterator][0].text:
                Logging(logfile, "Updating patch policy for " + software)
                patchTitleResponse = requests.get(
                    patchURL + "/id/" + responseTree[iterator][1].text,
                    auth=(jamfPrefs["API_USERNAME"], jamfPrefs["API_PASSWORD"]),
                    headers={"Accept": "application/xml"},
                )
                if patchTitleResponse.status_code != 200:
                    Logging(
                        logfile,
                        "There was an error in retrieving XML: "
                        + str(response.status_code),
                    )
                    Logging(logfile, str(patchTitleResponse.content))
                    Logging(logfile, patchURL + "/id/" + responseTree[iterator][1].text)
                else:
                    try:
                        patchTitleTree = ElementTree.fromstring(
                            patchTitleResponse.content
                        )
                        if patchTitleTree[6][0][0].text == updatedSoftware[software]:
                            for pkg in pkgList:
                                if updatedSoftware[software] in pkg:
                                    xmlData = (
                                        "<patch_software_title><versions><version><software_version>"
                                        + updatedSoftware[software]
                                        + "</software_version><package><name>"
                                        + pkg
                                        + "</name></package></version></versions></patch_software_title>"
                                    )
                                    newResponse = requests.put(
                                        patchURL
                                        + "/id/"
                                        + responseTree[iterator][1].text,
                                        auth=(
                                            jamfPrefs["API_USERNAME"],
                                            jamfPrefs["API_PASSWORD"],
                                        ),
                                        data=xmlData,
                                        headers={"content-type": "application/xml"},
                                    )
                                    if newResponse.status_code != 201:
                                        Logging(
                                            logfile,
                                            "Update of "
                                            + software
                                            + " failed with error code: "
                                            + str(newResponse.status_code),
                                        )
                                        Logging(logfile, newResponse.content)
                                    else:
                                        Logging(
                                            logfile,
                                            pkg
                                            + " added to definition version "
                                            + updatedSoftware[software],
                                        )
                                        # UpdateTargetVersion(updatedSoftware[software])
                                    iterator = int(responseTree[0].text) + 50
                        else:
                            Logging(
                                logfile,
                                "Updated Version does not match the latest version in Jamf.",
                            )
                            Logging(
                                logfile,
                                "Jamf: "
                                + str(patchTitleTree[6][0][0].text)
                                + " != "
                                + "Updated: "
                                + updatedSoftware[software],
                            )
                            iterator = int(responseTree[0].text) + 50
                    except:
                        Logging(logfile, "There was a problem with the XML content")
                        Logging(logfile, str(patchTitleResponse.content))
                        Logging(
                            logfile, patchURL + "/id/" + responseTree[iterator][1].text
                        )
                        Logging(logfile, xmlData)
            iterator = iterator + 1
            if iterator == int(responseTree[0].text):
                software_not_found = True
        if software_not_found:
            Logging(
                logfile,
                "No patch policy found for "
                + software
                + " "
                + str(updatedSoftware[software]),
            )
            print(
                "No patch policy found for "
                + software
                + " "
                + str(updatedSoftware[software])
            )

def UpdateTargetVersion(updatedSoftware):
    logfile = "jamfPatchUpdate.log"
    apiPrefs = AutomationPreferences("API_USERNAME", "API_PASSWORD", "JSS_URL")
    apiURL = apiPrefs["JSS_URL"] + "/JSSResource/patchpolicies"
    response = requests.get(
        apiURL,
        auth=(apiPrefs["API_USERNAME"], apiPrefs["API_PASSWORD"]),
        headers={"Accept": "application/xml"},
    )
    patchPolicyContent = ElementTree.fromstring(response.content)
    for software in updatedSoftware:
        counter = 1
        Logging(logfile, "Updating target version for " + software)
        for title in patchPolicyContent:
            while counter <= int(patchPolicyContent[0].text):
                softwareTestPolicy = software + " Update Test"
                if softwareTestPolicy == patchPolicyContent[counter][1].text:
                    patchPolicyID = patchPolicyContent[counter][0].text
                    xmlData = (
                        "<patch_policy><general><target_version>"
                        + updatedSoftware[software]
                        + "</target_version></general></patch_policy>"
                    )
                    patchTrgtResponse = requests.put(
                        apiURL + "/id/" + patchPolicyID,
                        auth=(apiPrefs["API_USERNAME"], apiPrefs["API_PASSWORD"]),
                        data=xmlData,
                        headers={"Content-type": "application/xml"},
                    )
                    if patchTrgtResponse.status_code != 201:
                        Logging(
                            logfile,
                            software
                            + " target version update failed with response code: "
                            + str(patchTrgtResponse.status_code),
                        )
                        Logging(
                            logfile,
                            software
                            + " target version "
                            + updatedSoftware[software]
                            + " was not updated to "
                            + patchPolicyContent[counter][1].text,
                        )
                        SlackNotification(
                            logfile,
                            ":failed: "
                            + patchPolicyContent[counter][1].text
                            + " was not updated. Please update "
                            + patchPolicyContent[counter][1].text
                            + " to "
                            + updatedSoftware[software]
                            + " manually.",
                        )
                    else:
                        Logging(
                            logfile,
                            patchPolicyContent[counter][1].text
                            + " has been updated to target version "
                            + updatedSoftware[software],
                        )
                        SlackNotification(
                            logfile,
                            ":white_check_mark: "
                            + patchPolicyContent[counter][1].text
                            + " has been updated to target version "
                            + updatedSoftware[software],
                        )
                    counter = int(patchPolicyContent[0].text) + 1
                else:
                    counter = counter + 1
            if counter == int(patchPolicyContent[0].text):
                Logging(logfile, softwareTestPolicy + " wasn't found.")

def Main():
    logfile = "jamfPatchUpdate.log"
    todayDate = str(date.today())
    Logging(logfile, "********************" + str(todayDate) + "********************")
    softwareUpdate = GetUpdatedSoftwareVersion()
    if len(softwareUpdate) != 0:
        AddPackageToDefinition(softwareUpdate)
        UpdateTargetVersion(softwareUpdate)
    else:
        Logging(logfile, "No new software updates.")

Main()


from django.db import models
from geoposition.fields import GeopositionField
from django import forms

class Clinic(models.Model):
    """
    A clinic providing health services.
    """

    name = models.CharField(
      'Name of the clinic',
      max_length = 255,
      unique = True,
    )

    location = GeopositionField(
      'Physical location of the clinic'
    )

    opening_times = models.CharField(
      'Clinic opening hours and days',
      max_length = 255
    )

    services_provided = models.ManyToManyField(
      'ClinicService',
    )

    def __unicode__(self):
        return self.name

class ClinicService(models.Model):
    """
    A health service provided by a clinic.
    """

    name = models.CharField(
      'Short name for the service',
      max_length = 50,
      unique = True,
    )

    description = models.CharField(
      'Longer description of the service provided',
      max_length = 255
    )

    def __unicode__(self):
        return self.name

class ClinicFeedback(models.Model):
    """
    A feedback submission for a clinic.
    """

    clinic = models.ForeignKey(Clinic)

    visit_date = models.DateField(
      'Date of visit'
    )

    patient_age = models.IntegerField(
      'Your age (years)',
      blank = True, null = True,
    )

    patient_sex = models.CharField(
      'Your sex (gender)',
      blank = True, null = True,
      max_length = 1,
      choices = (
        ('M', 'Male'),
        ('F', 'Female'),
      )
    )

    services_needed = models.ManyToManyField(
      'ClinicService',
      blank = True, null = True,
    )

    provider_sex = models.CharField(
      'Provider\'s sex (gender)',
      blank = True, null = True,
      max_length = 1,
      choices = (
        ('M', 'Male'),
        ('F', 'Female'),
      ),
      #widget = forms.RadioSelect(),
    )

    free_questions = models.CharField(
      'Were you free to ask any questions you had?',
      max_length = 1,
      choices = (
        ('Y', 'Yes'),
        ('S', 'Somewhat'),
        ('N', 'No'),
      ),
      blank = True, null = True,
    )

    got_info = models.CharField(
      'Did you get the information you wanted?',
      max_length = 1,
      choices = (
        ('Y', 'Yes'),
        ('S', 'Somewhat'),
        ('N', 'No'),
      ),
      blank = True, null = True,
    )

    got_supplies = models.CharField(
      'Did you get the supplies you wanted?',
      max_length = 1,
      choices = (
        ('Y', 'Yes'),
        ('N', 'No'),
        ('X', 'Didn\'t want any'),
      ),
      blank = True, null = True,
    )

    harsh_provider = models.CharField(
      'Was any provider harsh or made you feel ashamed?',
      max_length = 1,
      choices = (
        ('Y', 'Yes'),
        ('S', 'Somewhat'),
        ('N', 'No'),
      ),
      blank = True, null = True,
    )

    enough_privacy = models.CharField(
      'Did you have enough privacy?',
      max_length = 1,
      choices = (
        ('Y', 'Yes'),
        ('S', 'Somewhat'),
        ('N', 'No'),
      ),
      blank = True, null = True,
    )

    pal_provided = models.NullBooleanField(
      'Did a PAL provide services to you within the facility?'
    )

    waiting_time = models.IntegerField(
      'About how long did you have to wait? (minutes)',
      blank = True, null = True,
    )

    cost = models.IntegerField(
      'What did you pay for services, if anything?',
      blank = True, null = True,
    )

    recommended = models.CharField(
      'Would you recommend this place to other youths?',
      max_length = 1,
      choices = (
        ('Y', 'Yes'),
        ('M', 'Maybe'),
        ('N', 'No'),
      ),
      blank = True, null = True,
    )

    why_recommend = models.CharField(
      'Why or why not?',
      max_length = 255,
      blank = True, null = True,
    )