import os, platform, shutil, time, re, webbrowser, urllib.request
from tkinter import *
from tkinter import ttk
from tkinter.filedialog import askopenfilename
from PIL import Image, ImageTk
from codeur import *
from utilitaire import *

from classe_doc_int import *

class ClasseDoc(ClasseDocInt):
	def __init__(self, texte_police, texte_taille, couleur_fond, largeur_texte,
	taille_tab):
		ClasseDocInt.__init__(self, texte_police, texte_taille, couleur_fond,
		largeur_texte, taille_tab)

		self.fichierVerif = ""
		self.cheminFichier = ""
		self.image = []

		self.indexAR = 0
		self.indexMaxAR = 0
		self.indexPosAR = []

		self.boutonEnr.configure(command=self.Enr)

		self.Gras_check = IntVar()
		self.boutonGras.configure(command=self.Gras)
		self.Doc.tag_configure("GRAS", font=self.PoliceGras)

		self.Code_check = IntVar()
		self.boutonCode.configure(command=self.Code)
		self.Doc.tag_configure("CODE", font=self.PoliceCode)
		self.tailleTab = taille_tab
		self.Doc.bind("<Tab>", self.Tab)
		self.Doc.bind("<BackSpace>", self.Effacement)

		self.Surligner_check = IntVar()
		self.boutonSurlignRien.configure(command=self.SurlignRien)
		self.boutonSurlignJaune.configure(command=self.SurlignJaune)
		self.Doc.tag_configure("JAUNE", background="#FFFF00")
		self.boutonSurlignVert.configure(command=self.SurlignVert)
		self.Doc.tag_configure("VERT", background="#00FF00")
		self.boutonSurlignBleu.configure(command=self.SurlignBleu)
		self.Doc.tag_configure("BLEU", background="#00FFFF")

		self.efForm.configure(command=self.SupprFormatage)

		self.Styles_check = IntVar()
		self.choixTypePar.bind("<<ComboboxSelected>>", self.TypePar)
		self.Doc.tag_configure("T1", font=self.PoliceT1)
		self.Doc.tag_configure("T2", font=self.PoliceT2)
		self.Doc.tag_configure("T3", font=self.PoliceT3)
		self.Doc.tag_configure("T4", font=self.PoliceT4)
		self.Doc.tag_configure("CITATION",
		font=self.PoliceCite, lmargin1="20", lmargin2="20")
		self.Doc.tag_configure("AVERTISSEMENT", foreground="#ea0000",
		lmargin1="20", lmargin2="20", font=self.PoliceGras)
		self.Doc.tag_configure("CONSEIL", foreground="#007f7f",
		lmargin1="20", lmargin2="20", font=self.PoliceGras)
		self.Doc.tag_configure("AUTEUR", font=self.PoliceAuteur,
		lmargin1="80", lmargin2="80")

		self.Doc.tag_configure("LIEN", foreground="blue", underline=1)

		self.Doc.tag_raise(SEL)

		self.Doc.tag_bind("LIEN", "<Enter>", self.EntrerLien)
		self.Doc.tag_bind("LIEN", "<Leave>", self.SortirLien)
		self.Doc.tag_bind("LIEN", "<Button-1>", self.Lien)

		self.boutonImage.configure(command=self.Image)
		self.boutonImageWeb.configure(command=self.ImageWeb)
		self.boutonCreerDessin.configure(command=self.CreerDessin)

		self.Doc.bind("<KeyPress>", self.InfosBarreEtat)
		self.Doc.bind("<ButtonRelease>", self.InfosBarreEtat)

		self.Doc.bind("<KeyRelease>", self.Traqueur)
		self.Doc.bind("<ButtonRelease>", self.Traqueur, add="+")

		self.Doc.bind("<space>", self.SauvUndoRedo)
		self.Doc.bind("<KeyRelease-space>", self.GenLiens)
		self.Doc.bind("<Return>", self.Entree)

		self.Doc.bind("<Button-1>", self.EffacerMenu)
		if platform.system() == "Darwin":
			self.Doc.bind("<Button-2>", self.MenuContextuel)
		else:
			self.Doc.bind("<Button-3>", self.MenuContextuel)

		self.balises = []

	def Tab(self, toto=0):
		self.Doc.insert("insert", " "*self.tailleTab)
		return("break")

	def Effacement(self, toto=0):
		finDeTab = "insert -"+str(self.tailleTab)+"c"
		if self.Doc.get(finDeTab, "insert") == " "*self.tailleTab:
			self.Doc.delete(finDeTab, "insert")
			return("break")

	def DeplDroite(self, toto=0):
		self.DeplElem(dir='droite')

	def DeplGauche(self, toto=0):
		self.DeplElem(dir='gauche')

	def DeplElem(self, dir):
		sel1 = self.Doc.index(SEL_FIRST)
		sel2 =  self.Doc.index(SEL_LAST)
		selec = self.Doc.get(SEL_FIRST, SEL_LAST)
		self.Doc.delete(SEL_FIRST,SEL_LAST)

		if dir == "droite":
			self.Doc.insert(INSERT+'+1c', selec)
			self.Doc.tag_add("sel", sel1+'+1c', sel2+'+1c')
			self.Doc.mark_set(INSERT, INSERT+'+1c')
		if dir == "gauche":
			self.Doc.insert(INSERT+'-1c', selec)
			self.Doc.tag_add("sel", sel1+'-1c', sel2+'-1c')
			self.Doc.mark_set(INSERT, INSERT+'-1c')

	def EntrerLien(self, toto):
		self.Doc.config(cursor="hand2")
	def SortirLien(self, toto):
		self.Doc.config(cursor="xterm")
	def Lien(self, toto):
		protocoles = ["http://", "https://", "ftp://", "sftp://"]
		for protocole in protocoles:
			debutLien = self.Doc.search(protocole, CURRENT, backwards=True)
			finLien = self.Doc.search(" ", CURRENT)
			webbrowser.open(self.Doc.get(debutLien, finLien))

	def Entree(self, toto):
		self.Doc.insert("insert", "\n")
		try:
			self.Doc.tag_remove("T1", "insert linestart",
			"insert linestart + 1 lines")
			self.Doc.tag_remove("T2", "insert linestart",
			"insert linestart + 1 lines")
			self.Doc.tag_remove("T3", "insert linestart",
			"insert linestart + 1 lines")
			self.Doc.tag_remove("T4", "insert linestart",
			"insert linestart + 1 lines")
			self.Doc.tag_remove("CITATION", "insert linestart",
			"insert linestart + 1 lines")
			self.Doc.tag_remove("AVERTISSEMENT", "insert linestart",
			"insert linestart + 1 lines")
			self.Doc.tag_remove("CONSEIL", "insert linestart",
			"insert linestart + 1 lines")
			self.Doc.tag_remove("AUTEUR", "insert linestart",
			"insert linestart + 1 lines")
		except:
			pass
		self.Doc.delete("insert -1c", "insert")

	def ImageWeb(self, toto=0):
		urlImage = self.frame.clipboard_get()
		lienFaux = 0

		protocoles = ["http://", "https://", "ftp://", "sftp://"]
		for protocole in protocoles:
			if re.search("^"+protocole, urlImage) != None and \
			re.search("(jpg)|(jpeg)|(png)|(webp)|(bmp)|(tif)|(tiff)|(gif)|\
			(eps)|(ppm)|(xbm)|(im)|(msp)|(pcx)|(spi)\.$", urlImage) != None:

				urlImage.replace("/", "")
				listeImage = urlImage.rsplit('.', 1)
				nouveauNomImage = str(int(time.time()))+"."+listeImage[1]

				try:
					HTTPimage = urllib.request.urlopen(urlImage)

					fichier = open("./Images/"+nouveauNomImage, "wb")
					fichier.write(HTTPimage.read())
					fichier.close()

					self.image.append(ImageTk.PhotoImage(Image.open("./Images/"+
					nouveauNomImage), name=nouveauNomImage))
					self.Doc.image_create(INSERT, image=self.image[-1])
					self.SauvUndoRedo()
					self.Traqueur()
				except:
					messagebox.showerror("Image introuvable", "L'adresse \
renvoie vers une ressource introuvable (erreur HTTP 404).")
			else:
				lienFaux += 1

		if lienFaux == 4:
			messagebox.showerror(message='Veuillez copier un lien dans le \
presse-papier pour insérer l\'image. \n\nLes formats suivants sont \
supportés :\n jpg, png, webp, bmp, tif, gif, eps, ppm, xbm, im, msp, pcx et \
spi.')

	def Image(self, toto=0):
		urlImage = askopenfilename(filetypes=[
		('Image','*.jpg'), ('Image','*.jpeg'), ('Image','*.png'),
		('Image','*.webp'), ('Image','*.bmp'), ('Image','*.tif'),
		('Image','*.tiff'), ('Image','*.gif'), ('Image','*.eps'),
		('Image','*.ppm'), ('Image','*.xbm'), ('Image','*.im'),
		('Image','*.msp'), ('Image','*.pcx'), ('Image','*.spi'),
		('Image JPEG','*.jpg'), ('Image JPEG','*.jpeg'), ('Image PNG','*.png'),
		('Image WEBP','*.webp'), ('Image BMP','*.bmp'), ('Image TIFF','*.tif'),
		('Image TIFF','*.tiff'), ('Image GIF','*.gif'), ('Image EPS','*.eps'),
		('Image PPM','*.ppm'), ('Image XBM','*.xbm'), ('Image IM','*.im'),
		('Image MSP','*.msp'), ('Image PCX','*.pcx'), ('Image SPIDER','*.spi')
		],
		initialdir=os.path.expanduser('~'), title='Importer une image')

		if urlImage:
			listeImage = urlImage.rsplit('.', 1)
			nouveauNomImage = str(int(time.time()))+"."+listeImage[1]

			shutil.copyfile(urlImage, "./Images/"+nouveauNomImage)

			self.image.append(ImageTk.PhotoImage(Image.open("./Images/"+
			nouveauNomImage), name=nouveauNomImage))
			self.Doc.image_create(INSERT, image=self.image[-1])
			self.SauvUndoRedo()
			self.Traqueur()

	def CreerDessin(self, toto=0):
		if platform.system() == "Windows":
			nouveauNomImage = str(int(time.time()))+".png"

			os.system('copy '+os.path.abspath('')+'\Images\mod.png '+
			os.path.abspath('')+'\Images\\'+nouveauNomImage)

			os.system('mspaint '+os.path.abspath('')+'\Images\\'+
			nouveauNomImage)

			self.image.append(ImageTk.PhotoImage(
			Image.open(".\Images\\"+nouveauNomImage), name=nouveauNomImage))

			self.Doc.image_create(INSERT, image=self.image[-1])

			self.SauvUndoRedo()
			self.Traqueur()
		elif platform.system() == "Linux":
			if os.path.isfile("/usr/bin/xpaint"):
				nouveauNomImage = str(int(time.time()))+".png"

				os.system('cp '+os.path.abspath('')+'/Images/mod.png '+
				os.path.abspath('')+'/Images/'+nouveauNomImage)

				os.system('xpaint '+os.path.abspath('')+'/Images/'+
				nouveauNomImage)

				self.image.append(ImageTk.PhotoImage(Image.open("./Images/"+
				nouveauNomImage), name=nouveauNomImage))

				self.Doc.image_create(INSERT, image=self.image[-1])

				self.SauvUndoRedo()
				self.Traqueur()
			else:
				messagebox.showerror("Application XPaint introuvable", "\
L'application XPaint est nécessaire pour créer des dessins. Elle est disponible \
dans les dépôts de nombreuses distributions.")
		elif platform.system() == "Darwin":
			if os.path.isfile("/Applications/Paintbrush"):
				nouveauNomImage = str(int(time.time()))+".png"

				os.system('cp '+os.path.abspath('')+'/Images/mod.png '+
				os.path.abspath('')+'/Images/'+nouveauNomImage)

				os.system('paintbrush '+os.path.abspath('')+'/Images/'+
				nouveauNomImage)

				self.image.append(ImageTk.PhotoImage(Image.open("./Images/"+
				nouveauNomImage), name=nouveauNomImage))

				self.Doc.image_create(INSERT, image=self.image[-1])

				self.Traqueur()
			else:
				messagebox.showerror("Application Paintbrush introuvable", "\
L'application Paintbrush est nécessaire pour créer des dessins. Elle est \
disponible librement sur http://paintbrush.sourceforge.net")

	def SauvUndoRedo(self, toto=0):
		self.indexMaxAR += 1
		self.indexAR = self.indexMaxAR
		self.indexPosAR.append(self.Doc.index(INSERT))

		fichierCode = Codeur(self.balises, self.Doc.dump(0.0, END), self.image)

		fichier = open("Temporaire/AnnulerRefaire/"+str(self.indexAR),
		'w', encoding='utf-8')
		fichier.write(fichierCode)
		fichier.close()

	def SauvFuturUndoRedo(self, toto=0):
		self.indexPosAR.append(self.Doc.index(INSERT))

		fichierCode = Codeur(self.balises, self.Doc.dump(0.0, END), self.image)

		fichier = open("Temporaire/AnnulerRefaire/"+str(self.indexAR),
		'w', encoding='utf-8')
		fichier.write(fichierCode)
		fichier.close()

	def Enr(self, toto=0):
		fichierCode = Codeur(self.balises, self.Doc.dump(0.0, END), self.image)
		self.fichierVerif = fichierCode

		fichier = open(self.cheminFichier, 'w', encoding='utf-8')
		fichier.write(fichierCode)
		fichier.close()

		self.Traqueur()

	def Suppr(self):
		self.Doc.delete(SEL_FIRST,SEL_LAST)

	def Copier(self):
		self.frame.clipboard_clear()
		self.frame.clipboard_append(self.Doc.get(SEL_FIRST, SEL_LAST))

	def Couper(self):
		self.Copier()
		self.Doc.delete(SEL_FIRST, SEL_LAST)
		self.SauvUndoRedo()

	def Coller(self):
		pressePapiers = self.frame.clipboard_get()
		protocoles = ["http://", "https://", "ftp://", "sftp://"]
		for protocole in protocoles:
			if re.search(protocole, pressePapiers) != None:
				pressePapiers = pressePapiers+" "

		try:
			self.Doc.delete(SEL_FIRST, SEL_LAST)
			self.Doc.insert(INSERT, pressePapiers)
		except:
			self.Doc.insert(INSERT, pressePapiers)

		self.GenLiens()
		self.SauvUndoRedo()

		#imageCollee = self.image.append(ImageTk.PhotoImage(imageCollee,
		#name=str(int(time.time()))))
		#self.Doc.image_create(INSERT, image=self.image[-1])

	def BaliseMode(self, balise):
		if balise == "GRAS":
			enfonce = self.Gras_check.get()
		elif balise == "CODE":
			enfonce = self.Code_check.get()

		# Si du texte est sélectionné
		try:
			 # S'il est en balisé
			if balise in self.Doc.tag_names("sel.first"):
				self.Doc.tag_remove(balise, "sel.first", "sel.last")
			# Sinon, s'il est normal
			else:
				if self.Doc.get("sel.last") == "\n":
					self.Doc.tag_add(balise, "sel.first",
					"sel.last +1l linestart")
				else:
					self.Doc.tag_add(balise, "sel.first", "sel.last")
			self.SauvUndoRedo()
			self.Traqueur()

		# Si aucune sélection n'est faite
		except:
			prochainCarac = self.Doc.get(INSERT, "insert +1c")
			caracApresMot = self.Doc.get("insert wordend", "insert wordend +1c")

			# Si le curseur est entre deux mots
			if prochainCarac == " " or prochainCarac == "\n" or\
			prochainCarac == "\t":
				# Si le curseur est sur du balisé
				if enfonce == 1:
					def LettreTapee(touche=""):
						if caracApresMot == "\n":
							self.Doc.tag_remove(balise, "insert -1c",
							"insert +1l linestart")
						else:
							self.Doc.tag_remove(balise, "insert -1c",
							"insert wordend")

					self.Doc.bind("<KeyRelease>", LettreTapee)

					self.SauvUndoRedo()
					self.Traqueur(forcer=balise)

				# Sinon si le curseur est sur du texte normal
				else:
					def LettreTapee(touche=""):
						if caracApresMot == "\n":
							self.Doc.tag_add(balise, "insert -1c",
							"insert +1l linestart")
						else:
							self.Doc.tag_add(balise, "insert -1c",
							"insert wordend")

					self.Doc.bind("<KeyRelease>", LettreTapee)

					self.SauvUndoRedo()
					self.Traqueur(forcer=balise, pos=True)

			# Si le curseur est dans un mot
			else:
				if balise in self.Doc.tag_names("insert"):
					if caracApresMot == "\n":
						self.Doc.tag_remove(balise, "insert wordstart",
						"insert +1l linestart")
					else:
						self.Doc.tag_remove(balise, "insert wordstart",
						"insert wordend")
				else:
					if caracApresMot == "\n":
						self.Doc.tag_add(balise, "insert wordstart",
						"insert +1l linestart")
					else:
						self.Doc.tag_add(balise, "insert wordstart",
						"insert wordend +1c")
				self.SauvUndoRedo()
				self.Traqueur()

		self.SauvUndoRedo()

	def Gras(self, toto=0):
		self.BaliseMode("GRAS")

	def Code(self, toto=0):
		self.BaliseMode("CODE")

	def SurlignRien(self, toto=0):
		couleurs = ["JAUNE", "VERT", "BLEU"]
		for i in couleurs:
			try:
				self.Doc.tag_remove(i, "sel.first", "sel.last")
			except:
				self.Doc.tag_remove(i, "insert wordstart", "insert wordend")
		self.SauvUndoRedo()
		self.Traqueur()

	def SurlignJaune(self, toto=0):
		self.SurlignRien()
		try:
			self.Doc.tag_add("JAUNE", "sel.first", "sel.last")
		except:
			self.Doc.tag_add("JAUNE", "insert wordstart", "insert wordend")
		self.SauvUndoRedo()
		self.Traqueur()

	def SurlignVert(self, toto=0):
		self.SurlignRien()
		try:
			self.Doc.tag_add("VERT", "sel.first", "sel.last")
		except:
			self.Doc.tag_add("VERT", "insert wordstart", "insert wordend")
		self.SauvUndoRedo()
		self.Traqueur()

	def SurlignBleu(self, toto=0):
		self.SurlignRien()
		try:
			self.Doc.tag_add("BLEU", "sel.first", "sel.last")
		except:
			self.Doc.tag_add("BLEU", "insert wordstart", "insert wordend")
		self.SauvUndoRedo()
		self.Traqueur()

	def SupprFormatage(self, toto=0):
		for i in self.Doc.tag_names():
			if not i == "sel":
				try:
					self.Doc.tag_remove(i, "sel.first", "sel.last")
				except:
					self.Doc.tag_remove(i, "0.0", END)
		self.SauvUndoRedo()

	def ToutSel(self):
		self.Doc.focus_set()
		self.Doc.tag_add("sel", "0.0", END)

	def TypePar(self, toto=0):
		def effacerAutresStyles():
			try:
				self.Doc.tag_remove("T1", "insert linestart",
				"insert linestart + 1 lines")
				self.Doc.tag_remove("T2", "insert linestart",
				"insert linestart + 1 lines")
				self.Doc.tag_remove("T3", "insert linestart",
				"insert linestart + 1 lines")
				self.Doc.tag_remove("T4", "insert linestart",
				"insert linestart + 1 lines")
				self.Doc.tag_remove("CITATION", "insert linestart",
				"insert linestart + 1 lines")
				self.Doc.tag_remove("AVERTISSEMENT", "insert linestart",
				"insert linestart + 1 lines")
				self.Doc.tag_remove("CONSEIL", "insert linestart",
				"insert linestart + 1 lines")
				self.Doc.tag_remove("AUTEUR", "insert linestart",
				"insert linestart + 1 lines")
			except:
				pass

		if self.choixTypePar.get() != "Paragraphe":

			if "Titre 1" or "Titre 2" or "Titre 3" or "Titre 4"\
			or "Citation" or "Avertissement" or "Conseil" or "Source"\
			in self.Doc.tag_names("insert"):
				effacerAutresStyles()

			if self.choixTypePar.get() == "Titre 1":
				self.Doc.tag_add("T1", "insert linestart",
				"insert linestart + 1 lines")
				self.Styles_check.set(1)
			elif self.choixTypePar.get() == "Titre 2":
				self.Doc.tag_add("T2", "insert linestart",
				"insert linestart + 1 lines")
				self.Styles_check.set(2)
			elif self.choixTypePar.get() == "Titre 3":
				self.Doc.tag_add("T3", "insert linestart",
				"insert linestart + 1 lines")
				self.Styles_check.set(3)
			elif self.choixTypePar.get() == "Titre 4":
				self.Doc.tag_add("T4", "insert linestart",
				"insert linestart + 1 lines")
				self.Styles_check.set(4)
			elif self.choixTypePar.get() == "Citation":
				self.Doc.tag_add("CITATION", "insert linestart",
				"insert linestart + 1 lines")
				self.Styles_check.set(5)
			elif self.choixTypePar.get() == "Avertissement":
				self.Doc.tag_add("AVERTISSEMENT", "insert linestart",
				"insert linestart + 1 lines")
				self.Styles_check.set(6)
			elif self.choixTypePar.get() == "Conseil":
				self.Doc.tag_add("CONSEIL", "insert linestart",
				"insert linestart + 1 lines")
				self.Styles_check.set(7)
			elif self.choixTypePar.get() == "Source":
				self.Doc.tag_add("AUTEUR", "insert linestart",
				"insert linestart + 1 lines")
				self.Styles_check.set(8)

		else:
			effacerAutresStyles()
			self.Styles_check.set(0)
		self.SauvUndoRedo()
		self.Traqueur()

	def MenuContextuel(self,event):
		try:
			self.menu.destroy()
		except:
			pass

		self.menu = Menu(tearoff=0)
		self.menu.add_command(label="Couper", command=self.Couper)
		self.menu.add_command(label="Copier", command=self.Copier)
		self.menu.add_command(label="Coller", command=self.Coller)
		self.menu.add_command(label="Insérer l'image du Web",
		command=self.ImageWeb)
		self.menu.add_separator()
		self.menu.add_command(label="Supprimer", command=self.Suppr)

		try:
			self.frame.clipboard_get()
		except:
			self.menu.entryconfigure(2, state='disabled')

		try:
			self.Doc.get(SEL_FIRST, SEL_LAST)
		except:
			self.menu.entryconfigure(0, state='disabled')
			self.menu.entryconfigure(1, state='disabled')
			self.menu.entryconfigure(5, state='disabled')

		if self.cheminFichier == "":
			self.menu.entryconfigure(0, state='disabled')
			self.menu.entryconfigure(2, state='disabled')
			self.menu.entryconfigure(3, state='disabled')
			self.menu.entryconfigure(5, state='disabled')

		try:
			urlImage = self.frame.clipboard_get()
			protocoles = ["http://", "https://", "ftp://", "sftp://"]
			for protocole in protocoles:
				if re.search("^http://", urlImage) == None or \
				re.search("(jpg)|(jpeg)|(png)|(webp)|(bmp)|(tif)|(tiff)|(gif)|\
				(eps)|(ppm)|(xbm)|(im)|(msp)|(pcx)|(spi)\.$", urlImage) == None:
					self.menu.entryconfigure(3, state='disabled')
		except:
			self.menu.entryconfigure(3, state='disabled')

		self.menu.post(event.x_root, event.y_root)

	def EffacerMenu(self,event):
		try:
			self.menu.destroy()
		except:
			pass

	def GenLiens(self, toto=0):
		protocoles = ["http://", "https://", "ftp://", "sftp://"]
		for protocole in protocoles:
			chaineDoc = self.Doc.get(0.0, END)
			debutLien = '0.0'
			finLien = '0.0'

			i = 0
			while i < chaineDoc.count(protocole):
				debutLien = self.Doc.search(protocole, debutLien+'+1c')
				finLien = self.Doc.search(" ", debutLien)
				self.Doc.tag_add("LIEN", debutLien, finLien)
				i += 1

	def InfosBarreEtat(self, ouverture=False):
		document = self.Doc.get(0.0, END)

		self.nbLignes.configure(text=str(len(document.split('\n'))-1))
		self.nbMots.configure(text=str(len(document.split())))
		if ouverture == True:
			self.pos.configure(text='0.0')
		else:
			self.pos.configure(text=self.Doc.index(INSERT))

	def Traqueur(self, toto=0, forcer="", pos=False):
		# Icône de sauvegarde
		if Codeur(self.balises, self.Doc.dump(0.0, END), self.image) !=\
		self.fichierVerif:
			self.boutonEnr.config(image=self.i2)
			self.etatSauv.configure(text="Modifications non enregistrées !")
		else:
			self.boutonEnr.config(image=self.i1)
			self.etatSauv.configure(text="Enregistré")

		if forcer == "":
			self.Doc.unbind("<KeyRelease>")
			self.Doc.bind("<KeyRelease>", self.Traqueur)

		# Undo Redo
		if self.indexAR == 0:
			self.boutonUndo.configure(state=DISABLED)
		else:
			self.boutonUndo.configure(state=NORMAL)

		if self.indexAR == self.indexMaxAR:
			self.boutonRedo.configure(state=DISABLED)
		else:
			self.boutonRedo.configure(state=NORMAL)

		# Méthodes de gestion des boutons de barre d'outil ou de menu
		def ActiverGras():
			self.boutonGras.configure(relief=SUNKEN, overrelief=SUNKEN)
			self.Gras_check.set(1)

		def DesactiverGras():
			self.boutonGras.configure(relief=FLAT, overrelief=RAISED)
			self.Gras_check.set(0)

		def ActiverCode():
			self.boutonCode.configure(relief=SUNKEN, overrelief=SUNKEN)
			self.Code_check.set(1)

		def DesactiverCode():
			self.boutonCode.configure(relief=FLAT, overrelief=RAISED)
			self.Code_check.set(0)

		# Mise en force de bouton
		if forcer=="GRAS":
			if pos==True: ActiverGras()
			else: DesactiverGras()

		if forcer=="CODE":
			if pos==True: ActiverCode()
			else: DesactiverCode()

		# Sinon, gestion automatique de l'état des boutons
		try:
			if forcer != "GRAS":
				if "GRAS" in self.Doc.tag_names("insert"):
					ActiverGras()
				else:
					DesactiverGras()

			if forcer != "CODE":
				if "CODE" in self.Doc.tag_names("insert"):
					ActiverCode()
				else:
					DesactiverCode()

			if "JAUNE" in self.Doc.tag_names("insert"):
				self.boutonSurlignRien.configure(relief=FLAT, overrelief=RAISED)
				self.boutonSurlignJaune.configure(relief=SUNKEN,
				overrelief=SUNKEN)
				self.boutonSurlignVert.configure(relief=FLAT, overrelief=RAISED)
				self.boutonSurlignBleu.configure(relief=FLAT, overrelief=RAISED)
				self.Surligner_check.set(1)
			elif "VERT" in self.Doc.tag_names("insert"):
				self.boutonSurlignRien.configure(relief=FLAT, overrelief=RAISED)
				self.boutonSurlignJaune.configure(relief=FLAT,
				overrelief=RAISED)
				self.boutonSurlignVert.configure(relief=SUNKEN,
				overrelief=SUNKEN)
				self.boutonSurlignBleu.configure(relief=FLAT, overrelief=RAISED)
				self.Surligner_check.set(2)
			elif "BLEU" in self.Doc.tag_names("insert"):
				self.boutonSurlignRien.configure(relief=FLAT, overrelief=RAISED)
				self.boutonSurlignJaune.configure(relief=FLAT,
				overrelief=RAISED)
				self.boutonSurlignVert.configure(relief=FLAT, overrelief=RAISED)
				self.boutonSurlignBleu.configure(relief=SUNKEN,
				overrelief=SUNKEN)
				self.Surligner_check.set(3)
			else:
				self.boutonSurlignRien.configure(relief=FLAT, overrelief=RAISED)
				self.boutonSurlignJaune.configure(relief=FLAT,
				overrelief=RAISED)
				self.boutonSurlignVert.configure(relief=FLAT, overrelief=RAISED)
				self.boutonSurlignBleu.configure(relief=FLAT, overrelief=RAISED)
				self.Surligner_check.set(0)

		except:
			pass

		if "T1" in self.Doc.tag_names("insert"):
			self.choixTypePar.set("Titre 1")
			self.Styles_check.set(1)
		elif "T2" in self.Doc.tag_names("insert"):
			self.choixTypePar.set("Titre 2")
			self.Styles_check.set(2)
		elif "T3" in self.Doc.tag_names("insert"):
			self.choixTypePar.set("Titre 3")
			self.Styles_check.set(3)
		elif "T4" in self.Doc.tag_names("insert"):
			self.choixTypePar.set("Titre 4")
			self.Styles_check.set(4)
		elif "CITATION" in self.Doc.tag_names("insert"):
			self.choixTypePar.set("Citation")
			self.Styles_check.set(5)
		elif "AVERTISSEMENT" in self.Doc.tag_names("insert"):
			self.choixTypePar.set("Avertissement")
			self.Styles_check.set(6)
		elif "CONSEIL" in self.Doc.tag_names("insert"):
			self.choixTypePar.set("Conseil")
			self.Styles_check.set(7)
		elif "AUTEUR" in self.Doc.tag_names("insert"):
			self.choixTypePar.set("Source")
			self.Styles_check.set(8)
		else:
			self.choixTypePar.set("Paragraphe")
			self.Styles_check.set(0)


