import tkinter
from tkinter import *
from PIL import Image, ImageTk
import os
import time
import random

class PageOne():
    def __init__(self):
        root.geometry("720x576")
        root.configure(bg='white')
        self.getImg()
        self.getBut()
        self.placeObj()

    def getImg(self):
        img = Image.open("image\hiroLogo.jpg")
        weight, height = img.size
        weight, height = int(weight*0.5), int(height*0.5)

        img = img.resize((weight, height))
        img = ImageTk.PhotoImage(img)

        self.label = tkinter.Label(image=img)
        self.label.image = img

    def getBut(self):
        self.btn_st = Button(text="Start", font=("Arial", 10, "bold"), width=30, height=2, activebackground="green", bd=5, command=self.callPageTwo, bg='#73c088')
        self.btn_qu = Button(text="Quit", font=("Arial", 10, "bold"), width=30, height=2, activebackground="red", bd=5, command=self.exitProgram, bg='#fd464a')

    def callPageTwo(self):
        self.clearObj()
        PageTwo()

    def placeObj(self):
        self.label.place(relx = 0.5, rely = 0.4, anchor = "center")
        self.btn_st.place(relx = 0.5, rely = 0.8, anchor = "center")
        self.btn_qu.place(relx = 0.5, rely = 0.9, anchor = "center")

    def clearObj(self):
        self.label.destroy()
        self.btn_st.destroy()
        self.btn_qu.destroy()

    def exitProgram(self):
        os._exit(0)

#One Person
class PageTwo():
    def __init__(self):
        self.check = False
        self.getObj()
        self.placeObj()

    def getObj(self):
        self.label1 = Label(text="Name", font=("Arial", 15, ""))
        self.entPla = Entry(width = 20, font=("Arial", 15, ""), justify='center')
        self.label2 = Label(text="How Much Money To Play", font=("Arial", 13, "bold"))
        self.entMon = Entry(width = 20, font=("Arial", 15, ""), justify='center')
        self.btn = Button(text="Enter", font=("Arial", 10, "bold"), command=self.getValue, bd=5, bg='#73c088')

    def placeObj(self):
        self.label1.place(relx = 0.5, rely = 0.35, anchor = "center")
        self.entPla.place(relx = 0.5, rely = 0.4, anchor = "center")
        self.label2.place(relx = 0.5, rely = 0.48, anchor = "center")
        self.entMon.place(relx = 0.5, rely = 0.53, anchor = "center")
        self.btn.place(relx = 0.5, rely = 0.63, anchor = "center")

    def getValue(self):
        self.namePla = self.entPla.get()
        self.numMon = self.entMon.get()
        if self.numMon.isnumeric() and int(self.numMon) > 0:
            self.clearObj()
            Game(self.namePla, self.numMon)
        else:
            self.getObj()
            self.placeObj()
            Label(text="Input Must Be\nCardinal Numbers", fg='red', font=("Arial", 13, "")).place(relx = 0.75, rely = 0.53, anchor = "center")

    def clearObj(self):
        self.label1.destroy()
        self.label2.destroy()
        self.entPla.destroy()
        self.entMon.destroy()
        self.btn.destroy()

