import os
import shutil

from beartype.typing import Union, Optional, Tuple

from chatllama.rlhf.config import (
    Config,
    ConfigActor,
    ConfigCritic,
    ConfigReward,
)
from chatllama.rlhf.model_list import hf_models

ConfigType = Union[Config, ConfigActor, ConfigCritic, ConfigReward]

class ModelLoader:
    """Class to load and save models and their checkpoints during training."""

    def __init__(
        self,
    ) -> None:
        pass

    @staticmethod
    def get_training_stats_path(config: ConfigType) -> str:
        """Method to get the path to the training stats file. Used when saving

        Args:
            config (ConfigType): the config object
        """
        model_folder, model_name, path = ModelLoader.get_model_path(
            config, is_checkpoint=True
        )
        stat_path = os.path.join(model_folder, "training_stats.json")
        return stat_path

    @staticmethod
    def look_for_last_checkpoint(
        model_folder: str,
        model_name: str,
    ) -> Optional[str]:
        """Method to look for the last checkpoint in the model folder
        checkpoint are saved as {model_name}_epoch_{current_epoch}.pt

        Args:
            model_folder (str): the folder where the checkpoints are saved
            model_name (str): the name of the model
        """
        # remove .pt to model name
        model_name = model_name.split(".")[0]
        checkpoints = [
            f for f in os.listdir(model_folder) if f.startswith(model_name)
        ]
        if len(checkpoints) == 0:
            return None
        else:
            checkpoints = sorted(checkpoints)
            # get last checkpoint
            last_checkpoint = checkpoints[-1]
            return last_checkpoint

    @staticmethod
    def look_for_checkpoint_by_name(
        model_folder: str,
        checkpoint_name: str,
    ) -> Optional[str]:
        """Method to look for a particular checkpoint in the model folder
        checkpoint are saved as
        {model_name}_epoch_{current_epoch}_steps_{current_steps}.pt

        Args:
            model_folder (str): the folder where the checkpoints are saved
            checkpoint_name (str): the name of the checkpoint
        """
        # look for a file named checkpoint_name in the model folder
        path = os.path.join(model_folder, checkpoint_name)
        if os.path.exists(path):
            return checkpoint_name
        else:
            return None

    @staticmethod
    def get_checkpoint_name(config: ConfigType) -> str:
        if isinstance(config, Config):
            return config.trainer.checkpoint_name
        else:
            return config.checkpoint_name

    @staticmethod
    def get_base_model_folder_from_config(config: ConfigType) -> str:
        if isinstance(config, ConfigActor) or isinstance(config, ConfigReward):
            return config.model_folder
        elif isinstance(config, Config):
            return config.actor.model_folder
        else:
            raise ValueError(
                "Config type not recognized during saving or loading"
            )

    @staticmethod
    def get_model_type_from_config(config: ConfigType) -> str:
        if isinstance(config, ConfigReward):
            # here use ad-hoc flag from config to distinguish between
            #  reward and critic
            if config.is_reward:
                return "reward"
            else:
                return "critic"
        elif isinstance(config, ConfigActor):
            return "actor"
        elif isinstance(config, Config):
            return "actor_rl"

    @staticmethod
    def get_model_name_from_config(config: ConfigType) -> str:
        model_name = None
        if isinstance(config, Config):
            model_name = config.actor.model
        elif isinstance(config, ConfigReward) or isinstance(
            config, ConfigActor
        ):
            model_name = config.model
        if model_name in hf_models:
            return os.path.split(model_name)[-1]
        if model_name is None:
            raise ValueError("Model name not found")
        return model_name

    @staticmethod
    def delete_old_checkpoints(
        model_folder: str, model_name: str, n_ckp_to_keep: int = 5
    ):
        """Method to discard old checkpoints, keeping only the last
        n_ckp_to_keep

        Args:
            model_folder (str): the folder where the checkpoints are saved
            model_name (str): the name of the model
            n_ckp_to_keep (int): the number of checkpoints to keep
        """

        # remove .pt to model name
        model_name = model_name.split(".")[0]
        checkpoints = [
            f for f in os.listdir(model_folder) if f.startswith(model_name)
        ]
        if len(checkpoints) == 0:
            return
        else:
            checkpoints = sorted(checkpoints)
            # check if the number of checkpoint is greater than 5
            if len(checkpoints) > n_ckp_to_keep:
                for c in checkpoints[:-n_ckp_to_keep]:
                    checkpoint_path = os.path.join(model_folder, c)
                    os.remove(checkpoint_path)

    @staticmethod
    def get_model_path(
        config: ConfigType,
        is_checkpoint: bool = False,
        current_epoch: Optional[int] = None,
        current_step: Optional[int] = None,
        max_epochs: int = 1_000_000_000,
        max_steps: int = 1_000_000_000,
    ) -> Tuple[str, str, Optional[str]]:
        """Method to get the path to the right model file. Used when saving
        the model.
        The hierarchy of the model folder is:
        -- model_folder: here store the models trained, for each type of model
                        there is a dedicated folder
            -- actor
            -- critic
            -- reward
            -- actor_rl
            -- checkpoints: here store the checkpoints during training, for
                            each type of model there is a dedicated folder
                -- actor
                -- critic
                -- reward
                -- actor_rl

        Args:
            config (ConfigType): the config object, contains info of the model
            is_checkpoint (bool): if True, the path is for a checkpoint
            current_epoch (Optional[int]): the current epoch, used to create
                the checkpoint name. If is_checkpoint is True, and
                current_epoch is None, return just the folder and the simple
                model name for the possible checkpoint.
            current_step (Optional[int]): the current step, used to create
                the checkpoint name.
            max_epochs (Optional[int]): the maximum number of epochs, used to
                create the checkpoint name.
            max_steps (Optional[int]): the maximum number of steps, used to
                create the checkpoint name.

        Returns:
            model_folder (str): the folder where the model is saved
            model_name (str): the name of the model
            path (Optional[str]): the path to the model. If is_checkpoint is
                True, and current_epoch is None, return None
        """
        model_folder = ModelLoader.get_base_model_folder_from_config(config)

        # Add the checkpoint path if necessary
        if is_checkpoint:
            model_folder = os.path.join(model_folder, "checkpoints")

        # Create the folder for the model type
        #  (Actor, Critic, Reward, Actor_RL)
        model_type = ModelLoader.get_model_type_from_config(config)
        model_folder = os.path.join(model_folder, model_type)

        # Make the path if not exists
        if os.path.exists(model_folder) is False:
            os.makedirs(model_folder, exist_ok=True)
            print(f"Model folder does not exist. Creating it: {model_folder}")

        # Create the model name
        model_name = ModelLoader.get_model_name_from_config(config)

        # If is a checkpoint and current epoch are available
        # extend the model name with the epoch, if none epoch is provided
        # just return the simple model name
        if is_checkpoint and current_epoch is not None:
            # number of characters to store the checkpoints
            n_char = max(len(str(max_epochs)), len(str(max_steps)))
            # create the string epoch such that it is always the same length
            # equalt to n_char (i.e. 00000001) necessary for sorting
            string_epoch = str(current_epoch)
            string_epoch = "0" * (n_char - len(string_epoch)) + string_epoch
            string_epoch = f"_epoch_{string_epoch}"
            if current_step is not None:
                string_step = str(current_step)
                string_step = "0" * (n_char - len(string_step)) + string_step
                string_step = f"_step_{string_step}"
                model_name = f"{model_name}{string_epoch}{string_step}.pt"
            else:
                model_name = f"{model_name}{string_epoch}.pt"
        else:
            model_name = f"{model_name}.pt"

        # if the epoch is not provided, and it is a checkpoint
        # is impossible to know the path to the file.
        # but we can know the model folder and the model name
        if is_checkpoint and current_epoch is None:
            path = None
        else:
            path = os.path.join(model_folder, model_name)
        return model_folder, model_name, path

    @staticmethod
    def check_model_path(
        config: ConfigType,
        is_checkpoint: bool = False,
        current_epoch: Optional[int] = None,
        current_step: Optional[int] = None,
    ) -> Optional[int]:
        """Method to check if the model path exists to load models
        or checkpoints.

        Args:
            config (ConfigType): the config object, contains info of the model
            is_checkpoint (bool): if True, the path is for a checkpoint
            current_epoch (Optional[int]): the current epoch.
                is is_checkpoint is True, and current_epoch is None,
                it will look for the last checkpoint and return it.

        Returns:
            path (Optional[str]): the path to the model. If is_checkpoint is
                True, and current_epoch is None, search for the last checkpoint
                and return it. If no checkpoint is found, return None.
            epoch (Optional[int]): the epoch of the checkpoint if an actual
                checkpoint is found. If no checkpoint is found, return None.
        """
        model_folder, model_name, path = ModelLoader.get_model_path(
            config,
            is_checkpoint,
            current_epoch,
        )

        # If i am looking for a checkpoint.
        if is_checkpoint and current_epoch is None:
            # If the checkpoint is specified by name use it
            checkpoint_name = ModelLoader.get_checkpoint_name(config)
            if checkpoint_name is not None:
                checkpoint = ModelLoader.look_for_checkpoint_by_name(
                    model_folder, checkpoint_name
                )
            else:
                checkpoint = ModelLoader.look_for_last_checkpoint(
                    model_folder, model_name
                )
            if checkpoint is not None:
                path = os.path.join(model_folder, checkpoint)
                # Get the epoch number from the checkpoint name

        if path is not None:
            if os.path.exists(path) is False:
                path = None

        if path is None:
            if is_checkpoint:
                checkpoint_name = ModelLoader.get_checkpoint_name(config)
                if checkpoint_name is not None:
                    print(
                        f"No checkpoint found at {model_folder} "
                        f"with name {config.checkpoint_name}"
                    )
                else:
                    print(
                        f"No previous checkpoint found at "
                        f"{model_folder} for {model_name}"
                    )
            else:
                print(
                    f"No previous model found at "
                    f"{model_folder} for model {model_name}"
                )
        else:
            if is_checkpoint:
                # the name is modelname_epoch_00000001_step_00000001.pt
                # or modelname_epoch_00000001.pt
                if "_step_" in path:
                    epoch = int(path.split("_epoch_")[-1].split("_")[0])
                    step = int(path.split("_step_")[-1].split(".")[0])
                    print(
                        f"Found checkpoint for epoch {epoch + 1},"
                        f" step {step + 1}..."
                    )
                else:
                    epoch = int(path.split("_epoch_")[-1].split(".")[0])
                    print(f"Found checkpoint for epoch {epoch + 1} ...")
            else:
                print(f"Found model at {path}")
        return path

    def init_critic_from_reward(config: ConfigCritic) -> None:
        """Method to initialize the critic from the reward model.
        If the critic folder is empty
        """

        if config.is_reward is True:
            raise ValueError(
                "The config should work for the Critic model,"
                "but the config seems to be for the Reward model"
            )

        # check that the critic folder is empty
        path = ModelLoader.check_model_path(config)
        _, _, critic_path = ModelLoader.get_model_path(config)
        if path is None:
            print("Initializing Critic from Reward model...")
            config.is_reward = True
            path = ModelLoader.check_model_path(config)
            if path is not None:
                _, _, reward_path = ModelLoader.get_model_path(config)
                # copy the file in reward_path to critic_path
                shutil.copy(reward_path, critic_path)
            else:
                print("Critic Model remains uninitialized")
        config.is_reward = False


#!/usr/bin/env python

# encoding: utf-8

