import logging
from typing import Any, Dict

from sqlalchemy import NUMERIC, DateTime, bindparam, case, func, select
from sqlalchemy.dialects.postgresql import INTERVAL
from sqlalchemy.sql import Select
from sqlalchemy.sql.functions import concat

from execution_engine.constants import CohortCategory
from execution_engine.omop.concepts import Concept
from execution_engine.omop.criterion.abstract import Criterion
from execution_engine.util import Interval, ValueNumber, value_factory
from execution_engine.util.sql import SelectInto

__all__ = ["DrugExposure"]

class DrugExposure(Criterion):
    """A drug exposure criterion in a cohort definition."""

    def __init__(
        self,
        name: str,
        exclude: bool,
        category: CohortCategory,
        drug_concepts: list[str],
        ingredient_concept: Concept,
        dose: ValueNumber | None,
        frequency: int | None,
        interval: Interval | str | None,
        route: Concept | None,
    ) -> None:
        """
        Initialize the drug administration action.
        """
        super().__init__(name=name, exclude=exclude, category=category)
        self._set_omop_variables_from_domain("drug")
        self._drug_concepts = drug_concepts
        self._ingredient_concept = ingredient_concept
        self._dose = dose
        self._frequency = frequency

        if interval is not None:
            if isinstance(interval, str):
                interval = Interval(interval)
            assert isinstance(interval, Interval), "interval must be an Interval or str"

        self._interval = interval
        self._route = route

    @property
    def concept(self) -> Concept:
        """Get the concept of the ingredient associated with this DrugExposure"""
        return self._ingredient_concept

    def _sql_filter_concept(self, query: Select) -> Select:
        """
        Return the SQL to filter the data for the criterion.
        """
        drug_exposure = self._table

        query = query.where(drug_exposure.c.drug_concept_id.in_(self._drug_concepts))

        return query

    def _sql_generate(self, query: Select) -> Select:
        drug_exposure = self._table

        query = self._sql_filter_concept(query)

        if self._dose is not None:
            if self._route is not None:
                # route is not implemented yet because it uses HemOnc codes in the standard vocabulary
                # (cf concept_class_id = 'Route') but these are not standard codes and HemOnc might not be
                # addressable in FHIR
                logging.warning("Route specified, but not implemented yet")

            # todo: this won't work if no interval is specified (e.g. when just looking for a single dose)
            interval = func.cast(concat(1, self._interval.name), INTERVAL)  # type: ignore
            interval_length_seconds = func.cast(
                func.extract("EPOCH", interval), NUMERIC
            ).label("interval_length_seconds")
            one_second = func.cast(concat(1, "second"), INTERVAL)

            # Filter only drug_exposures that are inbetween the start and end date of the cohort
            query = super()._insert_datetime(query)

            interval_starts = query.add_columns(
                (
                    func.date_trunc(
                        "day", bindparam("observation_start_datetime", type_=DateTime)
                    )
                    + interval_length_seconds
                    * (
                        func.floor(
                            func.extract(
                                "EPOCH",
                                (
                                    drug_exposure.c.drug_exposure_start_datetime
                                    - func.date_trunc(
                                        "day",
                                        bindparam(
                                            "observation_start_datetime", type_=DateTime
                                        ),
                                    )
                                ),
                            )
                            / interval_length_seconds
                        )
                        * one_second
                    )
                ).label("interval_start"),
                drug_exposure.c.drug_exposure_start_datetime.label("start_datetime"),
                drug_exposure.c.drug_exposure_end_datetime.label("end_datetime"),
                drug_exposure.c.quantity.label("quantity"),
            ).cte("interval_starts")

            date_ranges = select(
                interval_starts.c.person_id,
                func.generate_series(
                    interval_starts.c.interval_start,
                    interval_starts.c.end_datetime,
                    interval,
                ).label("interval_start"),
                interval_starts.c.start_datetime,
                interval_starts.c.end_datetime,
                interval_starts.c.quantity,
            ).cte("date_ranges")

            interval_quantities = (
                select(
                    date_ranges.c.person_id,
                    date_ranges.c.interval_start,
                    (
                        func.least(
                            date_ranges.c.end_datetime,
                            date_ranges.c.interval_start + interval,
                        )
                        - func.greatest(
                            date_ranges.c.start_datetime,
                            date_ranges.c.interval_start,
                        )
                    ).label("time_diff"),
                    date_ranges.c.start_datetime,
                    date_ranges.c.end_datetime,
                    date_ranges.c.quantity,
                )
                .select_from(date_ranges)
                .cte("interval_quantities")
            )

            # Calculate the ratio of the interval that the drug was taken and handle the case where the
            # interval is 0 (set ratio to 1 explicitly, this is a "bolus" dose)
            ir_ratio_num = func.extract("EPOCH", interval_quantities.c.time_diff)
            ir_ratio_denom = func.extract(
                "EPOCH", interval_quantities.c.end_datetime
            ) - func.extract("EPOCH", interval_quantities.c.start_datetime)
            ir_ratio = case(
                (ir_ratio_denom == 0, 1), else_=ir_ratio_num / ir_ratio_denom
            ).label("ratio")

            interval_ratios = (
                select(
                    interval_quantities.c.person_id,
                    interval_quantities.c.interval_start,
                    ir_ratio,
                    interval_quantities.c.quantity,
                )
                .select_from(interval_quantities)
                .cte("interval_ratios")
            )

            c_interval_quantity = func.sum(
                interval_ratios.c.quantity * interval_ratios.c.ratio
            ).label("interval_quantity")
            c_interval_count = func.count().label("interval_count")

            query = (
                select(
                    interval_ratios.c.person_id,
                    interval_ratios.c.interval_start.label("valid_from"),
                    (interval_ratios.c.interval_start + interval - one_second).label(
                        "valid_to"
                    ),
                    c_interval_quantity,
                    c_interval_count,
                )
                .select_from(interval_ratios)
                .where(interval_ratios.c.ratio > 0)
                .group_by(interval_ratios.c.person_id, interval_ratios.c.interval_start)
                .having(
                    self._dose.to_sql(column_name=c_interval_quantity, with_unit=False)
                )
                .having(c_interval_count >= self._frequency)
                .order_by(interval_ratios.c.person_id, interval_ratios.c.interval_start)
            )

        return query

    def _insert_datetime(self, query: SelectInto) -> SelectInto:
        """
        Return the SQL to insert the datetime for the criterion.

        Nothing to do here, because the datetime is already inserted by the
        _sql_generate method.
        """
        return query

    def _sql_select_data(self, query: Select) -> Select:
        """
        Return the SQL to select the data for the criterion.
        """

        drug_exposure = self._table

        query = query.add_columns(
            drug_exposure.c.drug_concept_id.label("parameter_concept_id"),
            drug_exposure.c.drug_exposure_start_datetime.label("start_datetime"),
            drug_exposure.c.drug_exposure_end_datetime.label("end_datetime"),
            drug_exposure.c.quantity.label("drug_dose_as_number"),
        )

        return query

    def description(self) -> str:
        """
        Get a human-readable description of the criterion.
        """
        return (
            f"{self.__class__.__name__}['{self._name}']("
            f"ingredient={self._ingredient_concept.concept_name}, "
            f"dose={str(self._dose)}, frequency={self._frequency}/{self._interval}, "
            f"route={self._route.concept_name if self._route is not None else None} "
            f")"
        )

    def dict(self) -> dict[str, Any]:
        """
        Return a dictionary representation of the criterion.
        """
        return {
            "name": self._name,
            "exclude": self._exclude,
            "category": self._category.value,
            "drug_concepts": self._drug_concepts,
            "ingredient_concept": self._ingredient_concept.dict(),
            "dose": self._dose.dict() if self._dose is not None else None,
            "frequency": self._frequency,
            "interval": self._interval,
            "route": self._route.dict() if self._route is not None else None,
        }

    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> "DrugExposure":
        """
        Create a drug exposure criterion from a dictionary representation.
        """

        dose = value_factory(**data["dose"]) if data["dose"] is not None else None

        assert dose is None or isinstance(dose, ValueNumber), "Dose must be a number"

        return cls(
            name=data["name"],
            exclude=data["exclude"],
            category=CohortCategory(data["category"]),
            drug_concepts=data["drug_concepts"],
            ingredient_concept=Concept(**data["ingredient_concept"]),
            dose=dose,
            frequency=data["frequency"],
            interval=data["interval"],
            route=Concept(**data["route"]) if data["route"] is not None else None,
        )


import flask
from flask import Flask, render_template, request, redirect
from web3 import Web3

app = Flask(__name__)

candidates = {1: "badi mohammad", 2: "hamza saht", 3: "omar hussein"}

# Connect to the Sepolia network
web3 = Web3(
    Web3.HTTPProvider(
        "https://eth-sepolia.g.alchemy.com/v2/ji4q9T9gKbrr9hk41agAd6JvmuvKhDJk"
    )
)

# Load the contract ABI and address
contract_address = "0x9eE6c65458701930770ADE3ACC9dE59437640b83"
contract_abi = [
    {"inputs": [], "stateMutability": "nonpayable", "type": "constructor"},
    {
        "inputs": [{"internalType": "uint8", "name": "_candidateId", "type": "uint8"}],
        "name": "vote",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function",
    },
    {
        "inputs": [{"internalType": "uint256", "name": "", "type": "uint256"}],
        "name": "candidates",
        "outputs": [
            {"internalType": "uint256", "name": "id", "type": "uint256"},
            {"internalType": "string", "name": "name", "type": "string"},
            {"internalType": "uint256", "name": "voteCount", "type": "uint256"},
        ],
        "stateMutability": "view",
        "type": "function",
    },
    {
        "inputs": [],
        "name": "candidatesCount",
        "outputs": [{"internalType": "uint8", "name": "", "type": "uint8"}],
        "stateMutability": "view",
        "type": "function",
    },
    {
        "inputs": [{"internalType": "uint8", "name": "_candidateId", "type": "uint8"}],
        "name": "getCandidatesVoteCount",
        "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}],
        "stateMutability": "view",
        "type": "function",
    },
    {
        "inputs": [{"internalType": "address", "name": "", "type": "address"}],
        "name": "voters",
        "outputs": [{"internalType": "bool", "name": "", "type": "bool"}],
        "stateMutability": "view",
        "type": "function",
    },
]

# Instantiate the contract
contract = web3.eth.contract(address=contract_address, abi=contract_abi)

# Define the home route
@app.route("/")
def home():
    return render_template("index.html")

# Define a route to interact with the smart contract
@app.route("/interact", methods=["GET", "POST"])
def interact():
    if flask.request.method == "GET":
        badi = contract.functions.getCandidatesVoteCount(1).call()
        hamza = contract.functions.getCandidatesVoteCount(2).call()
        omar = contract.functions.getCandidatesVoteCount(3).call()
        return render_template("result.html", Badi=badi, Hamza=hamza, Omar=omar)
    elif flask.request.method == "POST":
        votedCandidate = request.form.get("name")
        for key in candidates:
            if votedCandidate.lower() in candidates[key]:
                votedCandidate = key
                break
        else:
            return render_template("index.html")

        print(contract.functions.vote(votedCandidate).call())
        return redirect("/interact", code=302)

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


from re import search
import hashlib
from Crypto.Cipher import AES
from Crypto import Random
import os
from configparser import ConfigParser
from locale import getdefaultlocale
import gettext
from subprocess import check_output, CalledProcessError
import logging
from logging.handlers import TimedRotatingFileHandler
import warnings
from tkinter import TclVersion
from tkinter.messagebox import showwarning

# --- paths
PATH = os.path.dirname(__file__)

if os.access(PATH, os.W_OK) and os.path.exists(os.path.join(PATH, "images")):
    # the app is not installed
    # local directory containing config files
    LOCAL_PATH = os.path.join(PATH, "config")
    PATH_LOCALE = os.path.join(PATH, "locale")
    PATH_IMAGES = os.path.join(PATH, "images")
