import discord
from discord import app_commands
from discord.ext import commands
from statbotics import Statbotics
from datetime import datetime
from random import shuffle
from os import environ
from utils import *
from tba import *

# Setting channel ids
BOT_TESTING_CHANNEL_ID = 1031012980692889615
CONEUNIST_CHANNEL_ID = 1040069639847301120
CHANNEL_ID = BOT_TESTING_CHANNEL_ID

# Get the token from the environment variables
TOKEN = environ['MATCH_BOT_DISCORD_TOKEN']

# Getting current year. By default, only matches from the current season are listed
year = int(datetime.today().strftime("%Y"))

# Initalize Statbotics
sb = Statbotics()

# TODO: Determine required intents
intents = discord.Intents.default()
intents.message_content = True
intents.members = True

# Initialize our bot
bot = commands.Bot(command_prefix='!', intents=intents)

# Runs when bot connects
@bot.event
async def on_ready():
    print(f'Logged in as {bot.user} (ID: {bot.user.id})')
    try:
        synced = await bot.tree.sync()
        print(f"Synced {len(synced)} command(s)")
    except Exception as e:
        print(e)

@bot.tree.command(name="teaminfo", description="Display basic information about a team")
@app_commands.describe(team = "The team number or id")
async def team_info(interaction: discord.Interaction, team: int):
    team_object = get_team_object(team)
    tba_link = "https://www.thebluealliance.com/team/" + str(team)

    embed = discord.Embed(title=get_team_name(team_object), url=tba_link, description="", color=discord.Color.blue())
    embed.set_author(name="The Blue Alliance", url="https://www.thebluealliance.com", icon_url="https://raw.githubusercontent.com/the-blue-alliance/the-blue-alliance-logo/main/ios/tba-icon-Artwork.png")

    embed.add_field(name="Sponsors", value=team_object["name"], inline=False)
    embed.add_field(name="Location", value=get_team_location(team_object), inline=True)
    embed.add_field(name="Rookie Year", value=str(team_object["rookie_year"]), inline=True)

    view = discord.ui.View(timeout=None)
    for social in get_team_socials(team_object).items():
        view.add_item(discord.ui.Button(label=social[0], style=discord.ButtonStyle.link, url=social[1]))

    save_team_avatar(team_object, year)
    avatar_file = discord.File(AVATAR_TEMP_PATH, filename=AVATAR_TEMP_NAME)
    embed.set_thumbnail(url="attachment://"+AVATAR_TEMP_NAME)

    try:
        await interaction.response.send_message(file=avatar_file, embed=embed, view=view)
    except:
        await interaction.response.send_message(file=avatar_file, embed=embed)

@bot.tree.command(name="teamstats", description="Display ranking of a team and other skill-based stats for this season")
@app_commands.describe(team = "The team number or id")
async def team_stats(interaction: discord.Interaction, team: int):
    team_object = get_team_object(team)
    tba_link = "https://www.statbotics.io/team/" + str(team)

    embed = discord.Embed(title=get_team_name(team_object), url=tba_link, description="", color=discord.Color.red())
    embed.set_author(name="Statbotics", url="https://www.statbotics.io")

    stats_dict = sb.get_team_year(team=team, year=year)

    embed.add_field(name="Wins", value=str(stats_dict["wins"]), inline=True)
    embed.add_field(name="Losses", value=str(stats_dict["losses"]), inline=True)
    embed.add_field(name="Ties", value=str(stats_dict["ties"]), inline=True)

    embed.add_field(name="", value="", inline=False)

    embed.add_field(name="Auto EPA", value=str(round(stats_dict["auto_epa_end"], 1)), inline=True)
    embed.add_field(name="Teleop EPA", value=str(round(stats_dict["teleop_epa_end"], 1)), inline=True)
    embed.add_field(name="Endgame EPA", value=str(round(stats_dict["endgame_epa_end"], 1)), inline=True)
    embed.add_field(name="Total EPA", value=str(round(stats_dict["epa_end"], 1)), inline=True)

    embed.add_field(name="", value="", inline=False)

    embed.add_field(name="Global Rank", value=str(stats_dict["total_epa_rank"]) + " out of " + str(stats_dict["total_team_count"]), inline=True)
    if stats_dict["country"] != None:
        embed.add_field(name=stats_dict["country"] + " Rank", value=str(stats_dict["country_epa_rank"]) + " out of " + str(stats_dict["country_team_count"]), inline=True)
    if stats_dict["state"] != None:
        embed.add_field(name=stats_dict["state"] + " Rank", value=str(stats_dict["state_epa_rank"]) + " out of " + str(stats_dict["state_team_count"]), inline=True)

    save_team_avatar(team_object, year)
    avatar_file = discord.File(AVATAR_TEMP_PATH, filename=AVATAR_TEMP_NAME)
    embed.set_thumbnail(url="attachment://"+AVATAR_TEMP_NAME)

    await interaction.response.send_message(file=avatar_file, embed=embed)

@bot.tree.command(name="eventinfo", description="Display basic information about an event")
@app_commands.describe(event = "The event number or id")
async def event_info(interaction: discord.Interaction, event: str):
    if event == "archimedes":
      event = "2023arc"
    elif event == "curie":
      event = "2023cur"
    elif event == "daly":
      event = "2023dal"
    elif event == "galileo":
      event = "2023gal"
    elif event == "hopper":
      event = "2023hop"
    elif event == "johnson":
      event = "2023joh"
    elif event == "milstein":
      event = "2023mil"
    elif event == "newton":
      event = "2023new"
    elif event == "einstein":
      event = "2023cmptx"
    event_object = tba.event(event)
    tba_link = "https://www.thebluealliance.com/event/" + event

    year = event_object["year"]
    date_string = date_range_string(event_object["start_date"], event_object["end_date"])
    location_string = "📍 "+event_object["address"]
    try:
        week = str(int(event_object["week"])+1)
        full_string = f"🗓 {date_string}, {year} (Week {week})\n{location_string}"
    except TypeError:
        full_string = f"🗓 {date_string}, {year}\n{location_string}"

    embed = discord.Embed(title=event_object["name"], url=tba_link, description=full_string, color=discord.Color.blue())
    embed.set_author(name="The Blue Alliance", url="https://www.thebluealliance.com", icon_url="https://raw.githubusercontent.com/the-blue-alliance/the-blue-alliance-logo/main/ios/tba-icon-Artwork.png")

    all_team_numbers = [team["team_number"] for team in tba.event_teams(event)]
    shuffle(all_team_numbers)
    all_teams_string = ""
    i = 0
    for team in all_team_numbers:
        if i != 0:
            all_teams_string += ", "
        all_teams_string += str(team)
        if i > 100:
            all_teams_string += f" and {len(all_team_numbers)-i} more"
            break
        i += 1

    embed.add_field(name="Teams", value=all_teams_string, inline=False)
    #embed.add_field(name="Status", value=str(team_object["rookie_year"]), inline=True)

    view = discord.ui.View(timeout=None)
    for webcast in get_event_webcasts(event_object).items():
        view.add_item(discord.ui.Button(label=webcast[0], style=discord.ButtonStyle.link, url=webcast[1]))

    try:
        await interaction.response.send_message(embed=embed, view=view)
    except:
        await interaction.response.send_message(embed=embed)

@bot.tree.command(name="nextmatch", description="Displays the next match the team will play in or the next match in the event")
@app_commands.describe(type = "Either 'team' or 'event'", id = "The team/event number or id")
async def next_match(interaction: discord.Interaction, type: str, id: str):
    response = "`Sending...`"
    matches = get_team_or_event_matches(type, id, year)
    if matches == {}:
        response = "`Error: Must input valid team or event`"

    await interaction.response.send_message(response)

    if matches != {}:
        header = "**Next upcoming match for "
        if type == "team":
            header = header + format_team_header(int(id)) + ":**"
        if type == "event":
            header = header + "the " + format_event_header(id) + ":**"
        print_out = split_string_under_2000(get_match_table(get_next_match(matches)))
        await bot.get_channel(CHANNEL_ID).send(header)
        await bot.get_channel(CHANNEL_ID).send(code_block(print_out[0]))

@bot.tree.command(name="recentmatch", description="Displays the last played match for the team or in the event, as well as the match video if posted")
@app_commands.describe(type = "Either 'team' or 'event'", id = "The team/event number or id")
async def recent_match(interaction: discord.Interaction, type: str, id: str):
    response = "`Sending...`"
    matches = get_team_or_event_matches(type, id, year)
    if matches == {}:
        response = "`Error: Must input valid team or event`"

    await interaction.response.send_message(response)

    if matches != {}:
        header = "**Most recent match for "
        if type == "team":
            header = header + format_team_header(int(id)) + ":**"
        if type == "event":
            header = header + "the " + format_event_header(id) + ":**"
        print_out = split_string_under_2000(get_match_table(get_most_recent_match(matches)))
        await bot.get_channel(CHANNEL_ID).send(header)
        await bot.get_channel(CHANNEL_ID).send(code_block(print_out[0]))
        await bot.get_channel(CHANNEL_ID).send(get_match_video(get_most_recent_match(matches)))

@bot.tree.command(name="allmatches", description="Displays all matches played by a team or in an event")
@app_commands.describe(type = "Either 'team' or 'event'", id = "The team/event number or id")
async def all_matches(interaction: discord.Interaction, type: str, id: str):
    response = "`Sending...`"
    matches = get_team_or_event_matches(type, id, year)
    if matches == {}:
        response = "`Error: Must input valid team or event`"

    await interaction.response.send_message(response)

    if matches != {}:
        header = "**All matches for "
        if type == "team":
            header = header + format_team_header(int(id)) + ":**"
        if type == "event":
            header = header + "the " + format_event_header(id) + ":**"
        print_out = split_string_under_2000(get_match_table(matches))
        await bot.get_channel(CHANNEL_ID).send(header)
        for out in print_out:
            await bot.get_channel(CHANNEL_ID).send(code_block(out))

bot.run(TOKEN)


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

import numpy as np
import matplotlib.pyplot as plt
import logRegress as lr

def loadDataSet():
    '''
    Function:
        加载数据
    :return
        dataMat - 数据列表
        labelMat - 标签列表
    Modify:
        2018-08-16
    '''
    dataMat = []; labelMat = []
    fr = open('testSet.txt')
    for line in fr.readlines():
        # lineArr = line.split()可以直接划分字符串了
        lineArr = line.strip().split()
        # 将列表对象添加到dataMat中，注意为多精度的小数float
        # 为了方便计算，该函数还将X0的值设为1.0
        dataMat.append([1.0, float(lineArr[0]), float(lineArr[1])])
        # 同理将最后一列的标签信息添加，按照整型添加
        labelMat.append(int(lineArr[-1]))
    return dataMat, labelMat

