from tkinter import *
from tkinter import Tk, Label, Button
from tkinter import ttk
from tkinter import filedialog
import openpyxl
from tkinter import messagebox
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
import random
import math

class Kmeans():

    def dosyaSec(self):
        try:
            self.filename = filedialog.askopenfilename(initialdir="/", title="Select file",
                                                  filetypes=(("CSV field", "*.csv"), ("all files", "*.*")))
            if(self.filename!=""):
                self.listekutusu.insert(0,"Dosya Yolu : {}".format(self.filename))
                self.degerleri_oku(self.filename)
                k_max_deger = []
                for i in range (2,uzunluk+1):
                    k_max_deger.append(i)
                self.kdeger["values"] = k_max_deger
# okunan x ve y değerleri grafik üzerinde gösteriliyor
                plt.xlabel("x1")
                plt.ylabel("x2")
                bc2=plt.scatter(x_degerler,y_degerler)
                plt.grid(True)
                plt.show()
        except:
            messagebox.showerror("HATA","HATALI SECİM YAPTINIZ")

    def degerleri_oku(self,yol):
        global x_degerler
        global y_degerler
        global uzunluk
        dataset = pd.read_csv(self.filename)
        x_degerler = (dataset.iloc[:,0].values)
        y_degerler =(dataset.iloc[:,1].values)
        uzunluk = x_degerler.__len__()
        self.listekutusu.insert(END,"")
        self.listekutusu.insert(END,"""Gözlem  Degisken1 Degisken2 """)
        for i in range(0,uzunluk):
            self.listekutusu.insert(END,"X{:<10}{:^15}{:^25}".format(i+1,x_degerler[i],y_degerler[i]))

        self.kdeger.configure(state="readonly")

    def k_deger(self,event=None):

            self.cendroidx=[]
            self.cendroidy=[]
            self.renkler=["red","black","purple","navy","DARKGREEN","cyan","AQUAMARINE","AZURE","BISQUE","BISQUE","BISQUE","BLANCHEDALMOND","BLUE","BLUEVIOLET"]
            k_degeri =int(self.kdeger.get())
            self.x_degerler = x_degerler
            self.y_degerler = y_degerler
            self.listekutusu.insert(END,"")
            self.listekutusu.insert(END,"K degeri {} olarak belirlendi".format(self.kdeger.get()))
            self.listekutusu.insert(END,"")