else:
    # local directory containing config files
    LOCAL_PATH = os.path.join(os.path.expanduser("~"), ".checkmails")
    PATH_LOCALE = "/usr/share/locale"
    PATH_IMAGES = "/usr/share/checkmails/images"

if not os.path.isdir(LOCAL_PATH):
    os.mkdir(LOCAL_PATH)
PATH_CONFIG = os.path.join(LOCAL_PATH, "checkmails.ini")
LOG_PATH = os.path.join(LOCAL_PATH, "checkmails.log")

# --- log
handler = TimedRotatingFileHandler(LOG_PATH, when='midnight',
                                   interval=1, backupCount=7)
logging.basicConfig(level=logging.INFO,
                    format='%(asctime)-15s %(levelname)s: %(message)s',
                    handlers=[handler])
logging.getLogger().addHandler(logging.StreamHandler())

# --- ttf fonts
local_path = os.path.join(os.path.expanduser("~"), ".fonts")
try:
    local_fonts = os.listdir(local_path)
except FileNotFoundError:
    local_fonts = []
TTF_FONTS = {f.split(".")[0]: os.path.join(local_path, f)
             for f in local_fonts if search(r".(ttf|TTF)$", f)}
for root, dirs, files in os.walk("/usr/share/fonts"):
    for f in files:
        if search(r".(ttf|TTF)$", f):
            TTF_FONTS[f.split(".")[0]] = os.path.join(root, f)
if "LiberationSans-Bold" in TTF_FONTS:
    default_font = "LiberationSans-Bold"
elif TTF_FONTS:
    default_font = list(TTF_FONTS.keys())[0]
else:
    default_font = ""

# --- read config file
CONFIG = ConfigParser()
if os.path.exists(PATH_CONFIG):
    CONFIG.read(PATH_CONFIG)
    LANGUE = CONFIG.get("General", "language")
    if not CONFIG.has_option("General", "font"):
        CONFIG.set("General", "font", default_font)
    elif CONFIG.get("General", "font") not in TTF_FONTS:
        CONFIG.set("General", "font", default_font)
    if not CONFIG.has_option("General", "check_update"):
        CONFIG.set("General", "check_update", "True")
    if not CONFIG.has_option("General", "trayicon"):
        CONFIG.set("General", "trayicon", "")
else:
    LANGUE = ""
    CONFIG.add_section("General")
    CONFIG.add_section("Mailboxes")
    # time in ms between to checks
    CONFIG.set("General", "time", "300000")
    CONFIG.set("General", "timeout", "60000")
    CONFIG.set("General", "font", default_font)
    CONFIG.set("General", "check_update", "True")
    CONFIG.set("Mailboxes", "active", "")
    CONFIG.set("Mailboxes", "inactive", "")
    CONFIG.set("General", "trayicon", "")

def save_config():
    """Save configuration to config file."""
    with open(PATH_CONFIG, 'w') as fichier:
        CONFIG.write(fichier)

# --- system tray icon
def get_available_gui_toolkits():
    """Check which gui toolkits are available to create a system tray icon."""
    toolkits = {'gtk': True, 'qt': True, 'tk': True}
    b = False
    try:
        import gi
        b = True
    except ImportError:
        toolkits['gtk'] = False

    try:
        import PyQt5
        b = True
    except ImportError:
        try:
            import PyQt4
            b = True
        except ImportError:
            try:
                import PySide
                b = True
            except ImportError:
                toolkits['qt'] = False

    tcl_packages = check_output(["tclsh",
                                 os.path.join(PATH, "packages.tcl")]).decode().strip().split()
    toolkits['tk'] = "tktray" in tcl_packages
    b = b or toolkits['tk']
    if not b:
        raise ImportError("No GUI toolkits available to create the system tray icon.")
    return toolkits

TOOLKITS = get_available_gui_toolkits()
GUI = CONFIG.get("General", "trayicon").lower()

if not TOOLKITS.get(GUI):
    DESKTOP = os.environ.get('XDG_CURRENT_DESKTOP')
    if DESKTOP == 'KDE':
        if TOOLKITS['qt']:
            GUI = 'qt'
        else:
            warnings.warn("No version of PyQt was found, falling back to another GUI toolkits so the system tray icon might not behave properly in KDE.")
            GUI = 'gtk' if TOOLKITS['gtk'] else 'tk'
    else:
        if TOOLKITS['gtk']:
            GUI = 'gtk'
        elif TOOLKITS['qt']:
            GUI = 'qt'
        else:
            GUI = 'tk'
    CONFIG.set("General", "trayicon", GUI)

# --- Translation
APP_NAME = "checkmails"

if LANGUE not in ["en", "fr"]:
    # Check the default locale
    lc = getdefaultlocale()[0][:2]
    if lc == "fr":
        # If we have a default, it's the first in the list
        LANGUE = "fr_FR"
    else:
        LANGUE = "en_US"
    CONFIG.set("General", "language", LANGUE[:2])

gettext.find(APP_NAME, PATH_LOCALE)
gettext.bind_textdomain_codeset(APP_NAME, "UTF-8")
gettext.bindtextdomain(APP_NAME, PATH_LOCALE)
gettext.textdomain(APP_NAME)
LANG = gettext.translation(APP_NAME, PATH_LOCALE,
                           languages=[LANGUE], fallback=True)
LANG.install()

# --- Cryptographic functions to safely store login information
def decrypt(mailbox, pwd):
    """Returns the login and password for the mailbox that where encrypted using pwd."""
    key = hashlib.sha256(pwd.encode()).digest()
    try:
        with open(os.path.join(LOCAL_PATH, mailbox), 'rb') as fich:
            iv = fich.read(AES.block_size)
            cipher = AES.new(key, AES.MODE_CFB, iv)
            server, login, password, folder = cipher.decrypt(fich.read()).decode().split("\n")
    except FileNotFoundError:
        showwarning(_("Warning"), _("Unknown mailbox %(name)r will be removed from configuration file.") % {'name': mailbox})
        active = CONFIG.get("Mailboxes", "active").split(", ")
        inactive = CONFIG.get("Mailboxes", "inactive").split(", ")
        while "" in active:
            active.remove("")
        while "" in inactive:
            inactive.remove("")
        if mailbox in active:
            active.remove(mailbox)
        if mailbox in inactive:
            inactive.remove(mailbox)
        CONFIG.set("Mailboxes", "active", ", ".join(active))
        CONFIG.set("Mailboxes", "inactive", ", ".join(inactive))
        save_config()
        return None, None, None, None
    return server, login, password, folder

def encrypt(mailbox, pwd, server, login, password, folder):
    """Encrypt the mailbox connection information using pwd."""
    key = hashlib.sha256(pwd.encode()).digest()
    iv = Random.new().read(AES.block_size)
    cipher = AES.new(key, AES.MODE_CFB, iv)
    info = [server, login, password, folder]
    with open(os.path.join(LOCAL_PATH, mailbox), 'wb') as fich:
        fich.write(iv)
        try:
            fich.write(cipher.encrypt("\n".join(info)))
        except TypeError:
            fich.write(cipher.encrypt("\n".join(info).encode()))

# --- Images
ICON = os.path.join(LOCAL_PATH, "icon_mail.png")
if GUI == 'tk':
    IMAGE = os.path.join(PATH_IMAGES, "mail.png")
    FONTSIZE = 10
else:
    IMAGE = os.path.join(PATH_IMAGES, "mail128.png")
    FONTSIZE = 70
ICON_48 = os.path.join(PATH_IMAGES, "mail48.png")
IMAGE2 = os.path.join(PATH_IMAGES, "mail.svg")
ADD = os.path.join(PATH_IMAGES, "add.png")
DEL = os.path.join(PATH_IMAGES, "del.png")
EDIT = os.path.join(PATH_IMAGES, "edit.png")
IM_ERROR = os.path.join(PATH_IMAGES, "error.png")
IM_QUESTION = os.path.join(PATH_IMAGES, "question.png")

def internet_on():
    """Check the Internet connexion."""
    try:
        check_output(["ping", "-c", "1", "www.google.com"])
        return True
    except CalledProcessError:
        return False

# --- compatibility
if TclVersion < 8.6:
    # then tkinter cannot import PNG files directly, we need to use PIL
    # but to create an image from a string with the data keyword, we still need
    # the regular tkinter.PhotoImage
    from PIL import ImageTk
    from tkinter import PhotoImage as TkPhotoImage

    class MetaPhotoImage(type):
        def __call__(cls, *args, **kwargs):
            if 'file' in kwargs:
                return ImageTk.PhotoImage(*args, **kwargs)
            else:
                return TkPhotoImage(*args, **kwargs)

    class PhotoImage(metaclass=MetaPhotoImage):
        pass

else:
    # no need of ImageTk dependency
    from tkinter import PhotoImage


import ipaddress
import math

class FirstSpyEstimator:
    def __init__(self, tx_maps, true_sources: {ipaddress.ip_address: [int]}):
        self.p = 0.0
        self.r = 0.0
        self.r_old = 0.0

        benign_nodes = len(true_sources)
        self.observer_map = {}  # BLOCK_ID: observer

        txs = sorted([item for sublist in list(true_sources.values()) for item in sublist])

        tx_ip_map = {}
        for tx in txs:
            first_time = math.inf
            for spy in tx_maps:
                spy_data = tx_maps[spy]
                obs_time = spy_data[tx][1]
                if obs_time < first_time:
                    first_time = obs_time
                    from_ip = spy_data[tx][0]
                    tx_ip_map[tx] = from_ip
                    self.observer_map[tx] = spy

            #print("Mapped TX %d to IP %s, first spy: %d" % (tx, from_ip, observer_map[tx]))

        self.ip_tx_map = {} # Mapping created by adversary

        for ip in true_sources.keys():
            self.ip_tx_map[ip] = []

        for tx, ip in tx_ip_map.items():
            if ip not in self.ip_tx_map:
                self.ip_tx_map[ip] = []
            self.ip_tx_map[ip].append(tx)

        for ip in true_sources.keys():
            fp = 0
            fn = 0
            tp = 0
            for tx in true_sources[ip]:
                if tx in self.ip_tx_map[ip]:
                    tp += 1
                else:
                    fn += 1

            if tp == 0:
                continue
            for tx in self.ip_tx_map[ip]:
                if tx not in true_sources[ip]:
                    fp += 1

            self.r += tp/(tp+fn)
            self.p += tp/(tp+fp)

        #print(len(true_sources.keys()))
        t_s = len(true_sources.keys())
        self.r = self.r/t_s
        self.p = self.p/t_s


import kivy
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.clock import Clock
from kivy.uix.tabbedpanel import TabbedPanelItem, TabbedPanel
from kivy.uix.gridlayout import GridLayout
from kivy.uix.label import Label
from kivy.uix.textinput import TextInput
from kivy.uix.checkbox import CheckBox
from kivy.uix.spinner import Spinner
from kivy.core.window import Window
from kivy.garden.matplotlib.backend_kivyagg import FigureCanvasKivyAgg
import ast
import json
from kivy.factory import Factory
import os
import matplotlib.pyplot as plt
from definitions import PARAMETERS_VARIATIONS_INFO_DIR, MODEL_TRAININGS_DIR, getModelDir