def plotDataSet():
    '''
    Function:
        加载数据
    :return: None
    Modify:
        2018-08-16
    '''
    dataMat, labelMat = loadDataSet()                                       # 加载数据集
    dataArr = np.array(dataMat)                                             # 转换成numpy的array数组
    n = np.shape(dataMat)[0]                                                # 数据数组的个数
    xcord1 = []; ycord1 = []                                                # 正样本
    xcord2 = []; ycord2 = []                                                # 负样本
    for i in range(n):                                                      # 根据数据集标签进行分类
        if int(labelMat[i]) == 1:
            xcord1.append(dataArr[i,1]); ycord1.append(dataArr[i,2])        # 1为正样本
        else:
            xcord2.append(dataArr[i,1]); ycord2.append(dataArr[i,2])        # 0为负样本
    fig = plt.figure()
    ax = fig.add_subplot(111)                                               # 添加subplot
    # scatter函数中x，y为二维坐标，s为size，c为color，marker为形状，alpha为透明度的值
    ax.scatter(xcord1, ycord1, s= 20, c= 'red', marker= 's', alpha=.5)      # 绘制正样本
    ax.scatter(xcord2, ycord2, s= 20, c= 'green', alpha=.5)                 # 绘制负样本,marker默认是圆点

    plt.title('DataSet')                                                    # 绘制title
    plt.xlabel('x'); plt.ylabel('y')                                        # 绘制label
    plt.show()

def plotBestFit(weights):
    '''
    Function:
        绘制数据集
    :param weights: 权重参数数组
    :return: None
    Modify:
        2018-08-16
    '''
    dataMat, labelMat = loadDataSet()                                       # 加载数据集
    dataArr = np.array(dataMat)                                             # 转换成numpy的array数组
    n = np.shape(dataMat)[0]                                                # 数据个数
    xcord1 = []; ycord1 = []                                                # 正样本
    xcord2 = []; ycord2 = []                                                # 负样本
    for i in range(n):                                                      # 根据数据集标签进行分类
        if int(labelMat[i]) == 1:
            xcord1.append(dataArr[i, 1]); ycord1.append(dataArr[i, 2])      # 1为正样本
        else:
            xcord2.append(dataArr[i, 1]); ycord2.append(dataArr[i, 2])      # 0为负样本

    fig = plt.figure()
    ax = fig.add_subplot(111)                                               # 添加subplot
    ax.scatter(xcord1, ycord1, s=20, c='red', marker='*', alpha=.5)         # 绘制正样本
    ax.scatter(xcord2, ycord2, s=20, c='green', alpha=.5)                   # 绘制负样本,marker默认是圆点
    x = np.arange(-3.0, 3.0, 0.1)
    y = (-weights[0] - weights[1] * x) / weights[2]
    ax.plot(x, y)

    plt.title('BestFit')                                                    # 绘制title
    plt.xlabel('X1');
    plt.ylabel('X2')                                                        # 绘制label
    plt.show()

if __name__ == '__main__':
    plotDataSet()
    dataMat, labelMat = lr.loadDataSet()
    weights = lr.gradAscent(dataMat, labelMat)
    plotBestFit(weights)


"""
generic script
         -  -
text: "fooziman" output => "fo-zi-ma-"
text: "barziman" output => "ba-zi-an"
text: "qux" output => "qu-"
text: "eq" output => "eq"
cada 2 cosos agregar una raya
"""

def fn_hack_5(tx):
    tx = list(tx)
    for i in range(len(tx)):
        if i % 3 == 0 and i != 0:
            tx[i-1] = '-'
    return ''.join(tx)
print(fn_hack_5(''))


import abc
import logging
from time import time
import itertools
from functools import cmp_to_key
import re
from threading import Condition
# pylint: disable=import-error,no-name-in-module
# needed for google.protobuf import
from google.protobuf.message import DecodeError

from sawtooth_validator.state.merkle import MerkleDatabase
from sawtooth_validator.state.batch_tracker import BatchFinishObserver
from sawtooth_validator.networking.dispatch import Handler
from sawtooth_validator.networking.dispatch import HandlerResult
from sawtooth_validator.networking.dispatch import HandlerStatus
from sawtooth_validator.networking.dispatch import PreprocessorResult

from sawtooth_validator.protobuf import client_batch_pb2
from sawtooth_validator.protobuf import client_block_pb2
from sawtooth_validator.protobuf import client_state_pb2
from sawtooth_validator.protobuf import client_transaction_pb2
from sawtooth_validator.protobuf import client_batch_submit_pb2
from sawtooth_validator.protobuf import client_list_control_pb2
from sawtooth_validator.protobuf import client_peers_pb2
from sawtooth_validator.protobuf import client_status_pb2
from sawtooth_validator.protobuf.block_pb2 import BlockHeader
from sawtooth_validator.protobuf import validator_pb2
from sawtooth_validator.protobuf.client_batch_submit_pb2 \
    import ClientBatchSubmitResponse

LOGGER = logging.getLogger(__name__)
DEFAULT_TIMEOUT = 300
MAX_PAGE_SIZE = 1000
DEFAULT_PAGE_SIZE = 100

class _ResponseFailed(BaseException):
    """Raised when a response failed to complete and should be sent as is.

    Args:
        status (enum): Status to be sent with the incomplete response

    Attributes:
        status (enum): Status to be sent with the incomplete response
    """

    def __init__(self, status):
        super().__init__()
        self.status = status

class _ClientRequestHandler(Handler, metaclass=abc.ABCMeta):
    """Parent class for all Client Request Handlers.

    Handles the repetitive tasks of parsing a client request, and formatting
    the response. Also includes some helper methods common to multiple client
    handlers. Child classes should not implement the `handle` method directly,
    instead defining a unique `_respond` method specified below.

    Args:
        request_proto (class): Protobuf class of the request to be handled
        response_proto (class): Protobuf class of the response to be sent
        response_type (enum): Message status of the response
        tree (MerkleDatabase, optional): State tree to be queried
        block_store (BlockStoreAdapter, optional): Block chain to be queried

    Attributes:
        _status (class): Convenience ref to response_proto for accessing enums
    """

    def __init__(self, request_proto, response_proto, response_type,
                 tree=None, block_store=None):
        self._request_proto = request_proto
        self._response_proto = response_proto
        self._response_type = response_type
        self._status = response_proto

        self._id_regex = re.compile('[0-9a-f]{128}')
        self._state_root_regex = re.compile('[0-9a-f]{64}')
        self._namespace_regex = re.compile('^([0-9a-f]{2}){0,35}$')

        self._tree = tree
        self._block_store = block_store

    def handle(self, connection_id, message_content):
        """Handles parsing incoming requests, and wrapping the final response.

        Args:
            connection_id (str): ZMQ identity sent over ZMQ socket
            message_content (bytes): Byte encoded request protobuf to be parsed

        Returns:
            HandlerResult: result to be sent in response back to client
        """
        try:
            request = self._request_proto()
            request.ParseFromString(message_content)
        except DecodeError:
            LOGGER.info('Protobuf %s failed to deserialize', request)
            return self._wrap_result(self._status.INTERNAL_ERROR)

        try:
            response = self._respond(request)
        except _ResponseFailed as e:
            response = e.status

        return self._wrap_result(response)

    @abc.abstractmethod
    def _respond(self, request):
        """This method must be implemented by each child to build its response.

        Args:
            request (object): A parsed request object of the specified protobuf

        Returns:
            enum: An enum status, or...
            dict: A dict of attributes for the response protobuf
        """
        raise NotImplementedError('Client Handler must have _respond method')

    def _wrap_result(self, response):
        """Wraps child's response in a HandlerResult to be sent back to client.

        Args:
            response (enum or dict): Either an integer status enum, or a dict
                of attributes to be added to the protobuf response.
        """
        if isinstance(response, int):
            response = self._wrap_response(response)

        return HandlerResult(
            status=HandlerStatus.RETURN,
            message_out=self._response_proto(**response),
            message_type=self._response_type)

    def _wrap_response(self, status=None, **kwargs):
        """Convenience method to wrap a status with any key word args.

        Args:
            status (enum): enum response status, defaults to OK

        Returns:
            dict: inlcudes a 'status' attribute and any key word arguments
        """
        kwargs['status'] = status if status is not None else self._status.OK
        return kwargs

    def _get_head_block(self, request):
        """Fetches the request specified head block, or the chain head.

        Note:
            This method will fail if `_block_store` has not been set

        Args:
            request (object): The parsed protobuf request object

        Returns:
            Block: the block object at the head of the requested chain

        Raises:
            ResponseFailed: Failed to retrieve a head block
        """
        if request.head_id:
            if self._id_regex.fullmatch(request.head_id) is None:
                LOGGER.debug('Invalid head id requested: %s', request.head_id)
                raise _ResponseFailed(self._status.NO_ROOT)
            try:
                return self._block_store[request.head_id]
            except KeyError as e:
                LOGGER.debug('Unable to find block "%s" in store', e)
                raise _ResponseFailed(self._status.NO_ROOT) from e

        else:
            return self._get_chain_head()

    def _get_chain_head(self):
        if self._block_store.chain_head:
            return self._block_store.chain_head

        LOGGER.debug('Unable to get chain head from block store')
        raise _ResponseFailed(self._status.NOT_READY)

    def _set_root(self, request):
        """Sets the root of the merkle tree, returning any head id used.

        Note:
            This method will fail if `_tree` has not been set

        Args:
            request (object): The parsed protobuf request object

        Returns:
            str: the state root of the head block used to specify the root

        Raises:
            ResponseFailed: Failed to set the root if the merkle tree
        """
        if request.state_root:
            root = request.state_root
        else:
            head = self._get_chain_head()
            root = head.state_root_hash

        try:
            self._tree.set_merkle_root(root)
        except KeyError as e:
            LOGGER.debug('Unable to find root "%s" in database', e)
            raise _ResponseFailed(self._status.NO_ROOT) from e

        return root

    def _list_store_resources(self, request, head_id, filter_ids,
                              resource_fetcher, block_xform):
        """Builds a list of blocks or resources derived from blocks,
        handling multiple possible filter requests:
            - filtered by a set of ids
            - filtered by head block
            - filtered by both id and head block
            - not filtered (all current resources)

        Note:
            This method will fail if `_block_store` has not been set

        Args:
            request (object): The parsed protobuf request object
            head_id (str): Either request.head_id, or the current chain head
            filter_ids (list of str): the resource ids (if any) to filter by
            resource_fetcher (function): Fetches a resource by its id
                Expected args:
                    resource_id: The id of the resource to be fetched
                Expected return:
                    object: The resource to be appended to the results
            block_xform (function): Transforms a block into a list of resources
                Expected args:
                    block: A block object from the block store
                Expected return:
                    list: To be concatenated to the end of the results

        Returns:
            list: List of blocks or data from blocks. If filtered by ids,
                they will be listed in the same order as the id filters,
                otherwise they will be ordered from newest to oldest
        """
        resources = []

        # Simply fetch by id if filtered by id but not by head block
        if filter_ids and not request.head_id:
            for resource_id in filter_ids:
                try:
                    resources.append(resource_fetcher(resource_id))
                except (KeyError, ValueError, TypeError):
                    # Invalid ids should be omitted, not raise an exception
                    pass

        # Traverse block chain to build results for most scenarios
        else:
            current_id = head_id
            while current_id in self._block_store:
                block = self._block_store[current_id].block
                resources += block_xform(block)
                header = BlockHeader()
                header.ParseFromString(block.header)
                current_id = header.previous_block_id

        # If filtering by head AND ids, the traverse results must be winnowed
        if request.head_id and filter_ids:
            matches = {
                r.header_signature: r
                for r in resources if r.header_signature in filter_ids
            }
            resources = [matches[i] for i in filter_ids if i in matches]

        return resources

    def _validate_ids(self, resource_ids):
        """Validates a list of ids, raising a ResponseFailed error if invalid.

        Args:
            resource_id (list of str): The ids to validate

        Raises:
            ResponseFailed: The id was invalid, and a status of INVALID_ID
                will be sent with the response.
        """
        for resource_id in resource_ids:
            if self._id_regex.fullmatch(resource_id) is None:
                LOGGER.debug('Invalid resource id requested: %s', resource_id)
                raise _ResponseFailed(self._status.INVALID_ID)

    def _validate_state_root(self, state_root):
        """Validates a state root, raising a ResponseFailed error if invalid.

        Args:
            state_root (str): The state_root to validate

        Raises:
            ResponseFailed: The state_root was invalid, and a status of
                INVALID_ROOT will be sent with the response.
        """
        if self._state_root_regex.fullmatch(state_root) is None:
            LOGGER.debug('Invalid state root: %s', state_root)
            raise _ResponseFailed(self._status.INVALID_ROOT)

    def _validate_namespace(self, namespace):
        """Validates a namespace, raising a ResponseFailed error if invalid.

        Args:
            state_root (str): The state_root to validate

        Raises:
            ResponseFailed: The state_root was invalid, and a status of
                INVALID_ROOT will be sent with the response.
        """
        if self._namespace_regex.fullmatch(namespace) is None:
            LOGGER.debug('Invalid namespace: %s', namespace)
            raise _ResponseFailed(self._status.INVALID_ADDRESS)

