import os
from math import *
from qgis.PyQt import uic
from PyQt5 import QtCore
from qgis.PyQt import QtWidgets
from qgis.utils import iface
from qgis.core import QgsWkbTypes
from PyQt5.QtGui import QFont
from datetime import datetime
from PyQt5.QtCore import QRectF, Qt
from qgis.core import (
    QgsCoordinateReferenceSystem,
    QgsGeometry,
    QgsFeature,
    QgsField,
    QgsFields,
    QgsVectorLayer,
    QgsProject,
    QgsPoint,
)

# This loads your .ui file so that PyQt can populate your plugin with the elements from Qt Designer
FORM_CLASS, _ = uic.loadUiType(os.path.join(
    os.path.dirname(__file__), 'Informatics_plugin_dialog_base.ui'))

class InformaticsPluginDialog(QtWidgets.QDialog, FORM_CLASS):
    def __init__(self, parent=None):
        """Constructor."""
        super(InformaticsPluginDialog, self).__init__(parent)
        # Set up the user interface from Designer through FORM_CLASS.
        # After self.setupUi() you can access any designer object by doing
        # self.<objectname>, and you can use autoconnect slots - see
        # http://qt-project.org/doc/qt-4.8/designer-using-a-ui-file.html
        # #widgets-and-dialogs-with-auto-connect
        self.setupUi(self)
        self.pushbutton_count.clicked.connect(self.count_objects)
        self.pushbutton_showcoordinates.clicked.connect(self.enter_data_on_marked_object)
        self.pushbutton_hight.clicked.connect(self.calculate_height_difference)
        self.pushbutton_calculate.clicked.connect(self.area)
        self.pushbutton_clear.clicked.connect(self.clear_info)
        self.pushbutton_close.clicked.connect(self.closePlugin)
        self.pushbutton_report.clicked.connect(self.generate_report)
        self.setWindowTitle('Raport Informatics Plugin')
        self.current_date = datetime.now()

    def count_objects(self):
        selected_features = self.mMapLayerComboBox.currentLayer().selectedFeatures()
        number_of_selected_elements = len(selected_features)
        self.label_select.setText(str(number_of_selected_elements))

    def enter_data_on_marked_object(self):
        active_layer = iface.activeLayer()
        sel_features = active_layer.selectedFeatures()
        self.label_active.setText(active_layer.name())

        # Przygotuj zmienną do przechowywania współrzędnych
        coordinates = []

        for feature in sel_features:
            geom = feature.geometry()
            geomSingleType = QgsWkbTypes.isSingleType(geom.wkbType())

            if geom.type() == QgsWkbTypes.PointGeometry:
                if geomSingleType:
                    x = geom.asPoint()
                    x_str = f'nr: {feature.attribute("nr")}, X: {x.x():.3f}, Y: {x.y():.3f}'
                    coordinates.append(x_str)
                else:
                    x = geom.asMultiPoint()
                    x_str = f'MultiPoint {feature.attribute("nr")}: {str(x)}'
                    coordinates.append(x_str)
            elif geom.type() == QgsWkbTypes.LineGeometry:
                if geomSingleType:
                    x = geom.asPolyline()
                    x_str = f'Polyline {feature.attribute("nr")}: {str(x)}'
                    coordinates.append(x_str)
                else:
                    x = geom.asMultiPolyline()
                    x_str = f'MultiPolyline {feature.attribute("nr")}: {str(x)}'
                    coordinates.append(x_str)
            elif geom.type() == QgsWkbTypes.PolygonGeometry:
                if geomSingleType:
                    x = geom.asPolygon()
                    x_str = f'Polygon {feature.attribute("nr")}: {str(x)}'
                    coordinates.append(x_str)
                else:
                    x = geom.asMultiPolygon()
                    x_str = f'MultiPolygon {feature.attribute("nr")}: {str(x)}'
                    coordinates.append(x_str)
            else:
                print("Unknown or invalid geometry")

        # Wyświetl współrzędne w QTextEdit
        self.listObjects.setPlainText("\n".join(coordinates))

    def calculate_height_difference(self):
        selected_layer = self.mMapLayerComboBox.currentLayer()
        number_elements = len(selected_layer.selectedFeatures())
        if number_elements == 2:
            features = selected_layer.selectedFeatures()
            feature1 = features[0]
            feature2 = features[1]

            pnr1 = feature1["nr"]
            px1 = feature1["X"]
            py1 = feature1["Y"]
            pz1 = feature1["H"]

            pnr2 = feature2["nr"]
            px2 = feature2["X"]
            py2 = feature2["Y"]
            pz2 = feature2["H"]

            H = pz2 - pz1
            self.listoHigh.setText(f'The calculated elevation between point {pnr1} and point {pnr2} is {H:.3f} m')
        elif number_elements < 2:
            self.listoHigh.setText("Not enough points selected")
        else:
            self.listoHigh.setText("Too many points were selected")

    def area(self):
        selected_layer = self.mMapLayerComboBox.currentLayer()

        crs = selected_layer.crs()
        crs_authid = crs.authid() if crs else ''
        if 'EPSG:2180' in crs_authid:  # EPSG:2180 is for PL-1992
            self.label_crs.setText('PL-1992')
        elif 'EPSG:2176' in crs_authid:  # EPSG:2176 to EPSG:2179 are for PL-2000
            self.label_crs.setText('PL-2000 (5)')
        elif 'EPSG:2177' in crs_authid:
            self.label_crs.setText('PL-2000 (6)')
        elif 'EPSG:2178' in crs_authid:
            self.label_crs.setText('PL-2000 (7)')
        elif 'EPSG:2179' in crs_authid:
            self.label_crs.setText('PL-2000 (8)')

        selected_features = selected_layer.selectedFeatures()
        points = [feature.geometry().asPoint() for feature in selected_features]

        if len(points) < 3:
            self.label_area.setText("Not enough points selected")
            return

        # Sort points in clockwise order
        centroid = QgsPoint(sum(point.x() for point in points) / len(points), sum(point.y() for point in points) / len(points))
        points.sort(key=lambda point: -atan2(point.y() - centroid.y(), point.x() - centroid.x()))

        # Calculate area using Gauss's area formula
        area = 0.5 * abs(sum(points[i - 1].x() * points[i].y() - points[i].x() * points[i - 1].y() for i in range(len(points))))

        # Convert area to selected unit
        unit = self.comboBox_unit.currentText()
        if unit == 'm^2':
            area = area
        elif unit == 'Are':
            area *= 0.01
        elif unit == 'Hectare':
            area *= 0.0001

        self.label_area.setText(f'Area: {area:.3f} {unit}')

        if len(selected_features) > 0:
            # Create a new vector layer to hold the polygon feature
            if len(points) >= 3:
                new_layer = QgsVectorLayer("Polygon?crs=" + crs_authid, "Polygon Layer", "memory")
                provider = new_layer.dataProvider()
                new_layer.startEditing()

                # Create a polygon feature
                poly_feature = QgsFeature()
                polygon = QgsGeometry.fromPolygonXY([points])
                poly_feature.setGeometry(polygon)
                provider.addFeature(poly_feature)

                new_layer.commitChanges()
                QgsProject.instance().addMapLayer(new_layer)
            else:
                # Remove temporary polygon layer if it exists
                existing_layer = None
                for layer in QgsProject.instance().mapLayers().values():
                    if layer.name() == "Polygon Layer":
                        existing_layer = layer
                        break

                if existing_layer:
                    QgsProject.instance().removeMapLayer(existing_layer.id())

    def clear_info(self):
        self.label_select.setText("")
        self.listObjects.clear()
        self.listoHigh.setText("")
        self.label_area.setText("")
        self.label_crs.setText("")
        self.label_active.setText("")

        # Remove temporary polygon layer if it exists
        existing_layer = None
        for layer in QgsProject.instance().mapLayers().values():
            if layer.name() == "Polygon Layer":
                existing_layer = layer
                break

        if existing_layer:
            QgsProject.instance().removeMapLayer(existing_layer.id())

    def closePlugin(self):
        self.label_select.setText("")
        self.listObjects.clear()
        self.listoHigh.setText("")
        self.label_area.setText("")
        self.label_crs.setText("")
        self.label_active.setText("")

        existing_layer = None
        for layer in QgsProject.instance().mapLayers().values():
            if layer.name() == "Polygon Layer":
                existing_layer = layer
                break

        if existing_layer:
            QgsProject.instance().removeMapLayer(existing_layer.id())

        self.close()

    def generate_report(self):
        save_path, _ = QtWidgets.QFileDialog.getSaveFileName(self, 'Save a text report', '', 'Text Files (*.txt)')

        if save_path:
            current_date = QtCore.QDateTime.currentDateTime().toString("yyyy-MM-dd HH:mm:ss")

            with open(save_path, 'w') as file:
                file.write("Raport Informatics Plugin\n\n")
                file.write("Date the report was created: {}\n\n".format(current_date))
                file.write("Brief report of calculations of selected points\n\n")
                file.write("Active layer:\n")
                file.write("Number of points selected: " + self.label_select.text() + "\n\n")
                file.write("Summary of the coordinates of these points:\n")

                point_data = self.listObjects.toPlainText()
                file.write(point_data)

                file.write("\n\nCalculated elevation:\n")
                file.write(self.listoHigh.text() + "\n\n")
                file.write("Calculated surface area:\n")
                file.write(self.label_area.text() + "\n\n")
                file.write("Coordinate system of selected points:\n")
                file.write(self.label_crs.text() + "\n")

            QtWidgets.QMessageBox.information(self, 'Report generated', f'The report was recorded as {save_path}.')
        else:
            QtWidgets.QMessageBox.warning(self, 'Recording error', 'Report storage path not selected.')


""" account forms """
from django import forms
from .models import UserAccount

class UserAccountForm(forms.ModelForm):
    """ user account form class """
    class Meta:
        """ meta class """
        model = UserAccount
        exclude = ('user',)

    def __init__(self, *args, **kwargs):

        super().__init__(*args, **kwargs)
        placeholders = {
            'default_phone_number': 'Phone Number',
            'default_postcode': 'Postal Code',
            'default_city': 'Town or City',
            'default_address_line_one': 'Street Address 1',
            'default_address_line_two': 'Street Address 2',
            'default_county': 'County',
        }

        self.fields['default_phone_number'].widget.attrs['autofocus'] = True

        for field in self.fields:
            if field != 'default_country':
                if self.fields[field].required:
                    placeholder = f'{placeholders[field]} *'
                else:
                    placeholder = placeholders[field]
                self.fields[field].widget.attrs['placeholder'] = placeholder
            self.fields[field].widget.attrs['class'] = 'border-brown'

            self.fields[field].label = False


import discord
from discord.ext import commands
import asyncio
from Liste_chained import list_chained, Node, fifo, Stack

from datetime import datetime, timedelta
from Hashtable_user import HashTableUser
import json
import os
import requests
from bs4 import BeautifulSoup
from binary_tree_bot import *
intents = discord.Intents.all()

client = commands.Bot(command_prefix ="!", intents = intents)

my_list = list_chained("historique=liste chainÃ©e")
nod = Node("Ne")
fifo = fifo(None)

###____Reminder____
reminder_stack = Stack(None)

def load_suggestions():
    with open("suggestions.json", "r") as f:
        suggestions = json.load(f)
    return suggestions

suggestions = load_suggestions()

