"""
aoe2netwrapper.converters
-------------------------

This module implements a high-level class with static methods to convert result of AoENetAPI methods to
pandas DataFrames.
"""
from typing import List

from loguru import logger

from aoe2netwrapper.models import (
    LastMatchResponse,
    LeaderBoardResponse,
    MatchLobby,
    NumOnlineResponse,
    RatingTimePoint,
    StringsResponse,
)

try:
    import pandas as pd
except ImportError as error:
    logger.error(
        "User tried to use the 'converters' submodule without havinig installed the 'pandas' library."
    )
    raise NotImplementedError(
        "The 'aoe2netwrapper.converters' module exports results to 'pandas.DataFrame' objects and "
        "needs the 'pandas' library installed to function."
    ) from error

class Convert:
    """
    This is a convenience class providing methods to convert the outputs from the AoE2NetAPI query methods
    into pandas DataFrame objects. Every method below is a staticmethod, so no object has to be instantiated.
    """

    @staticmethod
    def strings(strings_response: StringsResponse) -> pd.DataFrame:
        """
        Convert the result given by a call to AoE2NetAPI().strings to a pandas DataFrame.

        Args:
            strings_response (StringsResponse): the response directly returned by your AoE2NetAPI
                client.

        Returns:
            A pandas DataFrame from the StringsResponse, each column being the values for a 'string' used
            by the API, and the index being the ID numbers. Since this is the result of a join for many
            'strings' that do not have the same amount of values, the resulting dataframe will contain NaNs
            wherever a given 'string' does not have a value for the given index ID.
        """
        if not isinstance(strings_response, StringsResponse):
            logger.error("Tried to use method with a parameter of type != StringsResponse")
            raise TypeError("Provided parameter should be an instance of 'StringsResponse'")

        logger.debug("Converting StringsResponse to DataFrame")
        dframe = pd.DataFrame(strings_response).transpose()
        dframe.columns = dframe.iloc[0]
        dframe = dframe.drop(index=[0]).reset_index(drop=True)
        dframe = dframe.drop(columns=["language"])

        logger.trace("Exporting each string attribute to its own dataframe and joining")
        result = pd.DataFrame()
        for col in dframe.columns:
            intermediate = pd.DataFrame()
            intermediate[col] = dframe[col][0]
            intermediate["id"] = intermediate[col].apply(lambda x: x.id)
            intermediate[col] = intermediate[col].apply(lambda x: x.string)
            result = result.join(intermediate.set_index("id"), how="outer")

        return result

    @staticmethod
    def leaderboard(leaderboard_response: LeaderBoardResponse) -> pd.DataFrame:
        """
        Convert the result given by a call to AoE2NetAPI().leaderboard to a pandas DataFrame.

        Args:
            leaderboard_response (LeaderBoardResponse): the response directly returned by your AoE2NetAPI
                client.

        Returns:
            A pandas DataFrame from the LeaderBoardResponse, each row being an entry in the leaderboard.
            Top level attributes such as 'start' or 'total' are broadcast to an entire array the size of
            the dataframe, and timestamps are converted to datetime objects.
        """
        if not isinstance(leaderboard_response, LeaderBoardResponse):
            logger.error("Tried to use method with a parameter of type != LeaderBoardResponse")
            raise TypeError("Provided parameter should be an instance of 'LeaderBoardResponse'")

        logger.debug("Converting LeaderBoardResponse leaderboard to DataFrame")
        dframe = pd.DataFrame(leaderboard_response.leaderboard)
        dframe = _export_tuple_elements_to_column_values_format(dframe)

        logger.trace("Inserting LeaderBoardResponse attributes as columns")
        dframe["leaderboard_id"] = leaderboard_response.leaderboard_id
        dframe["start"] = leaderboard_response.start
        dframe["count"] = leaderboard_response.count
        dframe["total"] = leaderboard_response.total

        logger.trace("Converting datetimes")
        dframe["last_match"] = pd.to_datetime(dframe["last_match"], unit="s")
        dframe["last_match_time"] = pd.to_datetime(dframe["last_match_time"], unit="s")
        return dframe

    @staticmethod
    def lobbies(lobbies_response: List[MatchLobby]) -> pd.DataFrame:
        """
        Convert the result given by a call to AoE2NetAPI().lobbies to a pandas DataFrame. The resulting
        DataFrame will contain several rows for each lobby, namely as many as there are players in said
        lobby. All global attributes of each lobby are broadcasted to arrays, making them duplicates.

        To isolate a specific lobby, either call the AoE2NetAPI().match method with the lobby's UUID or
        make use of the groupby functionality of pandas DataFrames.

        Args:
            lobbies_response (List[MatchLobby]): the response directly returned by your AoE2NetAPI
                client.

        Returns:
            A pandas DataFrame from the list of MatchLobby elements..
        """
        if not isinstance(lobbies_response, list):  # move list to List[MatchLobby] when supporting > 3.9
            logger.error("Tried to use method with a parameter of type != List[MatchLobby]")
            raise TypeError("Provided parameter should be an instance of 'List[MatchLobby]'")

        logger.debug("Converting Lobbies response to DataFrame")
        unfolded_lobbies = [_unfold_match_lobby_to_dataframe(match_lobby) for match_lobby in lobbies_response]
        return pd.concat(unfolded_lobbies).reset_index(drop=True)

    @staticmethod
    def last_match(last_match_response: LastMatchResponse) -> pd.DataFrame:
        """
        Convert the result given by a call to AoE2NetAPI().last_match to a pandas DataFrame. There is not
        much use to this as the DataFrame will only have one row, but the method is provided nonetheless in
        case users want to concatenate several of these results in a DataFrame.

        Args:
            last_match_response (LastMatchResponse): the response directly returned by your AoE2NetAPI
                client.

        Returns:
            A pandas DataFrame from the list of LastMatchResponse attributes. Beware: the 'players'
            column is directly the content of the 'LastMatchResponse.last_match.players' attribute and as
            such holds a list of LobbyMember objects.
        """
        if not isinstance(last_match_response, LastMatchResponse):
            logger.error("Tried to use method with a parameter of type != LastMatchResponse")
            raise TypeError("Provided parameter should be an instance of 'LastMatchResponse'")

        logger.debug("Converting LastMatchResponse last_match to DataFrame")
        dframe = pd.DataFrame(last_match_response.last_match).transpose()
        dframe.columns = dframe.iloc[0]
        dframe = dframe.drop(0).reset_index()

        logger.trace("Inserting LastMatchResponse attributes as columns")
        dframe["profile_id"] = last_match_response.profile_id
        dframe["steam_id"] = last_match_response.steam_id
        dframe["name"] = last_match_response.name
        dframe["country"] = last_match_response.country
        return dframe

    @staticmethod
    def match_history(match_history_response: List[MatchLobby]) -> pd.DataFrame:
        """
        Convert the result given by a call to AoE2NetAPI().match_history to a pandas DataFrame. The resulting
        DataFrame will contain several rows for each lobby, namely as many as there are players in said
        lobby. All global attributes of each lobby are broadcasted to arrays, making them duplicates.

        To isolate a specific lobby, either call the AoE2NetAPI().match method with the lobby's UUID or
        make use of the groupby functionality of pandas DataFrames.

        Args:
            match_history_response (List[MatchLobby]): the response directly returned by your AoE2NetAPI
                client.

        Returns:
            A pandas DataFrame from the list of MatchLobby elements.
        """
        # move list to List[MatchLobby] when supporting > 3.9
        if not isinstance(match_history_response, list):
            logger.error("Tried to use method with a parameter of type != List[MatchLobby]")
            raise TypeError("Provided parameter should be an instance of 'List[MatchLobby]'")

        logger.debug("Converting Match History response to DataFrame")
        unfolded_lobbies = [
            _unfold_match_lobby_to_dataframe(match_lobby) for match_lobby in match_history_response
        ]
        return pd.concat(unfolded_lobbies).reset_index(drop=True)

    @staticmethod
    def rating_history(rating_history_response: List[RatingTimePoint]) -> pd.DataFrame:
        """
        Convert the result given by a call to AoE2NetAPI().leaderboard to a pandas DataFrame.

        Args:
            rating_history_response (List[RatingTimePoint]): the response directly returned by your AoE2NetAPI
                client.

        Returns:
            A pandas DataFrame from the list of RatingTimePoint elements, each row being the information from
            one RatingTimePoint in the list. Timestamps are converted to datetime objects.
        """
        # move list to List[RatingTimePoint] when supporting > 3.9
        if not isinstance(rating_history_response, list):
            logger.error("Tried to use method with a parameter of type != List[RatingTimePoint]")
            raise TypeError("Provided parameter should be an instance of 'List[RatingTimePoint]'")

        logger.debug("Converting Rating History rsponse to DataFrame")
        dframe = pd.DataFrame(rating_history_response)
        dframe = _export_tuple_elements_to_column_values_format(dframe)

        logger.trace("Converting timestamps to datetime objects")
        dframe["time"] = pd.to_datetime(dframe["timestamp"], unit="s")
        dframe = dframe.drop(columns=["timestamp"])
        return dframe

    @staticmethod
    def matches(matches_response: List[MatchLobby]) -> pd.DataFrame:
        """
        Convert the result given by a call to AoE2NetAPI().match_history to a pandas DataFrame. The resulting
        DataFrame will contain several rows for each lobby, namely as many as there are players in said
        lobby. All global attributes of each lobby are broadcasted to arrays, making them duplicates.

        To isolate a specific lobby, either call the AoE2NetAPI().match method with the lobby's UUID or
        make use of the groupby functionality of pandas DataFrames.

        Args:
            matches_response (List[MatchLobby]): the response directly returned by your AoE2NetAPI
                client.

        Returns:
            A pandas DataFrame from the list of MatchLobby elements.
        """
        if not isinstance(matches_response, list):  # move list to List[MatchLobby] when supporting > 3.9
            logger.error("Tried to use method with a parameter of type != List[MatchLobby]")
            raise TypeError("Provided parameter should be an instance of 'List[MatchLobby]'")

        logger.debug("Converting Match History response to DataFrame")
        unfolded_lobbies = [_unfold_match_lobby_to_dataframe(match_lobby) for match_lobby in matches_response]
        return pd.concat(unfolded_lobbies).reset_index(drop=True)

    @staticmethod
    def match(match_response: MatchLobby) -> pd.DataFrame:
        """
        Convert the content of a MatchLobby to a pandas DataFrame. The resulting DataFrame will have as many
        rows as there are players in the lobby, and all global attributes will be broadcasted to columns of
        the same length, making them duplicates.

        Args:
            match_response (MatchLobby): a MatchLobby object.

        Returns:
            A pandas DataFrame from the MatchLobby attributes, each row being global information from the
            MatchLobby as well as one of the players in the lobby.
        """
        return _unfold_match_lobby_to_dataframe(match_response)

    @staticmethod
    def num_online(num_online_response: NumOnlineResponse) -> pd.DataFrame:
        """
        Convert the result given by a call to AoE2NetAPI().num_online to a pandas DataFrame.

        Args:
            num_online_response (NumOnlineResponse): the response directly returned by your AoE2NetAPI
                client.

        Returns:
            A pandas DataFrame from the NumOnlineResponse, each row being an entry in the leaderboard.
            Top level attributes such as 'app_id' are broadcast to an entire array the size of the
            dataframe, and timestamps are converted to datetime objects.
        """
        if not isinstance(num_online_response, NumOnlineResponse):
            logger.error("Tried to use method with a parameter of type != NumOnlineResponse")
            raise TypeError("Provided parameter should be an instance of 'NumOnlineResponse'")

        logger.debug("Converting NumOnlineResponse to DataFrame")
        dframe = pd.DataFrame(num_online_response.dict())

        logger.trace("Exporting 'player_stats' attribute contents to columns")
        dframe["time"] = dframe.player_stats.apply(lambda x: x["time"]).apply(pd.to_datetime)
        dframe["steam"] = dframe.player_stats.apply(lambda x: x["num_players"]["steam"])
        dframe["looking"] = dframe.player_stats.apply(lambda x: x["num_players"]["looking"])
        dframe["in_game"] = dframe.player_stats.apply(lambda x: x["num_players"]["in_game"])
        dframe["multiplayer"] = dframe.player_stats.apply(lambda x: x["num_players"]["multiplayer"])
        dframe["multiplayer_1h"] = dframe.player_stats.apply(lambda x: x["num_players"]["multiplayer_1h"])
        dframe["multiplayer_24h"] = dframe.player_stats.apply(lambda x: x["num_players"]["multiplayer_24h"])

        logger.trace("Removing 'player_stats' column to avoid nested & duplicate data")
        dframe = dframe.drop(columns=["player_stats"])
        return dframe

