# -*- coding: utf-8 -*-
"""
Created on Fri Jun 16 09:49:42 2017
@author: sunhp
基本线条形状绘画
"""

import turtle
import math

def square(t,length):
   t.pd()
   for i in range(4):
       t.fd(length)
       t.lt(90)
   print(t)

def polyline(t,n,length,a):
    t.pd()
    for i in range(n):
        t.fd(length)
        t.lt(a)

def polygon(t,n,length):
    t.pd()
    a = 360 / n
    polyline(t,n,length,a)

def arc(t,r,a):
    t.pd()
    length = 2 * math.pi * r * a / 360
    n = int(length / 3) + 1
    step_l = length / n
    step_a = a / n
    polyline(t,n,step_l,step_a)

def flower(t,r,n):
    t.pd()
    a = 2 * (180 - 360 / n)
    b = 360 / n
    for i in range(n):
        t.lt(b)
        arc(t,r,a)

bob = turtle.Turtle()
flower(bob,60,n = 7)
turtle.mainloop()


import json
import xml.etree.ElementTree as ET
import numpy as np
import pandas as pd
import fiona
import geopandas as gpd
from shapely.geometry import Polygon
from tqdm import tqdm
from pyAgriculture.sorting_utils import find_by_key
from pyAgriculture.agriculture import PyAgriculture
import os
from pathlib import Path

class Grid(PyAgriculture):
    def __init__(self, path):
        super().__init__(path)

    def read_indata(self) -> list:
        tree = ET.parse(self.path + 'TASKDATA.xml')
        task_data_dict = {}
        self.task_dicts = self.add_children(task_data_dict, tree.getroot())
        tasks = []
        for key in task_data_dict['GRD']:
            grd = task_data_dict['GRD'][key]
            gpd_ = self.read_grid_binary_file(self.path + grd['G'], float(grd['A']), float(grd['B']), float(grd['C']),
                                              float(grd['D']), int(grd['F']), int(grd['E']))
            tasks.append(gpd_)
        return tasks

    @staticmethod
    def read_grid_binary_file(file_path: str, n_start, e_start, n_delta, e_delta, nr_n_cols, nr_e_cols
                              ) -> gpd.GeoDataFrame:
        with open(file_path + '.bin', 'rb') as fin:
            binary_data = fin.read()
        read_point = 0
        east_count = 0
        north_count = 0
        cols = list(np.arange(e_start, e_start + e_delta * (nr_e_cols + 1), e_delta))
        rows = list(np.arange(n_start, n_start + n_delta * (nr_n_cols + 1), n_delta))
        polygons = []
        a_s = []
        while read_point < len(binary_data):
            for a in np.frombuffer(binary_data, [('AAA', np.dtype('int32'))],
                                   count=1, offset=read_point):
                a_s.append(a[0])
                read_point += 4
                if east_count >= nr_e_cols:
                    east_count = 0
                    north_count += 1
                x = cols[east_count]
                y = rows[north_count]
                polygons.append(Polygon([(x, y), (x + e_delta, y), (x + e_delta, y + n_delta), (x, y + n_delta)]))
                east_count += 1
        grid_ = gpd.GeoDataFrame({'geometry': polygons,
                                  'Val_a': a_s})
        return grid_

if __name__ == '__main__':
    g = Grid('c:/dev/program/pyAgriculture11783/lund2/')
    grid_list = g.read_indata()
    for grid in grid_list:
        grid.to_file("c:/dev/program/pyAgriculture11783/lund2.shp")


from ..Model import LlmGenerator
from ..Embeddings import BaseEmbeddings
from ..Memory import ConversationVectorMemory, VectorMemoryCore
from ..Prompt.Conversation import get_conversation_prompt, DEFAULT_SYSTEM
import gradio as gr
from copy import deepcopy
from typing import List, Dict, Any, Iterator, Literal, Union, Optional

def ended(text: str, accept: List[str]) -> bool:
    """Check if the text is a complete text given the accepted list of ending strings.

    Args:
        text (str): Text to check.
        accept (List[str]): Accepted list of ending strings.

    Returns:
        bool: True if text is completed, else return False.
    """
    for i in accept:
        length = len(i)
        if len(text) >= length:
            if text[-length:] == i:
                return True
    return False