# grafik üzerinde maximum  k sayısı kadar merkez oluşturmak için x ve y noktalarının aralığı belirleniyor
# belirlenen bu iki aralık arasında k sayısı kadar random olarak merzkez nokta oluşturulacak

            xmax = max(self.x_degerler)    #x değerlerinin maximumu
            ymax = max(self.y_degerler)    #y değerlerinin maximumu

            # k adet merkez oluşturuluyor
            i=0
            self.random_merkezler = {
                i+1: [np.random.randint(1,xmax) , np.random.randint(1,ymax)]
                for i in range(k_degeri)
            }
            print(self.random_merkezler[1])
            self.listekutusu.insert(END,"")
            self.listekutusu.insert(END,"Rastgele Oluşan Merkezler")
            for i in  self.random_merkezler:
                self.listekutusu.insert(END,"Cendroid{:<10} = {:^10}".format(i,str(self.random_merkezler[i])))
            self.listekutusu.insert(END,"")
            self.gozlemGrafik.configure(state="active")

            print(self.random_merkezler)
            for i in self.random_merkezler:
                self.cendroidx.append(self.random_merkezler[i][0])
                self.cendroidy.append(self.random_merkezler[i][1])

            ##### Merkez hesapla fonksiyonu kullanılarak rastgele oluşan merkezler değerlerin uzaklığı hesaplandı ve atamalar yapıldı sonuçta yeni üyelikler bulundu
            first_cluster_membership = self.merkez_hesapla(self.cendroidx,self.cendroidy)
            self.kontrol_kume=[]
            self.kontrol_kume.append(first_cluster_membership)
            self.first_cluster_membership = first_cluster_membership

            fig = plt.figure()
            plt.xlabel("x1")
            plt.ylabel("x2")
            bc2=plt.scatter(x_degerler,y_degerler)
            i=0
            for i in self.random_merkezler.keys():
                print(self.random_merkezler[i])
                plt.scatter(*self.random_merkezler[i], color=self.renkler[i-1], s=80)

            plt.grid(True)

            fig = plt.figure()
            ax = plt.axes()
            plt.xlabel("x1")
            plt.ylabel("x2")
            plt.scatter(x_degerler, y_degerler,s=20,c=first_cluster_membership)
            plt.scatter(self.cendroidx,self.cendroidy)

            for i in range(0,len(self.cendroidx)):
                cizgi_baslangicx=self.cendroidx[i]-0.5
                cizgi_baslangicy=self.cendroidy[i]-0.5
                ax.annotate(" ",xy=(self.cendroidx[i],self.cendroidy[i]),xytext=(cizgi_baslangicx,cizgi_baslangicy),
                arrowprops=dict(arrowstyle="->"))
                text="C{}".format(i+1)
                ax.text(self.cendroidx[i]+0.2,self.cendroidy[i]+0.2,text ,ha="center",fontsize=9)
                ax.set(title="Rastgele Oluşan Merkezlere Göre Dağılım")

            plt.grid(True)
            plt.show()

    def kmeans(self):

        self.kmeans_Hesapla(self.cendroidx,self.cendroidy,self.first_cluster_membership)

    def sonGrafGoster(self):

        self.grafgoster(self.centroit_degerlerix,self.centroit_degerleriy,self.kontrol_kume)

    def gozlemDegerGrafigi(self):

        fig, ax = plt.subplots()

        plt.xlabel("x1")
        plt.ylabel("x2")
        plt.scatter(x_degerler,y_degerler)

        plt.grid(True)
        ax.set(title="Gözlem Değerlerinin Grafik Üzerinde Dağılımı")
        plt.show()

    def __init__(self,pencere):

            self.pencere = pencere
            pencere.iconbitmap(r'data.ico')
            pencere.title(""" K MEANS ALGORİTHM                                                                                by KürşadKARAGÖZ""")
            pencere.configure(background='black')
            pencere.geometry("800x450+275+120")

            pencere.resizable(0,0)
            self.scrollbar = Scrollbar(pencere)
            self.listekutusu = Listbox(pencere , width = 127 , height = 25 ,background="black", fg="white",selectbackground="Red", yscrollcommand = self.scrollbar.set)
            self.listekutusu.place(x=10 , y = 40)
            self.scrollbar.pack(side=RIGHT , fill=Y)
            self.scrollbar.config(command=self.listekutusu.yview)

            self.dosyasecButton = Button(pencere,bg="red",font='arial 9 bold',fg="black", text = "Dosya Yolunu Belirleyiniz" ,width=21 , height = 1,command = self.dosyaSec)
            self.dosyasecButton.place(x=10,y=10)
            self.kdegerLabel = Label(pencere ,fg="black",text="K Degeri",bg="red",font='arial 9 bold')
            self.kdegerLabel.place(x=180,y=13)

            combostyle = ttk.Style()

            combostyle.theme_create('combostyle', parent='alt',
                             settings = {'TCombobox':
                                         {'configure':
                                          {'selectbackground': 'blue',
                                           'fieldbackground': 'red',
                                           'background': 'blue'
                                           }}}
                             )
    # ATTENTION: this applies the new style 'combostyle' to all ttk.Combobox
            combostyle.theme_use('combostyle')

            self.kdeger = ttk.Combobox(pencere, width=8 ,height=5, state="disabled" )
            self.kdeger.bind('<<ComboboxSelected>>',self.k_deger)
            self.kdeger.place(x=250,y=13)

            self.gozlemGrafik = Button(pencere,bg="red",font='arial 9 bold',fg="black",text= "Gözlem Değerleri Grafiği",width=25,height=1,state="disabled",command=self.gozlemDegerGrafigi)
            self.gozlemGrafik.place(x=330,y=10)

            self.cözümeBasla = Button(pencere,bg="red",font='arial 9 bold',fg="black",text="Çözüme Başla",width=15,height=1,command=self.kmeans)
            self.cözümeBasla.place(x=540,y=10)

            self.sonGraf = Button(pencere,text="Son Grafik",width=12,height=1,command=self.sonGrafGoster,bg="red",font='arial 9 bold',fg="black")
            self.sonGraf.place(x=680,y=10)

    def merkez_hesapla(self,centroit_degerlerix,centroit_degerleriy):

        kume_uyelikleri=[]
        min_index= 0
        m_uzaklik =[]
        m_uzakliklar=[]
        m_uzaklikdeger=0
        i=0
        y=0
        z=0
        print("cendroit değerleri x : {}".format(centroit_degerlerix))
        print("cendroit değerleri y : {}".format(centroit_degerleriy))
        for y in range(0,len(centroit_degerlerix)):
            for i in range(0,len(self.x_degerler)):
                self.x_degerler[i] = float(self.x_degerler[i])
                self.y_degerler[i] = float(self.y_degerler[i])
                m_uzaklikdeger=math.sqrt (pow((self.x_degerler[i])-(centroit_degerlerix[z]),2) +
                pow ((self.y_degerler[i])-(centroit_degerleriy[z]),2))
                m_uzaklik.append("{:.2f}".format(m_uzaklikdeger))
            m_uzakliklar.append(m_uzaklik)
            z +=1
            m_uzaklik = []

        self.listekutusu.insert(END,"")
        self.listekutusu.insert(END,"Merkezlerden olan uzaklıklar Hesaplandı")
        self.listekutusu.itemconfig(END,bg="black",fg="white")
        self.listekutusu.insert(END,"")
        self.listekutusu.insert(END,"""Gözlemler - Merkezlerden Uzaklıklar""")
        self.listekutusu.itemconfig(END,bg="black",fg="white")

        gecici_siralanacak_merkezler = []
        print(" Merkezden uzaklıklar: ")
        print(m_uzakliklar[0])
        print(m_uzakliklar[1])
       # print(m_uzakliklar[2])
        print("uzaklık taam")
        z=0
        i=0
        y=0
        for i in range(0,len(self.x_degerler)):
            for y in range(0,len(m_uzakliklar)):
                gecici_siralanacak_merkezler.append(float(m_uzakliklar[y][i]))

            min_index = gecici_siralanacak_merkezler.index(min(gecici_siralanacak_merkezler))
            min_index = min_index + 1
            del gecici_siralanacak_merkezler[:]
            kume_uyelikleri.append(min_index)

        print("Küme Üyeliği : {}".format(kume_uyelikleri))

        z=0
        renkler=["red","black","purple","navy","DARKGREEN","cyan","AQUAMARINE","AZURE","BISQUE","BISQUE","BISQUE","BLANCHEDALMOND","BLUE","BLUEVIOLET"]
        for y in range (0,len(centroit_degerlerix)):
            for i in range (0,len(self.x_degerler)):

                sonuc = "X{:<15}  d(M{:<1},X{:<1}) = {:^15}".format(i+1,z+1,i+1,m_uzakliklar[z][i])
                self.listekutusu.insert(END,sonuc)
                self.listekutusu.itemconfig(END,bg=renkler[z],fg="white")
                if z==14:
                    z=-1
            z +=1

        self.listekutusu.insert(END,"")
        self.listekutusu.insert(END,"Rastgele Atanan Merkezlere Göre Gözlem Değerlerinin Üyelikleri :")
        self.listekutusu.itemconfig(END,bg="purple",fg="white")
        self.listekutusu.insert(END,"")
        for i in range(0,len(kume_uyelikleri)):
            self.listekutusu.insert(END,"X{:<15} {:^15} {:^15} C{:<15}".format(i+1,self.x_degerler[i],self.y_degerler[i],kume_uyelikleri[i]))

        return kume_uyelikleri

    def kmeans_Hesapla(self,merkezx,merkezy,kumeler1):

        devamEt=True
        iterasyon = 1
        gozlem_uzunluk = len(self.x_degerler)

        while devamEt ==True:

            gecici=[]
            self.kume_gruplari = []   #aynı sınıflara ait elemanların sınıf indexleri
            self.kare_hatalari=[]
            self.centroit_degerlerix = []
            self.centroit_degerleriy = []

            self.listekutusu.insert(END,"")
            self.listekutusu.insert(END,"""
                                                                                Çözüm için {}. iterasyon Başladı
                                             """.format(iterasyon))
            self.listekutusu.itemconfig(END,bg="purple",fg="white")
            self.listekutusu.insert(END,"")
            self.listekutusu.insert(END,"a.) Centroit Değerleri (Küme Merkezleri) Hesaplandı")
            self.listekutusu.itemconfig(END,bg="black",fg="white")
            self.listekutusu.insert(END,"")

            # aynı sınıflara ait elemanlar belirlendi ve indeksleri bir diziye aktarıldı

            print("gözlem kümeleri . {}".format(kumeler1))
            for i in range(0,gozlem_uzunluk):
                for y in range(0,gozlem_uzunluk):
                    if (i==kumeler1[y]):
                        gecici.append(y)

                if len(gecici)!=0:
                    self.kume_gruplari.append(gecici)
                gecici=[]
            print("küme grupları : {}".format(self.kume_gruplari))

            uzunluk_y_z=0
            gecici = 0
            gecicix =0
            geciciy =0

            for i in range(0,len(self.kume_gruplari)):              #merkez sayısı
                uzunluk_y_z =self.kume_gruplari[i].__len__()
                for y in range(0,uzunluk_y_z):      #merkez içindeki  i'nci dizi eleman sayısı
                    gecici = self.kume_gruplari[i][y]
                    gecicix = gecicix + self.x_degerler[gecici]
                    geciciy = geciciy + self.y_degerler[gecici]
                #print("{}'nci küme bitti".format(i))
                self.centroit_degerlerix.append("{:.2f}".format(gecicix/uzunluk_y_z))
                self.centroit_degerleriy.append("{:.2f}".format(geciciy/uzunluk_y_z))
                gecicix=0
                geciciy=0

            i=0
            # sonuçlar yazdırılıyor.
            for i in range(0,self.centroit_degerlerix.__len__()):
                sonuc="Centroit M{0} = [{1},{2}]".format(i+1,self.centroit_degerlerix[i],self.centroit_degerleriy[i])
                self.listekutusu.insert(END,sonuc)
            print("{}. iterasyon Cendroid Degerlerix : {}".format(iterasyon,self.centroit_degerlerix))
            print("{}.iterasyon Cendroid Degerleriy : {}".format(iterasyon,self.centroit_degerleriy))
            print("{}. iterasyon Küme Üyelikleri : {}".format(iterasyon,kumeler1))

            #Cendroidlerin objeler olan uzaklıkları (Küme içi Değişmeler) Hesaplanıyor
            self.listekutusu.insert(END,"")
            self.listekutusu.insert(END,"b.) Toplam Kare Hata Hesaplandı")
            self.listekutusu.itemconfig(END,bg="black",fg="white")
            self.listekutusu.insert(END,"")

            uzunluk_y_z=0
            gecici = 0
            gecicix =0
            geciciy =0
            toplam =0.0
            toplam2=0.0
            dizi1 =[]
            dizi2 =[]
            dizi1x=[]
            dizi2x=[]
            kare_hata1 = 0
            kare_hata2 = 0
            kare_hata = 0
            for i in range(0,len(self.kume_gruplari)):              #merkez sayısı
                uzunluk_y_z =self.kume_gruplari[i].__len__()
                for y in range(0,uzunluk_y_z):      #merkez içindeki  i'nci dizi eleman sayısı
                    gecici = self.kume_gruplari[i][y]
                    gecicix =self.x_degerler[gecici]
                    geciciy = self.y_degerler[gecici]
                    dizi1.append(gecicix)
                    dizi2.append(geciciy)
                dizi1x.append(dizi1)
                dizi2x.append(dizi2)
                #self.kare_hatalari.append(toplam)
                #self.kare_hatalari.append(toplam2)
                dizi1=[]
                dizi2=[]
                gecicix=0
                geciciy=0
            #print(self.kare_hatalari)

            for i in range (0,len(self.centroit_degerlerix)):
                self.centroit_degerlerix[i] = float(self.centroit_degerlerix[i])
                self.centroit_degerleriy[i] = float(self.centroit_degerleriy[i])

            e1 = 0.0
            kare_hatalar=[]
            z=0
            for i in range (0,len(dizi1x)):
                for y in range (0,len(dizi2x[i])):
                    e1 = e1 + float(pow((float(dizi1x[i][y]) - self.centroit_degerlerix[z]),2) + pow((float(dizi2x[i][y]) - self.centroit_degerleriy[z]),2))
                z=z+1
                kare_hatalar.append("{:.2f}".format(e1))
                e1= 0.0
            print("{}. iterasyon Kare Hatalar : {}".format(iterasyon,kare_hatalar))
            i=0
            toplam_karehata = 0
            for i in range (0,len(kare_hatalar)):
                toplam_karehata += float(kare_hatalar[i])
            for i in range (0,len(kare_hatalar)):
                self.listekutusu.insert(END,"e{} kare = {}".format(i+1,kare_hatalar[i]))
            self.listekutusu.insert(END,"E (Toplam Kare Hata) = {}".format(toplam_karehata))
            self.listekutusu.itemconfig(END,bg="blue",fg="black")
            print("{}. iterasyon toplam Kare Hata : {}".format(iterasyon,toplam_karehata))

            # Uzaklıklar hesaplanıyor , Minimum uzaklığa göre gruplamalar yapılıyor
                # uzaklıkların hesaplanmasında yararlanılan öklid uzaklık formuludür
            m_uzaklik =[]
            self.m_uzakliklar=[]
            m_uzaklikdeger=0

            z=0
            for y in range(0,len(self.centroit_degerlerix)):
                for i in range(0,len(self.x_degerler)):
                    self.x_degerler[i] = float(self.x_degerler[i])
                    self.y_degerler[i] = float(self.y_degerler[i])
                    m_uzaklikdeger=math.sqrt (pow((self.x_degerler[i])-(self.centroit_degerlerix[z]),2) +
                    pow ((self.y_degerler[i])-(self.centroit_degerleriy[z]),2))
                    m_uzaklik.append("{:.2f}".format(m_uzaklikdeger))
                self.m_uzakliklar.append(m_uzaklik)
                z +=1
                m_uzaklik = []
            print("{}. iterasyon Merkezden Uzaklıklar : {}".format(iterasyon,self.m_uzakliklar))

            self.listekutusu.insert(END,"")
            self.listekutusu.insert(END,"c. Merkezlerden olan uzaklıklar Hesaplandı")
            self.listekutusu.itemconfig(END,bg="black",fg="white")
            self.listekutusu.insert(END,"")
            self.listekutusu.insert(END,"""Gözlemler Merkezlerden Uzaklıklar""")
            self.listekutusu.itemconfig(END,bg="black",fg="white")

            son_kume_uyelikleri=[]
            min_index=0
            gecici_siralanacak_merkezler=[]

            for i in range(0,len(self.x_degerler)):
                for y in range(0,len(self.m_uzakliklar)):
                    gecici_siralanacak_merkezler.append(float(self.m_uzakliklar[y][i]))

                min_index = gecici_siralanacak_merkezler.index(min(gecici_siralanacak_merkezler))
                min_index = min_index + 1
                del gecici_siralanacak_merkezler[:]
                son_kume_uyelikleri.append(min_index)

            self.son_kume_uyelikleri = son_kume_uyelikleri
            print("{} . iterasyon Küme Üyeliği : {}".format(iterasyon,son_kume_uyelikleri))

            z=0
            renkler=["red","blue","gray","purple","aliceblue","ANTIQUEWHITE","AQUA","AQUAMARINE","AZURE","BISQUE","BISQUE","BISQUE","BLANCHEDALMOND","BLUE","BLUEVIOLET"]
            for y in range (0,len(self.centroit_degerlerix)):
                for i in range (0,len(self.x_degerler)):

                    sonuc = "X{:<15}  d(M{:<1},X{:<1}) = {:^15}".format(i+1,z+1,i+1,self.m_uzakliklar[z][i])
                    self.listekutusu.insert(END,sonuc)
                    self.listekutusu.itemconfig(END,bg=renkler[z],fg="white")
                    if z==14:
                        z=-1
                z +=1

            i=0
            self.listekutusu.insert(END,"")
            self.listekutusu.insert(END,"{}. iterasyon sonucu oluşan küme üyelikleri :".format(iterasyon))
            self.listekutusu.itemconfig(END,bg="purple",fg="white")
            self.listekutusu.insert(END,"")
            for i in range(0,len(self.son_kume_uyelikleri)):
                self.listekutusu.insert(END,"X{:<15} {:^15} {:^15} C{:<15}".format(i+1,self.x_degerler[i],self.y_degerler[i],self.son_kume_uyelikleri[i]))

            print("{}. iterasyon son ".format(iterasyon))
            print(self.son_kume_uyelikleri)

            if(self.son_kume_uyelikleri == kumeler1):
                    devamEt=False
                    self.listekutusu.insert(END,"")
                    self.listekutusu.insert(END,"Bu Durumda Son Kümeler: ")
                    self.listekutusu.itemconfig(END,bg="purple",fg="white")
                    self.listekutusu.insert(END,"")

                    sonuc=""
                    print(self.kume_gruplari)

                    for i in range(0,len(self.kume_gruplari)):
                        for y in range(0,len(self.kume_gruplari[i])):
                            sonuc =sonuc + """, X{}""".format(self.kume_gruplari[i][y]+1)
                        sonuc=sonuc[1:len(sonuc)]
                        self.listekutusu.insert(END,"C{0} = {1}".format(i+1,sonuc))
                        sonuc=""
                    self.kontrol_kume = self.son_kume_uyelikleri
                    self.listekutusu.insert(END,"")
                    self.listekutusu.insert(END,"En Son Oluşan Merkezler :")
                    self.listekutusu.itemconfig(END,bg="black",fg="white")
                    self.listekutusu.insert(END,"")
                    i=0
                    for i in range(0,self.centroit_degerlerix.__len__()):
                        sonuc="Centroit M{0} = [{1},{2}]".format(i+1,self.centroit_degerlerix[i],self.centroit_degerleriy[i])
                        self.listekutusu.insert(END,sonuc)

                    self.listekutusu.insert(END,"")
                    self.listekutusu.insert(END,"""
                                                                                {}. İterasyon'da Sonuca ulaşıldı
                                """.format(iterasyon))
                    self.listekutusu.itemconfig(END,bg="purple",fg="white")
                    self.listekutusu.insert(END,"")

            else:
                print("devam ediyor")
                print(self.kontrol_kume)
                print("devam ediyor")
                self.kontrol_kume = self.son_kume_uyelikleri
                kumeler1 = self.son_kume_uyelikleri
                devamEt=True
                self.listekutusu.insert(END,"")
                self.listekutusu.insert(END,"""
                                                                                {}. İterasyon Tamamlandı, Devam Ediyor
                        """.format(iterasyon))
                self.listekutusu.itemconfig(END,bg="purple",fg="white")

            iterasyon +=1

    def grafgoster(self,centroitx=[],centroity=[],uyelikler=[]):

        ax = plt.axes()
        print("GRAFF GOSTER")
        print(centroitx)
        print(centroity)
        print(uyelikler)
        print("tm")
        plt.xlabel("x1")
        plt.ylabel("x2")
        plt.scatter(x_degerler, y_degerler,s=20,c=uyelikler)
        plt.scatter(centroitx,centroity)
        gecici = [x for i, x in enumerate(uyelikler) if i ==uyelikler.index(x)]

        print(gecici)
        print(len(gecici))
        print("tm")
        if(gecici[0] !=1):
            gecici.reverse()
        i=0
        print(centroitx)
        for i in range(0,len(centroitx)):
            print(i)
            cizgi_baslangicx=centroitx[i]-0.5
            cizgi_baslangicy=centroity[i]-0.5
            ax.annotate(" ",xy=(centroitx[i],centroity[i]),xytext=(cizgi_baslangicx,cizgi_baslangicy),
            arrowprops=dict(arrowstyle="->"))
            text="C{}".format(i+1)
            ax.text(centroitx[i]+0.2,centroity[i]+0.2,text ,ha="center",fontsize=9)
            ax.set(title="K-Means Algoritması Sonucu Oluşan Grafik")

        plt.grid(True)
        plt.show()