class _Pager:
    """A static class containing methods to paginate lists of resources.

    Contains a paginate method, as well as two helpers to fetch index of a
    resource by its id (either address or header_signature), or conversely
    to fetch the id by an index.
    """

    @classmethod
    def paginate_resources(cls, request, resources, on_fail_status):
        """Truncates a list of resources based on ClientPagingControls

        Args:
            request (object): The parsed protobuf request object
            resources (list of objects): The resources to be paginated

        Returns:
            list: The paginated list of resources
            object: The ClientPagingResponse to be sent back to the client
        """
        if not resources:
            return (resources, client_list_control_pb2.ClientPagingResponse())

        paging = request.paging
        limit = min(paging.limit, MAX_PAGE_SIZE) or DEFAULT_PAGE_SIZE
        # Find the start index from the location marker sent
        try:
            if paging.start:
                start_index = cls.index_by_id(paging.start, resources)
            else:
                start_index = 0

            if start_index < 0 or start_index >= len(resources):
                raise AssertionError
        except AssertionError:
            raise _ResponseFailed(on_fail_status) from AssertionError

        paged_resources = resources[start_index: start_index + limit]
        if start_index + limit < len(resources):
            paging_response = client_list_control_pb2.ClientPagingResponse(
                next=cls.id_by_index(start_index + limit, resources),
                start=cls.id_by_index(start_index, resources),
                limit=limit)
        else:
            paging_response = client_list_control_pb2.ClientPagingResponse(
                start=cls.id_by_index(start_index, resources),
                limit=limit)

        return paged_resources, paging_response

    @classmethod
    def index_by_id(cls, target_id, resources):
        """Helper method to fetch the index of a resource by its id or address

        Args:
            resources (list of objects): The resources to be paginated
            target_id (string): The address or header_signature of the resource

        Returns:
            integer: The index of the target resource

        Raises:
            AssertionError: Raised if the target is not found
        """
        for index in range(len(resources)):
            if cls.id_by_index(index, resources) == target_id:
                return index

        raise AssertionError

    @staticmethod
    def id_by_index(index, resources):
        """Helper method to fetch the id or address of a resource by its index

        Args:
            resources (list of objects): The resources to be paginated
            index (integer): The index of the target resource

        Returns:
            str: The address or header_signature of the resource,
                returns an empty string if not found
        """
        if index < 0 or index >= len(resources):
            return ''

        try:
            return resources[index].header_signature
        except AttributeError:
            return resources[index].address

class _Sorter:
    """A static class containing a method to sort lists of resources based on
    ClientSortControls sent with the request.
    """

    @classmethod
    def sort_resources(cls, request, resources, fail_enum, header_proto=None):
        """Sorts a list of resources based on a list of sort controls

        Args:
            request (object): The parsed protobuf request object
            resources (list of objects): The resources to be sorted
            fail_enum (int, enum): The enum status to raise with invalid keys
            header_proto(class): Class to decode a resources header

        Returns:
            list: The sorted list of resources
        """
        if not request.sorting:
            return resources

        value_handlers = cls._get_handler_set(request, fail_enum, header_proto)

        def sorter(resource_a, resource_b):
            for handler in value_handlers:
                val_a, val_b = handler.get_sort_values(resource_a, resource_b)

                if val_a < val_b:
                    return handler.xform_result(-1)
                if val_a > val_b:
                    return handler.xform_result(1)

            return 0

        return sorted(resources, key=cmp_to_key(sorter))

    @classmethod
    def _get_handler_set(cls, request, fail_enum, header_proto=None):
        """Goes through the list of ClientSortControls and returns a list of
        unique _ValueHandlers. Maintains order, but drops ClientSortControls
        that have already appeared to help prevent spamming.
        """
        added = set()
        handlers = []

        for controls in request.sorting:
            control_bytes = controls.SerializeToString()
            if control_bytes not in added:
                added.add(control_bytes)
                handlers.append(
                    cls._ValueHandler(controls, fail_enum, header_proto))

        return handlers

    class _ValueHandler:
        """Handles fetching proper compare values for one ClientSortControls.

        Args:
            controls (object): Individual SortControl object
            fail_status (integer, enum): Status to send when controls are bad
            header_proto (class): Class to decode the resource header
        """

        def __init__(self, controls, fail_status, header_proto=None):
            self._keys = controls.keys
            self._fail_status = fail_status
            self._header_proto = header_proto

            if controls.reverse:
                self.xform_result = lambda x: -x
            else:
                self.xform_result = lambda x: x

            if header_proto and self._keys[0] == 'header':
                self._had_explicit_header = True
                self._keys = self._keys[1:]
            else:
                self._had_explicit_header = False

        def get_sort_values(self, resource_a, resource_b):
            """Applies sort control logic to fetch from two resources the
            values that should actually be compared.
            """
            if (self._had_explicit_header
                    or self._header_proto
                    and not hasattr(resource_a, self._keys[0])):
                resource_a = self._get_header(resource_a)
                resource_b = self._get_header(resource_b)

            for key in self._keys:
                try:
                    resource_a = getattr(resource_a, key)
                    resource_b = getattr(resource_b, key)
                except AttributeError as e:
                    raise _ResponseFailed(self._fail_status) from e

            return resource_a, resource_b

        def _get_header(self, resource):
            """Fetches a header from a resource.
            """
            header = self._header_proto()
            header.ParseFromString(resource.header)
            return header

def block_num_to_hex(block_num):
    """Converts a block number to a hex string.
    This is used for proper index ordering and lookup.

    Args:
        block_num: uint64

    Returns:
        A hex-encoded str
    """
    return "{0:#0{1}x}".format(block_num, 18)

def _format_batch_statuses(statuses, batch_ids, tracker):
    """Takes a statuses dict and formats it for transmission with Protobuf and
    ZMQ.

    Args:
        statuses (dict of int): Dict with batch ids as the key, status as value
        batch_ids (list of str): The batch ids in their original order
        tracker (BatchTracker): A batch tracker with access to invalid info
    """
    proto_statuses = []

    for batch_id in batch_ids:
        if statuses[batch_id] == \
           client_batch_submit_pb2.ClientBatchStatus.INVALID:
            invalid_txns = tracker.get_invalid_txn_info(batch_id)
            for txn_info in invalid_txns:
                try:
                    txn_info['transaction_id'] = txn_info.pop('id')
                except KeyError as e:
                    LOGGER.debug(e)
        else:
            invalid_txns = None

        proto_statuses.append(
            client_batch_submit_pb2.ClientBatchStatus(
                batch_id=batch_id,
                status=statuses[batch_id],
                invalid_transactions=invalid_txns))

    return proto_statuses

class _BatchWaiter(BatchFinishObserver):
    """An observer which provides a method which locks until every batch in a
    set of ids is committed.

    Args:
        batch_tracker (BatchTracker): The BatchTracker that will notify the
            BatchWaiter that all of the batches it is interested in are no
            longer PENDING.
    """

    def __init__(self, batch_tracker):
        self._batch_tracker = batch_tracker
        self._wait_condition = Condition()
        self._statuses = None

    def notify_batches_finished(self, statuses):
        """Called by the BatchTracker the _BatchWaiter is observing. Should not
        be called by handlers.

        Args:
            statuses (dict of int): A dict with keys of batch ids, and values
                of status enums
        """
        with self._wait_condition:
            self._statuses = statuses
            self._wait_condition.notify()

    # pylint: disable=inconsistent-return-statements
    def wait_for_batches(self, batch_ids, timeout=None):
        """Locks until a list of batch ids is committed to the block chain
        or a timeout is exceeded. Returns the statuses of those batches.

        Args:
            batch_ids (list of str): The ids of the batches to wait for
            timeout(int): Maximum time in seconds to wait for

        Returns:
            list of BatchStatus: BatchStatuses to send back to client
        """
        self._batch_tracker.watch_statuses(self, batch_ids)
        timeout = timeout or DEFAULT_TIMEOUT
        start_time = time()

        with self._wait_condition:
            while True:
                if self._statuses is not None:
                    return _format_batch_statuses(
                        self._statuses, batch_ids, self._batch_tracker)

                if time() - start_time > timeout:
                    statuses = self._batch_tracker.get_statuses(batch_ids)
                    return _format_batch_statuses(
                        statuses, batch_ids, self._batch_tracker)

                self._wait_condition.wait(timeout - (time() - start_time))

class BatchSubmitFinisher(_ClientRequestHandler):
    def __init__(self, batch_tracker):
        self._batch_tracker = batch_tracker
        super().__init__(
            client_batch_submit_pb2.ClientBatchSubmitRequest,
            client_batch_submit_pb2.ClientBatchSubmitResponse,
            validator_pb2.Message.CLIENT_BATCH_SUBMIT_RESPONSE)

    def handle(self, connection_id, message_content):
        try:
            response = self._respond(message_content)
        except _ResponseFailed as e:
            response = e.status

        return self._wrap_result(response)

    def _respond(self, request):
        for batch in request.batches:
            if batch.trace:
                LOGGER.debug("TRACE %s: %s", batch.header_signature,
                             self.__class__.__name__)

        return self._status.OK