class ChatInterface:
    """Provide a GUI for user to chat with the llm.
    """
    def __init__(self, llm_generator: LlmGenerator, embeddings: BaseEmbeddings, ai_prefix: str = 'ASSISTANT', human_prefix: str = 'USER', mobile: bool = False) -> None:
        """_summary_

        Args:
            llm_generator (LlmGenerator): _description_
            embeddings (BaseEmbeddings): _description_
            ai_prefix (str, optional): _description_. Defaults to 'ASSISTANT'.
            human_prefix (str, optional): _description_. Defaults to 'USER'.
            mobile (bool): Defaultsto False.
        """
        self.model = llm_generator
        self.llm = self.model(temperature=0.8)
        self.embeddings = embeddings
        self.ai_prefix = ai_prefix
        self.human_prefix = human_prefix

        self.memory = self._get_memory('Untitled 0', from_exist=False)

        self.prompt = get_conversation_prompt(memory=self.memory)

        self.temp_info = dict(generation=False)
        self.stop = [f'{self.human_prefix}:']
        self.bot = dict()
        self.state = dict(generate = False)
        self.mobile = mobile

    @classmethod
    @property
    def titles(self) -> List[str]:
        return VectorMemoryCore.existing_chats

    @classmethod
    @property
    def title_dir_map(self) -> Dict[str, str]:
        return VectorMemoryCore.existing_chat_map

    @property
    def history(self) -> List[List[str]]:
        history = self.memory.core.chat_history
        if history.shape[0] == 0:
            return []
        else:
            return history[['human', 'ai']].values.tolist()

    @property
    def current_title(self) -> str:
        return self.memory.core.title

    @property
    def llm_state(self) -> Dict[str, float]:
        keys = ['temperature', 'top_p', 'top_k', 'repetition_penalty', 'max_new_tokens']
        state = dict()
        for k in keys:
            state[k] = self.llm.generation_config[k]
        return state

    @property
    def config_dict(self) -> Dict[str, Any]:
        config = dict(
            # conversation list
            new = dict(obj='textbox', args=dict(value = '', interactive=True, show_label=False, placeholder='New chat title here...', scale=4, container=False)),
            add = dict(obj='btn', args=dict(value='Add', min_width=15, variant='primary', size='sm', scale=1, interactive=True)),
            convos = dict(obj='dropdown', args=dict(choices=self.titles, label='Conversations', value=None)),
            select = dict(obj='btn', args=dict(value='Select', min_width=25, variant='primary', size='sm', interactive=True)),
            remove = dict(obj='btn', args=dict(value='Remove', min_width=25, variant='secondary', size='sm', interactive=True)),
            info = dict(obj='textbox', args=dict(value = '', interactive=True, placeholder='Important information here...', lines=18, max_lines=20, container=False)),

            # main console
            bot = dict(obj='chatbot', args=dict(label=self.current_title, height=600, value=self.history, show_copy_button=True)),
            user = dict(obj='textbox', args=dict(value = '', interactive=True, show_label=False, placeholder='Type your message here...', max_lines=40, scale=7, container=True)),
            send = dict(obj='btn', args=dict(value='Send', min_width=35, variant='primary', size='sm', scale=2, interactive=True)),
            cont = dict(obj='btn', args=dict(value='Continue', min_width=15, size='sm', scale=1, interactive=True)),
            start = dict(obj='textbox', args=dict(value = '', interactive=True, show_label=False, placeholder='Type the start of the chatbot message...', max_lines=40, scale=5, container=True)),
            regen = dict(obj='btn', args=dict(value='Re-generate', min_width=15, size='sm', scale=2, interactive=True)),
            rmlast = dict(obj='btn', args=dict(value='Remove last interaction', min_width=15, size='sm', scale=2, interactive=True)),

            # settings
            system = dict(obj='textbox', args=dict(value=DEFAULT_SYSTEM, show_label=False, placeholder='System message here...', lines=8, max_lines=40, scale=4, interactive=True)),
            temperature = dict(obj='slider', args=dict(value=self.llm.generation_config['temperature'], minimum=0, maximum=2, step=0.01, label='Temperature')),
            tokens = dict(obj='slider', args=dict(value=self.llm.generation_config['max_new_tokens'], minimum=0, maximum=4096, step=1, label='Maximum number of new tokens')),
            repeat = dict(obj='slider', args=dict(value=self.llm.generation_config['repetition_penalty'], minimum=0, maximum=2, step=0.01, label='Repetition penalty')),
            topp = dict(obj='slider', args=dict(value=self.llm.generation_config['top_p'], minimum=0, maximum=1, step=0.001, label='Top P')),
            topk = dict(obj='slider', args=dict(value=self.llm.generation_config['top_k'], minimum=0, maximum=500, step=1, label='Top K'))
        )
        return config

    @property
    def mobile_config_dict(self) -> Dict[str, Any]:
        config = deepcopy(self.config_dict)
        changes = dict(
            bot = dict(height=450, show_copy_button=False),
            start = dict(scale=4, placeholder='Start of bot message...'),
            send = dict(scale=1),
            cont = dict(scale=2),
            rmlast = dict(value='Remove last')
        )
        for k, v in changes.items():
            for a, i in v.items():
                config[k]['args'][a] = i
        return config

    def _get_memory(self, title: str, from_exist=True) -> ConversationVectorMemory:
        memory = ConversationVectorMemory(
            title=title,
            embeddings=self.embeddings,
            llm=self.llm,
            ai_prefix=self.ai_prefix,
            human_prefix=self.human_prefix,
            recent_chat_token_limit=750,
            related_chat_token_limit=600,
            from_exist=from_exist
        )
        return memory

    def get_prompt(self, msg: str, info: str = '', start: str = '', system: str = DEFAULT_SYSTEM) -> str:
        """Get the full prompt for the llm given the user input.

        Args:
            msg (str): user input
            extra_information (str, optional): Important information that must stick in the full prompt. Defaults to ''.
            ai_start (str, optional): Specify how the llm should start responding. Defaults to ''.
            system_message (str, optional): System message for the chat prompt. Defaults to DEFAULT_SYSTEM.

        Returns:
            str: The full prompt for the llm.
        """
        info = info.strip(' \n\r\t')
        info = '' if info == '' else f'\nImportant information:\n{info}\n'
        kwargs = {
            self.memory.input_key: msg.strip(' \n\r\t'),
            self.memory.memory_key: self.memory.load_memory_variables(inputs={self.memory.input_key: msg})[self.memory.memory_key],
            'extra_information': info,
            'system': system.strip(' \n\r\t'),
            'ai_start': start.lstrip(' \n\r\t')
        }
        prompt = self.prompt.format(**kwargs)
        return prompt

    def generate(self, prompt: str, prefix: str = '') -> Iterator[str]:
        """A generator yielding the next token.

        Args:
            prompt (str): The full input prompt to the llm.
            prefix (str, optional): The start of the output, should the suffix of the full prompt. Defaults to ''.
            auto_cont (bool): Whether to contiue if the output does not look completed.

        Returns:
            Iterator[str]: Generator of the output text.
        """
        output = prefix
        print(f'Number of input tokens: {self.llm.get_num_tokens(prompt)}')
        for token in self.llm.stream(prompt, stop=self.stop):
            output += token
            yield output

    # GUI functions
    def output_map(self, keys: Union[str, List[str]]) -> List[Any]:
        if type(keys) == str:
            keys = [keys]
        return list(map(lambda x: self.bot[x], keys))

    def vars(self, var_name: str, **kwargs: Dict[str, Any]) -> Union[gr.Button, gr.Text, gr.Textbox, gr.Dropdown, gr.Chatbot, gr.Slider, List[List[str]]]:
        keys = ['btn', 'text', 'textbox', 'dropdown', 'chatbot', 'slider']
        values = [gr.Button, gr.Text, gr.Textbox, gr.Dropdown, gr.Chatbot, gr.Slider]
        type_map = dict(zip(keys, values))
        vars = deepcopy(self.mobile_config_dict if self.mobile else self.config_dict)

        output = vars[var_name].copy()
        for k, v in kwargs.items():
            output['args'][k] = v
        output = type_map[output['obj']](**output['args'])
        return output

    def convo_btns(self, btn: str, convos: Optional[str] = '', new: str = '') -> List[Any]:
        if btn == 'Add':
            title = new.strip(' \n\t\r')
            if title != '':
                self.memory = self._get_memory(title=title, from_exist=True)
                self.memory.clear()

        elif btn == 'Select':
            title = convos if convos is not None else ''
            if title != '':
                self.memory = self._get_memory(title=title, from_exist=True)

        elif btn == 'Remove':
            title = convos if convos is not None else ''
            if title != '':
                import shutil
                if title == self.current_title:
                    self.memory = self._get_memory(title='Untitled 0', from_exist=False)
                shutil.rmtree(self.title_dir_map[title])
        output = [
            self.vars('bot'),
            self.vars('convos'),
            self.vars('new')
        ]
        return output

    def input_handler(self,
            btn: str,
            bot: List[List[str]],
            info: str,
            user: str,
            start: str,
            system: str,
            temperature: float,
            tokens: int,
            repeat: float,
            topp: float,
            topk: int
        ) -> List[Any]:
        # btn change states
        btns = dict(
            add = dict(),
            select = dict(),
            remove = dict(),
            send = dict(),
            cont = dict(),
            regen = dict(),
            rmlast = dict()
        )
        btns_keys = list(btns.keys())

        if btn == 'Send':
            msg = user.strip(' \n\r\t')
            if msg != '':
                prompt = self.get_prompt(msg=msg, info=info, start=start, system=system)
                start = start.strip(' \n\r\t')
                self.state['generate'] = True
                self.state['prompt'] = prompt
                self.state['start'] = start
                self.llm = self.model(temperature=temperature, max_new_tokens=tokens, top_p=topp, top_k=topk, repetition_penalty=repeat, stop=self.stop)
                bot = deepcopy(self.history)
                bot.append([msg, None])
                bot = self.vars('bot', value=bot, label=self.current_title)
                user = ''
                start = ''
                for k in btns_keys:
                    if k != 'send':
                        btns[k]['interactive'] = False
                    else:
                        btns[k]['value'] = 'Stop'
                        btns[k]['variant'] = 'stop'

        elif btn == 'Continue':
            history = deepcopy(self.history)
            if len(history) != 0:
                self.memory.core.remove_last_interaction()
                prompt = self.get_prompt(msg=history[-1][0], info=info, start=history[-1][1], system=system)
                self.state['generate'] = True
                self.state['prompt'] = prompt
                self.state['start'] = history[-1][1]
                self.llm = self.model(temperature=temperature, max_new_tokens=tokens, top_p=topp, top_k=topk, repetition_penalty=repeat, stop=self.stop)
                bot = deepcopy(self.history)
                bot.append([history[-1][0], history[-1][1]])
                bot = self.vars('bot', value=bot, label=self.current_title)
                for k in btns_keys:
                    if k != 'send':
                        btns[k]['interactive'] = False
                    else:
                        btns[k]['value'] = 'Stop'
                        btns[k]['variant'] = 'stop'

        elif btn == 'Re-generate':
            history = deepcopy(self.history)
            if len(history) != 0:
                self.memory.core.remove_last_interaction()
                prompt = self.get_prompt(msg=history[-1][0], info=info, start=start, system=system)
                self.state['generate'] = True
                self.state['prompt'] = prompt
                self.state['start'] = start
                self.llm = self.model(temperature=temperature, max_new_tokens=tokens, top_p=topp, top_k=topk, repetition_penalty=repeat, stop=self.stop)
                bot = deepcopy(self.history)
                bot.append([history[-1][0], None])
                bot = self.vars('bot', value=bot, label=self.current_title)
                for k in btns_keys:
                    if k != 'send':
                        btns[k]['interactive'] = False
                    else:
                        btns[k]['value'] = 'Stop'
                        btns[k]['variant'] = 'stop'

        elif btn == 'Stop':
            self.state = dict(generate = False)

        output = [
            self.vars('start', value=start),
            self.vars('user', value=user),
            bot
        ]
        for k, v in btns.items():
            output.append(self.vars(k, **v))
        # output_list = ['start', 'user', 'bot', 'add', 'select', 'remove', 'send', 'cont', 'regen', 'rmlast']
        return output

    def frontend_stream(self, bot: List[List[str]]) -> List[Any]:
        output = ''
        if self.state['generate']:
            for o in self.generate(prompt=self.state['prompt'], prefix=self.state['start']):
                if self.state['generate']:
                    output = o.strip(' \r\n\t')
                bot[-1][1] = output
                yield bot
            self.memory.core.save_interaction(text_input=bot[-1][0], text_output=output)
            yield self.vars('bot')
        else:
            yield bot

    def postgen_handler(self) -> List[Any]:
        btns = ['add', 'select', 'remove', 'send', 'cont', 'regen', 'rmlast']
        self.state = dict(generate=False)
        output = list()
        for k in btns:
            output.append(self.vars(k))
        return output

    def remove_last(self) -> List[Any]:
        if len(self.history) != 0:
            self.memory.core.remove_last_interaction()
        return self.history

    def _init_pc_frame(self) -> None:
        with gr.Blocks() as self.frame:
            with gr.Tab(label='Chat'):
                with gr.Row():
                    with gr.Column(): # Conversations
                        with gr.Group():
                            with gr.Row(variant='compact'):
                                self.bot['new'] = self.vars('new')
                                self.bot['add'] = self.vars('add')
                            self.bot['convos'] = self.vars('convos')
                            with gr.Row(variant='compact'):
                                self.bot['select'] = self.vars('select')
                                self.bot['remove'] = self.vars('remove')
                        self.bot['info'] = self.vars('info')

                    with gr.Column(scale=4): # Main console
                        self.bot['bot'] = self.vars('bot')
                        with gr.Row(variant='compact'):
                            self.bot['user'] = self.vars('user')
                            self.bot['send'] = self.vars('send')
                            self.bot['cont'] = self.vars('cont')
                        with gr.Row(variant='compact'):
                            self.bot['start'] = self.vars('start')
                            self.bot['regen'] = self.vars('regen')
                            self.bot['rmlast'] = self.vars('rmlast')

            with gr.Tab(label='Settings'): # Settings
                with gr.Row():
                    with gr.Column(scale=1):
                        self.bot['system'] = self.vars('system')
                    with gr.Column(scale=1):
                        self.bot['temperature'] = self.vars('temperature')
                        self.bot['tokens'] = self.vars('tokens')
                        self.bot['repeat'] = self.vars('repeat')
                        self.bot['topp'] = self.vars('topp')
                        self.bot['topk'] = self.vars('topk')

            # functions
            self.bot['add'].click(fn=self.convo_btns, inputs=self.output_map(['add', 'convos', 'new']), outputs=self.output_map(['bot', 'convos', 'new']))
            self.bot['select'].click(fn=self.convo_btns, inputs=self.output_map(['select', 'convos', 'new']), outputs=self.output_map(['bot', 'convos', 'new']))
            self.bot['remove'].click(fn=self.convo_btns, inputs=self.output_map(['remove', 'convos', 'new']), outputs=self.output_map(['bot', 'convos', 'new']))

            self.bot['send'].click(fn=self.input_handler,
                                   inputs=self.output_map([ 'send', 'bot', 'info', 'user', 'start', 'system', 'temperature', 'tokens', 'repeat', 'topp', 'topk']),
                                   outputs=self.output_map(['start', 'user', 'bot', 'add', 'select', 'remove', 'send', 'cont', 'regen', 'rmlast']),
                                   queue=False).then(
                                       fn=self.frontend_stream, inputs=self.output_map('bot'), outputs=self.output_map('bot')
                                   ).then(
                                       fn=self.postgen_handler, outputs=self.output_map(['add', 'select', 'remove', 'send', 'cont', 'regen', 'rmlast'])
                                   )
            self.bot['user'].submit(fn=self.input_handler,
                                   inputs=self.output_map([ 'send', 'bot', 'info', 'user', 'start', 'system', 'temperature', 'tokens', 'repeat', 'topp', 'topk']),
                                   outputs=self.output_map(['start', 'user', 'bot', 'add', 'select', 'remove', 'send', 'cont', 'regen', 'rmlast']),
                                   queue=False).then(
                                       fn=self.frontend_stream, inputs=self.output_map('bot'), outputs=self.output_map('bot')
                                   ).then(
                                       fn=self.postgen_handler, outputs=self.output_map(['add', 'select', 'remove', 'send', 'cont', 'regen', 'rmlast'])
                                   )
            self.bot['cont'].click(fn=self.input_handler,
                                   inputs=self.output_map([ 'cont', 'bot', 'info', 'user', 'start', 'system', 'temperature', 'tokens', 'repeat', 'topp', 'topk']),
                                   outputs=self.output_map(['start', 'user', 'bot', 'add', 'select', 'remove', 'send', 'cont', 'regen', 'rmlast']),
                                   queue=False).then(
                                       fn=self.frontend_stream, inputs=self.output_map('bot'), outputs=self.output_map('bot')
                                   ).then(
                                       fn=self.postgen_handler, outputs=self.output_map(['add', 'select', 'remove', 'send', 'cont', 'regen', 'rmlast'])
                                   )
            self.bot['regen'].click(fn=self.input_handler,
                                   inputs=self.output_map([ 'regen', 'bot', 'info', 'user', 'start', 'system', 'temperature', 'tokens', 'repeat', 'topp', 'topk']),
                                   outputs=self.output_map(['start', 'user', 'bot', 'add', 'select', 'remove', 'send', 'cont', 'regen', 'rmlast']),
                                   queue=False).then(
                                       fn=self.frontend_stream, inputs=self.output_map('bot'), outputs=self.output_map('bot')
                                   ).then(
                                       fn=self.postgen_handler, outputs=self.output_map(['add', 'select', 'remove', 'send', 'cont', 'regen', 'rmlast'])
                                   )
            self.bot['rmlast'].click(fn=self.remove_last, outputs=self.output_map('bot'))

    def _init_mobile_frame(self) -> None:
        with gr.Blocks() as self.frame:
            with gr.Tab(label='Chat'):
                self.bot['bot'] = self.vars('bot')
                self.bot['user'] = self.vars('user')
                with gr.Row('compact'):
                    self.bot['start'] = self.vars('start')
                    self.bot['send'] = self.vars('send')
                with gr.Row(variant='compact'):
                    self.bot['cont'] = self.vars('cont')
                    self.bot['regen'] = self.vars('regen')
                    self.bot['rmlast'] = self.vars('rmlast')

            with gr.Tab(label='Conversations'):
                with gr.Group():
                    with gr.Row(variant='compact'):
                        self.bot['new'] = self.vars('new')
                        self.bot['add'] = self.vars('add')
                    self.bot['convos'] = self.vars('convos')
                    with gr.Row(variant='compact'):
                        self.bot['select'] = self.vars('select')
                        self.bot['remove'] = self.vars('remove')
                self.bot['info'] = self.vars('info')

            with gr.Tab(label='Settings'): # Settings
                self.bot['system'] = self.vars('system')
                self.bot['temperature'] = self.vars('temperature')
                self.bot['tokens'] = self.vars('tokens')
                self.bot['repeat'] = self.vars('repeat')
                self.bot['topp'] = self.vars('topp')
                self.bot['topk'] = self.vars('topk')

            # functions
            self.bot['add'].click(fn=self.convo_btns, inputs=self.output_map(['add', 'convos', 'new']), outputs=self.output_map(['bot', 'convos', 'new']))
            self.bot['select'].click(fn=self.convo_btns, inputs=self.output_map(['select', 'convos', 'new']), outputs=self.output_map(['bot', 'convos', 'new']))
            self.bot['remove'].click(fn=self.convo_btns, inputs=self.output_map(['remove', 'convos', 'new']), outputs=self.output_map(['bot', 'convos', 'new']))

            self.bot['send'].click(fn=self.input_handler,
                                   inputs=self.output_map([ 'send', 'bot', 'info', 'user', 'start', 'system', 'temperature', 'tokens', 'repeat', 'topp', 'topk']),
                                   outputs=self.output_map(['start', 'user', 'bot', 'add', 'select', 'remove', 'send', 'cont', 'regen', 'rmlast']),
                                   queue=False).then(
                                       fn=self.frontend_stream, inputs=self.output_map('bot'), outputs=self.output_map('bot')
                                   ).then(
                                       fn=self.postgen_handler, outputs=self.output_map(['add', 'select', 'remove', 'send', 'cont', 'regen', 'rmlast'])
                                   )
            self.bot['cont'].click(fn=self.input_handler,
                                   inputs=self.output_map([ 'cont', 'bot', 'info', 'user', 'start', 'system', 'temperature', 'tokens', 'repeat', 'topp', 'topk']),
                                   outputs=self.output_map(['start', 'user', 'bot', 'add', 'select', 'remove', 'send', 'cont', 'regen', 'rmlast']),
                                   queue=False).then(
                                       fn=self.frontend_stream, inputs=self.output_map('bot'), outputs=self.output_map('bot')
                                   ).then(
                                       fn=self.postgen_handler, outputs=self.output_map(['add', 'select', 'remove', 'send', 'cont', 'regen', 'rmlast'])
                                   )
            self.bot['regen'].click(fn=self.input_handler,
                                   inputs=self.output_map([ 'regen', 'bot', 'info', 'user', 'start', 'system', 'temperature', 'tokens', 'repeat', 'topp', 'topk']),
                                   outputs=self.output_map(['start', 'user', 'bot', 'add', 'select', 'remove', 'send', 'cont', 'regen', 'rmlast']),
                                   queue=False).then(
                                       fn=self.frontend_stream, inputs=self.output_map('bot'), outputs=self.output_map('bot')
                                   ).then(
                                       fn=self.postgen_handler, outputs=self.output_map(['add', 'select', 'remove', 'send', 'cont', 'regen', 'rmlast'])
                                   )
            self.bot['rmlast'].click(fn=self.remove_last, outputs=self.output_map('bot'))

    def _init_frame(self) -> None:
        if self.mobile:
            self._init_mobile_frame()
        else:
            self._init_pc_frame()

    def run(self, share: bool=False, auth: Optional[tuple[str, str]]= None, debug: bool = False, mobile: bool = False, **kwargs: Dict[str, Any]) -> None:
        self.mobile = mobile
        self._init_frame()
        self.frame.queue()
        self.frame.launch(share=share, auth=auth, debug=debug, **kwargs)