# ----- Helpers ----- #

def _export_tuple_elements_to_column_values_format(dataframe: pd.DataFrame) -> pd.DataFrame:
    """
    Take in a pandas DataFrame with simple int values as columns, and elements being a tuple of
    (attribute_name, value) and cast it to have the attribute_name as column names, and the values as values.
    The original columns will be dropped in the process.

    Args:
        dataframe (pd.DataFrame): your pandas DataFrame.

    Returns:
        The refactored pandas DataFrame.
    """
    dframe = dataframe.copy(deep=True)
    logger.trace("Exporting attributes to columns and removing duplicate data")
    for _, col_index in enumerate(dframe.columns):
        attribute = dframe[col_index][0][0]
        dframe[attribute] = dframe[col_index].apply(lambda x: x[1])
        dframe = dframe.drop(columns=[col_index])
    return dframe

def _unfold_match_lobby_to_dataframe(match_lobby: MatchLobby) -> pd.DataFrame:
    """
    Convert the content of a MatchLobby to a pandas DataFrame. The resulting DataFrame will have as many
    rows as there are players in the lobby, and all global attributes will be broadcasted to columns of the
    same length, making them duplicates.

    Args:
        match_lobby (MatchLobby): a MatchLobby object.

    Returns:
        A pandas DataFrame from the MatchLobby attributes, each row being global information from the
        MatchLobby as well as one of the players in the lobby.
    """
    if not isinstance(match_lobby, MatchLobby):
        logger.error("Tried to use method with a parameter of type != MatchLobby")
        raise TypeError("Provided parameter should be an instance of 'MatchLobby'")

    logger.trace("Unfolding MatchLobby.players contents to DataFrame")
    dframe = pd.DataFrame(match_lobby.players)
    dframe = _export_tuple_elements_to_column_values_format(dframe)
    dframe = dframe.rename(columns={"name": "player"})

    logger.trace("Broadcasting global MatchLobby attributes")
    attributes_df = pd.DataFrame()
    for attribute, value in match_lobby.dict().items():
        if attribute != "players":
            attributes_df[attribute] = [value] * len(dframe)
    dframe = attributes_df.join(dframe, how="outer")

    logger.trace("Converting timestamps to datetime objects")
    dframe["opened"] = pd.to_datetime(dframe["opened"], unit="s")
    dframe["started"] = pd.to_datetime(dframe["started"], unit="s")
    dframe["finished"] = pd.to_datetime(dframe["finished"], unit="s")

    return dframe


from __future__ import print_function

import logging
import os
import random
import time
import signal

from relaax.client import rlx_client

from . import game_process

def run(rlx_server_url, env, seed):
    n_game = 0
    game = game_process.GameProcessFactory(env).new_env(_seed(seed))

    def toggle_rendering():
        if game.display:
            game._close_display = True
        else:
            game.display = True
            game._close_display = False

    signal.signal(signal.SIGUSR1, lambda _1, _2: toggle_rendering())
    signal.siginterrupt(signal.SIGUSR1, False)

    while True:
        try:
            client = rlx_client.Client(rlx_server_url)
            try:
                action = client.init(game.state())
                while True:
                    reward, reset = game.act(action)
                    if reset:
                        episode_score = client.reset(reward)
                        n_game += 1
                        print('Score at game', n_game, '=', episode_score)
                        game.reset()
                        action = _send(client, None, game.state())
                    else:
                        action = _send(client, reward, game.state())
            finally:
                client.disconnect()
        except rlx_client.Failure as e:
            _warning('{} : {}'.format(rlx_server_url, e.message))
            delay = random.randint(1, 10)
            _info('waiting for %ds...', delay)
            time.sleep(delay)

def _send(client, reward, state):
    start = time.time()
    action = client.send(reward, state)
    client.metrics().scalar('client latency', time.time() - start)
    return action

def _seed(value):
    if value is None:
        return random.randrange(1000000)
    return value

def _info(message, *args):
    logging.info('%d:' + message, os.getpid(), *args)

def _warning(message, *args):
    logging.warning('%d:' + message, os.getpid(), *args)


import logging

from django.conf import settings
from sqlalchemy.exc import OperationalError

from receval.apps.explorer.experiments import BaseExperiment
from sqlalchemy import create_engine
from sqlalchemy.sql import text

logger = logging.getLogger(__name__)

class ZbMath(BaseExperiment):
    db = None

    def get_db(self):
        if not self.db:
            if not settings.ZBMATH_DATABASE_URL:
                raise ValueError('ZBMATH_DATABASE_URL is not set!')

            conn_string = settings.ZBMATH_DATABASE_URL
            logger.info(f'ZB MATH database: {conn_string}')

            if settings.ZBMATH_SSL_CERT and settings.ZBMATH_SSL_KEY and settings.ZBMATH_SSL_ROOTCERT:
                conn_args = {
                    # "sslmode": "verify-full",
                    "sslcert": settings.ZBMATH_SSL_CERT,
                    "sslkey": settings.ZBMATH_SSL_KEY,
                    "sslrootcert": settings.ZBMATH_SSL_ROOTCERT,
                }

                logger.info(f'SSL connection: {conn_args}')
            else:
                conn_args = {}

            try:
                self.db = create_engine(conn_string, connect_args=conn_args)
            except OperationalError:
                # try again
                self.db = create_engine(conn_string, connect_args=conn_args)

        return self.db

    def get_item_data(self, doc_id=None, zbl_id=None) -> dict:

        if doc_id:
            s = text("""SELECT * FROM zbmath.math_documents WHERE id = :doc_id""")
        elif zbl_id:
            s = text("""SELECT * FROM zbmath.math_documents WHERE zbl_id = :zbl_id""")
        else:
            raise ValueError('Either doc_id or zbl_id must be set')

        res = self.get_db().execute(s, doc_id=doc_id, zbl_id=zbl_id)
        rows = [dict(row) for row in res]

        if len(rows) == 1:

            data = rows[0]

            # Get text
            s = text("""SELECT text FROM zbmath.math_reviews WHERE document = :doc_id LIMIT 1""")
            res = self.get_db().execute(s, doc_id=data['id'])

            rows = [dict(row) for row in res]

            if len(rows) == 1:
                data['text'] = rows[0]['text']
            else:
                raise ValueError('Invalid number of rows returned')

            # Citation count
            s = text("""SELECT COUNT(*) FROM zbmath.math_references WHERE zbl_id = :zbl_id""")
            res = self.get_db().execute(s, zbl_id=data['zbl_id'])

            rows = [dict(row) for row in res]

            if len(rows) == 1:
                data['citation_count'] = rows[0]['count']
            else:
                raise ValueError('Invalid number of rows returned')

            return data
        else:
            raise ValueError('Invalid number of rows returned')


from django.urls import path
from . import views

urlpatterns = [
    path('', views.index),
    path('books', views.books),
    path('register', views.register),
    path('login', views.login),
    path('logout', views.logout),
    path('books/add', views.addBook),
    path('submitBook', views.submitBook),
    path('books/<int:bookID>', views.bookPage),
    path('submitReview/<int:bookID>', views.submitReview),
    path('users/<int:userID>', views.userPage),
    path('delete/<int:reviewID>', views.deleteReview)
]


import os
import re
import tkinter as tk
from os import path as op
from tkinter import filedialog as fd
from tkinter import messagebox as mb

def is_num(data):
    """判断字符串是否为数字"""
    try:
        int(data)
        return True
    except:
        return False

def go_split(s, symbol):
    # 拼接正则表达式
    symbol = "[" + symbol + "]+"
    # 一次性分割字符串
    result = re.split(symbol, s)
    # 去除空字符
    return [x for x in result if x]

def takeSecond(elem):
    return elem[1]

class HFileRenamer:
    def __init__(self):
        root = tk.Tk()
        root.withdraw()
        self.root_path = None
        self.routes = []
        self.keys = {}
        self.change_root()

    def change_root(self):
        """选择目标路径"""
        mb.showinfo("", "请选择目标根目录")
        self.root_path = op.abspath(fd.askdirectory())

    def __rename_h_dir(self, p_path):
        c_paths = os.listdir(p_path)
        for c_path in c_paths:
            n_path = op.join(p_path, c_path)

    def __rename_file(self, f_path):
        print(op.basename(f_path))

    def __judge_root(self, r_path):
        c_paths = os.listdir(r_path)
        if 'root.info' in c_paths:
            c_paths.remove('root.info')
            root_info = open(op.join(r_path, 'root.info'), 'r+', encoding='utf-8')
            routes = root_info.read().split('\n')
            for c_path in c_paths:
                c_path = op.join(r_path, c_path)
                if c_path in routes:
                    self.__judge_root(c_path)
                else:
                    if op.isdir(c_path):
                        self.__rename_h_dir(c_path)
                    else:
                        self.__rename_file(c_path)

    def get_route(self):
        self.routes = []
        self.__get_route_(self.root_path)
        self.routes.sort()
        route_memo = open(op.join(self.root_path, "route_memo.info"), 'w+', encoding='utf-8')
        for route in self.routes:
            route_memo.write(route + '\n')
        route_memo.close()
        kk = []
        for key in self.keys.keys():
            kk.append([key, self.keys[key]])
        kk.sort(reverse=True, key=takeSecond)
        for k in kk:
            print(k[0], k[1])

    def __get_route_(self, p_path):
        c_paths = os.listdir(p_path)
        for c_path in c_paths:
            keys = go_split(c_path, ' 　_.()【】\n')
            for key in keys:
                if is_num(key):
                    key = int(key)
                if key in self.keys:
                    self.keys[key] = self.keys[key] + 1
                else:
                    self.keys[key] = 1
            c_path = op.join(p_path, c_path)
            if op.isdir(c_path):
                self.__get_route_(c_path)
            self.routes.append(c_path)

    def main(self):
        self.__judge_root(self.root_path)