class Game():
    def __init__(self, name, money):
        root.geometry("1280x750")
        root.configure(bg='green')
        self.getObj(name, money)
        self.showScreen()
        self.label3 = False

    def playGame(self, id):
        moneyBet = self.monPay.get()
        if self.label3:
            self.label3.destroy()
        if moneyBet.isnumeric():
            moneyBet = int(self.monPay.get())
            if int(self.money['text'])-moneyBet >= 0:
                self.money['text'] = int(self.money['text'])-moneyBet
            elif int(self.money['text'])-moneyBet < 0:
                moneyBet = int(self.money['text'])
                self.money['text'] = 0
            self.keepNum(id, moneyBet)
        else:
            self.label3 = Label(text="Input Must Be\nCardinal Numbers", fg='red', font=("Arial", 13, ""), bg='green')
            self.label3.place(relx = 0.9, rely = 0.55, anchor = "center")

    def newGame(self):
        self.butt15.destroy()
        self.butt16.destroy()
        self.butt25.destroy()
        self.butt123.destroy()
        self.butt5low.destroy()
        self.butt1.destroy()
        self.butt2.destroy()
        self.butt36.destroy()
        self.butt11Hiro.destroy()
        self.buttLow.destroy()
        self.butt3.destroy()
        self.butt24.destroy()
        self.buttHigh.destroy()
        self.butt4.destroy()
        self.butt35.destroy()
        self.butt6low.destroy()
        self.butt6.destroy()
        self.butt5.destroy()
        self.butt41.destroy()
        self.butt62.destroy()
        self.butt61.destroy()
        self.butt52.destroy()
        self.butt456.destroy()
        self.open.destroy()
        self.label.destroy()
        self.label1.destroy()
        self.label2.destroy()
        self.btn.destroy()
        self.dice1img.destroy()
        self.dice2img.destroy()
        self.dice3img.destroy()
        self.name.destroy()
        self.money.destroy()
        self.monPay.destroy()
        self.btn2.destroy()
        self.label4.destroy()
        self.label5.destroy()
        if self.label3:
            self.label3.destroy()
        PageOne()

    def showScreen(self):
        if int(self.money['text']) <= 0:
            img = Image.open("image\lose.jpg")
            weight, height = img.size
            weight, height = int(weight*0.8), int(height*0.8)

            img = img.resize((weight, height))
            img = ImageTk.PhotoImage(img)
            self.label = tkinter.Label(image=img, bd=0)
            self.label.image = img
            self.label.place(relx=0.5, rely=0.5, anchor='center')

            self.btn = Button(text='New Game', bg='green', font=("Arial", 13, ""), width=10, command=lambda: self.newGame())
            self.btn.place(relx=0.5, rely=0.75, anchor='center')
        else:
            self.bet = []
            self.getImg()
            self.placeObj()
            self.monButt()
            self.getButt()
            self.placeButt()
            self.shake()

    def killObj(self):
        self.butt15.destroy()
        self.butt16.destroy()
        self.butt25.destroy()
        self.butt123.destroy()
        self.butt5low.destroy()
        self.butt1.destroy()
        self.butt2.destroy()
        self.butt36.destroy()
        self.butt11Hiro.destroy()
        self.buttLow.destroy()
        self.butt3.destroy()
        self.butt24.destroy()
        self.buttHigh.destroy()
        self.butt4.destroy()
        self.butt35.destroy()
        self.butt6low.destroy()
        self.butt6.destroy()
        self.butt5.destroy()
        self.butt41.destroy()
        self.butt62.destroy()
        self.butt61.destroy()
        self.butt52.destroy()
        self.butt456.destroy()
        self.btn2.destroy()
        self.label1.destroy()
        self.label4.destroy()
        self.label5.destroy()
        self.open.destroy()

    def checkList(self, id):
        if id not in self.bet:
            self.bet.append(id)
        print(self.bet)

    def ranNum(self):
        return random.randint(1, 6)

    def openDice(self):
        self.label2.destroy()
        self.placeDice()
        self.checkHiLo()
        self.plusMoney()
        self.disButt()
        self.btn2 = Button(text="Next Bet", command=lambda: self.removeDice(), font=("Arial", 18, ""), height=2, width=8, bd=5)
        self.btn2.place(relx=0.9, rely=0.7, anchor='center')

    def removeDice(self):
        self.dice1img.destroy()
        self.dice2img.destroy()
        self.dice3img.destroy()
        self.killObj()
        self.showScreen()

    def disButt(self):
        self.butt15['state'] = "disabled"
        self.butt16['state'] = "disabled"
        self.butt25['state'] = "disabled"
        self.butt123['state'] = "disabled"
        self.butt5low['state'] = "disabled"
        self.butt1['state'] = "disabled"
        self.butt2['state'] = "disabled"
        self.butt36['state'] = "disabled"
        self.butt11Hiro['state'] = "disabled"
        self.buttLow['state'] = "disabled"
        self.butt3['state'] = "disabled"
        self.butt24['state'] = "disabled"
        self.buttHigh['state'] = "disabled"
        self.butt4['state'] = "disabled"
        self.butt35['state'] = "disabled"
        self.butt6low['state'] = "disabled"
        self.butt6['state'] = "disabled"
        self.butt5['state'] = "disabled"
        self.butt41['state'] = "disabled"
        self.butt62['state'] = "disabled"
        self.butt61['state'] = "disabled"
        self.butt52['state'] = "disabled"
        self.butt456['state'] = "disabled"

    def getDice(self, ran):
        print(ran)
        if ran == 1:
            self.img = Image.open("image\dice1.jpg")
        elif ran == 2:
            self.img = Image.open("image\dice2.jpg")
        elif ran == 3:
            self.img = Image.open("image\dice3.jpg")
        elif ran == 4:
            self.img = Image.open("image\dice4.jpg")
        elif ran == 5:
            self.img = Image.open("image\dice5.jpg")
        elif ran == 6:
            self.img = Image.open("image\dice6.jpg")
        weight, height = self.img.size
        weight, height = int(weight*0.07), int(height*0.07)

        self.img = self.img.resize((weight, height))
        self.img = ImageTk.PhotoImage(self.img)

    def checkHiLo(self):
        result_dice = self.dice1 + self.dice2 + self.dice3
        if result_dice >= 12: #แต้มสูง 12-18
            self.result = "HIGH"
        elif result_dice == 11: #11 ไฮโล
            self.result = "11HILO"
        elif result_dice <= 10: #แต้มต่ำ 3-10
            self.result = "LOW"

    def placeDice(self):
        self.dice1 = self.ranNum()
        self.getDice(self.dice1)
        self.dice1img = tkinter.Label(image=self.img)
        self.dice1img.image = self.img
        self.dice1img.place(relx=0.87, rely=0.15, anchor='center')

        self.dice2 = self.ranNum()
        self.getDice(self.dice2)
        self.dice2img = tkinter.Label(image=self.img)
        self.dice2img.image = self.img
        self.dice2img.place(relx=0.92, rely=0.15, anchor='center')

        self.dice3 = self.ranNum()
        self.getDice(self.dice3)
        self.dice3img = tkinter.Label(image=self.img)
        self.dice3img.image = self.img
        self.dice3img.place(relx=0.89, rely=0.25, anchor='center')

    def shake(self):
        self.label2.place(relx=0.9, rely=0.15, anchor='center')
        root.update()
        time.sleep(1)
        self.label2.place(relx=0.9, rely=0.2, anchor='center')

    def getObj(self, name, money):
        self.name = Label(text=str(name), font=("Arial",18,""), width=25)
        self.money = Label(text=str(money), font=("Arial",18,""), width=25)
        self.monPay = Entry(width = 23, font=("Arial", 15, ""), justify='center')

    def getImg(self):
        img = Image.open("image\hiro.jpg")
        weight, height = img.size
        weight, height = int(weight*0.24), int(height*0.24)

        img = img.resize((weight, height))
        img = ImageTk.PhotoImage(img)

        self.label1 = tkinter.Label(image=img, bd=0)
        self.label1.image = img

        img = Image.open("image\lid.jpg")
        weight, height = img.size
        weight, height = int(weight*0.45), int(height*0.45)

        img = img.resize((weight, height))
        img = ImageTk.PhotoImage(img)

        self.label2 = tkinter.Label(image=img, bd=0)
        self.label2.image = img

        img = Image.open("image\money.png")
        weight, height = img.size
        weight, height = int(weight*0.23), int(height*0.23)

        img = img.resize((weight, height))
        img = ImageTk.PhotoImage(img)

        self.label4 = tkinter.Label(image=img)
        self.label4.image = img

        img = Image.open("image\people.png")
        weight, height = img.size
        weight, height = int(weight*0.18), int(height*0.18)

        img = img.resize((weight, height))
        img = ImageTk.PhotoImage(img)

        self.label5 = tkinter.Label(image=img)
        self.label5.image = img

    def placeObj(self):
        self.label1.place(relx=0.905, rely=0.89, anchor='center')
        self.label2.place(relx=0.9, rely=0.2, anchor='center')
        self.label4.place(relx=0.8325, rely=0.5, anchor='center')
        self.label5.place(relx=0.83, rely=0.4, anchor='center')
        self.name.place(relx=0.9, rely=0.4, anchor='center')
        self.money.place(relx=0.9, rely=0.5, anchor='center')
        self.monPay.place(relx=0.91, rely=0.6, anchor='center')

    def keepNum(self, id, moneyBet):
        if id == 1:
            self.mon1 = str(int(self.mon1.replace(" ", "0"))+moneyBet)
            self.butt1['text'] = "1\n\n%s" %(self.mon1)
        elif id == 2:
            self.mon2 = str(int(self.mon2.replace(" ", "0"))+moneyBet)
            self.butt2['text'] = "2\n\n%s" %(self.mon2)
        elif id == 3:
            self.mon3 = str(int(self.mon3.replace(" ", "0"))+moneyBet)
            self.butt3['text'] = "3\n\n%s" %(self.mon3)
        elif id == 4:
            self.mon4 = str(int(self.mon4.replace(" ", "0"))+moneyBet)
            self.butt4['text'] = "4\n\n%s" %(self.mon4)
        elif id == 5:
            self.mon5 = str(int(self.mon5.replace(" ", "0"))+moneyBet)
            self.butt5['text'] = "5\n\n%s" %(self.mon5)
        elif id == 6:
            self.mon6 = str(int(self.mon6.replace(" ", "0"))+moneyBet)
            self.butt6['text'] = "6\n\n%s" %(self.mon6)
        elif id == [1, 5]:
            self.mon15 = str(int(self.mon15.replace(" ", "0"))+moneyBet)
            self.butt15['text'] = "1 o 5\n\n%s" %(self.mon15)
        elif id == [1, 6]:
            self.mon16 = str(int(self.mon16.replace(" ", "0"))+moneyBet)
            self.butt16['text'] = "1 o 6\n\n%s" %(self.mon16)
        elif id == [2, 5]:
            self.mon25 = str(int(self.mon25.replace(" ", "0"))+moneyBet)
            self.butt25['text'] = "2 o 5\n\n%s" %(self.mon25)
        elif id == [1, 2, 3]:
            self.mon123 = str(int(self.mon123.replace(" ", "0"))+moneyBet)
            self.butt123['text'] = "1 o 2 o 3\n\n%s" %(self.mon123)
        elif id == [3, 6]:
            self.mon36 = str(int(self.mon36.replace(" ", "0"))+moneyBet)
            self.butt36['text'] = "3 o 6\n\n%s" %(self.mon36)
        elif id == [2, 4]:
            self.mon24 = str(int(self.mon24.replace(" ", "0"))+moneyBet)
            self.butt24['text'] = "2 o 4\n\n%s" %(self.mon24)
        elif id == [3, 5]:
            self.mon35 = str(int(self.mon35.replace(" ", "0"))+moneyBet)
            self.butt35['text'] = "3 o 5\n\n%s" %(self.mon35)
        elif id == [4, 1]:
            self.mon41 = str(int(self.mon41.replace(" ", "0"))+moneyBet)
            self.butt41['text'] = "4 o 1\n\n%s" %(self.mon41)
        elif id == [4, 5, 6]:
            self.mon456 = str(int(self.mon456.replace(" ", "0"))+moneyBet)
            self.butt456['text'] = "4 o 5 o 6\n\n%s" %(self.mon456)
        elif id == [5, 2]:
            self.mon52 = str(int(self.mon52.replace(" ", "0"))+moneyBet)
            self.butt52['text'] = "5 o 2\n\n%s" %(self.mon52)
        elif id == [6, 1]:
            self.mon61 = str(int(self.mon61.replace(" ", "0"))+moneyBet)
            self.butt61['text'] = "6 o 1\n\n%s" %(self.mon61)
        elif id == [6, 2]:
            self.mon62 = str(int(self.mon62.replace(" ", "0"))+moneyBet)
            self.butt62['text'] = "6 o 2\n\n%s" %(self.mon62)
        elif id == [5, "LOW"]:
            self.mon5Low = str(int(self.mon5Low.replace(" ", "0"))+moneyBet)
            self.butt5low['text'] = "5 LOW\n\n%s" %(self.mon5Low)
        elif id == [6, "LOW"]:
            self.mon6Low = str(int(self.mon6Low.replace(" ", "0"))+moneyBet)
            self.butt6low['text'] = "6 LOW\n\n%s" %(self.mon6Low)
        elif id == "11HILO":
            self.mon11Hiro = str(int(self.mon11Hiro.replace(" ", "0"))+moneyBet)
            self.butt11Hiro['text'] = "11 Hiro\n\n%s" %(self.mon11Hiro)
        elif id == "LOW":
            self.monLow = str(int(self.monLow.replace(" ", "0"))+moneyBet)
            self.buttLow['text'] = "LOW\n\n%s" %(self.monLow)
        elif id == "HIGH":
            self.monHigh = str(int(self.monHigh.replace(" ", "0"))+moneyBet)
            self.buttHigh['text'] = "HIGH\n\n%s" %(self.monHigh)
        self.checkList(id)

    def plusMoney(self):
        if self.result in self.bet: # ต่ำ สูง 11Hiro
            self.highLow()
        if self.dice1 in self.bet:
            self.onlyNum(self.dice1)
        if self.dice2 in self.bet:
            self.onlyNum(self.dice2)
        if self.dice3 in self.bet:
            self.onlyNum(self.dice3)
        if ([self.dice1, self.dice2]) in self.bet:
            self.twoNum(self.dice1, self.dice2)
        if ([self.dice1, self.dice3]) in self.bet:
            self.twoNum(self.dice1, self.dice3)
        if ([self.dice2, self.dice1]) in self.bet:
            self.twoNum(self.dice2, self.dice1)
        if ([self.dice2, self.dice3]) in self.bet:
            self.twoNum(self.dice2, self.dice3)
        if ([self.dice3, self.dice1]) in self.bet:
            self.twoNum(self.dice3, self.dice1)
        if ([self.dice3, self.dice2]) in self.bet:
            self.twoNum(self.dice3, self.dice2)
        if ([self.dice1, self.dice2, self.dice3]) in self.bet:
            self.triNum(self.dice1, self.dice2, self.dice3)
        if ([self.dice1, self.dice3, self.dice2]) in self.bet:
            self.triNum(self.dice1, self.dice3, self.dice2)
        if ([self.dice2, self.dice1, self.dice3]) in self.bet:
            self.triNum(self.dice2, self.dice1, self.dice3)
        if ([self.dice2, self.dice3, self.dice1]) in self.bet:
            self.triNum(self.dice2, self.dice3, self.dice1)
        if ([self.dice3, self.dice1, self.dice2]) in self.bet:
            self.triNum(self.dice3, self.dice1, self.dice2)
        if ([self.dice3, self.dice2, self.dice1]) in self.bet:
            self.triNum(self.dice3, self.dice2, self.dice1)
        if ([self.dice1, self.result]) in self.bet:
            self.low56(self.dice1)
        if ([self.dice2, self.result]) in self.bet:
            self.low56(self.dice2)
        if ([self.dice3, self.result]) in self.bet:
            self.low56(self.dice3)

    def highLow(self):
        if self.result == "HIGH":
            self.money['text'] = int(self.money['text'])+int(self.monHigh.replace(" ", "0"))*2
        elif self.result == "LOW":
            self.money['text'] = int(self.money['text'])+int(self.monLow.replace(" ", "0"))*2
        elif self.result == "11HILO":
            self.money['text'] = int(self.money['text'])+int(self.mon11Hiro.replace(" ", "0"))*7

    def onlyNum(self, dice):
        if dice == 1:
            self.money['text'] = int(self.money['text'])+int(self.mon1.replace(" ", "0"))*2
        elif dice == 2:
            self.money['text'] = int(self.money['text'])+int(self.mon2.replace(" ", "0"))*2
        elif dice == 3:
            self.money['text'] = int(self.money['text'])+int(self.mon3.replace(" ", "0"))*2
        elif dice == 4:
            self.money['text'] = int(self.money['text'])+int(self.mon4.replace(" ", "0"))*2
        elif dice == 5:
            self.money['text'] = int(self.money['text'])+int(self.mon5.replace(" ", "0"))*2
        elif dice == 6:
            self.money['text'] = int(self.money['text'])+int(self.mon6.replace(" ", "0"))*2

    def twoNum(self, dice1, dice2):
        if dice1 == 1 and dice2 == 5:
            self.money['text'] = int(self.money['text'])+int(self.mon15.replace(" ", "0"))*5
        elif dice1 == 1 and dice2 == 6:
            self.money['text'] = int(self.money['text'])+int(self.mon16.replace(" ", "0"))*5
        elif dice1 == 2 and dice2 == 5:
            self.money['text'] = int(self.money['text'])+int(self.mon25.replace(" ", "0"))*5
        elif dice1 == 3 and dice2 == 6:
            self.money['text'] = int(self.money['text'])+int(self.mon36.replace(" ", "0"))*5
        elif dice1 == 2 and dice2 == 4:
            self.money['text'] = int(self.money['text'])+int(self.mon24.replace(" ", "0"))*5
        elif dice1 == 3 and dice2 == 5:
            self.money['text'] = int(self.money['text'])+int(self.mon35.replace(" ", "0"))*5
        elif dice1 == 4 and dice2 == 1:
            self.money['text'] = int(self.money['text'])+int(self.mon41.replace(" ", "0"))*5
        elif dice1 == 5 and dice2 == 2:
            self.money['text'] = int(self.money['text'])+int(self.mon52.replace(" ", "0"))*5
        elif dice1 == 6 and dice2 == 1:
            self.money['text'] = int(self.money['text'])+int(self.mon61.replace(" ", "0"))*5
        elif dice1 == 6 and dice2 == 2:
            self.money['text'] = int(self.money['text'])+int(self.mon62.replace(" ", "0"))*5

    def triNum(self, dice1, dice2, dice3):
        if dice1 == 1 and dice2 == 2 and dice3 == 3:
            self.money['text'] = int(self.money['text'])+int(self.mon123.replace(" ", "0"))*10
        elif dice1 == 4 and dice2 == 5 and dice3 == 6:
            self.money['text'] = int(self.money['text'])+int(self.mon456.replace(" ", "0"))*10

    def low56(self):
        if dice == 5:
            self.money['text'] = int(self.money['text'])+int(self.mon5Low.replace(" ", "0"))*5
        elif dice == 6:
            self.money['text'] = int(self.money['text'])+int(self.mon6Low.replace(" ", "0"))*5

    def monButt(self):
        self.mon15 = " "
        self.mon16 = " "
        self.mon25 = " "
        self.mon123 = " "
        self.mon5Low = " "
        self.mon1 = " "
        self.mon2 = " "
        self.mon36 = " "
        self.mon11Hiro = " "
        self.monLow = " "
        self.mon3 = " "
        self.mon24 = " "
        self.monHigh = " "
        self.mon4 = " "
        self.mon35 = " "
        self.mon6Low = " "
        self.mon6 = " "
        self.mon5 = " "
        self.mon41 = " "
        self.mon62 = " "
        self.mon61 = " "
        self.mon52 = " "
        self.mon456 = " "

    def getButt(self):
        self.butt15 = Button(text="1 o 5\n\n%s" %(self.mon15), command=lambda: self.playGame([1, 5]), font=("Arial",20,""), height=5, width=10, bd=5)
        self.butt16 = Button(text="1 o 6\n\n%s" %(self.mon16), command=lambda: self.playGame([1, 6]), font=("Arial",20,""), height=5, width=10, bd=5)
        self.butt25 = Button(text="2 o 5\n\n%s" %(self.mon25), command=lambda: self.playGame([2, 5]), font=("Arial",20,""), height=5, width=10, bd=5)
        self.butt123 = Button(text="1 o 2 o 3\n\n%s" %(self.mon123), command=lambda: self.playGame([1, 2, 3]), font=("Arial",20,""), height=5, width=10, bd=5)
        self.butt5low = Button(text="5 LOW\n\n%s" %(self.mon5Low), command=lambda: self.playGame([5, "LOW"]), font=("Arial",20,""), height=5, width=10, bd=5)
        self.butt1 = Button(text="1\n\n%s" %(self.mon1), command=lambda: self.playGame(1), font=("Arial",20,""), fg='red', height=5, width=10, bd=5)
        self.butt2 = Button(text="2\n\n%s" %(self.mon2), command=lambda: self.playGame(2), font=("Arial",20,""), height=5, width=10, bd=5)
        self.butt36 = Button(text="3 o 6\n\n%s" %(self.mon36), command=lambda: self.playGame([3, 6]), font=("Arial",20,""), height=5, width=10, bd=5)
        self.butt11Hiro = Button(text="11Hiro\n\n%s" %(self.mon11Hiro), command=lambda: self.playGame("11HILO"), font=("Arial",20,""), fg='red', height=5, width=21, bd=5)
        self.buttLow = Button(text="LOW\n\n%s" %(self.monLow), command=lambda: self.playGame("LOW"), font=("Arial",20,""), fg='red', height=5, width=10, bd=5)
        self.butt3 = Button(text="3\n\n%s" %(self.mon3), command=lambda: self.playGame(3), font=("Arial",20,""), height=5, width=10, bd=5)
        self.butt24 = Button(text="2 o 4\n\n%s" %(self.mon24), command=lambda: self.playGame([2, 4]), font=("Arial",20,""), height=5, width=10, bd=5)
        self.buttHigh = Button(text="HIGH\n\n%s" %(self.monHigh), command=lambda: self.playGame("HIGH"), font=("Arial",20,""), height=5, width=10, bd=5)
        self.butt4 = Button(text="4\n\n%s" %(self.mon4), command=lambda: self.playGame(4), font=("Arial",20,""), fg='red', height=5, width=10, bd=5)
        self.butt35 = Button(text="3 o 5\n\n%s" %(self.mon35), command=lambda: self.playGame([3, 5]), font=("Arial",20,""), height=5, width=10, bd=5)
        self.butt6low = Button(text="6 LOW\n\n%s" %(self.mon6Low), command=lambda: self.playGame([6, "LOW"]), font=("Arial",20,""), height=5, width=10, bd=5)
        self.butt6 = Button(text="6\n\n%s" %(self.mon6), command=lambda: self.playGame(6), font=("Arial",20,""), height=5, width=10, bd=5)
        self.butt5 = Button(text="5\n\n%s" %(self.mon5), command=lambda: self.playGame(5), font=("Arial",20,""), height=5, width=10, bd=5)
        self.butt41 = Button(text="4 o 1\n\n%s" %(self.mon41), command=lambda: self.playGame([4, 1]), font=("Arial",20,""), height=5, width=10, bd=5)
        self.butt62 = Button(text="6 o 2\n\n%s" %(self.mon62), command=lambda: self.playGame([6, 2]), font=("Arial",20,""), height=5, width=10, bd=5)
        self.butt61 = Button(text="6 o 1\n\n%s" %(self.mon61), command=lambda: self.playGame([6, 1]), font=("Arial",20,""), height=5, width=10, bd=5)
        self.butt52 = Button(text="5 o 2\n\n%s" %(self.mon52), command=lambda: self.playGame([5, 2]), font=("Arial",20,""), height=5, width=10, bd=5)
        self.butt456 = Button(text="4 o 5 o 6\n\n%s" %(self.mon456), command=lambda: self.playGame([4, 5, 6]), font=("Arial",20,""), height=5, width=10, bd=5)
        self.open = Button(text="Show Dice", command=lambda: self.openDice(), font=("Arial", 18, ""), height=2, width=8, bd=5)

    def placeButt(self):
        self.butt15.place(relx=0, rely=0, anchor='nw')
        self.butt16.place(relx=0, rely=0.25, anchor='nw')
        self.butt25.place(relx=0, rely=0.5, anchor='nw')
        self.butt123.place(relx=0, rely=0.75, anchor='nw')
        self.butt5low.place(relx=0.135, rely=0, anchor='nw')
        self.butt1.place(relx=0.135, rely=0.25, anchor='nw')
        self.butt2.place(relx=0.135, rely=0.5, anchor='nw')
        self.butt36.place(relx=0.135, rely=0.75, anchor='nw')
        self.butt11Hiro.place(relx=0.27, rely=0, anchor='nw')
        self.buttLow.place(relx=0.27, rely=0.25, anchor='nw')
        self.butt3.place(relx=0.27, rely=0.5, anchor='nw')
        self.butt24.place(relx=0.27, rely=0.75, anchor='nw')
        self.buttHigh.place(relx=0.405, rely=0.25, anchor='nw')
        self.butt4.place(relx=0.405, rely=0.5, anchor='nw')
        self.butt35.place(relx=0.405, rely=0.75, anchor='nw')
        self.butt6low.place(relx=0.540, rely=0, anchor='nw')
        self.butt6.place(relx=0.540, rely=0.25, anchor='nw')
        self.butt5.place(relx=0.540, rely=0.5, anchor='nw')
        self.butt41.place(relx=0.540, rely=0.75, anchor='nw')
        self.butt62.place(relx=0.675, rely=0, anchor='nw')
        self.butt61.place(relx=0.675, rely=0.25, anchor='nw')
        self.butt52.place(relx=0.675, rely=0.5, anchor='nw')
        self.butt456.place(relx=0.675, rely=0.75, anchor='nw')
        self.open.place(relx=0.9, rely=0.70, anchor='center')