@client.event
async def on_message(message):
    if message.author.bot:
        return
    if message.content.startswith(client.command_prefix):
        ctx = await client.get_context(message)
        await client.invoke(ctx)

    if message.content.startswith("Hello"):
        await message.channel.send("hello")
    await add_to_history(message)

    if message.author == client.user:
        return
'''
    if message.content.lower() == 'reset':
        await client.process_commands(message)
        return
    elif message.content.lower().startswith('speak about '):
        topic = message.content.lower().split('speak about ')[1]
        if topic in ['python', 'sports', 'music']:
            await message.channel.send(f"Je peux parler de {topic} !")
        else:
            await message.channel.send(f"Je ne peux pas parler de {topic}...")
    else:
        question = tree.get_question()
        await message.channel.send(question)
        response = message.content.lower()
        tree.send_answer(response)
        next_question = tree.get_question()
        await message.channel.send(next_question)
'''
### Ajout Historique du message

@client.event
async def on_ready():
    channel = client.get_channel(1091265494771843095)
    await channel.send('the bot is ready')

async def check_reminders():
    global reminder_stack

    while True:
        # Check if it's time to remind the user of a stored reminder
        if reminder_stack.size > 0 and reminder_stack.peek()[0] <= datetime.now():
            # Send the reminder message to the user
            remind_time, reminder = reminder_stack.pop()
            await client.send(f'Reminder: {reminder}')

        # Sleep for 1 second before checking again
        await asyncio.sleep(1)

# Call the check_reminders function to start the loop
check_reminders()

# _________________________________________History Related____________________________________________

HashTableUser = HashTableUser(bucket_size=10)

# fonction pour ajouter un message Ã  l'historique
async def add_to_history(message):
    if not message.content.startswith(tuple(str(i) for i in range(10))): # prevent le !menu
        author_id = str(message.author.id)
        timestamp = str(datetime.now())

        message_content = message.content
        message_data = f'Message : {message_content} | Auteur : {author_id} | Date/Heure : {timestamp}'
        Component_history = Node(message_data)
        my_list.append(Component_history.data)
        await message.channel.send(f'Le message "{Component_history.data}" est placÃ© dans l\'historique.')

        # lier l'historique Ã  l'utilisateur
        user_history = HashTableUser.get(author_id)

        # si l'historique n'existe pas encore, crÃ©er une nouvelle liste chainÃ©e pour cet utilisateur
        if not user_history:
            user_history = list_chained(f"Historique de {message.author.display_name}")
            HashTableUser.append(author_id, user_history)

        # ajouter le message Ã  l'historique de l'utilisateur
        user_history.append(Component_history.data)

        await message.channel.send(f'Le message "{Component_history.data}" est placÃ© dans l\'historique de {message.author.display_name}.')

        # enregistrer les donnÃ©es dans un fichier texte
        with open("history.txt", "a") as f:
            f.write(message_data + "\n")

# fonction pour sauvegarder les donnÃ©es dans hastable
def save_data():
    with open("history.txt", "w") as f:
        for user_id in HashTableUser.buckets:
            user_history = HashTableUser.get(user_id[0])
            for message_data in user_history:
                f.write(message_data + "\n")

def save_suggestions():
    with open("suggestions.json", "w") as f:
        json.dump(suggestions, f)

# fonction pour fermer le bot et sauvegarder les donnÃ©es avant de quitter

async def on_shutdown():
    save_data()
    await client.close()

@client.command(name="history")
async def show_history(ctx):
        history_list = my_list.show_all()
        history_str = "\n".join(history_list)
        if history_str:
            await ctx.channel.send("Les messages de l'historique sont:\n" + history_str)
        else:
            await ctx.channel.send("Fin historique.")
@client.command(name="last")
async def delete_last_message(ctx):
    my_list.delete_last()
    await ctx.send('plus de dernier message')

@client.command(name="sup")
async def delete_message(ctx, index: int):
    my_list.delete_at_index(index)
    await ctx.send(f'le message num {index} est sup.')

@client.command(name="tout")
async def delete_all_messages(ctx):
    my_list.delete_all()
    await ctx.send('tout les messages = supprime')

### Mouvement + last + user_history
@client.command(name="back")
async def navigate_backward(ctx):
    message = my_list.navigate_backward()
    await ctx.channel.send(message)

@client.command(name="forward")
async def navigate_forward(ctx):
    message = my_list.navigate_forward()
    await ctx.channel.send(message)

@client.command(name="last_message")
async def show_last_message(ctx):
    last_message = my_list.last_elmt()
    await ctx.channel.send("Le dernier message de l'historique est : " + last_message)

@client.command(name="user_history")
async def show_user_history(ctx, user_id: int):
    user_messages = [msg for msg in my_list.show_all() if str(user_id) in msg]
    if user_messages:
        message = "\n".join(user_messages)
        await ctx.channel.send(f"L'historique pour l'utilisateur avec l'ID {user_id} est :\n{message}")
    else:
        await ctx.channel.send(f"Aucun message pour l'utilisateur avec l'ID {user_id}")
#____________________________Menu_for_History______________________________
@client.command(name="menu")
async def menu(ctx):
    global fifo

    # regarde si qqn dans fifo , sinon place Ã  la suite
    if fifo.peek() is None:
        fifo.push(ctx.author.id)
    else:
        if fifo.peek().data != ctx.author.id:
            fifo.push(ctx.author.id)
        if fifo.peek() is None: # regarde si cest toujours null ou non
            await ctx.send("You are not currently first in line. Please wait your turn.")
            return

    while True:
        menu_str = "Que voulez-vous faire?\n" \
                   "1. Afficher l'historique\n" \
                   "2. Supprimer le dernier message\n" \
                   "3. Supprimer un message spÃ©cifique\n" \
                   "4. Tout supprimer\n" \
                   "5. Naviguer en arriÃ¨re\n" \
                   "6. Naviguer en avant\n" \
                   "7. Afficher le dernier message\n" \
                   "8. Afficher l'historique d'un utilisateur\n" \
                   "9. Quitter\n" \
                   "RÃ©pondez avec le numÃ©ro de l'option."
        await ctx.send(menu_str)
        try:
            message = await client.wait_for('message', timeout=30.0, check=lambda m: m.author == ctx.author)
        except asyncio.TimeoutError:
            await ctx.send("Temps Ã©coulÃ©. Commande annulÃ©e.")
            fifo.pop(ctx.author.id) # Remove user from fifo when they time out
            return

        if message.content == "1":
            await show_history(ctx)
        elif message.content == "2":
            await delete_last_message(ctx)
        elif message.content == "3":
            await ctx.send("Quel est l'index du message Ã  supprimer?")
            try:
                index_message = await client.wait_for('message', timeout=30.0, check=lambda m: m.author == ctx.author)
            except asyncio.TimeoutError:
                await ctx.send("Temps Ã©coulÃ©. Commande annulÃ©e.")
                fifo.pop(ctx.author.id) # Remove user from fifo when they time out
                return
            await delete_message(ctx, int(index_message.content))
        elif message.content == "4":
            await delete_all_messages(ctx)
        elif message.content == "5":
            message = my_list.navigate_backward()
            await ctx.channel.send(message)
        elif message.content == "6":
            message = my_list.navigate_forward()
            await ctx.channel.send(message)
        elif message.content == "7":
            last_message = show_last_message(ctx)
            await ctx.send(last_message)
        elif message.content == "8":
            await ctx.send("Veuillez mentionner l'utilisateur dont vous voulez voir l'historique.")
            try:
                user_mention = await client.wait_for('message', timeout=30.0, check=lambda m: m.author == ctx.author)
            except asyncio.TimeoutError:
                await ctx.send("Temps Ã©coulÃ©. Commande annulÃ©e.")
                fifo.pop(ctx.author.id) # Remove user from fifo when they time out
                return
            await show_user_history(ctx, user_mention.content)
        elif message.content == "9":
            await ctx.send("Au revoir !")
            fifo.pop() # vire user from fifo
            return
        else:
            await ctx.send("Option invalide. Veuillez rÃ©essayer.")

#_________________________ABRE POUR PAPOTER __________________________________( FAIS POST DEMO EN CLASSE)
### INITIER ARBRE

cooking_tree = Binary_Tree()
cooking_tree.add_subject("cooking", "What type of cuisine do you want to cook?")
cooking_tree.root = Junction(cooking_tree.print_subject("cooking"))
cooking_tree.root.add_junction("Do you want to cook Asian cuisine?", True)
cooking_tree.root.add_junction("Do you want to cook European cuisine?", False)
cooking_tree.root.right.add_junction("Do you want to cook Chinese cuisine?", True)
cooking_tree.root.right.add_junction("Do you want to cook Japanese cuisine?", False)
cooking_tree.root.right.right.add_leaf("Awesome, here are some Chinese cooking recipes! DOG !", True)
cooking_tree.root.right.left.add_leaf("Awesome, here are some Japanese cooking recipes! MIAOU ! ", False)
cooking_tree.root.left.add_junction("Do you want to cook Italian cuisine?", True)
cooking_tree.root.left.add_junction("Do you want to cook French cuisine?", False)
cooking_tree.root.left.right.add_leaf("Awesome, here are some Italian cooking recipes! : Pasta ", True)
cooking_tree.root.left.left.add_leaf("Awesome, here are some French cooking recipes! PAIN ", False)

### INTERACTION AVEC LARBRE  ( pour reset cliquer sur la croix)
@client.command(name="tree")
async def display_help_message(ctx):
    global actual_tree_node
    actual_tree_node = cooking_tree.root
    message = await ctx.send(actual_tree_node)
    await ctx.message.add_reaction("âœ…")
    await message.add_reaction("ðŸ‘�")
    await message.add_reaction("ðŸ‘Ž")
    await message.add_reaction("â�Œ")

    def check(reaction, user):
        return user == ctx.author and reaction.message.id == message.id

    try:
        while True:
            reaction, user = await client.wait_for('reaction_add', timeout=60.0, check=check)
            if str(reaction.emoji) == 'â�Œ':
                await message.delete()
                break
            elif str(reaction.emoji) == 'âœ…':
                actual_tree_node = cooking_tree.root
                await message.edit(content=actual_tree_node)
            elif str(reaction.emoji) == 'ðŸ‘�':
                actual_tree_node = cooking_tree.next_junction(actual_tree_node, True)
                if isinstance(actual_tree_node, Junction):
                    await message.edit(content=actual_tree_node)
                else:
                    await message.edit(content=actual_tree_node)
                    break
            elif str(reaction.emoji) == 'ðŸ‘Ž':
                actual_tree_node = cooking_tree.next_junction(actual_tree_node, False)
                if isinstance(actual_tree_node, Junction):
                    await message.edit(content=actual_tree_node)
                else:
                    await message.edit(content=actual_tree_node)
                    break
    except asyncio.TimeoutError:
        await message.delete()
##  sLECTION DES SUJETS EN FONCTION DE LA PRESENCE DE SUJET DANS LE TREE
@client.command(name="subject")
async def get_existing_subjects(ctx):
    existing_subjects = list(cooking_tree.subjects.keys())
    message = f"The existing subjects are {existing_subjects}"
    await ctx.send(message)

#####__________________________Option++___________________________________

#________________Sondage_____________________________ via list chained
with open("suggestions.json", "r") as f:
    suggestions = json.load(f)

# Emettre une suggestion
@client.command(name="sug")
async def suggestion(ctx, *, suggestion):
    author = ctx.message.author
    # Ajout la sug
    suggestions.append({"author": author.id, "suggestion": suggestion, "votes": []})
    await ctx.send(f"{author.mention} Votre suggestion a Ã©tÃ© prise en compte !")
    save_suggestions()