if __name__ == '__main__':
    copier = HFileRenamer()
    copier.get_route()


# This code converts integer to string without using the str() function

# by using the % and //
# 123 %10 gives 3
# 123 // 10 gives 12

def convert_to_string(input_int):
    # if input_int.isalpha():
    #     return 'requires an integer value'
    if input_int < 0:
        isNegative = True  # to catch the neegative number
        input_int *= -1
    else:
        isNegative = False
    output_str = []
    while input_int > 0:
        x = input_int % 10  # get the last number
        result = chr(ord('0') + x)  # convert it to string
        output_str.append(result)
        input_int //= 10  # this divides by 10 and remove the remaineder i.e automatically removes the last element because its in base 10
    output_str = output_str[::-1]  # reverse the list
    if isNegative:
        return '-' + ''.join(output_str)
    else:
        return ''.join(output_str)

input_int = 666
print(convert_to_string(input_int))
print(type(input_int))

output_str = convert_to_string(123)
print(type(output_str))


import os

from qgis.PyQt.QtCore import Qt, QTimer
from qgis.gui import QgsRubberBand

from qgis.core import (
    QgsCoordinateTransform,
    QgsRectangle,
    QgsPoint,
    QgsPointXY,
    QgsGeometry,
    QgsWkbTypes,
    QgsProject,
)
from qgis.PyQt import QtWidgets, uic
from qgis.PyQt.QtCore import pyqtSignal
from qgis.utils import iface

# using utils
from .utils import icon, parse_raw_coordinate,dialogBox

FORM_CLASS, _ = uic.loadUiType(os.path.join(os.path.dirname(__file__), "../ui/goto.ui"))

class GotoXYDialog(QtWidgets.QDialog, FORM_CLASS):
    """Dialog for Zoom to Location"""

    closingPlugin = pyqtSignal()

    def __init__(self, parent=iface.mainWindow()):
        self.iface = iface
        self.canvas = iface.mapCanvas()
        super(GotoXYDialog, self).__init__(parent)
        # self.utils = Utilities
        self.crossRb = QgsRubberBand(self.canvas, QgsWkbTypes.LineGeometry)
        self.crossRb.setColor(Qt.red)
        self.setWindowIcon(icon("icon.png"))

        self._currentcrs = None

        self.setupUi(self)
        self.cariLokasi.clicked.connect(self.zoomtodialog)
        self.selectProj.crsChanged.connect(self.set_crs)

    def closeEvent(self, event):
        self.closingPlugin.emit()
        event.accept()

    def set_crs(self):
        self._currentcrs = self.selectProj.crs()
        # print(self._currentcrs.description())

    def parse_coordinate(self):
        coordinate_text = self.mLineEditXY.text()
        points = parse_raw_coordinate(coordinate_text)
        first_point = next(points)
        return first_point

    def zoomtodialog(self):
        try:
            point = self.parse_coordinate()
        except Exception as e:
            return
        lon = point.x()
        lat = point.y()
        self.zoomTo(self._currentcrs, lat, lon)

    def zoomTo(self, src_crs, lat, lon):
        self.canvas.zoomScale(1000)
        canvas_crs = self.canvas.mapSettings().destinationCrs()
        transform = QgsCoordinateTransform(src_crs, canvas_crs, QgsProject.instance())

        try:
            x, y = transform.transform(float(lon), float(lat))
        except Exception as e:
            dialogBox("Kesalahan input koordinat. Periksa urutan x dan y data masukan")
            return

        rect = QgsRectangle(x, y, x, y)
        self.canvas.setExtent(rect)

        pt = QgsPointXY(x, y)
        self.highlight(pt)
        self.canvas.refresh()

    def highlight(self, point):

        currExt = self.canvas.extent()

        leftPt = QgsPoint(currExt.xMinimum(), point.y())
        rightPt = QgsPoint(currExt.xMaximum(), point.y())

        topPt = QgsPoint(point.x(), currExt.yMaximum())
        bottomPt = QgsPoint(point.x(), currExt.yMinimum())

        horizLine = QgsGeometry.fromPolyline([leftPt, rightPt])
        vertLine = QgsGeometry.fromPolyline([topPt, bottomPt])

        self.crossRb.reset(QgsWkbTypes.LineGeometry)
        self.crossRb.addGeometry(horizLine, None)
        self.crossRb.addGeometry(vertLine, None)

        QTimer.singleShot(1000, self.resetRubberbands)

    def resetRubberbands(self):
        self.crossRb.reset()


# -*- coding: utf-8 -*-
"""
Date:17.4.26
Description:
    打算开始上机器学习基石了，但不知道这个课总共有多久，于是写了这个，原谅我的懒……
    计算结果是15:30:54
@author: Drapor
"""
import re
import urllib2

url='https://www.youtube.com/playlist?list=PLXVfgk9fNX2I7tB6oIINGBmW50rrmFTqf'
request = urllib2.Request(url)
response = urllib2.urlopen(request)
content = response.read()
content = content.replace('\n','')
m=0
s=0
h=0
pattern = r'\d{1,2}:\d{1,2}'

result=re.findall(pattern,content)

for i in result:
    m+=int(i[:-3])
    s+=int(i[-2:])

m+=s/60
s=s%60
h+=m/60
m=m%60

str(h)+':'+str(m)+':'+str(s)


from unittest.mock import call, ANY
import pytest
from pki_file import PKIFile, KEY_ALGORITHMS, SIGNING_ALGORITHMS
from cryptography.hazmat.primitives.asymmetric import rsa, ec
from cryptography.hazmat.primitives import serialization

CWD = 'zion'
CERT_FILE_PATH = 'matrix/trinity'
PRIV_KEY_PATH = 'matrix/neo'
CERTIFICATE_PEM = 'Ooh, a storm is threatening'
CERTIFICATE_SUBJECT = 'My very life today'
CSR_PEM = 'If I don\'t get some shelter'

@pytest.fixture(name='config')
def fixture_config(mocker):
    """ A mocked PKI configuration """
    mock_config_class = mocker.patch('pki.Config')
    mock_config = mock_config_class.return_value
    return mock_config

@pytest.fixture(name='pkifile')
def fixture_pkifile(mocker, config):
    """ PKIFile constructor with dependencies mocked """
    # Set a default configuration
    config.key_algorithm = 'RSA-2048'
    config.signing_algorithm = 'SHA256WITHRSA'

    # Mock out the other basic dependencies of the constructor
    mocker.patch('pki.EffectiveConfig.__init__', return_value=None)
    mocker.patch('pki.EffectiveConfig.certificate_file_path', return_value=CERT_FILE_PATH)
    mocker.patch('pki.EffectiveConfig.private_key_path', return_value=PRIV_KEY_PATH)
    mocker.patch('pki_file.os.getcwd', return_value=CWD)
    return PKIFile(mocker.Mock())

@pytest.fixture(name='csr_builder')
def fixture_csr_builder(mocker):
    """ Do CSR builder setup and tear down """
    file = mocker.patch('pki_file.open', mocker.mock_open(read_data=CERTIFICATE_PEM))
    certificate = mocker.Mock()
    certificate.subject = CERTIFICATE_SUBJECT
    load_pem = mocker.patch('pki_file.load_pem_x509_certificate', return_value=certificate)
    csr_builder_class = mocker.patch('pki_file.CertificateSigningRequestBuilder')
    csr_builder = csr_builder_class.return_value
    csr_builder.subject_name.return_value.sign.return_value.public_bytes.return_value.decode.return_value = CSR_PEM

    yield csr_builder

    file.assert_called_once_with(CERT_FILE_PATH, 'rb')
    load_pem.assert_called_once_with(CERTIFICATE_PEM)
    csr_builder_class.assert_called_once()
    csr_builder.subject_name.return_value.sign.return_value.public_bytes\
                .assert_called_once_with(encoding=serialization.Encoding.PEM)

def test_create_csr_rsa(mocker, pkifile, config, csr_builder):
    """ Create CSR with RSA private key and signing algorithm """
    private_key = mocker.MagicMock(spec=rsa.RSAPrivateKey)
    gen_priv_key = mocker.patch('pki_file.rsa.generate_private_key', return_value=private_key)

    config.key_algorithm = 'RSA-2048'
    config.signing_algorithm = 'SHA256WITHRSA'

    assert pkifile.create_csr() == CSR_PEM

    gen_priv_key.assert_called_once_with(public_exponent=65537, key_size=KEY_ALGORITHMS[config.key_algorithm]['size'])
    private_key.private_bytes.assert_called_once_with(encoding=serialization.Encoding.PEM,
                                                      format=serialization.PrivateFormat.TraditionalOpenSSL,
                                                      encryption_algorithm=ANY)
    csr_builder.subject_name.assert_called_once_with(CERTIFICATE_SUBJECT)
    csr_builder.subject_name().sign.assert_called_once_with(private_key,
                                                            SIGNING_ALGORITHMS[config.signing_algorithm]['hash'])

def test_create_csr_ec(mocker, pkifile, config, csr_builder):
    """ Create CSR with EC private key and signing algorithm """
    private_key = mocker.MagicMock(spec=ec.EllipticCurvePrivateKey)
    gen_priv_key = mocker.patch('pki_file.ec.generate_private_key', return_value=private_key)

    config.key_algorithm = 'ECDSA-P256'
    config.signing_algorithm = 'ECDSA-WITH-SHA256'

    assert pkifile.create_csr() == CSR_PEM

    gen_priv_key.assert_called_once_with(KEY_ALGORITHMS[config.key_algorithm]['curve'])
    private_key.private_bytes.assert_called_once_with(encoding=serialization.Encoding.PEM,
                                                      format=serialization.PrivateFormat.PKCS8,
                                                      encryption_algorithm=ANY)
    csr_builder.subject_name.assert_called_once_with(CERTIFICATE_SUBJECT)
    csr_builder.subject_name().sign.assert_called_once_with(private_key,
                                                            SIGNING_ALGORITHMS[config.signing_algorithm]['hash'])