class TabWithInfo(TabbedPanelItem):
    def __init__(self, process, runs_len, **kwargs):
        super(TabWithInfo, self).__init__(**kwargs)

        self.process = process
        self.runs_len = runs_len

        self.last_graphs = []
        self.param_value_model = None

    def updateTab(self, info):

        if "Defaults" in info.keys():
            self.param_value_model = info["Defaults"].items()
            self.showParams()

        else:
            distance, torque, velocity = info["best_multi_fitness"]
            status = " (Running)" if not info["terminate"] else " (Finished)"

            self.ids.model_label.text = f"{info['model'][1]}/{self.runs_len}" + status
            self.ids.generation_label.text = str(info["generation"])
            self.ids.fitness_label.text = str(info["best_fitness"])
            self.ids.distance_label.text = str(distance)
            self.ids.torque_label.text = str(torque)
            self.ids.velocity_label.text = str(velocity)
            self.ids.mean_fitness_label.text = str(info["mean_fitness"])
            self.ids.time_label.text = "%.2f s" % info["time_elapsed"]

            if self.last_graphs is not None:
                for graph in self.last_graphs:
                    plt.close(graph)

            self.last_graphs = [info["fitness_graph"], info["individual_graph"], info["pareto_graph"]]
            self.showGraphs()

    def showParams(self):
        self.ids.params_tab.clear_widgets()

        for param, value in sorted(self.param_value_model):
            self.ids.params_tab.add_widget(Label(text=str(param)))
            self.ids.params_tab.add_widget(Label(text=str(value)))
            self.ids.params_tab.add_widget(Factory.SmallYSeparator())
            self.ids.params_tab.add_widget(Factory.SmallYSeparator())

    def showGraphs(self):
        if self.last_graphs is not None:
            self.ids.general_graphs.clear_widgets()
            self.ids.pareto_graph.clear_widgets()

            fitness_graph = FigureCanvasKivyAgg(self.last_graphs[0])
            individual_graph = FigureCanvasKivyAgg(self.last_graphs[1])
            pareto_graph = FigureCanvasKivyAgg(self.last_graphs[2])

            self.ids.general_graphs.add_widget(fitness_graph)
            fitness_graph.draw()
            self.ids.general_graphs.add_widget(individual_graph)
            individual_graph.draw()
            self.ids.pareto_graph.add_widget(pareto_graph)
            pareto_graph.draw()

class MainGrid(GridLayout):

    def __init__(self, queue, runs_len, **kwargs):
        super(MainGrid, self).__init__(**kwargs)

        self.queue = queue
        self.runs_len = runs_len
        self.cores = []
        self.tabs = []

        self.cols = 1

        self.tabbedPanel = TabbedPanel()
        self.tabbedPanel.do_default_tab = False
        self.add_widget(self.tabbedPanel)

        Clock.schedule_interval(self.update_info, 0.1)

    def update_info(self, dt):

        if not self.queue.empty():
            cores = [tab.process for tab in self.tabs]
            element = self.queue.get()
            process, model = element["model"]

            if process not in cores:
                new_tab = TabWithInfo(process, self.runs_len)
                new_tab.text = f"Process {len(cores) + 1}"

                self.tabs.append(new_tab)
                self.tabbedPanel.add_widget(new_tab)
                self.tabbedPanel.switch_to(new_tab)

            current_tab = list(filter(lambda x: x.process == process, self.tabs))[0]

            current_tab.updateTab(element)

class MainWindowGrid(GridLayout):

    pass

class InformationWindow(App):

    def __init__(self, queue, title, runs_len, **kwargs):
        super(InformationWindow, self).__init__(**kwargs)
        self.queue = queue
        self.title = 'Model: ' + title
        self.runs_len = runs_len
        self.interrupted = False

    def on_request_close(self, *args):
        self.interrupted = True
        self.stop()
        return True

    def build(self):
        Window.bind(on_request_close=self.on_request_close)
        w_width = 1080
        w_height = 607

        Window.minimum_width = w_width
        Window.minimum_height = w_height
        Window.size = (w_width, w_height)

        return MainGrid(self.queue, self.runs_len)

class MainWindow(App):
    def __init__(self, default_params, **kwargs):
        super(MainWindow, self).__init__(**kwargs)
        # Run
        self.chosen_option = None
        self.default_params = default_params
        self.text_inputs = {}
        self.use_defaults = False
        self.all_combinations = False
        self.continue_tuning = False
        self.run_window = None
        self.cores = 1
        self.repetitions = 1

        # Render
        self.render_window = None
        self.individuals_checkboxes = []
        self.render_model_name = ''
        self.render_run = 0
        self.all_runs = False

        # Tuning
        self.tuning_window = None
        self.tuning_run = None

        self.information = {}

        for key, value in self.default_params.items():
            self.default_params[key] = [value]

        with open(PARAMETERS_VARIATIONS_INFO_DIR, 'r') as f:
            self.parameters_variations = json.load(f)

    def build(self):
        self.title = 'Robotic Manipulator'
        return MainWindowGrid()

    def runAll(self):
        self.chosen_option = 1
        self.root.ids.run_button.text = "Run (Run All)"
        self.root.ids.info_layout.clear_widgets()
        self.runWindow()

    def initializeOnly(self):
        self.chosen_option = 2
        self.root.ids.run_button.text = "Run (Initialize Only)"
        self.root.ids.info_layout.clear_widgets()

    def profiling(self):
        self.chosen_option = 3
        self.root.ids.run_button.text = "Run (Profiling)"
        self.root.ids.info_layout.clear_widgets()

    def render(self):
        self.chosen_option = 4
        self.root.ids.run_button.text = "Run (Render)"
        self.root.ids.info_layout.clear_widgets()
        self.renderWindow()

    def findParetoFrontier(self):
        self.chosen_option = 5
        self.root.ids.run_button.text = "Run (Find Pareto Frontier)"
        self.root.ids.info_layout.clear_widgets()

    def tuneModel(self):
        self.chosen_option = 6
        self.root.ids.run_button.text = "Close"
        self.root.ids.info_layout.clear_widgets()
        self.tuningWindow()

    def runButton(self):
        if self.chosen_option == 1:
            self.parameters_variations = {key: ast.literal_eval('[' + t_input.text + ']') for key, t_input in self.text_inputs.items()}

            with open(PARAMETERS_VARIATIONS_INFO_DIR, 'w') as f:
                json.dump(self.parameters_variations, f, indent=4)

            try:
                self.cores = int(self.run_window.ids.cores.text)
            except ValueError:
                self.cores = 1

            try:
                self.repetitions = int(self.run_window.ids.repetitions.text)
            except ValueError:
                self.repetitions = 1

            self.information = {
                'parameters_variations': self.parameters_variations,
                'cores': self.cores,
                'run_name': self.run_window.ids.run_name.text,
                'all_combinations': self.all_combinations,
                'continue_tuning': self.continue_tuning,
                'repetitions': self.repetitions
            }
        elif self.chosen_option == 4:
            self.information = {
                'render_model_name': self.render_model_name,
                'render_run': self.render_run,
                'render_individuals': [i for i, val in enumerate([chbox.active for chbox in self.individuals_checkboxes]) if val],
                'all_runs': self.all_runs
            }

        self.information['final_option'] = self.chosen_option

        self.stop()

    def on_checkbox_active(self, checkbox, value):
        self.use_defaults = value
        self.showParameters()

    def allRunsCheckBox(self, checkbox, value):
        self.render_window.ids.individuals_layout.disabled = value
        self.all_runs = value

    def tuneParametersCheckBox(self, checkbox, value):
        self.all_combinations = value

    def continueTuningCheckBox(self, checkbox, value):
        self.continue_tuning = value

    def runWindow(self):
        self.run_window = Factory.RunWindow()
        self.root.ids.info_layout.add_widget(self.run_window)
        self.use_defaults = self.run_window.ids.use_defaults.active
        self.showParameters()

    def showParameters(self):
        self.run_window.ids.parameters_layout.clear_widgets()
        the_params = self.default_params if self.use_defaults else self.parameters_variations

        for param, value in sorted(the_params.items()):
            self.text_inputs[param] = TextInput(text=', '.join(map(str, value)), multiline=False)
            self.run_window.ids.parameters_layout.add_widget(Label(text=str(param)))
            self.run_window.ids.parameters_layout.add_widget(self.text_inputs[param])

    def renderWindow(self):
        self.render_window = Factory.RenderWindow()
        self.root.ids.info_layout.add_widget(self.render_window)
        models = [name for name in os.listdir(MODEL_TRAININGS_DIR) if os.path.isdir(os.path.join(MODEL_TRAININGS_DIR, name))]

        self.render_window.ids.model_selection.values = models

    def tuningWindow(self):
        self.tuning_window = Factory.TuningResultsWindow()
        self.root.ids.info_layout.add_widget(self.tuning_window)
        models = [name for name in os.listdir(MODEL_TRAININGS_DIR) if os.path.isdir(os.path.join(MODEL_TRAININGS_DIR, name))]

        self.tuning_window.ids.tuning_model_selection.values = models

    def selectedModel(self, instance, model):
        self.render_model_name = model

        self.render_window.ids.individuals_selection.clear_widgets()
        amount_of_runs = len([name for name in os.listdir(os.path.join(MODEL_TRAININGS_DIR, model, 'Graphs', 'Individuals')) if os.path.isdir(os.path.join(MODEL_TRAININGS_DIR, model, 'Graphs', 'Individuals', name))])

        self.render_window.ids.run_selection.values = list(map(str, sorted(range(amount_of_runs), reverse=True)))

    def selectedRun(self, instance, run):
        self.render_run = int(run)

        self.render_window.ids.individuals_selection.clear_widgets()
        with open(getModelDir(self.render_model_name)) as f:
            model_data = json.load(f)
        run_data = model_data["Best Individuals"][self.render_run]
        individuals = run_data["Genes"]

        self.individuals_checkboxes = []
        for i, ind in enumerate(individuals):
            self.individuals_checkboxes.append(CheckBox())
            self.render_window.ids.individuals_selection.add_widget(Label(text=f'Individual {i} (fit: %.4f)' % ind[2]))
            self.render_window.ids.individuals_selection.add_widget(self.individuals_checkboxes[i])

    def selectedModelForTuning(self, instance, run):
        self.tuning_run = str(run)

    def selectAllIndividuals(self):
        if all([chbox.active for chbox in self.individuals_checkboxes]):
            for chbox in self.individuals_checkboxes:
                chbox.active = False
        else:
            for chbox in self.individuals_checkboxes:
                chbox.active = True

    def generateTuningDict(self):
        if self.tuning_window is not None:
            self.tuning_window.ids.tuning_results.clear_widgets()
        if self.tuning_run is None:
            return
        else:
            import main
            from definitions import getTuningDict
            import json

            main.findDominantsFromTuning(self.tuning_run)
            with open(getTuningDict(self.tuning_run)) as f:
                tuning_dict = json.load(f)
            for i, (key, val) in enumerate(tuning_dict["best"].items()):
                widg = self.singleTuningInfo(**{"name": key, "values": val})
                self.tuning_window.ids.tuning_results.add_widget(widg)
                self.tuning_window.ids.tuning_results.rows_minimum[i] = self.tuning_window.ids.tuning_scroll_view.height * len(val) * 0.06

    def singleTuningInfo(self, **kwargs):

        top_layout = GridLayout()
        top_layout.cols = 1
        top_layout.add_widget(Factory.SeparatorY())

        inside_layout = GridLayout()
        inside_layout.cols = 2

        param_name = Label()
        param_name.text = kwargs["name"]

        param_values = GridLayout()
        param_values.cols = 2

        for val in kwargs["values"]:
            l_1 = Label()
            l_1.text = str(val[0])
            l_2 = Label()
            l_2.text = "%.4f" % val[1]
            param_values.add_widget(l_1)
            param_values.add_widget(l_2)

        inside_layout.add_widget(param_name)
        inside_layout.add_widget(param_values)
        top_layout.add_widget(inside_layout)
        top_layout.add_widget(Factory.SeparatorY())

        return top_layout

def runInfoDisplay(queue, title, event, runs_len):
    info_window = InformationWindow(queue=queue, title=title, runs_len=runs_len)
    info_window.run()

    if info_window.interrupted and event is not None:
        event.set()

def runMainWindow(default_params):
    main_window = MainWindow(default_params)
    main_window.run()

    main_window_information = main_window.information

    return main_window_information