root = Tk()
root.title("Hiro")
root.resizable(False, False)
pageOne = PageOne()
root.mainloop()


import os
import numpy as np
import matplotlib.pyplot as plt
import win32com.client as win32
import time

aspen = win32.Dispatch('Apwn.Document')
print("--- loading aspen .bkp file ---")
aspen.InitFromArchive2(os.path.abspath('simulation/PBR.bkp'))
print("--- .bkp file loaded---")

def run_simulation(temperature, filename):
    print("--- starting simulation ---")
    start_time = time.time()
    catalystWts = np.linspace(100, 200, 11)
    x_buoh, x_buacet = [], []

    # temperature = aspen.Tree.FindNode("\Data\Blocks\PBR\Input\REAC_TEMP").Value
    aspen.Tree.FindNode("\Data\Blocks\PBR\Input\REAC_TEMP").Value = temperature

    for catalyst in catalystWts:
        aspen.Tree.FindNode("\Data\Blocks\PBR\Input\CATWT").Value = catalyst
        aspen.Engine.Run2()
        x_buoh.append(aspen.Tree.FindNode("\Data\Streams\OUTPUT\Output\MOLEFLOW\MIXED\BUTANOL").Value)
        x_buacet.append(aspen.Tree.FindNode("\Data\Streams\OUTPUT\Output\MOLEFLOW\MIXED\BUT-ACET").Value)

    plt.plot(catalystWts, x_buacet, catalystWts, x_buoh)
    plt.title('PBR profile at %s' % temperature)
    plt.legend(['Butyl Acetate', 'Buthanol'])
    plt.xlabel('Catalyst weight (kg)')
    plt.ylabel('Mole flows, mol/h')
    plt.savefig('images/' + filename + '-buac-test.png')
    plt.clf()
    plt.close()
    print("--- %s seconds ---" % (time.time() - start_time))

    response = PbrSimulation(temperature)
    return response

class PbrSimulation:
    def __init__(self, temperature):
        self.temperature = temperature

def close_aspen():
    print("--- closing simulation ---")
    aspen.close()


# from itertools import combinations
# str, n=input().split()
# strings=sorted(str)
# for i in range(len(strings)):
#     print(strings[i], end="\n")
# combi=list(combinations(sorted(str),int(n)))

# for i in range(len(combi)):
#     print("".join(combi[i]))

from itertools import combinations
str, n = input().split()
for i in range(1,int(n)+1):
    combi=list(combinations(sorted(str),i))
    for i in combi:
      print("".join(i))


import sqlite3

class DBHelper:
    def __init__(self, dbname="todo.sqlite"):
        self.dbname = dbname
        self.conn = sqlite3.connect(dbname)

    def setup(self):
        stmt = "CREATE TABLE IF NOT EXISTS items (owner text, description text)"
        itemidx = "CREATE INDEX IF NOT EXISTS itemIndex ON items (description ASC)"
        ownidx = "CREATE INDEX IF NOT EXISTS ownIndex ON items (owner ASC)"
        self.conn.execute(stmt)
        self.conn.execute(itemidx)
        self.conn.execute(ownidx)
        self.conn.commit()

    def add_item(self, owner, item_text):
        stmt = "INSERT INTO items (owner, description) VALUES (?, ?)"
        args = (owner, item_text)
        self.conn.execute(stmt, args)
        self.conn.commit()

    def delete_item(self, owner, item_text):
        stmt = "DELETE FROM items WHERE owner = (?) AND description = (?)"
        args = (owner, item_text)
        self.conn.execute(stmt, args)
        self.conn.commit()

    def get_items(self, owner):
        stmt = "SELECT description FROM items WHERE owner = (?)"
        args = (owner,)
        return [x[0] for x in self.conn.execute(stmt, args)]


import pygame

def main():
    pygame.init()
    pygame.mixer.init()
    pantalla = pygame.display.set_mode([800, 800])
    pygame.display.set_caption("Laberinto mamadisimo")
    salir = False
    reloj1 = pygame.time.Clock()
    blanco=(255,255,255)

    fuente1=pygame.font.SysFont("calibri",16,True,False)
    fuente2=pygame.font.SysFont("Timesnewroman",36,True,True)

    presentacion=fuente2.render("MERLINO PRODUCTIONS",0,blanco)
    presentacion1=fuente2.render("PRESENTS",0,blanco)
    presentacion2=fuente2.render("ZOMBIE ENVOLU 2",0,blanco)

    while salir != True:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                salir = True

        reloj1.tick(20)
        pantalla.fill((0,0,0))
        pantalla.blit(presentacion2,(220,275))
        pygame.display.update()

    pygame.quit()

main()


from flask import render_template, request, url_for, flash, redirect, Blueprint
from werkzeug.exceptions import abort
from models import Posts
from start import db

posts = Blueprint('posts', __name__)

@posts.route('/')
def home():
    posts = Posts.query.all()
    return render_template('index.html', posts=posts)

@posts.route('/post/<int:post_id>')
def show_post(post_id):
    post = Posts.query.filter_by(id=post_id).first()
    if post is None:
        abort(404)
    return render_template('post.html', post=post)

@posts.route('/create', methods=('GET', 'POST'))
def create():
    if request.method == 'POST':
        title = request.form['title']
        content = request.form['content']

        if not title:
            flash('Title is required!')
        if not content:
            flash('Content is required!')

        if title and content:
            post = Posts(title=title, content=content)
            db.session.add(post)
            db.session.commit()
            return redirect(url_for('posts.home'))

    return render_template('create.html')

@posts.route('/edit/<int:post_id>', methods=('GET', 'POST'))
def edit(post_id):
    post = Posts.query.filter_by(id=post_id).first()

    if request.method == 'POST':
        post.title = request.form['title']
        post.content = request.form['content']

        if not post.title:
            flash('Title is required!')
        if not post.content:
            flash('Content is required!')

        if post.title and post.content:
            db.session.add(post)
            db.session.commit()
            return redirect(url_for('posts.show_post', post_id=post_id))

    return render_template('edit.html', post=post)

@posts.route('/delete/<int:post_id>', methods=('POST',))
def delete(post_id):
    post = Posts.query.filter_by(id=post_id).first()
    db.session.delete(post)
    db.session.commit()
    flash(f'"{post.title}" was successfully deleted!')
    return redirect(url_for('posts.home'))


from collections import defaultdict
import sys
sys.setrecursionlimit(10 ** 5)
v, e = map(int, input().split())
graph = defaultdict(list)
count = [0 for _ in range(v+1)]
visited = [0 for _ in range(v+1)]

for _ in range(e):
    a, b = map(int, input().split())
    count[a] += 1
    count[b] += 1
    graph[a].append(b)
    graph[b].append(a)

def dfs(x):
    for nx in graph[x]:
        if not visited[nx]:
            visited[nx] = 1
            dfs(nx)

odd = 0 # 차수가 홀수인 정점 체크
for i in range(1, v+1):
    if count[i] % 2:
        odd += 1

# 차가 홀수인 정점이 2개 이하면 오일러 경로 조건 만족
if odd <= 2:
    visited[1] = 1
    dfs(1)
    if sum(visited) == v: # 모든 정점을 방문하는지 확인
        print("YES")
    else:
        print("NO")
else:
    print("NO")


import logging
from typing import Any, Dict, List, Mapping, Optional

from langchain_core.callbacks import CallbackManagerForLLMRun
from langchain_core.language_models.llms import LLM
from langchain_core.pydantic_v1 import Extra, Field, root_validator
from langchain_core.utils import get_from_dict_or_env

from langchain_community.llms.utils import enforce_stop_tokens

logger = logging.getLogger(__name__)