import os
import tempfile
from io import DEFAULT_BUFFER_SIZE

from osgeo import gdal
from pyramid.response import FileIter, FileResponse, Response

from nextgisweb.env import _, env

from nextgisweb.core.exception import ValidationError
from nextgisweb.pyramid.util import set_output_buffering
from nextgisweb.resource import DataScope, resource_factory
from nextgisweb.spatial_ref_sys import SRS

from .gdaldriver import EXPORT_FORMAT_GDAL
from .model import RasterLayer

PERM_READ = DataScope.read
PERM_WRITE = DataScope.write

class RangeFileWrapper(FileIter):
    def __init__(self, file, block_size=DEFAULT_BUFFER_SIZE, offset=0, length=0):
        super().__init__(file=file, block_size=block_size)
        self.file.seek(offset, os.SEEK_SET)
        self.remaining = length

    def __next__(self):
        if self.remaining <= 0:
            raise StopIteration()
        data = self.file.read(min(self.remaining, self.block_size))
        if not data:
            raise StopIteration()
        self.remaining -= len(data)
        return data

def export(resource, request):
    request.resource_permission(PERM_READ)

    srs = SRS.filter_by(id=int(request.GET["srs"])).one() if "srs" in request.GET else resource.srs
    format = request.GET.get("format", "GTiff")
    bands = request.GET["bands"].split(",") if "bands" in request.GET else None

    if format is None:
        raise ValidationError(_("Output format is not provided."))

    if format not in EXPORT_FORMAT_GDAL:
        raise ValidationError(_("Format '%s' is not supported.") % (format,))

    driver = EXPORT_FORMAT_GDAL[format]

    filename = "%d.%s" % (
        resource.id,
        driver.extension,
    )
    content_disposition = "attachment; filename=%s" % filename

    def _warp(source_filename):
        with tempfile.NamedTemporaryFile(suffix=".%s" % driver.extension) as tmp_file:
            try:
                gdal.UseExceptions()
                gdal.Warp(
                    tmp_file.name,
                    source_filename,
                    options=gdal.WarpOptions(
                        format=driver.name, dstSRS=srs.wkt, creationOptions=driver.options
                    ),
                )
            except RuntimeError as e:
                raise ValidationError(str(e))
            finally:
                gdal.DontUseExceptions()

            response = FileResponse(tmp_file.name, content_type=driver.mime)
            response.content_disposition = content_disposition
            return response

    source_filename = env.raster_layer.workdir_filename(resource.fileobj)
    if bands is not None and len(bands) != resource.band_count:
        with tempfile.NamedTemporaryFile(suffix=".tif") as tmp_file:
            gdal.Translate(tmp_file.name, source_filename, bandList=bands)
            return _warp(tmp_file.name)
    else:
        return _warp(source_filename)

def cog(resource, request):
    request.resource_permission(PERM_READ)

    fn = env.raster_layer.workdir_filename(resource.fileobj)
    filesize = os.path.getsize(fn)

    if request.method == "HEAD":
        return Response(
            accept_ranges="bytes",
            content_length=filesize,
            content_type="image/geo+tiff",
        )

    if request.method == "GET":
        if not resource.cog:
            raise ValidationError(_("Requested raster is not COG."))

        range = request.range
        if range is None:
            raise ValidationError(_("Range header is missed or invalid."))

        content_range = range.content_range(filesize)
        if content_range is None:
            raise ValidationError(_("Range %s can not be read." % range))

        content_length = content_range.stop - content_range.start
        response = Response(
            status_code=206, content_range=content_range, content_type="image/geo+tiff"
        )

        response.app_iter = RangeFileWrapper(
            open(fn, "rb"), offset=content_range.start, length=content_length
        )
        response.content_length = content_length

        return response

def download(request):
    request.resource_permission(PERM_READ)

    filename = env.raster_layer.workdir_filename(request.context.fileobj)
    response = FileResponse(
        filename,
        content_type="image/tiff; application=geotiff",
        request=request,
    )
    response.content_disposition = "attachment; filename=%s.tif" % request.context.id
    set_output_buffering(request, response, False)
    return response

def setup_pyramid(comp, config):
    config.add_view(
        export,
        route_name="resource.export",
        context=RasterLayer,
        request_method="GET",
    )

    route_cog = config.add_route(
        "raster_layer.cog",
        "/api/resource/{id:uint}/cog",
        factory=resource_factory,
    )
    route_cog.head(cog, context=RasterLayer)
    route_cog.get(cog, context=RasterLayer)

    config.add_route(
        "raster_layer.download",
        "/api/resource/{id:uint}/download",
        factory=resource_factory,
    ).get(download, context=RasterLayer)


uroven_3000 = f"products/uroven---uglomer-elektronnyj-kapro-992"
bundeks_25 = f"products/shtukaturka-tsementnaya-bergauf-bau-putts-tsement-25kg-56sht"
aksolit_30 = f"products/shtukaturka-gipsovaya-aksolit-m50-30-kg-mashinnogo-naneseniya"

fio = "Тест Тест Тест"
form_phone = "9876543210"
email = "lyhxr@example.com"

city = "Нижний Новгород"
city_red_zone = ""
address_green_zone = "Литературная улица, 20А"
address_blue_zone = "Рудничная улица, 19"
address_red_zone = ""
distance_km = 40


# union set
def makeset(x):
    x.parent=x

def find(x):
    if x.parent ==x:
        return x
    else:
        return find(x)

def union(x,y):
    xroot=find(x)
    yroot=find(y)
    xroot.parent=yroot

# 并查集（684）：https://leetcode.com/problems/redundant-connection/description/
# Input: [[1,2], [2,3], [3,4], [1,4], [1,5]]
# Output: [1,4]
# Explanation: The given undirected graph will be like this:
# 5 - 1 - 2
#     |   |
#     4 - 3
class Solution:
    def findRedundantConnection(self, edges: List[List[int]]) -> List[int]:
        self.p = {x:x for x in range(1,len(edges)+1)}
        for x, y in edges:
            if self.union(x,y):
                return [x, y]

    def find(self,x):
        if self.p[x] != x:
            self.p[x] = self.find(self.p[x])
        return self.p[x]

    def union(self, x, y):
        if self.find(x) == self.find(y):
            return True
        self.p[self.find(x)] = self.find(y)

# 200. Number of Islands https://leetcode.com/problems/number-of-islands/
class Solution:
    def numIslands(self, grid: List[List[str]]) -> int:
        if not grid or not grid[0]:
            return 0
        uf = UnionFind(grid)
        directions = [(0,1),(0,-1),(-1,0),(1,0)]
        m,n=len(grid),len(grid[0])
        for i in range(m):
            for j in range(n):
                if grid[i][j]=="0":
                    continue
                for d in directions:
                    nr,nc=i+d[0],j+d[1]
                    if nr>=0 and nc>=0 and nr<m and nc<n and grid[nr][nc]=="1":
                        uf.union(i*n+j,nr*n+nc)
        return uf.count

class UnionFind(object):
    def __init__(self,grid):
        m,n =len(grid),len(grid[0])
        self.count=0
        self.parent=[-1]*(m*n)
        self.rank=[0]*(m*n)
        for i in range(m):
            for j in range(n):
                if grid[i][j]=="1":
                    self.parent[i*n+j]=i*n+j
                    self.count+=1
    def find(self,i):
        if self.parent[i]!=i:
            self.parent[i]=self.find(self.parent[i])
        return self.parent[i]

    def union(self,x,y):
        rootx=self.find(x)
        rooty=self.find(y)
        if rootx!=rooty:
            if self.rank[rootx]>self.rank[rooty]:
                self.parent[rooty]=rootx
            elif self.rank[rootx]<self.rank[rooty]:
                self.parent[rootx]=rooty
            else:
                self.parent[rooty]=rootx
                self.rank[rootx]+=1
            self.count-=1

# 547. Friend Circles https://leetcode.com/problems/friend-circles/submissions/
class Solution:
    # union find
    def findCircleNum(self, M: List[List[int]]) -> int:
        n = len(M)
        union = [i for i in range(n)]

        def find(x):
            if union[x] != x:
                union[x] = find(union[x])
            return union[x]

        def unite(x, y):
            union[find(y)] = find(x)

        for i in range(n):
            for j in range(i+1, n):
                if M[i][j]:
                    unite(i,j)

        for i in range(n):
            union[i] = find(i)

        return len(set(union))


import numpy as np
import scipy.stats as stats

from collect.collectAP import get_model_results as get_ap_results
from collect.collectFailure import get_model_results as get_failure_results
from get_inst import get_failure_stats

from functools import partial
import json

def get_model_DG(minfo, r=True):
    mean_d = 0.0
    cleanap = 0
    res = {}

    for corruption, c_info in minfo.items():
        if corruption == 'clean':
            cleanap = c_info
            break
    for corruption, c_info in minfo.items():
        if corruption == 'clean':
            continue
        res[corruption] = {}
        for s, ap in c_info.items():
            res[corruption][s] = {}
            for key in AP_KEYS:
                if r:
                    res[corruption][s][key] = 1 - ap[key]/cleanap[key]
                else:
                    res[corruption][s][key] = cleanap[key]-ap[key]
    return res