from sqlalchemy import Boolean, Column, ForeignKey, Integer, String, TIMESTAMP, Float, Table
from sqlalchemy.orm import relationship
from sqlalchemy.sql.sqltypes import Text
from database import Base

class User(Base):
    __tablename__ = "users"

    # user_id, roll_no, name, email, phone_number, password, can make reviews and orders
    user_id = Column(Integer, primary_key=True, index=True)
    roll_no = Column(String, unique=True, index=True)
    name = Column(String, index=True)
    email = Column(String, unique=True, index=True)
    phone_number = Column(String, unique=True, index=True)

    # one to many relationship with orders
    orders = relationship("Order", back_populates="customer")

    # one to many relationship with reviews
    reviews = relationship("Review", back_populates="reviewer")

materials_stores = Table('materials_stores', Base.metadata,
    Column('store_id', Integer, ForeignKey('shops.shop_id')),
    Column('material_id', Integer, ForeignKey('raw_materials.id')),
    Column('available', Boolean, nullable=False),
)

class Shop(Base):
    __tablename__ = "shops"

    shop_id = Column(Integer, primary_key=True, index=True)
    name = Column(String, index=True)
    address = Column(String, index=True)
    description = Column(Text)
    contact = Column(String, index=True)
    # create a column tags which stores an array of texts
    tags = Column(String)
    # create a column image which stores the image url
    image_url = Column(String)
    avg_rating = Column(String)

    orders = relationship("Order", back_populates="shop")
    reviews = relationship("Review", back_populates="reviewed_shop")
    items = relationship("Item", back_populates="shop")
    materials = relationship("RawMaterial", secondary=materials_stores, back_populates="stores")

class Order(Base):
    __tablename__ = "orders"

    # id, user_id, shop_id, created_at, status
    id = Column(Integer, primary_key=True, index=True)
    user_id = Column(Integer, ForeignKey("users.user_id"))
    shop_id = Column(Integer, ForeignKey("shops.shop_id"))
    total = Column(Float)
    created_at = Column(String)
    status = Column(String)

    # many to one relationship with users
    customer = relationship("User", back_populates="orders")

    # many to one relationship with shops
    shop = relationship("Shop", back_populates="orders")

    # one to many relationship with order_items
    items = relationship("OrderItem", back_populates="order")

class OrderItem(Base):
    __tablename__ = "order_items"

    # id, order_id, item_id, quantity
    id = Column(Integer, primary_key=True, index=True)
    order_id = Column(Integer, ForeignKey("orders.id"))
    item_id = Column(Integer, ForeignKey("food_item.item_id"))
    quantity = Column(Integer)
    total = Column(Integer)

    # many to one relationship with orders
    order = relationship("Order", back_populates="items")

    # many to one relationship with items
    item = relationship("Item", back_populates="order_items")

class Review(Base):
    __tablename__ = "reviews"

    # id, user_id, shop_id, created_at, rating, comment
    id = Column(Integer, primary_key=True, index=True)
    user_id = Column(Integer, ForeignKey("users.user_id"))
    shop_id = Column(Integer, ForeignKey("shops.shop_id"))
    item_id = Column(Integer, ForeignKey("food_item.item_id"))
    created_at = Column(TIMESTAMP)
    rating = Column(Integer)
    comment = Column(String)

    # many to one relationship with users
    reviewer = relationship("User", back_populates="reviews")

    # many to one relationship with shops
    reviewed_shop = relationship("Shop", back_populates="reviews")

    # many to one relationship with items
    reviewed_item = relationship("Item", back_populates="reviews")

class Item(Base):
    __tablename__ = "food_item"

    item_id = Column(Integer, primary_key=True, index=True)
    name = Column(String)
    veg_or_nonveg = Column(String)
    description = Column(String)
    price = Column(Integer)
    order_id = Column(Integer, ForeignKey("orders.id"))
    shop_id = Column(Integer, ForeignKey("shops.shop_id"))
    available = Column(Boolean)
    item_rating = Column(Float)
    category = Column(String)

    shop = relationship("Shop", back_populates="items")
    reviews = relationship("Review", back_populates="reviewed_item")
    order_items = relationship("OrderItem", back_populates="item")

class RawMaterial(Base):
    __tablename__ = "raw_materials"

    id = Column(Integer, primary_key=True, index=True)
    name = Column(String)
    stores = relationship("Shop", secondary=materials_stores, back_populates="materials")


'''
Lex Strings

Name: <your name>
'''
from collections import Counter, defaultdict

#
# Complete the 'rearrangedString' function below.
#
# The function is expected to return a STRING.
# The function accepts following parameters:
#  1. STRING s
#

# 1. This function will filter the alphanumeric characters from the string and sort them.
def filter_and_sort(s):
    alphanumeric_chars_list = [ch for ch in s if ch.isalnum()]
    alphanumeric_chars = ''.join(alphanumeric_chars_list)
    return sorted(alphanumeric_chars, reverse=True)

# 2. This function will take the sorted string and group the characters by their count.
def group_by_count(sorted_chars):
    char_count = Counter(sorted_chars)
    groups = defaultdict(list)
    for char, count in sorted(char_count.items(), key=lambda x: (-x[1], x[0])):
        groups[count].append(char)
    return groups

# 3. This function will take the groups and apply the alternating sort order.
def alternate_sort(groups):
    sorted_groups = []
    ascending_order = True
    for count, chars in sorted(groups.items(), reverse=True):
        chars = ''.join(chars)
        if not ascending_order:
            chars = chars[::-1]
        sorted_groups.append((count, chars))
        ascending_order = not ascending_order
    return sorted_groups

# 4.
def format_result(sorted_groups):
    return ','.join(f"{count}{chars}" for count, chars in sorted_groups)

def rearrangedString(s):
    # Write your code here
    '''
    1. Extract alphanumeric characters: We'll start by extracting only alphanumeric characters from the input string.
    2. Create frequency groups: We'll group characters by their frequency, preserving the order of characters within each group.
    3. Sort and alternate groups: We'll sort the groups by frequency, and then apply the alternating order rule within each group.
    4. Concatenate and format: Finally, we'll concatenate the groups and format the result as required.
    '''
    sorted_chars = filter_and_sort(s)
    groups = group_by_count(sorted_chars)
    sorted_groups = alternate_sort(groups)
    result = format_result(sorted_groups)

if __name__ == '__main__':
    import sys

    sys.stdin = open('lex_strings_sample_data.txt', 'r')
    for tc in range(10):
        s = input()
        result = rearrangedString(s)
        print('Test Case #{}: {}'.format(tc + 1, result))

'''
Your output on console should be:
Test Case #1: 6in,4ts,3aegr,2o,1ESTfhlmpx
Test Case #2: 5a,4se,3r,2tonkihc,1ACFHLRSdflmuwy
Test Case #3: 2135ei,1tsrohgfdaTPI9642
Test Case #4: 7es,4lh,2a,1ytrobS
Test Case #5: 8a,5n,4gu,3rlic,2CPSdehmosty,1vbVRJIBA
Test Case #6: 7ae,6ni,5t,4rhd,3gl,2vsoc,119CDIOVbmpuwy
Test Case #7: 9e,5nica,4or,3th,202CTsu,1vpmlfdSA
Test Case #8: 53,472,345689deo,2trni1,1IPTafghsu
Test Case #9: 14e,13p,7i,6r,5cdk,4P,2alost,1ywnmfH
Test Case #10: 8o,7e,5hn,3wtsrda,2ikp,1ylfbT10
'''


# coding=utf-8
from django import forms
from django.db.models import Q
from django.forms.models import formset_factory

from BanBanTong.db import models

class RolePrivilegesForm(forms.ModelForm):

    class Meta:
        model = models.RolePrivilege
        exclude = ['uuid', 'role']

class RoleForm(forms.ModelForm):

    def __init__(self, *args, **kwargs):
        super(RoleForm, self).__init__(*args, **kwargs)
        self.fields['name'].error_messages = {
            'required': u'请输入角色名！'
        }

    def clean(self):
        cleaned_data = super(RoleForm, self).clean()

        name = cleaned_data.get('name')

        # 判断角色名是否重复
        if name:
            existing = False
            if self.instance._state.adding:
                if models.Role.objects.filter(name=name).count() > 0:
                    existing = True
            else:
                if models.Role.objects.filter(~Q(uuid=self.instance.uuid),
                                              name=name).count() > 0:
                    existing = True
            if existing:
                self._errors['name'] = self.error_class([u'角色名已存在！'])

        return cleaned_data

    class Meta:
        model = models.Role
        exclude = ['uuid']

RolePrivilegesFormSet = formset_factory(RolePrivilegesForm)


import threading
import time
import serial.tools.list_ports
from os import environ
from re import search

from PyQt6.QtCore import QObject, pyqtSignal

from UM.Platform import Platform
from UM.Signal import Signal, signalemitter
from UM.OutputDevice.OutputDevicePlugin import OutputDevicePlugin
from UM.i18n import i18nCatalog

from cura.PrinterOutput.PrinterOutputDevice import ConnectionState

from . import USBPrinterOutputDevice

i18n_catalog = i18nCatalog("cura")

@signalemitter
class USBPrinterOutputDeviceManager(QObject, OutputDevicePlugin):
    """Manager class that ensures that an USBPrinterOutput device is created for every connected USB printer."""

    addUSBOutputDeviceSignal = Signal()
    progressChanged = pyqtSignal()

    def __init__(self, application, parent = None):
        if USBPrinterOutputDeviceManager.__instance is not None:
            raise RuntimeError("Try to create singleton '%s' more than once" % self.__class__.__name__)

        super().__init__(parent = parent)
        USBPrinterOutputDeviceManager.__instance = self

        self._application = application

        self._serial_port_list = []
        self._usb_output_devices = {}
        self._usb_output_devices_model = None
        self._update_thread = threading.Thread(target = self._updateThread)
        self._update_thread.daemon = True

        self._check_updates = True

        self._application.applicationShuttingDown.connect(self.stop)
        # Because the model needs to be created in the same thread as the QMLEngine, we use a signal.
        self.addUSBOutputDeviceSignal.connect(self.addOutputDevice)

        self._application.globalContainerStackChanged.connect(self.updateUSBPrinterOutputDevices)

    # The method updates/reset the USB settings for all connected USB devices
    def updateUSBPrinterOutputDevices(self):
        for device in self._usb_output_devices.values():
            if isinstance(device, USBPrinterOutputDevice.USBPrinterOutputDevice):
                device.resetDeviceSettings()

    def start(self):
        self._check_updates = True
        self._update_thread.start()

    def stop(self, store_data: bool = True):
        self._check_updates = False

    def _onConnectionStateChanged(self, serial_port):
        if serial_port not in self._usb_output_devices:
            return

        changed_device = self._usb_output_devices[serial_port]
        if changed_device.connectionState == ConnectionState.Connected:
            self.getOutputDeviceManager().addOutputDevice(changed_device)
        else:
            self.getOutputDeviceManager().removeOutputDevice(serial_port)

    def _updateThread(self):
        while self._check_updates:
            container_stack = self._application.getGlobalContainerStack()
            if container_stack is None:
                time.sleep(5)
                continue
            port_list = []  # Just an empty list; all USB devices will be removed.
            if container_stack.getMetaDataEntry("supports_usb_connection"):
                machine_file_formats = [file_type.strip() for file_type in container_stack.getMetaDataEntry("file_formats").split(";")]
                if "text/x-gcode" in machine_file_formats:
                    # We only limit listing usb on windows is a fix for connecting tty/cu printers on MacOS and Linux
                    port_list = self.getSerialPortList(only_list_usb=Platform.isWindows())
            self._addRemovePorts(port_list)
            time.sleep(5)

    def _addRemovePorts(self, serial_ports):
        """Helper to identify serial ports (and scan for them)"""

        # First, find and add all new or changed keys
        for serial_port in list(serial_ports):
            if serial_port not in self._serial_port_list:
                self.addUSBOutputDeviceSignal.emit(serial_port)  # Hack to ensure its created in main thread
                continue
        self._serial_port_list = list(serial_ports)

        for port, device in self._usb_output_devices.items():
            if port not in self._serial_port_list:
                device.close()

    def addOutputDevice(self, serial_port):
        """Because the model needs to be created in the same thread as the QMLEngine, we use a signal."""

        device = USBPrinterOutputDevice.USBPrinterOutputDevice(serial_port)
        device.connectionStateChanged.connect(self._onConnectionStateChanged)
        self._usb_output_devices[serial_port] = device
        device.connect()

    def getSerialPortList(self, only_list_usb = False):
        """Create a list of serial ports on the system.

        :param only_list_usb: If true, only usb ports are listed
        """
        base_list = []
        try:
            port_list = serial.tools.list_ports.comports()
        except TypeError:  # Bug in PySerial causes a TypeError if port gets disconnected while processing.
            port_list = []
        for port in port_list:
            if not isinstance(port, tuple):
                port = (port.device, port.description, port.hwid)
            if not port[2]:  # HWID may be None if the device is not USB or the system doesn't report the type.
                continue
            if only_list_usb and not port[2].startswith("USB"):
                continue

            # To prevent cura from messing with serial ports of other devices,
            # filter by regular expressions passed in as environment variables.
            # Get possible patterns with python3 -m serial.tools.list_ports -v

            # set CURA_DEVICENAMES=USB[1-9] -> e.g. not matching /dev/ttyUSB0
            pattern = environ.get('CURA_DEVICENAMES')
            if pattern and not search(pattern, port[0]):
                continue

            # set CURA_DEVICETYPES=CP2102 -> match a type of serial converter
            pattern = environ.get('CURA_DEVICETYPES')
            if pattern and not search(pattern, port[1]):
                continue

            # set CURA_DEVICEINFOS=LOCATION=2-1.4 -> match a physical port
            # set CURA_DEVICEINFOS=VID:PID=10C4:EA60 -> match a vendor:product
            pattern = environ.get('CURA_DEVICEINFOS')
            if pattern and not search(pattern, port[2]):
                continue

            base_list += [port[0]]

        return list(base_list)

    __instance = None # type: USBPrinterOutputDeviceManager

    @classmethod
    def getInstance(cls, *args, **kwargs) -> "USBPrinterOutputDeviceManager":
        return cls.__instance