def test_create_csr_mismatched_family(mocker, pkifile, config):
    """ Mismatched encryption family for key and signing algorithms results in no CSR """
    mocker.patch('pki_file.open', mocker.mock_open(read_data=CERTIFICATE_PEM))
    certificate = mocker.Mock()
    certificate.subject = CERTIFICATE_SUBJECT
    mocker.patch('pki_file.load_pem_x509_certificate', return_value=certificate)
    config.key_algorithm = 'RSA-2048'
    config.signing_algorithm = 'ECDSA-WITH-SHA256'
    assert pkifile.create_csr() is None

def test_create_csr_exception(mocker, pkifile):
    """ Create CSR should handle exceptions """
    mocker.patch('pki_file.open', side_effect=Exception('mocked error'))
    assert pkifile.create_csr() is None

def test_rotate(mocker, pkifile):
    """ Rotate should copy to backups and write new cert and key """
    shutil_copy2 = mocker.patch('pki_file.shutil.copy2')
    file = mocker.patch('pki_file.open', mocker.mock_open())
    assert pkifile.rotate(CERTIFICATE_PEM)
    calls = [call(f'{CERT_FILE_PATH}', f'{CWD}/{PKIFile.CERTIFICATE_BAK}'),
             call(f'{PRIV_KEY_PATH}', f'{CWD}/{PKIFile.PRIVATE_KEY_BAK}')]
    shutil_copy2.assert_has_calls(calls, any_order=False)
    calls = [call(f'{CERT_FILE_PATH}', 'w', encoding='utf-8'), call(f'{PRIV_KEY_PATH}', 'w', encoding='utf-8')]
    file.assert_has_calls(calls, any_order=True)
    calls = [call(CERTIFICATE_PEM), call(None)]
    file().write.assert_has_calls(calls, any_order=True)

def test_rotate_exception(mocker, pkifile):
    """ Rotate should handle exceptions """
    mocker.patch('pki_file.shutil.copy2', side_effect=Exception('mocked error'))
    assert not pkifile.rotate(CERTIFICATE_PEM)

def test_rollback(mocker, pkifile):
    """ Rollback should restore from backups and delete new """
    shutil_copy2 = mocker.patch('pki_file.shutil.copy2')
    os_remove = mocker.patch('pki_file.os.remove')
    assert pkifile.rollback()
    calls = [call(f'{CWD}/{PKIFile.CERTIFICATE_BAK}', f'{CERT_FILE_PATH}'),
             call(f'{CWD}/{PKIFile.PRIVATE_KEY_BAK}', f'{PRIV_KEY_PATH}')]
    shutil_copy2.assert_has_calls(calls, any_order=False)
    calls = [call(f'{CWD}/{PKIFile.CERTIFICATE_BAK}'), call(f'{CWD}/{PKIFile.PRIVATE_KEY_BAK}')]
    os_remove.assert_has_calls(calls, any_order=False)

def test_rollback_exception(mocker, pkifile):
    """ Rollback should handle exceptions """
    mocker.patch('pki_file.shutil.copy2', side_effect=Exception('mocked error'))
    assert not pkifile.rollback()

def test_backup_exists(mocker, pkifile):
    """ Backup should exist if both files exist """
    os_path_exists = mocker.patch('pki_file.os.path.exists', return_value=True)
    assert pkifile.backup_exists()
    calls = [call(f'{CWD}/{PKIFile.CERTIFICATE_BAK}'), call(f'{CWD}/{PKIFile.PRIVATE_KEY_BAK}')]
    os_path_exists.assert_has_calls(calls, any_order=False)

def test_backup_not_exists_if_neither(mocker, pkifile):
    """ Backup should not exist if neither file exists """
    os_path_exists = mocker.patch('pki_file.os.path.exists', return_value=False)
    assert not pkifile.backup_exists()
    os_path_exists.assert_called_once_with(f'{CWD}/{PKIFile.CERTIFICATE_BAK}')

def test_backup_not_exists_if_no_cert(mocker, pkifile):
    """ Backup should not exist if just the cert backup is missing """
    os_path_exists = mocker.patch('pki_file.os.path.exists', return_value=False)
    os_path_exists.side_effect = [False, True]
    assert not pkifile.backup_exists()
    os_path_exists.assert_called_once_with(f'{CWD}/{PKIFile.CERTIFICATE_BAK}')

def test_backup_not_exists_if_no_key(mocker, pkifile):
    """ Backup should not exist if just the key backup is missing """
    os_path_exists = mocker.patch('pki_file.os.path.exists', return_value=False)
    os_path_exists.side_effect = [True, False]
    assert not pkifile.backup_exists()
    calls = [call(f'{CWD}/{PKIFile.CERTIFICATE_BAK}'), call(f'{CWD}/{PKIFile.PRIVATE_KEY_BAK}')]
    os_path_exists.assert_has_calls(calls, any_order=False)

def test_delete_backup(mocker, pkifile):
    """ Backup should be deleted """
    os_remove = mocker.patch('pki_file.os.remove')
    pkifile.delete_backup()
    calls = [call(f'{CWD}/{PKIFile.CERTIFICATE_BAK}'), call(f'{CWD}/{PKIFile.PRIVATE_KEY_BAK}')]
    os_remove.assert_has_calls(calls, any_order=False)


from drg_group.yinchuan_2023.Base import message,intersect,SS_VALID
from drg_group.yinchuan_2023.DRG import MDCQ_DRG

def group(record):
  adrg_zd=["D13.901","D18.000x044","D18.100x023","D58.000","D73.100","D73.400","D73.500","D73.501","D73.805","R16.100x001","S36.002"]
  adrg_zd1=[]
  adrg_ss=["41.2x03","41.4200x002","41.4300","41.5x00","41.5x01","41.9400","41.9501"]
  adrg_ss1=[]
  adrg_ss2=[]
  dept_list=[]
  if True and record.zdList[0] in adrg_zd and record.ssList and record.ssList[0] in adrg_ss and record.ssList and intersect(record.ssList,adrg_ss):
    message('符合QB1入组条件，匹配规则：主诊断匹配、主手术匹配、某一手术匹配')

    if MDCQ_DRG.QB13_group(record):
      return 'QB13'

    if MDCQ_DRG.QB15_group(record):
      return 'QB15'

    return 'QB1'
  else:
    return ''


import copy
import numpy

class Monkey:
    def __init__(self):
        self.items = []
        self.operation = ''
        self.test = {
            'divisibleby': 0,
            'true': 0,
            'false': 0
        }
        self.inspected = 0

    def __str__(self):
        o = ''
        o += f"Items     : {self.items}\n"
        o += f"Operation : {self.operation}\n"
        o += f"Test      : {self.test}\n"
        return o

monkeys1 = []

lines = open("input2.txt").readlines()

# Parse input
for i in range(len(lines)):
    monkey = None
    if lines[i].strip().startswith("Monkey"):
        monkey = Monkey()
        # Starting items
        startidx = len("Starting items: ")
        str_items = lines[i+1].strip()[startidx:].split(',')
        for v in str_items:
            monkey.items.append(int(v))

        # Operation
        startidx = len("Operation: new = ")
        monkey.operation = lines[i+2].strip()[startidx:]

        # Test
        startidx = len("Test: divisible by ")
        monkey.test['divisibleby'] = int(lines[i+3].strip()[startidx:])

        # True
        startidx = len("If true: throw to monkey ")
        monkey.test['true'] = int(lines[i+4].strip()[startidx:])

        # False
        startidx = len("If false: throw to monkey ")
        monkey.test['false'] = int(lines[i+5].strip()[startidx:])
        i += 6

        monkeys1.append(monkey)

monkeys2 = copy.deepcopy(monkeys1)

# Part 1
for r in range(20):
    # print(f"Round {r+1}")
    for i,m in enumerate(monkeys1):
        # print(f"Monkey {i}:")
        for old in m.items:
            # print(f"  Inspect {old}")
            m.inspected += 1
            new = eval(m.operation)
            worry = int(numpy.floor(new/3))
            if worry % m.test['divisibleby'] == 0:
                monkeys1[m.test['true']].items.append(worry)
            else:
                monkeys1[m.test['false']].items.append(worry)
        m.items.clear()

inspected = []
for i,m in enumerate(monkeys1):
    inspected.append(m.inspected)
inspected.sort(reverse=True)
print(inspected[0] * inspected[1])

# Part 2
divisibility = []
for m in monkeys2:
    divisibility.append(m.test['divisibleby'])
lcmval = numpy.lcm.reduce(divisibility)

for r in range(10000):
    # print(f"Round {r+1}")
    for i,m in enumerate(monkeys2):
        # print(f"Monkey {i}:")
        # print(m.items)
        worries = []
        for old in m.items:
            # print(f"  Inspect {old}")
            m.inspected += 1
            new = eval(m.operation)
            w = int(numpy.floor(new%lcmval))
            worries.append(w)

        for worry in worries:
            # worry = int(worry/divisor)
            if worry % m.test['divisibleby'] == 0:
                monkeys2[m.test['true']].items.append(worry)
            else:
                monkeys2[m.test['false']].items.append(worry)
        m.items.clear()
        # print(f"Monkey {i}: {m.inspected}")

inspected=[]
for i,m in enumerate(monkeys2):
    # print(m.inspected)
    inspected.append(m.inspected)
inspected.sort(reverse=True)
print(inspected[0] * inspected[1])


import os
import pandas as pd
import rampwf as rw
from rampwf.workflows import FeatureExtractorRegressor
from rampwf.workflows import FeatureExtractorClassifier
from rampwf.score_types.base import BaseScoreType
from sklearn.model_selection import GroupShuffleSplit
from sklearn.model_selection import StratifiedShuffleSplit
from sklearn.metrics import balanced_accuracy_score
from sklearn.metrics import accuracy_score
from sklearn.preprocessing import LabelEncoder
from rampwf.score_types.classifier_base import ClassifierBaseScoreType
import numpy as np

problem_title = 'Prediction of the severity of an accident'
_target_column_name = 'grav'
# A type (class) which will be used to create wrapper objects for y_pred
_prediction_label_names = [1, 2, 3, 4]
Predictions = rw.prediction_types.make_multiclass(
    label_names=_prediction_label_names)
#Predictions = rw.prediction_types.make_regression()
# An object implementing the workflow

class Accident(FeatureExtractorClassifier):
    def __init__(self, workflow_element_names=[
            'feature_extractor', 'classifier']):
        super(Accident, self).__init__(workflow_element_names[:2])
        self.element_names = workflow_element_names

workflow = Accident()