# affiche la liste de sug
@client.command(name="show_sug")
async def list_suggestions(ctx):
    # RÃ©cupÃ©ration de la liste de suggestions
    suggestions_list = []
    for i, suggestion in enumerate(suggestions):
        votes_emoji = "ðŸ‘� " + str(len(suggestion["votes"])) if suggestion["votes"] else ""
        suggestion_text = f"{i}. {suggestion['suggestion']} - {ctx.guild.get_member(suggestion['author']).mention} {votes_emoji}"
        suggestions_list.append(suggestion_text)
    # Envoi de la liste de suggestions dans un message
    await ctx.send("\n\n".join(suggestions_list))

# Commande pour voter
@client.command(name="vote")
async def vote(ctx, suggestion_number):
    author = ctx.message.author
    try:
        suggestion_number = int(suggestion_number)
        # RÃ©cupÃ©ration de la suggestion correspondante
        suggestion = suggestions[suggestion_number]
        # VÃ©rification que l'auteur
        if author.id not in suggestion["votes"]:
            # Ajout du vote Ã  la suggestion
            suggestion["votes"].append(author.id)
            await ctx.message.add_reaction("ðŸ‘�")
            save_suggestions()
        else:
            await ctx.send(f"{author.mention} Vous avez dÃ©jÃ  votÃ© pour cette suggestion.")
    except:
        await ctx.send(f"{author.mention} La suggestion nÂ°{suggestion_number} n'existe pas.")
@client.command(name="show_vot")
async def show_all_suggestions(ctx):

    suggestions_list = list_chained("")

    for suggestion in suggestions:
        votes_emoji = "ðŸ‘� " + str(len(suggestion["votes"])) if suggestion["votes"] else ""
        suggestion_text = f"{suggestion['suggestion']} - {ctx.guild.get_member(suggestion['author']).mention} {votes_emoji}"
        suggestions_list.append(suggestion_text)
    # Envoi de toutes les suggestions dans un message
    await ctx.send("\n\n".join(suggestions_list.show_all()))

#_______ 2eme___Options________Reminder
@client.command(name='remindme')
async def remindme(ctx, time_str: int, *, reminder: str):
    global reminder_stack

    remind_time = None

    try:
        remind_time = datetime.now() + timedelta(seconds=int(time_str))
    except ValueError:
        await ctx.send('Invalid input. Usage: !remindme [time in seconds] [reminder message]')
        return

    # Push the reminder message and time onto the stack
    reminder_stack.push((remind_time, reminder))

    # Send a confirmation message to the user
    await ctx.send(f'Reminder set for {remind_time.strftime("%m/%d/%Y %I:%M %p")} with message: {reminder}')

#_____option lol _____________
@client.command(name="lol")
async def youtube(ctx, *, url):

    if "youtube.com/watch?v=" not in url:
        await ctx.send("Ce n'est pas un lien valide de vidÃ©o YouTube.")
        return

    # Supprime l'Ã©ventuelle balise "<>"
    url = url.strip("<>")
    # RÃ©cupÃ¨re l'identifiant
    video_id = url.split("youtube.com/watch?v=")[1].split("&")[0]

    video_url = f"https://www.youtube.com/watch?v={video_id}"

    os.system(f"start {video_url}")
    await ctx.send(f"Ouverture de la vidÃ©o : {video_url}")
#________HIHI_____________
@client.command(name="scrap")
async def image(ctx, *, mot):
    # Effectuer une recherche Google Images avec le mot
    recherche = mot.replace(' ', '+')
    url = f'https://www.google.com/search?q={recherche}&tbm=isch'
    headers = {'User-Agent': 'Mozilla/5.0'}
    response = requests.get(url, headers=headers)
    soup = BeautifulSoup(response.content, 'html.parser')
    images = soup.find_all('img')

    # TÃ©lÃ©charger la premiÃ¨re image
    for image in images:
        src = image['src']
        if src.startswith('https') and not src.endswith('.svg'):
            response = requests.get(src, stream=True)
            if response.status_code == 200:
                with open(f'{mot}.jpg', 'wb') as file:
                    for chunk in response.iter_content(1024):
                        file.write(chunk)
                break

     # Stocker le mot de la recherche et le nom de l'image dans un fichier JSON
    data = {'mot': mot, 'image': f'{mot}.jpg'}
    with open('Images.json', 'w') as file:
        json.dump(data, file)

    # Envoyer l'image dans le canal Discord
    with open(f'{mot}.jpg', 'rb') as file:
        image = discord.File(file)
        await ctx.send(file=image)

##________________Ma note _____________ ( lancez la commande !)

@client.command(name="note")
async def note20(ctx):

    message = await ctx.send("Donnez une note sur 20 Ã  Yann :")

    #
    def check(m):
        return m.author == ctx.author and m.channel == ctx.channel

    try:
        note_message = await client.wait_for('message', check=check, timeout=10.0)
    except asyncio.TimeoutError:
        await message.edit(content=" Je me suis endormi ...")
        return

    # VÃ©rifie que la note = un nombre
    try:
        note = float(note_message.content)
    except ValueError:
        await ctx.send("Une note cest un nombre ... on part sur 20 merci ! ")
        return

    # VÃ©rifie que la note est entre 0 et 20
    if note < 0 or note > 20:
        await ctx.send("La note doit Ãªtre entre 0 et 20, cest pas du jeu sinon")
        return

    await ctx.send("Un 20 ? Merci Ã§a rÃ©gale :) !")

client.run("Tokenmiamiam")


# Name: NegImgGenerator
# Author: Peter Mai and Harrison Kinsley
# Reference: https://pythonprogramming.net/haar-cascade-object-detection-python-opencv-tutorial/
#
# This program is used as preparation for haar cascade image recognition training
# and is composed of three primary features. It's first feature is to gather
# various images online and modifying them to be used as negative image. The
# second feature is it'll remove user-specified pictures that are bad picture.
# The third feature is it will generate a pos and neg file called bg.txt
#
# This program runs on Python 3

"""Modules used for downloading images online and converting them"""
import urllib.request
import argparse
import sys
import os
import cv2
import numpy as np

width = 0
height = 0

def generate_raw_images():
    """ Asks users for a link to a website that holds various other links to
    images that would be downloaded to generate the negative images. You can
    get this link by going to site such as http://image-net.org
    """

    global width
    global height

    # Ask user to specify how many images to collect along with width and height
    width = int(input("Please enter negative image width:    "))
    height = int(input("Please enter negative image height:   "))
    max_neg = int(input("How many negative image to generate:  "))

    print("\nGreat! You chose to generate " + str(max_neg) + " " + str(width) +
          "x" + str(height) + " negative images.\n")

    print("You can get a list of links from http://image-net.org after ")
    print("searching under Downloads > URLS\n")
    sources = int(input("How many of these sources do you want to provide: "))

    # Collect specified source url from user
    source_url = []
    for source_idx in range(0, sources):
        source_url.append(input("Please enter source link " + str(source_idx+1) +": "))

    print("\nStoring negative images to " + os.path.dirname(os.path.abspath(__file__))+"/neg...\n")

    # Create a 'neg' directory if it has not been created
    if not os.path.exists('neg'):
        os.makedirs('neg')

    # Keep track of current image
    pic_num = 0
    max_neg_per_source = max_neg / sources

    # For each link, gather max_neg / sources negative images
    for source_idx in range(0, sources):
        neg_images_link = source_url[source_idx]
        neg_images_urls = urllib.request.urlopen(neg_images_link).read().decode()

        # Attempt to download image and convert it to specified scaled image
        for url in neg_images_urls.split('\n'):
            try:
                print(url)
                urllib.request.urlretrieve(url, "neg/"+str(pic_num)+'.jpg')
                img = cv2.imread("neg/"+str(pic_num)+'.jpg', cv2.IMREAD_GRAYSCALE)
                resized_image = cv2.resize(img, (width, height))
                cv2.imwrite("neg/"+str(pic_num)+'.jpg', resized_image)
                pic_num += 1
                if pic_num % max_neg_per_source == 0:
                    break

            except Exception as ex:
                print(str(ex))

    print("Done.\n")

def remove_bad_images():
    """ Remove bad pictures that user specified. These images are often images
    retrieved when link no longer works and the host website returns an
    invalid image rather than a 404 error.
    """

    print("Please store any images you want to remove in ")
    print("  " + os.path.dirname(os.path.abspath(__file__)) + "/bad_images/...\n")
    input("Enter 'y' to continue: ")

    # Scan each image in 'neg' against all images in 'bad_images'
    print("Begin searching for files to remove...")
    for file_type in ['neg']:
        for img in os.listdir(file_type):
            for bad_img in os.listdir('bad_images'):
                try:
                    current_image_path = str(file_type) + '/' + str(img)
                    bad_img = cv2.imread('bad_images/' + str(bad_img))
                    question = cv2.imread(current_image_path)

                    # Remove 'neg' image if it matches 'bad_image'
                    if bad_img.shape == question.shape and not(np.bitwise_xor(bad_img,question).any()):
                        print("removing " + current_image_path)
                        os.remove(current_image_path)

                except Exception as ex:
                    print(str(ex))

    print("Done.\n")

def create_pos_n_neg():
    """ This module will generate a positive and negative file from the negative
    images gathered. It will produce a bg.txt background file
    """

    global width
    global height

    if width == 0:
        width = int(input("Please enter negative image width:    "))
    if height == 0:
        height = int(input("Please enter negative image height:    "))

    print("Begin generating background file.")
    for file_type in ['neg']:

        # Generate background file bg.txt
        for img in os.listdir(file_type):
            if file_type == 'neg':
                line = file_type+'/'+img+'\n'
                with open('bg.txt', 'a') as f:
                    f.write(line)

            elif file_type == 'pos':
                line = file_type+'/'+img+' 1 0 0 ' + str(width) + ' ' + str(height) + '\n'
                with open('info.dat', 'a') as f:
                    f.write(line)

    print("Done.\n")

# Ask for command-line arguments on how to run program
parser = argparse.ArgumentParser()
parser.add_argument("method",help="\"all\" Perform all three steps.\n" +
                                  "\"generate_raw_images\" Only generate neg images.\n" +
                                  "\"remove_bad_images\" Remove bad images.\n" +
                                  "\"create_pos_n_neg\" Generate bg.txt.\n")
args = parser.parse_args()

# Run script based on what user specified
if args.method == "all":
    generate_raw_images()
    remove_bad_images()
    create_pos_n_neg()
elif args.method == "generate_raw_images":
    generate_raw_images()
elif args.method == "remove_bad_images":
    remove_bad_images()
elif args.method == "create_pos_n_neg":
    create_pos_n_neg()
else:
    print("error: " + args.method + " is not a valid argument")
    parser.print_help()
    sys.exit()


from typing import Optional, List

class TreeNode:
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right

def sum_left_leaves(node: TreeNode, parent: TreeNode, result: List[int]):
    if node is None:
        return
    if node.left is None and node.right is None and parent is not None:
        if node == parent.left:
            result.append(node.val)
    sum_left_leaves(node.left, node, result)
    sum_left_leaves(node.right, node, result)

class Solution:
    def sumOfLeftLeaves(self, root: Optional[TreeNode]) -> int:
        result = []
        sum_left_leaves(root, None, result)
        return sum(result)


from datetime import datetime