def extract_func(command, data_dict):
    command = command.split('||')
    town = command[0]
    population = int(command[1])
    gold = int(command[2])

    if town not in data_dict:
        data_dict[town] = [population, gold]
    else:
        data_dict[town][0] += population
        data_dict[town][1] += gold

    return data_dict

def sail_func(command, data_dict):
    command = command.split('=>')
    current_command = command[0]

    if current_command == 'Plunder':
        town = command[1]
        people = int(command[2])
        gold = int(command[3])

        data_dict[town][0] -= people
        data_dict[town][1] -= gold

        print(f"{town} plundered! {gold} gold stolen, {people} citizens killed.")

        if data_dict[town][0] <= 0 or data_dict[town][1] <= 0:
            del data_dict[town]
            print(f"{town} has been wiped off the map!")

    elif current_command == 'Prosper':
        town = command[1]
        gold = int(command[2])

        if gold > 0:
            data_dict[town][1] += gold
            print(f"{gold} gold added to the city treasury. {town} now has {data_dict[town][1]} gold.")
        else:
            print("Gold added cannot be a negative number!")

    return data_dict

def pirates():
    data_dict = {}
    condition = False
    while True:
        command = input()

        if command == 'End':
            break
        elif command != 'Sail' and not condition:
            data_dict = extract_func(command, data_dict)

        elif command == 'Sail':
            condition = True
            continue

        elif condition:
            data_dict = sail_func(command, data_dict)

    print(f'Ahoy, Captain! There are {len(data_dict)} wealthy settlements to go to:')

    for data in data_dict:
        town = data
        current_population = data_dict[data][0]
        current_gold = data_dict[data][1]
        print(f'{town} -> Population: {current_population} citizens, Gold: {current_gold} kg')