'''
 * Create File crawler
 * Created by leixu on 2018/5/10
 * IDE PyCharm
'''
import asyncio
from enum import Enum
from concurrent.futures import ProcessPoolExecutor
import aiohttp
import os
from Coli.logger import logger
import multiprocessing

total_count = 0

class CrawlerStatus(Enum):
    FREE = 0
    BUSY = 1
    NOT_AVAILABLE = 2
    WAITING = 3

class CurrentArgInfo(object):
    pass

class FetchResult(object):
    def __init__(self):
        self.is_error = False
        self.error = None
        self.content = None
        self.ok = False

    def set_expection(self, error):
        self.is_error = True
        self.error = error

    def set_text_content(self, content):
        self.ok = True
        self.content = content

class Crawler(object):
    RUNNING = 0
    FREE = 0
    TOTAL = 0
    TOTAL_REQUEST = 0

    def __init__(self, loop: asyncio.AbstractEventLoop, queue, out_queue: asyncio.Queue):
        self.loop = loop
        self.status = CrawlerStatus.FREE
        self._s_command = None
        self.TOTAL += 1
        self.async_queue = queue
        self.out_async_queue = out_queue
        self.task = None

    def send_command(self, command):
        self._s_command = command

    def start(self):

        async def watch_new_url():
            while True:
                if self.status == CrawlerStatus.FREE:
                    url, kwargs = await self.async_queue.get()
                    await self.fetch(url, kwargs)

        self.task = self.loop.create_task(watch_new_url())

    def end_fetch(self):
        self.RUNNING -= 1
        self.FREE += 1
        self.TOTAL_REQUEST += 1
        self.status = CrawlerStatus.FREE
        logger.warn("Process" + str(os.getpid()) +
                    "         CurrentRequestIndex:" + str(self.TOTAL_REQUEST))

    async def fetch(self, url, kwargs):
        self.RUNNING += 1
        self.status = CrawlerStatus.BUSY

        async def _data_fetch_task(_url, _kwargs):
            async with aiohttp.ClientSession() as session:
                async with session.get(_url) as resp:
                    fr = FetchResult()
                    content = await resp.text()
                    fr.set_text_content(content)
                    self.out_async_queue.put_nowait(fr)

        try:
            await _data_fetch_task(url, kwargs)
            self.end_fetch()
        except Exception as e:
            print(e)
            fr = FetchResult()
            fr.set_expection(e)
            self.out_async_queue.put_nowait(fr)


import apa102