pencere = Tk()
basla = Kmeans(pencere)
pencere.colormapwindows()

pencere.mainloop()


from selenium import webdriver
from selenium.webdriver.common.by import By
options = webdriver.FirefoxOptions()
options.add_argument('--headless')
import time

class jay:

    driver = webdriver.Firefox()

    def __init__(self,url):
        self.url = url

    def by_anchor_tag(self,anchor_tag_link):
        try:
            driver = webdriver.Firefox(firefox_options=options)
            self.driver.get(self.url)
            anchor_tag_link = self.driver.find_element(by = By.LINK_TEXT , value = anchor_tag_link)
            time.sleep(7)
            anchor_tag_link.click()

        except:
            print("anchor tag not found !")

url_1 = "https://www.w3schools.com"

s = jay(url_1)

s.by_anchor_tag("HTML Reference")


from datetime import datetime

def getBasicInfo():
    choice = input("""\t1. Add new income
    2. Add new expense
    3. Check current balance (income - expenses)
    4. Check specific month's balance
    5. Check specific month's income data
    6. Check specific month's expenses data
    7. Check total income by category
    8. Check total expenses by category
    9. Exit the program
    Choose an option (int): """)
    return choice

def addNewIncome():
    is_correct = True
    info = "New income was not added due to:"
    arr = []
    month_id = None
    amount = None

    name = str(input("Enter income name [str]: "))
    try:
        amount = int(input("Enter income amount [int]: "))
    except ValueError:
        info += "\nIncorrect datatype for amount."
        is_correct = False
    category = str(input("Enter income category [str]: "))
    datetime_str = str(input("Enter date & time of income (YYYY-MM-DD HH:MM:SS) or leave blank to add current date % "
                             "time [str]: "))
    if datetime_str == "":
        datetime_str = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
    if checkIfDateTimeIsValid(datetime_str):
        month_id = int(datetime_str[5:7])
    else:
        info += "\nIncorrect pattern for datetime field."
        is_correct = False

    arr.append(name)
    arr.append(amount)
    arr.append(category)
    arr.append(datetime_str)
    arr.append(month_id)
    arr.append(is_correct)
    arr.append(info)
    return arr

def addNewExpense():
    arr = addNewIncome()
    note = str(input("Enter note (optional) [str]: "))
    arr.insert(5, note)

    return arr

def getMonth(month):
    months = {"January": 1, "February": 2, "March": 3, "April": 4, "May": 5, "June": 6,
              "July": 7, "August": 8, "September": 9, "October": 10, "November": 11, "December": 12}

    if isinstance(month, int):
        for name, month_id in months.items():
            if month_id == month:
                return name

    elif isinstance(month, str):
        month_id = months.get(month)
        return month_id

def checkForMonth(month):
    month_id = None

    if len(month) > 2:
        if getMonth(month.capitalize()) is not None:
            month_id = getMonth(month.capitalize())
        else:
            print("Incorrect month name input.")
    elif 2 >= len(month) > 0 and 1 <= int(month) <= 12:
        month_id = month
    else:
        print("Month with this ID does not exist.")

    return month_id

def checkIfDateTimeIsValid(datetime_str):
    try:
        datetime.strptime(datetime_str, '%Y-%m-%d %H:%M:%S')
        return True
    except ValueError:
        return False


# IMPORTS #
import os
import requests
from bs4 import BeautifulSoup as bs

# SET VARIABLES #
url = "https://unsplash.com/search/photos/puppet"
page = requests.get(url)
soup = bs(page.text, 'html.parser')
image_tags = soup.find_all('img')
i = 0

# CREATE DIRECTORY TO STORE IMAGES #

if not os.path.exists('puppet'):
    os.makedirs('puppet')

# CHANGE TO CREATED DIRECTORY
os.chdir('puppet')

# DOWNLOAD 50 IMAGES INTO FOLDER #
for image in image_tags:
    try:
        url = image['src']
        source = requests.get(url)
        if source.status_code == 200 and i < 50:
            with open('puppet_' +str(i) + '.jpg', 'wb') as f:
                f.write(requests.get(url).content)
                f.close()
                i += 1
    except:
        pass


#!/usr/bin/env python3

import pygame as pg
import colors as col
import solar_vis as vis
import solar_model as physics
import solar_input as file_io

def main():
    pg.init()

    screen = pg.display.set_mode((vis.window_width, vis.window_height))
    GUI_manager = vis.InterfaceManager(screen)
    model = physics.Model([])

    clock = pg.time.Clock()
    quit_flag = False

    while not quit_flag:
        time_delta = clock.tick(60) / 1000.0
        if GUI_manager.is_running:
            model.update(time_delta * GUI_manager.get_speed())

        screen.fill(col.black)
        GUI_manager.update(time_delta, model.time)
        for event in pg.event.get():
            GUI_manager.process_event(event)
            if event.type == pg.QUIT:
                quit_flag = True
            elif event.type == vis.LOADEVENT:
                model = physics.Model(file_io.load_from_file(event.file))
            elif event.type == vis.SAVEEVENT:
                file_io.save_to_file(model.objects, event.file)

        vis.draw_objects(model.objects, model.scale_factor, screen)
        pg.display.update()

if __name__ == "__main__":
    main()


from django.urls import path, include
# Импортируем созданное нами представление
from .views import PostList,PostDetail,PostCreate,PostUpdate,PostDelete,subscribe_me,PostCount, upgrade_me, notsubscribe_me, TTT
from django.views.decorators.cache import cache_page

urlpatterns = [
    path('', cache_page(60)(PostList.as_view()), name='post_list'),
    path('<int:pk>', PostDetail.as_view(), name='post_detail'),
    path('news/create/', PostCreate.as_view(), name='news_create'),
    path('news/<int:pk>/edit/', PostUpdate.as_view(), name='news_edit'),
    path('news/<int:pk>/delete/', PostDelete.as_view(), name='news_delete'),
    path('articles/create/', PostCreate.as_view(), name='post_create'),
    path('articles/<int:pk>/edit/', PostUpdate.as_view(), name='post_edit'),
    path('articles/<int:pk>/delete/', PostDelete.as_view(), name='post_delete'),
    path('subscribe/', subscribe_me, name='subscribe'),
    path('notsubscribe/', notsubscribe_me, name='notsubscribe'),
    path('post_count/', PostCount.as_view(), name='post_count'),
    path('upgrade/', upgrade_me, name='upgrade'),
    path('hello', TTT.as_view(), name='index_ttt'),
    path('i18n/', include('django.conf.urls.i18n'))
    ]


from typing import Optional, Tuple, List, Union

from ovos_bus_client.client import MessageBusClient
from ovos_plugin_common_play.ocp import OCP_ID
from ovos_plugin_common_play.ocp.status import *
from ovos_plugin_common_play.ocp.utils import ocp_plugins, find_mime
from ovos_utils.json_helper import merge_dict
from ovos_utils.log import LOG
from ovos_utils.messagebus import Message
from os.path import join, dirname
from dbus_next.service import Variant

# TODO subclass from dict (?)
class MediaEntry:
    def __init__(self, title="", uri="", skill_id=OCP_ID,
                 image=None, match_confidence=0,
                 playback=PlaybackType.UNDEFINED,
                 status=TrackState.DISAMBIGUATION, phrase=None,
                 position=0, length=None, bg_image=None, skill_icon=None,
                 artist=None, is_cps=False, cps_data=None, javascript="",
                 **kwargs):
        self.match_confidence = match_confidence
        self.title = title
        uri = uri or ""  # handle None
        self.uri = f'file://{uri}' if uri.startswith('/') else uri
        self.artist = artist
        self.skill_id = skill_id
        self.status = status
        self.playback = PlaybackType(playback) if isinstance(playback, int) \
            else playback
        self.image = image or join(dirname(__file__),
                                   "res/ui/images/ocp_bg.png")
        self.position = position
        self.phrase = phrase
        self.length = length  # None -> live stream
        self.skill_icon = skill_icon or join(dirname(__file__),
                                             "res/ui/images/ocp.png")
        self.bg_image = bg_image or join(dirname(__file__),
                                         "res/ui/images/ocp_bg.png")
        self.is_cps = is_cps
        self.data = kwargs
        self.cps_data = cps_data or {}
        self.javascript = javascript  # custom code to run in Webview after page load

    def update(self, entry: dict, skipkeys: list = None, newonly: bool = False):
        """
        Update this MediaEntry object with keys from the provided entry
        @param entry: dict or MediaEntry object to update this object with
        @param skipkeys: list of keys to not change
        @param newonly: if True, only adds new keys; existing keys are unchanged
        """
        skipkeys = skipkeys or []
        if isinstance(entry, MediaEntry):
            entry = entry.as_dict
        entry = entry or {}
        for k, v in entry.items():
            if k not in skipkeys and hasattr(self, k):
                if newonly and self.__getattribute__(k):
                    # skip, do not replace existing values
                    continue
                self.__setattr__(k, v)

    @staticmethod
    def from_dict(data: dict):
        """
        Construct a `MediaEntry` object from dict data.
        @param data: dict information to build the `MediaEntry` for
        @return: MediaEntry object
        """
        if data.get("bg_image") and data["bg_image"].startswith("/"):
            data["bg_image"] = "file:/" + data["bg_image"]
        data["skill"] = data.get("skill_id") or OCP_ID
        data["position"] = data.get("position", 0)
        data["length"] = data.get("length") or \
                         data.get("track_length") or \
                         data.get("duration")  # or get_duration_from_url(url)
        data["skill_icon"] = data.get("skill_icon") or data.get("skill_logo")
        data["status"] = data.get("status") or TrackState.DISAMBIGUATION
        data["playback"] = data.get("playback", PlaybackType.UNDEFINED)
        data["uri"] = data.get("stream") or data.get("uri") or data.get("url")
        data["title"] = data.get("title") or data["uri"]
        data["artist"] = data.get("artist") or data.get("author")
        data["is_cps"] = data.get("is_old_style") or data.get("is_cps", False)
        data["cps_data"] = data.get("cps_data") or {}
        return MediaEntry(**data)

    @property
    def info(self) -> dict:
        """
        Return a dict representation of this MediaEntry + infocard for QML model
        """
        return merge_dict(self.as_dict, self.infocard)

    @property
    def infocard(self) -> dict:
        """
        Return dict data used for a UI display
        """
        return {
            "duration": self.length,
            "track": self.title,
            "image": self.image,
            "album": self.skill_id,
            "source": self.skill_icon,
            "uri": self.uri
        }

    @property
    def mpris_metadata(self) -> dict:
        """
        Return dict data used by MPRIS
        """
        meta = {"xesam:url": Variant('s', self.uri)}
        if self.artist:
            meta['xesam:artist'] = Variant('as', [self.artist])
        if self.title:
            meta['xesam:title'] = Variant('s', self.title)
        if self.image:
            meta['mpris:artUrl'] = Variant('s', self.image)
        if self.length:
            meta['mpris:length'] = Variant('d', self.length)
        return meta

    @property
    def as_dict(self) -> dict:
        """
        Return a dict reporesentation of this MediaEntry
        """
        return {k: v for k, v in self.__dict__.items()
                if not k.startswith("_")}

    @property
    def mimetype(self) -> Optional[Tuple[Optional[str], Optional[str]]]:
        """
        Get the detected mimetype tuple (type, encoding) if it can be determined
        """
        if self.uri:
            return find_mime(self.uri)

    def __eq__(self, other):
        if isinstance(other, MediaEntry):
            other = other.infocard
        # dict compatison
        return other == self.infocard

    def __repr__(self):
        return str(self.as_dict)

    def __str__(self):
        return str(self.as_dict)