import google.protobuf.empty_pb2
from paperpilot_common.helper.field import datetime_to_timestamp
from paperpilot_common.protobuf.monitor.client_pb2 import (
    ClientContainerStatus,
    ClientStatus,
    Status,
)
from paperpilot_common.protobuf.monitor.server_pb2 import (
    ProjectStatus,
    ServerStatus,
)
from paperpilot_common.utils.log import get_logger

from server.business.grpc.monitor_client import monitor_clients
from server.business.svg import SvgDrawer
from server.config import data

class MonitorPublicService:
    logger = get_logger("monitor.server.service")

    def __init__(self):
        self.projects = {_["id"]: _ for _ in data["projects"]}

    async def get_client_status(self) -> list[ClientStatus]:
        result = []
        for client in monitor_clients:
            try:
                result.append(
                    await client.stub.GetStatus(
                        google.protobuf.empty_pb2.Empty, timeout=0.8
                    )
                )
            except Exception as e:
                self.logger.error(f"get client status error: {e}")

        return result

    async def get_status(self) -> ServerStatus:
        client_status = await self.get_client_status()
        projects_info: dict[str, list[ClientContainerStatus]] = {}

        for client in client_status:
            for project in client.projects:
                project_name = project.project_name
                if project_name not in projects_info:
                    projects_info[project_name] = []

                projects_info[project_name].extend(project.containers)

        projects = []

        for project_name, containers in projects_info.items():
            project = self.projects.get(project_name, None)

            if not project:
                project = {
                    "id": project_name,
                    "name": project_name,
                    "description": "",
                }

            projects.append(
                ProjectStatus(
                    id=project["id"],
                    name=project["name"],
                    description=project["description"],
                    healthy_count=len(
                        [_ for _ in containers if _.status == Status.HEALTHY]
                    ),
                    total_count=len(containers),
                )
            )

        return ServerStatus(
            host_count=len(client_status),
            projects=projects,
            time=datetime_to_timestamp(datetime.now()),
        )

    async def get_status_svg(self) -> str:
        client_status = await self.get_client_status()
        projects_info: dict[str, list[ClientContainerStatus]] = {}

        for client in client_status:
            for project in client.projects:
                project_name = project.project_name
                if project_name not in projects_info:
                    projects_info[project_name] = []

                projects_info[project_name].extend(project.containers)

        projects = []

        for project_name, containers in projects_info.items():
            project = self.projects.get(project_name, None)

            if not project:
                project = {
                    "id": project_name,
                    "name": project_name,
                    "description": "",
                }

            projects.append(
                dict(
                    id=project["id"],
                    name=project["name"],
                    description=project["description"],
                    healthy_count=len(
                        [_ for _ in containers if _.status == Status.HEALTHY]
                    ),
                    total_count=len(containers),
                )
            )

        data = dict(
            host_count=len(client_status),
            projects=projects,
            time=datetime.now(),
        )

        drawer = SvgDrawer(data)

        return drawer.draw()

monitor_service: MonitorPublicService = MonitorPublicService()


from telebot import types

from exceptions.bot_error_handler import bot_error_handler
from services.bot.authentication_service import AuthenticationService
from utils.constants.messages import PPM_AUTH
from utils.logger import Logger
from utils.string_utils import StringUtil

def register_parent_auth_handlers(bot):
    @bot.message_handler(commands=['logout'])
    @bot_error_handler(bot)
    def handle_parent_logout(message):
        res = AuthenticationService.logout_parent(message.chat.id)
        bot.send_message(message.chat.id, "Вы успешно вышли из системы")
        Logger.bot_info(message.chat.id, "authentication",
                        f"Parent logged out. Result: {res}")

    @bot.message_handler(commands=['login'])
    @bot_error_handler(bot)
    def handle_parent_login(message):
        if AuthenticationService.is_parent_with_tg_id_authorized(message.chat.id):
            bot.send_message(message.chat.id, PPM_AUTH.ERROR_ALREADY_AUTHENTICATED)
            Logger.bot_handled_error(message.chat.id, "authentication", "Parent with such tg_id already authed")
        else:
            markup = types.InlineKeyboardMarkup(row_width=1)
            button1 = types.InlineKeyboardButton(PPM_AUTH.BUTTON_AUTH_METHOD_MANUAL_INPUT,
                                                 callback_data='auth_by_input')
            button2 = types.InlineKeyboardButton(PPM_AUTH.BUTTON_AUTH_METHOD_TG_FETCH, callback_data='auth_by_tg')
            markup.add(button1, button2)
            bot.send_message(message.chat.id, PPM_AUTH.INFO_AUTH_METHOD_SELECTION, reply_markup=markup)

    @bot.callback_query_handler(func=lambda call: call.data.startswith("auth_by"))
    @bot_error_handler(bot)
    def process_auth_type_selection(call):
        if call.data == 'auth_by_input':
            bot.send_message(call.message.chat.id, PPM_AUTH.INFO_AUTH_METHOD_MANUAL_INPUT_HINT)
            bot.register_next_step_handler(call.message, process_auth_contact_input_handler)
        elif call.data == 'auth_by_tg':
            markup = types.ReplyKeyboardMarkup(one_time_keyboard=True, resize_keyboard=True)
            item = types.KeyboardButton(PPM_AUTH.BUTTON_AUTH_METHOD_TG_FETCH_PROCESS, request_contact=True)
            markup.add(item)
            bot.send_message(call.message.chat.id, PPM_AUTH.INFO_AUTH_METHOD_TG_FETCH_HINT,
                             reply_markup=markup)

    @bot.message_handler(content_types=['contact'])
    @bot_error_handler(bot)
    def process_auth_contact_tg_handler(message):
        contact = message.contact
        phone_number = contact.phone_number
        parent_tg_id = message.chat.id
        username = message.from_user.username
        _process_auth_on_phone_number_introduced(message, parent_tg_id, phone_number, username)

    @bot_error_handler(bot)
    def process_auth_contact_input_handler(message):
        phone_number = message.text
        parent_tg_id = message.chat.id
        username = message.from_user.username
        _process_auth_on_phone_number_introduced(message, parent_tg_id, phone_number, username)

    def _process_auth_on_phone_number_introduced(message, parent_tg_id, phone_number, username):
        if AuthenticationService.is_parent_with_phone_number_authorized(phone_number):
            bot.send_message(message.chat.id, PPM_AUTH.ERROR_PHONE_NUMBER_ALREADY_USED)
            Logger.bot_handled_error(message.chat.id, "authentication",
                                     f"Parent with such phone_number({phone_number}) already authed")
            return
        result = AuthenticationService.authorize_parent(phone_number, parent_tg_id, username)
        if result:
            parent_name, saved_children_names = result
            string_children_names = StringUtil.list_to_string(saved_children_names)
            msg = PPM_AUTH.RESULT(string_children_names)
            bot.send_message(message.chat.id, msg)
            Logger.bot_info(parent_tg_id, "parent_authentication",
                            f"Parent with phone_number={phone_number} and tg_username={username} successfully authenticated")

        else:
            msg = PPM_AUTH.ERROR_AUTH_FAILED
            bot.send_message(message.chat.id, msg)
            Logger.bot_handled_error(parent_tg_id, "parent_authentication",
                                     f"Parent with phone_number={phone_number} and tg_username={username} not authenticated")


import sys
from collections import defaultdict
from collections import deque

input = lambda: sys.stdin.readline().rstrip()

N, M = map(int, input().split())
materials = defaultdict(int)

for _ in range(N):
    name, amount = input().split()
    # 파는 재료는 중복되지 않는다
    materials[name] = int(amount)

equations = defaultdict(list)

for _ in range(M):
    name, equation = input().split("=")
    required_materials = defaultdict(int)
    for eq in equation.split("+"):
        i = 0

        while '0' <= eq[i] <= '9':
            i += 1

        material_amount = int(eq[:i])
        material_name = eq[i:]
        required_materials[material_name] += material_amount

    equations[name].append(required_materials)

dq = deque(equations.items())
visited = set()
for i in range(50*50):
    if not dq:
        break
    name, required_materials_list = dq.popleft()
    outerCanMake = False
    for required_materials in required_materials_list:
        canMake = True
        price = 0
        for material in required_materials:
            if material not in materials:
                canMake = False
                continue
            else:
                price += required_materials[material] * materials[material]
                if price > 1000000000:
                    price = 1000000001
        if canMake:
            outerCanMake = True
            materials[name] = price if materials[name] == 0 else min(materials[name], price)

    dq.append([name, required_materials_list])

if 'LOVE' not in materials and 'LOVE' not in equations:
    print(-1)
else:
    ans = materials['LOVE']
    print(ans if ans !=0 else -1)


# Script to compile all english URL-based articles into a pandas dataframe with all language texts included.

import requests
import json
import sys
import wikipedia
import subprocess
import json
import pandas as pd

languagelist = ['en', 'zh', 'es', 'de', 'ru', 'ja']
#From translate.py ec3bd
#given a link to a wikipedia article,
#will return the text content of that article in a dictionary keyed by its page title
def fetch_article(link):
	ind = link.index("/wiki/")
	title = link[ind+6:]
	print(title)
	wikipedia.set_lang("en")
	page = wikipedia.page(title)
	content = page.content
	#print(len(content))
	#Divide at earliest point to cut down on unnecessary characters
	try:
		content = content[:content.index("== See also ==")]
	except ValueError:
		try:
			content = content[:content.index("== References ==")]
		except ValueError:
			print("no references might be other language")

	#print("Num characters in article: "+ str(len(content)))

	retdict = {'title': title, 'en': content}
	#print(content.split()[:30])
	languagelist = ['zh', 'es', 'de', 'ru', 'ja']
	for lang_title in languagelist:
		#get languages this article is in
		param_dict = {"action":"query",
						"prop":"langlinks",
						"format":"json",
						"lllang": lang_title,
						"redirects":1,
						"titles":title}
		req = requests.get("https://en.wikipedia.org/w/api.php", params=param_dict)
		results = req.json()
		#print(results)

		for pageid, info in results['query']['pages'].items():
			if 'langlinks' in info.keys():
				for lang in info['langlinks']:
					#print(lang)
					wikipedia.set_lang(lang['lang'])
					page = wikipedia.page(lang['*'])
					content = page.content
					retdict[lang['lang']] = content
			else:
				retdict[lang_title]="NONE"
	print(retdict.keys())
	return retdict

# Combine multiple translated articles into a dictionary in the following form:
# {title: [title1, title2, title3 ... titleN], en: [en-text1, en-text2...], ... }

def compile_article_dict(article_list):
	article_dict = {"title":[], "en":[], "zh":[], "es":[], "de":[], "ru":[], "ja":[]}
	new_article_dict = {}
	for article in article_list:
		new_article_dict = fetch_article(article)
		#print(new_article_dict.keys())
		for k in new_article_dict.keys() & article_dict.keys():
			# Assuming actually changes the list in article_dict
			article_dict[k].append(new_article_dict[k])
	return article_dict

# Given dictionary with multiple languages titles/articles, creates a pandas dataframe
# with following headers: Title | en text | zh text | es text | de text | ru text | ja text
def articles_to_dataframe_append(article_dict):
	article_df = pd.DataFrame.from_dict(article_dict)
	print(article_df.head())
	# Finally, place into csv for others to use.
	with open('multi-lang_articles_pandas_1.csv', 'a') as f:
		article_df.to_csv(path_or_buf=f, index=False, header=False)
	return article_df