class BatchStatusRequest(_ClientRequestHandler):
    def __init__(self, batch_tracker):
        self._batch_tracker = batch_tracker
        super().__init__(
            client_batch_submit_pb2.ClientBatchStatusRequest,
            client_batch_submit_pb2.ClientBatchStatusResponse,
            validator_pb2.Message.CLIENT_BATCH_STATUS_RESPONSE)

    def _respond(self, request):
        self._validate_ids(request.batch_ids)

        if request.wait:
            waiter = _BatchWaiter(self._batch_tracker)
            statuses = waiter.wait_for_batches(
                request.batch_ids,
                request.timeout)
        else:
            statuses_dict = self._batch_tracker.get_statuses(request.batch_ids)
            statuses = _format_batch_statuses(
                statuses_dict, request.batch_ids, self._batch_tracker)

        if not statuses:
            return self._status.NO_RESOURCE

        return self._wrap_response(batch_statuses=statuses)

class StateListRequest(_ClientRequestHandler):
    def __init__(self, database, block_store):
        super().__init__(
            client_state_pb2.ClientStateListRequest,
            client_state_pb2.ClientStateListResponse,
            validator_pb2.Message.CLIENT_STATE_LIST_RESPONSE,
            tree=MerkleDatabase(database),
            block_store=block_store)

    def _respond(self, request):
        if request.state_root != '':
            self._validate_state_root(request.state_root)
        state_root = self._set_root(request)

        # Fetch entries and encode as protobuf
        self._validate_namespace(request.address)
        entries = [
            client_state_pb2.ClientStateListResponse.Entry(address=a, data=v)
            for a, v in self._tree.leaves(request.address or '')]

        # Order entries, remove if tree.entries refactored to be ordered
        entries.sort(key=lambda l: l.address)

        if self.is_reverse(request.sorting, self._status.INVALID_SORT):
            entries.reverse()

        entries, paging = _Pager.paginate_resources(
            request,
            entries,
            self._status.INVALID_PAGING)

        if not entries:
            return self._wrap_response(
                self._status.NO_RESOURCE,
                state_root=state_root,
                paging=paging)

        return self._wrap_response(
            state_root=state_root,
            paging=paging,
            entries=entries)

    @staticmethod
    def is_reverse(sorting, fail_status):
        if not sorting:
            return False

        if not sorting[0].keys == ['default']:
            raise _ResponseFailed(fail_status)

        return sorting[0].reverse

class StateGetRequest(_ClientRequestHandler):
    def __init__(self, database, block_store):
        super().__init__(
            client_state_pb2.ClientStateGetRequest,
            client_state_pb2.ClientStateGetResponse,
            validator_pb2.Message.CLIENT_STATE_GET_RESPONSE,
            tree=MerkleDatabase(database),
            block_store=block_store)

    def _respond(self, request):
        if request.state_root != '':
            self._validate_state_root(request.state_root)
        state_root = self._set_root(request)

        # Fetch leaf value
        self._validate_namespace(request.address)
        try:
            value = self._tree.get(request.address)
        except KeyError:
            LOGGER.debug('Unable to find entry at address %s', request.address)
            return self._status.NO_RESOURCE
        except ValueError:
            LOGGER.debug('Address %s is a nonleaf', request.address)
            return self._status.INVALID_ADDRESS

        return self._wrap_response(state_root=state_root, value=value)

class BlockListRequest(_ClientRequestHandler):
    def __init__(self, block_store):
        super().__init__(
            client_block_pb2.ClientBlockListRequest,
            client_block_pb2.ClientBlockListResponse,
            validator_pb2.Message.CLIENT_BLOCK_LIST_RESPONSE,
            block_store=block_store)

    def _respond(self, request):
        head_block = self._get_head_block(request)
        self._validate_ids(request.block_ids)
        blocks = None
        paging_response = None

        if request.block_ids:
            blocks = self._block_store.get_blocks(request.block_ids)
            blocks = itertools.filterfalse(
                lambda block: block.block_num > head_block.block_num,
                blocks)

            # realize the iterator
            blocks = list(map(lambda blkw: blkw.block, blocks))

            paging_response = client_list_control_pb2.ClientPagingResponse()
        else:
            paging = request.paging
            sort_reverse = BlockListRequest.is_reverse(
                request.sorting, self._status.INVALID_SORT)
            limit = min(paging.limit, MAX_PAGE_SIZE) or DEFAULT_PAGE_SIZE
            iterargs = {
                'reverse': not sort_reverse
            }

            if paging.start:
                iterargs['start_block_num'] = paging.start
            elif not sort_reverse:
                iterargs['start_block'] = head_block

            block_iter = None
            try:
                block_iter = self._block_store.get_block_iter(**iterargs)
                blocks = block_iter
                if sort_reverse:
                    blocks = itertools.takewhile(
                        lambda block: block.block_num <= head_block.block_num,
                        blocks)

                blocks = itertools.islice(blocks, limit)
                # realize the result list, which will evaluate the underlying
                # iterator
                blocks = list(map(lambda blkw: blkw.block, blocks))

                next_block = next(block_iter, None)
                if next_block:
                    next_block_num = block_num_to_hex(
                        next_block.block_num)
                else:
                    next_block_num = None

                block_id = blocks[0].header_signature
                start = self._block_store[block_id].block_num
            except ValueError:
                if paging.start:
                    return self._status.INVALID_PAGING

                return self._status.NO_ROOT
            except KeyError:
                if paging.start:
                    return self._status.INVALID_PAGING

                return self._status.NO_ROOT

            paging_response = client_list_control_pb2.ClientPagingResponse(
                next=next_block_num,
                limit=limit,
                start=block_num_to_hex(start)
            )

        if not blocks:
            return self._wrap_response(
                self._status.NO_RESOURCE,
                head_id=head_block.identifier,
                paging=paging_response)

        return self._wrap_response(
            head_id=head_block.identifier,
            paging=paging_response,
            blocks=blocks)

    @staticmethod
    def is_reverse(sorting, fail_status):
        if not sorting:
            return False

        if not sorting[0].keys == ['block_num']:
            raise _ResponseFailed(fail_status)

        return sorting[0].reverse

class BlockGetByIdRequest(_ClientRequestHandler):

    def __init__(self, block_store):
        super().__init__(
            client_block_pb2.ClientBlockGetByIdRequest,
            client_block_pb2.ClientBlockGetResponse,
            validator_pb2.Message.CLIENT_BLOCK_GET_RESPONSE,
            block_store=block_store)

    def _respond(self, request):
        self._validate_ids([request.block_id])

        try:
            block = self._block_store[request.block_id].block

        except KeyError as e:
            LOGGER.debug(e)
            return self._status.NO_RESOURCE

        return self._wrap_response(block=block)

class BlockGetByNumRequest(_ClientRequestHandler):
    def __init__(self, block_store):
        super().__init__(
            client_block_pb2.ClientBlockGetByNumRequest,
            client_block_pb2.ClientBlockGetResponse,
            validator_pb2.Message.CLIENT_BLOCK_GET_RESPONSE,
            block_store=block_store)

    def _respond(self, request):
        try:
            block = self._block_store.get_block_by_number(
                request.block_num).block

        except KeyError as e:
            LOGGER.debug(e)
            return self._status.NO_RESOURCE

        return self._wrap_response(block=block)

class BlockGetByTransactionRequest(_ClientRequestHandler):
    def __init__(self, block_store):
        super().__init__(
            client_block_pb2.ClientBlockGetByTransactionIdRequest,
            client_block_pb2.ClientBlockGetResponse,
            validator_pb2.Message.CLIENT_BLOCK_GET_RESPONSE,
            block_store=block_store)

    def _respond(self, request):
        self._validate_ids([request.transaction_id])

        try:
            block = self._block_store.get_block_by_transaction_id(
                request.transaction_id).block
        except ValueError as e:
            LOGGER.debug(e)
            return self._status.NO_RESOURCE

        return self._wrap_response(block=block)

class BlockGetByBatchRequest(_ClientRequestHandler):
    def __init__(self, block_store):
        super().__init__(
            client_block_pb2.ClientBlockGetByBatchIdRequest,
            client_block_pb2.ClientBlockGetResponse,
            validator_pb2.Message.CLIENT_BLOCK_GET_RESPONSE,
            block_store=block_store)

    def _respond(self, request):
        self._validate_ids([request.batch_id])

        try:
            block = self._block_store.get_block_by_batch_id(
                request.batch_id).block
        except ValueError as e:
            LOGGER.debug(e)
            return self._status.NO_RESOURCE

        return self._wrap_response(block=block)

class BatchListRequest(_ClientRequestHandler):
    def __init__(self, block_store):
        super().__init__(
            client_batch_pb2.ClientBatchListRequest,
            client_batch_pb2.ClientBatchListResponse,
            validator_pb2.Message.CLIENT_BATCH_LIST_RESPONSE,
            block_store=block_store)

    def _respond(self, request):
        head_id = self._get_head_block(request).header_signature
        self._validate_ids(request.batch_ids)

        batches = self._list_store_resources(
            request,
            head_id,
            request.batch_ids,
            self._block_store.get_batch,
            lambda block: list(block.batches))

        if self.is_reverse(request.sorting, self._status.INVALID_SORT):
            batches.reverse()

        batches, paging = _Pager.paginate_resources(
            request,
            batches,
            self._status.INVALID_PAGING)

        if not batches:
            return self._wrap_response(
                self._status.NO_RESOURCE,
                head_id=head_id,
                paging=paging)

        return self._wrap_response(
            head_id=head_id,
            paging=paging,
            batches=batches)

    @staticmethod
    def is_reverse(sorting, fail_status):
        if not sorting:
            return False

        if not sorting[0].keys == ['default']:
            raise _ResponseFailed(fail_status)

        return sorting[0].reverse

class BatchGetRequest(_ClientRequestHandler):
    def __init__(self, block_store):
        super().__init__(
            client_batch_pb2.ClientBatchGetRequest,
            client_batch_pb2.ClientBatchGetResponse,
            validator_pb2.Message.CLIENT_BATCH_GET_RESPONSE,
            block_store=block_store)

    def _respond(self, request):
        self._validate_ids([request.batch_id])

        try:
            batch = self._block_store.get_batch(request.batch_id)
        except ValueError as e:
            LOGGER.debug(e)
            return self._status.NO_RESOURCE

        return self._wrap_response(batch=batch)

class TransactionListRequest(_ClientRequestHandler):
    def __init__(self, block_store):
        super().__init__(
            client_transaction_pb2.ClientTransactionListRequest,
            client_transaction_pb2.ClientTransactionListResponse,
            validator_pb2.Message.CLIENT_TRANSACTION_LIST_RESPONSE,
            block_store=block_store)

    def _respond(self, request):
        head_id = self._get_head_block(request).header_signature
        self._validate_ids(request.transaction_ids)

        transactions = self._list_store_resources(
            request,
            head_id,
            request.transaction_ids,
            self._block_store.get_transaction,
            lambda block: [t for a in block.batches for t in a.transactions])

        if self.is_reverse(request.sorting, self._status.INVALID_SORT):
            transactions.reverse()

        transactions, paging = _Pager.paginate_resources(
            request,
            transactions,
            self._status.INVALID_PAGING)

        if not transactions:
            return self._wrap_response(
                self._status.NO_RESOURCE,
                head_id=head_id,
                paging=paging)

        return self._wrap_response(
            head_id=head_id,
            paging=paging,
            transactions=transactions)

    @staticmethod
    def is_reverse(sorting, fail_status):
        if not sorting:
            return False

        if not sorting[0].keys == ['default']:
            raise _ResponseFailed(fail_status)

        return sorting[0].reverse