def get_degradation(ap_results, r=True):
    results = {}
    for m, minfo in ap_results.items():
        results[m] = get_model_DG(minfo, r)
    return results

AP_KEYS = ['AP']
#AP_KEYS = ['AP', 'AP50', 'AP75', 'APs', 'APm', 'APl']
areaRngLbl = ['all', 'small', 'medium', 'large']

if __name__ == '__main__':
    APITEM = 1 #0 for ap; 1 for degradation

    ann_file = '/yueyuxin/data/coco/annotations/instances_val2017.json'
    anns = json.load(open(ann_file))

    path = '../../'
    #path = '../../retinanet'

    raw_ap_results = get_ap_results(path)
    #degradation_results = get_degradation(raw_ap_results, r=False)
    degradation_results = get_degradation(raw_ap_results, r=True)
    if APITEM == 1:
        ap_results = degradation_results
    else:
        ap_results = raw_ap_results

    failure_results = get_failure_results(path, get_failure_func=partial(get_failure_stats, anns=anns))

    Object = 'area'

    if Object == 'area':
        L = lambda x: areaRngLbl
        F = lambda fl_c_info,s,k,lbl: fl_c_info[s]['area_num'][lbl]/fl_c_info[s]['instance_num']
    else:
        raise NotImplementedError

    for k in AP_KEYS:
        for lbl in L(k):
        #for lbl in areaRngLbl:
        #for lbl in ['crowdratio']:
        #for lbl in [k]:
            ap = []
            fl = []

            for m in failure_results.keys():
                fl_info = failure_results[m]
                ap_info = ap_results[m]
                for c in fl_info.keys():
                    fl_c_info = fl_info[c]
                    ap_c_info = ap_info[c]
                    for s in fl_c_info.keys():
                        if fl_c_info[s] is None: continue
                        fl.append(F(fl_c_info,s,k,lbl))
                        #fl.append(fl_c_info[s]['crowd_num']/fl_c_info[s]['instance_num'])
                        #fl.append(fl_c_info[s]['area_num'][lbl]/fl_c_info[s]['instance_num'])
                        #fl.append(fl_c_info[s][k])
                        ap.append(ap_c_info[s][k])
            print([f'{_:.3f}' for _ in ap[:20]])
            print([f'{_:.3f}' for _ in fl[:20]])
            print(k,lbl,stats.kendalltau(ap, fl))
            print('-'*20)


# -*- coding: utf-8 -*-
"""
@author: irene
"""

import argparse
import os

DP_METHOD = "dp"
SA_METHOD = "sa"

class KnapsackSolverParser(argparse.ArgumentParser):
    def __init__(self, description='Script solving the 3-D bounded knapsack problem'):
        super(KnapsackSolverParser, self).__init__(description=description)
        self.add_argument('-f', type=str, dest="inst_file_path", default=os.getcwd()+'/../input.csv',
                            help='Path to inst *.txt file')
        self.add_argument('-r', type=int, dest="repeat", default=1,
                            help='Number of repetitions. Default value: 1')
        self.add_argument("-m", default=SA_METHOD, type=str, dest="method",
                            choices=[DP_METHOD, SA_METHOD],
                            help="Solving method. Default value:  SA method")
        self.add_argument('-st', type=int, dest="start_temperature", default=50,
                            help='Initial temperature for annealing approach. Default value: 1500')
        self.add_argument('-mt', type=int, dest="min_temperature", default=1,
                            help='Minimum temperature for annealing approach. Default value: 0.01')
        self.add_argument('-n', type=int, dest="steps", default=100,
                            help='Number of steps for annealing approach iteration. Default value: 400')
        self.add_argument('-e', type=bool, dest="evaluate", default=False,
                            help='Flag for whether to evaluate the current method. Default value: True')
        self.add_argument('-ub', type=bool, dest="use_builtin", default=True,
                          help='Flag for whether to use the built in parameters. \
                          To specify parameters for algorithms, set False. Default value: True')
        self.add_argument('-d', type=bool, dest="debug_mode", default=False,
                            help='Set true to debug mode and use random generated testcases. Default value: False')


from time import sleep
import cv2

import config
from supermarket import Supermarket

if __name__ == '__main__':
    print('Starting simulation')
    market = Supermarket()
    market.add_customers(config.initial_customer_count)

    while True:
        sleep(0.02)
        market.next_frame()
        cv2.imshow('Supermarket', market.frame)

        if cv2.waitKey(1) & 0xFF == ord('q'):
            print('Ending simulation')
            break

cv2.destroyAllWindows()


import shutil

import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt
import os
import glob

URL = "https://storage.googleapis.com/download.tensorflow.org/example_images/flower_photos.tgz"
zip_file = tf.keras.utils.get_file(origin=URL,
                                   fname="flower_photos.tgz",
                                   extract=True)

base_dir = os.path.join(os.path.dirname(zip_file), 'flower_photos')

classes = ['rose', 'daisy', 'dandelion', 'sunflower', 'tulip']

#moving the images to training and validation arrays
for type in classes:
    images_path = os.path.join(base_dir, type)
    images = glob.glob(images_path + '/*.jpg')
    print("{}: {} images".format(type, len(images)))
    train = images[:round(len(images)*0.8)]
    val = images[round(len(images)*0.8):]

#moving the images in the arrays into files
    for t_image in train:
        if not os.path.exists(os.path.join(base_dir, 'train', type)):
            os.makedirs(os.path.join(base_dir, 'train', type))
        shutil.move(t_image, os.path.join(base_dir, 'train', type))

    for v_image in val:
        if not os.path.exists(os.path.join(base_dir, 'val', type)):
            os.makedirs(os.path.join(base_dir, 'val', type))
        shutil.move(v_image, os.path.join(base_dir, 'val', type))

train_directory = os.path.join(base_dir, 'train')
validate_directory = os.path.join(base_dir, 'val')

#DATA AUGMENTATION
batch_size = 100
IMG_shape = 150

#   for training set
#   applying: random 45 deg rotation,
#             random  zoom, up to 50% zoom,
#             horizontal flip,
#             width and height shift up to 0.15
image_gen = tf.keras.preprocessing.image.ImageDataGenerator(rescale=1./255,
                                                            rotation_range=45,
                                                            zoom_range=0.5,
                                                            horizontal_flip=True,
                                                            width_shift_range=0.15,
                                                            height_shift_range=0.15
                                                            )
train_data_gen = image_gen.flow_from_directory(
                                                directory=train_directory,
                                                batch_size=batch_size,
                                                shuffle=True,
                                                target_size=(IMG_shape, IMG_shape),
                                                class_mode='sparse'
                                                )
#   for validation set
#   applying: rescale only
image_gen = tf.keras.preprocessing.image.ImageDataGenerator(rescale=1./255)
val_data_gen = image_gen.flow_from_directory(
                                                directory=validate_directory,
                                                batch_size=batch_size,
                                                shuffle=True,
                                                target_size=(IMG_shape, IMG_shape),
                                                class_mode='sparse'
                                                )

#CREATING THE MODEL
model = tf.keras.Sequential([
    tf.keras.layers.Conv2D(filters=16, kernel_size=(3,3), padding='same', input_shape=(IMG_shape,IMG_shape,3), activation='relu'),
    tf.keras.layers.MaxPool2D(pool_size=(2,2)),

    tf.keras.layers.Conv2D(filters=32, kernel_size=(3,3), padding='same', activation='relu'),
    tf.keras.layers.MaxPool2D(pool_size=(2,2)),

    tf.keras.layers.Conv2D(filters=64, kernel_size=(3,3), padding='same', activation='relu'),
    tf.keras.layers.MaxPool2D(pool_size=(2,2)),

    tf.keras.layers.Flatten(),
    tf.keras.layers.Dropout(0.2),
    tf.keras.layers.Dense(units=512, activation='relu'),

    tf.keras.layers.Dropout(0.2),
    tf.keras.layers.Dense(units=5, activation='softmax')
])

#COMPILING THE MODEL
model.compile(optimizer=tf.keras.optimizers.Adam(),
              loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
              metrics=['accuracy']
              )
#TRAINING THE MODEL
epochs = 80
history = model.fit_generator(
                                generator=train_data_gen,
                                steps_per_epoch=int(np.ceil(train_data_gen.n) / float(batch_size)),
                                epochs=epochs,
                                validation_data=val_data_gen,
                                validation_steps=int(np.ceil(val_data_gen.n) / float(batch_size))
                                )

#PLOTTING THE ACCURACY GRAPHS
acc = history.history['accuracy']
val_acc = history.history['val_accuracy']

loss = history.history['loss']
val_loss = history.history['val_loss']

epochs_range = range(epochs)

plt.figure(figsize=(8, 8))
plt.subplot(1, 2, 1)
plt.plot(epochs_range, acc, label='Training Accuracy')
plt.plot(epochs_range, val_acc, label='Validation Accuracy')
plt.legend(loc='lower right')
plt.title('Training and Validation Accuracy')

plt.subplot(1, 2, 2)
plt.plot(epochs_range, loss, label='Training Loss')
plt.plot(epochs_range, val_loss, label='Validation Loss')
plt.legend(loc='upper right')
plt.title('Training and Validation Loss')
plt.show()


import numpy as np
from itertools import combinations
import random

#############     FUNCTIONS     #############################
def gen_vector(C,D):
    global guess_vector,answer,r_guess
    a_C=[]

    for i in range(C):
       a_C.append(i+1)
    guess_vector = list(combinations(a_C,D))
    answer = random.choice(guess_vector)
    r_guess = random.choice(guess_vector)
    ###   ####   ####print(answer)
##    while(True):
##        if answer == r_guess:
##            r_guess = random.choice(guess_vector)
##        else:
##            break

    TF = []
    for i in range(len(guess_vector)):
        TF.append(True)

    return guess_vector,answer,r_guess,TF

def check_matches(ans,guess):
    correct = 0

    for i in range(len(ans)):
        if ans[i] == guess[i]:
            correct+=1

    return correct

def Mastermind_Guess_Game(Color=0,Digit=0,comp=0):
    global C,D,guess_vector

################  CODE MAKER       ####################################
    if comp == 0:
        print("\t\t\tMASTERMIND\n\n")
        print("\t\tCode Maker's Turn\n")
    if Color!=0 and Digit!=0:
        C=Color
        D=Digit
        flag = 1
    else:
        C = int(input("With How Many Colors you want to play : "))
        D = int(input("With How Many Digits you want to make Code : "))

    #return C,D

    R = 8      # NO. of Rounds

    colors = ['Red','White','Green','Violet','Orange','Indigo','Black','Blue','Yellow']
    ##index = []
    ##print("\nEnter a unique Digit(1-%d) for the colors below:-\n"%C)
    ##for i in range(D):
    ##    print(colors[i],end='')
    ##    ind = int(input('->'))
    ##    index.append(ind)
    if comp==0:
        option = int(input("\nWant to Make your own code press 1\nWant to generate a random code press 2\n>>"))

    comb,ans,r_guess,TF = gen_vector(C,D)
    ans = list(ans)

    if comp == 0:
        if option == 1:
            print("Available Colors :\n",colors[:C],"\nNote:\n 1.Use only 1-%d numbers for making the code\n2.Remember Code is the Index value of Colors Starting from 1 ="%(C))
            ans = input("\nMake The Code of %d digits : "%D)
            ans = [int(x) for x in list(ans)]

    ##############    CODE BREAKER      ##################################
    if comp==0:
        print('\n'*100)
        print("\n\t\tLet's Play The Game !!!\n\t\tCode Breaker's Turn\n")
        print("\n List Of Colors :\n",colors[:C],"\nGuess a Code of %d Digits(1-%d) Which are index values of colors starting from 1"%(D,C))

        hint = int(input("\n\nHINT\nON - 1\nOFF - 2\n>>"))
    guess_vector = np.array(guess_vector)
    while(True):
        if comp==0:
            print("\nCHANCES LEFT :",R)
            guess = input("Guess The Code : ")
            guess = [int(x) for x in list(guess)]
        else:
            guess = list(random.choice(guess_vector))
            ###   ####   ####print(guess)
        if comp==0:
            while(True):
                if len(guess)!=D:
                    print("\nEnter %d digits code"%D)
                    guess = input("Guess The Code : ")
                    guess = [int(x) for x in list(guess)]
                else:
                    break

        score = check_matches(ans,guess)
        if comp==0:
            print("\nCORRECT MATCHES ARE ",score)

        for i in range(len(guess_vector)):
            if check_matches(guess,list(guess_vector[i])) == score:
                TF[i] = True
            else:
                TF[i] = False
        guess_vector = guess_vector[TF]

        TF = []
        for i in range(len(guess_vector)):
            TF.append(True)
        R-=1
        if comp==0:
            if hint == 1:
                print("HINT : Combinations Which have exactly %d match with your guess are given below :\n"%score,guess_vector,'\nAdvice: Try combinations shown above may be one of them is correct \n')
        if ans == guess:
            if comp == 0:
                print("\t\tCONGRATULATIONS!!!\n\t\tYOU WON")
            break

        if R == 0:
            if comp == 0:
                print("\n\t\tGAME OVER\n\t\t YOU LOSE")
            R=8
            break

    if comp==0:
        print("Correct Code is ",ans)
        for i in ans:
            print(colors[i-1],end=', ')

    R = 8-R
    return R