class Playlist(list):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self._position = 0

    @property
    def position(self) -> int:
        """
        Return the current position in the playlist
        """
        return self._position

    @property
    def entries(self) -> List[MediaEntry]:
        """
        Return a list of MediaEntry objects in the playlist
        """
        entries = []
        for e in self:
            if isinstance(e, dict):
                e = MediaEntry.from_dict(e)
            if isinstance(e, MediaEntry):
                entries.append(e)
        return entries

    @property
    def current_track(self) -> Optional[MediaEntry]:
        """
        Return the current MediaEntry or None if the playlist is empty
        """
        if len(self) == 0:
            return None
        self._validate_position()
        track = self[self.position]
        if isinstance(track, dict):
            track = MediaEntry.from_dict(track)
        return track

    @property
    def is_first_track(self) -> bool:
        """
        Return `True` if the current position is the first track or if the
        playlist is empty
        """
        if len(self) == 0:
            return True
        return self.position == 0

    @property
    def is_last_track(self) -> bool:
        """
        Return `True` if the current position is the last track of if the
        playlist is empty
        """
        if len(self) == 0:
            return True
        return self.position == len(self) - 1

    def goto_start(self) -> None:
        """
        Move to the first entry in the playlist
        """
        self._position = 0

    def clear(self) -> None:
        """
        Remove all entries from the Playlist and reset the position
        """
        super(Playlist, self).clear()
        self._position = 0

    def sort_by_conf(self):
        """
        Sort the Playlist by `match_confidence` with high confidence first
        """
        self.sort(key=lambda k: k.match_confidence
                  if isinstance(k, MediaEntry) else
                  k.get("match_confidence", 0), reverse=True)

    def add_entry(self, entry: MediaEntry, index: int = -1) -> None:
        """
        Add an entry at the requested index
        @param entry: MediaEntry to add to playlist
        @param index: index to insert entry at (default -1 to append)
        """
        assert isinstance(index, int)
        # TODO: Handle index out of range
        if isinstance(entry, dict):
            entry = MediaEntry.from_dict(entry)
        assert isinstance(entry, MediaEntry)
        if index == -1:
            index = len(self)

        if index < self.position:
            self.set_position(self.position + 1)

        self.insert(index, entry)

    def remove_entry(self, entry: Union[int, dict, MediaEntry]) -> None:
        """
        Remove the requested entry from the playlist or raise a ValueError
        @param entry: index or MediaEntry to remove from the playlist
        """
        if isinstance(entry, int):
            self.pop(entry)
            return
        if isinstance(entry, dict):
            entry = MediaEntry.from_dict(entry)
        assert isinstance(entry, MediaEntry)
        for idx, e in self.entries:
            if e == entry:
                self.pop(idx)
                break
        else:
            raise ValueError(f"entry not in playlist: {entry}")

    def replace(self, new_list: List[Union[dict, MediaEntry]]) -> None:
        """
        Replace the contents of this Playlist with new_list
        @param new_list: list of MediaEntry or dict objects to set this list to
        """
        self.clear()
        for e in new_list:
            self.add_entry(e)

    def set_position(self, idx: int):
        """
        Set the position in the playlist to a specific index
        @param idx: Index to set position to
        """
        self._position = idx
        self._validate_position()

    def goto_track(self, track: Union[MediaEntry, dict]) -> None:
        """
        Go to the requested track in the playlist
        @param track: MediaEntry to find and go to in the playlist
        """
        if isinstance(track, MediaEntry):
            requested_uri = track.uri
        else:
            requested_uri = track.get("uri", "")
        for idx, t in enumerate(self):
            if isinstance(t, MediaEntry):
                pl_entry_uri = t.uri
            else:
                pl_entry_uri = t.get("uri", "")
            if requested_uri == pl_entry_uri:
                self.set_position(idx)
                LOG.debug(f"New playlist position: {self.position}")
                return
        LOG.error(f"requested track not in the playlist: {track}")

    def next_track(self) -> None:
        """
        Go to the next track in the playlist
        """
        self.set_position(self.position + 1)

    def prev_track(self) -> None:
        """
        Go to the previous track in the playlist
        """
        self.set_position(self.position - 1)

    def _validate_position(self) -> None:
        """
        Make sure the current position is valid; default `position` to 0
        """
        if self.position < 0 or self.position >= len(self):
            LOG.error(f"Playlist pointer is in an invalid position "
                      f"({self.position}! Going to start of playlist")
            self._position = 0

    def __contains__(self, item):
        if isinstance(item, dict):
            item = MediaEntry.from_dict(item)
        if not isinstance(item, MediaEntry):
            return False
        for e in self.entries:
            if not e.uri and e.data.get("playlist"):
                if e.title == item.title and not item.uri:
                    return True
                # track in playlist
                for t in e.data["playlist"]:
                    if t.get("uri") == item.uri:
                        return True
            elif e.uri == item.uri:
                return True
        return False

class NowPlaying(MediaEntry):
    def __init__(self, *args, **kwargs):
        MediaEntry.__init__(self, *args, **kwargs)
        self._player = None

    @property
    def bus(self) -> MessageBusClient:
        """
        Return the MessageBusClient inherited from the bound OCPMediaPlayer
        """
        return self._player.bus

    @property
    def _settings(self) -> dict:
        """
        Return the dict settings inherited from the bound OCPMediaPlayer
        """
        return self._player.settings

    def as_entry(self) -> MediaEntry:
        """
        Return a MediaEntry representation of this object
        """
        return MediaEntry.from_dict(self.as_dict)

    def bind(self, player):
        """
        Bind an OCPMediaPlayer object to this NowPlaying instance. Registers
        messagebus event handlers and defines `self._player`
        @param player: OCPMediaPlayer instance to bind
        """
        # needs to start with _ to avoid json serialization errors
        self._player = player
        self._player.add_event("ovos.common_play.track.state",
                               self.handle_track_state_change)
        self._player.add_event("ovos.common_play.media.state",
                               self.handle_media_state_change)
        self._player.add_event("ovos.common_play.play",
                               self.handle_external_play)
        self._player.add_event("ovos.common_play.playback_time",
                               self.handle_sync_seekbar)
        self._player.add_event('gui.player.media.service.get.meta',
                               self.handle_player_metadata_request)
        self._player.add_event('mycroft.audio.service.track_info_reply',
                               self.handle_sync_trackinfo)
        self._player.add_event('mycroft.audio.service.play',
                               self.handle_audio_service_play)
        self._player.add_event('mycroft.audio.playing_track',
                               self.handle_audio_service_play_start)

    def shutdown(self):
        """
        Remove NowPlaying events from the MessageBusClient
        """
        self._player.remove_event("ovos.common_play.track.state")
        self._player.remove_event("ovos.common_play.playback_time")
        self._player.remove_event('gui.player.media.service.get.meta')
        self._player.remove_event('mycroft.audio_only.service.track_info_reply')

    def reset(self):
        """
        Reset the NowPlaying MediaEntry to default parameters
        """
        LOG.debug("Resetting NowPlaying")
        self.title = ""
        self.artist = None
        self.skill_icon = None
        self.skill_id = None
        self.position = 0
        self.length = None
        self.is_cps = False
        self.cps_data = {}
        self.data = {}
        self.phrase = None
        self.javascript = ""
        self.playback = PlaybackType.UNDEFINED
        self.status = TrackState.DISAMBIGUATION

    def update(self, entry: dict, skipkeys: list = None, newonly: bool = False):
        """
        Update this MediaEntry and emit `gui.player.media.service.set.meta`
        @param entry: dict or MediaEntry object to update this object with
        @param skipkeys: list of keys to not change
        @param newonly: if True, only adds new keys; existing keys are unchanged
        """
        if isinstance(entry, MediaEntry):
            entry = entry.as_dict
        super().update(entry, skipkeys, newonly)
        # uri updates should not be skipped
        if newonly and entry.get("uri"):
            super().update({"uri": entry["uri"]})
        # sync with gui media player on track change
        if not self._player:
            LOG.error("Instance not bound! Call `bind` before trying to use "
                      "the messagebus.")
            return
        self.bus.emit(Message("gui.player.media.service.set.meta",
                              {"title": self.title,
                               "image": self.image,
                               "artist": self.artist}))

    def extract_stream(self):
        """
        Get metadata from ocp_plugins and add it to this MediaEntry
        """
        uri = self.uri
        if not uri:
            raise ValueError("No URI to extract stream from")
        if self.playback == PlaybackType.VIDEO:
            video = True
        else:
            video = False
        meta = ocp_plugins.extract_stream(uri, video)
        # update media entry with new data
        if meta:
            LOG.info(f"OCP plugins metadata: {meta}")
            self.update(meta, newonly=True)
        elif not any((uri.startswith(s) for s in ["http", "file", "/"])):
            LOG.info(f"OCP WARNING: plugins returned no metadata for uri {uri}")

    # events from gui_player/audio_service
    def handle_external_play(self, message):
        """
        Handle 'ovos.common_play.play' Messages. Update the metadata with new
        data received unconditionally, otherwise previous song keys might
        bleed into the new track
        @param message: Message associated with request
        """
        if message.data.get("tracks"):
            # backwards compat / old style
            playlist = message.data["tracks"]
            media = playlist[0]
        else:
            media = message.data.get("media", {})
        if media:
            self.update(media, newonly=False)

    def handle_player_metadata_request(self, message):
        """
        Handle 'gui.player.media.service.get.meta' Messages. Emit a response for
        the GUI to handle new metadata.
        @param message: Message associated with request
        """
        self.bus.emit(message.reply("gui.player.media.service.set.meta",
                                    {"title": self.title,
                                     "image": self.image,
                                     "artist": self.artist}))

    def handle_track_state_change(self, message):
        """
        Handle 'ovos.common_play.track.state' Messages. Update status
        @param message: Message with updated `state` data
        @return:
        """
        state = message.data.get("state")
        if state is None:
            raise ValueError(f"Got state update message with no state: "
                             f"{message}")
        if isinstance(state, int):
            state = TrackState(state)
        if not isinstance(state, TrackState):
            raise ValueError(f"Expected int or TrackState, but got: {state}")

        if state == self.status:
            return
        self.status = state
        LOG.info(f"TrackState changed: {repr(state)}")

        if state == TrackState.PLAYING_SKILL:
            # skill is handling playback internally
            pass
        elif state == TrackState.PLAYING_AUDIOSERVICE:
            # audio service is handling playback
            pass
        elif state == TrackState.PLAYING_VIDEO:
            # ovos common play is handling playback in GUI
            pass
        elif state == TrackState.PLAYING_AUDIO:
            # ovos common play is handling playback in GUI
            pass

        elif state == TrackState.DISAMBIGUATION:
            # alternative results # TODO its this 1 track or a list ?
            pass
        elif state in [TrackState.QUEUED_SKILL,
                        TrackState.QUEUED_VIDEO,
                        TrackState.QUEUED_AUDIOSERVICE]:
            # audio service is handling playback and this is in playlist
            pass

    def handle_media_state_change(self, message):
        """
        Handle 'ovos.common_play.media.state' Messages. If ended, reset.
        @param message: Message with updated MediaState
        """
        state = message.data.get("state")
        if state is None:
            raise ValueError(f"Got state update message with no state: "
                             f"{message}")
        if isinstance(state, int):
            state = MediaState(state)
        if not isinstance(state, MediaState):
            raise ValueError(f"Expected int or TrackState, but got: {state}")
        # Don't do anything. Let OCP manage this object's state
        # if state == MediaState.END_OF_MEDIA:
        #     # playback ended, allow next track to change metadata again
        #     self.reset()

    def handle_sync_seekbar(self, message):
        """
        Handle 'ovos.common_play.playback_time' Messages sent by audio backend
        @param message: Message with 'length' and 'position' data
        """
        self.length = message.data["length"]
        self.position = message.data["position"]

    def handle_sync_trackinfo(self, message):
        """
        Handle 'mycroft.audio.service.track_info_reply' Messages with current
        media defined in message.data
        @param message: Message with dict MediaEntry data
        """
        self.update(message.data)

    def handle_audio_service_play(self, message):
        """
        Handle 'mycroft.audio.service.play' Messages with list of tracks in data
        @param message: Message with 'tracks' data
        """
        tracks = message.data.get("tracks") or []
        # only present in ovos-core
        skill_id = message.context.get("skill_id") or 'mycroft.audio_interface'
        for idx, track in enumerate(tracks):
            # TODO try to extract metadata from uri (latency ?)
            if idx == 0:
                self.update(
                    {"uri": track,
                     "title": track.split("/")[-1],
                     "status": TrackState.QUEUED_AUDIOSERVICE,
                     'skill_id': skill_id,
                     "playback": PlaybackType.AUDIO_SERVICE}
                )
            else:
                # TODO sync playlist ?
                pass

    def handle_audio_service_play_start(self, message):
        """
        Handle 'mycroft.audio.playing_track' Messages
        @param message: Message notifying playback has started
        """
        self.update(
            {"status": TrackState.PLAYING_AUDIOSERVICE,
             "playback": PlaybackType.AUDIO_SERVICE})