import binascii
import base58
import hashlib
from hashlib import sha256
from ecdsa import SECP256k1,VerifyingKey,util,BadSignatureError
from six import b

#字符串按字节反转。大小端数据的字符串转换。eg:"123456" to "563412"
def str_reverse_on_byte(data):
    return binascii.hexlify(binascii.unhexlify(data)[::-1]).decode()

#16进制字符串转整型。eg:"11d" to 285
def hexstr2int(hexstr,byteorder='big'):
    return int.from_bytes(binascii.a2b_hex(hexstr), byteorder=byteorder)

###########################################################################################################
# get_varint(data):
#     解析varint
# params:
#     data:待解析数据。数据类型为:str
# return:
#     返回解析结果。数据类型为:tuple,长度为2。
#     tuple[0]为varint的数值位(不包含标识位),tuple[1]为数据位长度。数值位为小端存储。
###########################################################################################################
def get_varint(data):
    flag = hexstr2int(data[0:2])
    if flag < 253:
        return data[0:2],0
    if flag == 253:
        varint_size = 4
    elif flag == 254:
        varint_size = 8
    elif flag == 255:
        varint_size = 16
    return str_reverse_on_byte(data[2:varint_size + 2]),varint_size

###########################################################################################################
# single_sha256(data,byteorder = 'big'):
#     计算sha256
# params:
#     data:待计算数据。数据类型为:str
#     byteorder:字节序。"big"为大端,"little":为小端。数据类型为:str
# return:
#     返回sha256分散结果，数据类型为:str
###########################################################################################################
def single_sha256(data,byteorder = 'big'):
    if(byteorder == 'little'):
        res = binascii.hexlify(sha256(binascii.unhexlify(data)).digest()[::-1])
    else:
        res = binascii.hexlify(sha256(binascii.unhexlify(data)).digest())
    return res.decode()

###########################################################################################################
# double_sha256(data,byteorder = 'big'):
#     计算两次sha256
# params:
#     data:待计算数据。数据类型为:str
#     byteorder:字节序。"big"为大端,"little":为小端。数据类型为:str
# return:
#     返回两次sha256分散结果，数据类型为:str
###########################################################################################################
def double_sha256(data,byteorder = 'big'):
    if(byteorder == 'little'):
        res = binascii.hexlify(sha256(sha256(binascii.unhexlify(data)).digest()).digest()[::-1])
    else:
        res = binascii.hexlify(sha256(sha256(binascii.unhexlify(data)).digest()).digest())
    return res.decode()

###########################################################################################################
# single_ripemd160(data,byteorder = 'big'):
#     计算ripemd160
# params:
#     data:待计算数据。数据类型为:str
#     byteorder:字节序。"big"为大端,"little":为小端。数据类型为:str
# return:
#     返回ripemd160分散结果，数据类型为:str
###########################################################################################################
def single_ripemd160(data,byteorder = 'big'):
    if (byteorder == 'little'):
        res = binascii.hexlify(hashlib.new('ripemd160', binascii.unhexlify(data)).digest()[::-1])
    else:
        res = hashlib.new('ripemd160', binascii.unhexlify(data)).hexdigest()
    return res

###########################################################################################################
# single_base58(data):
#     base58编码
# params:
#     data:待做编码的数据。数据类型为:str
# return:
#     返回base58编码数据。数据类型为:str
###########################################################################################################
def single_base58(data):
    return base58.b58encode(binascii.unhexlify(data))

###########################################################################################################
# pubkey_2_btc_addr(pubkey,ver):
#     通过公钥计算比特币地址
# params:
#     pubkey:公钥,DER格式。数据类型为:str
#     ver:版本号,通常为"00"。数据类型为:str
# return:
#     返回比特币地址，数据类型为:str
###########################################################################################################
def pubkey_2_btc_addr(pubkey,ver):
    # 对pubKey计算sha256,结果再做ripemd160
    res_hash160 = single_ripemd160(single_sha256(pubkey))

    # 填充版本号,一般为00
    res_hash160 = ver + res_hash160

    # 计算两次sha256,所得结果的前8位作为校验值,填充到加密数据后
    res_dhash = double_sha256(res_hash160)
    res_dhash = res_hash160 + res_dhash[:8]

    # base58编码
    res_b58 = single_base58(res_dhash)
    return res_b58

###########################################################################################################
# pkhash_2_btc_addr(pkhash,ver):
#     通过公钥哈希值计算比特币地址
# params:
#     pkhash:公钥哈希值,即公钥计算SHA256和RIPEMD160后的值。数据类型为:str
#     ver:版本号,通常为"00"。数据类型为:str
# return:
#     返回比特币地址，数据类型为:str
###########################################################################################################
def pkhash_2_btc_addr(pkhash,ver):
    # 填充版本号,一般为00
    res = ver + pkhash

    # 计算两次sha256,所得结果的前8位作为校验值,填充到加密数据后
    res_dhash = double_sha256(res)
    res_dhash = res + res_dhash[:8]

    # base58编码
    res_b58 = single_base58(res_dhash)
    return res_b58

###########################################################################################################
# get_merkle_tree(merkle_leaves):
#     计算merkle tree，返回merkle tree全节点。最后一个节点为merkle root。
# params:
#     merkle_leaves:叶子节点。数据类型为:list
# return：
#     merkle tree全节点。数据类型为:list
###########################################################################################################
def get_merkle_tree(merkle_leaves):
    node_count = len(merkle_leaves)
    nodes = []
    for index in range(1, node_count + 1, 2):
        b1 = binascii.unhexlify(merkle_leaves[index - 1])[::-1]
        if index == node_count:
            b2 = binascii.unhexlify(merkle_leaves[index - 1])[::-1]
        else:
            b2 = binascii.unhexlify(merkle_leaves[index])[::-1]
        nodes.append(binascii.hexlify(sha256(sha256(b1 + b2).digest()).digest()[::-1]).decode())

    if len(nodes) != 1:
        new_nodes = get_merkle_tree(nodes)
        for n in new_nodes:
            merkle_leaves.append(n)
    else:
        merkle_leaves.append(nodes[0])
    return merkle_leaves

###########################################################################################################
# op_scriptsig_ecdsa_verify(sig,msg,pubkey,sigdecode = 'der'):
#     op_scriptsig验证，返回验证结果。
# params:
#     sig：签名数据。数据类型：str
#     msg：消息。数据类型：str
#     pubkey：公钥。数据类型：str
#     sigdecode：签名格式。默认为DER格式，数据类型：str
# return：
#     验证码结构。True or False
###########################################################################################################
def op_scriptsig_ecdsa_verify(sig,msg,pubkey,sigdecode = 'der'):
    try:
        if sigdecode == 'der':
            vk = VerifyingKey.from_string(bytes.fromhex(pubkey), curve=SECP256k1)
            res = vk.verify(binascii.unhexlify(sig.encode('ascii')), b(msg), hashfunc=hashlib.sha256,
                            sigdecode=util.sigdecode_der)
        else:
            vk = VerifyingKey.from_string(bytes.fromhex(pubkey), curve=SECP256k1)
            res = vk.verify(binascii.unhexlify(sig.encode('ascii')), b(msg), hashfunc=hashlib.sha256)
        return res
    except BadSignatureError:
        return False
    except Exception as ex:
        return False


import win32com.client
def WMIDateStringToDate(dtmDate):
    strDateTime = ""
    if (dtmDate[4] == 0):
        strDateTime = dtmDate[5] + '/'
    else:
        strDateTime = dtmDate[4] + dtmDate[5] + '/'
    if (dtmDate[6] == 0):
        strDateTime = strDateTime + dtmDate[7] + '/'
    else:
        strDateTime = strDateTime + dtmDate[6] + dtmDate[7] + '/'
        strDateTime = strDateTime + dtmDate[0] + dtmDate[1] + dtmDate[2] + dtmDate[3] + " " + dtmDate[8] + dtmDate[9] + ":" + dtmDate[10] + dtmDate[11] +':' + dtmDate[12] + dtmDate[13]
    return strDateTime

strComputer = "."
objWMIService = win32com.client.Dispatch("WbemScripting.SWbemLocator")
objSWbemServices = objWMIService.ConnectServer(strComputer,"root\cimv2")
colItems = objSWbemServices.ExecQuery("SELECT * FROM Win32_Service")
for objItem in colItems:
    if objItem.AcceptPause != None:
        print("AcceptPause: %s" % objItem.AcceptPause)
    if objItem.AcceptStop != None:
        print("AcceptStop: %s" % objItem.AcceptStop)
    if objItem.Caption != None:
        print("Caption: %s" % objItem.Caption)
    if objItem.CheckPoint != None:
        print("CheckPoint: %s" % objItem.CheckPoint)
    if objItem.CreationClassName != None:
        print("CreationClassName: %s" % objItem.CreationClassName)
    if objItem.Description != None:
        print("Description: %s" % objItem.Description)
    if objItem.DesktopInteract != None:
        print("DesktopInteract: %s" % objItem.DesktopInteract)
    if objItem.DisplayName != None:
        print("DisplayName: %s" % objItem.DisplayName)
    if objItem.ErrorControl != None:
        print("ErrorControl: %s" % objItem.ErrorControl)
    if objItem.ExitCode != None:
        print("ExitCode: %s" % objItem.ExitCode)
    if objItem.InstallDate != None:
        print("InstallDate: %s" % WMIDateStringToDate(objItem.InstallDate))
    if objItem.Name != None:
        print("Name: %s" % objItem.Name)
    if objItem.PathName != None:
        print("PathName: %s" % objItem.PathName)
    if objItem.ProcessId != None:
        print("ProcessId: %s" % objItem.ProcessId)
    if objItem.ServiceSpecificExitCode != None:
        print("ServiceSpecificExitCode: %s" % objItem.ServiceSpecificExitCode)
    if objItem.ServiceType != None:
        print("ServiceType: %s" % objItem.ServiceType)
    if objItem.Started != None:
        print("Started: %s" % objItem.Started)
    if objItem.StartMode != None:
        print("StartMode: %s" % objItem.StartMode)
    if objItem.StartName != None:
        print("StartName: %s" % objItem.StartName)
    if objItem.State != None:
        print("State: %s" % objItem.State)
    if objItem.Status != None:
        print("Status: %s" % objItem.Status)
    if objItem.SystemCreationClassName != None:
        print("SystemCreationClassName: %s" % objItem.SystemCreationClassName)
    if objItem.SystemName != None:
        print("SystemName: %s" % objItem.SystemName)
    if objItem.TagId != None:
        print("TagId: %s" % objItem.TagId)
    if objItem.WaitHint != None:
        print("WaitHint: %s" % objItem.WaitHint)