if __name__ == '__main__':

    Rounds = Mastermind_Guess_Game()
    print("\n\nTotal Rounds Taken",Rounds)


from datetime import datetime
from typing import List

import pytest
from sqlalchemy.orm import Session
from sqlalchemy_utils.functions import drop_database

from core.Enums import Mnemonic
from core.model.CoreModels import OhlcFrame, TradesEntry
from core.model.models import OHLC, Trades
from core.orm.createTables import create_tables
from core.orm.orm import Base, engine, connection, session as session_maker
from kraken.KrakenPersistors import KrakenPersistor

def setup_module():
    create_tables(log=False)
    i = 0

def teardown_module():
    Base.metadata.drop_all(engine)
    connection.close()

    # if some test fails and doesnt close its session, the db may not de destroyed
    # so i force close all sessions
    session = session_maker()
    session.close_all()

    engine.dispose()
    drop_database(engine.url)
    pass

# both list must have the same members in the same order. Is not intented to be optimal, just a helper
def are_list_equals_helper(l1: list, l2: list) -> bool:
    for el1, el2 in zip(l1, l2):
        if el1 != el2:
            return False

    return len(l1) == len(l2)

@pytest.fixture
def instantiate_persistor():
    yield KrakenPersistor()
    session: Session = session_maker()
    session.query(OHLC).delete()
    session.query(Trades).delete()
    session.commit()
    session.close()

@pytest.fixture
def ohlc_data():
    l: List[OhlcFrame] = []
    d = datetime(2019, 1, 2, 12)

    l.append(OhlcFrame(100, 120, 80, 101, d, 10))

    d = d.replace(hour=13)
    l.append(OhlcFrame(103, 105, 99, 100, d, 11))

    d = d.replace(hour=14)
    l.append(OhlcFrame(101, 108, 91, 103, d, 12))

    return l

@pytest.fixture
def trades_data():
    l: List[TradesEntry] = []

    # first ohlc
    d = datetime(2019, 1, 2, 11, minute=40)
    l.append(TradesEntry(100, 3, 'buy', d))

    d = d.replace(minute=45)
    l.append(TradesEntry(120, 3, 'buy', d))

    d = d.replace(minute=50)
    l.append(TradesEntry(80, 2, 'buy', d))

    d = d.replace(minute=51)
    l.append(TradesEntry(101, 2, 'buy', d))
    # end first ohlc
    # second ohlc

    d = d.replace(hour=12, minute=10)
    l.append(TradesEntry(103, 3, 'buy', d))

    d = d.replace(minute=15)
    l.append(TradesEntry(105, 3, 'buy', d))

    d = d.replace(minute=30)
    l.append(TradesEntry(99, 3, 'buy', d))

    d = d.replace(minute=31)
    l.append(TradesEntry(100, 2, 'buy', d))
    # end first ohlc
    # third ohlc

    d = d.replace(hour=13, minute=10)
    l.append(TradesEntry(101, 3, 'buy', d))

    d = d.replace(minute=11)
    l.append(TradesEntry(108, 3, 'buy', d))

    d = d.replace(minute=12)
    l.append(TradesEntry(91, 3, 'buy', d))

    d = d.replace(minute=13)
    l.append(TradesEntry(103, 3, 'buy', d))

    return l

def clear_table(table):
    session: Session = session_maker()
    session.query(table).delete()
    session.commit()
    session.close()

def test_empty_last_ohlc(instantiate_persistor: KrakenPersistor):
    ohlc = instantiate_persistor.get_newest_ohlc(Mnemonic.BTC)
    assert ohlc is None

def test_insert_ohlc_frames(instantiate_persistor: KrakenPersistor, ohlc_data: List[OhlcFrame]):
    instantiate_persistor.persist_ohlc(ohlc_data, Mnemonic.BTC)
    session: Session = session_maker()
    ohlc = session.query(OHLC).all()
    session.close()
    assert len(ohlc) == 3

def test_generate_ohlc(instantiate_persistor: KrakenPersistor, trades_data: List[TradesEntry],
                       ohlc_data: List[OhlcFrame]):
    ohlc_from_trades = instantiate_persistor.trades_to_ohlc(trades_data)
    assert are_list_equals_helper(ohlc_from_trades, ohlc_data)

def test_merge_ohlc_frames(instantiate_persistor: KrakenPersistor, ohlc_data: List[OhlcFrame]):
    # when the table is empty, should insert the new data as it is
    to_update, new = instantiate_persistor.merge_ohlc_with_last(ohlc_data, Mnemonic.BTC)
    assert len(new) == 3
    assert are_list_equals_helper(new, ohlc_data)
    assert to_update is None

    kraken_id = instantiate_persistor.kraken_id

    ohlc = OHLC(50, 51, 49, 50, volume=3, date=ohlc_data[0].date, exchange_id=kraken_id, currency_id=1)
    session: Session = session_maker()
    session.add(ohlc)
    session.commit()
    session.close()

    # when the last frame collides with some part of the new data, should update the last one and
    # remove the collisions from ohlc_data. The ohlc values should update based on the merge of the last frame
    to_update, new = instantiate_persistor.merge_ohlc_with_last(ohlc_data, Mnemonic.BTC)
    assert to_update is not None
    assert to_update.open == 50 and to_update.high == 120 and to_update.low == 49 and to_update.close == 101
    assert to_update.volume == 13
    assert len(new) == 2

    # Data inserted from other currencies should not affect the new data
    to_update, new = instantiate_persistor.merge_ohlc_with_last(ohlc_data, Mnemonic.ETH)
    assert to_update is None
    assert len(new) == 3
    assert are_list_equals_helper(ohlc_data, new)

def test_insert_ohlc_with_no_empty_db(instantiate_persistor: KrakenPersistor, ohlc_data: List[OhlcFrame]):
    ohlc = OHLC(50, 55, 49, 52, 10, ohlc_data[0].date,
                instantiate_persistor.kraken_id, instantiate_persistor.nemo_index[Mnemonic.BTC.value])

    first = ohlc_data[0]
    session = session_maker()
    session.add(ohlc)
    session.commit()

    instantiate_persistor.persist_ohlc(ohlc_data, Mnemonic.BTC)
    oldest_ohlc: OHLC = session.query(OHLC).order_by(OHLC.date.asc()).first()
    all_ohlc: List[OHLC] = session.query(OHLC).all()

    assert oldest_ohlc is not None
    assert oldest_ohlc.open == 50 and oldest_ohlc.low == 49 and oldest_ohlc.high == first.high
    assert oldest_ohlc.close == first.close
    assert oldest_ohlc.volume == first.volume + 10
    assert len(all_ohlc) == 3

    # persisting with another nemo, should not be affected by the above results
    instantiate_persistor.persist_ohlc(ohlc_data, Mnemonic.ETH)
    eth_id = instantiate_persistor.nemo_index[Mnemonic.ETH.value]

    # dont need to filter by exchange since im not testing that
    all_ohlc = session.query(OHLC).filter(OHLC.currency_id == eth_id).all()
    oldest_ohlc = all_ohlc[0]

    assert len(all_ohlc) == 3
    assert oldest_ohlc.open == first.open and oldest_ohlc.high == first.high and oldest_ohlc.low == first.low
    assert oldest_ohlc.close == first.close and oldest_ohlc.volume == first.volume

    session.close()


x = []
for i in range(15):
    x.append(int(input()))
i = 0
j = 0
par = []
impar = []
for obj in x:
    if i == 5:
        i=0
        for a in par:
            print(a)
        par.clear()
    if j == 5:
        j = 0
        for a in impar:
            print(a)
        impar.clear()
    if obj%2==0:
        par.append("par[%d] = %d"%(i,obj))
        i+=1
    else:
        impar.append("impar[%d] = %d"%(j,obj))
        j+=1

for a in impar:
    print(a)
for a in par:
    print(a)


from copy import deepcopy
import os
import random
import numpy as np
import math
import matplotlib.pyplot as plt
import numpy as np

global BALANCING_FACTOR
BALANCING_FACTOR = 1.03
global NUM_PARTITIONS

# Parameters defined for balancing partition sizes
global W_MIN
global W_MAX
def parse_netlist(rel_path):
    """Parses the netlist

    Args:
        rel_path (string): relative path to location of the input file

    Returns:
        list: list version of netlist
    """
    script_dir = os.path.dirname(__file__) #<-- absolute dir the script is in

    abs_file_path = os.path.join(script_dir, rel_path)
    # reading in the file
    data = []
    with open(abs_file_path) as rfile:
        data_raw = rfile.readlines()
        for line in data_raw:
            data.append(line.strip())
    data = list(filter(('').__ne__, data))
    split_data = []
    for i in range(int(len(data))):
        temp = (data[i].split())
        temp = list(map(int, temp))
        split_data.append(temp)
    return split_data

def vertex_info_init(nodes, num_nodes, edges):
    vertex_info = {}

    # finds which partition each vertex of each edge belongs to
    which_partition = {}
    for i in range(len(edges)):
        which_partition[i] = []
        for j in range(len(edges[i][0])):
            for k in range(len(nodes)):
                if (edges[i][0][j] in nodes[k]):
                    which_partition[i].append(k)
    # print("which partition")
    # print(which_partition)
    for i in range(num_nodes):
        # get the associated vertices
        vertex_info[i] = []
        # current partition of the node
        vertex_info[i].append(-1)
        # the partitions that the node attaches to (N)
        vertex_info[i].append(set())
        # the partitions that the node attaches to externally AND internally (ID & ED)
        for j in range(len(nodes)):
            # vertex_info[i].append(0)
            vertex_info[i].append(set())
        for j in range(len(nodes)):
            # if the node is in the partition
            if (i in nodes[j]):
                vertex_info[i][0] = j
                # look at all of the edges of the node:
                for k in range(len(nodes[j][i][0])):
                    # for each edge, look at each associated vertex
                    for l in range(len(edges[nodes[j][i][0][k]][0])):
                        vertex_info[i][1].add(which_partition[nodes[j][i][0][k]][l])
                        # 1st 2 indicies are the partition of the node, and the partitions the node attaches to
                        # this assigns the node to the ED field
                        # This line of code below works just fine, but it might not be needed. Will be counting
                        # the number of nodes in a partition instead of storing each one for simplicity, unless
                        # that backfires.
                        # Remember to change the earlier line in the first j loop to use sets instead if we choose
                        # to use this bad boi.
                        vertex_info[i][which_partition[nodes[j][i][0][k]][l] + 2].add(edges[nodes[j][i][0][k]][0][l])
                        # vertex_info[i][which_partition[nodes[j][i][0][k]][l] + 2] += 1
                for k in range(2, len(vertex_info[i])):
                    vertex_info[i][k] = len(vertex_info[i][k])
                break
        # lock condition
        vertex_info[i].append(0)
    # print("vertex_info")
    # print(vertex_info)
    return vertex_info