pirates()

# moe reshenie predi lekciqta
# cities_dict = {}
#
# while True:
#     info = input()
#
#     if info == "Sail":
#         break
#     cities_info = info.split("||")
#     city = cities_info[0]
#     population = int(cities_info[1])
#     gold = int(cities_info[2])
#
#     if city in cities_dict.keys():
#         cities_dict[city][0] += population
#         cities_dict[city][1] += gold
#     else:
#         cities_dict[city] = [population, gold]
#
# while True:
#     text = input()
#
#     if text == "End":
#         break
#
#     to_do = text.split("=>")
#     command = to_do[0]
#     town = to_do[1]
#
#     if command == "Plunder":
#         people = int(to_do[2])
#         gold = int(to_do[3])
#
#         cities_dict[town][0] -= people
#         cities_dict[town][1] -= gold
#         print(f"{town} plundered! {gold} gold stolen, {people} citizens killed.")
#
#         if cities_dict[town][0] == 0 or cities_dict[town][1] == 0:
#             del cities_dict[town]
#             print(f"{town} has been wiped off the map!")
#
#     else:
#         gold = int(to_do[2])
#
#         if gold < 0:
#             print(f"Gold added cannot be a negative number!")
#         else:
#             cities_dict[town][1] += gold
#             print(f"{gold} gold added to the city treasury. {town} now has {cities_dict[town][1]} gold.")
#
#
# if len(cities_dict.keys()) == 0:
#     print("Ahoy, Captain! All targets have been plundered and destroyed!")
# else:
#     count = len(cities_dict.keys())
#     print(f"Ahoy, Captain! There are {count} wealthy settlements to go to:")
#     for city in cities_dict.keys():
#         print(f"{city} -> Population: {cities_dict[city][0]} citizens, Gold: {cities_dict[city][1]} kg")


from flask import Blueprint, render_template, redirect, request, flash
from . import db
from .models import Deck, Card
from datetime import datetime

views = Blueprint('views', __name__)

@views.route('/')
def index():
    return render_template('index.html')

@views.route('/dashboard/<username>')
def dashboard(username):
    decks = Deck.query.filter_by(creator=username).all()
    return render_template('dashboard.html', username=username, decks=decks)

@views.route('/begin/<deck_name>')
def begin(deck_name):
    t = datetime.now()
    deck = Deck.query.filter_by(deck_name=deck_name).first()
    deck.last_reviewed = t
    db.session.commit()

    return redirect('/review/' + deck_name)

@views.route('/review/<deck_name>')
def review(deck_name):
    card = Card.query.filter_by(part_of_deck=deck_name, card_id=1).first()
    if card == None:
        flash('Please create a card to review it.')
        return render_template('create_card.html', deck_name=deck_name)

    deck = Deck.query.filter_by(deck_name=deck_name).first()
    username = deck.creator
    return render_template('review.html',
                           card=card,
                           deck_name=deck_name,
                           username=username)

@views.route('/review/<deck_name>/<card_id>', methods=["GET", "POST"])
def review_next(deck_name, card_id):
    if request.method == "POST":
        partialscore = request.values.get('partialscore')

        c = Card.query.filter_by(part_of_deck=deck_name,
                                 card_id=card_id).first()
        c.partial = int(partialscore)

        db.session.commit()

        cards = Card.query.filter_by(part_of_deck=deck_name).all()
        total = 0
        for cd in cards:
            total = total + cd.partial

        count = Card.query.filter_by(part_of_deck=deck_name).count()
        new_score = int(total / count)

        deck = Deck.query.filter_by(deck_name=deck_name).first()

        username = deck.creator
        deck.score = new_score
        db.session.commit()

        card_id = int(card_id) + 1
        card = Card.query.filter_by(part_of_deck=deck_name,
                                    card_id=card_id).first()
        if card == None:
            return redirect('/dashboard/' + username)

        return render_template('review.html',
                               card=card,
                               deck_name=deck_name,
                               username=username)
    else:
        card = Card.query.filter_by(part_of_deck=deck_name,
                                    card_id=card_id).first()
        return render_template('review.html', card=card, deck_name=deck_name)

@views.route('/about')
def about():
    return render_template('about.html')

@views.route('/all_cards/<deck_name>')
def all_cards(deck_name):
    cards = Card.query.filter_by(part_of_deck=deck_name).all()
    deck = Deck.query.filter_by(deck_name=deck_name).first()
    print(deck)
    username = deck.creator
    return render_template('all_cards.html',
                           cards=cards,
                           deck_name=deck_name,
                           username=username)

@views.route('/create_card/<deck_name>')
def create_card(deck_name):
    return render_template('create_card.html', deck_name=deck_name)

@views.route('/create_card/<deck_name>', methods=["POST"])
def created_card(deck_name):
    front = request.form.get('front')
    back = request.form.get('back')

    if front == "" or back == "":
        flash('Card cannot be empty. Please try again.')
        return redirect('/create_card/' + deck_name)

    count = Card.query.filter_by(part_of_deck=deck_name).count()
    count = count + 1
    card = Card.query.filter_by(front=front, back=back,part_of_deck=deck_name).first()
    if card:
        flash('Card already exists')
        return redirect('/create_card/' + deck_name)

    new_card = Card(card_id=count,
                    part_of_deck=deck_name,
                    front=front,
                    back=back)

    db.session.add(new_card)
    db.session.commit()

    cards = Card.query.filter_by(part_of_deck=deck_name).all()
    return render_template('all_cards.html', cards=cards, deck_name=deck_name)