def articles_to_dataframe(article_dict):
	article_df = pd.DataFrame.from_dict(article_dict)
	print(article_df.head())
	# Finally, place into csv for others to use.
	with open('multi-lang_articles_pandas_1.csv', 'w') as f:
		article_df.to_csv(path_or_buf=f, index=False, header=False)
	return article_df

def main():
	link_list = []
	# raw_article_links.txt is the list of title , link\n lines.
	with open('raw_article_links.txt', 'r') as raw_text:
		# Comes in format title, link\n title, link\n
		line = raw_text.readline()
		while line:
			link_list.append(line.split(",")[1].lstrip().strip('\n'))
			line = raw_text.readline()

		#print(link_list)
	raw_text.close()

	article_dict = compile_article_dict(link_list)

	# If creating new dataframe, uncomment this one and comment following one.
	#art_df = articles_to_dataframe(article_dict)
	art_df = articles_to_dataframe_append(article_dict)
	#print(art_df.head())

if __name__ == '__main__':
	main()


from typing import Optional, Dict, Any, Union, List

from phidata.asset.table.sql.postgres import PostgresTable
from phidata.workflow import Workflow
from phidata.task import TaskArgs, task
from phidata.utils.log import logger

from data.products.tiingo.nasdaq_100 import nasdaq_100_tickers
from data.products.tiingo.sp_500 import sp_500_tickers
from workspace.config import dev_db, pg_db_connection_id

##############################################################################
## This file defines a workflow that downloads daily stock prices from tiingo
## The workflow is part of the tiingo data product
##############################################################################

# Step 1: Define a postgres table named `daily_prices`.
prices_table = PostgresTable(
    name="daily_prices",
    db_conn_id=pg_db_connection_id,
    db_conn_url=dev_db.get_db_connection_url_local(),
)

# Step 2: Build a workflow that loads the prices_table
# 2.1: Define typed inputs for our workflow
#   Create a class that inherits from TaskArgs
#   and contains the inputs for our task as class variables
class LoadPricesArgs(TaskArgs):
    # The table to load
    prices_table: PostgresTable = prices_table
    # Tickers to get prices for, as a string or list of strings
    tickers: Union[str, List[str]] = ["AAPL", "GOOG"]
    # start_date: Start of price download range in YYYY-MM-DD format.
    start_date: Optional[str] = None
    # end_date: End of price download range in YYYY-MM-DD format.
    end_date: Optional[str] = None
    # Rows to cache before writing to db
    cache_size: int = 5000
    frequency: str = "daily"
    # Tiingo Api key should be provided using the TIINGO_API_KEY
    # env variable. But for local testing, we can pass the api_key here if needed
    api_key: Optional[str] = None
    # If True, will drop table before loading data, thereby rewriting the table
    drop_table_before_load: bool = False

# 2.2: Write a task to drop daily data.
@task
def drop_prices(**kwargs) -> bool:
    """
    This task drops daily data before loading, so we dont have duplicates
    """
    args = LoadPricesArgs.from_kwargs(kwargs)
    run_date = args.run_date

    # drop_table_before_load
    if args.drop_table_before_load:
        logger.info(f"Dropping table: {args.prices_table.name}")
        args.prices_table.delete()
    # or drop rows for current date so we dont have duplicates
    else:
        logger.info(f"Dropping data for: {run_date}")
        args.prices_table.run_sql_query(
            f"DELETE FROM {args.prices_table.name} WHERE ds = '{run_date}'"
        )
    return True

# 2.3: Instantiate the task
drop = drop_prices()

# 2.4: Write a task to load daily prices
@task
def load_ticker_prices(**kwargs) -> bool:

    import pandas as pd
    from tiingo import TiingoClient

    # Get inputs as typed arguments by creating LoadPricesArgs from kwargs
    args: LoadPricesArgs = LoadPricesArgs.from_kwargs(kwargs)
    # logger.info(f"args: {args}")

    run_date = args.run_date
    if args.run_date is None:
        logger.error("Invalid run_date")
        return False
    logger.info(f"Loading {args.prices_table.name} for {run_date}")

    # Build tiingo_config
    tiingo_config: Dict[str, Any] = {
        "session": True,
    }
    # Set TIINGO_API_KEY if provided
    if args.api_key is not None:
        tiingo_config["api_key"] = args.api_key

    # Build TiingoClient
    tiingo_client: TiingoClient = TiingoClient(tiingo_config)

    # List of tickers to read prices for
    tickers_list: List[str] = []

    # If a ticker is provided as a str, convert to a list
    if isinstance(args.tickers, str):
        tickers_list = [args.tickers]
    elif isinstance(args.tickers, list):
        tickers_list = args.tickers

    # Get ticker prices and load prices_table
    prices_df: pd.DataFrame = pd.DataFrame()
    for ticker in tickers_list:
        logger.info(f"Getting prices for {ticker}")
        try:
            single_ticker_price = tiingo_client.get_dataframe(
                tickers=ticker,
                startDate=args.start_date,
                endDate=args.end_date,
                frequency=args.frequency,
            )
            single_ticker_price["ticker"] = ticker
        except Exception as e:
            logger.warning(
                f"Received error with {ticker}: {e}. Continuing to next ticker"
            )
            continue

        prices_df = pd.concat([prices_df, single_ticker_price])

        # write to table if rows_in_df > cache_size
        rows_in_df = prices_df.shape[0]
        if rows_in_df >= args.cache_size:
            prices_df["ds"] = run_date
            prices_df.reset_index(drop=True, inplace=True)
            prices_df.set_index(["ds", "ticker"], inplace=True)
            write_success = args.prices_table.write_pandas_df(
                prices_df, if_exists="append"
            )
            if write_success:
                # only clear existing df if write is successful
                prices_df = pd.DataFrame()

    # write final set of rows
    prices_df["ds"] = run_date
    prices_df.reset_index(drop=True, inplace=True)
    prices_df.set_index(["ds", "ticker"], inplace=True)

    # logger.info("Sample data:")
    # logger.info(prices_df[:5])
    return args.prices_table.write_pandas_df(prices_df, if_exists="append")

# 2.5: Instantiate the task to load daily nasdaq prices
# Because we are reusing the load_ticker_prices task, we need to provide
#   a unique name so airflow can create separate tasks for each
# Run this:
#   Locally: `phi wf run tiingo:prices:nasdaq`
#   In a Dev databox: `phi wf run tiingo:prices:nasdaq -e dev`
#   In a Prd databox: `phi wf run tiingo:prices:nasdaq -e prd`
load_nasdaq = load_ticker_prices(
    name="load_nasdaq",
    tickers=nasdaq_100_tickers,
)

# 2.6: Instantiate the task to load daily s&p 500 prices
# Run this:
#   Locally: `phi wf run tiingo:prices:sp500`
#   In a Dev databox: `phi wf run tiingo:prices:sp500 -e dev`
#   In a Prd databox: `phi wf run tiingo:prices:sp500 -e prd`
load_sp500 = load_ticker_prices(
    name="load_sp500",
    tickers=sp_500_tickers,
)

# 2.6: Create a Workflow object and add the tasks
prices = Workflow(
    name="prices",
    tasks=[drop, load_nasdaq, load_sp500],
    graph={
        load_nasdaq: [drop],
        load_sp500: [drop],
    },
    outputs=[prices_table],
)


import json
from asgiref.sync import async_to_sync
from channels.generic.websocket import WebsocketConsumer
from django.utils import timezone
from chat.models import ChatMessage, Chat
class ChatConsumer(WebsocketConsumer):
    def connect(self):
        self.room_name = self.scope["url_route"]["kwargs"]["room_name"]
        self.room_group_name = "chat_%s" % self.room_name

        # Join room group
        async_to_sync(self.channel_layer.group_add)(
            self.room_group_name, self.channel_name
        )

        self.accept()

    def disconnect(self, close_code):
        # Leave room group
        async_to_sync(self.channel_layer.group_discard)(
            self.room_group_name, self.channel_name
        )

    # Receive message from WebSocket
    def receive(self, text_data):
        text_data_json = json.loads(text_data)
        message = text_data_json["message"]
        print("data: ",text_data_json)
        user=self.scope["user"]
        chat = Chat.objects.get(id=text_data_json["roomName"])

        ChatMessage.objects.create(text=message, sender=chat.first_user, receiver=chat.second_user, chat_id=chat, timestamp=timezone.now())
        # Send message to room group
        async_to_sync(self.channel_layer.group_send)(
            self.room_group_name, {"type": "chat_message", "message": message,"user":user.username}
        )

    # Receive message from room group
    def chat_message(self, event):
        message = event["message"]
        user=event["user"]
        print(event)
        # Send message to WebSocket
        self.send(text_data=json.dumps({"message": message,"user":user}))


from naval_battle.model.boards.board import Board, CellType, BoardException
import pytest

def test_grid_getter():
    board = Board(2, 2)

    expected_grid = [[CellType.WATER, CellType.WATER], [CellType.WATER, CellType.WATER]]

    assert board.grid == expected_grid

def test_rows_getter():
    board = Board(2, 3)

    assert board.rows == 2

def test_columns_getter():
    board = Board(2, 3)

    assert board.columns == 3

def test_create_board_with_negative_row_should_fail():
    with pytest.raises(
        BoardException,
        match="O board não pode ser criado com um número negativo de linhas",
    ):
        Board(-1, 2)

def test_create_board_with_negative_column_should_fail():
    with pytest.raises(
        BoardException,
        match="O board não pode ser criado com um número negativo de colunas",
    ):
        Board(2, -1)

def test_create_board_with_more_than_ten_rows_should_fail():
    with pytest.raises(
        BoardException,
        match="O board não pode ser criado com um número maior que dez de linhas",
    ):
        Board(11, 5)

def test_create_board_with_more_than_ten_columns_should_fail():
    with pytest.raises(
        BoardException,
        match="O board não pode ser criado com um número maior que dez de colunas",
    ):
        Board(5, 11)

def test_str_method():
    board = Board(1, 5)

    grid = board.grid

    grid[0][0] = CellType.SHIP

    line_one, line_two = str(board).split("\n")

    assert line_one == "   0⃣  1⃣  2⃣  3⃣  4⃣"
    assert line_two == "0⃣  🚢 🟦 🟦 🟦 🟦"


import serial
import keyboard

# this port address is for the serial tx/rx pins on the GPIO header
SERIAL_PORT = 'COM6'
# be sure to set this to the same rate used on the Arduino
SERIAL_RATE = 115200

def main():
	ser = serial.Serial(SERIAL_PORT, SERIAL_RATE)
	while True:
		baca = ser.readline().decode('utf-8')
		reading = int(baca)

		print(reading)

		if reading == 1:
			print("atas")
			keyboard.press_and_release('up')
		elif reading == 2:
			keyboard.press_and_release('down')

		#keyboard.wait('esc')

if __name__ == "__main__":
    main()


from PyQt5 import uic
from PyQt5.QtWidgets import QSizePolicy, QDialog, QMessageBox
from PyQt5.QtCore import pyqtSignal, QDate
from datetime import datetime
import model.main as model

DB_PATH = './data/'

Ui_NewWell, QtBaseClass = uic.loadUiType("./resources/newWell.ui")