def get_values(netlist):
    """gets descriptive values of netlist

    Args:
        netlist (list): list version of netlist

    Returns:
        num_nodes (int): number of blocks in netlist
        num_connections (int): number of connections between cells
        num_rows (int): number of grid rows for circuit to be placed
        num_columns (int): number of grid columns for circuit to be placed
        new_netlist (dict): the key is the net number, the 1st list associated is the respective net, the 2nd list
                            will contain the cost of the given net
    """
    num_nodes, num_connections, num_rows, num_columns = netlist[0]
    netlist = netlist[1:]
    new_netlist = {}
    for i in range(num_connections):
        new_netlist[int(i)] = []
        new_netlist[int(i)].append(netlist[i][1:])
        # the 0 will represet that the node has not yet been moved (it is unlocked)
        new_netlist[int(i)].append(0)
        new_netlist[int(i)].append(0)
    return num_nodes, num_connections, num_rows, num_columns, new_netlist

def init_cell_placements(num_nodes, num_rows, num_connections, num_columns, netlist):
    """Places cells into the nxm grid as specified by the input file (random locations)

    Args:
        num_nodes (int): [description]
        num_rows (int): number of rows in cell grid
        num_connections (int): number of nets in cell grid
        num_columns (int): number of columns in cell grid
        netlist (dict): the key is the net number, the 1st list associated is the respective net, the 2nd list
                        will contain the cost of the given net (left for init_cell_placement)

    Returns:
        dict: contains the locations of each block in the format of:
              block: [[current_cell_x, current_cell_y], [associated netlist nets]]
    """
    block_locations = {}
    avail_locations = []
    for i in range(num_rows):
        for j in range(num_columns):
            temp_loc = [i, j]
            avail_locations.append(temp_loc)
    random.shuffle(avail_locations)

    # after this, block locations looks like: block: [[current_cell_x, current_cell_y], [associated netlist nets]]
    for i in range(num_nodes):
        block_locations[int(i)] = []
        associated_nets = []
        for j in range(num_connections):
            if int(i) in netlist[j][0]:
                associated_nets.append(j)
        block_locations[int(i)].append(associated_nets)
        block_locations[int(i)].append(0)
        block_locations[int(i)].append(0)
    avail_locations = []
    # fill in blank block locations
    return block_locations

def split_nodes_random(nodes, num_partitions):
    """Splits the nodes randomly into 2 equally sized lists (within 1)

    Args:
        nodes (list): nodes of the circuit

    Returns:
        nodes_a, nodes_b (lists): list of nodes of the circuit
    """
    new_nodes = []
    for _ in range(num_partitions):
        new_nodes.append({})
    num_nodes = len(nodes)
    node_locations = [i for i in range(num_nodes)]
    random.shuffle(node_locations)
    for i in range(len(nodes)):
        new_nodes[node_locations[i] % num_partitions][i] = nodes[i]
    # print_node_lists(new_nodes)
    return new_nodes

def print_node_lists(nodes):
    num_node_lists = len(nodes)
    for i in range(num_node_lists):
        print("Node list number " + str(i) + ":")
        print(nodes[i])

def block_swap(nodes, node_info, edges, node_location_1, node_to_swap_1, node_location_2):
    """Swaps 2 blocks

    Args:
        nodes (list): list of dicts containing the variable number of partitions: [partition number][key (node number)][associated edges]

        node_info (dict): [partition number][key (node number)][partition of vertex][<partitions attached to>][<number of attached nodes in partition A>]...
                          [<locked status>]
        edges (dic): for each key [<list of nodes>][<1 or 0, representing cost>][<# nodes in partition a>]
        node_location_1 (int): the partition number that the node is located in
        node_to_swap_1 (int): the node to swap
        node_location_2 (int): the partition number that the node is located in
        node_to_swap_2 (int): the node to swap

    Returns:
        null (modified node_info, swapped nodes)
    """

    # modifies the number of nodes in each partition
    # I don't know if this is right, but it seems to be working
    counted_vertices = set()
    for i in range(len(nodes[node_location_1][node_to_swap_1][0])):
        for j in range(len(edges[nodes[node_location_1][node_to_swap_1][0][i]][0])):
            if edges[nodes[node_location_1][node_to_swap_1][0][i]][0][j] in counted_vertices:
                continue
            counted_vertices.add((edges[nodes[node_location_1][node_to_swap_1][0][i]][0][j]))
            node_info[edges[nodes[node_location_1][node_to_swap_1][0][i]][0][j]][node_location_2 + 2] += 1
            node_info[edges[nodes[node_location_1][node_to_swap_1][0][i]][0][j]][node_location_1 + 2] -= 1
    temp = deepcopy(nodes[node_location_1][node_to_swap_1])
    del nodes[node_location_1][node_to_swap_1]
    nodes[node_location_2][node_to_swap_1] = temp
    # will also need to update the vertex_info[i][1] block, to see if there are other nodes outside of the
    # partition it connects to, but I don't know if we need this field. Will keep it in for now.
    for i in range(len(node_info)):
        for j in range(2, len(node_info[i]) - 1):
            if not node_info[i][j]:
                node_info[i][1].discard(j - 2)
            else:
                node_info[i][1].add(j - 2)

    # swaps the partition location of the given nodes in node_info
    node_info[node_to_swap_1][0] = node_location_2

    # update the lock
    node_info[node_to_swap_1][-1] = 1
    return

def calc_cost(edges, nodes):
    """Caclulates the cost of the partitioning

    Args:
        edges (dict): edges and the vertexes attached to each
        nodes (list of dicts): nodes in each partition: [partition number][key (node number)][associated edges]

    Returns:
        int: number of edge cuts
    """
    cost = 0
    for i in range(len(edges)):
        cut_edge = -1
        for j in range(len(edges[i][0])):
            this_cut_edge = -1
            for k in range(len(nodes)):
                if edges[i][0][j] in nodes[k]:
                    this_cut_edge = k
                    break
            if (cut_edge != -1 and this_cut_edge != cut_edge):
                cost += 1
                break
            else:
                cut_edge = this_cut_edge
    return cost
def calc_cost_cuts(node_info):
    """Sums the total edge cuts

    Args:
        node_info (dict): [partition number][key (node number)][partition of vertex][<partitions attached to>][<number of attached nodes in partition A>]...
                          [<locked status>]

    Returns:
        cost: number of edge cuts
    """
    cost = 0
    for i in range(len(node_info)):
        edge_cuts = 0
        for j in range(2, len(node_info[i]) - 1):
            if(node_info[i][j] > 0):
                edge_cuts += 1
            if (edge_cuts > 1):
                cost += 1
                break
    return cost

def calc_gain(nodes, node_info, node, edges):
    """Calculates the gain of a node

    Args:
        nodes (_type_): _description_
        node_info (_type_): _description_
        node (int): the node of interest

    Returns:
        null
    """
    i_deg = node_info[node][node_info[node][0] + 2]
    e_deg = -1
    max_partition = -1
    is_solved = 0
    for i in range(2, len(node_info[node]) - 1):
        # Skip the internal node
        if (i - 2 == node):
            continue
        if (node_info[node][i] > e_deg):
            e_deg = node_info[node][i]
            max_partition = i - 2
        if (node_info[node][i] > 0):
            is_solved = 1
    # Because it's a greedy algorithm, if all of the nodes are already in a single partition, we don't need to swap.
    # We only will be considering boundary nodes.
    if (is_solved == 0):
        return

    if (len(nodes[max_partition]) + 1 <= W_MAX and len(nodes[node_info[node][0]]) - 1 >= W_MIN):
        # print("Node in question: " + str(node) + ", Max external degree: " + str(e_deg) + ", Partition External: " + str(max_partition) + ", Internal Degree: " + str(i_deg) + ", Internal partition: " + str(node_info[node][0]))
        # # Only make the swap if we're in the acceptable imbalance parameters
        # print("Number of nodes (B): " + str(len(nodes[max_partition])) + ", W_MAX: " + str(W_MAX) + ", Number of nodes (A): " + str(len(nodes[node_info[node][0]])) + ", W_MIN: " + str(W_MIN))
        # print_node_lists(nodes)
        # print("node_info")
        # print(node_info)
        # print("edges")
        # print(edges)
        # print(node_info)
        # We make the swap if the degree is higher, or if there's an imbalance
        if (e_deg > i_deg or (e_deg == i_deg and len(nodes[max_partition]) - len(nodes[node_info[node][0]]) > 0)):
            block_swap(nodes, node_info, edges, node_info[node][0], node, max_partition)
    return

def unlock_nodes(node_info):
    for i in range(len(node_info)):
        node_info[i][-1] = 0

def main(input_file, random_seed, num_partitions):
    """Performs K-Way Partitioning

    Args:
        input_file (string): filepath to input file
        random_seed (int): random seed

    Returns:
        edges, nodes, node_info, cost
    """
    # random.seed(9)
    global NUM_PARTITIONS
    NUM_PARTITIONS = num_partitions
    random.seed(random_seed)
    edges = parse_netlist(input_file)
    num_nodes, num_connections, num_rows, num_columns, edges = get_values(edges)

    # Set the global constants, based on the size of the inputs
    global W_MIN
    W_MIN = int(.9 * (num_nodes / NUM_PARTITIONS))
    global W_MAX
    W_MAX = math.ceil(BALANCING_FACTOR * (num_nodes / NUM_PARTITIONS))

    nodes = init_cell_placements(num_nodes, num_rows, num_connections, num_columns, edges)
    nodes = split_nodes_random(nodes, NUM_PARTITIONS)
    node_info = vertex_info_init(nodes, num_nodes, edges)

    for i in range(8):
        vertices = list(range(len(node_info)))
        random.shuffle(vertices)

        for i in range(num_nodes):
            calc_gain(nodes, node_info, vertices[i], edges)
        unlock_nodes(node_info)
    # print(calc_cost(node_info))
    # print(edges)
    # print("first node info")
    # print(node_info)
    # block_swap(nodes, node_info, edges, 0, 1, 1)
    # print("second node info")
    # print(node_info)

    # print_node_lists(nodes)
    return edges, nodes, node_info, calc_cost(edges, nodes)

# main()


weight = int(input())
cnt = 0

while weight > 0:
    if weight % 5 == 0:
        cnt += weight // 5
        weight = 0
        break
    else:
        weight -= 3
        cnt += 1

if weight == 0:
    print(cnt)
else:
    print("-1")

# 나머지가 3 이하일 때 i 를 하나 깍아도 안되는 케이스가 발생한다
# 3과 5의 최대 공배수 를 생각해봐야 할듯..


import requests
import concurrent.futures

data_to_post = {
    "cod_city": 123456,
    "date": "2023-06-29",
    "hour": 12,
    "precipitation": 1.0,
    "dry_bulb_temperature": 25.0,
}

data_to_put = {
    "cod_city": 123456,
    "date": "2023-06-29",
    "hour": 13,
    "precipitation": 2.0,
    "dry_bulb_temperature": 26.0,
}

cod_city_to_delete = 123456

def create_weather_data(url, data):
    response = requests.post(url, json=data)
    print(f'Response from POST {url}: status code - {response.status_code}, response - {response.json()}')

def get_weather_data(url):
    response = requests.get(url)
    print(f'Response from GET {url}: status code - {response.status_code}, response - {response.json()}')