class Accident_error(ClassifierBaseScoreType):
    is_lower_the_better = False
    minimum = 0.0
    maximum = float('inf')

    def __init__(self, name='error', precision=2):
        self.name = name
        self.precision = precision

    def __call__(self, y_true, y_pred):

        if isinstance(y_true, pd.Series):
            y_true = y_true.values

        balanced_score = balanced_accuracy_score(y_true, y_pred)

        return balanced_score

score_types = [
    Accident_error(name='error', precision=2),
]

#score_types = [
#rw.score_types.BalancedAccuracy(name='BalancedAccuracy', precision=3)
#]

def get_cv(X, y):
    cv = StratifiedShuffleSplit(n_splits=8, test_size=0.2, random_state=57)
    return cv.split(X, y)

def _read_data(path, f_name1,f_name2,f_name3,f_name4):
    data1 = pd.read_csv(os.path.join(path, 'data', f_name1), low_memory=False)
    data2 = pd.read_csv(os.path.join(path, 'data', f_name2), low_memory=False)
    data3 = pd.read_csv(os.path.join(path, 'data', f_name3), low_memory=False)
    data4 = pd.read_csv(os.path.join(path, 'data', f_name4), low_memory=False, encoding='latin-1')
    dataMerge = pd.merge(data1,data2, on='Num_Acc', how='left')
    dataMerge1 =  pd.merge(dataMerge,data3, on='Num_Acc', how='left')
    dataMerge2 = pd.merge(dataMerge1,data4, on='Num_Acc', how='left')
    y_array = dataMerge2[_target_column_name].values
    X_df = dataMerge2.drop(_target_column_name, axis=1)
    return X_df, y_array

def get_train_data(path='.'):
    f_name1 = 'usagers-2017.csv'
    f_name2 = 'lieux-2017.csv'
    f_name3 = 'vehicules-2017.csv'
    f_name4 = 'caracteristiques-2017.csv'
    return _read_data(path, f_name1,f_name2,f_name3,f_name4)

def get_test_data(path='.'):
    f_name1 = 'usagers-2018.csv'
    f_name2 = 'lieux-2018.csv'
    f_name3 = 'vehicules-2018.csv'
    f_name4 = 'caracteristiques-2018.csv'
    return _read_data(path, f_name1,f_name2,f_name3,f_name4)


from collections import defaultdict

n = int(input())

grid = []

for i in range(n):
    row = list(map(int, input().split()))
    cur = []
    for j in range(n):
        if row[j]:
            cur.append(j+1)
    print(len(cur), *cur)


from setuptools import find_packages
from setuptools import setup

REQUIRED_PACKAGES = ['keras','google-cloud-storage']

setup(
    name='trainer',
    version='0.1',
    install_requires=REQUIRED_PACKAGES,
    include_package_data=True,
    description='My trainer application package.',
    packages=find_packages()
)


from flask import Flask,request,render_template,flash,redirect
import requests
app=Flask(__name__)
app.secret_key="secret key"
@app.route("/",methods=['GET','POST'])
def main():
    if request.method=='POST':
        try:

            city_name=request.form['name']
            print(city_name)
            url = 'http://api.openweathermap.org/data/2.5/weather?q={}&units=metric&APPID=UR API KEY'
            response=requests.get(url.format(city_name)).json()
            print(response)
            temp = response['main']['temp']
            weather = response['weather'][0]['description']
            min_temp = response['main']['temp_min']
            max_temp = response['main']['temp_max']
            icon = response['weather'][0]['icon']
            long=response['coord']['lon']
            lati=response['coord']['lat']
            feeling=response['main']['feels_like']
            return render_template('index.html',temp=temp,weather=weather,min_temp=min_temp,max_temp=max_temp,icon=icon, city_name = city_name,long=long,lati=lati,feeling=feeling)
        except Exception as e:
            flash(f'Error: {str(e)} enter the correct city name', 'error')
            return redirect("/")
    return render_template('index.html')

if (__name__=='__main__'):
    app.run(debug=True)


import sys
input = sys.stdin.readline

n = int(input())
Stairs = [0]
for i in range(n):
  Stairs.append(int(input()))

memo = [[0 for j in range(n+1)] for i in range(3)]

# 0 -> 다음으로 갈 수 있음
# 1 -> 다음으로 못감
# 2 -> 최대값

memo[0][1] = Stairs[1]
memo[2][1] = Stairs[1]

if n >=2:
  memo[0][2] = Stairs[2]
  memo[1][2] = Stairs[2] + Stairs[1]
  memo[2][2] = Stairs[2] + Stairs[1]

for i in range(3,n+1):
  memo[0][i] = Stairs[i] + memo[2][i-2]
  memo[1][i] = Stairs[i] + memo[0][i-1]
  memo[2][i] = max(memo[1][i],memo[0][i])

print(memo[2][n])


#15min
def isLuckyNum(n):
    for ch in str(n):
        if ch != '4' and ch != '7':
            return False
    return True

n = int(input())
for i in range(1,n+1):
    if n % i == 0:
        if isLuckyNum(int(n/i)):
            print('YES')
            exit()
print('NO')


from cx_Freeze import setup, Executable

# On appelle la fonction setup

buildOptions = dict(
    includes=["pygame.py"],
    include_files=["fichier1.txt", "mon_icone.ico"]
)

setup(
    name="BoumeurMan",
    version="1",
    description="Projet Terminale 2021",
    executables=[Executable("main.py")],
)


import numpy as np
from JorGpi.POSCARloader import POSCARloader

class KPOINTS:
    def __init__(self,POSCAR="POSCAR",resolution=0.001):
        self.multipliers = np.arange(1.0,89,resolution)
        loader = POSCARloader(POSCAR)
        loader.parse()
        self.directions = loader()['directions']
        self.found      = []
        self.volume = np.linalg.det(self.directions)
        self.invert_directions()

    def invert_directions(self):
        self.invdirections = []
        for i in range(3):
            j = (i+1)%3
            k = (i+2)%3
            self.invdirections.append(np.cross(self.directions[j],self.directions[k])/self.volume)
        self.invdirections = np.array(self.invdirections)
        self.invdirections /= np.max([np.linalg.norm(b) for b in self.invdirections])

    def __call__(self,treshold):
        newlyFound = []
        for mul in self.multipliers:
            local = mul*self.invdirections
            err = np.sum(np.abs([np.linalg.norm(l)- np.int(np.linalg.norm(l)) for l in local]))
            if err >= treshold:
                continue
            justFound = [ np.int(np.linalg.norm(l)) for l in local ]
            if justFound not in self.found and 0 not in justFound:
                self.found.append(justFound)
                newlyFound.append([justFound,err])
        return newlyFound

    @staticmethod
    def print_all(records,display):
        for record,error in records:
            print("{:3d} {:3d} {:3d} +/- {:4.3f}  {:7d}".format(*record,error,np.prod(record)).center(display))


import time
import heapq
def Scheduling(Arrival,Burst):
	clock=0
	n=len(Arrival)
	ReadyQueue=[]
	heapq.heapify(ReadyQueue)
	Completion=[0 for i in range(len(Burst))]	# clock time at completion
	Copy=[]		# to detect if a process is already transferred to ReadyQueue
	for i in range(len(Arrival)):	#puting in process with arrival time minimum in ReadyQueue
		if Arrival[i]==0:
			heapq.heappush(ReadyQueue,[Burst[i],i])
			n=n-1
			Copy.append(i)
	timequanta=average(ReadyQueue)
	while len(ReadyQueue)!=0 or (n!=0):	#Implementation
		i=heapq.heappop(ReadyQueue)
		if i[0]<=timequanta:
			clock=clock+i[0]
			Completion[i[1]]=clock
			for i in range(len(Arrival)):# Appending arrived processes in ReadyQueue
				if Arrival[i]<=clock and (i not in Copy) :
					heapq.heappush(ReadyQueue,[Burst[i],i])
					n=n-1
					Copy.append(i)
					timequanta=average(ReadyQueue)
			if len(ReadyQueue)==0 and n!=0: # While CPU is idle
				l=len(Copy)
				x=Arrival[l]
				heapq.heappush(ReadyQueue,[Burst[l],l])
				clock=Arrival[l]
				Copy.append(l)
				n=n-1
		else:
			i[0]=i[0]-timequanta
			clock=clock+timequanta
			if (Burst[i[1]]-i[0])>timequanta:
				heapq.heappush(ReadyQueue,i)
			else:
				clock=clock+i[0]
				Completion[i[1]]=clock
				if len(ReadyQueue)==0 and n!=0: # While CPU is IDLE
					l=len(Copy)
					x=Arrival[l]
					heapq.heappush(ReadyQueue,[Burst[l],l])
					clock=Arrival[l]
					Copy.append(l)
					n=n-1
			for i in range(len(Arrival)):	# Appending arrived Processes in ReadyQueue
				if Arrival[i]<=clock and (i not in Copy):
					heapq.heappush(ReadyQueue,[Burst[i],i])
					n=n-1
					timequanta=average(ReadyQueue)

	print(Completion)
	Waiting=[]
	TurnAround=[]
	for i in range(len(Completion)): #Calculation of AWT and ATT
		Waiting.append(Completion[i]-Arrival[i]-Burst[i])
		TurnAround.append(Completion[i]-Arrival[i])
	print('Average Waiting Time is : ',sum(Waiting)/(len(Arrival)),'\nAverage TurnAround Time is :',sum(TurnAround)/len(Arrival))

def average(ReadyQueue):#Function to calculate average of burst time of processes present in ReadyQueue
	average=0
	for i in ReadyQueue:
		average=average+i[0]
	return average/len(ReadyQueue)

'''Calling Function and Calculating Time Taken'''
def main():
	Arrival=[0,1,2,3,9,1000]
	Burst=[5,10,5,9,4,11919191]
	x=time.time()
	m=min(Arrival)
	for i in range(len(Arrival)):
		Arrival[i]=Arrival[i]-m
	print(Arrival)
	Scheduling(Arrival,Burst)
	y=(time.time()-x)
	print("Time Taken by Scheduler - ",y) #Time taken
if __name__ == '__main__':
	main()


n=int(input())                          # read input n
for i in range(n):                      # for each in in range between 0 and n
   a,b,c=map(int,input().split(" "))    # raed inputs of number of cats and dogsand legs
   c1=a+b
   c2=c1*4
   if(c1==2 and c%4==0):                #if c1 satisfies the condition print yes
      print("yes")
   elif(c1==1 and c%4==0):              # else if condition satisfies print no
      print("yes")
   else:                                # else print no
      print("no")


import time
from datetime import datetime

import numpy as np

np.random.seed(50000)