class Petals(LLM):
    """Petals Bloom models.

    To use, you should have the ``petals`` python package installed, and the
    environment variable ``HUGGINGFACE_API_KEY`` set with your API key.

    Any parameters that are valid to be passed to the call can be passed
    in, even if not explicitly saved on this class.

    Example:
        .. code-block:: python

            from langchain_community.llms import petals
            petals = Petals()

    """

    client: Any
    """The client to use for the API calls."""

    tokenizer: Any
    """The tokenizer to use for the API calls."""

    model_name: str = "bigscience/bloom-petals"
    """The model to use."""

    temperature: float = 0.7
    """What sampling temperature to use"""

    max_new_tokens: int = 256
    """The maximum number of new tokens to generate in the completion."""

    top_p: float = 0.9
    """The cumulative probability for top-p sampling."""

    top_k: Optional[int] = None
    """The number of highest probability vocabulary tokens
    to keep for top-k-filtering."""

    do_sample: bool = True
    """Whether or not to use sampling; use greedy decoding otherwise."""

    max_length: Optional[int] = None
    """The maximum length of the sequence to be generated."""

    model_kwargs: Dict[str, Any] = Field(default_factory=dict)
    """Holds any model parameters valid for `create` call
    not explicitly specified."""

    huggingface_api_key: Optional[str] = None

    class Config:
        """Configuration for this pydantic config."""

        extra = Extra.forbid

    @root_validator(pre=True)
    def build_extra(cls, values: Dict[str, Any]) -> Dict[str, Any]:
        """Build extra kwargs from additional params that were passed in."""
        all_required_field_names = {field.alias for field in cls.__fields__.values()}

        extra = values.get("model_kwargs", {})
        for field_name in list(values):
            if field_name not in all_required_field_names:
                if field_name in extra:
                    raise ValueError(f"Found {field_name} supplied twice.")
                logger.warning(
                    f"""WARNING! {field_name} is not default parameter.
                    {field_name} was transferred to model_kwargs.
                    Please confirm that {field_name} is what you intended."""
                )
                extra[field_name] = values.pop(field_name)
        values["model_kwargs"] = extra
        return values

    @root_validator()
    def validate_environment(cls, values: Dict) -> Dict:
        """Validate that api key and python package exists in environment."""
        huggingface_api_key = get_from_dict_or_env(
            values, "huggingface_api_key", "HUGGINGFACE_API_KEY"
        )
        try:
            from petals import AutoDistributedModelForCausalLM
            from transformers import AutoTokenizer

            model_name = values["model_name"]
            values["tokenizer"] = AutoTokenizer.from_pretrained(model_name)
            values["client"] = AutoDistributedModelForCausalLM.from_pretrained(
                model_name
            )
            values["huggingface_api_key"] = huggingface_api_key

        except ImportError:
            raise ImportError(
                "Could not import transformers or petals python package."
                "Please install with `pip install -U transformers petals`."
            )
        return values

    @property
    def _default_params(self) -> Dict[str, Any]:
        """Get the default parameters for calling Petals API."""
        normal_params = {
            "temperature": self.temperature,
            "max_new_tokens": self.max_new_tokens,
            "top_p": self.top_p,
            "top_k": self.top_k,
            "do_sample": self.do_sample,
            "max_length": self.max_length,
        }
        return {**normal_params, **self.model_kwargs}

    @property
    def _identifying_params(self) -> Mapping[str, Any]:
        """Get the identifying parameters."""
        return {**{"model_name": self.model_name}, **self._default_params}

    @property
    def _llm_type(self) -> str:
        """Return type of llm."""
        return "petals"

    def _call(
        self,
        prompt: str,
        stop: Optional[List[str]] = None,
        run_manager: Optional[CallbackManagerForLLMRun] = None,
        **kwargs: Any,
    ) -> str:
        """Call the Petals API."""
        params = self._default_params
        params = {**params, **kwargs}
        inputs = self.tokenizer(prompt, return_tensors="pt")["input_ids"]
        outputs = self.client.generate(inputs, **params)
        text = self.tokenizer.decode(outputs[0])
        if stop is not None:
            # I believe this is required since the stop tokens
            # are not enforced by the model parameters
            text = enforce_stop_tokens(text, stop)
        return text


import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd
import matplotlib.gridspec as gridspec
import math

sscf_dark_data = [
    [1,    1.892824E7],
    [2,    1.4671248E7],
    [3,    1.432372E7],
    [4,    1.3928736E7],
    [4.25, 1.392728E7],
    [4.5,  1.3926672E7],
    [4.75, 1.3926672E7],
    [4.8,  1.3926784E7],
    [4.9,  1.3926784E7],
    [5,    1.9272504E7]
]

def get_sebf_log(filename="gail/sebf-expert.txt"):
    with open(filename, "r") as f:
        line = f.readline()
        count = 0
        jobs_ep = [] # jobs in an episode
        while line:
            if line.startswith("sortedJobs"):
                jobs_str = line.split(":")[-1].strip()[1:-1].split(",")
                # print(jobs_str)
                count += 1
                jobs = []
                for job_s in jobs_str:
                    job_name, job_sent = job_s.strip().split("(")
                    name = eval(job_name.split("-")[-1])
                    sent = eval(job_sent.split("|")[-1].split("/")[0])
                    jobs.append([name, sent])
                jobs_ep.append(jobs)
                # print(jobs)
            line = f.readline()
        return jobs_ep

def analyse_sebf_log():
    jobs_ep = get_sebf_log()
    ## proceed jobs
    # print(jobs_ep)
    prior_jobs = {}
    sent_list = []
    for jobs in jobs_ep:
        for pr, job in enumerate(jobs):
            size = math.log10(job[1]) if job[1] != 0 else 0
            if size == 0:
                continue
            sent_list.append([pr, size])
            if pr in prior_jobs:
                prior_jobs[pr].append(size)
            else:
                prior_jobs[pr]= [size]
    print(prior_jobs.keys())
    sent_list = np.array(sent_list)

    sns.set_style('white')
    data_sent = pd.DataFrame({'prior':sent_list[:,0], 'sent':sent_list[:,1]})
    sns.scatterplot(data=data_sent, x='prior', y='sent')
    plt.xlabel("Priority")
    plt.ylabel("Sent Size(B)")

    # plt.subplot(2, 2, 2)
    # num_jobs = np.array([[key, len(prior_jobs[key])] for key in prior_jobs])
    # plt.scatter(num_jobs[:, 0], num_jobs[:, 1])
    # plt.xlabel("Priority")
    # plt.ylabel("Number of Coflows")

    avg_jobs = np.array([[key, sum(prior_jobs[key])/len(prior_jobs[key])] for key in prior_jobs])
    data = pd.DataFrame({'x':avg_jobs[:,0], 'y':avg_jobs[:,1]})
    sns.lmplot(data=data, x='x', y='y')
    plt.xlabel('Priority')
    plt.ylabel('Average Sent Size(B)')

    plt.show()

def rebuild_mlfq_based_on_sebf():
    jobs_ep = get_sebf_log()
    jobs_log = []
    for jobs in jobs_ep:
        jobs_log.append([(math.log10(job[1]) if job[1] != 0 else 0) for job in jobs])
    MLFQ = [[],[],[],[],[],[],[],[],[],[]]
    N = 10
    ## 尾链表重叠
    count = 0 # 统计优先级错位的数量
    # for jobs in jobs_log:
    #     if len(jobs) <= N:
    #         for i,job in enumerate(jobs):
    #             MLFQ[i].append(job)
    #     else:
    #         rem = len(jobs) - N
    #         count += (rem*2)
    #         for i in range(N-rem):
    #             MLFQ[i].append(jobs[i])
    #         j = N-rem
    #         for i in range(N-rem, N):
    #             MLFQ[i].append(jobs[j])
    #             MLFQ[i].append(jobs[j+1])
    #             j += 2

    ## 末队列添加
    for jobs in jobs_log:
        if len(jobs) <= N:
            for i,job in enumerate(jobs):
                MLFQ[i].append(job)
        else:
            rem = len(jobs) - N
            count += rem
            for i in range(N):
                MLFQ[i].append(jobs[i])
            for i in range(N, N+rem):
                MLFQ[N-1].append(jobs[i])
    sum_active_c = sum([len(jobs) for jobs in jobs_ep])
    print("total: ", sum_active_c, "mismatch:", count)
    print("Rate of mismatch:", round(count/sum_active_c, 4)*100, "%")

    ## 画图
    nozero_MLFQ = []
    for queue in MLFQ:
        q = []
        for size in queue:
            if size > 0:
                q.append(size)
        nozero_MLFQ.append(q)
    queue_size = np.array([[min(queue), max(queue), sum(queue)/len(queue)] for queue in MLFQ])
    print(queue_size)
    queue_nozero = np.array([[min(queue), max(queue), sum(queue)/len(queue)] for queue in nozero_MLFQ])
    print(queue_nozero)
    # plt.plot(range(queue_size.shape[0]), queue_size[:, 2])
    plt.plot(range(queue_nozero.shape[0]), queue_nozero[:, 0], 'ro-')
    plt.plot(range(queue_nozero.shape[0]), queue_nozero[:, 1], 'b+-')
    plt.plot(range(queue_nozero.shape[0]), queue_nozero[:, 2])
    plt.legend(['min', 'max', 'average'])
    plt.show()

def plot_sscf_dark():
    sns.set_style('white')

    data = np.array(sorted(sscf_dark_data, key=lambda x : x[0]))
    print(data)
    plt.plot(data[:, 0], data[:, 1], 'o-')
    plt.show()

if __name__ == "__main__":
    pass
    # analyse_sebf_log()

    # rebuild_mlfq_based_on_sebf()

    plot_sscf_dark()


import flask
import json
import base64
import flask_cors

app=flask.Flask(__name__)

flask_cors.CORS(app, resources={r"/api/*": {"origins": "*"}})

_RETURN_INVALID_REQUEST_PARAMETER = json.dumps({
    'Error': {
        'Code': 'NotParameterGet',
                'Message': 'Invalid request parameter got, check parameter'
    }
})

from modules.part_segementation.app import segementation
@app.route('/api/part_seg', methods=['post'])
def part():
    """
        Parameter
        ---
            - `image` (base64)
    """

    if not flask.request.data:  # check if valid data
        return _RETURN_INVALID_REQUEST_PARAMETER
    # parase paramter
    data_json = json.loads(flask.request.data.decode('utf-8'))

    if 'image' not in data_json:
        return json.dumps({
            'Error': {
                'Code': 'Part_seg.LossParameter',
                'Message': 'parameter "image" not found in request'
            }
        })
    try:
        # image_data = base64.b64decode(data_json['image'])
        # SELECT_IMAGE = image_data
        return json.dumps({
            'image':'data:image/jpeg;base64,'+segementation(data_json['image'])
        })
    except:
        return json.dumps({
            'Error': {
                'Code': 'UploadImage.DecodeImageError',
                'Message': 'decode image error'
            }
        })

if __name__=='__main__':
    app.run(
        host='127.0.0.1',
        # host='192.168.1.131',
        # port=2021
        )


import xml.etree.ElementTree as ET
import os.path
import sys
import random

from classes.Station import Station
from classes.Node import Node
from classes.Link import Link
from classes.Network import Network
from classes.Port import Port
from classes.Flow import Flow
from classes.Target import Target
from classes.Switch import Switch

################################################################@
""" Local methods """
################################################################@

""" parseStations
    Method to parse stations
        root : the xml main root
"""
def parseStations(root,network):
    for station in root.findall('station'):

        network.stations.append (   Station(name=station.get('name'),capacity=float(station.get('transmission-capacity')),network=network) )

""" parseSwitches
    Method to parse switches
        root : the xml main root
"""
def parseSwitches(root,network):
    for sw in root.findall('switch'):
        network.switches.append (   Switch( name=sw.get('name'),
                                            latency=float(sw.get('tech-latency')),
                                            capacity=float(sw.get('transmission-capacity')),
                                            network=network),
                                            )

""" parseEdges
    Method to parse edges
        root : the xml main root
"""
def parseEdges(root,network):
    for sw in root.findall('link'):

        frm = [s for s in (network.stations + network.switches) if s.name()==sw.get('from')][0]
        to =  [s for s in (network.stations + network.switches) if s.name()==sw.get('to')][0]

        from_port=Port(device=frm,number=int(sw.get('fromPort')))

        to_port=Port(device=to,number=int(sw.get('toPort')))

        lk = Link(name=sw.get('name'),
                                     frm=frm,
                                     to=to,
                                     from_port=from_port,
                                     to_port=to_port,
                                     capacity=float(sw.get('transmission-capacity')),
                                     network=network)

        from_port.link(lk)
        to_port.link(lk)

        if frm.is_switch():
            frm.ports.append(from_port)
            frm.links.append(lk)
        else:
            frm.port(from_port)
            frm.link(lk)

        if to.is_switch():
            to.ports.append( to_port )
            to.links.append(lk)
        else:
            to.port(to_port)
            to.link = lk

        network.links.append ( lk )