@views.route('/create_deck/<username>')
def create_deck(username):
    return render_template('create_deck.html', username=username)

@views.route('/create_deck/<username>', methods=["POST"])
def created_deck(username):
    deck_name = request.form.get('deck_name')

    count = Deck.query.count()
    count = count + 1
    deck = Deck.query.filter_by(deck_name=deck_name).first()

    if deck_name == "":
        flash('Deck name cannot be empty. Please try again.')
        return redirect('/create_deck/' + username)

    if deck:
        flash('Deck already exists')
        return redirect('/create_deck/' + username)

    new_deck = Deck(deck_id=count,
                    deck_name=deck_name,
                    creator=username,
                    score=None,
                    is_public=True)

    db.session.add(new_deck)
    db.session.commit()

    return redirect('/dashboard/' + username)

@views.route('/edit_card/<deck_name>/<card_id>')
def edit_card(deck_name, card_id):
    card = Card.query.filter_by(part_of_deck=deck_name,
                                card_id=card_id).first()

    return render_template('edit_card.html', card=card)

@views.route('/edit_card/<deck_name>/<card_id>', methods=["POST"])
def edited_card(deck_name, card_id):
    front = request.form.get('front')
    back = request.form.get('back')

    if front == "" or back == "":
        flash('Card cannot be empty. Please try again.')
        return redirect('/edit_card/' + deck_name + '/' + card_id)

    card = Card.query.filter_by(front=front, back=back,part_of_deck=deck_name).first()
    if card:
        flash('Card already exists')
        return redirect('/create_card/' + deck_name)

    Card.query.filter_by(card_id=card_id,
                         part_of_deck=deck_name).update(dict(front=front))
    Card.query.filter_by(card_id=card_id,
                         part_of_deck=deck_name).update(dict(back=back))
    db.session.commit()

    cards = Card.query.filter_by(part_of_deck=deck_name).all()
    return render_template('all_cards.html', cards=cards, deck_name=deck_name)

@views.route('/delete_card/<deck_name>/<card_id>')
def delete_card(deck_name, card_id):
    card = Card.query.filter_by(part_of_deck=deck_name,
                                card_id=card_id).first()

    db.session.delete(card)
    db.session.commit()

    return redirect('/all_cards/' + deck_name)

@views.route('/delete_deck/<deck_name>')
def delete_deck(deck_name):
    cards = Card.query.filter_by(part_of_deck=deck_name).all()
    for card in cards:
        db.session.delete(card)
    db.session.commit()

    deck = Deck.query.filter_by(deck_name=deck_name).first()
    username = deck.creator
    db.session.delete(deck)
    db.session.commit()

    return redirect('/dashboard/' + username)

@views.route('/edit_deck/<username>/<deck_name>')
def edit_deck(deck_name,username):
    deck = Deck.query.filter_by(deck_name=deck_name).first()
    return render_template('edit_deck.html', deck=deck,username=username)

@views.route('/edit_deck/<username>/<deck_name>', methods=["POST"])
def edited_deck(deck_name,username):
    new_deck_name = request.form.get('deck_name')

    deck = Deck.query.filter_by(deck_name=new_deck_name,creator=username).first()

    if deck:
        flash('Deck already exists')
        return redirect('/edit_deck/'+username+'/' + deck_name)

    Card.query.filter_by(part_of_deck=deck_name).update(dict(part_of_deck=new_deck_name))

    Deck.query.filter_by(deck_name=deck_name).update(
        dict(deck_name=new_deck_name))
    deck = Deck.query.filter_by(deck_name=new_deck_name).first()
    username = deck.creator
    db.session.commit()

    return redirect('/dashboard/' + username)


import math

def polynomial(x, coefficients):
    result = 0
    for i, coef in enumerate(coefficients):
        result += coef * x ** (max_exponent - i)
    return result

def integral(a, b):
    num_segments = int((b - a) / ((b - a) / 1000))
    integral_sum = 0.5 * (polynomial(a, arr) + polynomial(b, arr))
    for i in range(1, num_segments):
        integral_sum += polynomial(a + i * ((b - a) / 1000), arr)
    return ((b - a) / 1000) * integral_sum

max_exponent = int(input())
arr = []
n = 0
while True:
    n = int(input())
    if n == -999:
        break
    arr.append(n)

a = float(input())
b = float(input())

integral_result = integral(a, b)
print(integral_result)


N,Y=map(int, input().split())      # (2)数字が2つ以上で別々に受け取り  入力例:A B

for ii in range(N+1):
    for jj in range(N+1-ii):
            kk = N-ii-jj
            val = 10000*ii + 5000*jj + 1000*kk
            if val == Y:
                print(ii, jj, kk)
                exit()
print("-1 -1 -1")


'''
n = int(input('请输入加油站数量：'))
a = []  # a[i][0]存储第i个加油站里离起点距离，a[i][0]存储第i个加油站可加油量
for i in range(n):
    a.append(list(map(int, input().split())))
b = []  # b[i][0]存储加加油站的编号，b[i][1]存储该加油站的可加油量

oil = int(input("初始油量："))
home = int(input('家离起点距离：'))
#初始化加油信息
'''
n = 7
a = [[10, 4,0], [15, 7,1], [18, 6,2], [31, 12,3], [35, 16,4], [36, 10,5], [42, 9,6]]
f = [False]*(n+1)
b = []
oil = 23    # 起始油量
home = 50    # 终点距离
a.append([home,0,7])
n+=1
loc=0
while a[loc][1]!=0:
    flag=True
    o=oil
    tail=0
    sl=0
    while flag:
        o-=a[tail][0]
        if o<0:
            break
        tail+=1
    need=a[tail+1][0]-a[tail][0]
    ra=a[loc:tail+1]
    for j in range(len(ra)-1):
        max=j
        for g in range (j,len(ra)):
            if ra[j][1]<ra[g][1]:
                max=g
        ra[j],ra[max]=a[max],a[j]
    oilget=0
    print(ra)
    for j in range(len(ra)):
        oilget+=ra[j][1]
        sl+=1
        f[ra[j][2]]=True
        if need-oilget<=0:
            break
    oil+=oilget
    loc+=tail
# 输出加油站的信息：
print(f'最少的加油次数为：{sl}')
s = '此次加油站的编号为：'
for i in range(n-1):
    if f[i]:
        s += str(i)+f'{a[i]}'+'、'
print(s)


import requests

def check_hash(url, hash_):
    """
    Checks that the given double 256-hash exists at
    twitter url.
    """
    try:
        resp = requests.get(url)
        content = resp.text
        present = hash_ in content
        return present, ""
    except Exception:
        return None

if __name__ == '__main__':
    URL = "https://twitter.com/HashesSparkl/status/1008182155057360898"
    HASH = "a8e26fa85a95a531ebd98b4454d17790430cc4a11ce157e2ad051f7c3c128ce8"
    print(check_hash(URL, HASH))


# Flip
# https://www.interviewbit.com/problems/flip/
#
# You are given a binary string(i.e. with characters 0 and 1) S consisting of characters
# S1, S2, …, SN. In a single operation, you can choose two indices L and R such that
# 1 ≤ L ≤ R ≤ N and flip the characters SL, SL+1, …, SR. By flipping, we mean change
# character 0 to 1 and vice-versa.
#
# Your aim is to perform ATMOST one operation such that in final string number of 1s is
# maximised. If you don’t want to perform the operation, return an empty array. Else,
# return an array consisting of two elements denoting L and R. If there are multiple
# solutions, return the lexicographically smallest pair of L and R.
#
# Notes:
#
# - Pair (a, b) is lexicographically smaller than pair (c, d) if a < c or, if a == c and b < d.
#
# For example,
#
# If the array is
#
# S = 010
#
# Pair of [L, R] | Final string
# _______________|_____________
# [1 1]          | 110
# [1 2]          | 100
# [1 3]          | 101
# [2 2]          | 000
# [2 3]          | 001
#
# We see that two pairs [1, 1] and [1, 3] give same number of 1s in final string. So, we return [1, 1].
#
# Another example,
# If S = 111
# No operation can give us more than three 1s in final string. So, we return empty array [].
#
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

class Solution:
    # @param A : string
    # @return a list of integers
    def flip(self, A):
        max_diff = diff = start = 0
        ans = None

        for i, a in enumerate(A):
            diff += (1 if a is '0' else -1)

            if diff < 0:
                diff = 0
                start = i + 1
                continue

            if diff > max_diff:
                max_diff = diff
                ans = [start, i]

        return [] if ans is None else (ans[0] + 1, ans[1] + 1)

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

if __name__ == "__main__":
    s = Solution()
    print(s.flip('101'))


import discord

from discord import app_commands
from discord.ext import commands

PATRON_PERK_ROLES = [605349824472154134, 683559116731318423]
HELPER_ROLE = 705550299699478609

class NoConfigFailure(commands.CheckFailure):
    pass

async def helper_check(bot, user):
    try:
        support_member = await bot.get_guild(594276321937326091).fetch_member(user.id)
    except discord.NotFound:
        return False
    else:
        if any(r.id == HELPER_ROLE for r in support_member.roles):
            return True
        else:
            return False

async def check_guild_permissions(intr, perms, check=all):
    if await intr.client.is_owner(intr.user):
        return True
    is_owner = await intr.client.is_owner(intr.user)
    if is_owner:
        return True

    if intr.guild is None:
        raise commands.CheckFailure('You must be in a guild to run this command!')
    if intr.guild_id == 594276321937326091:
        # custom message for the support server
        raise commands.CheckFailure("You should run this command in your server! Get the invite link with `+invite`.")
    if await helper_check(intr.client, intr.user):
        return True

    resolved = intr.user.resolved_permissions
    return check(getattr(resolved, name, None) == value for name, value in perms.items())

def manage_guild():
    async def pred(interaction: discord.Interaction):
        perms = await check_guild_permissions(interaction, {'manage_guild': True})
        if not perms:
            raise commands.CheckFailure('You must have `Manage Server` permissions to use this command!')
        return True
    return app_commands.check(pred)

def is_patron_pred(ctx):
    if ctx.author.id in ctx.bot.owner_ids:
        return True

    guild = ctx.bot.get_guild(594276321937326091)
    if not guild:
        return False

    member = guild.get_member(ctx.author.id)
    if not member:
        return False

    return any(r.id in PATRON_PERK_ROLES for r in member.roles)

def is_patron():
    return commands.check(is_patron_pred)

async def before_invoke(ctx):
    config_type = getattr(ctx, 'config_type', None)
    if not config_type:
        return

    # invalidate = getattr(ctx, 'invalidate', False)
    error = getattr(ctx, 'error_without_config', False)
    channel = getattr(ctx, 'custom_channel', ctx.channel)

    if config_type in ['donationboard', 'trophyboard', 'lastonlineboard']:
        ctx.config = await ctx.bot.utils.board_config(channel.id)

    elif config_type == 'event':
        ctx.config = await ctx.bot.utils.event_config(ctx.guild.id)

    elif config_type == 'donationlog':
        ctx.config = await ctx.bot.utils.log_config(channel.id, 'donation')

    elif config_type == 'trophylog':
        ctx.config = await ctx.bot.utils.log_config(channel.id, 'trophy')

    elif config_type == 'legendlog':
        ctx.config = await ctx.bot.utils.log_config(channel.id, 'legend')

    if error and not ctx.config:
        raise NoConfigFailure(f'Please create a {config_type} with `+help add {config_type}`')

async def after_invoke(ctx):
    if not getattr(ctx, 'invalidate', False):
        return
    config_type = getattr(ctx, 'config_type', None)
    if not config_type:
        return

    if not getattr(ctx, 'config', None):
        return
    return ctx

def requires_config(config_type, error=False):
    async def pred(ctx):
        ctx.before_invoke = before_invoke
        ctx.after_invoke = after_invoke
        ctx.config_type = config_type
        ctx.error_without_config = error
        return True
    return commands.check(pred)