import constants
import base_class

character_default_move_speed = 5 # pixels/tick
character_default_wall_cooldown = constants.framerate*15
character_boosted_move_speed = 8 # pixels/tick

default_effect_durations = {
    'speed' : 10*constants.framerate,
    'tripleshot' : 10*constants.framerate,
    'bulletspeed' : 10*constants.framerate,
    'points' : 10*constants.framerate,
    'ignorewalls' : 10*constants.framerate,
}

class Character(base_class.Base):

    image = constants.default_image
    sx = sy = 49
    wall_timer = 0 #ticks/frames
    current_move_speed = character_default_move_speed

    def __init__(self, pos):

        self.score = 0

        #pos:
        # 0 = left
        # 1 = right
        if pos==0:
            self.x = constants.frame_width*0.1
            self.y = constants.frame_height*0.45+constants.frame_start_y

        elif pos==1:
            self.x = constants.frame_width*0.85
            self.y = constants.frame_height*0.45+constants.frame_start_y

        self.orientation = pos

        self.effect_durations = {
            "speed": -1,
            "tripleshot": -1,
            "bulletspeed": -1,
            "points": -1,
            "ignorewalls": -1,
        }

    def show(self, window):
        window.blit(self.image, (self.x, self.y))

    def set_cooldown(self):
        self.wall_timer = character_default_wall_cooldown

    def tick(self):
        self.wall_timer -= 1
        if self.effect_durations["speed"] > -1: self.effect_durations["speed"] -= 1
        if self.effect_durations["tripleshot"] > -1: self.effect_durations["tripleshot"] -= 1
        if self.effect_durations["bulletspeed"] > -1: self.effect_durations["bulletspeed"] -= 1
        if self.effect_durations["points"] > -1: self.effect_durations["points"] -= 1
        if self.effect_durations["ignorewalls"] > -1: self.effect_durations["ignorewalls"] -= 1
        if self.effect_durations["speed"] < 1 and self.current_move_speed==character_boosted_move_speed:
            self.unboost_speed()

    def start_movement(self, direction):
        if direction == -1:
            self.dy = -self.current_move_speed
        if direction == 1:
            self.dy = self.current_move_speed

    def boost_speed(self):
        self.current_move_speed = character_boosted_move_speed
        self.effect_durations["speed"] = constants.framerate*10

    def unboost_speed(self):
        self.current_move_speed = character_default_move_speed

    def shoot(self, bullet_class, pos):
        if self.orientation == 0:
            orientation = 1
        else:
            orientation = 0

        vel_coeff = constants.bullet_default_velocity
        if self.effect_durations["bulletspeed"] > -1:
            vel_coeff = constants.bullet_boosted_velocity

        ignore_walls = False
        if self.effect_durations["ignorewalls"] > -1:
            ignore_walls = True

        bullets = [
            bullet_class(orientation, pos, vel_coeff, ignore_walls),
        ]

        if self.effect_durations["tripleshot"]>-1:
            bullets.append(
                bullet_class(orientation, (pos[0], pos[1]+40), vel_coeff, ignore_walls)
            )
            bullets.append(
                bullet_class(orientation, (pos[0], pos[1] - 40), vel_coeff, ignore_walls)
            )

        return bullets

    def boost_general(self, effect):
        self.effect_durations[effect] = default_effect_durations[effect]

    def score_multiplier(self):
        if self.effect_durations["points"] > -1: return 2
        else: return 1


#!/usr/bin/env python3

def insert_char(input, rules):
    new_input = dict(input)
    for seq in input:
        if input[seq] > 0:
            first = seq[0]+rules[seq]
            second = rules[seq]+seq[1]
            num = input[seq]

            new_input[seq] -= num
            new_input[first] += num
            new_input[second] += num
    return new_input

with open('./input/14_input.txt') as input_file:
    input = input_file.read().splitlines()

    start_seq = input[0]

    directions = input[2:]
    rules = {}

    for d in directions:
        d = d.split(' -> ')
        if d[0] not in rules.keys():
            rules[d[0]] = d[1]

    seq_freq = {key:0 for key in rules}

    for i in range(len(start_seq)-1):
        to_find = start_seq[i:i+2]
        seq_freq[to_find] += 1

    counter = 0
    while counter < 40:
        seq_freq = insert_char(seq_freq, rules)
        counter += 1

    letter_freq = {}

    for k,v in seq_freq.items():
        if k[0] in letter_freq:
            letter_freq[k[0]] += v//2
        else:
            letter_freq[k[0]] = v//2
        if k[1] in letter_freq:
            letter_freq[k[1]] += v//2
        else:
            letter_freq[k[1]] = v//2

    print(letter_freq)

    min_let = min(letter_freq, key=letter_freq.get)
    max_let = max(letter_freq, key=letter_freq.get)

    print(letter_freq[max_let] - letter_freq[min_let])


ready = True
while(1):
    while(ready):
        x = input('waiting for command : ')
        if x == 'start':
            print('send start to Pc2')
            ready = False
        if x == 'top':
            print('000000000000000 [x,y]')
    while(not ready):
        y = input('side of picture and degree: ').split()
        print(y)
        ready = True


import json
import requests
import pandas as pd
import sweetviz as sv
import pandas_profiling

def extract_data(url = "http://api.tvmaze.com/schedule/web?date=2020-12-"):
    data = []

    for i in range(1,32):
        url_api =  url + str(i).zfill(2)
        result = requests.get(url_api)
        dato = json.loads(result.text)
        with open("./json/2020-12-" + str(i) +'.json', 'w') as json_file:
            json.dump(dato, json_file)
        data.extend(dato)
    return data

def dataframe_episodes(data):

    episodes = []

    for episode in data:

        show_id = episode["_embedded"]["show"]["id"]

        episode_id = episode["id"]
        episode_name = episode["name"]
        episode_url = episode["url"]
        episode_season = episode["season"]
        episode_number = episode["number"]
        episode_type = episode["type"]
        episode_airdate = episode["airdate"]
        episode_airtime = episode["airtime"]
        episode_airstamp = episode["airstamp"]
        episode_runtime = episode["runtime"]
        episode_rating = episode["rating"]["average"]

        episode = {
            'show_id': show_id,
            'episode_id': episode_id,
            'name': episode_name,
            'url': episode_url,
            'season': episode_season,
            'number': episode_number,
            'type': episode_type,
            'airdate': episode_airdate,
            'airtime': episode_airtime,
            'airstamp': episode_airstamp,
            'runtime': episode_runtime,
            'rating': episode_rating,

        }

        episodes.append(episode)

    df_episodes = pd.DataFrame(episodes).reset_index(drop=True)
    return df_episodes

def dataframe_shows(data):

    shows = []

    for episode in data:

        show_id = episode["_embedded"]["show"]["id"]
        show_name = episode["_embedded"]["show"]["name"]
        show_url = episode["_embedded"]["show"]["url"]
        show_name = episode["_embedded"]["show"]["name"]
        show_type = episode["_embedded"]["show"]["type"]
        show_language = episode["_embedded"]["show"]["language"]
        show_genres = episode["_embedded"]["show"]["genres"]
        show_status = episode["_embedded"]["show"]["status"]
        show_runtime = episode["_embedded"]["show"]["runtime"]
        show_averageRuntime = episode["_embedded"]["show"]["averageRuntime"]
        show_premiered = episode["_embedded"]["show"]["premiered"]
        show_ended = episode["_embedded"]["show"]["ended"]
        show_officialSite = episode["_embedded"]["show"]["officialSite"]
        show_schedule_time = episode["_embedded"]["show"]["schedule"]["time"]
        show_schedule_days = episode["_embedded"]["show"]["schedule"]["days"]
        show_rating = episode["_embedded"]["show"]["rating"]["average"]
        show_weight = episode["_embedded"]["show"]["weight"]
        show_network = episode["_embedded"]["show"]["network"]
        try:
            show_webChannel_id = episode["_embedded"]["show"]["webChannel"]["id"]
        except:
            show_webChannel_id = []
        show_externals = episode["_embedded"]["show"]["externals"]
        try:
            show_image = episode["_embedded"]["show"]["image"]["original"]
        except:
            show_image = []
        show_summary = episode["_embedded"]["show"]["summary"]

        show = {
            'show_id': show_id,
            'name': show_name,
            "url": show_url,
            "type": show_type,
            "language": show_language,
            "genres": show_genres,
            "status": show_status,
            "runtime": show_runtime,
            "averageRuntime": show_averageRuntime,
            "premiered":show_premiered,
            "ended": show_ended,
            "officialSite": show_officialSite,
            "schedule_time": show_schedule_time,
            "schedule_days": show_schedule_days,
            "rating": show_rating,
            "weight": show_weight,
            "network": show_network,
            "webchannnel_id": show_webChannel_id,
            "externals": show_externals,
            "image": show_image,
            "summary": show_summary
        }

        shows.append(show)

    df_shows = pd.DataFrame(shows).drop_duplicates("show_id").reset_index(drop=True)
    return df_shows

def dataframe_webchannel(data):

    web_channels = []

    for episode in data:
        try:
            show_webChannel_id = episode["_embedded"]["show"]["webChannel"]["id"]
            show_webChannel_name = episode["_embedded"]["show"]["webChannel"]["name"]
            show_webChannel_country_name = episode["_embedded"]["show"]["webChannel"]["country"]["name"]
            show_webChannel_country_code = episode["_embedded"]["show"]["webChannel"]["country"]["code"]
            show_webChannel_country_timezone = episode["_embedded"]["show"]["webChannel"]["country"]["timezone"]
            show_webChannel_officialSite = episode["_embedded"]["show"]["webChannel"]["officialSite"]
        except:
            pass
        web_channel = {
            'id': show_webChannel_id,
            'name': show_webChannel_name,
            'country': show_webChannel_country_name,
            'code': show_webChannel_country_code,
            'timezone': show_webChannel_country_timezone,
            'officialSite': show_webChannel_officialSite,
        }

        web_channels.append(web_channel)

    df_webchannel = pd.DataFrame(web_channels).drop_duplicates("id").reset_index(drop=True)
    return df_webchannel

def profile_sv(df):
    analysis = sv.analyze(df)
    return analysis

def profile_shows(df):
    df = df[["show_id", "name", "url", "type", "language", "status", "runtime", "averageRuntime", "premiered"]]
    profile_shows= pandas_profiling.ProfileReport(df)
    profile_shows.to_file("df_shows.html")
    return df

def drop_missing(df):
    thresh = len(df) * 0.6
    df.dropna(axis=1, thresh=thresh, inplace=True)
    return df