""" parseFlows
    Method to parse flows
        root : the xml main root
"""
def parseFlows(root,network):
    for sw in root.findall('flow'):

        source = [s for s in (network.stations) if s.name()==sw.get('source')][0]

        flow = Flow (name=sw.get('name'),
                     source=source,
                     payload=float(sw.get('max-payload')),
                     overhead=67,
                     period=float(sw.get('period')),
                     network=network)

        for tg in sw.findall('target'):
            target_object = [s for s in (network.stations) if s.name()==tg.get('name')][0]
            target = Target( name=tg.get('name'),
                             target=target_object,
                             flow=flow)

            flow.targets.append(target)
            target.path.append(flow.source)
            for pt in tg.findall('path'):
                path_node=[s for s in (network.stations + network.switches) if s.name()==pt.get('node')][0]
                target.path.append(path_node)
                if path_node.is_switch() and not(flow in path_node.flows) :
                    path_node.flows.append(flow)

        network.flows.append (flow)
        source.flows.append(flow)

""" parseNetwork
    Method to parse the whole network
        xmlFile : the path to the xml file
"""
def parseNetwork(xmlFile,network):
    if os.path.isfile(xmlFile):
        tree = ET.parse(xmlFile)
        root = tree.getroot()

        for sw in root.findall('network'):
            network.overhead(float(sw.get("overhead")))
            network.name(sw.get("name"))
            network.technology(sw.get("technology"))
            network.capacity(float(sw.get("transmission-capacity")))
            network.shortest_path_policy(sw.get("shortest-path-policy"))

        parseStations(root,network)
        parseSwitches(root,network)
        parseEdges(root,network)
        parseFlows(root,network)
    else:
        print("File not found: "+xmlFile)

""" traceNetwork
    Method to trace the network to the console
"""
def traceNetwork(network):
    print("Stations:")
    for node in network.stations:
        print ("\t" + node.name())

    print("\nSwitches:")
    for node in network.switches:
        print ("\t" + node.name())

    print("\nEdges:")
    for edge in network.links:
        print ("\t" + edge.name() + ": " + edge.frm().name() + "=>" + edge.to().name())

    print("\nFlows:")
    for flow in network.flows:
        print ("\t" + flow.name() + ": " + flow.source.name() + " (L=" + str(flow.payload()) +", p=" + str(flow.period()) + ")")
        for target in flow.targets:
            print ("\t\tTarget=" + target.target().name())
            for node in target.path:
                print ("\t\t\t" + node.name())

""" createFakeResultsFile
    Method to create a fake result file ; only delays are generated (random value between 40 and 80)
        xmlFile : the path to the xml (input) file
"""
def createFakeResultsFile (xmlFile,network):
    posDot = xmlFile.rfind('.')
    if not (posDot == -1):
        resFile = xmlFile[0:posDot]+'_res.xml'
    else:
        resFile = xmlFile+'_res.xml'
    res = open(resFile,"w")
    res.write('<?xml version="1.0" encoding="UTF-8"?>\n')
    res.write('<results>\n')
    res.write('\t<delays>\n')
    for flow in network.flows:
        res.write('\t\t<flow name="' + flow.name() + '">\n');
        for target in flow.targets:
            res.write('\t\t\t<target name="' + target.name() + '" value="'+str(random.randint(400, 800))+'" />\n');
        res.write('\t\t</flow>\n')
    res.write('\t</delays>\n')
    res.write('</results>\n')
    res.close()
    file2output(resFile)

def createResultsFile (xmlFile,network):
    posDot = xmlFile.rfind('.')
    if not (posDot == -1):
        resFile = xmlFile[0:posDot]+'_res.xml'
    else:
        resFile = xmlFile+'_res.xml'
    res = open(resFile,"w")
    res.write('<?xml version="1.0" encoding="UTF-8"?>\n')
    res.write('<results>\n')

    # delays
    res.write('\t<delays>\n')
    for flow in network.flows:
        res.write('\t\t<flow name="' + flow.name() + '">\n');
        for target in flow.targets:
            res.write('\t\t\t<target name="' + target.name() + '" value="'+str(  format(target.eed()*1000000, '.0f'  )   )+'" />\n');
        res.write('\t\t</flow>\n')
    res.write('\t</delays>\n')

    #link loads
    res.write('\t<load>\n')
    for link in network.links:
        res.write('\t\t<edge name="' + link.name() + '">\n');
        res.write('\t\t\t<usage type="' + 'direct' + '" value="'+str(link.direct_usage()  )+'"' +  ' percent="'+str(  format(link.direct_load()*100, '.2f'  )   )+'%" />\n')
        res.write('\t\t\t<usage type="' + 'reverse' + '" value="'+str(link.reverse_usage() )+'"' + ' percent="'+str( format(link.reverse_load()*100,  '.2f' ) )+'%" />\n')
        res.write('\t\t</edge>\n')
    res.write('\t</load>\n')

    # backlogs
    res.write('\t<backlogs>\n')
    for sw in network.switches:
        res.write('\t\t<switch name="' + sw.name() + '">\n');
        for port in sw.ports:
            if port.backlog() > 0:
                res.write('\t\t\t<port num="' + str(port.number()) + '" backlog="'+str(format(port.backlog()/8 , '.0f' ))+'"' +  ' delay="'+str( format(port.delay()*1000000, '.1f') )+'" />\n')
        res.write('\t\t</switch>\n')
    res.write('\t</backlogs>\n')

    res.write('</results>\n')
    res.close()
    file2output(resFile)

""" file2output
    Method to print a file to standard ouput
        file : the path to the xml (input) file
"""
def file2output (file):
    hFile = open(file, "r")
    for line in hFile:
        print(line.rstrip())


# vim: ft=python expandtab
from xml.etree.ElementTree import SubElement
from uuid import uuid4
from site_init import *

Import('env run_target dev_target')
'''
	-I$(top_srcdir)				\
	-I$(top_srcdir)/libdocument		\
	-DGNOMELOCALEDIR=\"$(datadir)/locale\"  \
	-DEVINCE_COMPILATION			\
	$(BACKEND_CFLAGS)			\
	$(POPPLER_CFLAGS)                       \
	$(WARN_CXXFLAGS)			\
	$(DISABLE_DEPRECATED)
'''
env_evshell = env.Clone(PDB='evince.pdb')
env_evshell.Append(CPPDEFINES = [("GNOMELOCALEDIR", r'"\"' + env['PREFIX'].replace('\\', r'\\') + r'\\share\\locale\""'),
                                 ("GNOMEICONDIR", r'"\"' + env['PREFIX'].replace('\\', r'\\') + r'\\share\\evince\\pixmap\""'),
                                 ("BINDIR", r'"\"' + env['PREFIX'].replace('\\', r'\\') + r'\\bin\""'),
                                 ("LIBEXEDIR", r'"\"' + env['PREFIX'].replace('\\', r'\\') + r'\\bin\""'),
                                 ("DATADIR", r'"\"' + env['PREFIX'].replace('\\', r'\\') + r'\\share\\evince\""'),
                                 ("GNOMEDATADIR", r'"\"' + env['PREFIX'].replace('\\', r'\\') + r'\\share\\evince\""'),
                                 ("_WIN32_WINNT", "0x0500"),
                                 ("EVINCE_COMPILATION")])
env_evshell.Append(CPPPATH=['#', '#libdocument', '#libview', '#properties', '#libmisc', '#cut-n-paste/totem-screensaver', '#cut-n-paste/evinfobar', '#cut-n-paste/zoom-control', '#cut-n-paste/toolbar-editor', '#cut-n-paste/gimpcellrenderertoggle', '#cut-n-paste/smclient', '../msvc'])

evince_SOURCES=Split("\
	eggfindbar.c			\
	ev-application.c		\
	ev-file-monitor.c		\
	ev-history.c			\
	ev-keyring.c			\
	ev-marshal.c			\
	ev-message-area.c		\
	ev-metadata.c			\
	ev-navigation-action.c		\
	ev-navigation-action-widget.c	\
	ev-password-view.c		\
	ev-progress-message-area.c	\
	ev-properties-dialog.c		\
	ev-properties-fonts.c		\
	ev-properties-license.c		\
	ev-open-recent-action.c		\
	ev-utils.c			\
	ev-window.c			\
	ev-window-title.c		\
	ev-sidebar.c			\
	ev-sidebar-attachments.c	\
	ev-sidebar-layers.c		\
	ev-sidebar-links.c		\
	ev-sidebar-page.c		\
	ev-sidebar-thumbnails.c		\
	main.c")

env_evshell['GLIB_GENMARSHAL_ARGV'] = [('prefix', 'ev_marshal')]
env_evshell.MarshalGenerator(['ev-marshal.c', 'ev-marshal.h'], 'ev-marshal.list')
env_evshell.Depends(['ev-marshal.c', 'ev-marshal.h'], 'SConscript')

env_evshell.ParseConfig('pkg-config glib-2.0 --cflags --libs')
env_evshell.ParseConfig('pkg-config gthread-2.0 --cflags --libs')
env_evshell.ParseConfig('pkg-config gio-2.0 --cflags --libs')
env_evshell.ParseConfig('pkg-config gtk+-2.0 --cflags --libs')
env_evshell.ParseConfig('pkg-config atk --cflags --libs')
env_evshell.ParseConfig('pkg-config cairo --cflags --libs')
env_evshell.ParseConfig('pkg-config pango --cflags --libs')
env_evshell.ParseConfig('pkg-config poppler-glib --cflags --libs')
env_evshell.ParseConfig('pkg-config libxml-2.0 --cflags --libs')

env_evshell.Append(CPPPATH="#data")
#env_evshell.Append(LDFLAGS="-mwindow")

evince = env_evshell.Program(['evince.exe'], evince_SOURCES + ['#properties/evproperties.lib', '#libdocument/evdocument.lib', '#libview/evview.lib', '#libmisc/evmisc.lib', '#cut-n-paste/evinfobar/evinfobar.lib', '#cut-n-paste/smclient/evsmclient.lib', '#cut-n-paste/toolbar-editor/evtoolbareditor.lib', '#cut-n-paste/totem-screensaver/evtotemscrsaver.lib','#cut-n-paste/gimpcellrenderertoggle/evgimpcellrenderertoggle.lib', '#cut-n-paste/zoom-control/evephyzoom.lib', env_evshell.RES('evince-icon.rc')])
env_evshell.AddPostAction(evince, 'mt.exe -nologo -manifest ${TARGET}.manifest -outputresource:$TARGET;2')
if not env_evshell['DEBUG']:
    env_evshell.AddPostAction(evince, 'editbin.exe /subsystem:windows $TARGET')

env_evshell.Alias('install', env_evshell.Install('$PREFIX/bin', 'evince.exe'))
run_dbin = find_tag_by_id(run_target, 'Directory', 'bin')
if run_dbin == None:
    run_dbin = SubElement(run_target, 'Directory', Id='bin', Name='bin')
    run_cexe = SubElement(run_dbin, "Component", Id='exes', Guid=str(uuid4()).upper())
else:
    run_cexe = find_tag_by_id(run_dbin, 'Component', 'exes')
    if run_cexe == None:
        run_cexe = SubElement(run_dbin, "Component", Id='exes', Guid=str(uuid4()).upper())
FileElement(run_cexe, 'evince.exe', 'bin', env_evshell)

if env_evshell['DEBUG'] == 1:
    env_evshell.Alias('install', env_evshell.Install('$PREFIX/pdb', 'evince.pdb'))
    dev_dpdb = find_tag_by_id(dev_target, 'Directory', 'pdb')
    if dev_dpdb == None:
        dev_dpdb = SubElement(dev_target, 'Directory', Id='pdb', Name='pdb')
        dev_cpdb = SubElement(dev_dpdb, "Component", Id='pdbs', Guid=str(uuid4()).upper())
    else:
        dev_cpdb = find_tag_by_id(dev_dpdb, 'Component', 'pdbs')
        if dev_cpdb == None:
            dev_cpdb = SubElement(dev_dpdb, "Component", Id='pdbs', Guid=str(uuid4()).upper())
    FileElement(dev_cpdb, env_evshell['PDB'], 'pdb', env_evshell)


import asyncio
from collections import namedtuple
import asyncpg
from asyncpg.pool import Pool
import logging
from decimal import Decimal
import yaml
from typing import List, Tuple, Dict, T, NamedTuple
from datetime import datetime, timedelta, timezone
from importlib import import_module
from dateutil import parser
import struct
from config import config

TIMEFRAMES = [
    60, 300, 900, 1800, 3600, 14400, 43200, 86400
]

class Trade(NamedTuple):
    pair_id: int
    timestamp: int
    amount: float
    price: float

    def serialize(self):
        return struct.pack('iQdd', self.pair_id, self.timestamp,
                           self.amount, self.price)

    @classmethod
    def deserialize(cls, b):
        return cls(*struct.unpack('iQdd', b))