def update_weather_data(url, data):
    response = requests.put(url, json=data)
    print(f'Response from PUT {url}: status code - {response.status_code}, response - {response.json()}')

def delete_weather_data(url):
    response = requests.delete(url)
    print(f'Response from DELETE {url}: status code - {response.status_code}, response - {response.json()}')

# Crie um executor de thread pool
with concurrent.futures.ThreadPoolExecutor() as executor:
    # Inicie várias threads que irão executar as operações CRUD
    executor.submit(create_weather_data, 'http://35.194.27.80:5000/api/create_weather', data_to_post)
    executor.submit(get_weather_data, 'http://35.194.27.80:5000/api/weather')
    executor.submit(update_weather_data, f'http://35.194.27.80:5000/api/update_weather/{data_to_put["cod_city"]}', data_to_put)
    executor.submit(delete_weather_data, f'http://35.194.27.80:5000/api/delete_weather/{cod_city_to_delete}')


from .test_case import TemporaryBaseDirectoryTestCase
from infi.app_repo.config import Configuration
from infi.app_repo import ftpserver
from infi.app_repo.utils import ensure_directory_exists, path, fopen
from mock import patch
from io import StringIO, BytesIO

class FtpServerTestCase(TemporaryBaseDirectoryTestCase):
    def setUp(self):
        super(FtpServerTestCase, self).setUp()
        self.config = self._get_config_for_test()
        ensure_directory_exists(self.config.incoming_directory)
        self.test_succeded = False

    def mark_success(self, filepath):
        self.test_succeded = True

    def test_upload(self):
        with patch.object(ftpserver.AppRepoFtpHandler, "on_file_received") as on_file_received:
            on_file_received.side_effect = self.mark_success
            fd = BytesIO(b"hello world")
            with self.ftp_server_context(self.config), self.ftp_client_context(self.config, True) as client:
                client.storbinary("STOR testfile", fd)

        self.assertTrue(self.test_succeded)
        self.assertTrue(path.exists(path.join(self.config.incoming_directory, 'testfile')))

    def test_download(self):
        with fopen(path.join(self.config.incoming_directory, 'testfile'), 'w') as fd:
            fd.write('hello world')

        with patch.object(ftpserver.AppRepoFtpHandler, "on_file_sent") as on_file_sent:
            on_file_sent.side_effect = self.mark_success

            with self.ftp_server_context(self.config), self.ftp_client_context(self.config) as client:
                client.retrbinary('RETR incoming/testfile', lambda *args, **kwargs: None)

        self.assertTrue(self.test_succeded)

class FtpWithRpcTestCase(TemporaryBaseDirectoryTestCase):
    def setUp(self):
        from gevent.event import Event
        super(FtpWithRpcTestCase, self).setUp()
        self.config = self._get_config_for_test()
        ensure_directory_exists(path.join(self.config.incoming_directory, 'main-stable'))
        self.test_succeded = Event()

    def mark_success(self, config, index, filepath):
        self.test_succeded.set()

    def test_upload(self):
        from infi.app_repo import service
        with patch("infi.app_repo.service.process_filepath_by_name") as process_filepath_by_name:
            process_filepath_by_name.side_effect = self.mark_success
            fd = BytesIO(b"hello world")
            with self.ftp_server_context(self.config), self.ftp_client_context(self.config, True) as client:
                with self.rpc_server_context(self.config) as server:
                    client.storbinary("STOR main-stable/testfile", fd)
                    self.test_succeded.wait(1)
        self.assertTrue(self.test_succeded.is_set())


import logging
import os
from ..utils.mail_sender import send_mail_to_user
from jinja2 import Template
import boto3
from ..utils.json_util import loads
from datetime import datetime
import sentry_sdk
from sentry_sdk.integrations.aws_lambda import AwsLambdaIntegration

sentry_sdk.init(dsn=os.environ.get('SENTRY_DSN'), integrations=[AwsLambdaIntegration()])

client = boto3.client('dynamodb', region_name=os.environ['AWS_REGION'])

USERS_TABLE_NAME = os.environ['USERS_TABLE_NAME']
IDEAS_TABLE_NAME = os.environ['IDEAS_TABLE_NAME']
TAGS_TABLE_NAME = os.environ['TAGS_TABLE_NAME']
STATS_ACTIONS_TABLE_NAME = os.environ['STATS_ACTIONS_TABLE_NAME']

logger = logging.getLogger()
logger.setLevel(logging.INFO)

def get_user_by_id(user_id: str) -> dict:
    resp = client.get_item(
        TableName=USERS_TABLE_NAME,
        Key={'userId': {'S': user_id}}
    )
    return resp.get('Item')

def get_idea_by_id(user_id: str, idea_id: str) -> dict:
    resp = client.get_item(
        TableName=IDEAS_TABLE_NAME,
        Key={'userId': {'S': user_id}, 'ideaId': {'S': idea_id}}
    )
    return resp.get('Item')

def get_idea_tags(idea_id: str):
    resp = client.query(
        TableName=TAGS_TABLE_NAME,
        IndexName='ideaTags',
        KeyConditionExpression="ideaId = :ideaId",
        ExpressionAttributeValues={":ideaId": {"S": idea_id}},
    )
    return map(lambda raw_tag: raw_tag['tag']['S'], resp.get('Items', []))

def create_stats_record(idea_id: str, idea_owner_id: str, email: str, sharer: str, sharer_authorized=False):
    client.put_item(
        TableName=STATS_ACTIONS_TABLE_NAME,
        Item={
            "actionType": {"S": "share"},
            "createdDate": {"S": datetime.now().isoformat()},
            "ideaId": {"S": idea_id},
            "email": {"S": email},
            "idea_owner_id": {"S": idea_owner_id},
            "sharer": {"S": "id_{}".format(sharer) if sharer_authorized else "name_{}".format(sharer)}
        }
    )

def endpoint(event, context):
    # logger.info(event)
    ctx = event.get('ctx')
    arguments = ctx.get('arguments')
    idea_id = arguments.get('ideaId')
    idea_owner_id = arguments.get('ideaOwnerId')
    sender_name = arguments.get('senderName')
    friend_name = arguments.get('friendName')
    email = arguments.get('email')
    identity = ctx.get('identity')
    sender_id = None
    if identity:
        sender_id = identity.get('username')
    idea_to_send = get_idea_by_id(idea_owner_id, idea_id)
    idea_tags = list(get_idea_tags(idea_id))
    if idea_to_send is None:
        return {'ok': False, 'error': 'Idea Not Found'}
    if idea_owner_id != sender_id and idea_to_send['visibility']['S'] != 'PUBLIC':
        return {'ok': False, 'error': 'Idea is private'}

    shortId = idea_to_send['shortId']['S']
    slug = idea_to_send['slug']['S']

    SUBJECT = f"[Daily Idea] {sender_name} sent you Idea!"  # change to name
    BUCKET_URL_PREFIX = os.environ.get('BUCKET_URL_PREFIX')

    idea_created_time = idea_to_send['createdDate']['S'][:10]
    idea_created_time_formatted = datetime.strptime(idea_created_time, '%Y-%m-%d').strftime('%m/%d/%Y')

    render_context = {
        "tags": idea_tags,
        "friend_name": friend_name,
        "sender_name": sender_name,
        "BUCKET_URL_PREFIX": BUCKET_URL_PREFIX,
        "BASE_SITE_URL": f"https://{os.environ['DOMAIN_NAME']}/",
        "idea": loads(idea_to_send),
        "idea_created_time": idea_created_time_formatted,
        "link_to_idea": f"https://{os.environ['DOMAIN_NAME']}/i/{shortId}/{slug}",
        "datetime": datetime,
    }

    with open('./functions/share_idea/share_idea.html') as html_template_file:
        html_template = Template(html_template_file.read())
        with open('./functions/share_idea/share_idea.txt') as txt_template_file:
            txt_template = Template(txt_template_file.read())
            html_content = html_template.render(**render_context)
            txt_content = txt_template.render(**render_context)
            send_mail_to_user(email, SUBJECT, txt_content, html_content, f"{sender_name} via Daily Idea")
    create_stats_record(idea_id, idea_owner_id, email, sender_id if sender_id else sender_name, sender_id is not None)
    return {"ok": True}


import streamlit as st
import pandas as pd
import altair as alt

st.write(
    """
# Shanghai COVID Curve
Upload your Shanghai COVID with data and cases to see the curve.
"""
)

uploaded_file = st.file_uploader("Upload EXCEL FILE", type=".XLSX")

use_example_file = st.checkbox(
    "Use example file", False, help="Use in-built example file to demo the app"
)

# If CSV is not uploaded and checkbox is filled, use values from the example file
# and pass them down to the next if block
if use_example_file:
    uploaded_file = "Shanghai_COVID.xlsx"

if uploaded_file:
    df = pd.read_excel(uploaded_file)
    st.dataframe(df)
    chart_alt = alt.Chart(df).mark_line().encode(x="Date",   y="Cases",   color="Category" ).properties(
   height=600, width=800
    )
    st.altair_chart(chart_alt)


import requests
import threading
import time

def output(ok_list,file_path):
    num=1
    temp_1='''<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ProxifierProfile version="101" platform="MacOSX" product_id="2" product_minver="200">
<Options>
    <Resolve>
        <AutoModeDetection enabled="false"/>
        <ViaProxy enabled="false">
            <TryLocalDnsFirst enabled="false"/>
        </ViaProxy>
        <ExclusionList ExcludeSimpleHostnames="true" ExcludeLocalhost="true" ExcludeSelfHostname="true" ExcludeLocalDomain="true">localhost;%SimpleHostnames%;%ComputerName%;*.local;
</ExclusionList>
    </Resolve>
    <Encryption mode="basic"/>
    <HttpProxiesSupport enabled="true"/>
    <HandleDirectConnections enabled="false"/>
    <ConnectionLoopDetection enabled="true"/>
    <ProcessServices enabled="true"/>
    <ProcessOtherUsers enabled="true"/>
</Options>
<ProxyList>
    '''
    temp_2=''
    temp_3='''
    </ProxyList>
<ChainList/>
<RuleList>
    <Rule enabled="true">
        <Name>burpsuite</Name>
        <Applications>"Burp Suite Professional.app"; "Burp Suite Professional"; com.install4j.7318-9294-3757-1226.70</Applications>
        <Action type="Direct"/>
    </Rule>
    <Rule enabled="true">
        <Name>Default</Name>
        <Action type="Direct"/>
    </Rule>
</RuleList>
</ProxifierProfile>
    '''
    #for g in range(len(ok_list)):
    for key in ok_list:
        wnum=num+100
        num+=1
        ip=key
        port=ok_list[key]
        temp_2+='''
        <Proxy id="{}" type="SOCKS5">
            <Address>{}</Address>
            <Port>{}</Port>
            <Options>0</Options>
        </Proxy>\n
        '''.format(str(wnum),ip,port)
        ppx_name=str(time.time_ns())+'.ppx'
    with open(file_path+'/result/'+ppx_name, 'a') as s:
        s.write(temp_1+temp_2+temp_3)
    print('验证完毕，结果位于根目录下的'+ppx_name)

def check_proxy(all_proxy,file_path):
    ok_list={}
    socks=['socks5']
    proxy_file=open(file_path+"/result/"+str(time.time_ns())+".txt",'a',encoding='utf-8')
    for sock in socks:
        for key in all_proxy:
            ip_port=str(key)+":"+str(all_proxy[key])

            web_proxy="{}://{}".format(sock,ip_port)
            proxy = {
                'http': web_proxy,
                'https': web_proxy
            }
            headers = {
                'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_16_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36'
            }
            try:
                #r = requests.get('http://httpbin.org/ip', headers=headers, proxies=proxy, timeout=5)
                r = requests.get('https://www.baidu.com', headers=headers, proxies=proxy, timeout=5)
                if r.status_code == 200:
                    print('【{}】{}----验证成功'.format(threading.current_thread().name,web_proxy))
                    ok_list[key]=all_proxy[key]
                    proxy_file.write(str(ip_port)+"\n")
            except Exception as e:
                print('【{}】{}----超时'.format(threading.current_thread().name,web_proxy))
    proxy_file.close()
    #return ok_list
    output(ok_list,file_path)