def to_date(df):
    df["airstamp"] = df['airstamp'].str[:10]
    df["airstamp"] = df["airstamp"].apply(pd.to_datetime)
    df["airdate"] = df['airdate'].apply(pd.to_datetime)
    return df

def format_shows(df):
    df["premiered"] = df["premiered"].apply(pd.to_datetime)
    df['summary'] = df_shows['summary'].str.replace(r'<[^<]+?>', '')
    return df

def to_category(df):
    cols = df.select_dtypes(include='object').columns
    for col in cols:
        ratio = len(df[col].value_counts()) / len(df)
        if ratio < 0.05:
            df[col] = df[col].astype('category')
    return df

if __name__ == '__main__':
    datos = extract_data()
    #Dataframe Episodes
    dataframe_episodes = dataframe_episodes(datos)
    dataframe_episodes = drop_missing(dataframe_episodes)
    dataframe_episodes = to_date(dataframe_episodes)
    dataframe_episodes = to_category(dataframe_episodes)
    dataframe_episodes.to_csv('dataframe_episodes.csv', index=False)
    profile_episodes = profile_sv(dataframe_episodes)
    profile_episodes.show_html('dataframe_episodes.html')

    #Dataframe Shows
    df_shows = dataframe_shows(datos)
    df_shows = drop_missing(df_shows)
    df_shows = format_shows(df_shows)
    df_shows = to_category(df_shows)
    df_shows.to_csv('df_shows.csv', index=False)
    #profile_shows = profile_shows(df_shows)

    #Dataframe webchannel
    df_webchannel = dataframe_webchannel(datos)
    df_webchannel = drop_missing(df_webchannel)
    df_webchannel = to_category(df_webchannel)
    df_webchannel.to_csv('df_webchannel.csv', index=False)
    profile_webchannel = profile_sv(df_webchannel)
    profile_webchannel.show_html('df_webchannel.html')


def encode_range(r):
    i, j = r
    if i == j:
        return str(i)
    else:
        return f"{i}-{j}"

def encode(g):
    result = [[int(i), int(i)] for i in g]
    changed = True
    while changed:
        changed = False
        prev = [None, None]
        for i, r in enumerate(result):
            if prev[1] is not None and r[0] == prev[1] + 1:
                result[i][0] = prev[0]
                del result[i - 1]
                changed = True
                break
            else:
                prev = r
    return " ".join([encode_range(r) for r in result])

def decode(s):
    if s == "":
        return []
    result = []
    for r in s.split(" "):
        if "-" in r:
            a, b = r.split("-")
            result.extend(list(range(int(a), int(b) + 1)))
        else:
            result.append(int(r))
    return [str(i) for i in result]

if __name__ == "__main__":

    def test(a, b):
        c = encode(a)
        print(f'{a} => "{b}"')
        if c != b:
            print("ERROR!", c)
        if decode(encode(a)) != a:
            print("ENCODE-DECODE ERROR!")

    test(["0", "1", "2"], "0-2")
    test(["0", "1", "2"], "0-2")
    test(["0", "1", "2", "3"], "0-3")
    test(["0"], "0")
    test(["1", "2", "4"], "1-2 4")
    test(["0", "1", "2", "7", "8", "10"], "0-2 7-8 10")
    test([], "")


import torch
import torchvision
from torch import nn

class MyBetaModel(nn.Module):
    def __init__(self):
        super(MyBetaModel, self).__init__()
        self.convModel = nn.Sequential(
            nn.Conv2d(3, 32, kernel_size=5, stride=1, padding=2),
            nn.MaxPool2d(2),
            nn.Conv2d(32, 32, 5, 1, 2),
            nn.MaxPool2d(2),
            nn.Conv2d(32, 64, 5, 1, 2),
            nn.MaxPool2d(2),
        )
        self.convFlatten = nn.Sequential(
            nn.Flatten(),
            nn.Linear(1024, 64, bias=True),
            nn.Linear(64, 10, bias=True),
        )

    def forward(self, inputs):
        temp = self.convModel(inputs)
        outputs = self.convFlatten(temp)
        return outputs

if __name__ == '__main__':
    processModel = MyBetaModel()
    torch.save(processModel, './BetaModel/myBetaModel.pth')  # save model

# process validation
    x = torch.rand(1, 3, 32, 32)
    processVAL = torch.Tensor(x)
    result = processModel(processVAL)
    print(result.shape)
    print(result.size)
    print(result)


import sqlite3
import typing

from timetable_loader import BaseTimetableLoader

def add_new_user(cursor: sqlite3.Cursor, user_id, group_id: int):
    cursor.execute("""
        INSERT INTO users VALUES (?, ?)
    """, (user_id, group_id))

def delete_timetable_for_group(cursor: sqlite3.Cursor, group_id: int):
    cursor.execute("""
        DELETE FROM timetable WHERE group_id = ?
    """, (group_id, ))

def upload_timetable_for_group(cursor: sqlite3.Cursor, timetable: BaseTimetableLoader):
    cursor.executemany(f"""
        INSERT INTO timetable VALUES (?, ?, ?, ?, ?, ?)
    """, timetable)

def get_timetable_for_group_and_day(cursor: sqlite3.Cursor, group_id: int, weekday: str):
    return cursor.execute("""
        SELECT subject, tutor, place, time
        FROM timetable
        WHERE group_id = ? AND weekday = ?
    """, (group_id, weekday)).fetchall()


import gym
import numpy as np

from keras_ppo_icm import Agent

if __name__ == '__main__':
    #env_name = 'MountainCar-v0'
    env_name = 'CartPole-v1'
    env = gym.make(env_name)
    agent = Agent(
        input_shape=env.observation_space.shape,
        action_num=env.action_space.n,
        alpha=1e-3,
        beta=5e-3,
        gamma=0.99,
        eta=30,
        icm_alpha=1e-3,
        icm_beta=0.2,
        entropy_coef=.1,
        entropy_decay=0.999)
    from tensorflow.keras.utils import plot_model
    plot_model(agent.actor, to_file='actor_model.png', show_shapes=True)
    plot_model(agent.critic, to_file='critic_model.png', show_shapes=True)
    plot_model(agent.icm, to_file='icm_model.png', show_shapes=True)
    episode_num = 0
    solved = False
    total_steps = 0
    total_rewards = []
    while not solved:
        state = env.reset()
        done = False
        running_reward = 0
        train_step = 0
        while not done:
            state, reward, done, _ = agent.step(env, state)
            running_reward += reward
            train_step += 1
            #env.render()
        actor_loss, critic_loss, icm_loss = agent.learn()
        total_rewards.append(running_reward)
        total_rewards = total_rewards[-100:]
        mean_reward = np.mean(total_rewards)
        print(
            f'Episode: {episode_num: 6d} ({train_step: 3d}), '
            f'Mean Reward: {mean_reward: 4.0f} ({running_reward: 4.0f}), '
            f'Actor Loss: {actor_loss:0.5f}, '
            f'Critic Loss: {critic_loss:0.5f}, '
            f'ICM Loss: {icm_loss:0.5f}'
        )
        if episode_num % 100 == 0:
            agent.save_model(
                f'{env_name.lower()}_actor.h5',
                f'{env_name.lower()}_critic.h5',
                f'{env_name.lower()}_icm.h5'
            )
        if mean_reward >= 500:
            solved = True
            agent.save_model(
                f'{env_name.lower()}_actor.h5',
                f'{env_name.lower()}_critic.h5',
                f'{env_name.lower()}_icm.h5'
            )
            print(f'Solved after {episode_num} ({total_steps} steps)')
        total_steps += train_step
        episode_num += 1


with open('day22.txt') as file:
	lines = [line.strip() for line in file.readlines()]

def parse_commands(lines, min, max):
	commands = []
	for line in lines:
		command, coords_string = line.split()
		coords_separate_string = [coord[2:] for coord in coords_string.split(',')]
		cube = tuple((int(min), int(max) + 1) for min, max in [coord.split('..') for coord in coords_separate_string])
		outside = False
		for minv, maxv in cube:
			if minv < min or minv > max or maxv < min or maxv > max:
				outside = True
				break
		if outside:
			continue
		commands.append((command, cube))
	return commands

def overlap(range1, range2):
	min1, max1 = range1
	min2, max2 = range2
	p1 = max(min1, min2)
	p2 = min(max1, max2)
	p2 = max(p1, p2)
	return (p1, p2)

def intersect(cube1, cube2):
	return (
		overlap(cube1[0], cube2[0]),
		overlap(cube1[1], cube2[1]),
		overlap(cube1[2], cube2[2]))

def volume(cube):
	(min1, max1), (min2, max2), (min3, max3) = cube
	return (max1 - min1) * (max2 - min2) * (max3 - min3)

def activate(commands):
	on_cubes = []
	off_cubes = []
	on_volume = 0
	for command, cube in commands:
		on, off = len(on_cubes), len(off_cubes)
		if command == 'on':
			on_volume += volume(cube)
			on_cubes.append(cube)
		for on_cube in on_cubes[:on]:
			i = intersect(cube, on_cube)
			v = volume(i)
			if v > 0:
				on_volume -= v
				off_cubes.append(i)
		for off_cube in off_cubes[:off]:
			i = intersect(cube, off_cube)
			v = volume(i)
			if v > 0:
				on_volume += v
				on_cubes.append(i)
	return on_volume

print('Part 1:', activate(parse_commands(lines, -50, +50)))
print('Part 2:', activate(parse_commands(lines, -1e300, +1e300)))


def solution(rows, columns, queries):
    li_matrix = [[x+(y*columns)+1 for x in range(columns)] for y in range(rows)]
    dir = [(1,0),(0,1),(-1,0),(0,-1)]
    answer = []
    for query in queries:
        sy,sx,ey,ex = query
        sx,sy,ex,ey = sx-1,sy-1,ex-1,ey-1
        size = 2*(ex-sx+1)+2*(ey-sy+1)-4
        cnt = 0
        dir_cur = 0
        cx, cy = sx, sy
        last = li_matrix[cy][cx]
        lowest = last
        while cnt < size:
            dx, dy = dir[dir_cur]
            nx, ny = cx + dx, cy+ dy
            if sx <= nx <= ex and sy <= ny <= ey and 0<=nx<columns and 0<=ny<rows:
                cnt += 1
                if lowest > li_matrix[ny][nx]:
                    lowest = li_matrix[ny][nx]
                li_matrix[ny][nx], last = last, li_matrix[ny][nx]
                cx, cy = nx, ny
            else:
                dir_cur += 1
        answer.append(lowest)
    return answer

print(solution(3, 2, [[1, 1, 3, 2]]))
# print(solution(	3, 3, [[1, 1, 2, 2], [1, 2, 2, 3], [2, 1, 3, 2], [2, 2, 3, 3]]))


# tests.py

from unittest import TestCase, main as unittest_main
from app import app
from unittest import TestCase, main as unittest_main, mock
from bson.objectid import ObjectId

sample_id = ObjectId('5d55cffc4a3d4031f42827a3')
sample_deck = { 'img': "static/red.jpeg",  'description': 'Red playing cards' }
sample_data = {
    'img': sample_deck['img'],
    'description': sample_deck['description']
}

sample_id = ObjectId('5d55cffc4a3d4031f42827a4')
sample_item = { 'img': "static/red.jpeg",  'description': 'Red playing cards', 'quantity': 1}
sample_item = {
    'img': sample_item['img'],
    'description': sample_item['description'],
    'quantity': sample_item['quantity']
}

class PlaylistsTests(TestCase):
    """Flask tests."""

    def setUp(self):
        """Stuff to do before every test."""
        # Get the Flask test client
        self.client = app.test_client()

        # Show Flask errors that happen during tests
        app.config['TESTING'] = True

    #tests shop home page
    def test_index(self):
        result = self.client.get('/index')
        self.assertEqual(result.status, '200 OK')
        self.assertIn(b'Deck of Cards', result.data)

    #tests cart view page
    def test_cart(self):
        result = self.client.get('/cart')
        self.assertEqual(result.status, '200 OK')
        self.assertIn(b'Currently in cart', result.data)

    #tests checkout page
    def test_new(self):
        result = self.client.get('/cart/checkout')
        self.assertEqual(result.status, '405 METHOD NOT ALLOWED')