class TransactionGetRequest(_ClientRequestHandler):
    def __init__(self, block_store):
        super().__init__(
            client_transaction_pb2.ClientTransactionGetRequest,
            client_transaction_pb2.ClientTransactionGetResponse,
            validator_pb2.Message.CLIENT_TRANSACTION_GET_RESPONSE,
            block_store=block_store)

    def _respond(self, request):
        self._validate_ids([request.transaction_id])

        try:
            txn = self._block_store.get_transaction(request.transaction_id)
        except ValueError as e:
            LOGGER.debug(e)
            return self._status.NO_RESOURCE

        return self._wrap_response(transaction=txn)

class PeersGetRequest(_ClientRequestHandler):
    def __init__(self, gossip):
        super().__init__(
            client_peers_pb2.ClientPeersGetRequest,
            client_peers_pb2.ClientPeersGetResponse,
            validator_pb2.Message.CLIENT_PEERS_GET_RESPONSE
        )
        self._gossip = gossip

    def _respond(self, request):
        peers = self._gossip.get_peers()
        endpoints = [peers[connection_id] for connection_id in peers]
        return self._wrap_response(peers=endpoints)

class StatusGetRequest(_ClientRequestHandler):
    def __init__(self, gossip):
        super().__init__(
            client_status_pb2.ClientStatusGetRequest,
            client_status_pb2.ClientStatusGetResponse,
            validator_pb2.Message.CLIENT_STATUS_GET_RESPONSE
        )
        self._gossip = gossip

    def _respond(self, request):
        peers = [
            self._response_proto.Peer(endpoint=endpoint)
            # {'endpoint': endpoint}
            for endpoint in self._gossip.get_peers().values()
        ]

        return self._wrap_response(
            endpoint=self._gossip.endpoint,
            peers=sorted(peers, key=lambda peer: peer.endpoint))

def client_batch_submit_request_preprocessor(message_content_bytes):
    request = client_batch_submit_pb2.ClientBatchSubmitRequest()

    try:
        request.ParseFromString(message_content_bytes)
    except DecodeError:
        LOGGER.error('ClientBatchSubmitRequest failed to deserialize')

        return PreprocessorResult(
            status=HandlerStatus.RETURN,
            message_out=ClientBatchSubmitResponse(
                status=ClientBatchSubmitResponse.INTERNAL_ERROR),
            message_type=validator_pb2.Message.CLIENT_BATCH_SUBMIT_RESPONSE)

    return PreprocessorResult(content=request)


#  List - Used to store multiple items in a single variable

food = ["doza", "idly", "poori","coffee","tea","chapathi"]

food.append("Ice Cream")
food.remove("idly")
food.pop()
# food.insert(0, "Noodles")
food.sort()
food.clear()
print(food)


import os
import sys
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))

from sumoenv import TrafficControlEnv

import typer

app = typer.Typer(context_settings={"help_option_names": ["-h", "--help"]}, add_completion=False)

@app.command("allroutes")
def save_route_trajectories(
    net_fname: str = typer.Argument(help="The file name of the sumo network"),
    step_length: float = 0.01,
    use_gui: bool = True,
    save_file: str = "sumo_routes.pk",
    output_path: str = os.path.join("output","converter"),
    plot_traj: bool = True):
    """
    Save the trajectories of all available routes in the network.
    """
    if not os.path.exists(output_path):
        os.makedirs(output_path)

    save_file = os.path.join(output_path, save_file)
    env = TrafficControlEnv(net_fname = net_fname, step_length=step_length, use_gui=use_gui)
    env.get_route_trajectories(save_file=save_file, plot_traj=plot_traj)
    env.close()

if __name__ == "__main__":
    app()


from fastapi import APIRouter
from fastapi.responses import JSONResponse
from fastapi.staticfiles import StaticFiles
from pydantic import BaseModel
from typing import List
from call_chatgpt import call_chatgpt
from logger import logger

router = APIRouter()

menu = """
ラーメン:
醤油ラーメン 普通800円、大盛900円
味噌ラーメン 普通800円、大盛900円
塩ラーメン 普通800円、大盛900円
激辛ラーメン 普通900円、大盛1000円
冷やし中華 800円
丼もの:
カツ丼 普通800円、大盛1000円
天丼 普通800円、大盛1000円
親子丼 普通800円、大盛1000円
ランチセット：
ラーメン炒飯セット 1000円
ラーメン餃子セット 1000円
ラーメンカツ丼セット 1000円
単品:
餃子 300円
ミニ炒飯 300円
唐揚げ 300円
飲み物:
ビール 大1000円、中700円、小500円
お茶 300円
"""

class Message(BaseModel):
    role: str
    content: str

@router.get("/order/init")
def initorder():
    logger.debug("てすとてｓつお")
    data = {
        "message": "どうも！来々軒です。ご注文は何ですか？"
    }
    # JSONResponseに辞書型のデータを渡して返す
    return JSONResponse(content=data)

@router.post("/order")
def order(messages: List[Message]):

    # messagesの最後から10要素のみにする
    messages = messages[-10:]

    # System Prompt
    system_prompt = f"""あなたは注文ボットです。来々軒というラーメン屋の宅配注文を受け付ける自動サービスです。
まず、お客様に挨拶をし、注文を受け付けます。
注文がすべて揃うまで待ち、それを要約して最終確認としてお客様に他に何か追加したいものがないか尋ねます。
注文が揃ったら、住所と名前を尋ねます。
金額は決して提示してはなりません。
注文が完了、もしくは金額を聞かれたら「サマリーボタンを押してください」と返答してください。
メニューから商品を一意に特定できるように、すべての単品注文、サイズを明確に確認してください。
短く、親しみやすいスタイルで返答します。
メニューは以下のとおりです。
{menu}
"""
    # messagesの先頭に要素を追加
    messages.insert(0, Message(role="system", content=system_prompt))

    logger.debug(messages)

    # ChatGPTを呼び出す
    answer = call_chatgpt([m.dict() for m in messages])

    data = {
        "message": answer
    }
    # JSONResponseに辞書型のデータを渡して返す
    return JSONResponse(content=data)

@router.post("/order/summary")
def summary(messages: List[Message]):

    # messagesの最後から10要素のみにする
    messages = messages[-10:]

    # mesagesの内容を平文のテキストにする。roleによって話者名をつける
    text = ""
    for m in messages:
        if m.role == "user":
            text += "お客様: " + m.content + "\n"
        elif m.role == "assistant":
            text += "あなた: " + m.content + "\n"

    # System Prompt
    system_prompt = f"""あなたは会話履歴からJSONを生成するマシーンです。
JSONには、1) item_name 2) item_size 3) item_price 4) quantity. 5) delivery_address 6) customer_name を含めてください。
JSON以外の説明や補足は不要です。

出力JSON例:
{{
    order:[
    {{
      "item_name": "醤油ラーメン",
      "item_size": "普通"
      "item_price": 800,
      "quantity": 2
    }},
    {{
      "item_name": "味噌ラーメン",
      "item_size": "普通"
      "item_price": 800,
      "quantity": 1
    }},
    {{
      "item_name": "ビール",
      "item_size": "大"
      "item_price": 1000,
      "quantity": 1,
    }}
    ],
    "delivery_address": "東京都渋谷区神南1-1-1",
    "customer_name": "山田太郎"
}}

会話履歴:
{text}

メニュー表:
{menu}
"""

    # 新しいList(Messsage)を作成し、先頭に要素を追加
    messages = [Message(role="system", content=system_prompt),Message(role="user",content="JSONのみ回答して下さい")]

    logger.debug(messages)

    # ChatGPTを呼び出す
    answer = call_chatgpt([m.dict() for m in messages])

    data = {
        "message": answer
    }
    # JSONResponseに辞書型のデータを渡して返す
    return JSONResponse(content=data)


"""Data pipeline."""
import gzip
import json
from io import BytesIO
from typing import List, Tuple, TypeVar

import numpy as np
import torch
import torch.distributed as dist
from logging_utils import get_logger

logger = get_logger()
T_co = TypeVar("T_co", covariant=True)

def chunks(l, n):
    """Yield n number of striped chunks from l."""
    for i in range(0, n):
        yield l[i::n]

###### Load GPT pretraining data ######
class GPTPretrainingDataset(torch.utils.data.Dataset):
    """GPT Pretraining Dataset."""

    def __init__(
        self,
        input_paths: List[str],
        max_sequence_length=None,
        zipped=True,
    ):
        self.input_paths = input_paths
        self.max_sequence_length = max_sequence_length
        self.zipped = zipped
        self.drop_last = True
        self.input_data = []
        self.num_replicas = dist.get_world_size() if dist.is_initialized() else 1
        self.rank = dist.get_rank() if dist.is_initialized() else 0
        self.__read_examples(self.input_paths)

    def __read_examples(self, paths: List[str]):
        for path in paths:
            self.input_data = []
            # 1 below:  each item of an S3Dataset object is a pair
            # The 0th element is a string for S3 object address
            # The 1st element is binary data
            if isinstance(path, tuple):
                filepath = path[0]
                fileobj = BytesIO(path[1])
            else:
                fileobj = path

            if self.zipped:
                with gzip.open(fileobj, "rt") as f:
                    self.input_data = [ln for _, ln in enumerate(f, 1)]
            else:
                with open(fileobj, "r") as f:
                    self.input_data = [ln for ln in f]
            if dist.get_rank() == 0:
                logger.debug(f"Read {len(self.input_data)} sequences from file")

    def __len__(self) -> int:
        return len(self.input_data)

    def __getitem__(self, index: int) -> Tuple[torch.Tensor, torch.Tensor]:
        obj = json.loads(self.input_data[index])
        iids = torch.tensor(obj["input_ids"], dtype=torch.long)
        attns = torch.tensor(obj["attention_mask"], dtype=torch.long)
        self.actual_sequence_length = len(obj["input_ids"])

        if self.actual_sequence_length > self.max_sequence_length:
            s_idx = np.random.randint(0, self.actual_sequence_length - self.max_sequence_length)
            e_idx = s_idx + self.max_sequence_length
            iids = iids[s_idx:e_idx]
            attns = attns[s_idx:e_idx]
        return iids, attns


#####################################
### WELCOME TO YOUR OOP PROJECT #####
#####################################

# For this project you will be using OOP to create a card game. This card game will
# be the card game "War" for two players, you an the computer. If you don't know
# how to play "War" here are the basic rules:
#
# The deck is divided evenly, with each player receiving 26 cards, dealt one at a time,
# face down. Anyone may deal first. Each player places his stack of cards face down,
# in front of him.
#
# The Play:
#
# Each player turns up a card at the same time and the player with the higher card
# takes both cards and puts them, face down, on the bottom of his stack.
#
# If the cards are the same rank, it is War. Each player turns up three cards face
# down and one card face up. The player with the higher cards takes both piles
# (six cards). If the turned-up cards are again the same rank, each player places
# another card face down and turns another card face up. The player with the
# higher card takes all 10 cards, and so on.
#
# There are some more variations on this but we will keep it simple for now.
# Ignore "double" wars
#
# https://en.wikipedia.org/wiki/War_(card_game)