#!/usr/bin/env python3
# -*- coding: utf-8 -*-

from selenium import webdriver
import pickle
import sys

url_ps4 = "https://m.cafe.naver.com/jgameshop/4228"  # JGame NaverCafe Mobile Page Used PS4 Titles

def print_games(games, start=0):
    """
    :param games: 게임목록 리스트
    :param start: 출력을 시작할 행
    :return:
    """
    current = -1
    for i in games:
        current += 1
        if current < start:
            continue
        if i[0] == '#':
            continue
        print(i)

def check_equal_lists(list1, list2):
    for i in list1:
        if i not in list2:
            return False
    for j in list2:
        if j not in list1:
            return False
    return True

# 지난 정보 로딩
try:
    games_ps4_old = []
    f = open('ps4', 'rb')
    games_ps4_old = pickle.load(f)
    f.close()
except:
    print("ERROR : ps4 file read error")
finally:
    pass
    # print_games(games_ps4_old, 11)

# Chrome Headless 웹드라이버 설정
options = webdriver.ChromeOptions()
options.add_argument('headless')
driver = webdriver.Chrome('chromedriver', options=options)

# 새 정보 읽기
driver.get(url_ps4)
games_ps4_new = driver.find_element_by_xpath('//*[@id="postContent"]').text.split('\n')  # '\n' 으로 끊어서 List로
driver.quit()
# print(games_ps4_new[11:])

if check_equal_lists(games_ps4_old, games_ps4_new):
    print("변경이 없으므로 프로그램을 종료합니다.")
    sys.exit()

# 새 파일로 덮어쓰기
try:
    f = open('ps4', 'wb')
    pickle.dump(games_ps4_new, f)
    f.close()
except:
    print("ERROR : ps4 file write error")
finally:
    pass

# 게임변경 검색
games_ps4_sold = []
games_ps4_incomming = []
for old in games_ps4_old:
    if old not in games_ps4_new:
        games_ps4_sold.append(old)

for new in games_ps4_new:
    if new not in games_ps4_old:
        games_ps4_incomming.append(new)

print("팔린 PS4 Games")
print(games_ps4_sold)
print("새로들어온 PS4 Games")
print(games_ps4_incomming)


import torch.nn as nn
import torch
import numpy as np
import matplotlib.pyplot as plt
from torch.utils.data.dataset import TensorDataset
from torch.utils.data.dataloader import DataLoader
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split

iris = load_iris()
X = iris['data']
y = iris['target']

X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=1./3, random_state=1)

X_train_norm = (X_train - np.mean(X_train)) / np.std(X_train)
X_train_norm = torch.from_numpy(X_train_norm).float()
y_train = torch.from_numpy(y_train)
train_ds = TensorDataset(X_train_norm, y_train)
torch.manual_seed(1)
batch_size = 2
train_dl = DataLoader(train_ds, batch_size, shuffle=True)

class Model(nn.Module):
    def __init__(self, input_size, hidden_size, output_size) -> None:
        super().__init__()
        self.layer1 = nn.Linear(input_size, hidden_size)
        self.layer2 = nn.Linear(hidden_size, output_size)

    def forward(self, x):
        x = self.layer1(x)
        x = nn.Sigmoid()(x)
        x = self.layer2(x)
        x = nn.Softmax(dim=1)(x)
        return x

input_size = X_train_norm.shape[1]
hidden_size = 16
output_size = 3
model = Model(input_size, hidden_size, output_size)

learning_rate = 0.001
loss_fn = nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)

num_epochs = 100
loss_hist = [0] * num_epochs
accuracy_hist = [0] * num_epochs
for epoch in range(num_epochs):
    for x_batch, y_batch in train_dl:
        # 1 gen pred
        pred = model(x_batch)
        # 2 calc loss
        loss = loss_fn(pred, y_batch)
        # 3 compute grad
        loss.backward()
        # 5 update prameters
        optimizer.step()
        # 6 reset grads
        optimizer.zero_grad()
        loss_hist[epoch] += loss.item() * y_batch.size(0)
        is_correct = (torch.argmax(pred, dim=1) == y_batch).float()
        accuracy_hist[epoch] += is_correct.mean()
    loss_hist[epoch] /= len(train_dl.dataset)
    accuracy_hist[epoch] /= len(train_dl.dataset)

fig = plt.figure(figsize=(12, 5))
ax = fig.add_subplot(1, 2, 1)
ax.plot(loss_hist, lw=3)
ax.set_title('Training loss', size=15)
ax.set_xlabel('Epoch', size=15)
ax.tick_params(axis='both', which='major', labelsize=15)
ax = fig.add_subplot(1, 2, 2)
ax.plot(accuracy_hist, lw=3)
ax.set_title('Training accuracy', size=15)
ax.set_xlabel('Epoch', size=15)
ax.tick_params(axis='both', which='major', labelsize=15)
plt.show()

X_test_norm = (X_test - np.mean(X_train)) / np.std(X_train)
X_test_norm = torch.from_numpy(X_test_norm).float()
y_test = torch.from_numpy(y_test)
y_pred = model(X_test_norm)
correct = (torch.argmax(y_pred, dim=1) == y_test).float()
accuracy = correct.mean()
print(f'Test Acc.: {accuracy:.4f}')


from tkinter import *
from tkinter import ttk
import tkinter as tk

class DeviceConfigRoutingView(tk.Toplevel):
    def __init__(self, rootWindow,controller, name, interfaces, dataOspf):
        super().__init__(rootWindow, height=673, width=762, bg="white", highlightbackground="#00A2FF", highlightthickness=4)
        self.controller = controller
        self.name = name
        self.interfaces = interfaces
        self.dataOspf = dataOspf
        self.resizable(width=True, height=True)
        #self.configure(background="#D9D9D9")
        self.geometry("530x450")
        self.title("Config Routing de {}.".format(name))
        self.update()
        self.data = {'ospf': {
                             'routerId': '0', 'processId': '1',
                             'interfaces': {}}}
        self.createView(name)

    def createView(self, name):
        imgBtnAccept = PhotoImage(file = 'Vista/assets/btn_accept_config.png')
        imgBtnCancel = PhotoImage(file = 'Vista/assets/btn_cancel_config.png')
        imgLineaBg = PhotoImage(file = 'Vista/assets/linea_bg.png')
        self.image = imgLineaBg

        titulo = Label(self)
        titulo.place(relx=0.3, rely=0.09, height=21, width=200)
        titulo.configure(disabledforeground="#a3a3a3")
        titulo.configure(font="-family {Andale Mono} -size 19")
        titulo.configure(foreground="#000000")
        titulo.configure(text="OSPF en {}".format(self.name))

        paramLabel = Label(self)
        paramLabel.place(relx=0.155, rely=0.211, relheight=0.05, relwidth=0.202)
        paramLabel.configure(font="-family {Andale Mono} -size 15")
        paramLabel.configure(text="Parámetros")

        paramLabel = Label(self)
        paramLabel.place(relx=0.6, rely=0.211, relheight=0.05, relwidth=0.302)
        paramLabel.configure(font="-family {Andale Mono} -size 15")
        paramLabel.configure(text="Config Actual")

        ridLabel = Label(self)
        ridLabel.place(relx=0.04, rely=0.3, relheight=0.05, relwidth=0.11)
        ridLabel.configure(text="Router ID",font="-family {Andale Mono} -size 10")

        ridLabel = Label(self)
        ridLabel.place(relx=0.04, rely=0.4, relheight=0.05, relwidth=0.25)
        ridLabel.configure(text="default-info originate",font="-family {Andale Mono} -size 10")

        self.ridEntry = Entry(self)
        self.ridEntry.place(relx=0.17, rely=0.3, relheight=0.05
                , relwidth=0.12)
        self.ridEntry.configure(takefocus="", background="#ABE0FF")
        self.ridEntry.configure(cursor="ibeam", font="-family {Andale Mono} -size 10")

        pidLabel = Label(self)
        pidLabel.place(relx=0.3, rely=0.3, relheight=0.05, relwidth=0.11)
        pidLabel.configure(text="PID",font="-family {Andale Mono} -size 10")
        self.chk_do = IntVar()
        defaultCheck = Checkbutton(self, var=self.chk_do, offvalue= 0, onvalue=1)
        defaultCheck.place(relx=0.32, rely=0.4, relwidth=0.150,  relheight=0.05)
        defaultCheck.configure(takefocus="")
        defaultCheck.configure(text="", font="-family {Andale Mono} -size 11")

        self.pidEntry = Entry(self)
        self.pidEntry.place(relx=0.4, rely=0.3, relheight=0.05
                , relwidth=0.05)
        self.pidEntry.configure(takefocus="", background="#ABE0FF")
        self.pidEntry.configure(cursor="ibeam", font="-family {Andale Mono} -size 10")

        paramLabel = Label(self)
        paramLabel.place(relx=0.015, rely=0.475, relheight=0.05, relwidth=0.5)
        paramLabel.configure(font="-family {Andale Mono} -size 15")
        paramLabel.configure(text="Interfaces OSPF")

        self.interfacesCombo = ttk.Combobox(self)
        self.interfacesCombo.place(relx=0.05, rely=0.6, relheight=0.05, relwidth=0.27)
        self.interfacesCombo.configure(values=self.interfaces, state='readonly', font="-family {Andale Mono} -size 10")
        self.interfacesCombo.current(0)
        self.currentInterface = self.interfacesCombo.get()
        self.interfacesCombo.bind("<<ComboboxSelected>>", self.comboboxCambio)
        self.interfacesCombo.bind("<Button-1>", self.changeCurrent)
        self.chk = IntVar()
        self.activarInterfaz = Checkbutton(self, var=self.chk, offvalue= 0, onvalue=1)
        self.activarInterfaz.place(relx=0.35, rely=0.6, relwidth=0.150,  relheight=0.05)
        self.activarInterfaz.configure(takefocus="")
        self.activarInterfaz.configure(text="Activar", font="-family {Andale Mono} -size 11")

        areaLabel = Label(self)
        areaLabel.place(relx=0.05, rely=0.7, relheight=0.05, relwidth=0.12)
        areaLabel.configure(font="-family {Andale Mono} -size 11")
        areaLabel.configure(text="Area")

        self.areaEntry = Entry(self)
        self.areaEntry.place(relx=0.21, rely=0.7, relheight=0.05
                , relwidth=0.05)
        self.areaEntry.configure(takefocus="", background="#ABE0FF")
        self.areaEntry.configure(cursor="ibeam", font="-family {Andale Mono} -size 10")

        costeLabel = Label(self)
        costeLabel.place(relx=0.015, rely=0.77, relheight=0.05, relwidth=0.2)
        costeLabel.configure(font="-family {Andale Mono} -size 11")
        costeLabel.configure(text="Coste OSPF")

        self.costeEntry = Entry(self)
        self.costeEntry.place(relx=0.21, rely=0.77, relheight=0.05
                , relwidth=0.05)
        self.costeEntry.configure(takefocus="", background="#ABE0FF")
        self.costeEntry.configure(cursor="ibeam", font="-family {Andale Mono} -size 10")

        helloLabel = Label(self)
        helloLabel.place(relx=0.015, rely=0.84, relheight=0.05, relwidth=0.2)
        helloLabel.configure(font="-family {Andale Mono} -size 11")
        helloLabel.configure(text="Hello Timer")

        self.helloEntry = Entry(self)
        self.helloEntry.place(relx=0.21, rely=0.84, relheight=0.05
                , relwidth=0.05)
        self.helloEntry.configure(takefocus="", background="#ABE0FF")
        self.helloEntry.configure(cursor="ibeam", font="-family {Andale Mono} -size 10")

        priLabel = Label(self)
        priLabel.place(relx=0.3, rely=0.73, relheight=0.05, relwidth=0.15)
        priLabel.configure(font="-family {Andale Mono} -size 11")
        priLabel.configure(text="Prioridad")

        self.priEntry = Entry(self)
        self.priEntry.place(relx=0.47, rely=0.73, relheight=0.05
                , relwidth=0.05)
        self.priEntry.configure(takefocus="", background="#ABE0FF")
        self.priEntry.configure(cursor="ibeam", font="-family {Andale Mono} -size 10")

        deadLabel = Label(self)
        deadLabel.place(relx=0.3, rely=0.81, relheight=0.05, relwidth=0.15)
        deadLabel.configure(font="-family {Andale Mono} -size 11")
        deadLabel.configure(text="Dead Timer")

        self.deadEntry = Entry(self)
        self.deadEntry.place(relx=0.47, rely=0.81, relheight=0.05
                , relwidth=0.05)
        self.deadEntry.configure(takefocus="", background="#ABE0FF")
        self.deadEntry.configure(cursor="ibeam", font="-family {Andale Mono} -size 10")

        scrollbar = Scrollbar(self)
        scrollbar.pack(side=RIGHT, fill=Y)
        textbox = Text(self)
        textbox.place(relx=0.58, rely=0.27, relheight=0.7, relwidth=0.4)
        textbox.insert(INSERT, self.dataOspf)
        # attach textbox to scrollbar
        textbox.config(yscrollcommand=scrollbar.set)
        scrollbar.config(command=textbox.yview)

        btnAccept = tk.Button(self,
                    text='Accept',
                    image=imgBtnAccept, compound='center',
                    fg="white", font=("Andale Mono", 10),
                    command=lambda:self.acceptClick())
        btnAccept.image = imgBtnAccept
        btnAccept.place(relx=0.08, rely=0.94)
        btnCancel = tk.Button(self, text='Cancel',
                           image=imgBtnCancel,font=("Andale Mono", 10) ,
                           compound='center', fg="white", command=lambda: self.destroy())
        btnCancel.image = imgBtnCancel
        btnCancel.place(relx=0.25, rely=0.94)
        raya = tk.Canvas(self)
        raya.place(relx=0.55, rely=0.226, relheight=0.651
                , relwidth=0.001)
        raya.configure(borderwidth="2")
        raya.configure(highlightbackground="#000000")
        raya.configure(insertbackground="black")
        raya.configure(relief="ridge")

    def acceptClick(self):
        self.currentInterface = self.interfacesCombo.get()
        self.data['ospf']['interfaces'].update({self.currentInterface: {}})
        self.data['ospf']['processId'] = self.pidEntry.get()
        self.data['ospf']['routerId'] = self.ridEntry.get()
        self.data['ospf']['default-originate'] = self.chk_do.get()
        if self.chk.get():
            self.data['ospf']['interfaces'][self.currentInterface]['area'] = self.areaEntry.get()
            self.data['ospf']['interfaces'][self.currentInterface]['coste'] = self.costeEntry.get()
            self.data['ospf']['interfaces'][self.currentInterface]['helloTimer'] = self.helloEntry.get()
            self.data['ospf']['interfaces'][self.currentInterface]['deadTimer'] = self.deadEntry.get()
            self.data['ospf']['interfaces'][self.currentInterface]['priority'] = self.priEntry.get()
        print(self.data)
        self.controller.createRouting(self, self.data, self.name)

    def changeCurrent(self, event):
        self.currentInterface = self.interfacesCombo.get()
        if self.chk.get():
            self.data['ospf']['interfaces'].update({self.currentInterface: {}})
            self.data['ospf']['interfaces'][self.currentInterface]['area'] = self.areaEntry.get()
            self.data['ospf']['interfaces'][self.currentInterface]['coste'] = self.costeEntry.get()
            self.data['ospf']['interfaces'][self.currentInterface]['helloTimer'] = self.helloEntry.get()
            self.data['ospf']['interfaces'][self.currentInterface]['deadTimer'] = self.deadEntry.get()
            self.data['ospf']['interfaces'][self.currentInterface]['priority'] = self.priEntry.get()

    def comboboxCambio(self,event):
        self.update()