class NewWell(QDialog, Ui_NewWell):
    sessionChanged = pyqtSignal(model.Session)

    def __init__(self, parent=None):
        super(NewWell, self).__init__(parent)
        Ui_NewWell.__init__(self)
        self.setupUi(self)
        # controller handling
        today = QDate(datetime.today())
        self.dateEdit.setDate(today)
        self.session = model.Session()
        # connections
        self.okButton.clicked.connect(self.store_data)
        self.cancelButton.clicked.connect(self.close)

    def store_data(self):
        # Pass data from view to model
        self.model = model.Well()
        self.model.well['name'] = self.nameEdit.text()
        self.model.well['field'] = self.fieldEdit.text()
        self.model.well['area'] =  self.areaEdit.text()
        self.model.well['province'] = self.provinceEdit.text()
        self.model.well['country'] = self.countryEdit.text()
        self.model.well['company'] = self.companyEdit.text()
        self.model.well['driller'] = self.drillerEdit.text()
        self.model.well['operator'] = self.operatorEdit.text()
        self.model.well['witness'] = self.witnessEdit.text()
        self.model.well['date'] = self.dateEdit.date().toString("yyyy-MM-dd")
        self.model.well['service'] = self.serviceEdit.text()
        self.model.well['comments'] = self.commentsEdit.toPlainText()
        self.model.well['footNote'] = self.footNoteEdit.toPlainText()
        self.model.well['inDate'] = datetime.today().\
                                        strftime("%Y-%m-%d %H:%M:%S")

        self.session.active['well'] = self.model.well['name']
        self.session.active['run'] = 1
        self.session.active['DBpath'] = "{}{}.db".format(
                                            DB_PATH,
                                            self.model.well['field'])
        passTable = model.Pass().\
                create_table(self.session.active['DBpath'])
        self.session.active['pass'] = passTable
        self.session.active['mode'] = 'realtime'

        print(self.model.well.values()) # DEBUG

        # Store well data, emit session parameters and link well_run_pass table
        error = self.model.write()
        if error:
            self.dialog_critical(error)
        else:
            self.sessionChanged.emit(self.session)

        error  = model.WellRunTable().write(self.session)
        if error:
            self.dialog_critical(error)
        else:
            self.close()

    def dialog_critical(self, s):
        dlg = QMessageBox(self)
        dlg.setText(s)
        dlg.setIcon(QMessageBox.Critical)
        dlg.show()


from rich.console import Console
from rich.columns import Columns
from rich.panel import Panel
from rich.table import Table
from rich import box
from classes.character.character import Character

from factories.character.character_factory import CharacterFactory
from factories.character.life_path_factory import LifePathFactory
from factories.stats_factory import StatsFactory
from factories.weapon.melee_weapon_factory import MeleeWeaponFactory
from factories.weapon.weapon_factory import WeaponFactory
from factories.weapon.guns_factory import GunFactory
from utils.dises import get_random_d10, get_random_d6

# print('STATS:    ', character._stats.__dict__)
# print('SKILLS:   ', character._skills.__dict__)
# print('LIFE PATH:   ', character._life_path.__dict__)

def character_list(character: Character):
    console = Console()
    name = Panel('[red]' + character._name, style="red",)
    role = Panel(character._role, style="red",)
    hits = Panel(
        f'[red]{character._hit_points}[/red] / [green]{character._max_hit_points}[/green]', style="red",)

    # STATS
    stats = []
    for key, value in character._stats.__dict__.items():
        stats.append(f'{key[1:].capitalize()}: {value} ')

    # Skills
    skills = []
    for key, value in character._skills.__dict__.items():
        skills.append(f'{key[1:].capitalize()}: [cyan bold]{value} ')

    skills_table = Table(title='Skills', show_header=False,
                         width=70, min_width=70, box=box.ROUNDED)
    for i in range(0, 21, 3):
        skills_table.add_row(skills[i], skills[i+1], skills[i+2])

    # Life path
    life_path = []
    for key, value in character._life_path.__dict__.items():
        if type(value) == str:
            life_path.append([key, value])
        elif type(value) == list and len(value) == 0:
            life_path.append([key, 'None'])
        else:
            actors = ''
            for i in value:
                actors += i + '\n'
            life_path.append([key, actors[:-1]])
    # print(life_path)
    console.print(Columns((name, role, hits)))
    console.print(Panel(Columns(stats), style="red",
                        title='[red]STATS', width=70, ))
    console.print(skills_table, style="red")
    for i in life_path:
        console.print(Panel(i[1], style="red", title=i[0], width=70))

if __name__ == '__main__':
    stats_factory = StatsFactory()
    life_path_factory = LifePathFactory()

    melee_weapon_factory = MeleeWeaponFactory()
    gun_factory = GunFactory()
    weapon_factory = WeaponFactory(
        melee_weapon_factory, gun_factory)
    character_factory = CharacterFactory(
        stats_factory, life_path_factory, weapon_factory)

    character = character_factory.create_random_fixer('Hero')

    character_list(character)


from collections import OrderedDict, namedtuple

from multicorn import ForeignDataWrapper
from multicorn.utils import log_to_postgres, ERROR, WARNING, INFO, DEBUG

from .bqclient import BqClient