from random import shuffle

# from Python.Python_Level_Two.Part3_OOP_Project_SOLUTIONS import SUITE

# Two useful variables for creating Cards.
SUITS = 'Hrt Dia Spa Clb'.split()
RANKS = '2 3 4 5 6 7 8 9 10 J Q K A'.split()

class Deck:
    """
    This is the Deck Class. This object will create a deck of cards to initiate
    play. You can then use this Deck list of cards to split in half and give to
    the players. It will use SUITE and RANKS to create the deck. It should also
    have a method for splitting/cutting the deck in half and Shuffling the deck.
    """

    def __init__(self):
        self.allcards = [(suit, rank) for suit in SUITS for rank in RANKS]

    def shuffle(self):
        shuffle(self.allcards)

    def deal_hands(self):
        return self.allcards[::2], self.allcards[1::2]

    pass

class Hand:
    '''
    This is the Hand class. Each player has a Hand, and can add or remove
    cards from that hand. There should be an add and remove card method here.
    '''

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

    def __str__(self):
        return "Contains {} cards".format(len(self.cards))

    def add_card(self, added_cards):
        return self.cards.extend(added_cards)

    def remove_card(self):
        return self.cards.pop()

    pass

class Player:
    """
    This is the Player class, which takes in a name and an instance of a Hand
    class object. The Player can then play cards and check if they still have cards.
    """

    def __init__(self, name, hand):
        self.name = name
        self.hand = hand

    def play_cards(self):
        drawn_card = self.hand.remove_card()
        print("{} has played {}".format(self.name, drawn_card))
        print('\n')
        return drawn_card

    def remove_war_cards(self):
        war_cards = []
        if len(self.hand.cards) < 3:
            return self.hand.cards
        else:
            for x in range(3):
                war_cards.append(self.hand.cards.pop())
            return war_cards

    def still_has_cards(self):
        return len(self.hand.cards) != 1

    pass

######################
#### GAME PLAY #######
######################
print("Welcome to War, let's begin...")

deck_of_cards = Deck()
deck_of_cards.shuffle()
player_hand1, player_hand2 = deck_of_cards.deal_hands()

terminator = Player("Computer", Hand(player_hand2))
human_name = input("Player Name:")
human = Player(human_name, Hand(player_hand1))

total_round = 0
war_count = 0

while human.still_has_cards() or terminator.still_has_cards():
    total_round += 1
    print("It is time for a new round!")
    print("Here are the current standings: ")
    print(human.name+" count: "+str(len(human.hand.cards)))
    print(terminator.name+" count: "+str(len(terminator.hand.cards)))
    print("Both players play a card!")
    print('\n')

    table_cards = []

    computer_played = terminator.play_cards()
    human_played = human.play_cards()

    table_cards.append(computer_played)
    table_cards.append(human_played)

    if computer_played[1] == human_played[1]:
        war_count += 1
        table_cards.extend(terminator.remove_war_cards())
        table_cards.extend(human.remove_war_cards())

        computer_played = terminator.play_cards()
        human_played = human.play_cards()

        if RANKS.index(computer_played[1]) < RANKS.index(human_played[1]):
            print(human.name+" has the higher card, adding to hand.")
            human.hand.add_card(table_cards)
        else:
            print(terminator.name+" has the higher card, adding to hand.")
            terminator.hand.add_card(table_cards)

    else:
        if RANKS.index(computer_played[1]) < RANKS.index(human_played[1]):
            print(human.name+" has the higher card, adding to hand.")
            human.hand.add_card(table_cards)
        else:
            print(terminator.name+" has the higher card, adding to hand.")
            terminator.hand.add_card(table_cards)

print("Great Game, it lasted: "+str(total_round))
print("A war occured "+str(war_count)+" times.")

print('Doesthe computer still ahve card? ')

# Use the 3 classes along with some logic to play a game of war!


class Solution(object):
    def wordBreak(self, s, wordDict):
        """
        :type s: str
        :type wordDict: List[str]
        :rtype: bool
        """
        dp = [False]*(len(s)+1) #use dynamic programming
        dp[0]= True
        for i in range(len(s)+1):
            for j in range(i+1): #see if there are any "break-points" we could continue from
                if dp[j] and s[j:i] in wordDict:
                    dp[i]= True
                    break
        if dp[-1]:
            return True

        return False


import requests
import json
from tkinter import *
from PIL import Image, ImageTk
import os
import urllib.request

class WeatherApp:
    def __init__(self, master):
        self.width = 600
        self.height = 550
        self.canvas = Canvas(master, height= self.height, width= self.width)
        self.canvas.pack()
        self.background_image = PhotoImage(file='canvaspic.png')
        self.background_label = Label(master, image=self.background_image)
        self.background_label.place(relwidth=1, relheight=1)
        self.frame1 = Frame(master, bg="#80dfff", bd=10)
        self.frame1.place(relx = 0.1, rely=0.1, relheight = 0.2, relwidth= 0.8)
        self.label1 = Label(self.frame1, bg="white")
        self.label1.place(relx = 0.001, rely=0.005, relheight = 1, relwidth= 1)
        self.button1 = Button(self.label1, text="Get Weather", font="Arial", command= lambda: self.get_weather())
        self.button1.place(relx = 0.65, rely=0.2, relheight = 0.6, relwidth= 0.3)
        self.entry1 = Entry(self.label1, font="Arial")
        self.entry1.place(relx=0.05, rely=0.2, relheight=0.6, relwidth=0.5)
        self.frame2 = Frame(master, bg="#80dfff", bd=10)
        self.frame2.place(relx = 0.1, rely=0.7, relheight = 0.2, relwidth= 0.8)
        self.label2 = Label(self.frame2, bg="white", font="Arial")
        self.label2.place(relx = 0.001, rely=0.005, relheight = 1, relwidth= 1)
        self.testimage = PhotoImage(file="01d.png")
        self.label3 = Canvas(self.frame2, bg="white", bd=0, highlightthickness=0)
        self.label3.place(relx=0.7, rely=0.1, relheight=0.7, relwidth=0.3)

    def get_weather(self):
        try:
            url = "http://api.openweathermap.org/data/2.5/weather?q={}&units=imperial&appid=85071fc9957db8d8bf613dfd2b66c598"
            city = self.entry1.get()
            r = requests.get(url.format(city)).json()
            city_ = city
            temp = r["main"]["temp"]
            conditions = r["weather"][0]["description"]
            icon_ = r["weather"][0]["icon"]
            final_output = 'City: %s \nConditions: %s \nTemperature (°F): %s' % (city_, conditions, temp)
            self.label2["text"] = final_output
            self.open_image(icon_)
        except:
            self.label2["text"] = "There was a problem retrieving that information"

    def open_image(self, icon):
        size = int(self.frame2.winfo_height() * 0.75)
        img = ImageTk.PhotoImage(Image.open('./img/' + icon + '.png').resize((size, size)))
        self.label3.delete("all")
        self.label3.image = img
        self.label3.create_image(0, 0, anchor='nw', image=img)

root = Tk()
root.title("Weather App")
app_gui = WeatherApp(root)
root.mainloop()


import logging
import os
import time

import cloudpickle
import grpc

from smarts.zoo import worker as zoo_worker
from smarts.zoo import worker_pb2, worker_pb2_grpc

logging.basicConfig(level=logging.INFO)
log = logging.getLogger(f"worker_servicer.py - pid({os.getpid()})")

class WorkerServicer(worker_pb2_grpc.WorkerServicer):
    """Provides methods that implement functionality of Worker Servicer."""

    def __init__(self):
        self._agent = None
        self._agent_spec = None

    def build(self, request, context):
        time_start = time.time()
        self._agent_spec = cloudpickle.loads(request.payload)
        pickle_load_time = time.time()
        self._agent = self._agent_spec.build_agent()
        agent_build_time = time.time()
        log.debug(
            "Build agent timings:\n"
            f"  total ={agent_build_time - time_start:.2}\n"
            f"  pickle={pickle_load_time - time_start:.2}\n"
            f"  build ={agent_build_time - pickle_load_time:.2}\n"
        )
        return worker_pb2.Status()

    def act(self, request, context):
        if self._agent == None or self._agent_spec == None:
            context.set_details(f"Remote agent not built yet.")
            context.set_code(grpc.StatusCode.FAILED_PRECONDITION)
            return worker_pb2.Action()

        adapted_obs = self._agent_spec.observation_adapter(
            cloudpickle.loads(request.payload)
        )
        action = self._agent.act(adapted_obs)
        adapted_action = self._agent_spec.action_adapter(action)
        return worker_pb2.Action(action=cloudpickle.dumps(adapted_action))


#!/usr/bin/python3

# This script is used by the monioring/check-seslimits Jenkins job

import boto3
import argparse
import sys

# Copied from https://stackoverflow.com/a/41153081
class ExtendAction(argparse.Action):
    def __call__(self, parser, namespace, values, option_string=None):
        items = getattr(namespace, self.dest) or []
        items.extend(values)
        setattr(namespace, self.dest, items)

if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument('-c', '--critical', required=True, type=float,
                        help="Critical threshold in percentage")
    parser.add_argument('-w', '--warning', required=False, type=float,
                        help="Warning threshold in percentage (Optional)")
    parser.add_argument('-r', '--region', dest='regions', nargs='+',
                        action=ExtendAction, required=True,
                        help="AWS regions to check")
    args = parser.parse_args()

    if args.warning and args.warning >= args.critical:
        warn_str = f"Warning threshold ({args.warning})"
        crit_str = f"Critical threshold ({args.critical})"
        print(f"ERROR: {warn_str} >= {crit_str}")
        sys.exit(1)

    exit_code = 0

    session = boto3.session.Session()
    for region in args.regions:
        ses = session.client('ses', region_name=region)
        data = ses.get_send_quota()
        limit = data["Max24HourSend"]
        current = data["SentLast24Hours"]
        percent = current/limit
        level = None

        if percent >= args.critical:
            level = "CRITICAL"
        elif args.warning and percent >= args.warning:
            level = "WARNING"

        if level:
            print("{} {}/{} ({}%) - {}".format(region, current, limit, percent,
                  level))
            exit_code += 1

    sys.exit(exit_code)


# coding=utf-8

""" Autor: Víctor García Carrera, victorgarciacarrera@gmail.com
	Descarga el contenido del buscador de google con un término
	de búsqueda concreto y guarda el NUMERO DE RESULTADOS

	v3.2	BUSCA TAMBIEN CON site:*.es para covid-19 y coronavirus
"""

import sys
import os
import errno
from math import *
from random import *

""" Ejemplo obtenido de: https://www.edureka.co/blog/web-scraping-with-python/ """

from selenium import webdriver
from webdriver_manager.chrome import ChromeDriverManager
#from selenium.webdriver.common.keys import keys		#The Keys class provide keys in the keyboard like RETURN, F1, ALT etc.