class DBException(Exception): pass
class DBInvalidParams(DBException): pass

async def get_exchange_id(db_pool: Pool, name: str):
    async with db_pool.acquire() as conn:
        mod = import_module(f'.{name}', 'exchange')
        display_name = mod.Fetcher.NAME
        await conn.execute('''
            INSERT INTO exchanges (name, display_name)
            VALUES($1, $2)
            ON CONFLICT DO NOTHING
        ''', name, display_name)
        return await conn.fetchval('''
            SELECT id FROM exchanges WHERE name = $1
        ''', name)

async def get_pair_id(db_pool: Pool, ex_id: int, base: str, quote: str):
    async with db_pool.acquire() as conn:
        async def get():
            pair_id = await conn.fetchval('''
                SELECT id FROM pairs
                WHERE exchange = $1 AND
                      base = $2 AND
                      quote = $3
            ''', ex_id, base, quote)
            return pair_id
        pair_id = await get()
        if not pair_id:
            await conn.execute('''
                INSERT INTO pairs (exchange, base, quote)
                VALUES ($1, $2, $3)
            ''', ex_id, base, quote)
            pair_id = await get()
        return pair_id

time_2k = parser.parse('2000-01-01 00:00:00')\
    .replace(tzinfo=timezone.utc)\
    .astimezone(tz=None)\
    .timestamp() * 1000

async def insert_trade(db_pool: Pool, trade: Trade):
    logging.debug('trade: %s: pair: %s; amount: %s; price: %s',
                  # trade.timestamp.strftime('%d.%m.%Y %H:%M:%S'),
                  '',
                  trade.pair_id,
                  trade.amount,
                  trade.price)
    async with db_pool.acquire() as conn:
        await conn.set_type_codec(
            'timestamptz',
            encoder=lambda x: ((x - time_2k) * 1000,),
            decoder=str,
            schema='pg_catalog', format='tuple'
        )
        await conn.execute(
            '''
            INSERT INTO trades (pair, ts, amount, price)
            VALUES ($1, $2, $3, $4)
            ''',
            *trade
        )

def to_dict(record: asyncpg.Record) -> Dict[str, T]:
    result = {}
    for k, v in record.items():
        if isinstance(v, Decimal):
            result[k] = float(v)
        else:
            result[k] = v
    return result

async def get_pair_list(db_pool: Pool) -> List[Tuple[str, int, str, str]]:
    async with db_pool.acquire() as conn:
        result = await conn.fetch('''
            SELECT concat(pairs.base, '/', pairs.quote) as symbol,
                   pairs.id as pair_id,
                   exchanges.name as ex_name,
                   exchanges.display_name as disp_name
            FROM pairs
            JOIN exchanges ON pairs.exchange = exchanges.id
        ''')
        return result

async def get_summary(
    db_pool: Pool, pairs: List[int], start: datetime, end: datetime
) -> Dict[str, float]:
    async with db_pool.acquire() as conn:
        try:
            result = await conn.fetchrow(
                'SELECT * FROM get_summary($1::int[], $2, $3)',
                pairs, start, end
            )
            return to_dict(result)
        except asyncpg.exceptions.RaiseError as e:
            raise DBInvalidParams(str(e))

async def get_volume_chart(
    db_pool: Pool,
    pairs: List[int],
    start: datetime,
    interval: timedelta,
    count: int
) -> List[Tuple[int, float, float]]:
    if interval.total_seconds() not in TIMEFRAMES:
        raise DBInvalidParams('invalid interval')
    async with db_pool.acquire() as conn:
        await conn.set_type_codec(
            'numeric', encoder=str, decoder=float,
            schema='pg_catalog', format='text'
        )
        try:
            result = await conn.fetch(
                '''
                SELECT * FROM aggregate_volume(
                    $1::int[], $2, $3, $4
                )
                ''',
                pairs,
                start,
                interval,
                count
            )
            return [*map(tuple, result)]
        except asyncpg.exceptions.RaiseError as e:
            raise DBInvalidParams(str(e))

async def get_simple_price_chart(
    db_pool: Pool,
    pairs: List[int],
    start: datetime,
    interval: timedelta,
    count: int
) -> List[Tuple[int, float]]:
    if interval.total_seconds() not in TIMEFRAMES:
        raise DBInvalidParams('invalid interval')
    async with db_pool.acquire() as conn:
        await conn.set_type_codec(
            'numeric', encoder=str, decoder=float,
            schema='pg_catalog', format='text'
        )
        try:
            result = await conn.fetch(
                '''
                SELECT * FROM get_simple_price_chart(
                    $1::int[], $2, $3, $4
                )
                ''',
                pairs,
                start,
                interval,
                count
            )
            return [*map(tuple, result)]
        except asyncpg.exceptions.RaiseError as e:
            raise DBInvalidParams(str(e))

async def get_ohlc_chart(
    db_pool: Pool,
    pairs: List[int],
    start: datetime,
    interval: timedelta,
    count: int
) -> List[Tuple[int, float, float, float, float]]:
    if interval.total_seconds() not in TIMEFRAMES:
        raise DBInvalidParams('invalid interval')
    async with db_pool.acquire() as conn:
        await conn.set_type_codec(
            'numeric', encoder=str, decoder=float,
            schema='pg_catalog', format='text'
        )
        try:
            result = await conn.fetch(
                '''
                SELECT * FROM get_ohlc_chart(
                    $1::int[], $2, $3, $4
                )
                ''',
                pairs,
                start,
                interval,
                count
            )
            return [*map(tuple, result)]
        except asyncpg.exceptions.RaiseError as e:
            raise DBInvalidParams(str(e))

async def get_volume_profile_chart(
    db_pool: Pool,
    pairs: List[int],
    start: datetime,
    end: datetime,
    frames: int
) -> List[Tuple[float, float, float, float]]:
    async with db_pool.acquire() as conn:
        await conn.set_type_codec(
            'numeric', encoder=str, decoder=float,
            schema='pg_catalog', format='text'
        )
        try:
            result = await conn.fetch(
                '''
                SELECT * FROM get_volume_profile(
                    $1::int[], $2, $3, $4
                )
                ''',
                pairs,
                start,
                end,
                frames
            )
            return [*map(tuple, result)]
        except asyncpg.exceptions.RaiseError as e:
            raise DBInvalidParams(str(e))

async def connect() -> Pool:
    if not connect.db_pool:
        connect.db_pool = await asyncpg.create_pool(**config['dbconf'])
        logging.info(f"connected to db {config['dbconf']}")
    return connect.db_pool

connect.db_pool = None


import inspect
from typing import Union
from .. import _LOGGER

from ..const import (
    TEXT_UNKNOWN,
    WISERDEVICE,
    WiserAwayActionEnum,
    WiserDeviceModeEnum,
    WiserShutterAwayActionEnum,
)
from ..helpers.misc import is_value_in_list
from ..helpers.signal import _WiserSignalStrength
from ..rest_controller import _WiserRestController

class _WiserDevice(object):
    """Class representing a wiser heating device"""

    def __init__(
        self,
        wiser_rest_controller: _WiserRestController,
        endpoint: str,
        data: dict,
        device_type_data: dict,
        schedule: dict = None,
    ):
        self._data = data
        self._device_type_data = device_type_data
        self._wiser_rest_controller = wiser_rest_controller
        self._endpoint = endpoint

    async def _send_command(self, cmd: dict, device_level: bool = False):
        """
        Send control command to the smart plug
        param cmd: json command structure
        return: boolen - true = success, false = failed
        """
        if device_level:
            result = await self._wiser_rest_controller._send_command(
                WISERDEVICE.format(self.id), cmd
            )
            if result:
                self._data = result
        else:
            result = await self._wiser_rest_controller._send_command(
                self._endpoint.format(self.id), cmd
            )
            if result:
                self._device_type_data = result
        if result:
            _LOGGER.debug(
                "Wiser device - {} command successful".format(
                    inspect.stack()[1].function
                )
            )
            return True
        return False

    @property
    def device_lock_enabled(self) -> bool:
        """Get or set device lock"""
        return self._data.get("DeviceLockEnabled", False)

    async def set_device_lock_enabled(self, enabled: bool = False):
        if await self._send_command({"DeviceLockEnabled": enabled}, True):
            self._device_lock_enabled = enabled
            return True

    @property
    def device_type_id(self) -> int:
        """Get the device id for the specific device type"""
        return self._data.get("id")

    @property
    def identify(self) -> bool:
        """Get or set if the identify function is enabled"""
        return self._data.get("IdentifyActive", False)

    async def set_identify(self, enabled: bool = False):
        if await self._send_command({"Identify": enabled}, True):
            self._indentify_active = enabled
            return True

    @property
    def firmware_version(self) -> str:
        """Get firmware version of device"""
        return self._data.get("ActiveFirmwareVersion", TEXT_UNKNOWN)

    @property
    def id(self) -> int:
        """Get id of device"""
        return self._data.get("id")

    @property
    def model(self) -> str:
        """Get model of device"""
        # Lights and shutters currently have model identifier as Unknowm
        return (
            self._data.get("ProductType", TEXT_UNKNOWN)
            if self._data.get("ModelIdentifier") == TEXT_UNKNOWN
            else self._data.get("ModelIdentifier", TEXT_UNKNOWN)
        )

    @property
    def name(self) -> str:
        """Get name of device - ProductType + id"""
        return f"{self.product_type}-{self.id}"

    @property
    def node_id(self) -> int:
        """Get zigbee node id of device"""
        return self._data.get("NodeId", 0)

    @property
    def product_identifier(self) -> str:
        """Get product identifier of device"""
        return self._data.get("ProductIdentifier", TEXT_UNKNOWN)

    @property
    def product_model(self) -> str:
        """Get product model of device"""
        return self._data.get("ProductModel", TEXT_UNKNOWN)

    @property
    def parent_node_id(self) -> int:
        """Get zigbee node id of device this device is connected to"""
        return self._data.get("ParentNodeId", 0)

    @property
    def product_type(self) -> str:
        """Get product type of device"""
        return self._data.get("ProductType", TEXT_UNKNOWN)

    @property
    def room_id(self) -> int:
        """Get heating actuator room id"""
        return self._device_type_data.get("RoomId", 0)

    @property
    def serial_number(self) -> str:
        """Get serial number of device"""
        return self._data.get("SerialNumber", TEXT_UNKNOWN)

    @property
    def signal(self) -> _WiserSignalStrength:
        """Get zwave network information"""
        return _WiserSignalStrength(self._data)

class _WiserElectricalDevice(_WiserDevice):
    """Class representing a wiser electrical device"""

    def __init__(
        self,
        wiser_rest_controller: _WiserRestController,
        endpoint: str,
        data: dict,
        device_type_data: dict,
        schedule: dict,
    ):
        super().__init__(
            wiser_rest_controller, endpoint, data, device_type_data, schedule
        )
        self._schedule = schedule

        # Add device id to schedule
        if self._schedule:
            self._schedule._assignments.append(
                {"id": self.device_type_id, "name": self.name}
            )
            self._schedule._device_ids.append(self.id)

    @property
    def available_modes(self):
        """Get available modes"""
        return [mode.value for mode in WiserDeviceModeEnum]

    @property
    def available_away_mode_actions(self):
        """Get available away mode actions"""
        return [action.value for action in WiserAwayActionEnum]

    @property
    def away_mode_action(self) -> str:
        """Get or set the away action of the light (off or no change)"""
        return self._device_type_data.get("AwayAction", TEXT_UNKNOWN)

    async def set_away_mode_action(
        self, action: Union[WiserAwayActionEnum, WiserShutterAwayActionEnum, str]
    ) -> bool:
        if (
            type(action) == WiserAwayActionEnum
            or type(action) == WiserShutterAwayActionEnum
        ):
            action = action.value

        if is_value_in_list(action, self.available_away_mode_actions):
            if await self._send_command({"AwayAction": action}):
                self._away_action = action
                return True
        else:
            raise ValueError(
                f"{action} is not a valid away mode action.  Valid modes are {self.available_away_mode_actions}"
            )

    @property
    def device_type_id(self) -> int:
        """Get the device id for the specific device type"""
        return self._device_type_data.get("id")

    @property
    def mode(self) -> str:
        """Get or set the current mode of the light (Manual or Auto)"""
        return self._device_type_data.get("Mode", TEXT_UNKNOWN)

    async def set_mode(self, mode: Union[WiserDeviceModeEnum, str]) -> bool:
        if type(mode) == WiserDeviceModeEnum:
            mode = mode.value
        if is_value_in_list(mode, self.available_modes):
            return await self._send_command({"Mode": mode.title()})
        else:
            raise ValueError(
                f"{mode} is not a valid mode.  Valid modes are {self.available_modes}"
            )

    @property
    def name(self) -> str:
        return self._device_type_data.get("Name", TEXT_UNKNOWN)

    async def set_name(self, name: str) -> bool:
        if await self._send_command({"Name": name}):
            return True

    @property
    def schedule(self):
        """Get the schedule of the light"""
        return self._schedule

    @property
    def schedule_id(self) -> int:
        """Get the schedule id for the light"""
        return self._device_type_data.get("ScheduleId")