"""
Now for the actual rainbow cycle algorithm
"""
try:
    numPixels = 432-73 # 1/2 Strip plus one LED is broken
    strip = apa102.APA102(numPixels, 2) # Low brightness (2 out of max. 31)
    while True:  # Loop forever
        for j in range(numPixels<<8): # Shift the start of the rainbow across the strip
            for i in range(numPixels): # spread (or compress) one rainbow onto the strip
                # For a faster shift, add more than 1 * j per loop (e.g. + 2 * j)
                index = strip.wheel((((i << 8) // numPixels) + j*4) & 255)
                strip.setPixelRGB(i, index);
            strip.show()

except KeyboardInterrupt:  # Abbruch...
    print('Interrupted...')
    strip.clearStrip()
    print('Strip cleared')
    strip.cleanup()
    print('SPI closed')


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

def saturate_colors(colors, amount):
    """Saturate all colors."""
    if amount and float(amount) <= 1.0:
        for i, _ in enumerate(colors):
            if i not in [0, 7, 8, 15]:
                colors[i] = saturate_color(colors[i], float(amount))

    return colors


import numpy as np
import matplotlib.pyplot as plt

path = "https://raw.githubusercontent.com/OlafPBach/Advanced-Physics-Lab-2/main/Lab-2-Test-4.csv"
data = np.genfromtxt(path, delimiter=',', names =True,invalid_raise = False)
val1 = data['Test1']
time = data['Time1']

fig, ax = plt.subplots()
ax.plot(time*10**3,val1, color='blue')
ax.plot(0.48,3.1,"o",color='black')
ax.plot(0.86,6.3,"o",color='black')
ax.plot(1.21,9.15,"o",color='black')
ax.plot(1.58,11.5,"o",color='black')
ax.set_xlim(0,2)
ax.set_ylim(-1,13)
ax.set_xlabel('Time (ms)')
ax.set_ylabel('Amplitude (V)')
ax.set_title('Test 3')

plt.show()


from django.shortcuts import render, get_object_or_404 ,redirect
from django.utils import timezone
from .models import Post , Comment , Fungo , CsvFile
from .forms import PostForm , CommentForm , FungoForm , CsvFileForm
from django.contrib.auth.decorators import login_required

def post_list(request):
    posts = Post.objects.filter(published_date__lte=timezone.now()).order_by('published_date')
    return render(request, 'blog/post_list.html', {'posts': posts})

def post_detail(request, pk):
    post = get_object_or_404(Post, pk=pk)
    return render(request, 'blog/post_detail.html', {'post': post})

def post_new(request):
    if request.method == "POST":
        form = PostForm(request.POST)
        if form.is_valid():
            post = form.save(commit=False)
            post.author = request.user
            #post.published_date = timezone.now()
            post.save()
            return redirect('post_detail', pk=post.pk)
    else:
        form = PostForm()
    return render(request, 'blog/post_edit.html', {'form': form})

def post_edit(request, pk):
    post = get_object_or_404(Post, pk=pk)
    if request.method == "POST":
        form = PostForm(request.POST, instance=post)
        if form.is_valid():
            post = form.save(commit=False)
            post.author = request.user
            #post.published_date = timezone.now()
            post.save()
            return redirect('post_detail', pk=post.pk)
    else:
        form = PostForm(instance=post)
    return render(request, 'blog/post_edit.html', {'form': form})

def post_draft_list(request):
    posts = Post.objects.filter(published_date__isnull=True).order_by('created_date')
    return render(request, 'blog/post_draft_list.html', {'posts': posts})

def publish(self):
    self.published_date = timezone.now()
    self.save()

def post_publish(request, pk):
    post = get_object_or_404(Post, pk=pk)
    post.publish()
    return redirect('post_detail', pk=pk)

def post_remove(request, pk):
    post = get_object_or_404(Post, pk=pk)
    post.delete()
    return redirect('post_list')

def add_comment_to_post(request, pk):
    post = get_object_or_404(Post, pk=pk)
    if request.method == "POST":
        form = CommentForm(request.POST)
        if form.is_valid():
            comment = form.save(commit=False)
            comment.post = post
            comment.save()
            return redirect('post_detail', pk=post.pk)
    else:
        form = CommentForm()
    return render(request, 'blog/add_comment_to_post.html', {'form': form})

@login_required
def comment_approve(request, pk):
    comment = get_object_or_404(Comment, pk=pk)
    comment.approve()
    return redirect('post_detail', pk=comment.post.pk)

@login_required
def comment_remove(request, pk):
    comment = get_object_or_404(Comment, pk=pk)
    comment.delete()
    return redirect('post_detail', pk=comment.post.pk)

#############################################################################################

def fungo_list(request):
    fungos = Fungo.objects.filter().order_by('specie_genere')
    return render(request, 'blog/fungo_list.html', {'fungos': fungos})

def fungo_remove(request, pk):
    fungo = get_object_or_404(Fungo, pk=pk)
    fungo.delete()
    return redirect('fungo_list')

def fungo_new(request):
    if request.method == "POST":
        form = FungoForm(request.POST)
        if form.is_valid():
            fungo = form.save(commit=False)
            fungo.save()
            return redirect('fungo_list')#, pk=fungo.pk)
    else:
        form = FungoForm()
    return render(request, 'blog/fungo_edit.html', {'form': form})

def fungo_edit(request, pk):
    fungo = get_object_or_404(Fungo, pk=pk)
    if request.method == "POST":
        form = FungoForm(request.POST, instance=fungo)
        if form.is_valid():
            fungo = form.save(commit=False)
            fungo.save()
            return redirect('fungo_list' )#, pk=fungo.pk)
    else:
        form = FungoForm(instance=fungo)
    return render(request, 'blog/fungo_edit.html', {'form': form})

def fungo_detail(request, pk):
    fungo = get_object_or_404(Fungo, pk=pk)
    return render(request, 'blog/fungo_detail.html', {'post': post})

##############################################################################

####################        CSV Uploader

def csv_file_new(request):
    if request.method == "POST":
        form = CsvFileForm(request.POST)
        if form.is_valid():
            csv_file = form.save(commit=False)
            csv_file.save()
            return redirect('fungo_list')
    else:
        form = CsvFileForm()
    return render(request, 'blog/csv_file_edit.html', {'form': form})

def csv_file_edit(request, pk):
    csv_file = get_object_or_404(CsvFile, pk=pk)
    if request.method == "POST":
        form = CsvFileForm(request.POST, instance=csv_file)
        if form.is_valid():
            csv_file = form.save(commit=False)
            csv_file.save()
            return redirect('fungo_list' )
    else:
        form = CsvFileForm(instance=csv_file)
    return render(request, 'blog/csv_file_edit.html', {'form': form})


import ROOT as r

xsec = {"500To1000_TuneCUEP8M1": 0.109534, "1000To2000_TuneCUEP8M1": 0.0101229, "2000To4000_TuneCUEP8M1": 0.000474448, "4000To13000_TuneCUEP8M1": 5.505e-06,
        "500To1000_TuneCP2": 1.344e-01, "1000To2000_TuneCP2": 1.357e-02, "2000To4000_TuneCP2": 6.736e-04, "4000To13000_TuneCP2": 8.627e-06}
n_entries = {"500To1000_TuneCUEP8M1": 997600.0, "1000To2000_TuneCUEP8M1": 400000.0, "2000To4000_TuneCUEP8M1": 199400.0, "4000To13000_TuneCUEP8M1": 94000,
             "500To1000_TuneCP2": 983900.0, "1000To2000_TuneCP2": 392000.0, "2000To4000_TuneCP2": 200000.0, "4000To13000_TuneCP2": 100000}

f = {}
h = {}

for key in xsec.keys():
    f[key] = r.TFile("diphoton_mass_" + key + ".root")

out_file = r.TFile("tune_ratio.root", "recreate")

regions = ["all", "BB", "BE"]
bins = ["500To1000", "1000To2000", "2000To4000", "4000To13000"]
hist_types = ["TuneCUEP8M1", "TuneCUEP8M1_weighted", "TuneCP2"]
for region in regions:
    for key in f.keys():
        if "TuneCUEP8M1" in key:
            h[key + "_weighted"] = f[key].Get("gen/diphoton_mass_weighted_" + region)
            h[key + "_weighted"].Scale(xsec[key]/n_entries[key])
        h[key] = f[key].Get("gen/diphoton_mass_" + region)
        h[key].Scale(xsec[key]/n_entries[key])
        print(key, h[key].Integral())

    for hist_type in hist_types:
        for bin in bins:
            hist_name = bin + "_" + hist_type
            # clone first histogram of a given type; add the rest
            if hist_type not in h.keys():
                print(hist_name)
                h[hist_type] = h[hist_name].Clone()
            else:
                print(hist_name)
                h[hist_type].Add(h[hist_name])

    ratio = h["TuneCP2"].Clone("ratio_" + region)
    ratio.Divide(h["TuneCUEP8M1"])
    ratio.SetTitle(";m_{#gamma#gamma} (GeV);#sigma(CP2)/#sigma(CUEP8M1)")

    c = r.TCanvas("c", "c")
    ratio.GetYaxis().SetRangeUser(0., 5.)
    ratio.Draw()
    ratio.Write()

    ratio_weighted = h["TuneCP2"].Clone("ratio_weighted_" + region)
    ratio_weighted.Divide(h["TuneCUEP8M1_weighted"])
    ratio_weighted.SetMarkerColor(r.kRed)
    ratio_weighted.SetLineColor(r.kRed)
    ratio_weighted.Draw("same")
    ratio_weighted.Fit("pol0")
    ratio_weighted.Write()

    leg = r.TLegend(0.3, 0.5, 0.6, 0.85)
    leg.AddEntry(ratio, "Unweighted")
    leg.AddEntry(ratio_weighted, "Weighted to PDF from CP2")
    leg.SetBorderSize(0)
    leg.SetFillColor(0)
    leg.Draw()

    c.Print("tune_ratio_" + region + ".pdf")
    c.Print("tune_ratio_" + region + ".png")

out_file.Close()


# -*- coding: utf-8 -*-

#from apscheduler.schedulers.blocking import BlockingScheduler as Scheduler
#from apscheduler.schedulers.background import BackgroundScheduler as Scheduler

import apscheduler.events
import logging
import datetime
import time
import sys
from uuid import uuid4
import random

import socket
import fcntl
import struct

#import pickle
#import cloudpickle as pickle #不能处理_thread.lock
import dill as pickle  #不能处理six.with_metaclass(ABCMeta)继承的子类,从dispatch_table确认，dill处理的类型更多
#pickle.settings['recurse'] = True
#import copy_reg#python2
import copyreg
import types
import traceback

def err_listener(ev):
    if ev.exception:
        print(sys.exc_info())

#关于锁
#https://www.cnblogs.com/ironPhoenix/p/6048467.html
#https://redis.io/topics/distlock/

# 1 加锁成功、 0 失败
# expire 锁超时时间，建议为分布节点时间同步误差略大
def rlo(opener, key=None, owner=None, role=None, expire=3):
    assert role in ("work","standby"), "MutexScheduler.lock参数值错误，role有效值：work、standby！"
    script = "if KEYS[3]=='work' and redis.call('sismember', KEYS[1], KEYS[2])==1 or KEYS[3]=='standby' and redis.call('exists', KEYS[1])==1 then return 0 else redis.call('sadd', KEYS[1], KEYS[2]); if ARGV[1]>0 then redis.call('expire', KEYS[1], ARGV[1]); end return 1 end"
    #eval <script> 3 job_id1 scheduler_id standby 300
#    print(99999, job_id, scheduler_id, role)
    result = opener.register_script(script)(keys=[key, owner, role], args=[expire])
#    print(111111111,result,type(result))
    logging.info("role: %s", role)
    return result

# 1 释放成功 0 失败
def rle(opener, key=None, owner=None, role=None):
    assert role in ("work","standby"), "MutexScheduler.le参数值错误，role有效值：work、standby！"
    script = "return redis.call('srem', KEYS[1], KEYS[2])"
    result = opener.register_script(script)(keys=[key, owner], args=[])
    #eval <script> 2 job_id1 scheduler_id standby
#    print(333333333,result)
    return result

def rhb(opener, ip, now, key=None, **attrs):
    pass

#def lock(opener, job_id=None, scheduler_id=None, role=None):
##    print(job_id)
#    print('lock()')
#
#    #mongo
#    #now = datetime.datetime.now() - datetime.timedelta(seconds = 3)
#    #lck = opener.find_one({'name': 't'})
#
#    #redis
#    lck = opener.hgetall('lockstore')
#    if lck and 'update_time' in lck and lck['update_time']:
#        lck['update_time'] = datetime.datetime.strptime(lck['update_time'][:19], '%Y-%m-%d %H:%M:%S')
#
#    return lck
#
#def hb(ip, now, opener, job_id=None, **attrs):
##    print(job_id)
#    print('heartbeat()')
#    attrs['active_ip'] = ip
#    attrs['update_time'] = now
#    #mongo
#    #opener.update({'name': 't'}, {'$set': attrs}, upsert = True)
#    #redis
#    opener.hmset('lockstore', attrs)
#    #print(attrs)
#    #print(opener.hgetall('lockstore'))
#
#
#def le(lock_rec, job_id=None, scheduler_id=None, role=None):
#    #单实例redis锁
#    #set lock_key1 requestid_argv1 EX 30 NX
#    #set lock_key1 requestid_argv1 PX 30000 NX
#    #加锁
#    #eval "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end" 1 "lock_key1" "requestid_argv1"
#    #lock_key1存在且==requestid_argv1，删除/释放锁、否则释放失败。
#    #"if redis.call('get', KEYS[1])==ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end"
##    print(job_id)
#    if lock_rec:
##        print('active ip')
#        print('active ip', lock_rec)
#    else:
#         print('lock else')

#def get_ip(ifname):
#    name = socket.gethostname()
#    return socket.gethostbyname(name)
#
##    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
##    return socket.inet_ntoa(fcntl.ioctl(
##                            s.fileno(),
##                            0x8915, # SIOCGIFADDR
##                            struct.pack('256s', bytes(ifname[:15],'utf-8'))
##                            )[20:24]
##                        )

#def get_pickling_errors(obj,seen=None):
#    if seen == None:
#        seen = []
#    try:
#        state = obj.__getstate__()
#    except AttributeError:
#        return
#    if state == None:
#        return
#    if isinstance(state,tuple):
#        if not isinstance(state[0],dict):
#            state=state[1]
#        else:
#            state=state[0].update(state[1])
#    result = {}
#    for i in state:
#        try:
#            pickle.dumps(state[i],protocol=2)
#        except pickle.PicklingError:
#            if not state[i] in seen:
#                seen.append(state[i])
#                result[i]=get_pickling_errors(state[i],seen)
#    return result

def MutexSchedulerProxy(Scheduler):

    #todo: 当前的序列化方案，将code序列化，包括：self.role等数据，导致不恰当的行为？
    class MutexScheduler(Scheduler):
        def __init__(self, role, gconfig={}, ** options):
            assert role in ("work","standby"), "MutexScheduler.__init__参数值错误，role有效值：work、standby！"
            logging.getLogger().setLevel(logging.NOTSET) #todo: xxxx
            logging.info("") #todo: xxxx
            Scheduler.__init__(self, gconfig, ** options)
            self.uuid = uuid4().hex
            self.role = role #work:自己没有持有锁就可以获得锁、standby：任何人没有持有锁才可以获得锁
    #        self.ip = get_ip('eth0')
            self._logger.info("请确保调度器、锁、业务库，尽可能时间同步！")
            self._logger.info("Scheduler: %s, Role: %s", self.uuid,self.role)

    #    def __getstate__(self):
    #         return self.__dict__

    #    #添加telnet协议方便查看运行状态
    #    #@override
    #    def start(self):
    #        super(MutexScheduler, self).start()
    #        #todo:telnet
    ##        from twisted.internet import protocol
    ##        from scrapy.utils.reactor import listen_tcp
    ##        listen_tcp(123456, "localhost", self)

        #todo:执行锁
        #shards人工分片（数据分布不均匀时），否则，size自动分片（数据分布均匀时）
        def mutex_run(self, lock=None, lock_else=None, heartbeat=None,
                  unactive_interval=datetime.timedelta(seconds=30), opener=None, size=100, _shards=((1, 10),(11, 20))):
            def mutex_run_gen(func, job_id):
                def mtx_func(** options):
                    #待处理分片，从1开始
                    shard_id=1
                    shards=set((1,))
                    #记录分片扫描次数
                    shard_inc=1
                    uuid=uuid4().hex
                    while True:
                        #分片已经处理完
                        if not shards:
                            return 0
                        #锁分片：有待处理数据从头抢分片，没有待处理数据任务完成
                        while True:
                            try:
                                if shard_inc>10:
#                                    self._logger.warn("分片循环扫描过多！")
                                    pass
                                #人工分片
                                if _shards and len(shard_id)<=shard_id:
                                    shard_id=1
                                    shard_inc=shard_inc+1
                                #自动分片
                                elif 99999999<shard_id:
#                                    self._logger.warn("自动分片数过多！")
                                    pass
                                if lock(opener, job_id+shard_id+"_run", uuid, "standby", 0):
                                    shards.remove(shard_id)#移除处理的分片
                                    shard_id=shard_id+1#准备下一分片
                                    break
                                else:
                                    shards.add(shard_id)#记录未处理的分片
                                    shard_id=shard_id+1
                            except:
                                #上报错误
#                                self._logger.info("锁异常，未能加锁，请处理： %s", job_id+shard_id+"_run")
                                pass
                            #抢锁过程慢一点，随机暂停减少死锁
                            time.sleep(random.randint(1,100)/1000)
                        #处理人工分片参数
                        if _shards:
                            options.setdefault("shard", _shards[shard_id-1])
                        #处理自动分片参数
                        else:
                            options.setdefault("shard", (shard_id, shard_id*size))
                        #处理分片，干活
                        #必须：1、接收分片参数，2、返回是否有待处理记录数
                        cnt = func(**options) #返回是否有待处理记录数，如果还有待处理数据，则从头扫描
                        #释放锁    未释放的锁，会导致任务空转
                        for i in (1,2,3):
                            #非超时锁，释放失败必须额外处理
                            try:
                                if lock_else(opener, job_id+shard_id+"_run", uuid, "standby"):
                                    break
                            except:
                                #上报错误
    #                            self._logger.info("锁异常，未能释放，请清理： %s", job_id+shard_id+"_run")
                                pass
                            time.sleep(0.001)
                        if cnt>0:
                            #重置分片位置
                            shard_id=1
                            shard_inc=shard_inc+1
                        else:
                            #任务完成
                            return 0
                        #暂停一小会
                        time.sleep(1)

                return mtx_func

            self.mtx_run_gen = mutex_run_gen

            def inner(func):
                return func

            return inner

        #调度锁
        def mutex(self, lock=None, lock_else=None, heartbeat=None,
                  unactive_interval=datetime.timedelta(seconds=30), opener=None):
            def mutex_func_gen(func, job_id, uuid, role):
                #重要：不要引入外部thread\queue\等数据，降导致序列化错误
                def mtx_func(** options):
                    if lock:#装配
                        if lock(opener, job_id, uuid, role, unactive_interval): #加锁
                            result = func( ** options )#干活
                            #超时锁，释放失败影响不大
                            lock_else(opener, job_id, uuid, role) #释放
                            return result
                    else:#不装配
                        result = func(** options)#todo:执行job？
                        return result

                def ___mtx_func(** options):
    #                print(options)
                    if lock:#装配
                        #加锁 todo:以下操作需要原子化
                        lock_rec = lock(opener, job_id)
                        if 'schedulers' not in lock_rec or not lock_rec['schedulers']:
                            lock_rec['schedulers'] = set()
                        now = datetime.datetime.now()
    #                    print(lock_rec)
    #                    print(('update_time' in lock_rec and lock_rec['update_time'] and now - lock_rec['update_time'] >= unactive_interval))

                        # execute mutex job when the server is active, or the other server is timeout.
                        #role=='work' or 'standby'?
                        #验锁
                        if not lock_rec or (self.role=='work' and self.uuid not in lock_rec['schedulers']) or ('active_ip' in lock_rec and lock_rec['active_ip'] == ip) or ('update_time' in lock_rec and lock_rec['update_time'] and now - lock_rec['update_time'] >= unactive_interval):
                            #通过
    #                        print(3333)
                            if lock_rec:
                                del lock_rec['active_ip']
                                del lock_rec['update_time']

                            if not lock_rec:
                                lock_rec = {}

    #                        print(func)
                            lock_attrs = func( ** options )#todo:执行job？
    #                        print(lock_attrs)
                            if not lock_attrs:
                                lock_attrs = {}

                            # send heart beat
                            #print(344444)
                            if 'schedulers' not in lock_attrs or not lock_attrs['schedulers']:
                                lock_attrs['schedulers'] = set()
                            lock_attrs['schedulers'].add(self.uuid) #持锁人
                            #更新
                            heartbeat(opener, ip, now, job_id, ** lock_attrs)#todo:返回值写入lock？
                            return lock_attrs
                        else:
                            #未通过
                            #释放 todo：存在释放他人所拥有锁的风险
    #                        print(4444)
                            lock_else(lock_rec, job_id)
                    else:#不装配
                        #print(1111)
                        lock_attrs = func(** options)#todo:执行job？
                        return lock_attrs

    #            def _pickle_method(obj):
    ##                print(3233)
    ##                print(33333,obj)
    ##                exit()
    ##                pass
    #                return _thread.LockType, ()
    #            def _unpickle_method(func_name, obj, cls):
    #                print(777777777)
    #                return object
    #
    ##            print(55555)
    #            import _thread
    #            copyreg.pickle(_thread.LockType, _pickle_method, constructor_ob=_unpickle_method)#constructor_ob注册无效？
    #            copyreg.constructor(_unpickle_method)#constructor注册无效？

                return mtx_func

            self.mtx_func_gen = mutex_func_gen

            def inner(func):
                return func

            return inner

        #job.id
    #    @override
        def scheduled_job(self, ** options):
    #    def cron_schedule(self, ** options):
            def inner(func):
                if "id" not in options:
        #            traceback.print_stack()
                    job_id = uuid4().hex #todo:提前生成ID，便于JOB加锁
                    options['id'] = job_id
        #            options.setdefault("id", "{}.{}".format(func.__module__, func.__name__))
                else:
                    job_id = options['id']

                #todo:处理分片锁
                if hasattr(self, 'mtx_run_gen'):
                    func = self.mtx_run_gen(func, job_id)

                #处理任务锁
                if hasattr(self, 'mtx_func_gen'):
                    func = self.mtx_func_gen(func, job_id, self.uuid, self.role)

    #            print(func)
    #            import pickle
    #            import cloudpickle as pickle
    #            print(func)
    #            print(type(func))
    #            print(func is types.BuiltinMethodType)
    ##            def _pickle_method(m):
    ##                print(1111111)
    ##                return m, ()
    ##            copyreg.pickle(types.MethodType, _pickle_method)
    #            print(66666)
    #            sss=pickle.dumps(func)
    #            print(77777,pickle.loads(sss))
    #            exit()
    #            print(888888,job_id)
                func.job = self.add_job(func, ** options)
    #            print(func)
    #            print(func.job.id)
                return func
            return inner

    return MutexScheduler

# test
if __name__=='__main__':
    from apscheduler.schedulers.blocking import BlockingScheduler
    from apscheduler.schedulers.background import BackgroundScheduler
    import logging
    from framework.apscheduler.jsonsqlalchemy import JsonSQLAlchemyJobStore
    from apscheduler.jobstores.sqlalchemy import SQLAlchemyJobStore
    from apscheduler.jobstores.memory import MemoryJobStore
    from apscheduler.executors.pool import ThreadPoolExecutor, ProcessPoolExecutor
    executors = {
#    'default': ThreadPoolExecutor(20),
    'processpool': ProcessPoolExecutor(1)
    }
    jobstores = {
#    'default': MemoryJobStore(),
##    'mongo': MongoDBJobStore(),
#    #'default': SQLAlchemyJobStore(url='sqlite:///jobs.sqlite'),
#    'mysql': SQLAlchemyJobStore(url='mysql+mysqlconnector://root:12345678@localhost/scrapy_db',tablename='apscheduler_jobs')
#    'default': JsonSQLAlchemyJobStore(url='mysql+mysqlconnector://root:12345678@localhost/scrapy_db',tablename='apscheduler_jobs'),
    'mysql': JsonSQLAlchemyJobStore(url='mysql+mysqlconnector://root:12345678@localhost/scrapy_db',tablename='apscheduler_jobs')
    }

    sched = MutexSchedulerProxy(BlockingScheduler)("standby",jobstores=jobstores,executors=executors)

    #import pymongo
    #mongo = pymongo.Connection(host = '127.0.0.1', port = 27017)
    #lock_store = mongo['lockstore']['locks']

    import redis
    from redis import StrictRedis as Redis
    pool = redis.ConnectionPool(host = '127.0.0.1', port = 6379, db = 0, decode_responses=True)
    lock_store = Redis(connection_pool = pool)

    i = 0

#    @sched.cron_schedule(trigger='cron', second = '*')
    @sched.scheduled_job(trigger='cron', id="job11111111", replace_existing=True, kwargs={"aa":'lkjadslfkjsaldfkj',"bb":'bb'}, second = '*/1', jobstore='mysql')
#    @sched.mutex(lock = lock, heartbeat = hb, lock_else = le, opener=lock_store)
    @sched.mutex(lock = rlo, heartbeat = rhb, lock_else = rle, opener=lock_store, unactive_interval=30)
#    @sched.mutex_run(lock = rlo, heartbeat = rhb, lock_else = rle, opener=lock_store, unactive_interval=30, size=10, _shards=((1, 10),(11, 20)))
    # 由job向业务传递分片信息
    def job(aa="",bb="",shard=(1,10)):
        #待处理分片，从1开始
        shards=set((1,))
        shard_id=1
        while True:
            #分片已经处理完
            if not shards:
                return 0
            #锁分片
            while True:
                if rlo(lock_store, job_id, shard_id, 0):
                    shards.remove(shard_id)#移除处理的分片
                    shard_id=shard_id+1#准备下一分片
                    break
                else:
                    shards.add(shard_id)#记录未处理的分片
                    shard_id=shard_id+1
            #处理分片，确保分片参数有效覆盖任务数据 -- begin
            #select * from dual where state=0 and id>shard[0] and id<shard[1] order by updated
            items = ({"key":"val1"},{"key":"val2"})
            if items:
                for item in items:
#                    #收到退出信号
#                    if sigle=='exit':
#                        return 1
#                    #收到暂停信号
#                    elif sigle=='pause':
#                        return 2
#                    #收到恢复信号
#                    elif sigle=='resume':
#                        return 3
                    #todo: 干活
                    print(item)
                #通知框架是否有其他分片数据
                #items = select * from dual where state=0 limit 1;
#                return len(items)
            #处理分片，确保通知调度框架分片命中记录数 -- end
                #释放锁
                rle(lock_store, job_id, shard_id)
            else:
                #重置分片位置
                shard_id=1
#                return 0
            #暂停一小会
            time.sleep(10)

#    import pickle
#    print(job)
#    print(sched.mtx_func_gen())
#    print(pickle.dumps(job))
#    exit()
#    def ff(aa="aa", bb="bb"):
#        print(aa,bb)
#    ff=sched.mutex(lock = lock, heartbeat = hb, lock_else = le, opener=lock_store)
#    print(ff)
#    exit()

#    job=sched.scheduled_job(job,trigger='cron', kwargs={"aa":'aa111',"bb":'bb'}, second = '*/1')#todo:
#    print(job.job.id)

#    ii = 0
#
#    @sched.mutex(lock = lock, heartbeat = hb, lock_else = le, opener=lock_store)
##    @sched.cron_schedule(trigger='cron', second = '*')
#    @sched.scheduled_job(trigger='cron', second = '*/1')
#    # 由job向业务传递分片信息
#    def job2(**attr):
#        global ii
#        ii += 1
#        print(ii)

#    job = sched.add_job(func=job, kwargs={"aa":"aa","bb":"bb"}, trigger='cron', second='*/1')

    sched.add_listener(err_listener, apscheduler.events.EVENT_JOB_ERROR)

    sched.start()


import os.path
import numpy as np
import multiprocessing
from collections import OrderedDict
from subprocess import DEVNULL, STDOUT, check_call

#Decipher amount of simulated reads to suit x% of transcripts FPKM
def sim_amount(gene_list, fpkm_dict, num_read, total_len, percentile_val, fasta_dict, total_reps):
    #Get xth Percentile FPKM
    FPKM = []
    for gene in gene_list:
        FPKM.append(float(fpkm_dict[gene]))
    percentile_FPKM = np.percentile(np.array(FPKM),percentile_val)
    #Average fragment depth = (number of fragments x fragment size)/Total bases
    #Number of fragments per gene = average fragment depth x (cDNA length/fragment size)
    #FPKM = (Number of fragments per gene/(Number of reads/1000000))/(cDNA length/1000)
    #Merge and simplify
    #FPKM = (Number of fragments x 1000000000)/(Total bases x number of reads)
    #Number of fragments = (FPKM x Total bases x total num of fragments)/1000000000
    #Adjust "Total bases" by ratio of total_transcripts/number of genes
    #Number of fragments = (FPKM x Total bases x total num of fragments)/(1000000000) multiply by number of replicates  # x (total_transcripts/number of genes)
    sim1_num_frags = int((percentile_FPKM*total_len*num_read/2)/(1000000000))*total_reps  #*(len(fasta_dict)/len(gene_list))
    return sim1_num_frags, percentile_FPKM

#Decipher amount of simulated reads to suit x% of transcripts fragments
def sim_amount2(gene_list, fpkm_dict, total_len, percentile_val, total_reps, transcript_frag_dict, transcript_dict, cdna_size_dict):
    #Get xth Percentile FPKM
    FPKM_dict = OrderedDict()
    FPKM = []
    for gene in gene_list:
        FPKM_dict[gene] = float(fpkm_dict[gene])
    FPKM_tup_sort = sorted(FPKM_dict.items(), key=lambda x:x[1])
    for gene,fpkm in FPKM_tup_sort:
        FPKM.append(fpkm)
    percentile_index = int(len(FPKM)*(percentile_val/100)) - 1
    gene_name, percentile_FPKM = FPKM_tup_sort[percentile_index]
    for rep in transcript_frag_dict:
        last_rep_name = rep
    #Average fragment depth = (number of fragments x fragment size)/Total bases
    #Number of fragments per gene = average fragment depth x (cDNA length/fragment size)
    #FPKM = (Number of fragments per gene/(Number of reads/1000000))/(cDNA length/1000)
    #Merge and simplify
    #FPKM = (Number of fragments x 1000000000)/(Total bases x number of reads)
    #Number of fragments = (FPKM x Total bases x number of reads)/1000000000
    #Adjust "Total bases" by ratio of total_transcripts/number of genes
    #Number of fragments = (FPKM x Total bases x number of reads)/(1000000000)) multiply by number of replicates
    #Number of fragments = (Number of fragments per gene x Total bases)/cDNA length) multiply by number of replicates
    try:
        sim1_num_frags = int((transcript_frag_dict[last_rep_name]['@'+transcript_dict[gene_name]+'-e']*total_len)/cdna_size_dict[transcript_dict[gene_name]])*total_reps
    except:
        sim1_num_frags = int((transcript_frag_dict[last_rep_name]['@'+transcript_dict[gene_name]+'-i']*total_len)/cdna_size_dict[transcript_dict[gene_name]])*total_reps
    return sim1_num_frags, percentile_FPKM

#Chunk list generator
def split_chunks(a, n):
    k, m = divmod(len(a), n)
    return list(a[i * k + min(i, m):(i + 1) * k + min(i + 1, m)] for i in range(n))

#Split reference fasta to multiple fasta files according to number of threads
def split_fasta(output_dir, ref, num_threads, num_fasta):
    fasta = os.path.join(output_dir, ref)
    tmp_dict = OrderedDict()
    tmp_list = []
    for index in range(num_threads):
        tmp_dict[index] = open(os.path.join(output_dir, 'tmp' + str(index) + '.fa'), 'w')
    with open(fasta) as f:
        for line in f:
            tmp_list.append(line + next(f))
    #Split into chunks
    chunk_list = split_chunks(range(num_fasta), num_threads)
    for index in range(len(chunk_list)):
        for num in chunk_list[index]:
            tmp_dict[index].write(tmp_list[num])
    for index in tmp_dict:
        tmp_dict[index].close()

#Run single dwgsim
def single_subprocess_dwgsim(dwgsim_path, output_dir, num_threads, first_read_error, second_read_error, ins_length, ins_length_stdev, split_frags, read_length, mut_rate, indel_rate, indel_ext, indel_len, ran_read, seed, ref):
    check_call([str(dwgsim_path), '-e', str(first_read_error), '-E', str(second_read_error), '-d', str(ins_length), '-s', str(ins_length_stdev), '-N', str(split_frags), '-1', str(read_length), '-2', str(read_length), '-r', str(mut_rate), '-R', str(indel_rate), '-X', str(indel_ext), '-I', str(indel_len), '-y', str(ran_read), '-z', str(seed), '-o', '1', '-c', '0', '-S', '2', str(ref), str(ref + '.out')], stdout=DEVNULL, stderr=STDOUT)

#Run multi dwgsim
def multi_subprocess_dwgsim(current_gene_list, dwgsim_dir, output_dir, num_threads, first_read_error, second_read_error, ins_length, ins_length_stdev, sim_num_frags, read_length, mut_rate, indel_rate, indel_ext, indel_len, ran_read, seed):
    dwgsim_path = os.path.join(dwgsim_dir, 'dwgsim')
    in_fasta_list = []
    if len(current_gene_list) >= num_threads:
        for index in range(num_threads):
            in_fasta_list.append(os.path.join(output_dir, 'tmp' + str(index) + '.fa'))
        split_frags = round(sim_num_frags/num_threads)
        jobs = []
        for ref in in_fasta_list:
            p = multiprocessing.Process(target=single_subprocess_dwgsim, args=(dwgsim_path, output_dir, num_threads, first_read_error, second_read_error, ins_length, ins_length_stdev, split_frags, read_length, mut_rate, indel_rate, indel_ext, indel_len, ran_read, seed, ref))
            jobs.append(p)
            p.start()
    else:
        for index in range(len(current_gene_list)):
            in_fasta_list.append(os.path.join(output_dir, 'tmp' + str(index) + '.fa'))
        split_frags = round(sim_num_frags/len(current_gene_list))
        jobs = []
        for ref in in_fasta_list:
            p = multiprocessing.Process(target=single_subprocess_dwgsim, args=(dwgsim_path, output_dir, num_threads, first_read_error, second_read_error, ins_length, ins_length_stdev, split_frags, read_length, mut_rate, indel_rate, indel_ext, indel_len, ran_read, seed, ref))
            jobs.append(p)
            p.start()
    for job in jobs:
        job.join()
    #for ref in in_fasta_list:
        #check_call(['rm', ref], stdout=DEVNULL, stderr=STDOUT)
        #check_call(['rm', ref + '.out.mutations.vcf'], stdout=DEVNULL, stderr=STDOUT)
        #check_call(['rm', ref + '.out.mutations.txt'], stdout=DEVNULL, stderr=STDOUT)


from fastapi import FastAPI, Depends
from fastapi.responses import RedirectResponse
from fastapi.middleware.cors import CORSMiddleware
from routers import board, resources
from docs import tags_metadata_docs, description_docs

app = FastAPI(
    openapi_tags=tags_metadata_docs,
    title="Progetto CHeArIA",
    description=description_docs,
    version="1.0",
    contact={
        "url": "https://progettochearia.it"
    },
    license_info={
        "name": "GNU General Public License v3.0",
        "url": "https://raw.githubusercontent.com/liceocremona/chearia-backend/main/LICENSE"
    }
    )

origins=["https://progettochearia.it",
 "https://web.progettochearia.it",
 "https://admin.progettochearia.it"]
app.add_middleware(
    CORSMiddleware,
    allow_origins= origins,
    allow_methods=["*"],
    allow_headers=["*"],
)

app.include_router(
    board.router,
    prefix="/board",
)
app.include_router(
    resources.router,
    prefix="/resources",
)

@app.get("/", response_class=RedirectResponse, status_code=302, include_in_schema=False)
async def root():
    return "https://api.progettochearia.it/v1/docs"


divisor = int(input())
boundary = int(input())
number = 0

for number in range(boundary, divisor - 1, -1):
    if number == 0:   #it is not necessary to add this line because we're searching from the highest to lowest.
        continue
    if number % divisor == 0:
        break

print(number)


import os
import sys
import click

import pandas as pd

from mlhub.pkg import get_cmd_cwd

# Constants

ROUND = 3  # Number of decimal points to round to.

# Ensure paths are relative to the user's cwd.

os.chdir(get_cmd_cwd())

@click.command()
@click.argument('csvfile',
                type=click.File('r'),
                default=sys.stdin)
# help="the input data file, in csv format"
def cli(csvfile):

    # Quit if no data to read.

    try:
        df = pd.read_csv(csvfile)
    except pd.errors.EmptyDataError:
        click.echo("No data available.")
        sys.exit(1)

    # Apply the z-score method
    # https://towardsdatascience.com/data-normalization-with-pandas-and-scikit-learn-7c1cc6ed6475

    for column in df.columns:
        df[column] = (df[column] - df[column].mean()) / df[column].std()

    click.echo(df.round(ROUND).to_csv(index=False).strip())

if __name__ == "__main__":
    cli(prog_name="normalise")


import os

import pytest
from playwright.sync_api import Page

@pytest.fixture()
def authenticated_page(page) -> Page:
    page.goto("/sign-in")
    page.get_by_label("Email address").fill(os.environ.get("AYR_TEST_USERNAME"))
    page.get_by_label("Password").fill(os.environ.get("AYR_TEST_PASSWORD"))
    page.get_by_role("button", name="Sign in").click()
    page.wait_for_url("/browse")
    return page

@pytest.fixture(scope="session")
def browser_context_args(browser_context_args):
    """
    Fixture for configuring Playwright browser context arguments.
    This fixture is used to customize browser context arguments for Playwright
    browser instances. It sets the 'ignore_https_errors' option to True, which
    allows ignoring HTTPS errors, To disable JS set 'java_script_enabled' to False, which
    disables JavaScript in the browser context.
    Parameters:
        browser_context_args (dict): The default browser context arguments.
    Returns:
        dict: Updated browser context arguments with customized settings.
    """
    return {
        **browser_context_args,
        "ignore_https_errors": True,
        "java_script_enabled": False,
    }

@pytest.fixture()
def page(request, page) -> Page:
    if "test_css_" not in request.node.name and callable(request.node.obj):

        def route_intercept(route):
            if route.request.resource_type == "stylesheet":
                return route.abort()
            return route.continue_()

        page.route("**/*", route_intercept)
    return page


__all__ = (
    'CloudWatchAgentMetricsCollectedOptions',
    'CloudWatchAgentMetricsOptions',
    'CloudWatchAgentLogFileFilter',
    'CloudWatchAgentLogFileOptions',
    'CloudWatchAgentLogsOptions',
    'CloudWatchAgentConfigOptions',
    'CloudWatchAgentConfig'
)

from ideadatamodel import SocaBaseModel, exceptions
from ideasdk.utils import Utils, Jinja2Utils
from ideasdk.config.cluster_config import ClusterConfig

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

class CloudWatchAgentMetricsCollectedOptions(SocaBaseModel):
    # refer to https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch-Agent-Configuration-File-Details.html for more details
    name: str  # can be one of [cpu, disk, diskio, swap, mem, net, netstat, processes, nvidia_gpu, collectd, statsd]
    enabled: bool
    # if config is not provided, applicable defaults will be used from amazon-cloudwatch-agent-[linux|windows].yml jinja2 template
    # refer to cloudwatch agent config docs for config details on each metric section
    config: Optional[Dict]

class CloudWatchAgentMetricsOptions(SocaBaseModel):
    namespace: str
    metrics_collection_interval: Optional[int]
    force_flush_interval: Optional[int]
    # eg: "aggregation_dimensions" : [["AutoScalingGroupName"], ["InstanceId", "InstanceType"],[]]
    aggregation_dimensions: Optional[Union[List[str], List[List[str]]]]
    append_dimensions: Optional[Dict]
    # eg. ['ImageId', 'InstanceId', 'InstanceType', 'AutoScalingGroupName']
    include_dimensions: Optional[List[str]]
    metrics_collected: List[CloudWatchAgentMetricsCollectedOptions]

    @staticmethod
    def default_options(namespace: str, include: List[str] = None, exclude: List[str] = None) -> 'CloudWatchAgentMetricsOptions':
        metrics_collected = []
        sections = ['cpu', 'disk', 'diskio', 'swap', 'mem', 'net', 'netstat', 'processes']
        for section_name in sections:
            if Utils.is_not_empty(exclude):
                if section_name in exclude:
                    continue
            if Utils.is_not_empty(include):
                if section_name not in include:
                    continue
            metrics_collected.append(CloudWatchAgentMetricsCollectedOptions(
                name=section_name,
                enabled=True
            ))

        # ensures nvidia_gpu is also added
        for section_name in include:
            if section_name not in sections:
                metrics_collected.append(CloudWatchAgentMetricsCollectedOptions(
                    name=section_name,
                    enabled=True
                ))

        return CloudWatchAgentMetricsOptions(
            namespace=namespace,
            metrics_collected=metrics_collected
        )

class CloudWatchAgentLogFileFilter(SocaBaseModel):
    # can be one of [exclude, include]
    # Denotes the type of filter. Valid values are include and exclude.
    # With include, the log entry must match the expression to be published to CloudWatch Logs.
    # With exclude, each log entry that matches the filter is not sent to CloudWatch Logs.
    type: str
    # A regular expression string
    expression: str

class CloudWatchAgentLogFileOptions(SocaBaseModel):
    file_path: str
    # As part of the log_group_name and log_stream_name, you can use {instance_id}, {hostname}, {local_hostname}, and {ip_address} as variables within the name.
    # {hostname} retrieves the hostname from the EC2 metadata, and {local_hostname} uses the hostname from the network configuration file.
    # Specifies what to use as the log group name in CloudWatch Logs.
    log_group_name: str
    log_stream_name: str
    retention_in_days: Optional[int]
    auto_removal: Optional[bool]
    filters: Optional[List[CloudWatchAgentLogFileFilter]]
    # valid values are UTC and Local
    timezone: Optional[str]

class CloudWatchAgentLogsOptions(SocaBaseModel):
    force_flush_interval: Optional[int]
    default_log_stream_name: Optional[str]
    files: List[CloudWatchAgentLogFileOptions]

class CloudWatchAgentConfigOptions(SocaBaseModel):
    module_id: str
    base_os: str
    # metrics may be enabled at cluster level, but an individual module might not want to use metrics.
    enable_metrics: bool
    # cloud watch logging may be enabled at cluster level, but an individual module might not want to use cloud watch logs
    enable_logs: bool
    metrics: Optional[CloudWatchAgentMetricsOptions]
    logs: Optional[CloudWatchAgentLogsOptions]

class CloudWatchAgentConfig:

    def __init__(self, cluster_config: ClusterConfig, options: CloudWatchAgentConfigOptions):

        self.config = cluster_config

        if Utils.is_empty(options.module_id):
            raise exceptions.invalid_params('module_id is required')
        if Utils.is_empty(options.base_os):
            raise exceptions.invalid_params('base_os is required')

        self.options = options

        # defaults
        self.DEFAULT_METRICS_COLLECTION_INTERVAL = self.config.get_int('metrics.cloudwatch.metrics_collection_interval', 60)
        self.DEFAULT_METRICS_FORCE_FLUSH_INTERVAL = self.config.get_int('metrics.cloudwatch.force_flush_interval', 60)
        self.DEFAULT_LOGS_FORCE_FLUSH_INTERVAL = self.config.get_int('cluster.cloudwatch_logs.force_flush_interval', 5)
        self.DEFAULT_LOGS_RETENTION_IN_DAYS = self.config.get_int('cluster.cloudwatch_logs.retention_in_days', 90)

        # module id
        self.module_id = options.module_id

        # cluster name, aws region
        self.cluster_name = self.config.get_string('cluster.cluster_name', required=True)
        self.aws_region = self.config.get_string('cluster.aws.region', required=True)

        # platform
        self.platform = Utils.get_platform(base_os=options.base_os)

        # vpc endpoints
        self.logs_endpoint_override: Optional[str] = None
        self.metrics_endpoint_override: Optional[str] = None
        use_vpc_endpoints = self.config.get_bool('cluster.network.use_vpc_endpoints', False)
        if use_vpc_endpoints:
            logs_vpc_endpoint_enabled = self.config.get_bool('cluster.network.vpc_interface_endpoints.logs.enabled', False)
            if logs_vpc_endpoint_enabled:
                logs_endpoint_url = self.config.get_string('cluster.network.vpc_interface_endpoints.logs.endpoint_url', required=True)
                # "endpoint_override": "vpce-XXXXXXXXXXXXXXXXXXXXXXXXX.logs.us-east-1.vpce.amazonaws.com"
                self.logs_endpoint_override = logs_endpoint_url.replace('https://', '')

            metrics_vpc_endpoint_enabled = self.config.get_bool('cluster.network.vpc_interface_endpoints.monitoring.enabled', False)
            if metrics_vpc_endpoint_enabled:
                metrics_endpoint_url = self.config.get_string('cluster.network.vpc_interface_endpoints.monitoring.endpoint_url', required=True)
                # "endpoint_override": "vpce-XXXXXXXXXXXXXXXXXXXXXXXXX.monitoring.us-east-1.vpce.amazonaws.com"
                self.metrics_endpoint_override = metrics_endpoint_url.replace('https://', '')

        # metrics
        self.enable_metrics = Utils.get_as_bool(options.enable_metrics, False)
        self.metrics_collection_interval: Optional[int] = None
        self.metrics_namespace: Optional[str] = None
        self.metrics_force_flush_interval: Optional[int] = None
        self.aggregation_dimensions: Optional[Union[List[str], List[List[str]]]] = None
        self.metrics_collected: Dict[str, Dict[str, Any]] = {}
        self.append_dimensions: Optional[Dict] = None
        self.include_dimensions: Optional[List[str]] = None
        if self.enable_metrics:
            if Utils.is_empty(options.metrics):
                raise exceptions.invalid_params('metrics is required when enable_metrics = True')
            if Utils.is_empty(options.metrics.metrics_collected):
                raise exceptions.invalid_params('metrics.metrics_collected is required')

            if Utils.is_empty(options.metrics.namespace):
                self.metrics_namespace = f'{self.cluster_name}/{self.module_id}'
            else:
                self.metrics_namespace = options.metrics.namespace
            self.metrics_collection_interval = Utils.get_as_int(options.metrics.metrics_collection_interval, self.DEFAULT_METRICS_COLLECTION_INTERVAL)
            self.metrics_force_flush_interval = Utils.get_as_int(options.metrics.force_flush_interval, self.DEFAULT_METRICS_FORCE_FLUSH_INTERVAL)
            self.aggregation_dimensions = options.metrics.aggregation_dimensions
            self.append_dimensions = options.metrics.append_dimensions
            self.include_dimensions = options.metrics.include_dimensions
            for collected_metric in options.metrics.metrics_collected:
                metric_config = {
                    'enabled': Utils.get_as_bool(collected_metric.enabled, False),
                }
                if collected_metric.config is not None:
                    metric_config['config'] = collected_metric.config
                self.metrics_collected[collected_metric.name] = metric_config

        # logs
        self.enable_logs = Utils.get_as_bool(options.enable_logs, False)
        self.collected_log_files: Optional[List[Dict]] = None
        self.logs_force_flush_interval: Optional[int] = None
        self.default_log_stream_name: Optional[str] = None
        if self.enable_logs:
            if Utils.is_empty(options.logs):
                raise exceptions.invalid_params('logs is required when enable_logs = True')
            if Utils.is_empty(options.logs.files):
                raise exceptions.invalid_params('logs.files is required')
            for index, file_config in enumerate(options.logs.files):
                if Utils.is_empty(file_config.file_path):
                    raise exceptions.invalid_params(f'logs.files[{index}].file_path is required')
                if Utils.is_empty(file_config.log_group_name):
                    raise exceptions.invalid_params(f'logs.files[{index}].log_group_name is required')
                if Utils.is_empty(file_config.log_stream_name):
                    raise exceptions.invalid_params(f'logs.files[{index}].log_stream_name is required')

            self.default_log_stream_name = Utils.get_as_string(options.logs.default_log_stream_name, f'{self.module_id}_default_{{ip_address}}')
            self.logs_force_flush_interval = Utils.get_as_int(options.logs.force_flush_interval, self.DEFAULT_LOGS_FORCE_FLUSH_INTERVAL)
            collected_log_files = []
            for file_config in options.logs.files:
                if file_config.retention_in_days is None:
                    file_config.retention_in_days = self.DEFAULT_LOGS_RETENTION_IN_DAYS
                collected_log_files.append(Utils.to_dict(file_config))
            self.collected_log_files = collected_log_files

    def build(self) -> Dict:

        context = {
            # common
            'utils': Utils,
            'aws_region': self.aws_region,

            # logs
            'enable_logs': self.enable_logs,
            'logs_endpoint_override': self.logs_endpoint_override,
            'logs_force_flush_interval': self.logs_force_flush_interval,
            'default_log_stream_name': self.default_log_stream_name,
            'collected_log_files': self.collected_log_files,

            # metrics
            'enable_metrics': self.enable_metrics,
            'metrics_endpoint_override': self.metrics_endpoint_override,
            'metrics_collection_interval': self.metrics_collection_interval,
            'metrics_namespace': self.metrics_namespace,
            'metrics_force_flush_interval': self.metrics_force_flush_interval,
            'aggregation_dimensions': self.aggregation_dimensions,
            'append_dimensions': self.append_dimensions,
            'include_dimensions': self.include_dimensions,
            'metrics_collected': self.metrics_collected
        }

        env = Jinja2Utils.env_using_package_loader(
            package_name='ideasdk.metrics.cloudwatch',
            package_path='templates'
        )

        template = env.get_template(f'amazon-cloudwatch-agent-{self.platform}.yml')
        content = template.render(**context)
        return Utils.from_yaml(content)


import sys
from collections import deque
import heapq
input = sys.stdin.readline
n, m , r = map(int, input().split())
arr = [0] + list(map(int, input().split()))
#items = [0] + [int(x) for x in sys.stdin.readline().split()]
graph = [[] for _ in range(n+1)]
for _ in range(r) :
    h1, h2, w = map(int, input().split())
    graph[h1].append((h2, w))
    graph[h2].append((h1, w))

def dijkstra(start):
    que = []
    heapq.heappush(que, (0, start))
    D[start] = 0

    while que:
        dist, now = heapq.heappop(que)
        if D[now] < dist:
            continue

        for i in graph[now]:
            cost = dist + i[1]
            if cost < D[i[0]]:
                D[i[0]] = cost
                heapq.heappush(que, (cost, i[0]))

ans = 0
for i in range(1, n + 1):
    D = [int(1e9)] * (n + 1)
    dijkstra(i)
    tmp = 0
    for d in range(1, n + 1):
        if m >= D[d]:
            tmp += arr[d]

    ans = max(ans, tmp)

print(ans)
# 1차 풀이 - 잘돌아가는데 틀림 : bfs vs dijkstra의 차이를 모르겠음!
# def bfs(start):
#     visit = [-1] * (n+1)
#     visit[start] = 0
#     queue = deque()
#     queue.append(start)
#     maxVal = arr[start-1]
#
#     while queue:
#         t = queue.popleft()
#         for e, w in graph[t] :
#             if visit[e] == -1 and visit[t] + w <= m:
#                 visit[e] = visit[t] + w
#                 maxVal += arr[e-1]
#                 queue.append(e)
#     return maxVal
#
# val = 0
# for i in range(1, n+1):
#     val = max(val, bfs(i))
# print(val)


# This script removes all lines out of a cleaned csv except for the lines
# representing one region

import pandas as pd

# Load the dataset
input_file_path = "datasets\data_cleaned.csv"
output_file_path = r"datasets\data_cleaned_us.csv"
data = pd.read_csv(input_file_path)

# Filter rows where 'Region' is 'us'
filtered_data = data[data['Region'] == 'us']

# Save the filtered data back to a CSV or another desired format (optional)
filtered_data.to_csv(output_file_path, index=False)

print(f"\nData filtering completed. Saved to: '{output_file_path}'")


class Job:
    def __init__(self, name, job_position, description, minimum_age, requirement_experience,requirement_programmation_skill, requirement_english_skills, requirement_communication_skills):
        self.name = name
        self.job_position = job_position
        self.description = description
        self.minimum_age = minimum_age
        self.requirement_experience = requirement_experience
        self.requirement_programmation_skills = requirement_programmation_skill
        self.requirement_english_skills = requirement_english_skills
        self.requirement_communication_skills = requirement_communication_skills


num1=int(input("Enter first number "))
num2=int(input("Enter second number "))
if(num1==0 or num2==0):
    lcm =0
else:
    if(num1>num2):
        grt=num1
    else:
        grt=num2
    while(1):
        if((grt%num1==0) and (grt%num2==0)):
            lcm=grt
            break
        grt+=1
print("LCM of ",num1," and ",num2," = ",lcm)


from matplotlib import cm
from matplotlib.colors import LinearSegmentedColormap, ListedColormap

class Colors:
    bright_blue = (13 / 255, 0 / 255, 107 / 255)  # blue HSV(244, 255, 207)
    bright_red = (207 / 255, 0 / 255, 0 / 255)  # red HSV(0, 255, 207)

_bwr_data = [
    (13 / 255, 0 / 255, 107 / 255),  # blue negative HSV(244, 255, 207)
    (1.0, 1.0, 1.0),  # white center
    (207 / 255, 0 / 255, 0 / 255),  # red positive HSV(0, 255, 207)
]
_cmap_bwr = LinearSegmentedColormap.from_list("crownet_bwr", _bwr_data)

_registerd = False

def _register_cmap():
    if not _register_cmap:
        cm.register_cmap("crownet_bwr", _cmap_bwr)
        _registerd = True


"""
强化学习示例.
"""

import math
import random
from typing import Tuple

import sys
sys.path.append('../')

from sim import vec
from sim.common import Uav, Jammer, Radar
from sim.rl import Environment, RlReferee

##############################################################################
# 决策代理
##############################################################################

class CmdAgent:
    """ 简单指控代理. """

    def __init__(self):
        self.range_0 = 21.0
        self.range_1 = 30.0

    def encode_state(self, scene):
        """ 把场景翻译为输入."""
        jammer, uav = scene.find('jammer'), scene.find('target')
        s = vec.dist(uav.position, jammer.position)
        return s

    def decode_action(self, act_val):
        """ 把输出翻译为动作. """
        actions = {}
        if act_val == 1:
            actions['jammer.power_on'] = True
        if act_val == -1:
            actions['jammer.power_on'] = False
        return actions

    def decide(self, s):
        """ 根据状态（距离），产生决策.

        :return: 1表示power_on；-1表示power_off；0表示维持原状.
        """
        output = 0
        if s < self.range_0:
            output = 1
        if s > self.range_1:
            output = -1
        return output

##############################################################################

class DqnAgent:
    """ 深度Q网络代理. """

    def __init__(self):
        """ 初始化.

        :param network: 深度网络 inputs=2， output=3
            inputs = [dist, speed]
            outputs = softmax([on, off, keep])
        """
        self.network = None

    def encode_state(self, scene):
        """ 把场景翻译为输入."""
        jammer, uav = scene.find('jammer'), scene.find('target')
        d = vec.dist(uav.position, jammer.position)
        s = vec.dist(uav.velocity)
        return vec.vec([d, s])

    def decode_action(self, acts):
        """ 把输出翻译为动作. """
        mi = 0  # acts 中最大值的索引.
        actions = {}
        if mi == 0:
            actions['jammer.power_on'] = True
        elif mi == 1:
            actions['jammer.power_on'] = False
        return actions

    def decide(self, s) -> dict:
        """ 决策. """
        output = 0
        # output = network.forward(x)
        return output

##############################################################################
# 裁判
##############################################################################

class SimpleReferee(RlReferee):
    """ 简单裁判. """

    def calc_reward(self, scene) -> Tuple[float, bool]:
        """ 计算奖励值（reward, done）

        :return:
            reward 奖励值.  入侵=-1000， 其他=0
            done 入侵或飞机消失，可以结束.
        """
        jammer, uav = scene.find('jammer'), scene.find('target')
        d = vec.dist(uav.position, jammer.position)

        invade = d < 20.0  # 判断是否已经入侵.
        done = not uav.is_active() or invade

        reward = 0.0
        if invade:
            reward -= 1000.0
        if jammer.power_on:
            reward -= 1.0
        reward = max(-1000., reward)

        return reward, done

##############################################################################
# 环境/场景构建
##############################################################################

def setup_scene(scene):
    """ （随机）初始化场景. """
    scene.set_params(end=50.0)
    scene.add(Jammer(name='jammer', pos=[0, 0]))
    scene.add(Radar(pos=[10, 10]))

    d, theta = random.uniform(50, 100), random.uniform(0, math.pi * 2)
    pt = (d * math.cos(theta), d * math.sin(theta))
    speed = random.uniform(3, 5)
    scene.add(Uav(name='target', tracks=[pt, [0, 0]], speed=speed, life=30.0))

def play_once(show=False):
    """ 玩一次. """
    agent = CmdAgent()
    env = Environment(referee=SimpleReferee(), agent=agent, dt=.1)
    setup_scene(env.scene)

    s = env.reset()
    while True:
        if show:
            env.render()
        a = agent.decide(s)
        s_, r, done, info = env.step(a)
        if done:
            break
        s = s_
    return env.total_reward

def play(rounds=15):
    total_rewards = []
    for i in range(rounds):
        r = play_once(show=True)
        print('episode [{0}] : total reward = {1}'.format(str(i + 1), r))
        total_rewards.append(r)
    print('avg reward = {}'.format(sum(total_rewards) / len(total_rewards)))

if __name__ == '__main__':
    play()
    print('--- over ---')


#!/usr/bin/python3.5

from os.path import isfile
from sys import argv

import drawer
from bmp_opener import BMPOpener

class Launcher:
    def __init__(self):
        no_draw_options = Option('no draw', ['-d', '--nodraw'],
                                 'prevent drawing picture')
        quiet_options = Option('quiet', ['-q', '--quiet'],
                               'prevent showing info in tty')
        no_check_options = Option('no check', ['-c', '--nocheck'],
                                  'prevent checking fields in bmp')
        help_options = Option('help', ['-h', '--help'],
                              'show help')
        all_pseudonyms = []
        for option in [no_draw_options, quiet_options,
                       no_check_options, help_options]:
            all_pseudonyms += option.pseudonyms
        self.available_options = [no_check_options, no_draw_options,
                                  help_options, quiet_options]
        options = [arg for arg in argv[1:] if not isfile(arg)]
        files_to_open = [arg for arg in argv[1:] if isfile(arg)]
        if any(x in argv for x in help_options.pseudonyms):
            self.show_usage()
            self.show_available_options()
            exit()
        if any(x not in all_pseudonyms for x in options):
            print("There is a mistake in some option")
            print("Use py launcher.py -h to see help")
            exit()
        if not files_to_open:
            self.show_usage()
            exit()
        for file in files_to_open:
            self.bmp = BMPOpener(file).bmp_file
            if all(x not in argv for x in no_check_options.pseudonyms):
                self.bmp.validate()
            if all(x not in argv for x in quiet_options.pseudonyms):
                self.bmp.print_info()
            if all(x not in argv for x in no_draw_options.pseudonyms):
                self.bmp.parse_pixels()
                drawer.main(self.bmp)

    def show_usage(self):
        print("""Launch py launcher.py {path_to_bmp}""")

    def show_available_options(self):
        for option in self.available_options:
            print(option)

class Option:
    def __init__(self, name, pseudonyms, description):
        self.description = description
        self.pseudonyms = pseudonyms
        self.name = name

    def __str__(self):
        return "{}: can be called by {} and {}".format(self.name,
                                                       self.pseudonyms,
                                                       self.description)

if __name__ == "__main__":
    Launcher()


from django.contrib import admin
from django.urls import path,include

"""
PARA INCLUIR LAS URLS DE TU APP SE UTILIZA

path('nombreApi/',include('nombreApi.urls'))

RECORDAR INCLUIR LAS COMILLAS DENTRO DE LA FUNCIÓN INCLUDE
"""

urlpatterns = [
    path('admin/', admin.site.urls),
    path('',include('menuApis.urls')),
    path('valorant/',include('valorantApi.urls')),
    path('digimon/',include('digimonApi.urls')),
    path('makeup/',include('makeupApi.urls')),
    path('breakingbad/',include('breakingbadApi.urls')),
    path('disney/',include('disneyApi.urls')),
    path('freetogame/',include('freeToGameApi.urls')),
    path('noticias/',include('noticiasApi.urls')),
    path('covid/',include('covidApi.urls')),
    path('horoscopo/', include('horoscopoApi.urls')),
    path('personas/', include('personasApi.urls')),
    path('allauth/',include('allauthApi.urls')),
    path('accounts/', include('allauth.urls')),

]


'''Entrar com 20 números e imprimir a soma dos positivos e o total de números
negativos.'''

from random import randint

lista = []
i = 0
totNeg = 0
soma = 0

for i in range(0, 20):
    lista.append(randint(-20, 20))

for i in lista:
    if(lista[i] < 0):
        totNeg += 1
    elif(lista[i] > 0):
        soma = soma + lista[i]

print(lista)
print("A soma dos números positivos é: ", soma)
print("A quantidade de números negativos é de: ", totNeg)


# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import models, migrations

class Migration(migrations.Migration):

    dependencies = [
        ('music', '0017_delete_temporarymusic'),
    ]

    operations = [
        migrations.RemoveField(
            model_name='music',
            name='date',
        ),
    ]


class Solution:
    def maxValueOfCoins(self, piles: List[List[int]], k: int) -> int:
        for i in range(len(piles)):
            for j in range(1,len(piles[i])):
                piles[i][j] += piles[i][j-1]

        @lru_cache(None)
        def dp(index,k):

            if index == len(piles) or k == 0:
                return 0

            ans = dp(index+1,k)

            for i in range(min(k,len(piles[index]))):

                ans = max( ans, piles[index][i] + dp(index+1,k-(i+1))  )

            return ans

        return dp(0,k)


#Hi ก้อง , Hi แก้ม , Hello ก้อง , Hello แก้ม
greeting=["สวัสดี","Hi", "Hello", "Good Bye"]
people=["ก้อง", "แก้ม", "โจ๋" ]
result=[]
#แบบปกติ
for x in greeting:
     for y in people:
          result.append(x+y)
print(result)
#ลดรูป
result=[x+y for x in greeting for y in people]

print(result)


from bacsession import BacSession
from bachttpreq import BacHttpReq
import threading
import bacutil

# declare a global session manager, to make it available to
# HTTP server RequestHandler
sessionMgr = None

class BacSessionMgr:
    # remove a session when a session is idle for MAX_IDLE_TIME seconds
    MAX_IDLE_TIME = 100
    def __init__(self, appType, localFolder, proxyMode, nextServer):
        self.appType = appType
        self.localFolder = localFolder
        self.proxyMode = proxyMode

        # next server is explicitly specified
        # if not, it will be specified on URL
        self.nextServer = nextServer

        self.sessionCount = 0
        self.reqCount = 0           # a unique request index
        self.sessionList = list()

        self.lock = threading.Lock()

    def CreateHttpReq(self,
                      incomingReqHdlr,
                      method,
                      path,
                      headers):
        bacutil.DbgTrace("CreateHttpReq, from host %s, '%s %s" %
                         (incomingReqHdlr.client_address[0], method, path))

        # Get URL
        httpReq = BacHttpReq(incomingReqHdlr)

        # assign a global index to each request for debugging purpose
        self.lock.acquire()
        httpReq.SetIdx(self.reqCount)
        self.reqCount += 1
        self.lock.release()

        httpReq.SetUrl(method, path)
        httpReq.SetHeaders(headers)

        return httpReq

    # find a session that matches a new request.
    # if not found, a new session is created.
    def FindSession(self, httpReq):
        for session in self.sessionList:
            bacutil.DbgTrace("FindSession, session to host: %s, request to host %s" %
                             (session.tgtHost, httpReq.tgtHost))

            if session.MatchHttpReq(httpReq):
                return session

        bacutil.DbgTrace("FindSession, create a new session")
        session = BacSession(self.appType, self.localFolder)

        # configure a new session and start thread inside
        session.Configure(httpReq, self.sessionCount)
        self.sessionCount = self.sessionCount + 1

        self.sessionList.append(session)

        return session

    def RemoveSession(self):
        return

    def ProcessHttpReq(self, httpReq):
        bacutil.DbgTrace("BacSessionMgr::ProcessHttpReq")

        session = self.FindSession(httpReq)

        if session is not None:
            return session.ProcessHttpReq(httpReq)

        return None


# imports
import os
from flask import request, render_template, url_for, redirect
from werkzeug import secure_filename
from datetime import datetime
from dateutil.relativedelta import relativedelta
from pprint import pprint

from app import app, models

# Front page
@app.route('/')
def index():
    apps = models.findAllAppNames()
    return render_template("index.html", title="PERF", apps=apps)

@app.route('/dashboard/<appname>')
def dashboard(appname):

    title="PERF - " + appname + " Dashboard"
    now = datetime.now()

    dateParam = request.args.get('d')
    try:
        date = datetime.strptime(dateParam, '%m-%Y')
    except:
        date = now

    orderParam = request.args.get('o', 'callcount')
    summaryData = models.findMonthlySummaryByAppAndMonth(appname, date, orderParam)

    dateInfo = {
        "friendly": date.strftime('%B %Y'),
        "curParam": date.strftime('%m-%Y'),
        "prevParam": (date + relativedelta( months = -1 )).strftime('%m-%Y'),
        "nextParam": (date + relativedelta( months = +1 )).strftime('%m-%Y')
    }

    urlPrefix = "/dashboard/"+appname+"?d=" + dateInfo["curParam"]

    return render_template("dashboard.html", title=title, appname=appname, summaryData=summaryData, dateInfo=dateInfo, urlPrefix=urlPrefix)

@app.route('/method/<appname>/<methodname>')
def method(appname, methodname):
    formattedMethod = models.formatMethodName(methodname)
    title="PERF - " + appname + " - " + formattedMethod

    timeBucketData = models.findTimeBucketDateForMethod(appname, methodname)
    dailySummaryData = models.findDailySummaryForMethod(appname, methodname)

    return render_template("method.html",
                           title=title,
                           appname=appname,
                           methodname=methodname,
                           formattedMethod=formattedMethod,
                           timeBucketData=timeBucketData,
                           dailySummaryData=dailySummaryData)

@app.errorhandler(404)
def page_not_found(error):
    return render_template('page_not_found.html'), 404

@app.route('/tim')
def tim():
    app.logger.info('Tim')
    ##dataLoader.loadFromFilePath('/home/tcollins/dev/temp/test-performance-short.log');
    ##models.create_initial_db_schema();

    ##aggregator = models.DataAggregator();
    #aggregator.aggregate();
    return "TIM"

def allowed_file(file):
    return True

@app.route('/api/')
def api():
    return render_template("api.html", title="PERF - API Documentation")

@app.route('/api/upload-data', methods=['POST'])
def uploaddata():
    if request.method == 'POST':
        file = request.files['file']
        ##pprint(vars(request))
        appname = request.form['appname']
        if file and allowed_file(file):
            filename = secure_filename(file.filename)
            filepath = os.path.join(app.config['UPLOAD_FOLDER'], filename)
            file.save(filepath)

            dataLoader = models.DataLoader(appname);
            dataLoader.loadFromFilePath(filepath);

            return "Data Upload Complete!"

@app.route('/api/aggregate')
def apiAggregate():
    aggregator = models.DataAggregator();
    aggregator.aggregate();
    return "Aggregation Complete!"


# https://codingcompetitions.withgoogle.com/kickstart/round/000000000019ff08/0000000000387171

T = int(input())
for t in range(T):
    N = int(input())
    arr = list(map(int,input().split()))

    ans = 0
    maxim = float('-inf')
    for x in range(N):
        if x == N-1:
            if arr[x] > maxim:
                ans += 1
                maxim = arr[x]
        else:
            if arr[x] > maxim and arr[x] > arr[x+1]:
                ans += 1
                maxim = arr[x]
            if maxim  == float('-inf'):
                maxim = arr[0]

    print('Case #{}: {}'.format(t+1,ans))


from sys import stdin
from itertools import repeat, chain

def merge(decks):
    if len(decks) > 1:
        mid = len(decks) // 2
        L = decks[:mid]
        R = decks[mid:]
        merge(L)
        merge(R)
        i = 0
        j = 0
        k = 0
        while i < len(L) and j < len(R):
            if L[i] < R[j]:
                decks[k] = L[i]
                i += 1
            else:
                decks[k] = R[j]
                j += 1
            k += 1

        while i < len(L):
            decks[k] = L[i]
            i += 1
            k += 1

        while j < len(R):
            decks[k] = R[j]
            j += 1
            k += 1

def main():
    decks = []
    for line in stdin:
        (index, csv) = line.strip().split(':')
        decks.append(list(zip(map(int, csv.split(',')), repeat(index))))
    decks = list(chain.from_iterable(decks))
    merge(decks)
    print(''.join(v for (k, v) in decks))

if __name__ == "__main__":
    main()


import time

#
# Wrapper around a trac ticket
#
class TracTicket:

    def __init__(self, db, id):
        """
        Ctor
        """
        self.db = db
        self.id = id

    ###########################################################################
    #
    # API
    #
    ###########################################################################

    def get_hours(self):
        """
        Get the total hours worked.
        """
        result = self._get_custom_field_value('totalhours')
        if not result:
            return None

        try:
            hours = float(result)
        except:
            return None

        return hours

    def set_hours(self, prev_hours, new_hours, author, change_time = None,
                  comment = None):
        """
        Set the total hours worked.
        """

        prev_hours = str(prev_hours)
        new_hours = str(new_hours)

        self._save_custom_field_value('totalhours', new_hours)
        self._save_ticket_change(author, 'totalhours', prev_hours,
                                 new_hours, change_time, comment)

    def get_est_hours(self):
        """
        Get the estimated number of hours for the ticket.
        """

        result = self._get_custom_field_value('estimatedhours')
        if not result:
            return None

        try:
            hours = float(result)
        except:
            return None

        return hours

    def get_owner(self):
        """
        Get the owner of the ticket.
        """

        cursor = self.db.cursor();
        cursor.execute("SELECT owner FROM ticket WHERE id=%s", (self.id,))

        row = cursor.fetchone()
        if not row:
            return None

        return row[0]

    def set_st_id(self, prev_id, new_id, author, change_time = None,
                  comment = None):
        """
        Get the SlimTimer ID for the ticket.
        """

        prev_id = str(prev_id)
        new_id  = str(new_id)

        self._save_custom_field_value('slimtimer_id', new_id)
        self._save_ticket_change(author, 'slimtimer_id', prev_id, new_id,
                                 change_time, comment)

    ###########################################################################
    #
    # Internal methods
    #
    ###########################################################################

    def _get_custom_field_value(self, field):
        """
        Get the value of a ticket field that is a custom field.
        """

        cursor = self.db.cursor();
        cursor.execute("SELECT value FROM ticket_custom "
                       "WHERE ticket=%s and name=%s", (self.id, field))

        row = cursor.fetchone()
        if not row:
            return None

        return row[0]

    # The following code is courtesy of timingandestimationplugin.

    def _save_custom_field_value(self, field, value):
        """
        Save the value of a ticket field that is a custom field.
        """

        cursor = self.db.cursor();
        cursor.execute("SELECT * FROM ticket_custom "
                       "WHERE ticket=%s and name=%s", (self.id, field))

        if cursor.fetchone():
            cursor.execute("UPDATE ticket_custom SET value=%s "
                           "WHERE ticket=%s AND name=%s",
                           (value, self.id, field))

        else:
            cursor.execute("INSERT INTO ticket_custom (ticket,name,value)"
                           "VALUES(%s,%s,%s)",
                           (self.id, field, value))

    def _save_ticket_change(self, author, field, oldvalue,
                            newvalue, change_time = None, comment = None):
        """
        Save a ticket change record.
        """

        if not change_time:
            change_time = time.time()

        change_time = str(change_time)

        cursor = self.db.cursor();
        sql = """SELECT * FROM ticket_change
                 WHERE ticket=%s and author=%s and time=%s and field=%s"""
        cursor.execute(sql, (self.id, author, change_time, field))

        if cursor.fetchone():
            cursor.execute(
                   """UPDATE ticket_change  SET oldvalue=%s, newvalue=%s
                   WHERE ticket=%s and author=%s and time=%s and field=%s""",
                   (oldvalue, newvalue, self.id, author, change_time, field))
        else:
            cursor.execute(
                   """INSERT INTO ticket_change
                   (ticket,time,author,field, oldvalue, newvalue)
                   VALUES(%s, %s, %s, %s, %s, %s)""",
                   (self.id, change_time, author, field, oldvalue, newvalue))

            if comment:
                cursor.execute(
                       """INSERT INTO ticket_change
                       (ticket,time,author,field, oldvalue, newvalue)
                       VALUES(%s, %s, %s, %s, %s, %s)""",
                       (self.id, change_time, author, 'comment', '', comment))


import operator
import widget, wine

class Widget(widget.VineyardWidgetComboBox):
    def __init__(self):
        """ Compile a list of the available settings, our preferred first """
        our_settings = ['Full', 'Standard', 'Basic', 'Emulation']
        our_settings_lowered = [ n.lower() for n in our_settings ]

        settings = []
        # Use only the drivers that are available on this system
        for setting in our_settings:
            if setting.lower() in wine.audio.ACCELERATIONS:
                settings.append(setting)
        # Add drivers that weren't on our sorted list
        for setting in wine.audio.ACCELERATIONS:
            if setting.lower() not in our_settings_lowered:
                settings.append(setting.capitalize())

        match_values = [ (i, i.lower()) for i in settings ]

        widget.VineyardWidgetComboBox.__init__(self,
            title = '%s:' % _('Hardware acceleration'),
            values = settings,
            match_values = match_values,
            settings_key = 'sound-directsound-acceleration',
            get_function = self._get_function,
            set_function = wine.audio.set_acceleration)

    def _get_function(self):
        value = wine.audio.get_acceleration()
        return value.lower()


import sys
sys.setrecursionlimit(10**6)
input = sys.stdin.readline

# 접근방법: 그냥 dfs는 시간초과가 난다. dp도 같이 사용해준다.

# 상하좌우
dr = [-1, 1, 0, 0]
dc = [0, 0, -1, 1]

def dfs(r, c):

    # 도착
    if r == M-1 and c == N-1:
        return 1

    if visited[r][c] != -1:
        return visited[r][c]

    visited[r][c] = 0
    for i in range(4):
        nr = r + dr[i]
        nc = c + dc[i]

        if nr < 0 or nr >= M or nc < 0 or nc >= N:
            continue

        if field[nr][nc] < field[r][c]:
            visited[r][c] += dfs(nr, nc)

    return visited[r][c]

M, N = map(int, input().split()) # M은 세로(행), N은 가로(열)
field = [list(map(int, input().split())) for _ in range(M)]

visited = [[-1] * N for _ in range(M)]

print(dfs(0, 0))


from txircd.modbase import Module

class QuitServerNotice(Module):
    def sendQuitNotice(self, user, reason):
        if "sendservernotice" in self.ircd.module_data_cache:
            message = "Client quit: {} ({}) [{}]".format(user.prefix(), user.ip, reason)
            self.ircd.module_data_cache["sendservernotice"]("quit", message)

class Spawner(object):
    def __init__(self, ircd):
        self.ircd = ircd
        self.quitnotice = None

    def spawn(self):
        self.quitnotice = QuitServerNotice().hook(self.ircd)
        return {
            "actions": {
                "quit": self.quitnotice.sendQuitNotice
            }
        }


# 2.Создайте список из случайных чисел.
# Найдите номер его последнего локального максимума
# (локальный максимум — это элемент, который больше любого из своих соседей).

def task():
    n = int(input('Введите размер списка: '))
    if n < 2:
        print('Введено число меньше 2')
        return

    # Последовательно добавляем элементы
    print('Введите элементы списка: ')
    arr = []
    for i in range(n):
        arr.append(int(input()))

    found = False
    index = n-1     # начинаем с последнего элемента
    while(index > 0):   # исключаем начальный элемент, у которого только один сосед
        if index == n-1:    # у замыкающего элемента только один сосед слева
            if arr[index] > arr[index-1]:
                found = True
                break
        else:
            if arr[index] > arr[index-1] and arr[index] > arr[index+1]:
                found = True
                break
        index -= 1
    if not found:
        index = 0     # Единственный оставшийся вариант: начальный элемент
    print(f'Последний локальный максимум: {arr[index]}, индекс {index}')

task()