from bs4 import BeautifulSoup		#Libreria bs4 version ultima BeautifulSoup4
import pandas as pd

import string
import time
from datetime import datetime
import numpy as np

# INTENTAR ThreadPoolExecutor
from concurrent.futures import ProcessPoolExecutor
# Para ver si procesos o threads: https://dev.to/rhymes/how-to-make-python-code-concurrent-with-3-lines-of-code-2fpe

POOLSIZE = 10

""" ### FALTA HACER LISTA DE DRIVERS (meter @|FIREFOX|@) +
	###		+ CALCULO DE RESULTADOS (estadisticas, valorar con desviacion respecto a la media...)
	### 	+ INSPECCIONAR/MEDIR + DATOS como tiempo de respuesta, enlaces (expresiones regulares)
"""

def main():

	global POOLSIZE

	###########################################################################
	#########		CONFIGURACIÓN DE LAS BÚSQUEDAS		#######################
	#########		driver, lista de BUSQUEDAS 			#######################
	###########################################################################

	""" LINEAS PARA DESHABILITAR EL CONTROL DE GOOGLE: "Chrome is being controlled by automated test software" """
	chrome_options = webdriver.ChromeOptions();
	chrome_options.add_argument('--headless');		# EJECUCION EN BACKGROUND
	# To fix execution in script
	chrome_options.add_argument('--no-sandbox');
	chrome_options.add_argument('--disable-dev-shm-usage');
	##

	chrome_options.add_experimental_option("excludeSwitches", ['enable-automation', 'disable-infobars']);

	driver = webdriver.Chrome(ChromeDriverManager().install(), options=chrome_options );
	# ,service_args=['--verbose', '--log-path=/tmp/chromedriver.log' )

	""" Lista con el numero de resultados por termino de busqueda """
	resultados = []
	resultados_groups = []
	## Lista con los términos de búsqueda
	busquedas = []
	busquedas2 = []
	## Listas NUEVAS con los términos de búsqueda (SITE:*.es)
	busquedas_site = []
	busquedas2_site = []
	## Lista con los términos agrupados para paralelizar mejor la búsqueda
	busquedas_groups = []
	busquedas_groups2 = []
	## Lista NUEVAS con los términos agrupados para paralelizar mejor la búsqueda (SITE:*.es)
	busquedas_groups_site = []
	busquedas_groups2_site = []

	"""busquedas = ["*.es"]"""
	""" Lista(array numpy) con las búsquedas a realizar en Google """

	###########################################################################
	###########################################################################
	#### PROBAR CON site:*.es 		IMP!!!! 	###############################
	busquedas = np.array( ["*.es", "covid-19 *.es", "crisis * covid-19 *.es", "calma * covid-19 *.es", "esperanza * covid-19 *.es" ,
					"pánico * covid-19 *.es", "miedo * covid-19 *.es", "ansiedad * covid-19 *.es", "terror * covid-19 *.es",
					"inseguridad * covid-19 *.es", "enfado * covid-19 *.es", "rabia * covid-19 *.es", "ira * covid-19 *.es" ,
					"alegría * covid-19 *.es", "tristeza * covid-19 *.es" , "sorpresa * covid-19 *.es", "alivio * covid-19 *.es",
					"desconfianza * covid-19 *.es", "incertidumbre * covid-19 *.es", "sanidad * covid-19 *.es", "aislamiento * covid-19 *.es",
					"cuarentena * covid-19 *.es", "solidaridad * covid-19 *.es", "cooperación * covid-19 *.es", "protección * covid-19 *.es",
					"irresponsable * covid-19 *.es", "polític* * covid-19 *.es", "polític* * irresponsable* * covid-19 *.es", "medic* * covid-19 *.es",
					"cura * covid-19 *.es", "abastecimiento * covid-19 *.es", "alimentos crisis * covid-19 *.es", "alimentos * covid-19 *.es",
					"aislamiento * covid-19 *.es", "memes * covid-19 *.es", "bromas * covid-19 *.es", "chistes * covid-19 *.es",
					"alarma * covid-19 *.es", "gratitud * covid-19 *.es", "aplausos * covid-19 *.es", "agradecimiento * covid-19 *.es",
					"vacuna * covid-19 *.es", "mortalidad * covid-19 *.es", "muerte * covid-19 *.es"] )

	# Gestionamos otra lista de términos de búsqueda, buscando coronavirus en vez de covid-19
	for term in busquedas:
		new_term = term.replace('covid-19', 'coronavirus')
		busquedas2.append(new_term)

		term_site = term.replace('*.es', 'site:*.es')
		busquedas_site.append(term_site)
		term_site2 = term_site.replace('covid-19', 'coronavirus')
		busquedas2_site.append(term_site2)

	#print(busquedas2)

	"""busquedas2 = np.array( ["*.es", "coronavirus *.es", "crisis * coronavirus *.es", "calma * coronavirus *.es", "esperanza * coronavirus *.es" ,
					"pánico * coronavirus *.es", "miedo * coronavirus *.es", "ansiedad * coronavirus *.es", "terror * coronavirus *.es",
					"inseguridad * coronavirus*.es", "enfado * coronavirus *.es", "rabia * coronavirus *.es", "ira * coronavirus *.es" ,
					"alegría * coronavirus *.es", "tristeza * coronavirus *.es" , "sorpresa * coronavirus *.es", "alivio * coronavirus *.es",
					"desconfianza * coronavirus *.es", "incertidumbre * coronavirus *.es", "sanidad * coronavirus *.es", "aislamiento * coronavirus *.es",
					"cuarentena * coronavirus *.es", "solidaridad * coronavirus *.es", "cooperación * coronavirus *.es", "protección * coronavirus *.es",
					"irresponsable * coronavirus *.es", "polític* * coronavirus *.es", "polític* * irresponsable* * coronavirus *.es", "medic* * coronavirus *.es",
					"cura * coronavirus *.es", "abastecimiento * coronavirus *.es", "alimentos crisis * coronavirus *.es", "alimentos * coronavirus *.es",
					"aislamiento * coronavirus *.es", "memes * coronavirus *.es", "bromas * coronavirus *.es", "chistes * coronavirus *.es",
					"alarma * coronavirus *.es", "gratitud * coronavirus *.es", "aplausos * coronavirus *.es", "agradecimiento * coronavirus *.es",
					"vacuna * coronavirus *.es", "mortalidad * coronavirus *.es", "muerte * coronavirus *.es"] )
	"""

	# REORGANIZAMOS LA LISTA DE BÚSQUEDA PARA AGRUPAR LOS TÉRMINOS EN FUNCION DE POOLSIZE!!!
	init_len = len(busquedas)
	#print(init_len)
	groups = ceil(init_len/POOLSIZE)		# Agrupamos los términos para minimizar los lanzamientos del pool que son costosos

	# EJEMPLO: len(busquedas)=40, POOLSIZE=10, groups=4
	"""		busquedas_groups = np.array_split(busquedas, groups)
	print busquedas_groups		"""

	# Recorremos la lista de búsquedas agrupando por terminos
	for pos in range(0,init_len):
		if pos%groups==0:
			terms = []
			terms2 = []
			terms_site = []
			terms2_site = []
		terms.append(busquedas[pos])
		terms2.append(busquedas2[pos])
		terms_site.append(busquedas_site[pos])
		terms2_site.append(busquedas2_site[pos])
		if pos%groups==(groups-1) or pos==(init_len-1):	# Hemos llenado un grupo de terminos
			busquedas_groups.append(terms)
			busquedas_groups2.append(terms2)
			busquedas_groups_site.append(terms_site)
			busquedas_groups2_site.append(terms2_site)

	# Obtemos el array de búsquedas con subarrays agrupados para mejorar la búsqueda
	#print(busquedas_groups)
	#print(busquedas_groups2)

	"""SECUENCIAL!!"""
	""" Seleccionamos uno a uno los términos a buscar para obtener su número de resultados """
	"""for termino in busquedas:
		res = buscar(termino)
		resultados.append(str(res))
		"""

	"""PARALELO!!!!"""

	#### Finalizada INICIALIZACION, pasamos a busqueda

	executor = ProcessPoolExecutor(POOLSIZE)

	###########################################################################
	#########		ESCRITURA DE DATOS EN FICHEROS		#######################
	###########################################################################

	ahora = datetime.now()

	nombre_dir_clasica = 'Busqueda_'+ str(ahora.day) + "-" + str(ahora.month) + "-" + str(ahora.year) + "CLASICA"
	nombre_dir_nueva = 'Busqueda_'+ str(ahora.day) + "-" + str(ahora.month) + "-" + str(ahora.year) + "NUEVA"

	## Creamos un directorio donde guardar los resultados de las búsquedas
	try:
		os.mkdir(nombre_dir_clasica)
		os.mkdir(nombre_dir_nueva)
	except OSError as e:
		if e.errno != errno.EEXIST:
			raise

	## x:0..2 BUSQUEDA CLÁSICA, x:3..4 BUSQUEDA CON SITE
	for x in range(4):
		if x==0:		# primera busqueda con busquedas_groups con covid-19
			busq = busquedas_groups
			name = "covid-19_"
			search = busquedas
		elif x==1:			# segunda busqueda con busquedas_groups2 con coronavirus
			busq = busquedas_groups2
			name = "coronavirus_"
			search = busquedas2
		elif x==2:			# tercera busqueda con busquedas_groups_site con covid-19
			busq = busquedas_groups_site
			name = "covid-19_"
			search = busquedas_site
		elif x==3:			# cuarta busqueda con busquedas_groups2_site con coronavirus
			busq = busquedas_groups2_site
			name = "coronavirus_"
			search = busquedas2_site
		else:
			print("ERROR switch de las 4 busquedas")

		resultados = []

		## Inicio TIME
		start_time = time.time()

		######		LANZAMOS LOS HILOS DE BUSQUEDAS 		######

		#timeout=None, chunksize=1000
		resultados_groups = list(executor.map(buscar, busq))

		## Tiempo de busqueda
		busqueda_time = time.time() - start_time
		busqueda_time = round(busqueda_time,2)

		for arr in resultados_groups:
			for res in arr:
				resultados.append(res)

		print("\n\nResultados: " + str(resultados))
		ahora = datetime.now()

		""" Escribimos en un fichero BUSQUEDA *.es: NUMERO DE RESULTADOS: 500"""
		if x<2:		# BUSQUEDAS CLÁSICAS
			nombre_dir = nombre_dir_clasica
			nombre_file = nombre_dir + "/" + name + "CLASICO_" + str(ahora.day) + "-" + str(ahora.month) + "-" + str(ahora.year) + "_v3" + ".txt"
		else:
			nombre_dir = nombre_dir_nueva
			nombre_file = nombre_dir + "/" + name + "NUEVA_" + str(ahora.day) + "-" + str(ahora.month) + "-" + str(ahora.year) + "_v3" + ".txt"

		"""if (ahora.hour < 14 and ahora.hour > 2):
			nombre += " Morning" + ".txt"
		else:
			nombre += " Noche" + ".txt"
		"""

		print(nombre_file)
		print("\n\nVIENE ESCRITURA!!!")
		## ESCRIBIMOS LOS FICHEROS
		f = open(nombre_file, "w+")
		f.write("***\tBuscador v3.2 \t Archivo con el número de resultados obtenidos por término de búsqueda en GOOGLE\t***")
		f.write("\n***\tFECHA: " + str(ahora) + "\t***\n\n")
		f.write("TÉRMINO DE BÚSQUEDA\t\tNÚMERO APROXIMADO DE RESULTADOS\n")

		for j in range(0, len(resultados)):
			linea = "\n" + search[j] + "\t\t" + str(resultados[j])
			f.write(linea)

		f.write("\n\nTIEMPO DE BUSQUEDA(en segundos): " + str(busqueda_time))

		f.close()

	# Cierra todas las ventanas de búsqueda y finaliza correctamente la sesión WebDriver
	driver.quit()