class Conv():
    def __init__(self, in_channels, out_channels, kernel_size, stride, padding=0):
        self.in_channels = in_channels
        self.out_channels = out_channels
        self.kernel_size = kernel_size
        self.stride = stride
        self.kernels = []
        self.b = np.random.randn(self.out_channels) * np.sqrt(1. / self.out_channels)
        min = -0.1
        uniform_range = 0.1
        for i in range(self.out_channels):
            self.kernels.append(
                np.random.uniform(-uniform_range, uniform_range, ([self.in_channels, kernel_size, kernel_size])))
        self.kernels = np.array(self.kernels)
        self.cache = 0
        self.grads = 0
        self.padding = padding

    def forward(self, X):
        # Performs a forward convolution.

        n_C_prev, n_H_prev, n_W_prev = X.shape
        # X = self.zero_pad(X, pad=self.padding)

        n_C = self.out_channels
        n_H = int((n_H_prev + 2 * self.padding - self.kernel_size) / self.stride) + 1
        n_W = int((n_W_prev + 2 * self.padding - self.kernel_size) / self.stride) + 1
        arr = []
        arr.append(X)
        arr = np.array(arr)
        X_col = self.im2col(arr, self.kernel_size, self.kernel_size, self.stride, self.padding)
        w_col = self.kernels.reshape((self.out_channels, -1))
        b_col = self.b.reshape(-1, 1)
        # Perform matrix multiplication.
        out = w_col @ X_col + b_col
        # Reshape back matrix to image.
        out = np.array(np.hsplit(out, 1)).reshape((1, n_C, n_H, n_W))
        self.cache = arr, X_col, w_col
        return out[0]

    def im2col(self, X, HF, WF, stride, pad):
        # Transforms our input image into a matrix.
        # Padding
        X_padded = np.pad(X, ((0, 0), (0, 0), (pad, pad), (pad, pad)), mode='constant')
        i, j, d = self.get_indices(X.shape, HF, WF, stride, pad)
        # Multi-dimensional arrays indexing.
        cols = X_padded[:, d, i, j]
        cols = np.concatenate(cols, axis=-1)
        return cols

    def get_indices(self, X_shape, HF, WF, stride, pad):
        # get input size
        m, n_C, n_H, n_W = X_shape

        # get output size
        out_h = int((n_H + 2 * pad - HF) / stride) + 1
        out_w = int((n_W + 2 * pad - WF) / stride) + 1

        # ----Compute matrix of index i----

        # Level 1 vector.
        level1 = np.repeat(np.arange(HF), WF)
        # Duplicate for the other channels.
        level1 = np.tile(level1, n_C)
        # Create a vector with an increase by 1 at each level.
        everyLevels = stride * np.repeat(np.arange(out_h), out_w)
        # Create matrix of index i at every levels for each channel.
        i = level1.reshape(-1, 1) + everyLevels.reshape(1, -1)

        # ----Compute matrix of index j----
        slide1 = np.tile(np.arange(WF), HF)
        slide1 = np.tile(slide1, n_C)
        everySlides = stride * np.tile(np.arange(out_w), out_h)
        # Create matrix of index j at every slides for each channel.
        j = slide1.reshape(-1, 1) + everySlides.reshape(1, -1)

        # ----Compute matrix of index d----

        # This is to mark delimitation for each channel
        # during multi-dimensional arrays indexing.
        d = np.repeat(np.arange(n_C), HF * WF).reshape(-1, 1)

        return i, j, d

    def col2im(self, dX_col, X_shape, HF, WF, stride, pad):
        # Transform our matrix back to the input image.
        # Get input size
        N, D, H, W = X_shape
        # Add padding if needed.
        H_padded, W_padded = H + 2 * pad, W + 2 * pad
        X_padded = np.zeros((N, D, H_padded, W_padded))

        # Index matrices, necessary to transform our input image into a matrix.
        i, j, d = self.get_indices(X_shape, HF, WF, stride, pad)
        # Retrieve batch dimension by spliting dX_col N times: (X, Y) => (N, X, Y)
        dX_col_reshaped = np.array(np.hsplit(dX_col, N))
        # Reshape our matrix back to image.
        # slice(None) is used to produce the [::] effect which means "for every elements".
        np.add.at(X_padded, (slice(None), d, i, j), dX_col_reshaped)
        # Remove padding from new image if needed.
        if pad == 0:
            return X_padded
        elif type(pad) is int:
            return X_padded[:, :, pad:-pad, pad:-pad]

    def step(self, batchsize, eta):
        self.kernels -= eta * self.grads / batchsize
        self.grads = 0

    def backward(self, dout):
        arr = []
        arr.append(dout)
        dout = np.array(arr)
        X, X_col, w_col = self.cache
        m, _, _, _ = X.shape
        # Compute bias gradient.
        self.b = np.sum(dout, axis=(0, 2, 3))
        # Reshape dout properly.
        dout = dout.reshape(dout.shape[0] * dout.shape[1], dout.shape[2] * dout.shape[3])
        dout = np.array(np.vsplit(dout, m))
        dout = np.concatenate(dout, axis=-1)
        # Perform matrix multiplication between reshaped dout and w_col to get dX_col.
        dX_col = w_col.T @ dout
        # Perform matrix multiplication between reshaped dout and X_col to get dW_col.
        dw_col = dout @ X_col.T
        # Reshape back to image (col2im).
        dX = self.col2im(dX_col, X.shape, self.kernel_size, self.kernel_size, self.stride, self.padding)
        # Reshape dw_col into dw.
        # self.W['grad'] = dw_col.reshape((dw_col.shape[0], self.n_C, self.f, self.f))
        dw = dw_col.reshape((dw_col.shape[0], self.in_channels, self.kernel_size, self.kernel_size))
        self.grads += dw

        return dX[0]

class Dropout():
    def __init__(self, p):
        self.p = p

    def forward(self, h):
        np.random.seed(2147483648)
        u = np.random.binomial(1, self.p, size=h.shape)
        h *= u
        return h

    def backward(self, h):
        return h

    def step(self, batchsize, eta):
        pass