from typing import List
from collections import deque, defaultdict

n = 0
mmap = []
dx, dy = (1, 0, -1, 0), (0, 1, 0, -1)
db = defaultdict(list)

def encode(lst):
    ret = 0
    for l in lst:
        ret *= 10
        ret += l
    return ret

def decode(num):
    return list(map(int, list(str(num))))

def _gen_db(lst, sx, sy, d):
    dp = deque([lst[0]])
    for i in range(1, 5):
        item = dp[-1] * 10 + lst[i]
        dp.append(item)
        db[item].append((sx, sy, d))
    for i in range(1, len(lst)):
        sx += dx[d]
        sy += dy[d]
        for j in range(2, len(dp)):
            item = dp[j] % (10**j)
            dp[j] = item
            db[item].append((sx, sy, d))
        try:
            item = dp[-1] * 10 + lst[i + 4]
            dp.append(item)
            db[item].append((sx, sy, d))
        except:
            pass
        dp.popleft()

def init(N:int, mMap:List[List[int]]) -> None:
    global n, mmap, db
    n = N
    mmap = [mMap[i][:n] for i in range(n)]
    db.clear()
    for i in range(n):
        _gen_db(mmap[i], i, 0, 1)
        _gen_db([mmap[j][i] for j in range(n)], 0, i, 0)

def _get_candi_list(M, mStructure):
    global n, db
    ret = []
    structure = mStructure[:M]
    tg = max(structure) + 1
    rg = 6 - tg + min(structure)
    candi = [tg - item for item in structure]
    while rg:
        rg -= 1
        key = encode(candi)
        for cd in db[key]:
            ret.append((key, cd))
        rev_key = encode(candi[::-1])
        if key != rev_key:
            for cd in db[rev_key]:
                ret.append((rev_key, cd))
        for i in range(M):
            candi[i] += 1
    return ret

def numberOfCandidate(M:int, mStructure:List[int]) -> int:
    global n
    if M == 1:
        return n * n
    return len(_get_candi_list(M, mStructure))

def _bfs(structure, candidate, h):
    global n, mmap
    x, y, d = candidate
    copied_map = [[item for item in line] for line in mmap]
    for i in range(len(structure)):
        copied_map[x][y] += structure[i]
        x += dx[d]
        y += dy[d]

    q = deque([])
    start_pos = []
    for i in range(n):
        start_pos.append((0, i))
        start_pos.append((n-1, i))
        if i == 0 or i == n-1:
            continue
        start_pos.append((i, 0))
        start_pos.append((i, n-1))
    for sx, sy in start_pos:
        if not (0 < copied_map[sx][sy] < h):
            continue
        copied_map[sx][sy] = 0
        q.append((sx, sy))
        while q:
            cx, cy = q.popleft()
            for i in range(4):
                nx, ny = cx + dx[i], cy + dy[i]
                if not (0 <= nx < n) or not (0 <= ny < n):
                    continue
                if not (0 < copied_map[nx][ny] < h):
                    continue
                copied_map[nx][ny] = 0
                q.append((nx, ny))

    ret = 0
    for i in range(n):
        for j in range(n):
            if not copied_map[i][j]:
                continue
            ret += 1

    return ret

def maxArea(M:int, mStructure:List[int], mSeaLevel:int) -> int:
    global db
    ret = -1
    structure = mStructure[:M]
    if M == 1:
        candies = []
        k = mStructure[0]
        for i in range(n):
            for j in range(n):
                candies.append((k, (i, j, 0)))
    else:
        candies = _get_candi_list(M, structure)
    for candi in candies:
        ret = max(ret, _bfs(decode(candi[0]), candi[1], mSeaLevel))
    return ret


""" Discord bot """

#! /usr/bin/env python3

import discord
from discord.ext import commands
from typing import Dict, List, Any

from compute.middle_layer import check_backend
from utils.env import TOKEN, CHANNEL, GUILD, CMD_PREFIX

CUSTOM_COGS = ["cogs.players_cmds", "cogs.elevated_cmds"]

NEED_REGISTER_FUNCS = {"submit-by-map-name", "submit", "unregister", "rename", "mysubs", "cancelsub"}

# BOT FUNCTIONS START HERE
BOT = commands.Bot(command_prefix=CMD_PREFIX)

@BOT.check
def check_channel(ctx):
    if str(ctx.channel) in CHANNEL and str(ctx.guild) in GUILD:
        return True
    else:
        raise commands.errors.CheckFailure("channelerr")

@BOT.event
async def on_ready():
    print(f"{BOT.user.name} has connected to Discord and ready to get cmds")

@BOT.event
async def on_command_error(ctx, error):
    if isinstance(error, commands.errors.NoPrivateMessage):
        await ctx.send("Sorry, this command is not available in DMs.")
        return
    if isinstance(error, commands.errors.CheckFailure):
        if str(error) == "channelerr":
            print(
                f"[CHANNELERR] {ctx.author} asked for {ctx.message.content} on chan {ctx.channel} of {ctx.guild} at {ctx.message.created_at}"
            )
            return
        try:
            # Check if player is registered
            err_str = str(error)
            command_failed = err_str.split('command')[1].split('failed')[0].strip()
            print(str(error))
            print(err_str)
            print(command_failed)
            if command_failed in NEED_REGISTER_FUNCS:
                await ctx.send('Player not registered. Please use `!register "YOUR_INGAME_NAME"` (yeah, with **quotes** ^^) to register.\n \
    Exple : `!register "OMDN | Gneuh [knee-uh]"`')
                return
        except IndexError:
            await ctx.send("Sorry, you do not have the correct role for this command.")
            return
    if isinstance(error, commands.errors.CommandOnCooldown):
        await ctx.send(
            "Sorry, we have to limit this command to 1 use every 60 seconds..."
        )
        return
    else:
        print(error)
        return

def start_bot() -> None:
    # Ensure that backend is coherent and up&running before anything
    if not check_backend():
        print("Hmm, backend is having issues. Is mongodb up? Stopping here")
        return

    for cust_cog in CUSTOM_COGS:
        BOT.load_extension(cust_cog)

    BOT.run(TOKEN, bot=True, reconnect=True)

if __name__ == "__main__":
    start_bot()


class Solution(object):
    def mergeStones(self, stones, K):
        """
        :type stones: List[int]
        :type K: int
        :rtype: int
        """
        N = len(stones)
        prefix = [0 for i in range(N + 1)]
        for i in range(N):
            prefix[i + 1] += (prefix[i] + stones[i])

        inf = float("inf")

        import functools

        @functools.lru_cache(None)
        def dp(i, j, m):
            if (j - i + 1 - m) % (K - 1) != 0:
                return inf
            if i == j:
                return inf if m != 1 else 0
            if m == 1:
                return dp(i, j, K) + prefix[j + 1] - prefix[i]

            return min(dp(i, mid, 1) + dp(mid + 1, j, m - 1) for mid in range(i, j))

        res = dp(0, N - 1, 1)
        return res if res != inf else -1

python/Dynamic Programming/Minimum Cost to Merge Stones/Minimum Cost to Merge Stones.py


from collections import Counter

import pytest

from startupradar.transformers.basic import (
    DomainNameTransformer,
    CommonStringTransformer,
    CounterTransformer,
)
from startupradar.transformers.util.exceptions import InvalidDomainError

DOMAINS_INVALID = [
    "127.0.0.1",
    "localhost",
    "api.startupradar.co",
    "www.startupradar.co",
]

def test_domain_name_transformer_lengths():
    t = DomainNameTransformer()
    df = t.transform(["karllorey.com", "startupradar.co"])
    assert df["length"].values.tolist() == [9, 12]

@pytest.mark.parametrize("invalid_domain", DOMAINS_INVALID)
def test_domain_name_transformer_raises(invalid_domain):
    t = DomainNameTransformer()
    with pytest.raises(InvalidDomainError):
        t.transform([invalid_domain])

def test_domain_name_transformer_feature_names_out():
    t = DomainNameTransformer()
    df = t.transform(["karllorey.com", "startupradar.co"])
    assert df.columns.tolist() == t.get_feature_names_out()

def test_common_string_transformer():
    t = CommonStringTransformer(max_df=1.0, min_df=0.5, ngram_range=(3, 5))
    domains = ["kit.edu", "hs-ka.de", "rwth-aachen.de", "rwth-campus.com"]
    df_out = t.fit_transform(domains)
    common_substrings = [
        ".de",
        "rwt",
        "rwth",
        "rwth-",
        "th-",
        "wth",
        "wth-",
    ]
    assert df_out.columns.values.tolist() == common_substrings