if __name__ == '__main__':
    unittest_main()


def count(w):
    cnt = [0 for _ in range(26)]
    for c in w:
        if (c >= 'A' and c <= 'Z'):
            cnt[ord(c) - 65] += 1
        else:
            cnt[ord(c) - 97] += 1
    if (cnt.count(max(cnt)) > 1):
        print("?")
    else:
        print(chr(65 + cnt.index(max(cnt))))

word = input()
count(word)


import numpy as np
import glob
import sys
import cv2
import os
import json
import operator
from matplotlib import pyplot as plt

def get_data(directory):

    MIN_MATCH_COUNT = 10

    img1 = cv2.imread('data/original.jpg',0) #queryImage

    # Initiate SIFT detector
    sift = cv2.xfeatures2d.SIFT_create()

    # find the keypoints and descriptors with SIFT
    kp1, des1 = sift.detectAndCompute(img1,None)

    FLANN_INDEX_KDTREE = 0
    index_params = dict(algorithm = FLANN_INDEX_KDTREE, trees = 5)
    search_params = dict(checks = 5)

    flann = cv2.FlannBasedMatcher(index_params, search_params)

    all_images_to_compare = []
    allmatches={}
    titles = []
    for f in glob.iglob("database\*"):
        image = cv2.imread(f)
        titles.append(f)
        all_images_to_compare.append(image)
    for image_to_compare, title in zip(all_images_to_compare, titles):
        kp2, des2 = sift.detectAndCompute(image_to_compare,None)
        matches = flann.knnMatch(des1,des2,k=2)

        # store all the good matches as per Lowe's ratio test.
        good = []
        #print(matches)
        for m,n in matches:
            if m.distance < 0.7*n.distance:
                good.append(m)
        '''allmatches.append(good)
    best=allmatches.sort()
    for i in best:
        print(i)
    print(type(allmatches))'''
        if len(good)>0:
            #print("Enough matches are found - %d" % (len(good)))
            #print(title)
            allmatches[title]=len(good)

    sorted_d = sorted(allmatches.items(),key = operator.itemgetter(1), reverse=True)
    arr = []
    for s in sorted_d[:3]:
        arr.append(s[0])
        #cv2.imshow('Output',s[0])
    arr1 = []
    for x in arr:
        y = x.split("\\")
        arr1.append(y)
    return json.dumps(arr1)

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


def cycle_length(num):
    while num % 2 == 0:
        num //= 2
    while num % 5 == 0:
        num //= 5
    if num == 1:
        return 0
    remainder = 1
    length = 0
    while True:
        remainder = (remainder * 10) % num
        length += 1
        if remainder == 1:
            return length

def max_cycle_length(limit):
    max_length = 0
    max_d = 0
    for d in range(1, limit):
        len = cycle_length(d)
        if len > max_length:
            max_length = len
            max_d = d
    return max_d, max_length

print(max_cycle_length(1000))


import numpy as np
from gym.utils import seeding
import math
import matplotlib.pyplot as plt
from maze import MazeWorldSmall

def randargmax(b, np_random=None):
    if np_random is None:
        np_random = np.random
    return np_random.choice(np.flatnonzero(b == b.max()))

class Agent(object):
    def __init__(self, env, seed=None):
        self.env = env
        self.np_random, _ = seeding.np_random(seed)

    @property
    def n_states(self):
        return self.env.observation_space.n

    @property
    def n_actions(self):
        return self.env.action_space.n

    def act(self, s, explore):
        raise NotImplementedError

    def update(self, s, a, s1, r, done, verbose=False):
        raise NotImplementedError

    def close(self):
        pass

# No function approximation
# So it's just thinking about value and RL
class TabularQLearningAgent(Agent):
    def __init__(
            self,
            action_space,
            observation_space,
            gamma,
            lr,
            seed=None):

        super().__init__(env=None, seed=seed)
        n = observation_space.n
        m = action_space.n
        self.Q = np.zeros((n, m))

        self.training_episode = 0
        self.lr = lr
        # self._boltzmann_schedule = boltzmann_schedule

        self.gamma = gamma

    def act(self, s, eps):
        # Break ties randomly.
        best_a = randargmax(self.Q[s, :], self.np_random)
        if eps == 0:
            return best_a

        # Epsilon-greedy action selection
        if self.np_random.random_sample() > eps:
            return best_a
        else:
            return self.np_random.choice(range(len(self.Q[s, :])))

    def step(self, s, a, r, s1, done):
        self.update(s, a, r, s1, done)

    def get_q_values(self, s):
        return self.Q[s, :]

    def update(self, s, a, r, s1, done, verbose=False):
        if verbose:
            print(a)
            print({
                'before': self.Q[s, :],
            })
        # update_q_value = q_table[action, state] + alpha * (reward + (gamma_discount * next_state_value) - q_table[action, state])

        self.Q[s, a] += self.lr * (r + self.gamma * np.max(self.Q[s1, :]) - self.Q[s, a])
        if verbose:
            print({'after': self.Q[s, :]})

        if done:
            self.training_episode += 1

    def save(self, path):
        # we are not saving
        np.savez_compressed(path, Q=self.Q, training_episodes=self.training_episode)

    def load(self, path):
        obj = np.load(path)
        self.Q = obj['Q']
        self.training_episode = obj['training_episodes']

    def visualize(self):
        print(self.Q)

# we pretend this is the Stable-baselines training loop that we are not allowed to change
def train(agent, env, n_episodes=20, max_step=10,
          eps_start=1.0, eps_end=0.01, eps_decay=0.9, eval_render=True):

    eps = eps_start

    rewards = []
    for episode in range(n_episodes):
        state = env.reset()
        score, done, step_cnt = 0, False, 0
        while not done and step_cnt <= max_step:
            action = agent.act(state, eps=eps)
            next_state, reward, done, _ = env.step(action)
            agent.step(state, action, reward, next_state, done)

            score += reward
            step_cnt += 1
            state = next_state
        eps = max(eps_end, eps_decay * eps)
        rewards.append(score)

    if eval_render:
        state = env.reset()
        score, step_cnt, done = 0, 0, False
        env.render()
        while not done and step_cnt < max_step:
            action = agent.act(state, eps=0)
            next_state, reward, done, _ = env.step(action)
            score += reward
            state = next_state
            step_cnt += 1
            env.render()

    # a plot on reward should be average across all training instances
    return rewards

def plot_average_corr_training_reward():
    n_episodes = 100
    num_of_runs = 100
    avg_rewards = np.zeros(n_episodes)
    for _ in range(num_of_runs):
        env = MazeWorldSmall(program=None)  # correct env
        agent = TabularQLearningAgent(env.action_space,
                                      env.observation_space,
                                      gamma=0.9, lr=0.5,
                                      seed=12345)
        rewards = train(agent, env, n_episodes, eps_end=0, eval_render=False, max_step=10)  # max_step=8
        avg_rewards += np.array(rewards)

    # expected highest reward is 9 (because we have 10% of not getting any reward)
    avg_rewards = avg_rewards / num_of_runs
    plt.plot(avg_rewards)
    plt.hlines(y=9, xmin=0, xmax=n_episodes, linestyle='--') # color ='r',
    plt.xlabel("Episodes")
    plt.ylabel("Reward")
    plt.title(f"Average across {n_episodes} runs, episodic reward")
    plt.show()

def run_once():
    env = MazeWorldSmall(program=None) # correct env
    agent = TabularQLearningAgent(env.action_space,
                                  env.observation_space,
                                  gamma=0.9, lr=0.5,
                                  seed=12345)
    # 20 episodes won't work...ha
    train(agent, env, 100, eval_render=True, max_step=8)

# The purpose to reset (evaluate continously) is because
# some games after failing, does not respawn correctly, or reset the game into playable condition
def evaluate_continuously(env, agent, max_step, num_balls_win, eps, finish_reward=100):

    total_reward, step_cnt = 0, 0
    total_win, total_loss = 0, 0
    while (max(total_win, total_loss) < num_balls_win) and step_cnt < max_step:
        score, done = 0, False
        state = env.reset()
        while not done and step_cnt <= max_step:
            action = agent.act(state, eps=eps)
            next_state, reward, done, _ = env.step(action)
            score += reward
            total_reward += reward

            state = next_state
            step_cnt += 1
            # print(step_cnt, score)

        if reward == 10:
            total_win += 1
        elif reward == -5:
            total_loss += 1

    if total_win == 3:
        total_reward += finish_reward
    elif total_loss == 3:
        total_reward -= finish_reward

    return total_reward, total_win, total_loss

# now we are outside the training loop, we can collect data however we want
def execute_agent_collect_data(env, agent, max_step, num_balls_win, eps):
    # finish_reward=100
    # We have not implemented this...

    total_reward, step_cnt = 0, 0
    total_win, total_loss = 0, 0
    trajectory = []
    while (max(total_win, total_loss) < num_balls_win) and step_cnt < max_step:
        score, done = 0, False
        state = env.reset()
        while not done and step_cnt <= max_step:
            action = agent.act(state, eps=eps)
            next_state, reward, done, _ = env.step(action)

            trajectory.append((state, action, reward, next_state))

            score += reward
            total_reward += reward

            state = next_state
            step_cnt += 1
            # print(step_cnt, score)

        if reward == 10:
            total_win += 1
        elif reward == -5:
            total_loss += 1

    # Not implemented yet
    # if total_win == 3:
    #     total_reward += finish_reward
    # elif total_loss == 3:
    #     total_reward -= finish_reward

    return trajectory

def test_evaluate_continuously():
    env = MazeWorldSmall(program=None)  # correct env
    agent = TabularQLearningAgent(env.action_space,
                                  env.observation_space,
                                  gamma=0.9, lr=0.5,
                                  seed=12345)
    # 20 episodes won't work...ha
    train(agent, env, 150, eval_render=True, max_step=10)  # max_step=8
    for _ in range(30):
        # max_step = 30
        total_reward = evaluate_continuously(env, agent, max_step=30, num_balls_win=3, eps=0., finish_reward=20)
        print(total_reward)

def test_collect_traj():
    env = MazeWorldSmall(program=None)  # correct env
    agent = TabularQLearningAgent(env.action_space,
                                  env.observation_space,
                                  gamma=0.9, lr=0.5,
                                  seed=12345)
    # 20 episodes won't work...ha
    train(agent, env, 150, eval_render=True, max_step=10)  # max_step=8
        # max_step = 30
    traj = execute_agent_collect_data(env, agent, max_step=30, num_balls_win=3, eps=0.)

    print(traj[-5:])

if __name__ == '__main__':
    pass
    # run_once()
    # plot_average_corr_training_reward()
    # test_evaluate_continuously()

    test_collect_traj()


import pandas as pd
import os

def extractDataFromMETA():
    data = pd.read_excel(r'COVID-CT-MetaInfo.xlsx')
    df = pd.DataFrame(data, columns=[
        'File name', 'Age', 'Gender', 'Location', 'Medical history', 'Severity'])
    return df

def extractTrainedFileName():
    trainedPath = []
    for filename in os.listdir('data/CT_COVID'):
        trainedPath.append(filename)
    return trainedPath

# This method return a list of dicts with the extracted, crossed data of images in training
def extractTrainedData():
    df = extractDataFromMETA()
    trainedPaths = extractTrainedFileName()
    for index, row in df.iterrows():
        if row['File name'] not in trainedPaths:
            df.drop(index, inplace=True)
    dataDict = df.to_dict('records')
    ctr = 0
    for each in dataDict:
        ctr += 1
        each.update({'index': ctr})
    return dataDict