from django.shortcuts import render, redirect
from .helpers import load_books_from_file, save_books_to_file, delete_book_from_file,get_book_index_by_id,search_books_in_file
from .models import Book
from django.shortcuts import redirect, HttpResponse

def book_list(request):
    books = load_books_from_file()
    return render(request, 'library/book_list.html', {'books': books})

def add_book(request):
    if request.method == 'POST':
        title = request.POST['title']
        author = request.POST['author']
        genre = request.POST['genre']
        height = request.POST['height']
        publisher = request.POST['publisher']
        books = load_books_from_file()
        book_ids = [book['book_id'] for book in books]
        book_id = max(book_ids) + 1 if book_ids else 1
        book = {
            'book_id': book_id,
            'title': title,
            'author': author,
            'genre': genre,
            'height': int(height),
            'publisher': publisher
        }
        books.append(book)
        save_books_to_file(books)
        return redirect('book_list')
    return render(request, 'library/add_book.html')

def delete_book(request, book_id):
    books = load_books_from_file()
    book_index = get_book_index_by_id(int(book_id), books)
    if book_index is not None:
        book = books[book_index]
        success = delete_book_from_file(book)
        if success:
            return redirect('book_list')
    return HttpResponse('Book not found.')

def search_books(request):
    if request.method == 'POST':
        name = request.POST['name']
        genre = request.POST['genre']
        books = search_books_in_file(name, genre)
        return render(request, 'library/book_list.html', {'books': books})
    return redirect('book_list')


import random
import math
import logging
import torch
import torch.nn as nn
import numpy as np
import networkx as nx
import pandas as pd
import pprint

from typing import List, Tuple, Dict, Union
from ..base import *
from .link_state import *
from ...constants import DQNROUTE_LOGGER
from ...messages import *
from ...memory import *
from ...utils import *
from ...networks import *

MIN_TEMP = 1.5

logger = logging.getLogger(DQNROUTE_LOGGER)

class DQNRouter(LinkStateRouter, RewardAgent):
    """
    A router which implements DQN-routing algorithm
    """
    def __init__(self, batch_size: int, mem_capacity: int, nodes: List[AgentId],
                 optimizer='rmsprop', brain=None, random_init=False, max_act_time=None,
                 additional_inputs=[], **kwargs):
        super().__init__(**kwargs)
        self.batch_size = batch_size
        self.memory = Memory(mem_capacity)
        self.additional_inputs = additional_inputs
        self.nodes = nodes
        self.max_act_time = max_act_time

        if brain is None:
            self.brain = self._makeBrain(additional_inputs=additional_inputs, **kwargs)
            if random_init:
                self.brain.init_xavier()
            else:
                self.brain.restore()
                self.log('Restored model {}'.format(self.brain._label))

        else:
            self.brain = brain

        self.optimizer = get_optimizer(optimizer)(self.brain.parameters())
        self.loss_func = nn.MSELoss()

    def route(self, sender: AgentId, pkg: Package, allowed_nbrs: List[AgentId]) -> Tuple[AgentId, List[Message]]:
        if self.max_act_time is not None and self.env.time() > self.max_act_time:
            return super().route(sender, pkg, allowed_nbrs)
        else:
            to, estimate, saved_state = self._act(pkg, allowed_nbrs)
            reward = self.registerResentPkg(pkg, estimate, to, saved_state)
            return to, [OutMessage(self.id, sender, reward)] if sender[0] != 'world' else []

    def handleMsgFrom(self, sender: AgentId, msg: Message) -> List[Message]:
        if isinstance(msg, RewardMsg):
            action, Q_new, prev_state = self.receiveReward(msg)
            self.memory.add((prev_state, action[1], -Q_new))
            self._replay()
            return []
        else:
            return super().handleMsgFrom(sender, msg)

    def _makeBrain(self, additional_inputs=[], **kwargs):
        return QNetwork(len(self.nodes), additional_inputs=additional_inputs,
                        one_out=False, **kwargs)

    def _act(self, pkg: Package, allowed_nbrs: List[AgentId]):
        state = self._getNNState(pkg, allowed_nbrs)
        prediction = self._predict(state)[0]
        distr = softmax(prediction, MIN_TEMP)
        estimate = -np.dot(prediction, distr)

        to = -1
        while ('router', to) not in allowed_nbrs:
            to = sample_distr(distr)

        return ('router', to), estimate, state

    def _predict(self, x):
        self.brain.eval()
        return self.brain(*map(torch.from_numpy, x))\
                   .clone().detach().numpy()

    def _train(self, x, y):
        self.brain.train()
        self.optimizer.zero_grad()
        output = self.brain(*map(torch.from_numpy, x))
        loss = self.loss_func(output, torch.from_numpy(y))
        loss.backward()
        self.optimizer.step()
        return float(loss)

    def _getAddInput(self, tag, *args, **kwargs):
        if tag == 'amatrix':
            amatrix = nx.convert_matrix.to_numpy_array(
                self.network, nodelist=self.nodes, weight=self.edge_weight,
                dtype=np.float32)
            gstate = np.ravel(amatrix)
            return gstate
        else:
            raise Exception('Unknown additional input: ' + tag)

    def _getNNState(self, pkg: Package, nbrs: List[AgentId]):
        n = len(self.nodes)
        addr = np.array(self.id[1])
        dst = np.array(pkg.dst[1])

        neighbours = np.array(
            list(map(lambda v: v in nbrs, self.nodes)),
            dtype=np.float32)
        input = [addr, dst, neighbours]

        for inp in self.additional_inputs:
            tag = inp['tag']
            add_inp = self._getAddInput(tag)
            if tag == 'amatrix':
                add_inp[add_inp > 0] = 1
            input.append(add_inp)

        return tuple(input)

    def _sampleMemStacked(self):
        """
        Samples a batch of episodes from memory and stacks
        states, actions and values from a batch together
        """
        i_batch = self.memory.sample(self.batch_size)
        batch = [b[1] for b in i_batch]

        states = stack_batch([l[0] for l in batch])
        actions = [l[1] for l in batch]
        values = [l[2] for l in batch]

        return states, actions, values

    def _replay(self):
        """
        Fetches a batch of samples from the memory and fits against them
        """
        states, actions, values = self._sampleMemStacked()
        preds = self._predict(states)

        for i in range(self.batch_size):
            a = actions[i]
            preds[i][a] = values[i]

        self._train(states, preds)

class DQNRouterOO(DQNRouter):
    """
    Variant of DQN router which uses Q-network with scalar output
    """
    def _makeBrain(self, additional_inputs=[], **kwargs):
        return QNetwork(len(self.nodes), additional_inputs=additional_inputs,
                        one_out=True, **kwargs)

    def _act(self, pkg: Package, allowed_nbrs: List[AgentId]):
        state = self._getNNState(pkg, allowed_nbrs)
        prediction = self._predict(state).flatten()
        distr = softmax(prediction, MIN_TEMP)
        to_idx = sample_distr(distr)
        estimate = -np.dot(prediction, distr)

        saved_state = [s[to_idx] for s in state]
        to = allowed_nbrs[to_idx]
        return to, estimate, saved_state

    def _nodeRepr(self, node):
        return np.array(node)

    def _getAddInput(self, tag, nbr):
        return super()._getAddInput(tag)

    def _getNNState(self, pkg: Package, nbrs: List[AgentId]):
        n = len(self.nodes)
        addr = self._nodeRepr(self.id[1])
        dst = self._nodeRepr(pkg.dst[1])

        get_add_inputs = lambda nbr: [self._getAddInput(inp['tag'], nbr)
                                      for inp in self.additional_inputs]

        input = [[addr, dst, self._nodeRepr(v[1])] + get_add_inputs(v)
                 for v in nbrs]
        return stack_batch(input)

    def _replay(self):
        states, _, values = self._sampleMemStacked()
        self._train(states, np.expand_dims(np.array(values, dtype=np.float32), axis=0))

class DQNRouterEmb(DQNRouterOO):
    """
    Variant of DQNRouter which uses graph embeddings instead of
    one-hot label encodings.
    """
    def __init__(self, embedding: Union[dict, Embedding], edges_num: int, **kwargs):
        # Those are used to only re-learn the embedding when the topology is changed
        self.prev_num_nodes = 0
        self.prev_num_edges = 0
        self.init_edges_num = edges_num
        self.network_initialized = False

        if type(embedding) == dict:
            self.embedding = get_embedding(**embedding)
        else:
            self.embedding = embedding

        super().__init__(**kwargs)

    def _makeBrain(self, additional_inputs=[], **kwargs):
        return QNetwork(len(self.nodes), additional_inputs=additional_inputs,
                        embedding_dim=self.embedding.dim, one_out=True, **kwargs)

    def _nodeRepr(self, node):
        return self.embedding.transform(node).astype(np.float32)

    def networkStateChanged(self):
        num_nodes = len(self.network.nodes)
        num_edges = len(self.network.edges)

        if not self.network_initialized and num_nodes == len(self.nodes) and num_edges == self.init_edges_num:
            self.network_initialized = True

        if self.network_initialized and (num_edges != self.prev_num_edges or num_nodes != self.prev_num_nodes):
            self.prev_num_nodes = num_nodes
            self.prev_num_edges = num_edges
            self.embedding.fit(self.network, weight=self.edge_weight)
            # self.log(pprint.pformat(self.embedding._X), force=self.id[1] == 0)

class DQNRouterNetwork(NetworkRewardAgent, DQNRouter):
    pass

class DQNRouterOONetwork(NetworkRewardAgent, DQNRouterOO):
    pass

class DQNRouterEmbNetwork(NetworkRewardAgent, DQNRouterEmb):
    pass

class ConveyorAddInputMixin:
    """
    Mixing which adds conveyor-specific additional NN inputs support
    """
    def _getAddInput(self, tag, nbr=None):
        if tag == 'work_status':
            return np.array(
                list(map(lambda n: self.network.nodes[n].get('works', False), self.nodes)),
                dtype=np.float32)
        if tag == 'working':
            nbr_works = 1 if self.network.nodes[nbr].get('works', False) else 0
            return np.array(nbr_works, dtype=np.float32)
        else:
            return super()._getAddInput(tag, nbr)

class DQNRouterConveyor(LSConveyorMixin, ConveyorRewardAgent, ConveyorAddInputMixin, DQNRouter):
    pass

class DQNRouterOOConveyor(LSConveyorMixin, ConveyorRewardAgent, ConveyorAddInputMixin, DQNRouterOO):
    pass

class DQNRouterEmbConveyor(LSConveyorMixin, ConveyorRewardAgent, ConveyorAddInputMixin, DQNRouterEmb):
    pass


from uuid import UUID

from fastapi import Depends
from warehouse.api_client.client import WarehouseGeneralClient
from warehouse.models.warehouse import WarehouseListFilters, WarehouseModel

from svc.api.errors.warehouse import WarehouseNotFoundError
from svc.infrastructure.warehouse.models import WarehouseShortModel

class WarehouseManager:
    def __init__(
        self,
        warehouse_client: WarehouseGeneralClient = Depends(WarehouseGeneralClient.instance),
    ) -> None:
        self._warehouse_client = warehouse_client

    async def get_warehouses(self, warehouse_ids: list[UUID]) -> list[WarehouseModel]:
        if not warehouse_ids:
            return []

        response = await self._warehouse_client.warehouse.list_warehouses(
            WarehouseListFilters(
                warehouse_ids=warehouse_ids,
                offset=0,
                limit=len(warehouse_ids),
            )
        )

        if response.error is not None:
            raise Exception(response.error.code)

        if not response.result:
            return []

        return response.result.items

    async def get_single_warehouse(self, warehouse_id: UUID) -> WarehouseShortModel:
        response = await self._warehouse_client.warehouse.get_warehouse(warehouse_id=warehouse_id)
        if response.error is not None:
            raise Exception(response.error.code)

        if not response.result:
            raise WarehouseNotFoundError()

        res: WarehouseModel = response.result
        return WarehouseShortModel(
            id=res.id,
            active=res.active,
            tz=res.tz,
        )