def test_counter_transformer():
    class CharacterCount(CounterTransformer):
        def create_counter(self, x):
            # count characters
            return Counter(list(x))

    out = CharacterCount().fit_transform(["aaa", "bbb", "abc"])

    assert set(out.columns) == set("abc")
    assert out["a"].values.tolist() == [3, 0, 1]
    assert out["b"].values.tolist() == [0, 3, 1]
    assert out["c"].values.tolist() == [0, 0, 1]


# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import migrations, models

class Migration(migrations.Migration):

    dependencies = [
        ('project', '0016_auto_20141101_2222'),
    ]

    operations = [
        migrations.AddField(
            model_name='project',
            name='internal_rate_return',
            field=models.DecimalField(default=0.0, help_text=b'The internal rate of return for this project.', verbose_name=b'Internal Rate of Return', max_digits=6, decimal_places=3),
            preserve_default=True,
        ),
    ]


from datetime import datetime

from flask import Blueprint, render_template, request, g, redirect, url_for, flash
from blueprints.forms import QuestionForm, AnswerForm
from exts import db
from decorators import login_required, admin_login_required
from models import QuestionModel, AnswerModel, UserModel

# /auth
bp = Blueprint('admin_question', __name__, url_prefix='/admin_question')

# http://127.0.0.1:5000
@bp.route('/')
@admin_login_required
def index():
    page = request.args.get('page', 1, type=int)
    per_page = 5  # Set the number of questions per page
    offset = (page - 1) * per_page
    questions = QuestionModel.query.limit(per_page).offset(offset).all()
    total_questions= QuestionModel.query.count()
    pages = total_questions // per_page + (total_questions % per_page > 0)
    return render_template('admin/question/admin_question.html', questions=questions,
                           total_questions=total_questions, per_page=per_page,
                           pages=pages, page=page
                           )

@bp.route('/add_question', methods=['GET', 'POST'])
@admin_login_required
def add_question():
    print(request.form)
    if request.method == 'POST':
        form = QuestionForm(request.form)
        new_question = QuestionModel(
            title=form.title.data,
            content=form.content.data,
            author_id = '111'
        )
        print(new_question.title)
        db.session.add(new_question)
        db.session.commit()
        flash('New question was added successfully!', 'success')
        return redirect(url_for('admin_question.index'))
    return render_template('admin/question/add_question.html')

class DeleteQuestionForm:
    pass

@bp.route('/delete_question/<int:question_id>', methods=['GET', 'POST'])
@admin_login_required
def delete_question(question_id):
    question = QuestionModel.query.get_or_404(question_id)
    form = DeleteQuestionForm()
    if request.method == 'POST':
        answers = AnswerModel.query.filter_by(question_id=question.id)

        for answer in answers:
            db.session.delete(answer)
        db.session.delete(question)
        db.session.commit()
        return redirect(url_for('admin_question.index'))
    return render_template('admin/question/delete_question.html',
                           question=question, form=form)

@bp.route('/edit_question/<int:question_id>', methods=['GET', 'POST'])
@admin_login_required
def edit_question(question_id):
    question = QuestionModel.query.get_or_404(question_id)
    form = QuestionForm(obj=question)
    if request.method=='POST':
        form.populate_obj(question)
        db.session.commit()
        flash('Question updated successfully!', 'success')
        return redirect(url_for('admin_question.index'))
    return render_template('admin/question/edit_question.html', form=form)


import requests
import os
from dotenv import load_dotenv

load_dotenv()

def telegram_send_message(message):
    send_text = (
        "https://api.telegram.org/bot"
        + os.getenv("BOTTOKEN")
        + "/sendMessage?chat_id="
        + os.getenv("CHATID")
        + "&parse_mode=Markdown&text="
        + message
    )

    response = requests.get(send_text)

    return response.json()


#!/usr/bin/env python3

import logging
import os
import sys

import netaddr
import requests
import yaml

logger = logging.getLogger("dhcp-hook")
if not logger.handlers:
    formatter = logging.Formatter("[%(asctime)s] %(levelname)s in %(module)s: %(message)s")
    # stdout logging
    handler = logging.StreamHandler()
    handler.setFormatter(formatter)
    logger.addHandler(handler)
logger.setLevel(logging.DEBUG)

def get_apidata(configfile="/etc/cnaas-nms/apiclient.yml"):
    with open(configfile, "r") as apiclient_file:
        return yaml.safe_load(apiclient_file)

def get_jwt_token():
    try:
        token = os.environ["JWT_AUTH_TOKEN"]
    except Exception:
        raise ValueError("Could not find JWT token")
    return token

def canonical_mac(mac):
    """Return a standardized format of MAC-addresses for CNaaS to
    store in databases etc."""
    na_mac = netaddr.EUI(mac)
    na_mac.dialect = netaddr.mac_bare
    return str(na_mac)

def main() -> int:
    if len(sys.argv) < 3:
        return 1

    if sys.argv[1] == "commit":
        try:
            ztp_mac = canonical_mac(sys.argv[2])
            dhcp_ip = sys.argv[3]
            platform = sys.argv[4]
        except Exception as e:
            print(str(e))
            return 2

        apidata = get_apidata()
        base_url = apidata["cnaas_nms"]["base_url"]
        verify_tls = apidata["cnaas_nms"]["verify_tls"]
        params = {"filter[ztp_mac]": ztp_mac}
        token = get_jwt_token()

        if token is None:
            return 9

        r = requests.get(
            f"{base_url}/api/v1.0/devices",
            params=params,
            verify=verify_tls,
            headers={"Authorization": "Bearer " + token},
        )
        if r.status_code != 200:
            logger.error("Could not query device API: {} (status {})".format(r.text, r.status_code))
            return 10
        try:
            r_data = r.json()
            if "status" not in r_data or "data" not in r_data:
                raise ValueError("No status key in json data")
        except Exception:  # noqa: S110
            logger.error("Invalid JSON response from devices API: {}".format(r.text))
            return 11
        if r_data["status"] != "success":
            logger.error("Could not query device API: {} (status {})".format(r.text, r_data["status"]))
            return 12
        devices = r_data["data"]["devices"]
        if devices:
            dev_dict: dict = devices[0]
            dev_id: int = int(dev_dict["id"])
            if dev_dict["state"] == "DHCP_BOOT":
                data = {"ztp_mac": ztp_mac, "dhcp_ip": dhcp_ip}
                r = requests.post(
                    f"{base_url}/api/v1.0/device_discover",
                    json=data,
                    verify=verify_tls,
                    headers={"Authorization": "Bearer " + token},
                )
                if r.status_code != 200:
                    logger.error("Error when scheduling job to discover device: {} ({})".format(r.text, r.status_code))
                    return 20
                try:
                    r_data = r.json()
                    if "status" not in r_data or "job_id" not in r_data:
                        raise ValueError("No status key in json data")
                except Exception:  # noqa: S110
                    logger.error("Invalid JSON response from device_discover API: {}".format(r.text))
                    return 21

                logger.info(
                    "Device in state DHCP_BOOT acquired new lease, "
                    + "scheduling job id {} to discover device".format(r_data["job_id"])
                )
            elif dev_dict["state"] == "DISCOVERED":
                if dev_dict["dhcp_ip"] != dhcp_ip:
                    data = {"dhcp_ip": dhcp_ip}
                    r = requests.put(
                        f"{base_url}/api/v1.0/device/{dev_id}",
                        json=data,
                        verify=verify_tls,
                        headers={"Authorization": "Bearer " + token},
                    )
                    logger.info(
                        "Updating DHCP IP for device with ZTP MAC {} to: {} (status {})".format(
                            ztp_mac, dhcp_ip, r.status_code
                        )
                    )
            else:
                logger.error(
                    "Device with ztp_mac {} in state {} unexpectedly booted via DHCP ({})".format(
                        ztp_mac, dev_dict["state"], dhcp_ip
                    )
                )

        else:
            # Add new device
            logger.info("New device booted via DHCP to state DHCP_BOOT: {}".format(ztp_mac))
            data = {
                "ztp_mac": ztp_mac,
                "dhcp_ip": dhcp_ip,
                "hostname": f"mac-{ztp_mac}",
                "platform": platform,
                "state": "DHCP_BOOT",
                "device_type": "UNKNOWN",
            }
            r = requests.post(
                f"{base_url}/api/v1.0/device",
                json=data,
                verify=verify_tls,
                headers={"Authorization": "Bearer " + token},
            )
            if r.status_code != 200:
                logger.error("Error when adding new device: {} ({})".format(r.text, r.status_code))
                return 30
            try:
                r_data = r.json()
                if "status" not in r_data or "data" not in r_data:
                    raise ValueError("No status key in json data")
            except Exception:  # noqa: S110
                logger.error("Invalid JSON response from POST to device API: {}".format(r.text))
                return 31
            logger.info(
                "Added new device with hostname {} as id {} in device database".format(
                    r_data["data"]["added_device"]["hostname"], r_data["data"]["added_device"]["id"]
                )
            )

if __name__ == "__main__":
    sys.exit(main())


# coding=utf-8

from gym import Env
from gym.spaces import Discrete, Box
import numpy as np
import random
from enum import Enum
import json

REWARD_COLLISION = -10
REWARD_EDGE_OR_STOP = 0
REWARD_TIMEOUT_EXTRA = -1
REWARD_NORMAL = 2
REWARD_DELIVERY_SUCCESS = 20

class DeliveryEnv(Env):
    def __init__(self):
        self.rows = 4
        self.cols = 4
        self.observation_space = Discrete(self.rows * self.cols)
        # Move east: 0, west: 1, south: 2, north: 3, stop: 4
        self.action_space = Discrete(5)
        # Init the position of obstacles
        self.obstacles = random.sample(range(2, 15), 2)
        # Start position
        while True:
            self.state = random.sample(range(0, self.cols), 1)[0]
            self.start = self.state
            if self.start not in self.obstacles:
                break
        # Set destination
        while True:
            self.dest = random.sample(range(self.cols*2, self.cols*3), 1)[0]
            if self.dest not in self.obstacles:
                break
        # Set package time limit
        self.package_time = random.randint(int((self.dest-self.start)/2), self.cols*self.rows)
        self.time_counter = 0

    def reconstruct_env(self):
        with open('./freeze_env.json', 'r') as f:
            info = json.load(f)
            self.rows = info['rows']
            self.cols = info['cols']
            self.observation_space = Discrete(self.rows * self.cols)
            self.action_space = Discrete(info['action_space'])
            self.obstacles = info['obstacles']
            self.start = info['start']
            self.dest = info['dest']
            self.package_time = info['timeout']

    def freeze(self):
        info = {
            "rows": self.rows,
            "cols": self.cols,
            "action_space": 5,
            "obstacles": self.obstacles,
            "start": self.start,
            "dest": self.dest,
            "timeout": self.package_time
        }
        with open('./freeze_env.json', 'w') as f:
            json.dump(info, f)
        print('save env to file success!')

    def __check_edge(self, action):
        # 1. Check if reach the edge, if so, will not move
        # 2. Check if collsion with obstacles, if so, done
        # 3. Check if reach the destination, if so, done
        can_move = True
        if action == 0:
            if (self.state%self.cols + 1) >= self.cols:
                can_move = False
        elif action == 1:
            if self.state%self.cols < 1:
                can_move = False
        elif action == 2:
            if (self.state + self.cols) >= (self.cols * self.rows):
                can_move = False
        elif action == 3:
            if (self.state - self.cols) < 0:
                can_move = False
        return can_move

    def __check_timeout(self):
        return True if self.time_counter > self.package_time else False

    def __check_delivery_success(self):
        return True if self.state == self.dest else False

    def __check_collision(self):
        return True if self.state in self.obstacles else False

    def __move(self, action):
        if action == 0:
            # move east
            self.state += 1
        elif action == 1:
            # move west
            self.state -= 1
        elif action == 2:
            # move south
            self.state += self.cols
        elif action == 3:
            # move north
            self.state -= self.cols
        else:
            # stop
            pass

    def step(self, action):
        reward = 0
        done = False
        can_move = self.__check_edge(action)
        if can_move:
            self.__move(action)
            reward = REWARD_NORMAL
        else:
            # can't move
            reward = REWARD_EDGE_OR_STOP

        if self.__check_timeout():
            reward -= REWARD_TIMEOUT_EXTRA
        if self.__check_collision():
            done = True
            reward = REWARD_COLLISION
        if self.__check_delivery_success():
            done = True
            reward = REWARD_DELIVERY_SUCCESS

        info = {}
        return self.state, reward, done, info

    def render(self):
        print("="*20)
        print(f"start position: {self.state}")
        print(f"obstacles: {self.obstacles}")
        print(f"dest: {self.dest}")
        print(f"package time limit: {self.package_time}")
        print("="*20)
        for r in range(self.rows):
            row = ""
            for c in range(self.cols):
                position = r * self.cols + c
                if position == self.start:
                    row += " S"
                elif position in self.obstacles:
                    row += " X"
                elif position == self.dest:
                    row += " D"
                elif position == self.state:
                    row += " C"
                else:
                    row += " ."
            print(row)

    def reset(self):
        self.observation_space = Discrete(self.rows * self.cols)
        self.action_space = Discrete(5)
        while True:
            self.state = random.sample(range(0, self.cols), 1)[0]
            self.start = self.state
            if self.state not in self.obstacles:
                break
        # self.obstacles = random.sample(range(2, 15), 4)
        while True:
            self.dest = random.sample(range(self.cols*2, self.cols*3), 1)[0]
            if self.dest not in self.obstacles:
                break
        # Set package time limit
        self.package_time = random.randint(int((self.dest-self.start)/2), self.cols*self.rows)
        self.time_counter = 0
        return self.state