r"""Animate the display or removal of a mobject from a scene.

.. manim:: CreationModule
    :hide_source:

    from manim import ManimBanner
    class CreationModule(Scene):
        def construct(self):
            s1 = Square()
            s2 = Square()
            s3 = Square()
            s4 = Square()
            VGroup(s1, s2, s3, s4).set_x(0).arrange(buff=1.9).shift(UP)
            s5 = Square()
            s6 = Square()
            s7 = Square()
            VGroup(s5, s6, s7).set_x(0).arrange(buff=2.6).shift(2 * DOWN)
            t1 = Text("Write", font_size=24).next_to(s1, UP)
            t2 = Text("AddTextLetterByLetter", font_size=24).next_to(s2, UP)
            t3 = Text("Create", font_size=24).next_to(s3, UP)
            t4 = Text("Uncreate", font_size=24).next_to(s4, UP)
            t5 = Text("DrawBorderThenFill", font_size=24).next_to(s5, UP)
            t6 = Text("ShowIncreasingSubsets", font_size=22).next_to(s6, UP)
            t7 = Text("ShowSubmobjectsOneByOne", font_size=22).next_to(s7, UP)

            self.add(s1, s2, s3, s4, s5, s6, s7, t1, t2, t3, t4, t5, t6, t7)

            texts = [Text("manim", font_size=29), Text("manim", font_size=29)]
            texts[0].move_to(s1.get_center())
            texts[1].move_to(s2.get_center())
            self.add(*texts)

            objs = [ManimBanner().scale(0.25) for _ in range(5)]
            objs[0].move_to(s3.get_center())
            objs[1].move_to(s4.get_center())
            objs[2].move_to(s5.get_center())
            objs[3].move_to(s6.get_center())
            objs[4].move_to(s7.get_center())
            self.add(*objs)

            self.play(
                # text creation
                Write(texts[0]),
                AddTextLetterByLetter(texts[1]),
                # mobject creation
                Create(objs[0]),
                Uncreate(objs[1]),
                DrawBorderThenFill(objs[2]),
                ShowIncreasingSubsets(objs[3]),
                ShowSubmobjectsOneByOne(objs[4]),
                run_time=3,
            )

            self.wait()

"""

__all__ = [
    "Create",
    "Uncreate",
    "DrawBorderThenFill",
    "Write",
    "Unwrite",
    "ShowPartial",
    "ShowIncreasingSubsets",
    "AddTextLetterByLetter",
    "ShowSubmobjectsOneByOne",
    "AddTextWordByWord",
]

import itertools as it
from typing import (
    TYPE_CHECKING,
    Callable,
    Dict,
    Iterable,
    Optional,
    Sequence,
    Tuple,
    Union,
)

import numpy as np
from colour import Color

if TYPE_CHECKING:
    from manim.mobject.svg.text_mobject import Text

from ..animation.animation import Animation
from ..animation.composition import Succession
from ..mobject.mobject import Group, Mobject
from ..mobject.types.opengl_surface import OpenGLSurface
from ..mobject.types.opengl_vectorized_mobject import OpenGLVMobject
from ..mobject.types.vectorized_mobject import VMobject
from ..utils.bezier import integer_interpolate
from ..utils.rate_functions import double_smooth, linear, smooth

class ShowPartial(Animation):
    """Abstract class for Animations that show the VMobject partially.

    Raises
    ------
    :class:`TypeError`
        If ``mobject`` is not an instance of :class:`~.VMobject`.

    See Also
    --------
    :class:`Create`, :class:`~.ShowPassingFlash`

    """

    def __init__(
        self, mobject: Union[VMobject, OpenGLVMobject, OpenGLSurface, None], **kwargs
    ):
        pointwise = getattr(mobject, "pointwise_become_partial", None)
        if not callable(pointwise):
            raise NotImplementedError("This animation is not defined for this Mobject.")
        super().__init__(mobject, **kwargs)

    def interpolate_submobject(
        self,
        submobject: Mobject,
        starting_submobject: Mobject,
        alpha: float,
    ) -> None:
        submobject.pointwise_become_partial(
            starting_submobject, *self._get_bounds(alpha)
        )

    def _get_bounds(self, alpha: float) -> None:
        raise NotImplementedError("Please use Create or ShowPassingFlash")

class Create(ShowPartial):
    """Incrementally show a VMobject.

    Parameters
    ----------
    mobject : :class:`~.VMobject`
        The VMobject to animate.

    Raises
    ------
    :class:`TypeError`
        If ``mobject`` is not an instance of :class:`~.VMobject`.

    Examples
    --------
    .. manim:: CreateScene

        class CreateScene(Scene):
            def construct(self):
                self.play(Create(Square()))

    See Also
    --------
    :class:`~.ShowPassingFlash`

    """

    def __init__(
        self,
        mobject: Union[VMobject, OpenGLVMobject, OpenGLSurface],
        lag_ratio: float = 1.0,
        **kwargs,
    ) -> None:
        super().__init__(mobject, lag_ratio=lag_ratio, **kwargs)

    def _get_bounds(self, alpha: float) -> Tuple[int, float]:
        return (0, alpha)

class Uncreate(Create):
    """Like :class:`Create` but in reverse.

    Examples
    --------
    .. manim:: ShowUncreate

        class ShowUncreate(Scene):
            def construct(self):
                self.play(Uncreate(Square()))

    See Also
    --------
    :class:`Create`

    """

    def __init__(
        self,
        mobject: Union[VMobject, OpenGLVMobject],
        rate_func: Callable[[float], float] = lambda t: smooth(1 - t),
        remover: bool = True,
        **kwargs,
    ) -> None:
        super().__init__(mobject, rate_func=rate_func, remover=remover, **kwargs)

class DrawBorderThenFill(Animation):
    """Draw the border first and then show the fill.

    Examples
    --------
    .. manim:: ShowDrawBorderThenFill

        class ShowDrawBorderThenFill(Scene):
            def construct(self):
                self.play(DrawBorderThenFill(Square(fill_opacity=1, fill_color=ORANGE)))
    """

    def __init__(
        self,
        vmobject: Union[VMobject, OpenGLVMobject],
        run_time: float = 2,
        rate_func: Callable[[float], float] = double_smooth,
        stroke_width: float = 2,
        stroke_color: str = None,
        draw_border_animation_config: Dict = {},  # what does this dict accept?
        fill_animation_config: Dict = {},
        **kwargs,
    ) -> None:
        self._typecheck_input(vmobject)
        super().__init__(vmobject, run_time=run_time, rate_func=rate_func, **kwargs)
        self.stroke_width = stroke_width
        self.stroke_color = stroke_color
        self.draw_border_animation_config = draw_border_animation_config
        self.fill_animation_config = fill_animation_config
        self.outline = self.get_outline()

    def _typecheck_input(self, vmobject: Union[VMobject, OpenGLVMobject]) -> None:
        if not isinstance(vmobject, (VMobject, OpenGLVMobject)):
            raise TypeError("DrawBorderThenFill only works for vectorized Mobjects")

    def begin(self) -> None:
        self.outline = self.get_outline()
        super().begin()

    def get_outline(self) -> Mobject:
        outline = self.mobject.copy()
        outline.set_fill(opacity=0)
        for sm in outline.family_members_with_points():
            sm.set_stroke(color=self.get_stroke_color(sm), width=self.stroke_width)
        return outline

    def get_stroke_color(self, vmobject: Union[VMobject, OpenGLVMobject]) -> Color:
        if self.stroke_color:
            return self.stroke_color
        elif vmobject.get_stroke_width() > 0:
            return vmobject.get_stroke_color()
        return vmobject.get_color()

    def get_all_mobjects(self) -> Sequence[Mobject]:
        return [*super().get_all_mobjects(), self.outline]

    def interpolate_submobject(
        self,
        submobject: Mobject,
        starting_submobject: Mobject,
        outline,
        alpha: float,
    ) -> None:  # Fixme: not matching the parent class? What is outline doing here?
        index: int
        subalpha: int
        index, subalpha = integer_interpolate(0, 2, alpha)
        if index == 0:
            submobject.pointwise_become_partial(outline, 0, subalpha)
            submobject.match_style(outline)
        else:
            submobject.interpolate(outline, starting_submobject, subalpha)