#!/usr/bin/env python

"""PatternCalibration Detection Tests

use `python -m plant_detection.tests.test_pattern_detection /images/`

For Plant Detection.
"""
import os
import sys
import cv2
import numpy as np
from plant_detection.PatternCalibration import PatternCalibration

def result(found):
    'Generate result text.'
    return '\033[92mOK\033[0m' if found else '\033[91mMISS\033[0m'

def save_output(filepath):
    'Save side-by-side pattern detection image results.'
    def _fn(ret, img, original):
        output_dir = '{}/output/'.format(os.path.dirname(filepath))
        if not os.path.exists(output_dir):
            os.mkdir(output_dir)
        img = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
        img = np.concatenate((original, img), axis=1)
        if ret:
            text = 'OK'
            color = (0, 255, 0)
        else:
            text = 'MISS'
            color = (0, 0, 255)
        font = cv2.FONT_HERSHEY_SIMPLEX
        location = (original.shape[1] - 50, 50)
        img = cv2.putText(img, text, location, font, 2, color, 10)
        cv2.imwrite(output_dir + filepath.split('/')[-1], img)
    return _fn

def process_images(directory):
    'Detect pattern in images in directory.'
    pattern_calibration = PatternCalibration({})
    img_files = [f for f in os.listdir(directory) if '.' in f]
    count = 0
    for filename in img_files:
        img_path = directory + filename
        print(img_path)
        if os.path.exists(img_path):
            img = cv2.imread(img_path)
            ret, _centers = pattern_calibration.find_pattern(
                img, save_output=save_output(img_path))
            print('{:<16} {}'.format(result(ret), img_path))
            count += 1
        else:
            print('path not found:', img_path)

    if count > 0:
        print('{} result images saved to {}'.format(
            count, input_dir + 'output/'))

if __name__ == '__main__':
    input_dir = sys.argv[1]
    process_images(input_dir)


# 1. Імпортувати модуль pygame
import pygame
# 2. Імпортувати модуль os
import os
# 3. Імпортувати модуль random
import random
# 4. Ініціалізувати налаштування pygame
pygame.init()
# 5. Створити функцію create_path, що знаходить абсолютний шлях до файлу.
# Застосовуємо модуль os.path та його методи abspath(), join()
def create_path(file):
    return os.path.join(os.path.abspath(__file__+"/.."),file)
# 6. Створити клас Sprite, в методі init задати 5 параметрів зі значенням за замовчуванням None
    # - координата x
    # - координата y
    # - ширина
    # - висота
    # - ім'я зображення
class Sprite:
    def __init__(self,x=None,y=None,width=None,height=None,name_img=None):
        # 7. Задати 7 властивостей:
        # - X
        # - Y
        # - WIDTH
        # - HEIGHT
        # - NAME_IMG
        # - IMAGE
        self.X = x
        self.Y = y
        self.WIDTH = width
        self.HEIGHT = height
        self.NAME_IMG = name_img
        self.IMAGE = None
    # 8. Створити метод завантаження зображення до властивості IMAGE
    def load_image(self):
        # - створи змінну path, яка зберігає абсолютний шлях до файлу зображення, застосовуємо функцію create_path
        # - завантажити зображення до всластивості IMAGE
        # - трансформувати збережене в IMAGE зображення до розмірів,
        #   що збережені у властивостях WIDTH, HEIGHT. Та зберегти повторно у властивості IMAGE.
        self.IMAGE = create_path(self.NAME_IMG)
        self.IMAGE = pygame.image.load(self.IMAGE)
        self.IMAGE = pygame.transform.scale(self.IMAGE,(self.WIDTH,self.HEIGHT))
    # 9. Створити метод, що промальовує завантажене зображення із властивості IMAGE, метод приймає один параметр - ігрове вікно
    def blit_sprite(self,play):
        # - застосовуємо метод blit() модуля pygame
        play.blit(self.IMAGE,(self.X,self.Y))
# 8. За класом створюємо ігровое вікно з ім'ям win
play = pygame.display.set_mode((500,500))
# 9. Задаємо назву ігрового вікна
pygame.display.set_caption("Привет, Николай!")
# 10. Створюємо основну функцію гри run_game:
def run_game():
    # - створюємо метод clock
    fps = pygame.time.Clock()
    # - створюємо об'єкт класу Sprite з ім'ям sprite,
    sprite = Sprite(0,0,250,250,"nanyat.png")
    sprite.load_image()
    # - задаємо змінну game, що відповідає за роботу циклу
    game = True
    # - задаємо ігровий цикл while,
    while game == True:
    # - задаємо умову закриття ігрового вікна,
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                game = False
    # - задаємо фон ігрового вікна (мотод fill)
        play.fill((0,255,80))
    # - задіємо об'єкт sprite і викликаємо його метод blit_sprite(), малюємо зображення на ігровому вікні, в центрі екрану
        sprite.blit_sprite(play)
        fps.tick(random.randint(0,60))
        pygame.display.flip()
    # - задаємо оновлення ігрового екрану
# 11. І найголовніше – викликаємо основну функцію гри
run_game()


""" aoc_03_2.py

    Solution for Advent of Code 2017 day 03 part 2
"""

import itertools

import aoc_03_input

def get_square(num):
    ''' get_square(num)

        Return the numth square in the spiral.
    '''
    return list(generate_spiral(num))[num-1]

def generate_spiral(max_square):
    ''' spiral(max_square)

        A generator that generates a spiral according to Advent of Code 2017,
        day 03 part 2.
    '''

    spiral = {}

    current_dir = (0, 1)
    cord = (0, 0)

    for i in range(0, max_square):
        if i > max_square:
            break

        spiral[cord] = value(cord, spiral)
        yield {'cord': cord, 'value': spiral[cord]}

        current_dir = get_direction(cord, current_dir, spiral)
        cord = (cord[0] + current_dir[0], cord[1] + current_dir[1])

def get_direction(cord, current_direction, spiral):
    ''' get_direction(cord, current_direction, spiral)

        Given a cordinate and the current_direction, it checks whatever turning
        now would end up in a non occupied square, if so, return the new
        direction, otherwise we keep going in the same direction.
    '''

    new_direction = next_direction(current_direction)

    check_cord = (cord[0] + new_direction[0],
                  cord[1] + new_direction[1])

    if spiral.get(check_cord):
        return current_direction

    return new_direction

def next_direction(direction):
    ''' next_direction(direction)

        Maps a given direction to a new direction so that we turn left all the
        time in the spiral.
    '''
    direction_mappings = {
        (0, 1): (1, 0),
        (1, 0): (0, -1),
        (0, -1): (-1, 0),
        (-1, 0): (0, 1)
    }
    return direction_mappings[direction]

def value(cord, spiral):
    ''' value(cord, spiral)

        Get all values from neighbouring squares, and sums them up which is the
        value the square at cord should have.
    '''
    if cord == (0, 0):
        return 1

    neightbours_offsets = list(itertools.product([1, 0, -1], [1, 0, -1]))
    neightbours_offsets.remove((0, 0))  # Not interested in ourself

    neighbour_values = map(lambda offset: spiral.get((cord[0] + offset[0],
                                                      cord[1] + offset[1]), 0),
                           neightbours_offsets)
    return sum(neighbour_values)

def main():
    ''' main()

        Main function that use the input from Advent of Code and print the
        answer for day threes problem.
    '''
    target = aoc_03_input.get_input()

    # The square we want will always be in a square earlier than the target
    # value
    for square in generate_spiral(target):
        if square['value'] > target:
            print(square['value'])
            break

if __name__ == '__main__':
    main()


from PySide2.QtGui import QFontMetrics, QTextCursor
from PySide2.QtWidgets import QMainWindow, QLabel, QWidget, QVBoxLayout, \
    QHBoxLayout, QPushButton, QTextEdit, QScrollBar

from PySide2.QtWidgets import QMainWindow, QLabel, QWidget, QVBoxLayout, \
    QHBoxLayout, QPushButton, QStackedWidget

from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg
from matplotlib.figure import Figure
import seaborn as sns

from sklearn.metrics import accuracy_score, confusion_matrix

#Source: https://www.pythonguis.com/tutorials/plotting-matplotlib/
class MplCanvas(FigureCanvasQTAgg):

    def __init__(self, y_true, predicted, parent=None, width=16, height=9, dpi=100):

        fig = Figure(figsize=(width, height), dpi=dpi)
        cm = confusion_matrix(y_true, predicted)
        ax= fig.add_subplot(111)
        sns.heatmap(cm, annot=True, fmt='g', ax=ax, annot_kws={"size": 20})

        # labels, title and ticks
        ax.set_xlabel('Predicted labels', fontsize=20)
        ax.set_ylabel('True labels', fontsize=20)
        ax.set_title('Confusion Matrix', fontsize=20)
        ax.xaxis.set_ticklabels(['Tumor','Healthy'], fontsize=20)
        ax.yaxis.set_ticklabels(['Tumor','Healthy'], fontsize=20)

        super(MplCanvas, self).__init__(fig)

class ConfusionMatrixViewer(QMainWindow):

    def __init__(self, node, y_true, predicted):

        super().__init__()

        self.node = node
        #Trick to avoid window closing
        node.var = self

        #Create the layout
        container = QWidget()
        self.layout = QVBoxLayout(container)

        cm = MplCanvas(y_true, predicted)

        self.layout.addWidget(cm)
        self.setCentralWidget(container)

        self.setWindowTitle("Confusion Matrix viewer")

        self.show()


import asyncio
import logging

from google.protobuf.empty_pb2 import Empty
from grpc import ServicerContext

from proto.messages.meteo.meteo_messages_pb2 import RawMeteoData, RawPollutionData
from proto.services.processing import processing_service_pb2_grpc
from server.processing_service import ProcessingService

logger = logging.getLogger(__name__)

class ProcessingServiceServicer(processing_service_pb2_grpc.ProcessingServiceServicer):
    def __init__(self, processing_service: ProcessingService):
        logger.info("Initializing ProcessingServiceServicer")
        self._processing_service = processing_service
        self._background_tasks = set()

    async def ProcessMeteoData(self, meteo_data: RawMeteoData, context: ServicerContext) -> Empty:
        logger.info(f"{context.peer()} called ProcessMeteoData")
        task = asyncio.create_task(self._processing_service.process_meteo_data(meteo_data))
        self._background_tasks.add(task)
        task.add_done_callback(self._background_tasks.discard)
        return Empty()

    async def ProcessPollutionData(self, pollution_data: RawPollutionData, context: ServicerContext) -> Empty:
        logger.info(f"{context.peer()} called ProcessPollutionData")
        task = asyncio.create_task(self._processing_service.process_pollution_data(pollution_data))
        self._background_tasks.add(task)
        task.add_done_callback(self._background_tasks.discard)
        return Empty()


import os
import pymongo
# Grab the file that has the mongo URI data
if os.path.exists("env.py"):
    import env

# Create constants for URI login data / database / collection in database
MONGO_URI = os.environ.get("MONGO_URI")
DATABASE = "FirstCluster"
COLLECTION = "myFirstMDB"

# Connect to mongo
def mongo_connect(url):
    try:
        conn = pymongo.MongoClient(url)
        print("Mongo is connected")
        return conn
    except:
        print("Could not connect to MongoDB: %s") %e

# Run connect to mongo function
conn = mongo_connect(MONGO_URI)
# Add collection to a variable
coll = conn[DATABASE][COLLECTION]

# Create and insert a new doc to collection
#new_doc = {"first": "duglas", "last": "adams", "dob": "11/03/1952", "hair_colour": "grey", "occupation": "writer", "nationality": "british"}
#coll.insert(new_doc)

# Create and insert multiple new docs to collection
#new_docs = [{"first": "terry",
#             "last": "pratchett",
#             "dob": "28/04/1948",
#             "gender": "m",
#             "hair_colour": "not much",
#             "occupation": "writer",
#             "nationality": "british"},
#
#             {"first": "george",
#             "last": "rr martin",
#             "dob": "20/09/1948",
#             "gender": "m",
#             "hair_colour": "white",
#             "occupation": "writer",
#             "nationality": "american"}]
#coll.insert_many(new_docs)

# Show all documents in collection
#documents = coll.find()

# Find documents in collection
#documents = coll.find({"first": "duglas"})

# Remove document
#coll.remove({"first": "duglas"})

# Update single document
#coll.update_one({"nationality": "american"}, {"$set": {"hair_colour": "maroon"}})

# Update many documents
#coll.update_many({"nationality": "american"}, {"$set": {"hair_colour": "blue"}})

#documents = coll.find({"nationality": "american"})
for doc in documents:
    print(doc)