if __name__=="__main__":
    env = DeliveryEnv()
    env.render()

    print(f'after freeze...')
    env.freeze()
    env.reconstruct_env()
    env.render()


from pandas import read_csv
from pickle import dump
from glob import glob
from tqdm import tqdm

HEADERS = ["DATE", "NAME", "LATITUDE", "LONGITUDE", "MIN", "MAX", "PRCP", "PRCP_ATTRIBUTES", "SNDP", "FRSHTT"]
TYPES = {"NAME": str, "LATITUDE": float, "LONGITUDE": float, "MIN": float, "MAX": float, "PRCP": float, "PRCP_ATTRIBUTES": str, "SNDP": float, "FRSHTT": str}

data = []

files = glob('stations/*.csv')
for i, file in enumerate(tqdm(files)):
    df = read_csv(file, dtype=TYPES, parse_dates=["DATE"])[HEADERS]
    # Ignore any stations without a name
    if df["NAME"].isnull().any():
        continue
    # Convert to dictionary for faster operations
    df = df.to_dict()
    data.append(df)

with open('weather.pickle', 'wb') as f:
    dump(data, f)


import cv2
import numpy as np
webcam = cv2.VideoCapture(0)
webcam.set(3,640)
webcam.set(4,480)
webcam.set(10,100)
marea =400
count=0
face_cascade = cv2.CascadeClassifier('Resources/haarcascades/haarcascade_russian_plate_number.xml')
while True:
    ret, frame = webcam.read()
    imageGray=cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY)
    plates = face_cascade.detectMultiScale(imageGray, 1.3, 5)
    for (x,y,w,h) in plates:
        if (w*h)>marea:
            cv2.rectangle(frame,(x,y),(x+w,y+h),(255,0,0),2)
            cv2.putText(frame,"This is number Plate",(x,y+5),cv2.FONT_ITALIC,3,(0,255,255),2)
            numberplateimage=frame[y:y+h,x:x+w]
            cv2.imshow("The number Plate",numberplateimage)
    cv2.imshow("Webcam",frame)
    if cv2.waitKey(1) & 0xff==ord('s'):
        count+=1
        cv2.imwrite('Resources'+str(count)+'.jpg',imageRegionofInterest)
        cv2.rectangle(webcamimage,(0,200),(640,300),(0,255,255),cv2.FILLED)
        cv2.putText(webcamimage,"Saved",(150,265),cv2.FONT_HERSHEY_COMPLEX,2,(255,0,255),1)
        cv2.imshow("Result",webcamimage)
        cv2.waitKey(100)


import webapp2
import cgi
import urllib,json

class MainPage(webapp2.RequestHandler):
    def get(self):
        self.response.write("""

                  <link type="text/css" rel="stylesheet" href="/stylesheets/main.css" />

                <title>Twetter App</title>

 YOUR RECENT TWEETS !!!

Your Twitter Name:

                  <form action="/sign" method = "post"

<input type="text" name="name" value="Your twitter user name" />

<input type="submit" /> <input type="reset" />

                 </form>

              </html
                    """)

class Tweets(webapp2.RequestHandler):
    def post(self):
        name = (cgi.escape(self.request.get('name')))
        self.response.headers['Content-Type'] = 'text/plain'
       	tweets = urllib.urlopen("https://api.twitter.com/1/statuses/user_timeline.json?screen_name="+name)
        tweets = tweets.read()
        tweets = json.loads(tweets)
        count = 0
        for tweet in tweets:
            if tweet["text"][0] != 'R' and count<10:
               self.response.out.write(tweet['text'])
               self.response.out.write("\n")
               count += 1
app = webapp2.WSGIApplication([('/', MainPage),('/sign', Tweets)], debug=True)


import os
import io
import shutil
import hashlib
import mimetypes
from datetime import datetime
import pytz

from googleapiclient.http import MediaFileUpload

from . import log, auth, remote_fs
from .filesystem import *
from .errors import *

class LinuxFS(FileSystem):
    """ A linux specific file handler.
        Can upload files to Google Drive. """

    def __init__(self, path, is_dir=None):
        super().__init__()

        # use relative path from current working directory
        # so the sync folder can be moved around
        self.path = os.path.relpath(path)

        # for local fs, path is id
        self.id = self.path

        # We can create instance even if it doesn't exist yet
        self.exists = os.path.exists(self.path)
        self.name = os.path.basename(self.path)

        if self.exists:
            if os.path.isdir(self.path):
                self._is_dir = True
                self._mimeType = MimeTypes.linux_directory
            else:
                self._is_dir = False
                mmtype, encoding = mimetypes.guess_type(self.path)
                self._mimeType = mmtype

        # explicitly set is_dir if specified
        if is_dir is not None:
            self._is_dir = is_dir

    def is_local(self):
        return True

    def size(self):
        if not self.exists:
            return None
        if self.is_dir():
            return None

        return os.path.getsize(self.path)

    def create_dir(self):
        # declare this as a directory
        self._is_dir = True

        if self.exists:
            log.warn("Directory already exists: ", self)
            return
        else:
            os.makedirs(self.path)
            self.exists = True
            log.say("Created local directory: ", self.path)

    def md5(self):
        """ Calculate md5 by chunk, this should be okay with large files. """
        if self.is_dir() or not self.exists:
            return None

        md5 = hashlib.md5()
        with open(self.path, 'rb') as f:
            for chunk in iter(lambda: f.read(128 * md5.block_size), b''):
                md5.update(chunk)
        return md5.hexdigest()

    def modifiedTime(self):
        if not self.exists:
            return None

        # get OS modified time
        t = os.path.getmtime(self.path)

        # convert unix epoch time string to datetime
        dt = datetime.utcfromtimestamp(int(t))

        # set utc timezone
        return pytz.UTC.localize(dt)

    def list_dir(self, recursive=False):
        """ Populate self.children list by reading current directory items. """
        if not self.exists:
            raise ErrorPathNotExists(self)

        if self.is_file():
            raise NotADirectoryError(self)

        self.children = []
        for file in os.listdir(self.path):
            full_path = os.path.join(self.path, file)
            child = LinuxFS(full_path)
            self.children.append(child)

            # recursively read child directories
            if recursive and child.is_dir():
                child.list_dir(recursive=recursive)

    def gdrive_upload(self, parentIds):
        """ Upload a new file to G Drive. """

        if not self.exists:
            ErrorPathNotExists(self)

        if not self.is_file():
            raise IsADirectoryError(self)

        if not parentIds:
            raise ErrorParentNotFound(
                "Must specify parentIDs to upload file.", self)

        payload = {
            'name': self.name,
            'parents': parentIds
        }

        media = MediaFileUpload(self.path,
                                mimetype=self._mimeType,
                                chunksize=UPLOAD_CHUNK_SIZE,
                                resumable=True
                                )

        file = auth.service.files().create(
            body=payload,
            media_body=media,
            fields=FIELDS         # fields that will be returned in response json
        )

        response = None

        log.say("Uploading file:", self.name, "please wait ...")
        while response is None:
            status, response = file.next_chunk()
            if status:
                log.progress("Uploaded %d%%" % int(status.progress() * 100))

        if file:
            # record sync time
            self._syncTime = datetime.utcnow()
            log.say("Upload successful: ", self.path)
            return response
        else:
            log.error("Upload failed: ", response)
            return None

    def gdrive_update(self, remote_file):
        """ Update an existing G Drive file with a local file.
            @todo: update only bytes that changed.
        """

        if not self.exists:
            ErrorPathNotExists(self)

        if not isinstance(remote_file, remote_fs.GDriveFS):
            raise ErrorNotDriveFSObject(self)

        if not self.is_file():
            raise IsADirectoryError(self)

        if not remote_file.id:
            raise ErrorIDNotSet("Remote file ID invalid, can not update")

        payload = {
            'title': self.name,
        }

        media = MediaFileUpload(
            self.path,
            chunksize=UPLOAD_CHUNK_SIZE,
            resumable=True
        )

        file = auth.service.files().update(
            fileId=remote_file.id,
            body=payload,
            media_body=media,
            fields=FIELDS         # fields that will be returned in response json
        )

        response = None

        log.say("Uploading file:", self.name, "please wait ...")
        while response is None:
            status, response = file.next_chunk()
            if status:
                log.progress("Uploaded %d%%" % int(status.progress() * 100))

        if file:
            # update the remote file properties with the response json
            remote_file.set_object(response, None)

            # record sync time
            self._syncTime = datetime.utcnow()
            remote_file._syncTime = self._syncTime

            log.say("Update successful: ", self.path)
        else:
            log.error("Update failed: ", response)

        return remote_file

    def upload_or_download(self, mirror):
        if not isinstance(mirror, remote_fs.GDriveFS):
            raise ErrorNotDriveFSObject(mirror)

        response = self.gdrive_upload(mirror.parentIds)

        # path should be already set, so parent path is None
        mirror.set_object(response, None)

        return mirror

    def update(self, mirror):
        if not isinstance(mirror, remote_fs.GDriveFS):
            raise ErrorNotDriveFSObject(mirror)
        return self.gdrive_update(mirror)

    def remove(self):
        log.trace("Removing", self)

        if os.path.exists(self.path):
            try:
                if self.is_dir():
                    shutil.rmtree(self.path)
                else:
                    os.remove(self.path)
            except Exception as ex:
                log.error(ex)
            else:
                log.say("Delete OK:", self.path)


import controller
import time
import datetime