class Write(DrawBorderThenFill):
    """Simulate hand-writing a :class:`~.Text` or hand-drawing a :class:`~.VMobject`.

    Examples
    --------
    .. manim:: ShowWrite

        class ShowWrite(Scene):
            def construct(self):
                self.play(Write(Text("Hello", font_size=144)))

    .. manim:: ShowWriteReversed

        class ShowWriteReversed(Scene):
            def construct(self):
                self.play(Write(Text("Hello", font_size=144), reverse=True))
    """

    def __init__(
        self,
        vmobject: Union[VMobject, OpenGLVMobject],
        rate_func: Callable[[float], float] = linear,
        reverse: bool = False,
        **kwargs,
    ) -> None:
        run_time: Optional[float] = kwargs.pop("run_time", None)
        lag_ratio: Optional[float] = kwargs.pop("lag_ratio", None)
        run_time, lag_ratio = self._set_default_config_from_length(
            vmobject,
            run_time,
            lag_ratio,
        )
        self.reverse = reverse
        super().__init__(
            vmobject,
            rate_func=rate_func,
            run_time=run_time,
            lag_ratio=lag_ratio,
            **kwargs,
        )

    def _set_default_config_from_length(
        self,
        vmobject: Union[VMobject, OpenGLVMobject],
        run_time: Optional[float],
        lag_ratio: Optional[float],
    ) -> Tuple[float, float]:
        length = len(vmobject.family_members_with_points())
        if run_time is None:
            if length < 15:
                run_time = 1
            else:
                run_time = 2
        if lag_ratio is None:
            lag_ratio = min(4.0 / length, 0.2)
        return run_time, lag_ratio

    def reverse_submobjects(self) -> None:
        self.mobject.invert(recursive=True)

    def begin(self) -> None:
        if self.reverse:
            self.reverse_submobjects()
        super().begin()

    def finish(self) -> None:
        super().finish()
        if self.reverse:
            self.reverse_submobjects()

class Unwrite(Write):
    """Simulate erasing by hand a :class:`~.Text` or a :class:`~.VMobject`.

    Parameters
    ----------
    reverse : :class:`bool`
        Set True to have the animation start erasing from the last submobject first.

    Examples
    --------

    .. manim :: UnwriteReverseTrue

        class UnwriteReverseTrue(Scene):
            def construct(self):
                text = Tex("Alice and Bob").scale(3)
                self.add(text)
                self.play(Unwrite(text))

    .. manim:: UnwriteReverseFalse

        class UnwriteReverseFalse(Scene):
            def construct(self):
                text = Tex("Alice and Bob").scale(3)
                self.add(text)
                self.play(Unwrite(text, reverse=False))
    """

    def __init__(
        self,
        vmobject: VMobject,
        rate_func: Callable[[float], float] = linear,
        reverse: bool = True,
        **kwargs,
    ) -> None:

        run_time: Optional[float] = kwargs.pop("run_time", None)
        lag_ratio: Optional[float] = kwargs.pop("lag_ratio", None)
        run_time, lag_ratio = self._set_default_config_from_length(
            vmobject,
            run_time,
            lag_ratio,
        )
        super().__init__(
            vmobject,
            run_time=run_time,
            lag_ratio=lag_ratio,
            rate_func=lambda t: -rate_func(t) + 1,
            reverse=reverse,
            **kwargs,
        )

class ShowIncreasingSubsets(Animation):
    """Show one submobject at a time, leaving all previous ones displayed on screen.

    Examples
    --------

    .. manim:: ShowIncreasingSubsetsScene

        class ShowIncreasingSubsetsScene(Scene):
            def construct(self):
                p = VGroup(Dot(), Square(), Triangle())
                self.add(p)
                self.play(ShowIncreasingSubsets(p))
                self.wait()
    """

    def __init__(
        self,
        group: Mobject,
        suspend_mobject_updating: bool = False,
        int_func: Callable[[np.ndarray], np.ndarray] = np.floor,
        **kwargs,
    ) -> None:
        self.all_submobs = list(group.submobjects)
        self.int_func = int_func
        for mobj in self.all_submobs:
            mobj.set_opacity(0)
        super().__init__(
            group, suspend_mobject_updating=suspend_mobject_updating, **kwargs
        )

    def interpolate_mobject(self, alpha: float) -> None:
        n_submobs = len(self.all_submobs)
        index = int(self.int_func(alpha * n_submobs))
        self.update_submobject_list(index)

    def update_submobject_list(self, index: int) -> None:
        for mobj in self.all_submobs[:index]:
            mobj.set_opacity(1)

class AddTextLetterByLetter(ShowIncreasingSubsets):
    """Show a :class:`~.Text` letter by letter on the scene.

    Parameters
    ----------
    time_per_char : :class:`float`
        Frequency of appearance of the letters.

    .. tip::

        This is currently only possible for class:`~.Text` and not for class:`~.MathTex`

    """

    def __init__(
        self,
        text: "Text",
        suspend_mobject_updating: bool = False,
        int_func: Callable[[np.ndarray], np.ndarray] = np.ceil,
        rate_func: Callable[[float], float] = linear,
        time_per_char: float = 0.1,
        run_time: Optional[float] = None,
        **kwargs,
    ) -> None:
        # time_per_char must be above 0.06, or the animation won't finish
        self.time_per_char = time_per_char
        if run_time is None:
            run_time = np.max((0.06, self.time_per_char)) * len(text)

        super().__init__(
            text,
            suspend_mobject_updating=suspend_mobject_updating,
            int_func=int_func,
            rate_func=rate_func,
            run_time=run_time,
            **kwargs,
        )

class ShowSubmobjectsOneByOne(ShowIncreasingSubsets):
    """Show one submobject at a time, removing all previously displayed ones from screen."""

    def __init__(
        self,
        group: Iterable[Mobject],
        int_func: Callable[[np.ndarray], np.ndarray] = np.ceil,
        **kwargs,
    ) -> None:
        new_group = Group(*group)
        super().__init__(new_group, int_func=int_func, **kwargs)

    def update_submobject_list(self, index: int) -> None:
        current_submobjects = self.all_submobs[:index]
        for mobj in current_submobjects[:-1]:
            mobj.set_opacity(0)
        if len(current_submobjects) > 0:
            current_submobjects[-1].set_opacity(1)

# TODO, this is broken...
class AddTextWordByWord(Succession):
    """Show a :class:`~.Text` word by word on the scene. Note: currently broken."""

    def __init__(
        self,
        text_mobject: "Text",
        run_time: float = None,
        time_per_char: float = 0.06,
        **kwargs,
    ) -> None:
        self.time_per_char = time_per_char
        tpc = self.time_per_char
        anims = it.chain(
            *(
                [
                    ShowIncreasingSubsets(word, run_time=tpc * len(word)),
                    Animation(word, run_time=0.005 * len(word) ** 1.5),
                ]
                for word in text_mobject
            )
        )
        super().__init__(*anims, **kwargs)


"""Wind prediction model"""

import os
import pandas as pd
import numpy as np
from statsmodels.tsa.arima.model import ARIMAResults, ARIMA
from statsmodels.tsa.statespace.varmax import VARMAX, VARMAXResults
from typing import Tuple
from tqdm.autonotebook import trange
import statsmodels.api as sm

INTERVAL = pd.Timedelta(minutes=15)

def read_file(dir_path='./', processed=False) -> pd.DataFrame:
    if os.path.exists(dir_path+'ERDCSlow.hdf5') and processed:
        df = pd.read_hdf(dir_path+'ERDCSlow.hdf5', key='table', index_col='Time')
    else:
        df = pd.read_csv(dir_path + 'ERDCSlow.csv',
                        index_col='Time', parse_dates=['Time'])
        cols = []
        for col in df.columns:
            c = pd.to_numeric(df[col], errors='coerce', downcast='float')
            cols.append(c)
        df = pd.concat(cols, axis=1)

        df = df[['Speed', 'Direction', 'Temp']]
        df = df.dropna(axis=0, how='any')
        df.to_hdf(dir_path + '/ERDCSlow.hdf5', key='table')
    df['dx'] = np.cos(df.Direction)
    df['dy'] = np.sin(df.Direction)
    return df

def find_sequences(df, interval=pd.Timedelta(minutes=1), agg_fn='mean'):
    resampler = df.resample(interval)
    if agg_fn=='mean':
        dfm = resampler.mean()
    elif agg_fn=='max':
        dfm = resampler.max()
    elif isinstance(agg_fn, float):
        dfm = resampler.quantile(agg_fn)
    i, ii = 0, dfm.index[0]
    j, jj = 1, dfm.index[1]
    seqs = []
    while j < len(dfm):
        while i < len(dfm):
            if not np.isnan(dfm.Speed.iloc[i]):
                break
            i += 1
        j = i+1
        while j <= len(dfm):
            if j==len(dfm) or np.isnan(dfm.Speed.iloc[j]):
                seqs.append(dfm.iloc[i:j])
                i = j+1
                break
            j += 1

    for s in seqs:
        s.index.freq = interval

    return [s for s in seqs if len(s)>=4]

def pretrain(model_class, data: pd.DataFrame, exog=None, **kwargs) -> ARIMA:
    model = model_class(data, exog=exog, **kwargs)
    return model.fit()

def update(result: ARIMAResults, data: pd.DataFrame, exog, interval, append=True):
    if data.index[-1] - result.data.dates[-1] > interval:
        model = result.model.clone(data, exog=exog)
        result = model.fit(start_params=result.params)
    else:
        if append:
            result = result.append(data, exog=exog, refit=True)
        else:
            result = result.extend
    return result

def predict(result: ARIMAResults, data: pd.DataFrame, exog, interval, in_sample=True) -> Tuple[ARIMAResults, float]:
    if data.index[0] - result.data.dates[-1] > interval:
       result = result.apply(data, exog=exog)
    else:
        result = result.append(data, exog=exog)
    if in_sample:
        pred = result.predict(start=data.index[0], dynamic=False)
    else:
        # pred = result.forecast(steps=1)
        pred = result.predict(start=data.index[0], dynamic=0)
    return result, pred

def trial(
    interval, order, df, seq_kwargs={}, filter_fn=lambda df: df, split=0.25,
    endog_col='Speed', exog_cols=None
):
    df = filter_fn(df)
    seqs = find_sequences(df, interval, **seq_kwargs)
    # leave one out testing
    rmses = []
    rmses_persistent = []
    ntest = 0
    splits = int(len(seqs) * split)

    for i in trange(len(seqs), leave=False, desc='splits'):
        if isinstance(split, float) and 0<split<1:
            ntrain = int(len(seqs[i]) * (1-split))
            dtrain = [seqs[i].iloc[:ntrain]]
            dtest = [seqs[i].iloc[ntrain:]]
        else:
            if i==split:
                break
            dtest = [seqs[i]]
            dtrain = [seqs[j] for j in range(splits) if j!=i]

        endog = dtrain[0][endog_col]
        exog = exog_cols if exog_cols is None else dtrain[0][exog_cols]
        res = pretrain(sm.tsa.ARIMA, endog, exog=exog, order=order)
        for dft in dtrain[1:]:
            endog = dft[endog_col]
            exog = exog_cols if exog_cols is None else dft[exog_cols]
            res = update(res, endog, exog=exog, interval=interval)
        for dft in dtest:
            if dft.index[0] < res.data.dates[-1]:
                dft = dft.copy()
                dft.index += (res.data.dates[-1] - dft.index[0]) + (2 * interval)
                dft.index.freq = interval
            ntest += len(dft)
            # predictions = []
            # for k in trange(len(dft.Speed), leave=False, desc='instance'):
            #     res, pred = predict(res, dft.Speed.iloc[k:k+1], interval)
            #     predictions.append(pred)
            # pred = pd.concat(predictions)
            endog = dft[endog_col]
            exog = exog_cols if exog_cols is None else dft[exog_cols]
            res, pred = predict(res, endog, exog, interval)
            rmses.append(sm.tools.eval_measures.rmse(pred, endog) * len(dft))
            rmses_persistent.append(sm.tools.eval_measures.rmse(endog.iloc[:-1], endog.iloc[1:]) * (len(dft)-1))
            print(f'Split {i} \tRMSE: {rmses[-1]/len(dft):.2f}')
    return dict(
        rmse=sum(rmses) / ntest,
        rmse_persistent=sum(rmses_persistent) / (ntest - splits)
    )

def train_model(interval, order, df, endog_col, exog_cols, seq_kwargs={}):
    seqs = find_sequences(df, interval, **seq_kwargs)
    endog = seqs[0][endog_col]
    exog = exog_cols if exog_cols is None else seqs[0][exog_cols]
    res = pretrain(sm.tsa.ARIMA, endog, exog=exog, order=order)
    for dft in seqs[1:]:
        endog = dft[endog_col]
        exog = exog_cols if exog_cols is None else dft[exog_cols]
        res = update(res, endog, exog=exog, interval=interval)
    return res