### FUNCION QUE RECIBE UNA LISTA DE TÉRMINOS Y LOS BUSCA EN GOOGLE
def buscar(terminos):

	#global driver

	res = []

	###### CONFIGURACIÓN DEL DRIVER ######

	""" LINEAS PARA DESHABILITAR EL CONTROL DE GOOGLE: "Chrome is being controlled by automated test software" """
	chrome_options = webdriver.ChromeOptions();
	chrome_options.add_argument('--headless');		# EJECUCION EN BACKGROUND
	# To fix execution in script
	chrome_options.add_argument('--no-sandbox');
	chrome_options.add_argument('--disable-dev-shm-usage');
	##

	chrome_options.add_experimental_option("excludeSwitches", ['enable-automation', 'disable-infobars']);

	driver = webdriver.Chrome(ChromeDriverManager().install(), options=chrome_options );
	# , service_args=['--verbose', '--log-path=/tmp/chromedriver.log'] )

	## BUSCAMOS LOS TÉRMINOS
	for termino in terminos:
		""" Creamos el link de búsqueda con el término correspondiente """
		## v3.2 CAMBIO A google.es!!!!
		link = "https://www.google.es/search?q=" + termino
		print("\n" + link)

		""" Establecemos un tiempo entre las búsquedas para evitar CAPTCHA de Google """
		## NOTA: (cambiar IP????) ###################
		wait = random()*2
		time.sleep(wait)

		""" Abrimos la URL con la búsqueda """
		""" CDE PARA EVITAR FALLO DE CONEXIONES!!!! """
		try:
			driver.get(link)
		except requests.exceptions.ConnectionError:
			buscar(terminos)		# Retry

		""" Buscamos por tags, en nuestro caso, queremos buscar el tag con <div id="result-stats"> """
		content = driver.page_source
		soup = BeautifulSoup(content, "lxml")
		RESULT = soup.find(id ="result-stats")

		""" Obtenemos del texto el número de resultados """
		resu = str(RESULT)
		print("\nRESULT: " + resu)

		""" buscamos el numero de resultados por la cadena de Aproximadamente """
		iniIndex = resu.find("Aproximadamente")
		""" Situamos el indice despues de Aproximadamente, donde va el numero """
		iniIndex += 16
		endIndex = resu.find("resultados")
		num = resu[iniIndex:endIndex]
		#print(num)
		res.append(str(num))

	""" Cerramos la pestaña abierta """
	driver.close()

	""" Devolvemos el número de resultados de buscar el termino """
	return res

if __name__ == '__main__':
	main()


from django.core.management.base import BaseCommand
import csv
from Kick.models import Kickstarter_camp

class Command(BaseCommand):

    def add_arguments(self, parser):
        parser.add_argument('path', help='Path to CSV')

    def handle(self, *args, **kwargs):
        path = kwargs['path']
        with open(path, encoding="utf8") as csv_file:
            info = csv.reader(csv_file, delimiter=',')
            line = 0
            for row in info:
                if line != 0:
                    data = Kickstarter_camp.objects.create(
                        backers_count = int(row[0]),
                        blurb = row[1],
                        goal = row[11],
                        pledged = row[17])
                line += 1


from typing import Sequence, Tuple, Union
from dataclasses import dataclass
from scipy.integrate import odeint

import numpy as np
import logging

from dno.environment import EnvironmentModel

_logger = logging.getLogger(f'windy.model.{__name__}')

@dataclass
class WindyModel:
    v0: float
    pos0: np.array
    alpha: float
    mass: float

    env: EnvironmentModel
    verbose: Union[bool, int] = False

    v: np.ndarray = None
    run_time: float = None
    pos: np.ndarray = None

    @dataclass
    class ModelState:
        v: np.array
        pos: np.array
        time: float

    def __post_init__(self):
        self._log = logging.getLogger(f'{__name__}.{self.__class__.__name__}[{id(self)}]')
        if isinstance(self.verbose, bool):
            self.verbose = logging.DEBUG if self.verbose else logging.CRITICAL
        self._log.setLevel(logging.getLevelName(self.verbose))
        self.alpha = np.deg2rad(self.alpha)
        self.v0 = np.array([self.v0 * np.cos(self.alpha), 0, self.v0 * np.sin(self.alpha)])
        self.reset()

    def reset(self):
        self.v = self.v0
        self.pos = self.pos0
        self.run_time = 0

    # function that returns dy/dt
    def velocity_model(self, v: np.ndarray, time: np.ndarray):
        v_mod = np.linalg.norm(v)
        dvdt = np.array([
            -self.env.aerodynamic_coef.value / self.mass * v[0] * v_mod,
            -self.env.aerodynamic_coef.value / self.mass * v[1] * v_mod - self.env.g,
            -self.env.aerodynamic_coef.value / self.mass * v[2] * v_mod,
        ])
        return dvdt.ravel()

    def position_model(self, state: np.ndarray, time: np.ndarray):
        v = state[:3]
        v_mod = np.linalg.norm(v)
        dvdt = np.array([
            -self.env.aerodynamic_coef.value / self.mass * v[0] * v_mod,
            -self.env.aerodynamic_coef.value / self.mass * v[1] * v_mod - self.env.g,
            -self.env.aerodynamic_coef.value / self.mass * v[2] * v_mod,
        ]).ravel()
        print(dvdt)
        drdt = state[:3]
        print(drdt)
        dalldt = np.hstack((dvdt, drdt))
        return dalldt

    def position_model_alt(self, state: np.ndarray, time: np.ndarray):
        v = state[:3]
        v_mod = np.linalg.norm(v)
        dvdt = np.array([
            -self.env.aerodynamic_coef.value / self.mass * v[0] * v_mod,
            -self.env.aerodynamic_coef.value / self.mass * v[1] * v_mod - self.env.g,
            -self.env.aerodynamic_coef.value / self.mass * v[2] * v_mod,
        ]).ravel()
        drdt = state[:3] + self.env.winds.predict(state[4])
        dalldt = np.hstack((dvdt, drdt))
        return dalldt

    def solve_velocities(self, time: np.ndarray):
        return odeint(self.velocity_model, self.v0, time)

    def solve_positions(self, time: np.ndarray, wind: np.ndarray, v0: np.ndarray, pos0: np.ndarray):
        return odeint(self.position_model, np.hstack((np.asarray(v0) + np.asarray(wind), pos0)), time)

    def solve_positions_alt(self, time: np.ndarray, v0: np.ndarray, pos0: np.ndarray):
        return odeint(self.position_model_alt, np.hstack((np.asarray(v0), pos0)), time)

    def solve(self, target: np.ndarray):
        state = np.hstack((self.v0, self.pos0))
        last_state_stack = np.array((state, ))
        t_start = 0
        while state[4] > target[1]:
            t = np.linspace(t_start, t_start + 1, num=10)
            last_state_stack = self.solve_positions_alt(t, v0=state[:3], pos0=state[3:])
            state = last_state_stack[-1]
            t_start += 1
        starting_point = self.offset_for_target(target, state[3:])
        return starting_point

    @property
    def current_wind(self) -> np.array:
        return self.env.winds.predict(self.pos[1])

    @property
    def aerodynamic_acc(self) -> np.array:
        return -self.v * np.linalg.norm(self.v) * self.env.aerodynamic_coef.value / self.mass

    def step(self, dt: float):
        self._log.debug(f"Current position: {self.pos[1]:.2f}m above ground.")
        self._log.debug(f"Aerodynamic acc: {self.aerodynamic_acc}")
        self._log.debug(f"Winds: {self.current_wind}")
        self.v = np.asarray(self.v) + self.aerodynamic_acc * dt + dt * np.array([0, -self.env.g, 0])
        self._log.debug(f"Object's speed is: {self.v}")
        v_eff = self.current_wind + self.v
        self._log.debug(f"Effective speed is: {v_eff}")
        self.pos = self.pos + np.asarray(v_eff) * dt
        self._log.debug(f"Position is: {self.pos}")
        self.run_time += dt

    def offset_for_target(self, target: np.ndarray, position: np.ndarray) -> np.ndarray:
        drop_point = target - position + 2 * np.array(self.pos0)
        drop_point[1] = self.pos0[1]
        return drop_point

    def predict(self, target: np.ndarray, reset: bool = True, **run_kwargs) -> np.ndarray:
        if reset:
            self.reset()
        self.run(**run_kwargs)
        starting_point = self.offset_for_target(target, self.pos)
        return starting_point

    def score(self, starting_point: np.array, destination_point: np.array, reset: bool = True, **run_kwargs) -> Tuple[
        np.ndarray, float]:
        saved_pos0 = self.pos0
        try:
            self.pos0 = starting_point
            if reset:
                self.reset()
            self.run(**run_kwargs)
            landing_point = self.state.pos
            landing_point[1] = destination_point[1]
            return landing_point, np.linalg.norm(landing_point - destination_point)
        except Exception as e:
            self.pos0 = saved_pos0
            raise e
        finally:
            self.pos0 = saved_pos0

    @property
    def state(self) -> 'ModelState':
        return self.ModelState(v=self.v, pos=self.pos, time=self.run_time)

    def run(self, max_steps: int = None, dt: float = 0.01) -> Sequence['ModelState']:
        step = 0
        states = []
        while self.pos[1] > 0 and (max_steps is None or step < max_steps):
            self.step(dt)
            step += 1
            states.append(self.state)
            self._log.debug(f"State is: {self.state}")
        self._log.info(f"Final state is: {self.state}")
        if max_steps is not None and step >= max_steps:
            self._log.warning(f"WARN: stopped after maximum iterations: {step}")
        return states


from flask import Flask, render_template, request, redirect, flash
from werkzeug.utils import secure_filename
from main import getPrediction
import os

UPLOAD_FOLDER = 'static/images/'
app = Flask(__name__, static_folder="static")
app.secret_key = "secret key"
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER

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

@app.route('/predict', methods=['POST', 'GET'])
def submit_file():
    if request.method == 'POST':
        file = request.files['file']
        filename = secure_filename(file.filename)
        file.save(os.path.join(app.config['UPLOAD_FOLDER'],filename))
        class_label = getPrediction(filename)
        return "{}".format(class_label)
    return None

if __name__ == '__main__':
    port = int(os.environ.get('PORT', 5000))
    app.run(host='0.0.0.0', port=port)