start_time = time.time()

####define com ports for controller and baudrate (keep at 115200)
# port = '/dev/ttyACM0' # Linux
port = "COM5"  # Windows
baud_rate = 115200

setup = controller.Setup(port, baud_rate)
setup.connect()

#################### Fluidics parameters ###########################
wait = 10
move = controller.Motor()
power = controller.MainPower()

# Parameters related to peristaltic pumps
p1_new = [
    13.712609063042798,
    0.977763871750637,
    4.104248850640944e-05,
    -4.143399187088928e-08,
]
p1_default = [
    19.801938114061617,
    0.964367848880719,
    1.167139063529185e-05,
    -2.873709837738213e-09,
]
p2_default = [
    11.765533598083050,
    0.994151183002726,
    -2.200584843815698e-05,
    5.268389857671134e-09,
]
p_linear = [0, 1, 0, 0]

########### start of script! #################################################

# Main Power ON
print("\n----MAIN POWER ON----")
power.state("ON")
time.sleep(5)

# Homming
print("\n----NOZZLES HOMING----")
message_home2 = bytes("<homeDisp,0,0>", "UTF-8")
move.send(message_home2)
time.sleep(wait + 12)

print("\n----GANTRY HOMING----")
message_home1 = bytes("<homeGantry,0,0>", "UTF-8")
move.send(message_home1)
time.sleep(wait + 7)

######## Move to the cell being used for the failed test #############
print("\n----Moving to cell 2----")
pos = controller.Position_in_cell(2)  ### Change it to 2 or 3 ###
pos.run()
time.sleep(wait + 5)

### Initial Electrode Rinsing #################################################################
## "wait_time" in Rinse function (0 will skip the step, and below is the sequence)
## (1) Down / [LOOP start [ (2) suction / (3) flush / (4) suction] LOOP end] / (5) Up
## = [16, 12, 15, 12, 16]
rinse = controller.Rinse(
    loop=3, wait_time=[16, 12, 15, 12, 16]
)  # change the number of loops
rinse.run()
time.sleep(5)

### Electrode strong rinsing / bubbling / drying (SR) ###############################################
# (SR1) Filling reservoir with solvent
print("\n----\033[31m Filling reservoir with solvent \033[0m----")
filling_only = controller.Rinse(loop=1, wait_time=[16, 0, 15, 0, 16])
filling_only.run()

message_move1_back = bytes("<X,1000,-800>", "UTF-8")  # -870
move.send(message_move1_back)
time.sleep(10)

# (SR2) Argon bubbling
print("\n----\033[31mN2 bubbling\033[0m----")
n2_bubbling = controller.N2(loop=1, nozzle=2, wait_time=[12, 3, 12], mode="dual")
n2_bubbling.run()
time.sleep(7)

# (SR3) Suction only
suction_only = controller.Rinse(loop=1, wait_time=[16, 12, 0, 0, 16])
suction_only.run()
time.sleep(7)

# (SR4) Argon drying
print("\n----\033[31mN2 drying\033[0m----")
n2_drying = controller.N2(loop=1, nozzle=1, wait_time=[12, 3, 12], mode="single")
n2_drying.run()
time.sleep(10)

### Main Power OFF ##################################################################################

print("\n----MAIN POWER OFF----")
power.state("OFF")
time.sleep(5)

print("Finished")
setup.disconnect()

print("\n----\033[31m Print the total time duration \033[0m----")
end_time = time.time()
total_time = end_time - start_time
total_time_list = str(datetime.timedelta(seconds=total_time)).split(".")
print(total_time_list[0])  # Hrs:Mins:Secs format


import csv
import pandas as pd
import pathlib
import os.path
from validate import validate_date

# leeg sold.csv aanmaken
def create_soldcsv():
    with open(
        pathlib.Path(__file__).parent / "sold.csv", "w", newline=""
    ) as soldFile:
        writer = csv.writer(soldFile)
        writer.writerow(
            [
                "id",
                "buyid",
                "selldate",
                "product",
                "sellamount",
                "sellprice",
                "expirydate",
            ]
        )

# def checkexpdate(productsold):

def append_buyid(productsold):
    check_file = os.path.isfile("sold.csv")
    if not check_file:
        create_soldcsv()
    # Gekochte producten krijgen een 'buyid'.
    # Ieder verkocht product krijgt een eigen id en op basis
    # van productnaam en expirydate het buyid van de bijbehorende
    # inkoopbatch.
    # Hiervoor wordt eerst gekeken hoeveel er nog in voorraad is.

    # Lijst genereren met gekochte producten, aantal sommeren
    # op product en expirydate
    dfb = pd.read_csv("bought.csv", index_col="buyid")
    dfbgroup = dfb.groupby(["buyid", "product", "expirydate"])[
        "buyamount"
    ].sum()

    # Lijst genereren met verkochte producten, aantal sommeren
    # op product en expirydate
    dfs = pd.read_csv("sold.csv", index_col="id")
    dfsgroup = dfs.groupby(["buyid", "product", "expirydate"])[
        "sellamount"
    ].sum()

    # deze gegevens mergen op buyid
    inventory = pd.merge(
        dfbgroup.reset_index(), dfsgroup, how="left", on=["buyid"]
    ).fillna(0)

    # kolom toevoegen om aantal producten nog in voorraad uit te rekenen
    inventory["in_stock"] = inventory["buyamount"] - inventory["sellamount"]

    # ingevoerde product opzoeken in lijst om expirydate erbij te zoeken
    inv_productsold = inventory[
        inventory["product"].str.match(productsold[1])
    ]
    if inv_productsold.empty:
        print(
            "Product not in stock, or this amount not available.\n"
            "Check productname, sellamount"
        )
        exit()
    if len(inv_productsold) == 1 & (inv_productsold["in_stock"].sum(axis=0)
                                    < productsold[2]):
        available = inv_productsold["in_stock"].sum(axis=0)
        if available == 0:
            print("Product sold out")
        else:
            print(
                "Only "
                + str(available)
                + " items available, check input of sold product:"
                " productname or sellamount.\n"
                "Product NOT added to bought.csv"
            )
            exit()
    if len(inv_productsold) == 1 & (inv_productsold["in_stock"].sum(axis=0)
                                    >= productsold[2]):
        if inv_productsold.iat[0, 2] < productsold[0]:
            print("Product expired, product NOT added to sold.csv")
        else:
            buyid = inv_productsold.iat[0, 0]
            expdate = inv_productsold.iat[0, 2]
            prodlist = [buyid] + productsold + [expdate]
            append_prodlist(prodlist)
    if len(inv_productsold) > 1:
        print(inv_productsold)
        expdate = input("More expirydates available for this product, type "
                        "expirydate of your product:")
        validate_date(expdate)
        productsold = productsold + [expdate]
        appendbuyid_morexpdate(productsold)
# Er kunnen op meerdere dagen producten zijn ingekocht met
# dezelfde productnaam en eenzelfde expirydate of dezelfde productnaam
# en meerdere expirydates.
# Met behulp van bovenstaande functie wordt gecheckt of er bij een
# ingevoerd product meerdere expirydatums horen en laat die zien.
# De gebruiker moet de juiste expirydate invoeren.

# Hierna wordt een 2e functie gestart die eventueel nog een keer
# gestart kan worden als er producten worden verkocht die verdeeld moeten
# worden over meerdere inkoopbatches.
# Eerst wordt het de eerste batch getoond en daar wordt de
# de hoeveelheid gekochte producten vanaf gehaald. Is er dan
# nog over, worden die van de volgende batch afgehaald.
# Is het product dan uitverkocht, wordt hier melding van gemaakt.

def appendbuyid_morexpdate(productsold):
    # Begin van de functie is hetzelfde als de hierbovenstaande functie
    dfb = pd.read_csv("bought.csv", index_col="buyid")
    dfbgroup = dfb.groupby(["buyid", "product", "expirydate"])[
        "buyamount"
    ].sum()

    # Lijst met verkochte producten, aantal sommeren op product en expirydate
    dfs = pd.read_csv("sold.csv", index_col="id")
    dfsgroup = dfs.groupby(["buyid", "product", "expirydate"])[
        "sellamount"
    ].sum()

    # deze gegevens mergen op buyid
    inventory = pd.merge(
        dfbgroup.reset_index(), dfsgroup, how="left", on=["buyid"]
    ).fillna(0)

    # kolom toevoegen om aantal producten nog in voorraad uit te rekenen
    inventory["in_stock"] = inventory["buyamount"] - inventory["sellamount"]
    inv_productsold = inventory[
            inventory["product"].str.match(productsold[1])
            & (inventory["expirydate"].str.match(productsold[4]))
            & (inventory["in_stock"] > 0)]
    # Als er te weinig producten in voorraad zijn tov het ingegeven
    # aantal producten, komt er een melding.
    if inv_productsold["in_stock"].sum(axis=0) < productsold[2]:
        available = inv_productsold["in_stock"].sum(axis=0)
        print(
            "Only "
            + str(available)
            + " items available, check input of sold product:"
            " productname, sellamount and/or expirydate.\n"
            "Product NOT added to bought.csv"
        )
# Als er genoeg items in voorraad zijn, wordt buyid van 1e batch
# toegevoegd aan het verkochte product en aan bought.csv toegevoegd
    else:
        buyid = (inv_productsold.head(1)).iat[0, 0]
        instock_buyid = (inv_productsold.head(1)).iat[0, 5]
        if instock_buyid >= productsold[2]:
            prodlist = [buyid] + productsold
            append_prodlist(prodlist)
# Als er producten van een 2e inkoopbatch afgehaald moeten worden,
# wordt dat in het volgende stukje van de functie gedaan en wordt
# de functie herstart om met nieuwe voorraadgegevens te werken en
# de juiste inkoopbatch te gebruiken.
        elif instock_buyid < productsold[2]:
            prodlist = ([buyid] + productsold[:2] + [instock_buyid]
                        + productsold[3:])
            append_prodlist(prodlist)
            restamount = productsold[2] - instock_buyid
            if restamount == 0:
                print("Product out of stock.")
            else:
                restprodlist = productsold[:2] + [restamount] + productsold[3:]
                productsold = restprodlist
                appendbuyid_morexpdate(productsold)
    # Er komt een melding als het product is uitverkocht.
        if instock_buyid == productsold[2]:
            print("Last product sold, product out of stock.")
        else:
            pass

# # Met deze functie worden de producten toegevoegd aan de sold.csv
# # Eerst wordt gecontroleerd of er een sold.csv bestaat.
# # Afhankelijk daarvan wordt een 1e record toegevoegd met id 1
# # of gezocht naar hoogste id en die automatisch met 1 verhoogd.
def append_prodlist(prodlist):
    maxb_id = 0
    check_file = os.path.isfile("sold.csv")
    if check_file:
        dfb = pd.read_csv("sold.csv", index_col="id")
        if dfb.empty:
            prodlist = [1] + prodlist
            with open("sold.csv", "a", newline="") as productFile:
                productFilewriter = csv.writer(productFile)
                productFilewriter.writerow(prodlist)
                print("Product " + str(prodlist) + " is added to sold.csv")
        else:
            maxb_id = max(dfb.index)
            maxb_id += 1
            prodlist = [maxb_id] + prodlist
            with open("sold.csv", "a", newline="") as productFile:
                productFilewriter = csv.writer(productFile)
                productFilewriter.writerow(prodlist)
                print("Product " + str(prodlist) + " is added to sold.csv")
    if not check_file:
        create_soldcsv()
        append_prodlist(prodlist)

if __name__ == "__main__":
    create_soldcsv()