def save_arma_model(res, path):
    pass

def load_arma_model(path) -> ARIMA:
    pass

def save_combined_model(models, path='arma_model.pickle'):
    import pickle
    with open(path, 'wb') as f:
        pickle.dump(models, f)

def load_combined_model(path='arma_model.pickle'):
    import pickle
    with open(path, 'rb') as f:
        return pickle.load(f)

def combined_predict(df, res=Tuple[ARIMAResults, ARIMAResults, ARIMAResults], interval=INTERVAL):
    arma_speed, arma_dx, arma_dy = res
    arma_speed, pred_speed = predict(arma_speed, df.Speed, None, interval=interval)
    arma_dx, pred_dx = predict(arma_dx, df.dx, None, interval=interval)
    arma_dy, pred_dy = predict(arma_dy, df.dy, None, interval=interval)
    pred = pd.concat((pred_speed, pred_dx, pred_dy), axis=1)
    pred.columns = ['Speed', 'dx', 'dy']
    return(arma_speed, arma_dx, arma_dy), pred

if __name__=='__main__':
    import sys
    df = read_file(processed=True)
    dfog = df # original dataframe with all data
    # Testing data
    dft = dfog.loc['2022-06-28':'2022-07-07']
    # Training data
    df = dfog.loc['2022-03-10':'2022-06-27']
    if sys.argv[1]=='train':
        print('Training models')
        arma_speed = train_model(INTERVAL, (1,0,20), df, 'Speed', None)
        arma_dx = train_model(INTERVAL, (1,0,20), df, 'dx', None)
        arma_dy = train_model(INTERVAL, (1,0,20), df, 'dy', None)

        save_combined_model((arma_speed, arma_dx, arma_dy))
    else:
        print('Loading and testing model')
        res = load_combined_model()
        seqs = find_sequences(dft, INTERVAL)
        res, pred = combined_predict(seqs[0], res)
        print(pred.head())

        rmse_speed = sm.tools.eval_measures.rmse(pred.Speed, seqs[0].Speed)
        rmse_dx = sm.tools.eval_measures.rmse(pred.dx, seqs[0].dx)
        rmse_dy = sm.tools.eval_measures.rmse(pred.dx, seqs[0].dy)
        print(f'rmse_speed (m/s)={rmse_speed:.2f}')
        print(f'rmse_dx (cos(direction))={rmse_dx:.2f}')
        print(f'rmse_dy (sin(direction))={rmse_dy:.2f}')


import os, sys, pickle, math, time, re, xlwt
from nltk.tokenize import RegexpTokenizer

def sum_dict(a, b):
    temp = dict()
    for key in a.keys() | b.keys():
        temp[key] = sum([d.get(key, 0) for d in (a, b)])
    return temp

def get_size(obj, seen=None):
    size = sys.getsizeof(obj)
    if seen is None:
        seen = set()
    obj_id = id(obj)
    if obj_id in seen:
        return 0

    seen.add(obj_id)
    if isinstance(obj, dict):
        size += sum([get_size(v, seen) for v in obj.values()])
        size += sum([get_size(k, seen) for k in obj.keys()])
    elif hasattr(obj, '__dict__'):
        size += get_size(obj.__dict__, seen)
    elif hasattr(obj, '__iter__') and not isinstance(obj, (str, bytes, bytearray)):
        size += sum([get_size(i, seen) for i in obj])
    return size

def rename():
    global map_num2oldPath, file_cnt
    if not os.path.exists(PATH):
        print("Wrong input path")
        exit(-1)
    if not os.path.exists(PATH_NEW):
        os.makedirs(PATH_NEW)

    cnt = 0
    for root, dirs, files in os.walk(PATH, topdown=True):
        for file in files:
            if cnt == 0:
                cnt += 1
                continue
            old_file_path = os.path.join(root, file)
            new_file_path = os.path.join(PATH_NEW, str(cnt))
            map_num2oldPath[cnt] = os.path.abspath(old_file_path)
            with open(old_file_path, "r+", newline="", encoding="ISO-8859-1") as f:
                content = f.readlines()[:]
            with open(new_file_path, "w+", newline="", encoding="ISO-8859-1") as f:
                f.writelines(content)
            cnt += 1
    file_cnt = cnt - 1

class InvertedIndex:
    def __init__(self):
        self.map_token = dict()
        self.map_token_chunk = dict()
        self.map_doc2len = dict()
        self.chunk_cnt = 1

    def build(self):
        if not os.path.exists(PATH_CHUNKS):
            os.makedirs(PATH_CHUNKS)
        i = 1
        for root, dirs, files in os.walk(PATH_NEW, topdown=True):
            dirs.sort()
            for file in sorted(files):
                self.spimi_invert(os.path.join(PATH_NEW, str(i)), i)
                i += 1

        chunk_path = os.path.join(PATH_CHUNKS, str(self.chunk_cnt) + ".txt")
        with open(chunk_path, "wb") as f:
            pickle.dump(self.map_token_chunk, f)
        self.map_token_chunk.clear()
        self.spimi_merge()

    def spimi_invert(self, doc_path, doc_id):
        with open(doc_path, "r+", encoding="ISO-8859-1") as file:
            content = file.read().lower()

        for term in RegexpTokenizer('[A-Za-z]+').tokenize(content):
            if sys.getsizeof(self.map_token_chunk) > 1000000:
                chunk_path = os.path.join(PATH_CHUNKS, str(self.chunk_cnt) + ".txt")
                with open(chunk_path, "wb") as file:
                    pickle.dump(self.map_token_chunk, file)
                self.map_token_chunk.clear()
                self.chunk_cnt += 1
            if term in self.map_token_chunk:
                if doc_id in self.map_token_chunk[term]:
                    self.map_token_chunk[term][doc_id] += 1
                else:
                    self.map_token_chunk[term][doc_id] = 1
            else:
                self.map_token_chunk[term] = dict()
                self.map_token_chunk[term][doc_id] = 1

    def spimi_merge(self):
        self.map_token.clear()
        for i in range(self.chunk_cnt):
            chunk_path = os.path.join(PATH_CHUNKS, str(i + 1) + ".txt")
            with open(chunk_path, "rb") as file:
                self.map_token_chunk = pickle.loads(file.read())
            term_total = set(self.map_token_chunk.keys()).union(set(self.map_token.keys()))
            for term in term_total:
                if term in self.map_token_chunk and term in self.map_token:
                    self.map_token[term] = sum_dict(self.map_token[term], self.map_token_chunk[term])
                elif term in self.map_token_chunk:
                    self.map_token[term] = self.map_token_chunk[term]

    def get_len(self):
        global file_cnt
        self.map_doc2len = dict()

        for term in self.map_token:
            df = file_cnt / len(self.map_token[term])
            for doc_id in self.map_token[term]:
                temp = (1 + math.log10(self.map_token[term][doc_id])) * math.log10(df)
                if doc_id in self.map_doc2len:
                    self.map_doc2len[doc_id] += temp * temp
                else:
                    self.map_doc2len[doc_id] = temp * temp
        for term in self.map_doc2len:
            self.map_doc2len[term] = math.sqrt(self.map_doc2len[term])

    def cosine_search(self, query):
        global file_cnt
        query_cnt = dict()
        scores = dict()
        for term in query.lower().split(" "):
            if term in query_cnt:
                query_cnt[term] += 1
            else:
                query_cnt[term] = 1
        for term in query_cnt:
            if term in self.map_token:
                df = file_cnt / len(self.map_token[term])
                for doc_id in self.map_token[term]:
                    token_w = (1 + math.log10(self.map_token[term][doc_id])) * math.log10(df)
                    query_w = (1 + math.log10(query_cnt[term])) * math.log10(df)
                    if doc_id in scores:
                        scores[doc_id] += token_w * query_w
                    else:
                        scores[doc_id] = token_w * query_w
        for term in scores:
            scores[term] /= self.map_doc2len[term]
        return scores

if __name__ == "__main__":
    PATH = "D:/Code_PyCharm/IR/20_newsgroups"
    PATH_NEW = "D:/Code_PyCharm/IR/new_files"
    PATH_CHUNKS = "D:/Code_PyCharm/IR/chunks"
    map_num2oldPath = dict()
    file_cnt = 0
    print("IR System is starting, please wait for a minute...")
    rename()
    words = InvertedIndex()
    words.build()
    words.get_len()
    print("Finished.")
    while True:
        user_input = input("What do you wanna search?")
        top10 = list(words.cosine_search(user_input).items())
        top10.sort(key=lambda x: x[1], reverse=True)
        print("Result:")
        if top10:
            for doc_term in top10[:10]:
                print(map_num2oldPath[doc_term[0]])
        else:
            print('Sorry. Nothing found.')


import numpy as np
import math

from stable_baselines3 import DDPG
from environments.env_problem1 import OptProblem1

env = OptProblem1()

# define model
model = DDPG.load('./run1_50000_steps')

rl_actions = []

A = 1
alpha = 0.8
state = env.reset()
done = False

while not done:
    prediction = model.predict(np.reshape(np.array([state]), (1,1)))
    action = prediction[0]
    unscaled_state = (0.5 * (state + 1.0) * 10)
    low, high = 0.0001*A*unscaled_state**alpha, 0.9999*A*unscaled_state**alpha
    unscaled_action = low + (0.5 * (action + 1.0) * (high - low))
    rl_actions.append(unscaled_action)
    np.savez('predictions/predictions_1', rl_actions = rl_actions)
    state, reward, done, info = env.step(action)

# deviation between predicted paths after 30 periods
# optimal investment after 30 periods: 0.255
print('Deviation of predicted paths (30 periods):', abs(rl_actions[29] - 0.255))


n = int(input())
a = []
for _ in range(n):
    toDo = input()
    if toDo[0] =='E':
        a.append(int(toDo.split()[1]))
        print(len(a))
    elif len(a)>0:
        print(a.pop(0),len(a))
    else:
        print("-1 0")


import threading
import time
import random

import socket

def server():
    try:
        ss = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        print("[S]: Server socket created")
    except socket.error as err:
        print('socket open error: {}\n'.format(err))
        exit()

    server_binding = ('', 50007)
    ss.bind(server_binding)
    ss.listen(1)
    host = socket.gethostname()
    print("[S]: Server host name is {}".format(host))
    localhost_ip = (socket.gethostbyname(host))
    print("[S]: Server IP address is {}".format(localhost_ip))
    csockid, addr = ss.accept()
    print ("[S]: Got a connection request from a client at {}".format(addr))

    # send a intro message to the client.
    msg = "Welcome to CS 352!"
    csockid.send(msg.encode('utf-8'))

     # Receive data from the client
    data_from_client=csockid.recv(200)
    # data_from_client2=csockid.recv(100)
    data2 = data_from_client.decode('utf-8')
    dataup = data2.upper()
    csockid.send(dataup.encode('utf-8'))

    data = data_from_client.decode('utf-8')
    #print("[C]: Data received from client: {}".format(data_from_client.decode('utf-8')))
    sentences = data.splitlines()
    rev=''
    for i in sentences:
        rev = rev + i[::-1] +"\n"
    #datarev = data[::-1]
    csockid.send(rev.encode('utf-8'))

    time.sleep(5)

    # Close the server socket
    ss.close()
    exit()

if __name__ == "__main__":
    t1 = threading.Thread(name='server', target=server)
    t1.start()

    time.sleep(random.random() * 5)
    # t2 = threading.Thread(name='client', target=client)
    # t2.start()

    # time.sleep(5)
    # print("Done.")


from persistente import *
from interface import WidgetInterface
from PyQt5.QtWidgets import QApplication

# Carrega tarefas do arquivo
load_task_list('task_bank.txt')

# Solicita ao usuário que insira tarefas
#get_user_tasks()

# Salva tarefas no arquivo
save_task_list('task_bank.txt')

## Bloco de chamada da interface gráfica
def startInterface():
    app = QApplication([])
    widget = WidgetInterface()
    widget.show()
    app.exec_()

if __name__ == '__main__':
    startInterface()
## Fim do bloco