class ConstantForeignDataWrapper(ForeignDataWrapper):

    # Default vars
    client = None  # BqClient instance
    partitionPseudoColumn = 'partition_date'  # Name of the partition pseudo column
    # Pseudo column to fetch `count(*)` when using the remote counting and grouping feature
    countPseudoColumn = '_fdw_count'
    castingRules = None  # Dict of casting rules when using the `fdw_casting` option

    def __init__(self, options, columns):
        """
            Initialize instance, set class level vars
        """

        super(ConstantForeignDataWrapper, self).__init__(options, columns)

        # Set options
        self.setOptions(options)

        # Set table columns
        self.columns = columns

        # Set data types and conversion rules mapping
        self.setDatatypes()
        self.setConversionRules()

    def setOptions(self, options):
        """
            Set table options at class level
        """

        # Set options at class scope
        try:
            self.dataset = options['fdw_dataset']
            self.table = options['fdw_table']
            self.convertToTz = options.get('fdw_convert_tz')

            # Set verbose option
            self.setOptionVerbose(options.get('fdw_verbose'))

            # Set SQL dialect
            self.setOptionSqlDialect(options.get('fdw_sql_dialect'))

            # Set grouping option
            self.setOptionGroupBy(options.get('fdw_group'))

            # Set casting rules
            self.setOptionCasting(options.get('fdw_casting'))
        except KeyError:
            log_to_postgres(
                "You must specify these options when creating the FDW: fdw_dataset, fdw_table", ERROR)

    def setDatatypes(self):
        """
            Set data types mapping
        """

        # Create a named tuple
        datatype = namedtuple('datatype', 'postgres bq_standard bq_legacy')

        self.datatypes = [
            datatype('text', 'STRING', 'STRING'),
            # datatype('bytea', 'BYTES', 'BYTES'), # Not supported, need testing for support
            datatype('bigint', 'INT64', 'INTEGER'),
            datatype('double precision', 'FLOAT64', 'FLOAT'),
            datatype('boolean', 'BOOL', 'BOOLEAN'),
            datatype('timestamp without time zone', 'TIMESTAMP', 'TIMESTAMP'),
            datatype('date', 'DATE', 'DATE'),
            datatype('time without time zone', 'TIME', 'TIME'),
            datatype('timestamp without time zone', 'DATETIME', 'DATETIME'),
        ]

    def setConversionRules(self):
        """
            Set list of allowed conversion rules
        """

        # Create a named tuple
        conversionRule = namedtuple(
            'conversionRule', 'bq_standard_from bq_standard_to')

        self.conversionRules = [
            conversionRule('INT64', ['BOOL', 'FLOAT64', 'INT64', 'STRING']),
            conversionRule('FLOAT64', ['FLOAT64', 'INT64', 'STRING']),
            conversionRule('BOOL', ['BOOL', 'INT64', 'STRING']),
            conversionRule('STRING', ['BOOL', 'BYTES', 'DATE', 'DATETIME',
                                      'FLOAT64', 'INT64', 'STRING', 'TIME', 'TIMESTAMP']),
            conversionRule('BYTES', ['BYTES', 'STRING']),
            conversionRule(
                'DATE', ['DATE', 'DATETIME', 'STRING', 'TIMESTAMP']),
            conversionRule(
                'DATETIME', ['DATE', 'DATETIME', 'STRING', 'TIME', 'TIMESTAMP']),
            conversionRule('TIME', ['STRING', 'TIME']),
            conversionRule(
                'TIMESTAMP', ['DATE', 'DATETIME', 'STRING', 'TIME', 'TIMESTAMP']),
            conversionRule('ARRAY', ['ARRAY']),
            conversionRule('STRUCT', ['STRUCT']),
        ]

    def setOptionSqlDialect(self, standard_sql=None):
        """
            Set a flag for the SQL dialect.
            It can be `standard` or `legacy`. `standard` will be the default
        """

        self.dialect = 'standard'

        if standard_sql == 'legacy':
            self.dialect = 'legacy'

        # Verbose log
        if self.verbose:
            log_to_postgres("Set SQL dialect to `" + self.dialect + "`", INFO)

    def setOptionGroupBy(self, group):
        """
            Set a flag `self.groupBy` as `True` if `group` contains the string 'true'
            Otherwise, set it as `False`
        """

        if group == 'true':
            self.groupBy = True
            return

        self.groupBy = False

    def setOptionVerbose(self, verbose):
        """
            Set a flag `self.verbose` as `True` if `verbose` contains the string 'true'
            Otherwise, set it as `False`
        """

        if verbose == 'true':
            self.verbose = True
            return

        self.verbose = False

    def setOptionCasting(self, castingRules):
        """
            Conversion rules are received as a string, for example: '{"key": "FLOAT64", "datetime": "DATE"}'

            The string will be converted to a dict
        """

        if castingRules:
            # Cast string as a dict
            try:
                import ast
                self.castingRules = ast.literal_eval(castingRules)
            except Exception as e:
                log_to_postgres(
                    "fdw_casting conversion failed: `" + str(e) + "`", ERROR)

            # For security reasons, ensure that the string was correctly casted as a dict
            try:
                if type(self.castingRules) is not dict:
                    raise ValueError('fdw_casting format is incorrect.')
            except Exception as e:
                log_to_postgres(
                    "fdw_casting conversion failed: `" + str(e) + "`", ERROR)

    def getClient(self):
        """
            Manage a pool of instances of BqClient
            If the user uses different private keys in different tables, this method will return
               the correct instance of BqClient class associated to the table private key
        """

        # Returns an existing instance
        if self.client:
            return self.client

        # Or create a new instance
        return self.setClient()

    def setClient(self):
        """
            Attempt to connect to BigQuery client
        """

        try:
            # Attempt connection
            bq = BqClient()
            bq.setClient()

            # Verbose log
            if self.verbose:
                log_to_postgres(
                    "Connection to BigQuery client with BqClient instance ID " + str(id(bq)), INFO)

            # Add to pool
            self.client = bq

            return bq
        except RuntimeError:
            log_to_postgres(
                "Connection to BigQuery client failed", ERROR)

    def execute(self, quals, columns):
        """
            Executes a query
        """

        # # Verbose log
        # if self.verbose:
        #     log_to_postgres('Quals...', INFO)
        #     log_to_postgres(quals, INFO)
        #     log_to_postgres('Columns...', INFO)
        #     log_to_postgres(columns, INFO)

        # Returns instance of BqClient
        client = self.getClient()

        # Prepare query
        query, parameters = self.buildQuery(quals, columns)

        # Run query
        client.runQuery(query, parameters, self.dialect)

        # Return query output
        for row in client.readResult():
            # Create an ordered dict with the column name and value
            # Example: `OrderedDict([('column1', 'value1'), ('column2', value2)])`
            line = OrderedDict()
            for column in columns:
                line[column] = row[column]

            yield line

    def buildQuery(self, quals, columns):
        """
            Builds a BigQuery query
        """

        # Set query var
        query = ''

        # Add SELECT clause
        query += 'SELECT ' + self.buildColumnList(columns)

        # Add FROM clause
        query += " FROM `" + self.dataset + "." + self.table + "` "

        # Add WHERE clause
        clause, parameters = self.buildWhereClause(quals)
        query += clause

        # Add group by
        if self.groupBy:
            groupByColumns = self.buildColumnList(columns, 'GROUP_BY')
            if groupByColumns:
                query += ' GROUP BY ' + \
                    self.buildColumnList(columns, 'GROUP_BY')

        # Verbose log
        if self.verbose:
            log_to_postgres("Prepared query: `" + query + "`", INFO)

        return query, parameters

    def buildColumnList(self, columns, usage='SELECT'):
        """
            Build the SELECT clause of the SQL query
        """

        clause = ''

        # Disable aliases for Group By
        useAliases = True
        if usage == 'GROUP_BY':
            useAliases = False

        if columns:  # If we have columns
            for column in columns:
                if column == self.countPseudoColumn:  # Pseudo column to count grouped rows
                    if usage == 'SELECT':
                        clause += "count(*) " + \
                            self.addColumnAlias(column, useAliases) + ", "
                elif column == self.partitionPseudoColumn:  # Partition pseudo column
                    clause += "_PARTITIONTIME " + \
                        self.addColumnAlias(column, useAliases) + ", "
                else:  # Any other column
                    # Get column data type
                    dataType = self.getBigQueryDatatype(column)

                    # Save column original name
                    columnOriginalName = column

                    # If the data type is a date or a timestamp
                    if dataType in ['DATE', 'TIMESTAMP']:
                        column = self.setTimeZone(column, dataType)

                    # Data type casting
                    column = self.castColumn(
                        column, columnOriginalName, dataType)

                    clause += column + " " + \
                        self.addColumnAlias(
                            columnOriginalName, useAliases) + ", "

            # Remove final `, `
            clause = clause.strip(', ')
        elif usage == 'SELECT':  # Otherwise fetch all
            clause += "*"

        return clause

    def setTimeZone(self, column, dataType):
        """
            If the option `fdw_convert_tz` is used, convert the time zone automatically from UTC to the desired time zone
        """

        # Option is set
        if self.convertToTz:
            if dataType == 'DATE':  # BigQuery column type is `DATE`
                return 'DATE(' + column + ', "' + self.convertToTz + '") '
            else:  # BigQuery column type is `TIMESTAMP`
                return 'DATETIME(' + column + ', "' + self.convertToTz + '") '

        # Option is not set
        return column

    def castColumn(self, column, columnOriginalName, dataType):
        """
            If the option `fdw_casting` is used, this method will attempt to cast the column to the new type
        """

        if self.castingRules and columnOriginalName in self.castingRules:  # If we have casting rule for this column
            # Get desired casting
            castTo = self.castingRules[columnOriginalName]

            # Find if we have a matching rule
            rule = [
                conversionRule for conversionRule in self.conversionRules if conversionRule.bq_standard_from == dataType.upper()]

            if rule:
                # Check if casting from the original data type to the new one is supported
                if castTo.upper() in rule[0].bq_standard_to:
                    return 'CAST(' + column + ' as ' + castTo.upper() + ')'
                else:
                    log_to_postgres("Casting from the data type `" + dataType.upper(
                    ) + "` to the data type `" + castTo.upper() + "` is not permitted.", ERROR)
            else:
                log_to_postgres(
                    "Casting from the data type `" + dataType.upper() + "` is not permitted.", ERROR)

        # Option is not set
        return column

    def addColumnAlias(self, alias, useAliases=True):
        """
            Returns a string "as `alias`" if `useAliases` is `True`
        """

        if useAliases:
            return " as " + alias

        return ''

    def buildWhereClause(self, quals):
        """
            Build the WHERE clause of the SQL query
        """

        clause = ''
        parameters = []

        # Add WHERE clause
        # `quals` example: `[Qual('test', '=', 'test 2'), Qual('test', '~~', '3')]`
        if quals:
            clause += "WHERE "
            for qual in quals:
                if qual.field_name == self.partitionPseudoColumn:
                    clause += "_PARTITIONTIME " + \
                        str(self.getOperator(qual.operator)) + " ?"

                    # Format date as a timestamp
                    value = qual.value.strftime("%Y-%m-%d 00:00:00")

                    # Force data type to `TIMESTAMP`
                    parameters.append(self.setParameter(
                        qual.field_name, 'TIMESTAMP', value))
                else:
                    clause += str(qual.field_name) + " " + \
                        str(self.getOperator(qual.operator)) + " ?"
                    parameters.append(self.setParameter(
                        qual.field_name, self.getBigQueryDatatype(qual.field_name), qual.value))

                # Add ` AND `
                clause += " AND "

        # Remove final ` AND `
        clause = clause.strip(' AND ')

        return (clause, parameters)

    def getOperator(self, operator):
        """
            Validate operator
        """

        # List of BigQuery operators supported
        # Exhaustive list: https://cloud.google.com/bigquery/docs/reference/standard-sql/functions-and-operators#operators
        # Non listed operators may or may not work
        operators = ['=', '<', '>', '<=', '>=', '!=', '<>', 'LIKE', 'NOT LIKE']

        # Mapping between multicorn operators and BigQuery operators
        mapping = {}
        mapping['~~'] = 'LIKE'
        mapping['!~~'] = 'NOT LIKE'

        if operator in operators:  # Operator is natively supported
            return operator
        elif operator in mapping:  # Multicorn operator has a BigQuery equivalent
            return mapping[operator]
        else:  # Operator is not supported
            log_to_postgres(
                "Operator `" + operator + "` is not currently supported", ERROR)

    def getBigQueryDatatype(self, column, dialect='standard'):
        """
            Returns the BigQuery standard SQL data type of a PostgreSQL column

            Example: `column1` has the PostgreSQL type `bigint` which is called `INT64` in BigQuery standard SQL
        """

        # Get PostgreSQL column type
        # Example: `timestamp without time zone`
        pgDatatype = self.columns[column].base_type_name

        for datatype in self.datatypes:  # For each known data types
            if datatype.postgres == pgDatatype:  # If the PostgreSQL data type matches the known data type
                # Returns equivalent BigQuery data type
                if dialect == 'legacy':
                    return datatype.bq_legacy
                else:
                    return datatype.bq_standard

        # Return a default data type in an attempt to save the day
        return 'STRING'

    def setParameter(self, column, type_, value):
        """
            Set a parameter in BigQuery client
        """

        # Verbose log
        if self.verbose:
            log_to_postgres(
                "Add query parameter `" + self.client.varToString(value) + "` for column `" + column + "` with the type `" + type_ + "`", INFO)

        return self.client.setParameter(type_, value)


# python3

from abc import ABC
from collections import namedtuple
from sys import stdin
from typing import AnyStr, IO, List
from unittest import TestCase

test = namedtuple('test', 'input expected')

class StackWithMax:
    def __init__(self):
        self.__stack = []
        self.__maxes = []

    def push(self, a: int):
        self.__maxes.append(max(a, self.__maxes[len(self.__maxes) - 1]) if self.__maxes else a)
        self.__stack.append(a)

    def pop(self) -> int:
        self.__maxes.pop()
        return self.__stack.pop()

    def max(self) -> int:
        return self.__maxes[len(self.__maxes) - 1]

class Processor:
    @staticmethod
    def process(src: IO) -> List[str]:
        buffer, stack = [], StackWithMax()

        for _ in range(int(src.readline())):
            query = src.readline().split()
            if query[0] == 'push':
                stack.push(int(query[1]))
            elif query[0] == 'pop':
                stack.pop()
            elif query[0] == 'max':
                buffer.append(stack.max())

        return buffer

class Fake(IO, ABC):
    def __init__(self, rows: List[str]):
        self.__i = -1
        self.__rows = [str(len(rows))] + rows

    def readline(self, limit: int = -1) -> AnyStr:
        self.__i += 1
        return self.__rows[self.__i]

class Test(TestCase):
    def test_stack_with_max(self):
        tests = [
            # samples
            test([
                'push 2',
                'push 1',
                'max',
                'pop',
                'max',
            ], [
                2,
                2,
            ]),
            test([
                'push 1',
                'push 2',
                'max',
                'pop',
                'max',
            ], [
                2,
                1,
            ]),
            test([
                'push 2',
                'push 3',
                'push 9',
                'push 7',
                'push 2',
                'max',
                'max',
                'max',
                'pop',
                'max',
            ], [
                9,
                9,
                9,
                9,
            ]),
            test([
                'push 1',
                'push 7',
                'pop',
            ], []),
            test([
                'push 7',
                'push 1',
                'push 7',
                'max',
                'pop',
                'max',
            ], [
                7,
                7,
            ]),
        ]
        for i, t in enumerate(tests):
            self.assertEqual(t.expected, Processor.process(Fake(t.input)), msg='at {} position'.format(i))

if __name__ == '__main__':
    for entry in Processor.process(stdin):
        print(entry)


import pyautogui
import os

mx, my = None, None
folderpath = None
filename = []

def getfilename(folderpath):
    for *_, files in os.walk(folderpath):
        for file in files:
            if '.msp' in file:
                filename.append(file)

def ptpdf():
    # pyautogui.hotkey('altleft','tab')
    for i in range(len(filename)):
        pyautogui.click(mx, my)
        pyautogui.typewrite(filename[i])
        pyautogui.press('enter')
        pyautogui.PAUSE = 3
        pyautogui.press('down')
        content_log.insert('1.0', '{}、{}'.format(i + 1, filename[i]))

import tkinter
import tkinter.filedialog
import tkinter.scrolledtext

window = tkinter.Tk()
window.title()
window.geometry()

content_log = tkinter.scrolledtext.ScrolledText(font=('None', 14), height=15)
content_log.pack(side='bottom')

def select():
    folderpath = tkinter.filedialog.askdirectory()
    content_log.insert('end', folderpath)

button_select = tkinter.Button(window, text='1、选择文件夹', font=('None', 12), width=15, height=1, command=select)
button_select.pack(side='left')

def run():
    getfilename(folderpath=folderpath)
    ptpdf()

button_run = tkinter.Button(window, text='2、开始处理', font=('None', 12), width=15, height=1, command=run)
button_run.pack(side='left')

window.mainloop()


import openai
import secret
from io import BytesIO
from PIL import Image

# pip3 install Pillow

openai.api_key = secret.API_KEY

def read_rgba_image(path,resize) -> bytes:
    image = Image.open(path)
    if resize is not None:
        image = image .resize(resize)
    image = image.convert('RGBA')
    bytes_stream = BytesIO()
    image.save(bytes_stream, format='PNG')
    return bytes_stream.getvalue()

image_bytes = read_rgba_image("Image_generation/img/image.png",resize=(1024,1024))
mask_bytes = read_rgba_image("Image_generation/img/mask.png",resize=(1024,1024))

my_prompt = "a gold retriever is sitting there"
print(my_prompt)

response = openai.Image.create_edit(
    image=image_bytes,
    mask=mask_bytes,
    prompt=my_prompt,
    n=1,
    size="1024x1024"
)

for i in range(len(response['data'])):
    print("\n url: " + response['data'][i]['url'])


import os
import shutil
import unittest
from pathlib import Path