class MaxPool():

    def __init__(self, filter_size, stride=2, padding=0):
        self.f = filter_size
        self.s = stride
        self.p = padding
        self.cache = None

    def forward(self, X):
        # Apply Max pooling.
        self.cache = X
        arr = []
        arr.append(X)
        X = np.array(arr)

        m, n_C_prev, n_H_prev, n_W_prev = X.shape
        n_C = n_C_prev
        n_H = int((n_H_prev + 2 * self.p - self.f) / self.s) + 1
        n_W = int((n_W_prev + 2 * self.p - self.f) / self.s) + 1

        X_col = self.im2col(X, self.f, self.f, self.s, self.p)
        X_col = X_col.reshape(n_C, X_col.shape[0] // n_C, -1)
        M_pool = np.max(X_col, axis=1)
        # Reshape M_pool properly.
        M_pool = np.array(np.hsplit(M_pool, m))
        M_pool = M_pool.reshape(m, n_C, n_H, n_W)

        return M_pool[0]

    def step(self, batchsize, eta):
        pass

    def im2col(self, X, HF, WF, stride, pad):
        """
            Transforms our input image into a matrix.
            Parameters:
            - X: input image.
            - HF: filter height.
            - WF: filter width.
            - stride: stride value.
            - pad: padding value.
            Returns:
            -cols: output matrix.
        """
        # Padding
        X_padded = np.pad(X, ((0, 0), (0, 0), (pad, pad), (pad, pad)), mode='constant')
        i, j, d = self.get_indices(X.shape, HF, WF, stride, pad)
        # Multi-dimensional arrays indexing.
        cols = X_padded[:, d, i, j]
        cols = np.concatenate(cols, axis=-1)
        return cols

    def get_indices(self, X_shape, HF, WF, stride, pad):
        """
            Returns index matrices in order to transform our input image into a matrix.
            Parameters:
            -X_shape: Input image shape.
            -HF: filter height.
            -WF: filter width.
            -stride: stride value.
            -pad: padding value.
            Returns:
            -i: matrix of index i.
            -j: matrix of index j.
            -d: matrix of index d.
                (Use to mark delimitation for each channel
                during multi-dimensional arrays indexing).
        """
        # get input size
        m, n_C, n_H, n_W = X_shape

        # get output size
        out_h = int((n_H + 2 * pad - HF) / stride) + 1
        out_w = int((n_W + 2 * pad - WF) / stride) + 1

        # ----Compute matrix of index i----

        # Level 1 vector.
        level1 = np.repeat(np.arange(HF), WF)
        # Duplicate for the other channels.
        level1 = np.tile(level1, n_C)
        # Create a vector with an increase by 1 at each level.
        everyLevels = stride * np.repeat(np.arange(out_h), out_w)
        # Create matrix of index i at every levels for each channel.
        i = level1.reshape(-1, 1) + everyLevels.reshape(1, -1)

        # ----Compute matrix of index j----

        # Slide 1 vector.
        slide1 = np.tile(np.arange(WF), HF)
        # Duplicate for the other channels.
        slide1 = np.tile(slide1, n_C)
        # Create a vector with an increase by 1 at each slide.
        everySlides = stride * np.tile(np.arange(out_w), out_h)
        # Create matrix of index j at every slides for each channel.
        j = slide1.reshape(-1, 1) + everySlides.reshape(1, -1)

        # ----Compute matrix of index d----

        # This is to mark delimitation for each channel
        # during multi-dimensional arrays indexing.
        d = np.repeat(np.arange(n_C), HF * WF).reshape(-1, 1)

        return i, j, d

    def backward(self, dout):
        """
            Distributes error through pooling layer.
            Parameters:
            - dout: Previous layer with the error.

            Returns:
            - dX: Conv layer updated with error.
        """
        X = self.cache
        arr = []
        arr.append(X)
        X = np.array(arr)
        arr2 = []
        arr2.append(dout)
        dout = np.array(arr2)

        m, n_C_prev, n_H_prev, n_W_prev = X.shape

        n_C = n_C_prev
        n_H = int((n_H_prev + 2 * self.p - self.f) / self.s) + 1
        n_W = int((n_W_prev + 2 * self.p - self.f) / self.s) + 1

        dout_flatten = dout.reshape(n_C, -1) / (self.f * self.f)
        dX_col = np.repeat(dout_flatten, self.f * self.f, axis=0)
        dX = self.col2im(dX_col, X.shape, self.f, self.f, self.s, self.p)
        # Reshape dX properly.
        dX = dX.reshape(m, -1)
        dX = np.array(np.hsplit(dX, n_C_prev))
        dX = dX.reshape(m, n_C_prev, n_H_prev, n_W_prev)
        return dX[0]

    def col2im(self, dX_col, X_shape, HF, WF, stride, pad):
        """
            Transform our matrix back to the input image.
            Parameters:
            - dX_col: matrix with error.
            - X_shape: input image shape.
            - HF: filter height.
            - WF: filter width.
            - stride: stride value.
            - pad: padding value.
            Returns:
            -x_padded: input image with error.
        """
        # Get input size
        N, D, H, W = X_shape
        # Add padding if needed.
        H_padded, W_padded = H + 2 * pad, W + 2 * pad
        X_padded = np.zeros((N, D, H_padded, W_padded))

        # Index matrices, necessary to transform our input image into a matrix.
        i, j, d = self.get_indices(X_shape, HF, WF, stride, pad)
        # Retrieve batch dimension by spliting dX_col N times: (X, Y) => (N, X, Y)
        dX_col_reshaped = np.array(np.hsplit(dX_col, N))
        # Reshape our matrix back to image.
        # slice(None) is used to produce the [::] effect which means "for every elements".
        np.add.at(X_padded, (slice(None), d, i, j), dX_col_reshaped)
        # Remove padding from new image if needed.
        if pad == 0:
            return X_padded
        elif type(pad) is int:
            return X_padded[pad:-pad, pad:-pad, :, :]

class TanH():

    def __init__(self, alpha=1.7159):
        self.alpha = alpha
        self.cache = None

    def step(self, batchsize, eta):
        pass

    def forward(self, X):
        self.cache = X
        arr = [X]
        X = np.array(arr)
        return self.alpha * np.tanh(X)[0]

    def backward(self, new_deltaL):
        X = self.cache
        arr = [X]
        X = np.array(arr)
        return (new_deltaL * (1 - np.tanh(X) ** 2))[0]

class Relu():
    def __init__(self):
        self.relu_prime = lambda x: (x > 0) * 1
        self.x = None

    def forward(self, x):
        self.x = x
        scaling_factor = 1
        return np.maximum(0, x)  # * scaling_factor)

    def step(self, batchsize, eta):
        pass

    def backward(self, cache):
        scaling_factor = 0.1
        dX = cache.copy()
        dX[self.x <= 0] = 0
        dX[self.x > 0] *= scaling_factor
        return dX

    # class Relu():
    #     def __init__(self):
    #         self.relu_prime = lambda x: (x > 0) * 1
    #         self.x = None
    #
    #     def forward(self, image):
    #         self.x = image
    #         relu_out = np.zeros(image.shape)
    #         for map_num in range(image.shape[-1]):
    #             for r in np.arange(0, image.shape[0]):
    #                 for c in np.arange(0, image.shape[1]):
    #                     relu_out[r, c, map_num] = np.max([image[r, c, map_num], 0])
    #         return relu_out

    def step(self, batchsize, eta):
        pass

    def backward(self, cache):
        cache = cache * self.relu_prime(self.x)
        return cache

class Softmax():
    def forward(self, x):
        y = np.exp(x)
        self.h = y / y.sum(axis=None, keepdims=True) + 1e-15
        return self.h

    def backward(self, y):
        return self.h - y

    def step(self, batchsize, eta):
        pass

class LinearRelu():
    def __init__(self):
        self.x = None

    def relu_prime(self, x):
        return np.where(x > 0, 1.0, 0.0)

    def forward(self, input):
        self.input = input
        input[input < 0] = 0
        return input.copy()

    def backward(self, cache):
        cache = cache * self.relu_prime(self.input)
        return cache

    def step(self, batchsize, eta):
        pass

class leaky():
    def forward(self, x):
        leaky_way1 = np.where(x > 0, x, x * 0.01)
        return leaky_way1

    def backward(self, x, alpha=0.01):
        dx = np.ones_like(x)
        dx[x < 0] = alpha
        return dx

    def step(self, batchsize, eta):
        pass

class Linear():
    def __init__(self, in_size, out_size, uniform_range):
        self.W = np.random.uniform(-uniform_range, uniform_range, ([in_size, out_size]))
        self.b = np.random.uniform(-uniform_range, uniform_range, [1, out_size])
        self.x = 0
        self.z = 0
        self.grad = 0
        self.b_grad = 0

    def forward(self, input):
        self.input = input
        self.z = (np.dot(input, self.W) + self.b)
        return self.z

    def backward(self, cache):
        self.grad += np.dot(cache.T, self.input).T
        self.b_grad += cache
        cache = np.dot(cache, self.W.T)
        return cache

    def step(self, batchsize, eta):
        self.b -= eta * self.b_grad / batchsize
        self.W -= eta * self.grad / batchsize
        self.grad = 0
        self.b_grad = 0

class Flatten():
    def forward(self, image):
        self.image_shape = image.shape
        flat = image.flatten()
        flat = np.array([flat])
        return flat

    def step(self, batchsize, eta):
        pass

    def backward(self, dout):
        out = dout.reshape(self.image_shape)
        return out


# 숫자 다루기
# 자연수 35를 뒤집으면 53이 되고, 각 자리수를 합하면 8이 된다. 또,
# 1200을 뒤집으면 21이 되고, 각 자릿수를 합하면 3이 된다.
# 즉, 뒤집었을 때 불필요한 0은 무시된다.
# 자연수 N이 입력되면 그 수를 뒤집은 수와 각 자릿수의 합을 출력하는
# 프로그램을 작성하시오.
# 자연수 N이 입력된다. (1≤N≤1,000,000)
# 1. 첫째 줄에 뒤집은 수를 출력한다.
# 2. 둘째 줄에 각 자릿수의 합을 출력한다.
# method 1
n = input()
st, s = 0, 0
for i in range(len(n)-1, -1, -1):
    if n[i] != '0':
        st = i
        break
for i in range(st, -1, -1):
    l = int(n[i])
    print(l, end='')
    s += l
print('', s, sep='\n')


import contextlib
from typing import Any, Generator

import pytest
import responses

from pyastrosalt.auth import login as auth_login

# Prevent accidental real HTTP requests.
# Source: https://blog.jerrycodes.com/no-http-requests/
from pyastrosalt.web import api_url

@pytest.fixture(autouse=True)
def no_http_requests(monkeypatch):
    """Do not allow real HTTP requests."""

    def urlopen_mock(self, method, url, *args, **kwargs):
        raise RuntimeError(
            f"The test was about to {method} {self.scheme}://{self.host}{url}"
        )

    monkeypatch.setattr(
        "urllib3.connectionpool.HTTPConnectionPool.urlopen", urlopen_mock
    )

def login(token: str):
    """
    Login to the backend API server.

    Parameters
    ----------
    token: str
        Bearer token. For example, if the value is "secret", the Authorization HTTP
        header should have the value "Bearer secret" for requests requiring
        authentication.
    """
    rsp = responses.Response(
        method="POST",
        url=api_url("/token"),
        json={"access_token": "secret"},
    )
    responses.add(rsp)

    auth_login("joe", token)

@contextlib.contextmanager
def does_not_raise() -> Generator[Any, None, None]:
    """
    Yield nothing.

    This generator cam be used to test that no exception is raised.
    """
    yield


import string
from itertools import permutations
import random
import sys

# Counter class to keep track of fitness evaluations
class Counter:
    def __init__(self):
        self.__value = 0

    def inc(self):
        self.__value += 1

    def get(self):
        return self.__value

# Solution class represents a potential mapping solution
class Solution:
    def __init__(self, table : dict(), enc : dict(), enc_freq1 : dict(), enc_freq2 : dict(), eng : dict(), eng_freq1 : dict(), eng_freq2 : dict()):
        self._fit = float('-inf')
        self._table = table
        self.enc = enc
        self.eng = eng
        self.eng_freq1 = eng_freq1
        self.eng_freq2 = eng_freq2
        self.enc_freq1 = enc_freq1
        self.enc_freq2 = enc_freq2

    # Calculate and return the fitness score
    def get_fit(self, counter):
        did_not_calc = bool(self._fit == float('-inf'))
        if did_not_calc:
            counter.inc()
            self._fit = self.__eval_word(enc=self.enc, english=self.eng) + self.__eval_freq(enc_freq=self.enc_freq1, eng_freq=self.eng_freq1, epsilon=0.05) + self.__eval_freq(enc_freq=self.enc_freq2, eng_freq=self.eng_freq2, epsilon=0.005)
        return self._fit

    # Convert a word using the current mapping
    def convert(self, word : str):
        ans = ""
        for letter in word:
            if can_ignore(letter):
                ans += letter
            else:
                ans += self._table[letter]
        return ans

    ## giva a score for word match
    def __eval_word(self, english, enc):
        found = 0
        overall = len(enc)
        for word in enc:
            dec = self.convert(word)
            if dec in english:
                found += 1

        if overall == 0:
            return 0

        return found / overall

    ## give a score for the frequency match
    def __eval_freq(self, enc_freq, eng_freq, epsilon=0):
        count = 0
        inside = 0
        for key in enc_freq:
            dec_k = self.convert(key)
            if abs(eng_freq[dec_k] - enc_freq[key]) <= epsilon:
                ##print(dec_k + " : " + key + " -> " + str(eng_freq[dec_k]))
                inside += 1
            count += 1

        if count > 0:
            return inside / count
        return 0

    # Get the current mapping as a string
    def get_perm(self):
        perm = "{"
        for let in string.ascii_lowercase:
            perm += let + " : " + self._table[let]
            if let == 'z':
                perm += "}"
            else:
                perm += ", "
        return perm

    # Perform a mutation on the current mapping
    def mutation(self):
        c1, c2 = random.sample(string.ascii_lowercase, 2)
        val1 = self._table[c1]
        val2 = self._table[c2]
        t = self._table.copy()
        t[c1] = val2
        t[c2] = val1
        return t

    # Get the current mapping table
    def get_table(self):
        return self._table

    # Create an offspring with a new mapping table
    def offspring(self, table):
        return Solution(enc=self.enc, enc_freq1=self.enc_freq1, enc_freq2=self.enc_freq2, eng_freq1=self.eng_freq1, eng_freq2=self.eng_freq2, eng=self.eng, table=table)

# DarwinSolution class represents a solution using traditional Darwinian evolution
class DarwinSolution(Solution):
    ## constructor
    def __init__(self, table : dict(), enc : dict(), enc_freq1 : dict(), enc_freq2 : dict(), eng : dict(), eng_freq1 : dict(), eng_freq2 : dict(), n=2):
        super().__init__(table, enc, enc_freq1, enc_freq2, eng, eng_freq1, eng_freq2)
        self.__n = n
        self.__improved_table = None
        self.__improved_fit = float('-inf')
        self.__did_improve = False

    ## try to make an improvement
    def __improve(self, counter, n):
        self.__did_improve = True
        alphabet = string.ascii_lowercase
        n = min(n, int(len(alphabet) / 2))
        letters = random.sample(alphabet, n + n)
        opt_table = self._table.copy()
        for i in range(0, n):
            index = i + i
            k1 = letters[index]
            k2 = letters[index + 1]
            val1 = opt_table[k1]
            val2 = opt_table[k2]
            opt_table[k1] = val2
            opt_table[k2] = val1
            s = Solution(enc=self.enc, enc_freq1=self.enc_freq1, enc_freq2=self.enc_freq2, eng_freq1=self.eng_freq1, eng_freq2=self.eng_freq2, eng=self.eng, table=opt_table)
            ## check which is better
            score = s.get_fit(counter)
            if score > self.get_fit(counter):
                self.__improved_table = opt_table
                self.__improved_fit = score

    def get_fit(self, counter):
        if not self.__did_improve:
            self.__improve(counter=counter, n=self.__n)
        if self.__improved_fit == float('-inf'):
            return super().get_fit(counter)
        return self.__improved_fit

    ## convert cipher
    def convert(self, word: str):
        if self.__improved_table is None:
            return super().convert(word)
        ans = ""
        for letter in word:
            if can_ignore(letter):
                ans += letter
            else:
                ans += self.__improved_table[letter]
        return ans

    ## create a DrawinSolution offspring
    def offspring(self, table):
        return DarwinSolution(enc=self.enc, enc_freq1=self.enc_freq1, enc_freq2=self.enc_freq2, eng_freq1=self.eng_freq1, eng_freq2=self.eng_freq2, eng=self.eng, table=table)

# LamarckSolution class represents a solution using traditional Darwinian evolution
class LamarckSolution(Solution):
    def __init__(self, table : dict(), enc : dict(), enc_freq1 : dict(), enc_freq2 : dict(), eng : dict(), eng_freq1 : dict(), eng_freq2 : dict(), n=2):
        super().__init__(table, enc, enc_freq1, enc_freq2, eng, eng_freq1, eng_freq2)
        self.__n = n
        self.__did_improve = False

    ## try to improve the solution
    def __improve(self, counter, n):
        self.__did_improve = True
        alphabet = string.ascii_lowercase
        n = min(n, int(len(alphabet) / 2))
        letters = random.sample(alphabet, n + n)
        opt_table = self._table.copy()
        for i in range(0, n):
            index = i + i
            k1 = letters[index]
            k2 = letters[index + 1]
            val1 = opt_table[k1]
            val2 = opt_table[k2]
            opt_table[k1] = val2
            opt_table[k2] = val1
            s = Solution(enc=self.enc, enc_freq1=self.enc_freq1, enc_freq2=self.enc_freq2, eng_freq1=self.eng_freq1, eng_freq2=self.eng_freq2, eng=self.eng, table=opt_table)
            score = s.get_fit(counter)
            if score > self.get_fit(counter):
                self._fit = score
                self._table = opt_table

    ## make LamarckSolution offspring
    def offspring(self, table):
        return LamarckSolution(enc=self.enc, enc_freq1=self.enc_freq1, enc_freq2=self.enc_freq2, eng_freq1=self.eng_freq1, eng_freq2=self.eng_freq2, eng=self.eng, table=table)

    def get_fit(self, counter):
        if not self.__did_improve:
            self.__improve(counter=counter, n=self.__n)
        return super().get_fit(counter)

## chack if it is a character we need to ignore
def can_ignore(c):
    return bool(c == "." or c == "," or c == ";" or c == "\n" or c == " ")

## get frequency for each single character
def get_single_freq(enc):
    freq = dict()
    count = 0

    ## init every letter to 0
    for l in string.ascii_lowercase:
        freq[l] = 0

    ## count letters
    for letter in enc:
        if not can_ignore(letter):
            freq[letter] += 1
            count += 1

    if count > 0:
        for key in freq:
            freq[key] /= count

    return freq

## get frequency for each character pair
def get_pairs_freq(enc):
    freq = dict()
    count = 0
    previous = ""

    ## init all pairs to 0
    for l1 in string.ascii_lowercase:
        for l2 in string.ascii_lowercase:
            freq[l1 + l2] = 0

    ## count pairs
    for letter in enc:
        if not can_ignore(letter):
            if previous == "":
                previous = letter
            else:
                freq[previous + letter] += 1
                count += 1
        else:
            previous = ""

    if count > 0:
        for key in freq:
            freq[key] /= count

    return freq

## convert text to dictionary
def to_dict(text : str):
    ans = dict()
    alphabet = string.ascii_lowercase
    for i in range(0, 26):
        ans[alphabet[i]] = text[i]
    return ans

## select which solution to take to the crossover part
def select_next(options : list, counter):
    best = None
    score = float('-inf')
    for s in options:
        temp = s.get_fit(counter)
        if temp > score:
            score = temp
            best = s
    return best

## split solutions to pairs
def pair_solutions(solutions):
    ans = []
    random.shuffle(solutions)
    size = len(solutions)
    last = int(size / 2)
    for i in range(0, last):
        if 2 * i + 1 >= len(solutions):
            ans.append((solutions[2 * i], solutions[2 * i]))
        else:
            ans.append((solutions[2 * i], solutions[2 * i + 1]))
    return ans

## random crossover
def crossover(solutions, c):
    alphabet = list(string.ascii_lowercase)
    ## odds for a parent to stay for the next generation
    stay_odds = 0.35
    ## odds for a mutation
    mu_odds = 0.01
    next_gen = []
    for p in solutions:
        children = random.randint(1, 2)
        sol1 = p[0]
        converter1 = sol1.get_table()
        sol2 = p[1]
        converter2 = sol2.get_table()
        for _ in range(0, children):

            random.shuffle(alphabet)
            random_division = random.randint(1, 25)
            letters1 = alphabet[:random_division]
            letters2 = alphabet[random_division:]

            table1 = dict()
            for let in letters1:
                table1[let] = converter1[let]
            for let in letters2:
                table1[let] = converter2[let]

            off1 = sol1.offspring(table=table1)
            next_gen.append(off1)

            if random.random() <= mu_odds:
                ## mutation
                next_gen.append(sol1.offspring(table=off1.mutation()))

            if (random_division != len(alphabet) / 2):
                table2 = dict()
                for let in letters1:
                    table2[let] = converter2[let]
                for let in letters2:
                    table2[let] = converter1[let]
                off2 = sol2.offspring(table=table2)
                next_gen.append(off2)
                if random.random() <= mu_odds:
                    ## mutation
                    next_gen.append(sol2.offspring(table=off2.mutation()))

        if random.random() <= stay_odds:
            next_gen.append(sol1)
        if random.random() <= stay_odds:
            next_gen.append(sol2)

    return next_gen

## generate initial population
def gen_population(enc, enc_freq1, enc_freq2, english, eng_freq1, eng_freq2, sol_type=0, population_size=20000):
    alphabet = string.ascii_lowercase
    limited_permutations = set()

    # Generate limited permutations
    while len(limited_permutations) < population_size:
        permutation = random.sample(alphabet, len(alphabet))
        limited_permutations.add(''.join(permutation))
    if sol_type == 0:
        ## regular
        return [Solution(table=to_dict(x), enc=enc, eng=english, enc_freq1=enc_freq1, enc_freq2=enc_freq2, eng_freq1=eng_freq1, eng_freq2=eng_freq2) for x in limited_permutations]
    if sol_type == 1:
        ## darwin
        return [DarwinSolution(table=to_dict(x), enc=enc, eng=english, enc_freq1=enc_freq1, enc_freq2=enc_freq2, eng_freq1=eng_freq1, eng_freq2=eng_freq2) for x in limited_permutations]
    return [LamarckSolution(table=to_dict(x), enc=enc, eng=english, enc_freq1=enc_freq1, enc_freq2=enc_freq2, eng_freq1=eng_freq1, eng_freq2=eng_freq2) for x in limited_permutations]

## main genetic algorithm
def genetic(solutions, max_gen=800, max_con=15):

    c = Counter()
    gen = 0
    con = 0
    best_score = float('-inf')
    best_sol = None

    slice_size = 0

    while gen < max_gen and con < max_con and len(solutions) > slice_size:
        if len(solutions) > 10000:
            slice_size = 3
        else:
            slice_size = 2
        ## mix
        random.shuffle(solutions)
        ## keep for next generation
        end = int(0.15 * len(solutions))
        elite = solutions[:end]
        solutions = solutions[end:]
        ## split to slices and choose who continues on
        solutions = [select_next(sub_solution, c) for sub_solution in [solutions[i:i+slice_size] for i in range(0, len(solutions), slice_size)]]

        ## make pairs
        if len(solutions) % 2 != 0 and len(solutions) > 1:
            random.shuffle(solutions)
            s1 = solutions.pop()
            s2 = solutions.pop()
            solutions.append(select_next([s1, s2], c))

        pairs = pair_solutions(solutions)

        ## crossover
        next_gen = crossover(solutions=pairs, c=c)
        solutions = next_gen + elite
        ## find best
        next_sol = select_next(solutions, c)

        ## update best
        if next_sol is not None and next_sol.get_fit(c) > best_score:
            best_score = next_sol.get_fit(c)
            best_sol = next_sol
            con = 0
        else:
            con += 1
        gen += 1

    print("Best fit score: " + str(best_score))
    print("Generation: " + str(gen))
    print("Fitness counter: " + str(c.get()))
    return best_sol

## convert text to a set word words
def convert_to_set(text):
    ans = set()
    for word in text:
        word = word.strip().strip(".").strip(",").strip(";")
        if len(word) > 0:
            ans.add(word.lower())

    return ans

## convert frequencies file to a dictionary
def convert_freq_file(lines):
    ans = dict()
    for line in lines:
        if line == '' or line.isspace():
            break
        temp = line.split("\t")
        ans[temp[-1].lower()] = float(temp[0])
    return ans

def main(args):
    args_count = len(args)
    mode = 0
    pop_size = 20000
    if args_count > 0:
        # 0 - regular, 1 - Darwin , 2 - Lamarck
        mode = int(args[0])
        if args_count > 1:
            pop_size = int(args[1])

    ## extrect data from files
    english = set(line.strip() for line in open('dict.txt'))
    english.remove("")

    enc_txt = open("enc.txt", 'r')
    enc = enc_txt.read()
    enc_txt.close()

    freq_single = get_single_freq(enc)
    freq_pair = get_pairs_freq(enc)
    enc_set = convert_to_set(enc.split(" "))

    letter_freq_txt = open("Letter_Freq.txt", 'r')
    lf1 = letter_freq_txt.read().split("\n")
    letter_freq_txt.close()
    freq1 = convert_freq_file(lf1)

    letter2_freq_txt = open("Letter2_Freq.txt", 'r')
    lf2 = letter2_freq_txt.read().split("\n")
    letter2_freq_txt.close()
    freq2 = convert_freq_file(lf2)

    ## generate population
    pop = gen_population(sol_type=mode, enc=enc_set, english=english, enc_freq1=freq_single, enc_freq2=freq_pair, eng_freq1=freq1, eng_freq2=freq2, population_size=pop_size)

    ## get best solution from genetic algorithm
    ans = genetic(solutions=pop)

    ## write answers to files
    with open("perm.txt", 'w') as file:
        file.write(ans.get_perm())

    with open("plain.txt", 'w') as file:
        file.write(ans.convert(enc))

if __name__ == "__main__":
    main(sys.argv[1:])