import ctypes

# Binary Ninja components
import _binaryninjacore as core
import startup
import architecture
import callingconvention
import types

class _PlatformMetaClass(type):
	@property
	def list(self):
		startup._init_plugins()
		count = ctypes.c_ulonglong()
		platforms = core.BNGetPlatformList(count)
		result = []
		for i in xrange(0, count.value):
			result.append(Platform(None, core.BNNewPlatformReference(platforms[i])))
		core.BNFreePlatformList(platforms, count.value)
		return result

	@property
	def os_list(self):
		startup._init_plugins()
		count = ctypes.c_ulonglong()
		platforms = core.BNGetPlatformOSList(count)
		result = []
		for i in xrange(0, count.value):
			result.append(str(platforms[i]))
		core.BNFreePlatformOSList(platforms, count.value)
		return result

	def __iter__(self):
		startup._init_plugins()
		count = ctypes.c_ulonglong()
		platforms = core.BNGetPlatformList(count)
		try:
			for i in xrange(0, count.value):
				yield Platform(None, core.BNNewPlatformReference(platforms[i]))
		finally:
			core.BNFreePlatformList(platforms, count.value)

	def __setattr__(self, name, value):
		try:
			type.__setattr__(self, name, value)
		except AttributeError:
			raise AttributeError("attribute '%s' is read only" % name)

	def __getitem__(cls, value):
		startup._init_plugins()
		platform = core.BNGetPlatformByName(str(value))
		if platform is None:
			raise KeyError("'%s' is not a valid platform" % str(value))
		return Platform(None, platform)

	def get_list(cls, os = None, arch = None):
		startup._init_plugins()
		count = ctypes.c_ulonglong()
		if os is None:
			platforms = core.BNGetPlatformList(count)
		elif arch is None:
			platforms = core.BNGetPlatformListByOS(os)
		else:
			platforms = core.BNGetPlatformListByArchitecture(os, arch.handle)
		result = []
		for i in xrange(0, count.value):
			result.append(Platform(None, core.BNNewPlatformReference(platforms[i])))
		core.BNFreePlatformList(platforms, count.value)
		return result

class Platform(object):
	"""
	``class Platform`` contains all information releated to the execution environment of the binary, mainly the
	calling conventions used.
	"""
	__metaclass__ = _PlatformMetaClass
	name = None

	def __init__(self, arch, handle = None):
		if handle is None:
			self.arch = arch
			self.handle = core.BNCreatePlatform(arch.handle, self.__class__.name)
		else:
			self.handle = handle
			self.__dict__["name"] = core.BNGetPlatformName(self.handle)
			self.arch = architecture.Architecture(core.BNGetPlatformArchitecture(self.handle))

	def __del__(self):
		core.BNFreePlatform(self.handle)

	def __eq__(self, value):
		if not isinstance(value, Platform):
			return False
		return ctypes.addressof(self.handle.contents) == ctypes.addressof(value.handle.contents)

	def __ne__(self, value):
		if not isinstance(value, Platform):
			return True
		return ctypes.addressof(self.handle.contents) != ctypes.addressof(value.handle.contents)

	@property
	def default_calling_convention(self):
		"""
		Default calling convention.

		:getter: returns a CallingConvention object for the default calling convention.
		:setter: sets the default calling convention
		:type: CallingConvention
		"""
		result = core.BNGetPlatformDefaultCallingConvention(self.handle)
		if result is None:
			return None
		return callingconvention.CallingConvention(None, result)

	@default_calling_convention.setter
	def default_calling_convention(self, value):
		core.BNRegisterPlatformDefaultCallingConvention(self.handle, value.handle)

	@property
	def cdecl_calling_convention(self):
		"""
		Cdecl calling convention.

		:getter: returns a CallingConvention object for the cdecl calling convention.
		:setter sets the cdecl calling convention
		:type: CallingConvention
		"""
		result = core.BNGetPlatformCdeclCallingConvention(self.handle)
		if result is None:
			return None
		return callingconvention.CallingConvention(None, result)

	@cdecl_calling_convention.setter
	def cdecl_calling_convention(self, value):
		core.BNRegisterPlatformCdeclCallingConvention(self.handle, value.handle)

	@property
	def stdcall_calling_convention(self):
		"""
		Stdcall calling convention.

		:getter: returns a CallingConvention object for the stdcall calling convention.
		:setter sets the stdcall calling convention
		:type: CallingConvention
		"""
		result = core.BNGetPlatformStdcallCallingConvention(self.handle)
		if result is None:
			return None
		return callingconvention.CallingConvention(None, result)

	@stdcall_calling_convention.setter
	def stdcall_calling_convention(self, value):
		core.BNRegisterPlatformStdcallCallingConvention(self.handle, value.handle)

	@property
	def fastcall_calling_convention(self):
		"""
		Fastcall calling convention.

		:getter: returns a CallingConvention object for the fastcall calling convention.
		:setter sets the fastcall calling convention
		:type: CallingConvention
		"""
		result = core.BNGetPlatformFastcallCallingConvention(self.handle)
		if result is None:
			return None
		return callingconvention.CallingConvention(None, result)

	@fastcall_calling_convention.setter
	def fastcall_calling_convention(self, value):
		core.BNRegisterPlatformFastcallCallingConvention(self.handle, value.handle)

	@property
	def system_call_convention(self):
		"""
		System call convention.

		:getter: returns a CallingConvention object for the system call convention.
		:setter sets the system call convention
		:type: CallingConvention
		"""
		result = core.BNGetPlatformSystemCallConvention(self.handle)
		if result is None:
			return None
		return callingconvention.CallingConvention(None, result)

	@system_call_convention.setter
	def system_call_convention(self, value):
		core.BNSetPlatformSystemCallConvention(self.handle, value.handle)

	@property
	def calling_conventions(self):
		"""
		List of platform CallingConvention objects (read-only)

		:getter: returns the list of supported CallingConvention objects
		:type: list(CallingConvention)
		"""
		count = ctypes.c_ulonglong()
		cc = core.BNGetPlatformCallingConventions(self.handle, count)
		result = []
		for i in xrange(0, count.value):
			result.append(callingconvention.CallingConvention(None, core.BNNewCallingConventionReference(cc[i])))
		core.BNFreeCallingConventionList(cc, count.value)
		return result

	@property
	def types(self):
		"""List of platform-specific types (read-only)"""
		count = ctypes.c_ulonglong(0)
		type_list = core.BNGetPlatformTypes(self.handle, count)
		result = {}
		for i in xrange(0, count.value):
			name = types.QualifiedName._from_core_struct(type_list[i].name)
			result[name] = types.Type(core.BNNewTypeReference(type_list[i].type))
		core.BNFreeTypeList(type_list, count.value)
		return result

	@property
	def variables(self):
		"""List of platform-specific variable definitions (read-only)"""
		count = ctypes.c_ulonglong(0)
		type_list = core.BNGetPlatformVariables(self.handle, count)
		result = {}
		for i in xrange(0, count.value):
			name = types.QualifiedName._from_core_struct(type_list[i].name)
			result[name] = types.Type(core.BNNewTypeReference(type_list[i].type))
		core.BNFreeTypeList(type_list, count.value)
		return result

	@property
	def functions(self):
		"""List of platform-specific function definitions (read-only)"""
		count = ctypes.c_ulonglong(0)
		type_list = core.BNGetPlatformFunctions(self.handle, count)
		result = {}
		for i in xrange(0, count.value):
			name = types.QualifiedName._from_core_struct(type_list[i].name)
			result[name] = types.Type(core.BNNewTypeReference(type_list[i].type))
		core.BNFreeTypeList(type_list, count.value)
		return result

	@property
	def system_calls(self):
		"""List of system calls for this platform (read-only)"""
		count = ctypes.c_ulonglong(0)
		call_list = core.BNGetPlatformSystemCalls(self.handle, count)
		result = {}
		for i in xrange(0, count.value):
			name = types.QualifiedName._from_core_struct(call_list[i].name)
			t = types.Type(core.BNNewTypeReference(call_list[i].type))
			result[call_list[i].number] = (name, t)
		core.BNFreeSystemCallList(call_list, count.value)
		return result

	def __setattr__(self, name, value):
		try:
			object.__setattr__(self, name, value)
		except AttributeError:
			raise AttributeError("attribute '%s' is read only" % name)

	def __repr__(self):
		return "<platform: %s>" % self.name

	def __str__(self):
		return self.name

	def register(self, os):
		"""
		``register`` registers the platform for given OS name.

		:param str os: OS name to register
		:rtype: None
		"""
		core.BNRegisterPlatform(os, self.handle)

	def register_calling_convention(self, cc):
		"""
		``register_calling_convention`` register a new calling convention.

		:param CallingConvention cc: a CallingConvention object to register
		:rtype: None
		"""
		core.BNRegisterPlatformCallingConvention(self.handle, cc.handle)

	def get_related_platform(self, arch):
		result = core.BNGetRelatedPlatform(self.handle, arch.handle)
		if not result:
			return None
		return Platform(None, handle = result)

	def add_related_platform(self, arch, platform):
		core.BNAddRelatedPlatform(self.handle, arch.handle, platform.handle)

	def get_associated_platform_by_address(self, addr):
		new_addr = ctypes.c_ulonglong()
		new_addr.value = addr
		result = core.BNGetAssociatedPlatformByAddress(self.handle, new_addr)
		return Platform(None, handle = result), new_addr.value

	def get_type_by_name(self, name):
		name = types.QualifiedName(name)._get_core_struct()
		obj = core.BNGetPlatformTypeByName(self.handle, name)
		if not obj:
			return None
		return types.Type(obj)

	def get_variable_by_name(self, name):
		name = types.QualifiedName(name)._get_core_struct()
		obj = core.BNGetPlatformVariableByName(self.handle, name)
		if not obj:
			return None
		return types.Type(obj)

	def get_function_by_name(self, name):
		name = types.QualifiedName(name)._get_core_struct()
		obj = core.BNGetPlatformFunctionByName(self.handle, name)
		if not obj:
			return None
		return types.Type(obj)

	def get_system_call_name(self, number):
		return core.BNGetPlatformSystemCallName(self.handle, number)

	def get_system_call_type(self, number):
		obj = core.BNGetPlatformSystemCallType(self.handle, number)
		if not obj:
			return None
		return types.Type(obj)

	def generate_auto_platform_type_id(self, name):
		name = types.QualifiedName(name)._get_core_struct()
		return core.BNGenerateAutoPlatformTypeId(self.handle, name)

	def generate_auto_platform_type_ref(self, type_class, name):
		type_id = self.generate_auto_platform_type_id(name)
		return types.NamedTypeReference(type_class, type_id, name)

	def get_auto_platform_type_id_source(self):
		return core.BNGetAutoPlatformTypeIdSource(self.handle)


import sys
from traceback import format_exception

def get_traceback(self, exc_info=None):
    return ''.join(format_exception(*(exc_info or sys.exc_info())))

def current_stack(skip=0):
    try:
        1 / 0
    except ZeroDivisionError:
        f = sys.exc_info()[2].tb_frame
    for _ in xrange(skip + 2):
        f = f.f_back
    lst = []
    while f is not None:
        lst.append((f, f.f_lineno))
        f = f.f_back
    return lst


from strategy.context import Context
from strategy.home_duck import HomeDuck
from strategy.mallard_duck import MallardDuck

if __name__ == "__main__":
    context = Context()

    context.duck_strategy = MallardDuck()
    print("Client: Strategy is create MallardDuck")
    context.do_some_business_logic()
    print()

    print("Client: Strategy is create HomeDuck")
    context.duck_strategy = HomeDuck()
    context.do_some_business_logic()