from Main.kmer.Utils.minimizer.DefaultMinimizerHandler import DefaultMinimizerHandler

class MyTestCase(unittest.TestCase):
    def test_something(self):
        self.assertEqual(True, False)  # add assertion here

    def test_write_minimizers(self):
        g_utils = DefaultMinimizerHandler(3, 2)
        self.assertEqual("CU", g_utils.get_minimizers_from_kmer("ACU"))
        g_utils = DefaultMinimizerHandler(3, 2)
        self.assertEqual("CC", g_utils.get_minimizers_from_kmer("UCC"))
        g_utils = DefaultMinimizerHandler(3, 2)
        self.assertEqual("GG", g_utils.get_minimizers_from_kmer("CGG"))

    def test_write_kmer_to_partition(self):
        g_utils = DefaultMinimizerHandler(3, 2)
        kmer_list = self.__get_kmer_list()
        minimizer = g_utils.get_minimizers_from_kmer("ACU")
        self.write_and_check_file(kmer_list,minimizer,g_utils,"CU.bin","file1.db","AC")
        minimizer = g_utils.get_minimizers_from_kmer("UCC")
        self.write_and_check_file(kmer_list, minimizer, g_utils, "CC.bin", "file1.db","UG")
        minimizer = g_utils.get_minimizers_from_kmer("CGG")
        self.write_and_check_file(kmer_list, minimizer, g_utils, "GG.bin", "file1.db","CU")
        p = self.__get_partitions_path()
        p = os.path.join(p,"file1.db")
        shutil.rmtree(p)

    def write_and_check_file(self,kmer_list,minimizer,g_utils,filename,partname,expected_value):
        p = self.__generate_partitions(partname)
        file_path = os.path.join(p, filename)
        l1 = kmer_list[0:1]
        g_utils.find_super_kmer_and_write(kmer_list, minimizer, p)
        readed_value = self.__read_value_from_file(file_path)
        self.assertEqual(expected_value, readed_value)

    def __read_value_from_file(self,file_path):
        with open(file_path, "rb") as file:
            readed_value = file.read().decode('utf-8')
            file.close()
        return readed_value

    def __get_kmer_list(self):
        l = list()
        l.append("ACU")
        l.append("CUC")
        l.append("UCC")
        l.append("CCG")
        l.append("CGG")
        l.append("GGU")
        return l

    def __generate_partitions(self, subfolder):
        path = self.__get_partitions_path()
        path_p1 = os.path.join(path, subfolder)
        if os.path.exists(path_p1):
            shutil.rmtree(path_p1)
        os.mkdir(path_p1)
        return path_p1

    def __get_partitions_path(self):
        project_root = Path(os.path.abspath(os.path.dirname(__file__)))
        project_root = project_root.parent.absolute()
        path = os.path.join(project_root, "resource")
        path = os.path.join(path, "partitions")
        return path

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


from Tkinter import *
from PIL import ImageTk, Image
import tkFont
import os

win = Tk()
win.title("EcoSense")
win.geometry("800x480")

load = Image.open("image.jpg")
logo = ImageTk.PhotoImage(load)
myFont = tkFont.Font(family='Helvetica', size=24, weight='bold')

def exitProgram():
	print("Exit Button pressed")
	win.quit()

labelText = Label(win, text="\n\n\n<Insert Item>", font=myFont)
labelText.pack()

#logoPanel = Label(win, image=logo)
#logoPanel.image = logo
#ogoPanel.pack()
#logoPanel.pack(side=BOTTOM, fill="both", expand="yes")

exitButton = Button(win, text = "Exit", font = myFont, command = exitProgram, height = 2, width = 6)
exitButton.pack(side = BOTTOM)

mainloop()


# 패키지 설치
import torch
from torch import nn
import torch.nn.functional as F
import torch.optim as optim
from torch.utils.data import Dataset, DataLoader
import gluonnlp as nlp
import numpy as np
from tqdm import tqdm

import os

# kobert 라이브러리 임포트
from kobert import get_tokenizer
from kobert import get_pytorch_kobert_model

# transformers 라이브러리 임포트
from transformers import AdamW
from transformers.optimization import get_cosine_schedule_with_warmup

# GPU 사용 세팅
device = torch.device('cuda:0')

# 모델 불러오기
bertmodel, vocab = get_pytorch_kobert_model(cachedir=".cache")

# 데이터셋 다운로드
os.system('wget -O .cache/ratings_train.txt http://skt-lsl-nlp-model.s3.amazonaws.com/KoBERT/datasets/nsmc/ratings_train.txt')
os.system('wget -O .cache/ratings_test.txt http://skt-lsl-nlp-model.s3.amazonaws.com/KoBERT/datasets/nsmc/ratings_test.txt')

# 데이터셋 불러오기
dataset_train = nlp.data.TSVDataset(".cache/ratings_train.txt", field_indices=[1,2], num_discard_samples=1)
dataset_test = nlp.data.TSVDataset(".cache/ratings_test.txt", field_indices=[1,2], num_discard_samples=1)

# Tokenizer 가져오기
tokenizer = get_tokenizer()
tok = nlp.data.BERTSPTokenizer(tokenizer, vocab, lower=False)

# 데이터셋 클래스 정의
class BERTDataset(Dataset):
    def __init__(self, dataset, sent_idx, label_idx, bert_tokenizer, max_len,
                pad, pair):
        transform = nlp.data.BERTSentenceTransform(
            bert_tokenizer, max_seq_length=max_len, pad=pad, pair=pair)

        self.sentences = [transform([i[sent_idx]]) for i in dataset]
        self.labels = [np.int32(i[label_idx]) for i in dataset]

    def __getitem__(self, i):
        return (self.sentences[i] + (self.labels[i], ))

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

class BERTPredictDataset(Dataset):
	def __init__(self, sentence, sent_idx, label_idx, bert_tokenizer, max_len, pad, pair):
		transform = nlp.data.BERTSentenceTransform(bert_tokenizer, max_seq_length=max_len, pad=pad, pair=pair)
		self.sentence = [transform(sentence)]
		self.labels = [np.int32(0)]		# 무의미
	def __getitem__(self, index):
		return self.sentence[0]
	def __len__(self):
		return len(self.labels)

# hyperparameter 세팅
max_len = 64
batch_size = 64
warmup_ratio = 0.1
num_epochs = 1
max_grad_norm = 1
log_interval = 200
learning_rate =  5e-5

# 데이터셋 인스턴스화
data_train = BERTDataset(dataset_train, 0, 1, tok, max_len, True, False)
data_test = BERTDataset(dataset_test, 0, 1, tok, max_len, True, False)

# DataLoader 인스턴스화
train_dataloader = torch.utils.data.DataLoader(data_train, batch_size=batch_size, num_workers=5)
test_dataloader = torch.utils.data.DataLoader(data_test, batch_size=batch_size, num_workers=5)

# 모델 클래스 정의
class BERTClassifier(nn.Module):
    def __init__(self,
                bert,
                hidden_size = 768,
                num_classes=2,
                dr_rate=None,
                params=None):
        super(BERTClassifier, self).__init__()
        self.bert = bert
        self.dr_rate = dr_rate

        self.classifier = nn.Linear(hidden_size , num_classes)
        if dr_rate:
            self.dropout = nn.Dropout(p=dr_rate)

    def gen_attention_mask(self, token_ids, valid_length):
        attention_mask = torch.zeros_like(token_ids)
        for i, v in enumerate(valid_length):
            attention_mask[i][:v] = 1
        return attention_mask.float()

    def forward(self, token_ids, valid_length, segment_ids):
        attention_mask = self.gen_attention_mask(token_ids, valid_length)

        _, pooler = self.bert(input_ids = token_ids, token_type_ids = segment_ids.long(), attention_mask = attention_mask.float().to(token_ids.device))
        if self.dr_rate:
            out = self.dropout(pooler)
        else:
            out = pooler
        return self.classifier(out)

# 모델 인스턴스화
model = BERTClassifier(bertmodel,  dr_rate=0.5).to(device)

# optimizer와 scheduler를 위한 세팅
# Prepare optimizer and schedule (linear warmup and decay)
no_decay = ['bias', 'LayerNorm.weight']
optimizer_grouped_parameters = [
    {'params': [p for n, p in model.named_parameters() if not any(nd in n for nd in no_decay)], 'weight_decay': 0.01},
    {'params': [p for n, p in model.named_parameters() if any(nd in n for nd in no_decay)], 'weight_decay': 0.0}
]

# optimizer, loss 인스턴스화
optimizer = AdamW(optimizer_grouped_parameters, lr=learning_rate)
loss_fn = nn.CrossEntropyLoss()

# iteration 관련 세팅
t_total = len(train_dataloader) * num_epochs
warmup_step = int(t_total * warmup_ratio)

# Scheduler 인스턴스화
scheduler = get_cosine_schedule_with_warmup(optimizer, num_warmup_steps=warmup_step, num_training_steps=t_total)

# accuracy 계산 함수
def calc_accuracy(X,Y):
    max_vals, max_indices = torch.max(X, 1)
    train_acc = (max_indices == Y).sum().data.cpu().numpy()/max_indices.size()[0]
    return train_acc

# Training Loop
for e in range(num_epochs):
    train_acc = 0.0
    test_acc = 0.0
    model.train()
    for batch_id, (token_ids, valid_length, segment_ids, label) in tqdm(enumerate(train_dataloader), total=len(train_dataloader)):
        optimizer.zero_grad()
        token_ids = token_ids.long().to(device)
        segment_ids = segment_ids.long().to(device)
        valid_length= valid_length
        label = label.long().to(device)
        out = model(token_ids, valid_length, segment_ids)
        loss = loss_fn(out, label)
        loss.backward()
        torch.nn.utils.clip_grad_norm_(model.parameters(), max_grad_norm)
        optimizer.step()
        scheduler.step()  # Update learning rate schedule
        train_acc += calc_accuracy(out, label)
        if batch_id % log_interval == 0:
            print("epoch {} batch id {} loss {} train acc {}".format(e+1, batch_id+1, loss.data.cpu().numpy(), train_acc / (batch_id+1)))
    print("epoch {} train acc {}".format(e+1, train_acc / (batch_id+1)))
    model.eval()
    for batch_id, (token_ids, valid_length, segment_ids, label) in tqdm(enumerate(test_dataloader), total=len(test_dataloader)):
        token_ids = token_ids.long().to(device)
        segment_ids = segment_ids.long().to(device)
        valid_length= valid_length
        label = label.long().to(device)
        out = model(token_ids, valid_length, segment_ids)
        test_acc += calc_accuracy(out, label)
    print("epoch {} test acc {}".format(e+1, test_acc / (batch_id+1)))

# 새로운 문장에 대해 쿼리하기
def infer(sentence):
    sample_dataset = BERTPredictDataset(sentence, 0, 1, tok, max_len, True, False)
    sample_dataloader =  torch.utils.data.DataLoader(sample_dataset, batch_size=1, num_workers=5)
    it = iter(sample_dataloader)
    token_ids, valid_length, segment_ids= next(it)
    token_ids = token_ids.long().to(device)
    segment_ids = segment_ids.long().to(device)
    model.eval()
    with torch.no_grad():
        out = model(token_ids, valid_length, segment_ids)
    print(out)
    return out[0,1].item()

print(infer('정말 최고의 식당입니다. 완전 강추!!😝'))
print(infer('괜찮긴 한데 가격이 좀 비싸요ㅠㅠ😐'))
print(infer('다시는 안 갈 것 같아😡'))