import sys
import pygame
import basicGameLogic
from math import log2

# UI
size = width, height = 480, 500
playRegion = 480, 480
FPS = 60

# Colors
black = (0, 0, 0)
white = (255, 255, 255)
fontColor = (82, 52, 42)
defaultTileColor = (232, 232, 232)
tileBoarderColor = fontColor

# Game
boardSize = 4

def drawBoard(screen, board):
    screen.fill(black)
    for i in range(boardSize):
        for j in range(boardSize):
            color = defaultTileColor
            numberText = ''
            if board[i][j] != 0:
                gComponent = 235 - log2(board[i][j]) * ((235 - 52) / (boardSize ** 2))
                color = (235, gComponent, 52)
                numberText = str(board[i][j])
            rect = pygame.Rect(j * playRegion[0] / boardSize,
                                i * playRegion[1] / boardSize,
                                playRegion[0] / boardSize,
                                playRegion[1] / boardSize)

            pygame.draw.rect(screen, color, rect)
            pygame.draw.rect(screen, fontColor, rect, 1)

            fontImage = tileFont.render(numberText, 0, fontColor)
            if fontImage.get_width() > playRegion[0] / boardSize:
                fontImage = pygame.transform.scale(fontImage,
                                                   (playRegion[0] / boardSize,
                                                    fontImage.get_height() / fontImage.get_width() * playRegion[
                                                        0] / boardSize))
            screen.blit(fontImage,
                        (j * playRegion[0] / boardSize + (playRegion[0] / boardSize - fontImage.get_width()) / 2,
                         i * playRegion[1] / boardSize + (playRegion[1] / boardSize - fontImage.get_height()) / 2))

    fontImage = scoreFont.render("Score: {:,}".format(sum(map(sum, board))), 1, white)  # Sum of all elements
    screen.blit(fontImage, (1, playRegion[1] + 1))

def handleInput(event, board):
    if event.type == pygame.QUIT:
        sys.exit()
    if event.type == pygame.KEYDOWN:
        if event.key == pygame.K_RIGHT:
            basicGameLogic.board = basicGameLogic.merge_right(basicGameLogic.board)
            basicGameLogic.addNewValue()
        elif event.key == pygame.K_LEFT:
            basicGameLogic.board = basicGameLogic.merge_left(basicGameLogic.board)
            basicGameLogic.addNewValue()
        elif event.key == pygame.K_UP:
            basicGameLogic.board = basicGameLogic.merge_up(basicGameLogic.board)
            basicGameLogic.addNewValue()
        elif event.key == pygame.K_DOWN:
            basicGameLogic.board = basicGameLogic.merge_down(basicGameLogic.board)
            basicGameLogic.addNewValue()

def gameLoop():
    clock = pygame.time.Clock()
    basicGameLogic.board = basicGameLogic.initialize_board(boardSize)

    while True:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                sys.exit()
            elif event.type == pygame.KEYDOWN:
                handleInput(event, basicGameLogic.board)

        drawBoard(screen, basicGameLogic.board)
        pygame.display.flip()
        clock.tick(FPS)

if __name__ == '__main__':
    pygame.init()
    screen = pygame.display.set_mode(size)
    pygame.display.set_caption("2048")
    tileFont = pygame.font.SysFont("", 72)
    scoreFont = pygame.font.SysFont("", 22)
    gameLoop()


import datetime
from ..app import db

# On crée une classe Obelisque
class Obelisque(db.Model):
    obelisque_id = db.Column(db.Integer, unique=True, nullable=False, primary_key=True, autoincrement=True)
    # Le nom de l'obélisque
    obelisque_nom = db.Column(db.Text)
    # Hauteur de l'obélisque à proprement parler
    obelisque_hauteur = db.Column(db.Float)
    # Hauteur totale du monument
    obelisque_hauteur_avec_base = db.Column(db.Float)
    # Matériau composant l'obélisque
    obelisque_materiau = db.Column(db.Text)
    # L'obélisque est-il une commande égyptienne ou romaine ?
    obelisque_type_commande = db.Column(db.Text)
    # Une brève description
    obelisque_notice = db.Column(db.Text)
    # On transcrit les inscriptions latines présentes sur l'obélisque si elles existent
    obelisque_inscription_latine = db.Column(db.Text)
    # On traduit les inscriptions latines présentes sur l'obélisque si elles existent
    obelisque_inscription_latine_traduite = db.Column(db.Text)
    # Les sources utilisées pour rédiger la fiche
    obelisque_bibliographie = db.Column(db.Text)
    # URL de l'image
    obelisque_image_url = db.Column(db.Text)
    # Crédits pour l'image
    obelisque_image_auteur = db.Column(db.Text)
    # Licence de l'image
    obelisque_image_licence = db.Column(db.Text)
    # Lien vers la licence
    obelisque_image_licence_url = db.Column(db.Text)
    erige = db.relationship("Erige", back_populates="obelisque")
    authorships = db.relationship("Authorship", back_populates="obelisque")

    # Pour ajouter un obélisque :
    @staticmethod
    def obelisque_add(obelisque_add_nom, obelisque_add_hauteur, obelisque_add_hauteur_avec_base, obelisque_add_materiau,
                      obelisque_add_type_commande, obelisque_add_notice, obelisque_add_inscription_latine,
                      obelisque_add_inscription_latine_traduite, obelisque_add_bibliographie, obelisque_add_image_url,
                      obelisque_add_image_auteur, obelisque_add_image_licence, obelisque_add_image_licence_url):

        """ Fonction permettant d'ajouter un obélisque à la base de données.
            :param obelisque_add_*: données recueillies depuis le formulaire
            :type obelisque_add_*: Text ou Float (obelisque_add_hauteur, obelisque_add_hauteur_avec_base)
            :returns: ajout de l'entrée dans la table obelisque de la base de données """

        erreurs = []
        # On définit des attributs obligatoires et les erreurs affichées si ceux-ci sont laissés vides
        if not obelisque_add_nom:
            erreurs.append("veuillez renseigner le nom de l'obélisque")
        if not obelisque_add_hauteur:
            erreurs.append("veuillez renseigner la hauteur de l'obélisque")
        if not obelisque_add_hauteur_avec_base:
            erreurs.append("veuillez renseigner la hauteur totale du monument")
        if not obelisque_add_materiau:
            erreurs.append("veuillez renseigner le matériau composant l'obélisque")
        if not obelisque_add_type_commande:
            erreurs.append("veuillez renseigner le type de commande")
        if not obelisque_add_notice:
            erreurs.append("veuillez renseigner une brève notice sur l'obélisque")
        if not obelisque_add_bibliographie:
            erreurs.append("veuillez renseigner vos sources")
        if not obelisque_add_image_url:
            erreurs.append("veuillez renseigner l'URL de l'image")
        if not obelisque_add_image_auteur:
            erreurs.append("veuillez renseigner l'ayant-droit de l'image")
        if not obelisque_add_image_licence:
            erreurs.append("veuillez renseigner la licence permettant la réutilisation de l'image")
        if not obelisque_add_image_licence_url:
            erreurs.append("veuillez renseigner l'URL de la licence")

        # En cas d'erreur on affiche le message d'erreur associé
        if len(erreurs) > 0:
            return False, erreurs

        # En l'absence d'erreurs, on récupère les données du futur nouvel enregistrement à partir du formulaire
        ajoutable = Obelisque(obelisque_nom=obelisque_add_nom,
                              obelisque_hauteur=obelisque_add_hauteur,
                              obelisque_hauteur_avec_base=obelisque_add_hauteur_avec_base,
                              obelisque_materiau=obelisque_add_materiau,
                              obelisque_type_commande=obelisque_add_type_commande,
                              obelisque_notice=obelisque_add_notice,
                              obelisque_inscription_latine=obelisque_add_inscription_latine,
                              obelisque_inscription_latine_traduite=obelisque_add_inscription_latine_traduite,
                              obelisque_bibliographie=obelisque_add_bibliographie,
                              obelisque_image_url=obelisque_add_image_url,
                              obelisque_image_auteur=obelisque_add_image_auteur,
                              obelisque_image_licence=obelisque_add_image_licence,
                              obelisque_image_licence_url=obelisque_add_image_licence_url,
                              )

        # Si l'ajout fonctionne, on l'intègre à la base de données
        try:
            db.session.add(ajoutable)
            db.session.commit()
            return True, ajoutable

        # Sinon, on retourne une erreur
        except Exception as erreur:
            return False, [str(erreur)]

    @staticmethod
    def obelisque_delete(obelisque_id):

        """ Fonction permettant de supprimer un obélisque de la base de données.
            :param obelisque_id: id de l'obélisque à supprimer
            :type obelisque_id: integer
            :returns: suppression de l'obélisque sélectionné de la table obelisque de la base de données """

        supprimable = Obelisque.query.get(obelisque_id)

        # Si l'opération fonctionne, on supprime l'enregistrement de la base de données
        try:
            db.session.delete(supprimable)
            db.session.commit()
            return True

        # Sinon, on retourne une erreur
        except Exception as erreur:
            return False, [str(erreur)]

# On crée une classe Personne pour recenser ceux ayant fait ériger un obélisque
class Personne(db.Model):
    personne_id = db.Column(db.Integer, unique=True, nullable=False, primary_key=True, autoincrement=True)
    # Le nom du commanditaire
    personne_nom = db.Column(db.Text)
    # Ses fonctions
    personne_fonction = db.Column(db.Text)
    # Sa nationalité
    personne_nationalite = db.Column(db.Text)
    erige = db.relationship("Erige", back_populates="personne")
    authorships = db.relationship("Authorship", back_populates="personne")

    @staticmethod
    def personne_add(personne_add_nom, personne_add_fonction, personne_add_nationalite):

        """ Fonction permettant d'ajouter un commanditaire à la base de données.
            :param personne_add_*: données recueillies depuis le formulaire
            :type personne_add_*: Text
            :returns: ajout de l'entrée dans la table personne de la base de données """

        erreurs = []
        # On définit des attributs obligatoires et les erreurs affichées si ceux-ci sont laissés vides
        if not personne_add_nom:
            erreurs.append("veuillez renseigner le nom du commanditaire")
        if not personne_add_fonction:
            erreurs.append(
                "veuillez renseigner les fonctions du commanditaire")
        if not personne_add_nationalite:
            erreurs.append(
                "veuillez renseigner la nationalité du commanditaire")

        # En cas d'erreur on affiche le message d'erreur associé
        if len(erreurs) > 0:
            return False, erreurs

        # En l'absence d'erreurs, on récupère les données du futur nouvel enregistrement à partir du formulaire
        ajoutable = Personne(personne_nom=personne_add_nom,
                             personne_fonction=personne_add_fonction,
                             personne_nationalite=personne_add_nationalite)

        # Si l'ajout fonctionne, on l'intègre à la base de données
        try:
            db.session.add(ajoutable)
            db.session.commit()
            return True, ajoutable

        # Sinon, on retourne une erreur
        except Exception as erreur:
            return False, [str(erreur)]

    @staticmethod
    def personne_delete(personne_id):

        """ Fonction permettant de supprimer un commanditaire de la base de données.
            :param personne_id: id du commanditaire à supprimer
            :type personne_id: integer
            :returns: suppression du commanditaire sélectionné de la table personne de la base de données """

        supprimable = Personne.query.get(personne_id)

        # Si l'opération fonctionne, on supprime l'enregistrement de la base de données
        try:
            db.session.delete(supprimable)
            db.session.commit()
            return True

        # Sinon, on retourne une erreur
        except Exception as erreur:
            return False, [str(erreur)]

# On crée une classe Localisation pour recenser les lieux où les obélisques ont été érigés
class Localisation(db.Model):
    localisation_id = db.Column(db.Integer, unique=True, nullable=False, primary_key=True, autoincrement=True)
    # Le lieu exact de l'élévation
    localisation_lieu = db.Column(db.Text)
    # Le terme de "ville" est à concevoir au sens large, il s'agit d'indiquer ici une référence plus précise que le pays, mais moins précise que le lieu exact.
    # On y renseigne la ville si le lieu d'évélation en possède une, mais on y retrouve également des termes tels que "Voie Appienne" (donc une route)
    # ou "Karnak" (un complexe)
    localisation_ville = db.Column(db.Text)
    # Le pays du lieu de l'élévation
    localisation_pays = db.Column(db.Text)
    # La longitude
    localisation_longitude = db.Column(db.Float)
    # La latitude
    localisation_latitude = db.Column(db.Float)
    erige = db.relationship("Erige", back_populates="localisation")
    authorships = db.relationship("Authorship", back_populates="localisation")

    @staticmethod
    def localisation_add(localisation_add_lieu, localisation_add_ville, localisation_add_pays,
                         localisation_add_latitude, localisation_add_longitude):

        """ Fonction permettant d'ajouter un lieu à la base de données.
            :param localisation_add_*: données recueillies depuis le formulaire
            :type localisation_add_*: Text ou Float (localisation_add_latitude et localisation_add_longitude)
            :returns: ajout de l'entrée dans la table localisation de la base de données """

        erreurs = []
        # On définit des attributs obligatoires et les erreurs affichées si ceux-ci sont laissés vides
        if not localisation_add_lieu:
            erreurs.append("veuillez renseigner le nom du lieu")
        if not localisation_add_ville:
            erreurs.append(
                "veuillez renseigner le nom de la ville")
        if not localisation_add_pays:
            erreurs.append(
                "veuillez renseigner le nom du pays")
        if not localisation_add_latitude:
            erreurs.append(
                "veuillez renseigner une latitude")
        if not localisation_add_longitude:
            erreurs.append(
                "veuillez renseigner une longitude")

        # En cas d'erreur on affiche le message d'erreur associé
        if len(erreurs) > 0:
            return False, erreurs

        # En l'absence d'erreurs, on récupère les données du futur nouvel enregistrement à partir du formulaire
        ajoutable = Localisation(localisation_lieu=localisation_add_lieu,
                                 localisation_ville=localisation_add_ville,
                                 localisation_pays=localisation_add_pays,
                                 localisation_latitude=localisation_add_latitude,
                                 localisation_longitude=localisation_add_longitude)

        # Si l'ajout fonctionne, on l'intègre à la base de données
        try:
            db.session.add(ajoutable)
            db.session.commit()
            return True, ajoutable

        # Sinon, on retourne une erreur
        except Exception as erreur:
            return False, [str(erreur)]

    @staticmethod
    def localisation_delete(localisation_id):

        """ Fonction permettant de supprimer un lieu de la base de données.
            :param localisation_id: id du lieu à supprimer
            :type localisation_id: integer
            :returns: suppression du lieu sélectionné de la table localisation de la base de données """

        supprimable = Localisation.query.get(localisation_id)

        # Si l'opération fonctionne, on supprime l'enregistrement de la base de données
        try:
            db.session.delete(supprimable)
            db.session.commit()
            return True

        # Sinon, on retourne une erreur
        except Exception as erreur:
            return False, [str(erreur)]

# On crée une classe Erige servant de table de relation reliant les trois tables précédentes
# Cette table recense les élévations d'obélisques
class Erige(db.Model):
    __tablename__ = "erige"
    erige_id = db.Column(db.Integer, unique=True, nullable=False, primary_key=True, autoincrement=True)
    # On récupère l'id de l'obélisque élevé
    erige_id_obelisque = db.Column(db.Integer, db.ForeignKey('obelisque.obelisque_id'))
    # On récupère l'id du commanditaire ayant ordonné l'élévation
    erige_id_personne = db.Column(db.Integer, db.ForeignKey('personne.personne_id'))
    # On récupère l'id du lieu où a été élevé l'obélisque
    erige_id_localisation = db.Column(db.Integer, db.ForeignKey('localisation.localisation_id'))
    # On renseigne la date de l'élévation (au format Text, permettant aisément l'emploi de valeurs telles que "1279-1213 av. J.-C.")
    erige_date = db.Column(db.Text)
    # On indique si l'enregistrement correspond à la localisation actuelle de l'obélisque (0 = non, 1 = oui)
    erige_actuel = db.Column(db.Integer)
    obelisque = db.relationship("Obelisque", back_populates="erige")
    personne = db.relationship("Personne", back_populates="erige")
    localisation = db.relationship("Localisation", back_populates="erige")
    authorships = db.relationship("Authorship", back_populates="erige")

    @staticmethod
    def erige_add(erige_add_id_obelisque, erige_add_id_personne, erige_add_id_localisation, erige_add_date,
                  erige_add_actuel):

        """ Fonction permettant d'ajouter une élévation à la base de données.
            :param erige_add_*: données recueillies depuis le formulaire
            :type erige_add_*: Text (erige_add_date) ou Integer
            :returns: ajout de l'entrée dans la table erige de la base de données """

        erreurs = []
        # On définit des attributs obligatoires et les erreurs affichées si ceux-ci sont laissés vides
        if not erige_add_id_obelisque:
            erreurs.append("veuillez renseigner l'identifiant de l'obélisque'")
        if not erige_add_id_personne:
            erreurs.append(
                "veuillez renseigner l'identifiant du commanditaire'")
        if not erige_add_id_localisation:
            erreurs.append(
                "veuillez renseigner l'identifiant du lieu'")
        if not erige_add_date:
            erreurs.append(
                "veuillez renseigner la date d'élévation")

        # En cas d'erreur on affiche le message d'erreur associé
        if len(erreurs) > 0:
            return False, erreurs

        # En l'absence d'erreurs, on récupère les données du futur nouvel enregistrement à partir du formulaire
        ajoutable = Erige(erige_id_obelisque=erige_add_id_obelisque,
                          erige_id_personne=erige_add_id_personne,
                          erige_id_localisation=erige_add_id_localisation,
                          erige_date=erige_add_date,
                          erige_actuel=erige_add_actuel)

        # Si l'ajout fonctionne, on l'intègre à la base de données
        try:
            db.session.add(ajoutable)
            db.session.commit()
            return True, ajoutable

        # Sinon, on retourne une erreur
        except Exception as erreur:
            return False, [str(erreur)]

    @staticmethod
    def erige_delete(erige_id):

        """ Fonction permettant de supprimer une élévation de la base de données.
            :param erige_id: id de l'élévation à supprimer
            :type erige_id: integer
            :returns: suppression de l'élévation sélectionnée de la table erige de la base de données """

        supprimable = Erige.query.get(erige_id)

        # Si l'opération fonctionne, on supprime l'enregistrement de la base de données
        try:
            db.session.delete(supprimable)
            db.session.commit()
            return True

        # Sinon, on retourne une erreur
        except Exception as erreur:
            return False, [str(erreur)]

# On crée une classe Authorship pour recenser les modifications des utilisateurs
class Authorship(db.Model):
    __tablename__ = "authorship"
    authorship_id = db.Column(db.Integer, nullable=False, autoincrement=True, primary_key=True)
    authorship_obelisque_id = db.Column(db.Integer, db.ForeignKey('obelisque.obelisque_id'), nullable=True)
    authorship_personne_id = db.Column(db.Integer, db.ForeignKey('personne.personne_id'), nullable=True)
    authorship_localisation_id = db.Column(db.Integer, db.ForeignKey('localisation.localisation_id'), nullable=True)
    authorship_erige_id = db.Column(db.Integer, db.ForeignKey('erige.erige_id'), nullable=True)
    authorship_user_id = db.Column(db.Integer, db.ForeignKey('user.user_id'), nullable=False)
    # Pour renseigner l'heure, on utilise les paramètres locaux
    # Source : https://www.codegrepper.com/code-examples/python/python+datetime+local+timezone
    now = datetime.datetime.now()
    local_now = now.astimezone()
    authorship_date = db.Column(db.DateTime, default=local_now, nullable=False)
    obelisque = db.relationship("Obelisque", back_populates="authorships")
    personne = db.relationship("Personne", back_populates="authorships")
    localisation = db.relationship("Localisation", back_populates="authorships")
    erige = db.relationship("Erige", back_populates="authorships")
    user = db.relationship("User", back_populates="authorships")


import os
import sys
import torch
import numpy as np
import logging
from tqdm import tqdm
from MulticoreTSNE import MulticoreTSNE as TSNE
from sklearn.decomposition import PCA
from umap import UMAP
import random

sys.path.append(os.path.join(os.path.dirname(__file__), ".."))
from S.dataset import WSI
from plot_miccai.vis_utils import get_files_oneclass

def get_embed_feature(x, method: str):
    def tsne_embed(x):
        tsne = TSNE(n_components=2, random_state=0, perplexity=30, n_jobs=8)
        # tsne = TSNE(n_components=2, random_state=0, perplexity=5)
        x_embedded = tsne.fit_transform(x)
        return x_embedded

    def pca_embed(x):
        pca = PCA(n_components=2, random_state=0)
        x_embedded = pca.fit_transform(x)
        return x_embedded

    def umap_embed(x):
        umap = UMAP(n_components=2, random_state=0, n_neighbors=50)
        x_embedded = umap.fit_transform(x)
        return x_embedded

    if method == "tsne":
        x_embedded = tsne_embed(x)
    elif method == "pca":
        x_embedded = pca_embed(x)
    elif method == "umap":
        x_embedded = umap_embed(x)
    elif method == "direct":
        x_embedded = x
    else:
        sys.exit(f"cannot find method: {method}")
    return x_embedded

def extract_feature(model, device, test_loader, n_data):
    model.eval()
    init_flag = True
    with torch.no_grad():
        with tqdm(total=n_data, unit="img") as pbar:
            for batch in test_loader:
                data, target = batch["image"], batch["label"]
                data, target = data.to(device), target.to(device)
                latent_vecs = model(data)

                latent_vecs = latent_vecs.cpu()
                target = target.cpu()
                if init_flag:
                    latent_vecs_stack = latent_vecs
                    target_stack = target
                    init_flag = False
                else:
                    latent_vecs_stack = torch.cat((latent_vecs_stack, latent_vecs), 0)
                    target_stack = torch.cat((target_stack, target), 0)
                pbar.update(target.shape[0])
    return latent_vecs_stack, target_stack

def get_latent_vecs(
    model,
    file_list: list,
    classes: list = [0, 1, 2],
    input_shape: tuple = (256, 256),
    batch_size: int = 32,
):
    use_cuda = torch.cuda.is_available()
    device = torch.device("cuda" if use_cuda else "cpu")
    kwargs = {"num_workers": 0, "pin_memory": True} if use_cuda else {}

    if len(file_list) > 0:
        transform = {"Resize": True, "HFlip": False, "VFlip": False}
        dataset = WSI(
            file_list, classes, input_shape, transform, is_pred=False
        )
        dataset_loader = torch.utils.data.DataLoader(
            dataset, batch_size=batch_size, shuffle=False, **kwargs
        )

        latent_vecs, _ = extract_feature(
            model, device, dataset_loader, len(dataset)
        )
        latent_vecs = latent_vecs.numpy()
    else:  # このクラスのデータが存在しない場合
        latent_vecs = np.array([])
    return latent_vecs

def get_latent_vecs_list(
    model,
    all_class_files_list: list,  # 全クラスのファイルリストのリスト
    classes: list = [0, 1, 2],
    input_shape: tuple = (256, 256),
    batch_size: int = 32,
    output_dir: str = None,
    title: str = "latent_vecs"
):
    # all_class_files_list: [クラス0のfile list, クラス1のfile list, ..., クラスnのfile list]

    latent_vecs_list = []
    for cl_idx in range(len(classes)):
        files = all_class_files_list[cl_idx]
        # クラスごとに特徴量ベクトルを取得
        latent_vecs = get_latent_vecs(
            model,
            file_list=files,
            input_shape=input_shape,
            batch_size=batch_size,
        )
        # 特徴ベクトルを保存
        if output_dir is not None:
            np.save(
                f"{output_dir}{title}_cl{cl_idx}",
                latent_vecs,
            )

        latent_vecs_list.append(latent_vecs)
    logging.info(f"latent_vecs: {latent_vecs.shape}")
    return latent_vecs_list

# 各クラスのfile listのlistを取得
def get_all_class_files_list(
    wsi_list: list,
    imgs_dir: str,
    classes: list = [0, 1, 2],
):
    random.seed(0)
    all_class_files_list = []
    for class_idx in range(len(classes)):
        file_list = get_files_oneclass(
            wsi_list=wsi_list,
            classes=classes,
            imgs_dir=imgs_dir,
            cl_idx=class_idx,
        )
        random.shuffle(file_list)
        all_class_files_list.append(file_list)
    return all_class_files_list


def max_num(a, b, c):
    return max([a, b, c])

print(max_num(100, 1, 2))

def mult_list(myList):
    # Multiply elements one by one
    result = 1
    for x in myList:
        result = result * x
    return result

# Driver code
list1 = [1, 2, 3]
list2 = [3, 2, 4]
print(mult_list(list1))
print(mult_list(list2))

def rev_string(my_string):
    return my_string[::-1]

print(rev_string("MACBOOK PRO"))

def num_within(a, b, c):
    return a in range(b, c+1)

print(num_within(3, 2, 4))
print(num_within(3, 1, 3))
print(num_within(10, 2, 5))

triangle = [[1], [1, 1]]

def pascal(n):
    # base case
    if n < 1:
        print("invalid number of rows")
    elif n == 1:
        print(triangle[0])
    else:
        row_number = 2
        # fill up correct number of rows in triangle
        while len(triangle) < n:
            row = []
            row_prev = triangle[row_number - 1]
            # create correct row, then add to triangle (this row will be 1 longer than row before it)
            length = len(row_prev)+1
            for i in range(length):
                # first number is 1
                if i == 0:
                    row.append(1)
                # intermediate nunmbers get added from previous rows
                elif i > 0 and i < length-1:
                    row.append(triangle[row_number-1]
                               [i-1]+triangle[row_number-1][i])
                # last number is 1
                else:
                    row.append(1)
            triangle.append(row)
            row_number += 1

        # print triangle
        for row in triangle:
            print(row)

pascal(0)
pascal(1)
# '''
# output:
# 1
# '''

pascal(5)
# '''
# output:
# 1
# 1 1
# 1 2 1
# 1 3 3 1
# 1 4 6 4 1
# '''


#Cherry Pickup II
'''
You are given a rows x cols matrix grid representing a field of cherries where grid[i][j] represents the number of cherries that you can collect from the (i, j) cell.
You have two robots that can collect cherries for you:
    Robot #1 is located at the top-left corner (0, 0), and
    Robot #2 is located at the top-right corner (0, cols - 1).
Return the maximum number of cherries collection using both robots by following the rules below:
    From a cell (i, j), robots can move to cell (i + 1, j - 1), (i + 1, j), or (i + 1, j + 1).
    When any robot passes through a cell, It picks up all cherries, and the cell becomes an empty cell.
    When both robots stay in the same cell, only one takes the cherries.
    Both robots cannot move outside of the grid at any moment.
    Both robots should reach the bottom row in grid.

Example:
    Input: grid = [[3,1,1],[2,5,1],[1,5,5],[2,1,1]]
    Output: 24
    Explanation:
        Path of robot #1 and #2 are described in color green and blue respectively.
        Cherries taken by Robot #1, (3 + 2 + 5 + 2) = 12.
        Cherries taken by Robot #2, (1 + 5 + 5 + 1) = 12.
        Total of cherries: 12 + 12 = 24.
'''
from functools import lru_cache

class Solution:
    def cherryPickup(self,grid):
        @lru_cache(None)
        def dfs(r,c1,c2):
            if r==m:
                return 0
            if c1==c2:
                cherries=grid[r][c1]
            else:
                cherries=grid[r][c1]+grid[r][c2]
            res=0
            for nc1 in range(c1-1,c1+2):
                for nc2 in range(c2-1,c2+2):
                    if 0<=nc1<n and 0<=nc2<n:
                        res=max(res,dfs(r+1,nc1,nc2))
            return res+cherries
        m,n=len(grid),len(grid[0])
        return dfs(0,0,n-1)


#Importing libraries
import csv
import requests
import time
from bs4 import BeautifulSoup
import re

url = "https://www.cnbc.com/2020/08/08/as-trump-bans-wechat-some-in-china-turn-to-encrypted-messaging-app-signal.html"
art = []

#Cleaning The Data
def cleaning(art):
    text = art[0]
    # remove html markup
    text = re.sub("(<.*?>)","",text)
    #remove non-ascii and digits
    text = re.sub("(\\W)"," ",text)
    #remove whitespace
    #text = text.strip()

    art[0] = text

    return art

#Manual Entry
def manualEntry():
    print("Connection has been denied, please obtain the article text manually.")
    body = ""
    body = input()
    return body

#Scraping
def scrape(url):
    print("Fetching article: " + url)
    headers = {'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36'}
    p = ""
    response = requests.get(url, headers = headers)
    soup = BeautifulSoup(response.text, "html.parser")
    #art.append(soup.findAll('h2')[0].string)
    for i in range(0, len(soup.findAll('p'))):
        p += soup.findAll('p')[i].text
    art.append(p)

    if art[0] == "We've detected unusual activity from your computer network":
       p = manualEntry()
       art.append(p)
    #else:
        #print(art)
    #art.append(url)
    cleaning(art)
    #print(art)

scrape(url)


from rest_framework import viewsets
from rest_framework.permissions import IsAuthenticatedOrReadOnly
from django.utils.decorators import method_decorator
from drf_yasg.utils import swagger_auto_schema
import django_filters

from apps.base.paginations import CustomPagination
from apps.base.permissions import IsOwnerImageOrReadOnly
from apps.images.models import Image
from apps.images.serializers.image_serializers import ImageSerializer

__author__ = "Ricardo Robledo"
__version__ = "0.1"

# -------------------------------------------------------------
#                       Image view set
# -------------------------------------------------------------

class ImageFilter(django_filters.FilterSet):
    """
    This class filter our images by title and creation date

    Attributes:
        created_ate (datetime): creation date
        title (str): image title
    """

    title = django_filters.CharFilter(field_name='title')
    created_at = django_filters.DateTimeFilter(field_name='created_at', lookup_expr='gte')

    class Meta:
        model = Image
        fields = ['title', 'created_at']

@method_decorator(name='list', decorator=swagger_auto_schema(
    operation_description="""
    :param title: image title
    :param created_at: creation date
    """
))
@method_decorator(name='create', decorator=swagger_auto_schema(
    operation_description="""
    :param title: category which belongs the image
    :param link: image url
    :param description: brief description about a user
    :param user: user's foreign key
    """
))
@method_decorator(name='retrieve', decorator=swagger_auto_schema(
    operation_description=':param id: primary key of image'
))
@method_decorator(name='update', decorator=swagger_auto_schema(
    operation_description="""
    :param id: primaky key of image
    :param title: category which belongs the image
    :param link: image url
    :param description: brief description about a user
    :param user: user's foreign key
    """
))
@method_decorator(name='destroy', decorator=swagger_auto_schema(
    operation_description=':param id: primaky key of image'
))
@method_decorator(name='partial_update', decorator=swagger_auto_schema(
    operation_description='partial_update'
))
class ImageViewSet(viewsets.ModelViewSet):

    permission_classes = (IsAuthenticatedOrReadOnly, IsOwnerImageOrReadOnly,)
    queryset =  Image.objects.all().order_by('id')
    serializer_class = ImageSerializer
    filterset_class = ImageFilter
    pagination_class = CustomPagination
    #filterset_fields = ['title']


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Sun Jul 28 20:27:14 2019

@author: joscelynec

Given a sequence, find the length of the longest palindromic subsequence in it.

longest-palindromic-subsequence. As an example, if the given sequence is “BBABCBCAB”,
then the output should be 7 as “BABCBAB” is the longest palindromic subseuqnce in it.
“BBBBB” and “BBCBB” are also palindromic subsequences of the given sequence, but not the longest ones.

The naive solution for this problem is to generate all subsequences of the given sequence and
find the longest palindromic subsequence. This solution is exponential in term of time complexity.
Let us see how this problem possesses both important properties of a Dynamic Programming (DP) Problem
and can efficiently solved using Dynamic Programming.

https://youtu.be/_nCsPn7_OgI
https://www.geeksforgeeks.org/longest-palindromic-subsequence-dp-12/

"""
#Dynamic Program
def LongestPalindromicSubsequence (lst):
    length = len(lst)
    #Intialize a lengthxlength grid of -1
    grid = [[-1]*(length) for i in range(length)]
    #set the diagonal to 1
    for i in range(length):
        grid[i][i] = 1

    for l in range(2, length+1):
        for i in range(0, length - l +1):
            j = i + l - 1
            if(l == 2 and lst[i] == lst[j]):
                grid[i][j] = 2;
            elif(lst[i] == lst[j]):
                grid[i][j] = grid[i + 1][j-1] + 2
            else:
                grid[i][j] = max(grid[i + 1][j], grid[i][j - 1])

    return grid[0][length-1]

#Naive Recursive Solution

def calculateRecursive(lst, start, length):
    if length <= 1:
        return length
    if(lst[start] == lst[start+length-1]):
        return 2 + calculateRecursive(lst,start+1,length-2)
    else:
        return max(calculateRecursive(lst, start+1, length-1), calculateRecursive(lst, start, length-1))

l = []
for item in "BBABCBCAB":
    l.append(item)

print(l)
print(LongestPalindromicSubsequence (l))
print(calculateRecursive (l, 0, len(l)))
"""
['B', 'B', 'A', 'B', 'C', 'B', 'C', 'A', 'B']
7
7
"""


#!/usr/bin/env python
# -*- coding: utf-8 -*- #
from __future__ import unicode_literals

AUTHOR = u'Picovico'
SITENAME = u'Picovico Blog'
SITENAME_SHORT = "PICOVICO"
SITEURL = ''

PATH = 'content'

TIMEZONE = 'Asia/Kathmandu'

DEFAULT_LANG = u'en'

# Feed generation is usually not desired when developing
FEED_ALL_ATOM = None
CATEGORY_FEED_ATOM = None
TRANSLATION_FEED_ATOM = None
AUTHOR_FEED_ATOM = None
AUTHOR_FEED_RSS = None

# Blogroll
LINKS = (
        ('Picovico Official Website', 'http://picovico.com/'),
        ('The new Picovio Web', 'https://web.picovico.com/'),
         ('Picovico on Android', 'http://picovico.com/android'),
         ('Picovico for Business', 'http://picovico.com/business/'),
         ('Developer API', 'http://api.picovico.com'),)

# Social widget
SOCIAL = (('Facebook', 'http://facebook.com/picovico'),
          ('Twitter', 'http://twitter.com/picovico'),
          ('LinkedIn', 'http://picovico.com/linkedin'),
          ('Google Plus', 'http://plus.google.com/+Picovico'),
          ('Youtube', 'http://picovico.com/youtube'),
          ('Vimeo', 'http://vimeo.com/picovico'),
          )

DEFAULT_PAGINATION = 10

DISQUS_SITENAME = "picovico"
GOOGLE_ANALYTICS = "UA-56213136-6"

# Uncomment following line if you want document-relative URLs when developing
RELATIVE_URLS = True

THEME = "extent"

PLUGIN_PATHS = ["plugins", ]
PLUGINS = ["pv_absolute_path", ]


from matplotlib.pyplot import text
import pandas as pd
from bokeh.models import HoverTool, CustomJS, DateRangeSlider, Div, Paragraph, Dropdown, Select
from bokeh.palettes import Set1
from datetime import date
from bokeh.layouts import row, column
from bokeh.plotting import figure, show, ColumnDataSource,output_file
import numpy as np
from bokeh.palettes import Category10, Category20
from bokeh.transform import cumsum
from bokeh.tile_providers import get_provider, Vendors
import json

# EN TETE ----------------------------------------------------------------------------------------------------------

div_image = Div(text="""

                """, width=1200, height=200)
div_entete = Div(
                 text = """

VISUALISATIONS DE DONNEES SUR LES PORTS DE LA REGION BRETAGNE

"""

                 , width=1500, height=100)
par_entete=Div(text="""
Cette page a pour objectif de présenter les ports appartenant à la région Bretagne à travers différents graphiques
               et cartes. Les différentes visualisations ont pour objectifs de donner quelques repères géographiques, économiques et logistiques sur une selection
               de ports de la région Bretagne. Ces derniers sont de véritables aujourd'hui de véritables acteurs du développement touristiques, économique ou encore culturel de la région.

""", height=50)

# PREMIERE VISUALISATION  -----------------------------------------------------------------------------------

def coor_wgs84_to_web_mercator(lon, lat):
    k = 6378137
    x = lon * (k * np.pi/180.0)
    y = np.log(np.tan((90 + lat) * np.pi/360.0)) * k
    return (x,y)

#Import des données
fp = open("ports-appartenant-a-la-region-bretagne.geojson","r",encoding='utf-8')
dico = json.load(fp)

#Création du dictionnaire
commune=[]
nom_du_port = []
coordx = []
coordy= []
ls_activites = []#Contient sous formes de listes les différentes activités du port en question

for p in dico["features"]:
    commune.append(p["properties"]["commune"])
    nom_du_port.append(p["properties"]["nom"])
    X,Y = coor_wgs84_to_web_mercator(p["geometry"]["coordinates"][0],p["geometry"]["coordinates"][1])
    coordx.append(X)
    coordy.append(Y)
    ls = []
    if(p["properties"]["reparation_navale"]==1):
        ls.append(" réparation navale")
    if(p["properties"]["commerce"]==1):
        ls.append(" commerce")
    if(p["properties"]["peche"]==1):
        ls.append(" pêche")
    if(p["properties"]["plaisance"]==1):
        ls.append(" plaisance")
    ls_activites.append(ls)

#Création du dataframe et de la source
df2 = pd.DataFrame({'commune': commune, 'nom_du_port':nom_du_port, 'coordx': coordx, 'coordy':coordy, "ls_activites":ls_activites})
source = ColumnDataSource(df2)

#Création de la carte
p2 = figure(margin=(10,0,10,0),width=1100,height=600,x_axis_type="mercator", y_axis_type="mercator", active_scroll="wheel_zoom", title="Ports appartenant à la région Bretagne",  tools="pan,wheel_zoom,box_zoom,reset")
tile_provider = get_provider(Vendors.CARTODBPOSITRON)
p2.add_tile(tile_provider)

#Création des éléments graphiques représentant les ports
p2.circle_x(x="coordx",y="coordy",source =source,size =15, fill_color = "white", alpha=1,
           line_color ="navy")
p2.circle_cross(x="coordx",y="coordy",source =source,size =10, fill_color = "white", fill_alpha=0.5,
           line_color ="navy")

#Création de quelques éléments graphiques
hover_tool = HoverTool(tooltips=[( 'Commune', '@commune'),( 'Nom du port', '@nom_du_port'),('Activités', '@ls_activites')])
p2.xaxis.ticker = []
p2.yaxis.ticker = []
p2.add_tools(hover_tool)
p2.xgrid.grid_line_color = None
p2.ygrid.grid_line_color = None
p2.outline_line_width = 3
p2.outline_line_alpha = 1
p2.outline_line_color = "navy"
p2.toolbar.logo = None

#texte
par2 = Div(text="""

Voici la carte de l'ensemble des ports de la région Bretagne.
                 La Bretagne en possède 22. Pour chaque port, vous trouverez le nom du port,
                 de la commune ainsi que les activités portuaires.
""",margin=(100,0,0,30))

div2 = Div(text="""
Lien vers la base de données""",margin=(10,0,0,30))

# DEUXIEME GRAPHIQUE --------------------------------------------------------------------------------------

#traitement préalable des données
df1 = pd.read_csv("trafic-marchandises-ports.csv", sep = ";")

df_trafic = df1[["Date", "Nom du port", "Trafic total (en tonnes)"]]
df_trafic.Date = pd.to_datetime(df_trafic.Date)

df_trafic.columns = ['Date', 'Nom', 'Trafic']
df_trafic.Trafic = df_trafic.Trafic/1000

df_brest = df_trafic[df_trafic.Nom  == 'BREST'].sort_values(by = 'Date')
df_lorient = df_trafic[df_trafic.Nom  == 'LORIENT'].sort_values(by = 'Date')
df_roscoff = df_trafic[df_trafic.Nom  == 'ROSCOFF'].sort_values(by = 'Date')
df_legue = df_trafic[df_trafic.Nom  == 'LE LÉGUÉ'].sort_values(by = 'Date')
df_malo = df_trafic[df_trafic.Nom  == 'SAINT-MALO'].sort_values(by = 'Date')

df_brest = ColumnDataSource(df_brest)
df_lorient = ColumnDataSource(df_lorient)
df_roscoff = ColumnDataSource(df_roscoff)
df_legue = ColumnDataSource(df_legue)
df_malo = ColumnDataSource(df_malo)

#graphique
p1 = figure(margin=(10,0,10,0),title = "Trafic de marchandises des ports de la région Bretagne",
            x_axis_type = "datetime", x_axis_label = "Date",
            y_axis_label = "Trafci total (en milliers de tonnes)", width = 1000,
            tools = ['save', 'box_zoom'], y_range = (-10,400))
p1.toolbar.logo = None

palette = Set1[5]

p1.line(x = 'Date', y = 'Trafic', source = df_brest, legend_label = 'Brest', color = palette[0])
p1.line(x = 'Date', y = 'Trafic', source = df_lorient,legend_label = 'Lorient', color = palette[1])
p1.line(x = 'Date', y = 'Trafic', source = df_roscoff,legend_label = 'Roscoff', color = palette[2])
p1.line(x = 'Date', y = 'Trafic', source = df_legue,legend_label = 'Le Légué', color = palette[3])
p1.line(x = 'Date', y = 'Trafic', source = df_malo, legend_label = 'Saint-Malo', color = palette[4])

p1.legend.location = "top_left"
p1.legend.click_policy = "hide"

#affichage de la valeur au survol
hover_tool = HoverTool(tooltips=[( 'Date','@Date{%F} '),
                                 ('Trafic', '@Trafic')],
                        formatters={'@Date' : 'datetime'})
p1.add_tools(hover_tool)

##selection des dates pour l'axe des abscisses
date_range_slider = DateRangeSlider(title="Sélectionnez la date souhaitée",
                                    value=(date(2016, 3, 1), date(2020, 8, 1)),
                                    start=date(2016, 3, 1), end=date(2020, 8, 1),margin=(10,90,0,30))
date_range_slider.js_on_change("value", CustomJS(code="""
    console.log('date_range_slider: value=' + this.value, this.toString())
"""))

date_range_slider.js_link("value", p1.x_range, "start", attr_selector=0)
date_range_slider.js_link("value", p1.x_range, "end", attr_selector=1)

#texte
par1 = Paragraph(text="""Voici l'évolution du trafic mensuel de marchandises
                (en milliers de tonnes) entre le 1er mars 2016 et le 1er août 2020 pour les
                ports de commerce appartenant à la région Bretagne.Vous ouvez sélectionner le
                port souhaité et les différentes valeurs de trafic sur le graphique""",margin=(100,30,0,30))

div1 = Div(text="""
<a href="https://data.bretagne.bzh/explore/dataset/trafic-marchandises-des-ports-de-la-region-bretagne/table/?dataChart=eyJxdWVyaWVzIjpbeyJjaGFydHMiOlt7InR5cGUiOiJsaW5lIiwiZnVuYyI6IkNPTlNUQU5UIiwieUF4aXMiOiJ0cmFmaWNfdG90YWxfZW5fdG9ubmVzIiwic2NpZW50aWZpY0Rpc3BsYXkiOnRydWUsImNvbG9yIjoicmFuZ2UtRGFyazIifV0sInhBeGlzIjoiZGF0ZSIsIm1heHBvaW50cyI6IiIsInRpbWVzY2FsZSI6Im1vbnRoIiwic29ydCI6IiIsInNlcmllc0JyZWFrZG93biI6Im5vbV9kdV9wb3J0IiwiY29uZmlnIjp7ImRhdGFzZXQiOiJ0cmFmaWMtbWFyY2hhbmRpc2VzLWRlcy1wb3J0cy1kZS1sYS1yZWdpb24tYnJldGFnbmUiLCJvcHRpb25zIjp7fX19XSwiZGlzcGxheUxlZ2VuZCI6dHJ1ZSwiYWxpZ25Nb250aCI6dHJ1ZX0%3D ">Lien vers la base de données""",margin=(10,0,0,30))

# TROISIEME VISUALISATION -----------------------------------------------------------------------------------

#Import des données
#df = pandas.read_csv('espaces-de-concessions-des-ports-et-aeroports-appartenant-a-la-region-bretagne.csv',
#                     encoding = 'utf-8', sep=';')
dft = pd.read_csv('ports-appartenant-a-la-region-bretagne.csv', encoding='utf-8', sep=';')

#DataFrame des sites
#Série des villes
df_ville = dft.loc[:,"commune"]
df_ville = pd.Series(df_ville)

#Séries de la somme des concessions par ville
df3 = dft.loc[:,['plaisance','peche','commerce','reparation_navale','passager']]
df_somme = df3.sum(axis=1)
df_somme = pd.Series(df_somme)

#Dataframe pour faire la somme des concessions sur une même ville
df_test = pd.concat([df_ville,df_somme],axis=1)
grouped = df_test.groupby(['commune'])
df_fin = grouped.agg('sum')

#Initialisation des index
df_fin.reset_index(level=0, inplace=True)

#Transformtion en Séries
df_ville = pd.Series(df_fin['commune'])
df_somme = pd.Series(df_fin[0])

#Dataframe complet sur les sites
dict_sites = {df_ville[i]: df_somme[i] for i in range(len(df_ville))}
df_sites = pd.Series(dict_sites).reset_index(name='valeur').rename(columns={'index':'type'})
df_sites['angle'] = df_sites['valeur']/df_sites['valeur'].sum()*2*np.pi
df_sites['color'] = Category20[len(dict_sites)]

#DataFrame des concessions
#Série des concessions
df_conces = ["Plaisance", "Peche", "Commerce", "Reparation navale", "Passager"]
df_conces = pd.Series(df_conces)

#Série de la somme des concessins
df_somme = [dft["plaisance"].sum(),dft["peche"].sum(),dft["commerce"].sum(),dft["reparation_navale"].sum(),dft["passager"].sum()]
df_somme = pd.Series(df_somme)

#Dataframe complet sur les concessions
dict_concession = {df_conces[i]: df_somme[i] for i in range(len(df_conces))}
df_concession = pd.Series(dict_concession).reset_index(name='valeur').rename(columns={'index':'type'})
df_concession['angle'] = df_concession['valeur']/df_concession['valeur'].sum()*2*np.pi
df_concession['color'] = Category10[len(dict_concession)]

#Dictionnaire des données
don_pie_chart = {
    'Concession': dict(type=list(df_concession['type']),
               valeur=list(df_concession['valeur']),
               angle=list(df_concession['angle']),
               color=list(df_concession['color'])),
    'Site': dict(type=list(df_sites['type']),
               valeur=list(df_sites['valeur']),
               angle=list(df_sites['angle']),
               color=list(df_sites['color']))
    }

#Différents titres
titres = {
    'Concession': "Nombre des différents types de concessions en bretagne",
    'Site': "Nombres de concessions suivant le site maritime"
    }

#Définition du ColumnDataSource, initialisé sur les concessions
source_pie_chart = ColumnDataSource(don_pie_chart['Concession'])

#Création de la figure
pie_chart = figure(margin=(10,0,10,0),title="Nombre de ports par concession en bretagne", width = 900, height = 700
                , tools = ['save'])
pie_chart.toolbar.logo = None
pie_chart.wedge(x=0, y=1, radius=0.7, source=source_pie_chart, fill_color='color', legend_field='type',
                line_color="white", start_angle=cumsum('angle', include_zero=True), end_angle=cumsum('angle'))

#Création de l'outil de survol
hover_pie_chart = HoverTool(tooltips=[('Type ', '@type'),('Nombre', '@valeur')])
pie_chart.add_tools(hover_pie_chart)

#Arrière plan du graphique
pie_chart.axis.axis_label=None
pie_chart.axis.visible=False
pie_chart.grid.grid_line_color = None

#Paramètres de la légende
pie_chart.legend.location = 'top_left'
pie_chart.legend.background_fill_color = 'lightgray'
pie_chart.legend.background_fill_alpha = 0.7

#Callback
callback = CustomJS(args = {'source': source_pie_chart, 'data': don_pie_chart,
                            'title': pie_chart.title, 'titres': titres},
                    code = """source.data = data[cb_obj.value]
                             title.text = titres[cb_obj.value]
                         """)

#Selection de la figure
select = Select(title = 'Choisissez ce que vous voulez afficher :',
                value = 'Concession', options = ['Concession', 'Site'] ,margin=(10,0,0,30))
select.js_on_change('value', callback)

#texte
par3 = Paragraph(text="""Diagramme cicurlaire représentant les différentes cocnessions des principaux
                 ports de la région Bretagne, à savoir les ports de Brest, Lorient
                 et Saint-Malo. Vous pouvez visualiser sur le diagramme le type de concession
                 et le nombre de ports associé.""",margin=(100,0,0,30))

div3 = Div(text="""
Lien vers la base de données""",margin=(10,0,0,30))

# QUATRIEME VISUALISATION : CARTE DES CONCESSIONS ET ZONES PORTUAIRE ------------------------------------------------------------------------------

#Import des données
fp2 = open("espaces-de-concessions-des-ports-et-aeroports-appartenant-a-la-region-bretagne.geojson","r",encoding='utf-8')
dico2 = json.load(fp2)

#Construction du dictionnaire
site=[]
concession = []
coordx = []# les coordonnées x et y serviront à construire un multiplygone. Ils seront donc de la forme "[[[]]]"
coordy= []

for p in dico2["features"]:
    site.append(p["properties"]["site"])
    concession.append(p["properties"]["concession"])
    xc=[]
    yc=[]
    if(p["geometry"]):
        for c in p["geometry"]["coordinates"][0][0]:
            X,Y=coor_wgs84_to_web_mercator(c[0], c[1])
            xc.append(X)
            yc.append(Y)
    coordx.append([[xc]])
    coordy.append([[yc]])

#Construction du dataframe
df = pd.DataFrame({'site': site, 'concession':concession, 'coordx': coordx, 'coordy':coordy})
df_port = df[df['concession']!='AEROPORT']#On ne garde que les ports
source = ColumnDataSource(df_port)
source1 = ColumnDataSource(df_port)

#Creation de la carte
p4 = figure(margin=(10,0,10,0),width=1100,height=600,x_axis_type="mercator", y_axis_type="mercator", active_scroll="wheel_zoom", title="Zones portuaires et concessions de la région Bretagne",  tools="pan,wheel_zoom,box_zoom,reset")
tile_provider = get_provider(Vendors.CARTODBPOSITRON)
p4.add_tile(tile_provider)
print(df_port)
#Création des multipolygones pour les zones
p4.multi_polygons('coordx', 'coordy', source=source1,color = 'navy', fill_color='navy',
                     fill_alpha = 0.3)
hover_tool = HoverTool(tooltips=[('Site', '@site'),('Concessions', '@concession')])
p4.add_tools(hover_tool)

#Creation de l'outil de choix des ports
#On récupère la liste des ports et on créer le menu
ls=list(source.data['site'])
ls=list(set(ls))
menu = Dropdown(label='Choisissez un port', menu=ls,margin=(10,30,0,30))

#On créé un curtomJS pour changer les coordonnées des polygones suivant le choix du port
callback=CustomJS(args=dict(source=source1,ts=source), code="""
                    var data=ts.data;
                    var site=data['site'];

                    var concession=data['concession'];
                    var coordx=data['coordx'];
                    var coordy=data['coordy'];

                    var data1=source.data;
                    var f=cb_obj.item;

                    var s=[];
                    var c=[];
                    var x=[];
                    var y=[];

                    for(var i=0;i<concession.length; i++){
                        if(site[i]==f){
                          x.push(coordx[i]);
                          y.push(coordy[i]);
                          c.push(concession[i]);
                          s.push(site[i]);

                        }
                    }
                    data1['coordx']=x;
                    data1['coordy']=y;
                    data1['site']=s;
                    data1['concession']=c;

                    source.change.emit();
            """)

menu.js_on_event('menu_item_click', callback)

# Quelques éléments graphiques
p4.xaxis.ticker = []
p4.yaxis.ticker = []
p4.xgrid.grid_line_color = None
p4.ygrid.grid_line_color = None
p4.outline_line_width = 3
p4.outline_line_alpha = 1
p4.outline_line_color = "navy"
p4.toolbar.logo = None

#texte
par4 = Paragraph(text="""Carte représentant les différentes zones portuaires associées au choix du port. Pour chaque zone, vous trouverez le nom du site et la concession associée. (parfois nécéssaire de rafraîchir le graphique pour afficher correctement)""",margin=(100,30,0,30))

# PIED DE PAGE

div_pp = Div(text="""

 Page réalisée dans le cadre d'un projet de visualisation python sur Bokeh.

 Auteurs : Guillaume Béguec - Ewen Le Cunff - Maël Mandard

             """)

#affichage
layout = column(div_image,div_entete,par_entete,row(p2,column(par2, div2)), Div(text="""
"""),
                row( column(par1, date_range_slider, div1),p1),Div(text="""
"""),
                row(pie_chart, column(par3,select , div3)), Div(text="""
"""),
                row(column(par4, menu), p4),Div(text="""
"""),div_pp)
output_file(filename=("index.html"))

show(layout)


from trees.Tree import Tree
from trees.Node import Node
from trees.Stack import Stack
from trees.State import State

# create a tree and add some nodes
tree = Tree("apple")
tree.get_root().set_left_child(Node("banana"))
tree.get_root().set_right_child(Node("cherry"))
tree.get_root().get_left_child().set_left_child(Node("dates"))

def pre_order_with_stack(tree, debug_mode=False):
    visit_order = list()
    stack = Stack()
    node = tree.get_root()
    visit_order.append(node.get_value())
    state = State(node)
    stack.push(state)
    count = 0

    while node:
        if debug_mode:
            print(f"""
loop count: {count}
current node: {node}
stack:
{stack}
            """)
        count += 1
        if node.has_left_child() and not state.get_visited_left():
            state.set_visited_left()
            node = node.get_left_child()
            visit_order.append(node.get_value())
            state = State(node)
            stack.push(state)

        elif node.has_right_child() and not state.get_visited_right():
            state.set_visited_right()
            node = node.get_right_child()
            visit_order.append(node.get_value())
            state = State(node)

        else:
            stack.pop()
            if not stack.is_empty():
                state = stack.top()
                node = state.get_node()
            else:
                node = None

    if debug_mode:
        print(f"""
loop count: {count}
current node: {node}
stack:
{stack}
            """)
    return visit_order

pre_order_with_stack(tree, debug_mode=True)


# t_statistic.py
import scipy
import numpy as np
import matplotlib.pyplot as plt

def visualize_t_statistic():
    t_stat = -2.13165598142
    t_distibution = []
    num_bins = 1000
    for i in range(0, 10000000):
        t_distibution.append(scipy.random.standard_t(198))

    plt.hist(t_distibution, bins = num_bins,
             weights = np.array(len(t_distibution) * [1.0]) / len(t_distibution))
    plt.axvline(t_stat, color = 'w')
    plt.axvline(-t_stat, color = 'w')
    plt.title('T-Distribution with 198 Degrees of Freedom')
    plt.xlabel('T-statistic')
    plt.ylabel('Probability')
    plt.show()

if __name__ == '__main__':
    visualize_t_statistic()


from .queue_base import QueueManager
import theano
import theano.tensor as T
from theano.sandbox.rng_mrg import MRG_RandomStreams
import numpy as np
import constants

class QueuelessVariationalQueueManager( QueueManager ):
    """
    A variational-autoencoder-based manager which does not use the queue, with a configurable loss
    """

    def __init__(self, feature_size, period=None, variational_loss_scale=1):
        """
        Initialize the manager.

        Parameters:
            feature_size: The width of a feature
            period: Period for queue activations
            variational_loss_scale: Factor by which to scale variational loss
        """
        self._feature_size = feature_size
        self._period = period
        self._srng = MRG_RandomStreams(np.random.randint(0, 1024))
        self._variational_loss_scale = np.array(variational_loss_scale, np.float32)

    @property
    def activation_width(self):
        return self.feature_size*2

    @property
    def feature_size(self):
        return self._feature_size

    def helper_sample(self, input_activations):
        n_batch, n_time, _ = input_activations.shape
        means = input_activations[:,:,:self.feature_size]
        stdevs = abs(input_activations[:,:,self.feature_size:]) + constants.EPSILON
        wiggle = self._srng.normal(means.shape)

        vects = means + (stdevs * wiggle)

        strengths = T.zeros((n_batch, n_time))
        if self._period is None:
            strengths = T.set_subtensor(strengths[:,-1],1)
        else:
            strengths = T.set_subtensor(strengths[:,self._period-1::self._period],1)

        return strengths, vects, means, stdevs, {}

    def get_strengths_and_vects(self, input_activations):
        strengths, vects, means, stdevs, _ = self.helper_sample(input_activations)
        return strengths, vects

    def process(self, input_activations, extra_info=False):

        strengths, vects, means, stdevs, sample_info = self.helper_sample(input_activations)

        means_sq = means**2
        variance = stdevs**2
        loss_parts = 1 + T.log(variance) - means_sq - variance
        if self._period is None:
            loss_parts = loss_parts[:,-1]
        else:
            loss_parts = loss_parts[:,self._period-1::self._period]
        variational_loss = -0.5 * T.sum(loss_parts) * self._variational_loss_scale

        info = {"variational_loss":variational_loss}
        info.update(sample_info)
        if extra_info:
            return variational_loss, strengths, vects, info
        else:
            return variational_loss, strengths, vects


from common.python.utils import log_utils
from kernel.components.evaluation.evaluation import Evaluation
from kernel.components.evaluation.evaluation import PerformanceRecorder
from kernel.components.evaluation.param import EvaluateParam
from kernel.transfer.variables.transfer_class.validation_strategy_transfer_variable import \
    ValidationStrategyVariable
from kernel.utils import consts

LOGGER = log_utils.get_logger()

class ValidationStrategy(object):
    """
    This module is used for evaluating the performance of model during training process.
        it will be called only in fit process of models.

    Attributes
    ----------

    validation_freqs: None or positive integer or container object in python. Do validation in training process or Not.
                      if equals None, will not do validation in train process;
                      if equals positive integer, will validate data every validation_freqs epochs passes;
                      if container object in python, will validate data if epochs belong to this container.
                        e.g. validation_freqs = [10, 15], will validate data when epoch equals to 10 and 15.
                      Default: None

    train_data: None or DSource,
                if train_data not equal to None, and judge need to validate data according to validation_freqs,
                training data will be used for evaluating

    validate_data: None or DSource,
                if validate_data not equal to None, and judge need to validate data according to validation_freqs,
                validate data will be used for evaluating
    """

    def __init__(self, role=None, mode=None, validation_freqs=None, early_stopping_rounds=None,
                 use_first_metric_only=False):

        self.validation_freqs = validation_freqs
        self.role = role
        self.mode = mode
        self.flowid = ''
        self.train_data = None
        self.validate_data = None
        self.sync_status = False
        self.early_stopping_rounds = early_stopping_rounds
        self.use_first_metric_only = use_first_metric_only
        self.first_metric = None
        self.best_iteration = -1

        if early_stopping_rounds is not None:
            if early_stopping_rounds <= 0:
                raise ValueError('early stopping error should be larger than 0')
            if self.mode == consts.HORZ:
                raise ValueError('early stopping is not supported for horz algorithms')

            self.sync_status = True
            LOGGER.debug("early stopping round is {}".format(self.early_stopping_rounds))

        self.cur_best_model = None
        self.performance_recorder = PerformanceRecorder()
        self.transfer_inst = ValidationStrategyVariable()

        LOGGER.debug("end to init validation_strategy, freqs is {}".format(self.validation_freqs))

    def set_train_data(self, train_data):
        self.train_data = train_data

    def set_validate_data(self, validate_data):
        self.validate_data = validate_data
        if self.early_stopping_rounds and self.validate_data is None:
            raise ValueError('validate data is needed when early stopping is enabled')

    def set_flowid(self, flowid):
        self.flowid = flowid

    def need_run_validation(self, epoch):
        LOGGER.debug("validation_freqs is {}".format(self.validation_freqs))
        if not self.validation_freqs:
            return False

        if isinstance(self.validation_freqs, int):
            return (epoch + 1) % self.validation_freqs == 0

        return epoch in self.validation_freqs

    @staticmethod
    def generate_flowid(prefix, epoch, keywords="iteration", data_type="train"):
        return "_".join([prefix, keywords, str(epoch), data_type])

    @staticmethod
    def make_data_set_name(need_cv, model_flowid, epoch):
        data_iteration_name = "_".join(["iteration", str(epoch)])
        if not need_cv:
            return data_iteration_name

        cv_fold = "_".join(["fold", model_flowid.split(".", -1)[-1]])
        return ".".join([cv_fold, data_iteration_name])

    def is_best_performance_updated(self, use_first_metric_only=False):
        if len(self.performance_recorder.no_improvement_round.items()) == 0:
            return False
        for metric, no_improve_val in self.performance_recorder.no_improvement_round.items():
            if no_improve_val != 0:
                return False
            if use_first_metric_only:
                break
        return True

    def check_early_stopping(self, ):
        """
        check if satisfy early_stopping_round
        Returns bool
        """
        LOGGER.info('checking early stopping')

        no_improvement_dict = self.performance_recorder.no_improvement_round
        for metric in no_improvement_dict:
            if no_improvement_dict[metric] >= self.early_stopping_rounds:
                return True
        return False

    def sync_performance_recorder(self, epoch):
        """
        sync synchronize self.performance_recorder
        """
        if self.mode == consts.VERT and self.role == consts.PROMOTER:
            self.transfer_inst.validation_status.remote(self.performance_recorder, idx=-1, suffix=(epoch,))

        elif self.mode == consts.VERT:
            self.performance_recorder = self.transfer_inst.validation_status.get(idx=-1, suffix=(epoch,))[0]

        else:
            return

    def need_stop(self):
        return False if not self.early_stopping_rounds else self.check_early_stopping()

    def has_saved_best_model(self):
        return (self.early_stopping_rounds is not None) and (self.cur_best_model is not None)

    def export_best_model(self):
        if self.has_saved_best_model():
            return self.cur_best_model
        else:
            return None

    def evaluate(self, predicts, model, epoch):

        evaluate_param: EvaluateParam = model.get_metrics_param()
        evaluate_param.check_single_value_default_metric()

        eval_obj = Evaluation()
        eval_type = evaluate_param.eval_type

        metric_list = evaluate_param.metrics
        if self.early_stopping_rounds and self.use_first_metric_only and len(metric_list) != 0:

            single_metric_list = None
            if eval_type == consts.BINARY:
                single_metric_list = consts.BINARY_SINGLE_VALUE_METRIC
            elif eval_type == consts.REGRESSION:
                single_metric_list = consts.REGRESSION_SINGLE_VALUE_METRICS
            elif eval_type == consts.MULTY:
                single_metric_list = consts.MULTI_SINGLE_VALUE_METRIC

            for metric in metric_list:
                if metric in single_metric_list:
                    self.first_metric = metric
                    LOGGER.debug('use {} as first metric'.format(self.first_metric))
                    break

        eval_obj._init_model(evaluate_param)
        eval_obj.set_tracker(model.tracker)
        data_set_name = self.make_data_set_name(model.need_cv, model.flowid, epoch)
        eval_data = {data_set_name: predicts}
        eval_result_dict = eval_obj.fit(eval_data, return_result=True)
        eval_obj.output_data()
        LOGGER.debug("end to eval")

        return eval_result_dict

    def evaluate_data(self, model, epoch, data, data_type):
        if not data:
            return

        LOGGER.debug("start to evaluate data {}".format(data_type))
        model_flowid = model.flowid
        # model_flowid = ".".join(model.flowid.split(".", -1)[1:])
        flowid = self.generate_flowid(model_flowid, epoch, "iteration", data_type)
        model.set_flowid(flowid)
        predicts = model.predict(data)
        model.set_flowid(model_flowid)

        if self.mode == consts.HORZ and self.role == consts.ARBITER:
            pass
        elif self.mode == consts.VERT and self.role == consts.PROVIDER:
            pass
        else:
            predicts = predicts.mapValues(lambda value: value + [data_type])

        return predicts

    def validate(self, model, epoch):

        LOGGER.debug(
            "begin to check validate status, need_run_validation is {}".format(self.need_run_validation(epoch)))
        if not self.need_run_validation(epoch):
            return

        if self.mode == consts.HORZ and self.role == consts.ARBITER:
            return

        train_predicts = self.evaluate_data(model, epoch, self.train_data, "train")
        validate_predicts = self.evaluate_data(model, epoch, self.validate_data, "validate")

        if train_predicts is not None or validate_predicts is not None:

            predicts = train_predicts
            if validate_predicts:
                predicts = predicts.union(validate_predicts)

            eval_result_dict = self.evaluate(predicts, model, epoch)
            LOGGER.debug('showing eval_result_dict here')
            LOGGER.debug(eval_result_dict)

            if self.early_stopping_rounds:

                if len(eval_result_dict) == 0:
                    raise ValueError(
                        "eval_result len is 0, no single value metric detected for early stopping checking")

                if self.use_first_metric_only:
                    if self.first_metric:
                        eval_result_dict = {self.first_metric: eval_result_dict[self.first_metric]}
                    else:
                        LOGGER.warning('use first metric only but no single metric found in metric list')

                self.performance_recorder.update(eval_result_dict)

        if self.sync_status:
            self.sync_performance_recorder(epoch)
            LOGGER.debug('showing early stopping status, {} shows cur best performances'.format(self.role))
            LOGGER.debug(self.performance_recorder.cur_best_performance)
            LOGGER.debug('showing early stopping status, {} shows early stopping no improve rounds'.format(self.role))
            LOGGER.debug(self.performance_recorder.no_improvement_round)

        if self.early_stopping_rounds and self.is_best_performance_updated() and self.mode == consts.VERT:
            self.best_iteration = epoch
            best_model = model.export_model()
            self.cur_best_model = {'model': {'best_model': best_model}} if best_model is not None else None
            LOGGER.debug('cur best model saved, best iter is {}'.format(self.best_iteration))

            # model.tracker.save_training_best_model(best_model,self.best_iteration)


import unittest
from unittest.mock import Mock, patch

from huggingface_hub.utils import get_hf_hub_version, get_python_version
from huggingface_hub.utils._headers import _deduplicate_user_agent, _http_user_agent, build_hf_headers

from .testing_utils import handle_injection, handle_injection_in_test

# Only for tests that are not related to user agent
DEFAULT_USER_AGENT = _http_user_agent()

FAKE_TOKEN = "123456789"
FAKE_TOKEN_ORG = "api_org_123456789"
FAKE_TOKEN_HEADER = {
    "authorization": f"Bearer {FAKE_TOKEN}",
    "user-agent": DEFAULT_USER_AGENT,
}
NO_AUTH_HEADER = {"user-agent": DEFAULT_USER_AGENT}

@patch("huggingface_hub.utils._headers.HfFolder")
@handle_injection
class TestAuthHeadersUtil(unittest.TestCase):
    def test_use_auth_token_str(self) -> None:
        self.assertEqual(build_hf_headers(use_auth_token=FAKE_TOKEN), FAKE_TOKEN_HEADER)

    def test_use_auth_token_true_no_cached_token(self, mock_HfFolder: Mock) -> None:
        mock_HfFolder().get_token.return_value = None
        with self.assertRaises(EnvironmentError):
            build_hf_headers(use_auth_token=True)

    def test_use_auth_token_true_has_cached_token(self, mock_HfFolder: Mock) -> None:
        mock_HfFolder().get_token.return_value = FAKE_TOKEN
        self.assertEqual(build_hf_headers(use_auth_token=True), FAKE_TOKEN_HEADER)

    def test_use_auth_token_false(self, mock_HfFolder: Mock) -> None:
        mock_HfFolder().get_token.return_value = FAKE_TOKEN
        self.assertEqual(build_hf_headers(use_auth_token=False), NO_AUTH_HEADER)

    def test_use_auth_token_none_no_cached_token(self, mock_HfFolder: Mock) -> None:
        mock_HfFolder().get_token.return_value = None
        self.assertEqual(build_hf_headers(), NO_AUTH_HEADER)

    def test_use_auth_token_none_has_cached_token(self, mock_HfFolder: Mock) -> None:
        mock_HfFolder().get_token.return_value = FAKE_TOKEN
        self.assertEqual(build_hf_headers(), FAKE_TOKEN_HEADER)

    def test_write_action_org_token(self) -> None:
        with self.assertRaises(ValueError):
            build_hf_headers(use_auth_token=FAKE_TOKEN_ORG, is_write_action=True)

    def test_write_action_none_token(self, mock_HfFolder: Mock) -> None:
        mock_HfFolder().get_token.return_value = None
        with self.assertRaises(ValueError):
            build_hf_headers(is_write_action=True)

    def test_write_action_use_auth_token_false(self) -> None:
        with self.assertRaises(ValueError):
            build_hf_headers(use_auth_token=False, is_write_action=True)

    def test_implicit_use_disabled(self, mock_HfFolder: Mock) -> None:
        with patch(  # not as decorator to avoid friction with @handle_injection
            "huggingface_hub.constants.HF_HUB_DISABLE_IMPLICIT_TOKEN", True
        ):
            mock_HfFolder().get_token.return_value = FAKE_TOKEN
            self.assertEqual(build_hf_headers(), NO_AUTH_HEADER)  # token is not sent

    def test_implicit_use_disabled_but_explicit_use(self, mock_HfFolder: Mock) -> None:
        with patch(  # not as decorator to avoid friction with @handle_injection
            "huggingface_hub.constants.HF_HUB_DISABLE_IMPLICIT_TOKEN", True
        ):
            mock_HfFolder().get_token.return_value = FAKE_TOKEN

            # This is not an implicit use so we still send it
            self.assertEqual(build_hf_headers(use_auth_token=True), FAKE_TOKEN_HEADER)

class TestUserAgentHeadersUtil(unittest.TestCase):
    def _get_user_agent(self, **kwargs) -> str:
        return build_hf_headers(**kwargs)["user-agent"]

    @patch("huggingface_hub.utils._headers.get_fastai_version")
    @patch("huggingface_hub.utils._headers.get_fastcore_version")
    @patch("huggingface_hub.utils._headers.get_tf_version")
    @patch("huggingface_hub.utils._headers.get_torch_version")
    @patch("huggingface_hub.utils._headers.is_fastai_available")
    @patch("huggingface_hub.utils._headers.is_fastcore_available")
    @patch("huggingface_hub.utils._headers.is_tf_available")
    @patch("huggingface_hub.utils._headers.is_torch_available")
    @handle_injection_in_test
    def test_default_user_agent(
        self,
        mock_get_fastai_version: Mock,
        mock_get_fastcore_version: Mock,
        mock_get_tf_version: Mock,
        mock_get_torch_version: Mock,
        mock_is_fastai_available: Mock,
        mock_is_fastcore_available: Mock,
        mock_is_tf_available: Mock,
        mock_is_torch_available: Mock,
    ) -> None:
        mock_get_fastai_version.return_value = "fastai_version"
        mock_get_fastcore_version.return_value = "fastcore_version"
        mock_get_tf_version.return_value = "tf_version"
        mock_get_torch_version.return_value = "torch_version"
        mock_is_fastai_available.return_value = True
        mock_is_fastcore_available.return_value = True
        mock_is_tf_available.return_value = True
        mock_is_torch_available.return_value = True
        self.assertEqual(
            self._get_user_agent(),
            f"unknown/None; hf_hub/{get_hf_hub_version()};"
            f" python/{get_python_version()}; torch/torch_version;"
            " tensorflow/tf_version; fastai/fastai_version;"
            " fastcore/fastcore_version",
        )

    @patch("huggingface_hub.utils._headers.is_torch_available")
    @patch("huggingface_hub.utils._headers.is_tf_available")
    @handle_injection_in_test
    def test_user_agent_with_library_name_multiple_missing(
        self, mock_is_torch_available: Mock, mock_is_tf_available: Mock
    ) -> None:
        mock_is_torch_available.return_value = False
        mock_is_tf_available.return_value = False
        self.assertNotIn("torch", self._get_user_agent())
        self.assertNotIn("tensorflow", self._get_user_agent())

    def test_user_agent_with_library_name_and_version(self) -> None:
        self.assertTrue(
            self._get_user_agent(
                library_name="foo",
                library_version="bar",
            ).startswith("foo/bar;")
        )

    def test_user_agent_with_library_name_no_version(self) -> None:
        self.assertTrue(self._get_user_agent(library_name="foo").startswith("foo/None;"))

    def test_user_agent_with_custom_agent_string(self) -> None:
        self.assertTrue(self._get_user_agent(user_agent="this is a custom agent").endswith("this is a custom agent"))

    def test_user_agent_with_custom_agent_dict(self) -> None:
        self.assertTrue(self._get_user_agent(user_agent={"a": "b", "c": "d"}).endswith("a/b; c/d"))

    def test_user_agent_deduplicate(self) -> None:
        self.assertEqual(
            _deduplicate_user_agent(
                "python/3.7; python/3.8; hf_hub/0.12; transformers/None; hf_hub/0.12; python/3.7; diffusers/0.12.1"
            ),
            # 1. "python" is kept twice with different values
            # 2. "python/3.7" second occurrence is removed
            # 3. "hf_hub" second occurrence is removed
            # 4. order is preserved
            "python/3.7; python/3.8; hf_hub/0.12; transformers/None; diffusers/0.12.1",
        )


# -*- coding: utf-8 -*-
# __author__ = 'qingchen.zhang'

import os,re
import shutil
import gevent
from Bio import SeqIO
import numpy as np
import pandas as pd
from biocluster.module import Module
from biocluster.core.exceptions import OptionError
from biocluster.config import Config
from mbio.packages.metaasv.common_function import link_dir,link_file

class DeblurDenoiseSplitModule(Module):
    """
    按照样本进行拆分，Deblur 降噪, 基于训练好的数据进行降噪
    """
    def __init__(self, work_id):
        super(DeblurDenoiseSplitModule, self).__init__(work_id)
        options = [
            {"name": "fastq_dir", "type": "infile", "format": "sequence.fastq_dir"},##fastq_dir文件夹
            {'name': 'ref_fasta', 'type': 'infile', 'format': 'sequence.fasta'},  # 参考fasta序列,自定义模式上传的fasta文件
            {'name': 'database', 'type': 'string'},  # 数据库选择  用于选择参考数据库
            {"name": "min_sample_number", "type": "int", "default": 0},## 过滤长度的值
            {"name": "coverage", "type": "int", "default": 90},  # 根据90%的水平进行筛选， 理论上选择最小的文件
            {"name": "truc_len", "type": "int", "default": 0},##过滤长度的值，默认不过滤，如果不过滤deblur必须要对齐序列
            {"name": "min_size", "type": "int", "default": 1},
            {"name": "min_reads", "type": "int", "default": 10},
        ]
        self.add_option(options)
        self.fastq_dir = os.path.join(self.work_dir, "fastq_dir")
        self.trim_data = self.add_tool("metaasv.select_trimlength")
        self.file_list = []
        self.run_tools = []
        self.merge_tools = []

    def check_options(self):
        """
        参数二次检查
        :return:
        """
        if not self.option("fastq_dir").is_set:
            raise OptionError("请输入fastq文件夹！")
        if not self.option("database"):
            raise OptionError("请输入数据库类型！")

    def select_coverage(self):
        """
        根据每个样本的全部数据和占全部数据百分比的长度得到每个样本的trim长度
        :return:
        """
        options = {
            "fastq_dir":self.option("fastq_dir"),
            "coverage": self.option("coverage")
            }
        self.trim_data.set_options(options)
        self.trim_data.on("end", self.run_deblur)
        self.trim_data.run()

    def run_deblur(self):
        """
        运行软件deblur，非qiime2流程
        :return:
        """
        self.logger.info("min_sample_number: {}".format(self.option("truc_len")))
        if self.option("truc_len") == 0:
            result_path = os.path.join(self.trim_data.output_dir, "all_result.xls")
            min_number = self.get_min_seq_length(result_path)
        else:
            min_number = self.option("truc_len")
        if os.path.exists(self.fastq_dir):
            shutil.rmtree(self.fastq_dir)
        os.mkdir(self.fastq_dir)
        input_dir = self.option("fastq_dir").prop["path"]
        listdirs = os.listdir(input_dir)
        for file in listdirs:
            self.deblur = self.add_tool("metaasv.deblur_denoise_single")
            file_path = os.path.join(input_dir, file)
            new_file_path = os.path.join(self.fastq_dir, file)
            link_file(file_path, new_file_path)
            options = {
                "input_fastq": new_file_path,
                "database": self.option("database"),
                # "trim_length": self.option("trim_length"),
            }
            if self.option("ref_fasta").is_set:
                self.data_se = os.path.join(self.convert_file.output_dir, "data_se.qza")
                options["input_qza"] = self.data_se
            if self.option("ref_fasta").is_set:
                options["ref_fasta"] = os.path.join(self.taxon_file.output_dir, "ref_fasta.qza")## 用参考的序列
            if self.option("truc_len") != 0:
                options["truc_len"] = self.option("truc_len")
            elif self.option("coverage") != 0:
                options["truc_len"] = min_number
            else:
                options["truc_len"] = 90
            if self.option("min_size"):
                options["min_size"] = self.option("min_size")
            if self.option("min_reads"):
                options["min_reads"] = self.option("min_reads")
            self.deblur.set_options(options)
            self.run_tools.append(self.deblur)
        if len(self.run_tools) > 1:
            self.on_rely(self.run_tools, self.run_merge_file)
        else:
            self.run_tools[0].on('end', self.run_merge_file)
        for tool in self.run_tools:
            tool.run()
            gevent.sleep(0)

    def run_merge_file(self):
        """
        分别对feature-table、fasta和stat统计文件进行合并,fa去重
        :return:
        """
        asv_table = os.path.join(self.work_dir, "asv_table")
        if os.path.exists(asv_table):
            shutil.rmtree(asv_table)
        os.mkdir(asv_table)
        asv_fasta = os.path.join(self.work_dir, "asv_fasta")
        if os.path.exists(asv_fasta):
            shutil.rmtree(asv_fasta)
        os.mkdir(asv_fasta)
        n = 1
        j = 1
        for tool in self.run_tools:
            list_dirs = sorted(os.listdir(tool.output_dir))
            for file in list_dirs:
                file_path = os.path.join(tool.output_dir, file)
                if re.search(r'ASV_reps\.fa', file):
                    new_file = os.path.join(asv_fasta, file + str(n))
                    link_file(file_path, new_file)
                    n += 1
                elif re.search(r'ASV_table\.xls', file):
                    new_file = os.path.join(asv_table, file + str(j))
                    link_file(file_path, new_file)
                    j += 1

        self.merge1 = self.add_tool("metaasv.merge_file")
        options = {
            "input_dir": asv_table,
            "type": "table"
            }
        self.merge1.set_options(options)
        self.merge_tools.append(self.merge1)
        self.merge2 = self.add_tool("metaasv.merge_file")
        options = {
            "input_dir": asv_fasta,
            "type": "fasta"
            }
        self.merge2.set_options(options)
        self.merge_tools.append(self.merge2)

        if len(self.merge_tools) > 1:
            self.on_rely(self.merge_tools, self.create_mongo_data)
        else:
            self.merge_tools[0].on('end', self.create_mongo_data)
        for tool in self.merge_tools:
            tool.run()
            gevent.sleep(1)

    def create_mongo_data(self):
        """
        将ASV_table.xls和降噪后的序列文件统计信息进行合并
        :return:
        """
        result_dada = os.path.join(self.work_dir, "result_dada")
        if os.path.exists(result_dada):
            shutil.rmtree(result_dada)
        os.mkdir(result_dada)
        for tool in self.merge_tools:
            for file in sorted(os.listdir(tool.output_dir)):
                file_path = os.path.join(tool.output_dir, file)
                new_file = os.path.join(result_dada, file)
                link_file(file_path, new_file)
        asv_fasta = os.path.join(result_dada, "ASV_reps.fasta")
        asv_table_origin = os.path.join(result_dada, "ASV_table.xls")
        asv_table = pd.read_table(asv_table_origin, sep="\t", header=0)

        new_gene = {}
        number = 1
        ### 这里先对asv表的丰度进行过滤，然后根据过滤后的asv再提取序列，替换名称
        with open(asv_table_origin, 'r') as f, open(os.path.join(self.output_dir, "ASV_table.xls"), 'w') as w, open(os.path.join(self.output_dir, "ASV_md5.xls"), 'w') as outf:
            outf.write("ASV ID\tmd5\n")
            for line in f:
                if line.startswith("#OTU ID"):
                    line = line.strip().split("\t")
                    line[0] = "ASV ID"
                    new_line = "\t".join(line)
                    w.write(new_line+"\n")
                else:
                    line = line.strip().split("\t")
                    asv_id = line[0]
                    gene_name = "ASV" + str(number)
                    if asv_id not in new_gene:
                        new_gene[asv_id] = gene_name
                    line[0] = gene_name
                    asv_list = [float(x) for x in line[1:]]
                    total_asv_size = int(float(np.sum(asv_list)))
                    # choose_list = filter(lambda x: x != 0.0, asv_list)
                    # if len(choose_list) >= 2: ###在这里筛选asv_size，每条asv在至少两个样本中存在才保留，否则过滤掉
                    # if 10 >= self.option("min_reads"):
                    #     min_reads = 10
                    # else:
                    #     min_reads = self.option("min_reads")
                    if total_asv_size >= int(self.option("min_reads")):## 在这里筛选asv_abundance，所有样本的总和大于等于10的asv才会保留，否则过滤
                        number += 1
                        w.write("\t".join(line) + "\n")
                        outf.write("{}\t{}\n".format(gene_name, asv_id))

        with open(os.path.join(self.output_dir, "ASV_reps.fasta"), "w") as wf:
            for seq_record in SeqIO.parse(asv_fasta, 'fasta'):
                gene_id = seq_record.id
                gene_seq = seq_record.seq
                if gene_id in new_gene:
                    gene_name = new_gene[gene_id]
                    wf.write(">{}\n{}\n".format(gene_name, gene_seq))

        mongo_denoise_stat = self.work_dir + "/denoise_stat.xls"
        sample_list = list(asv_table.columns)[1:]
        sample_number_dict = {}
        sequence_number_dict = {}
        for sample in sample_list:
            asv_number = len(list(asv_table[sample][asv_table[sample] != 0.0]))
            if sample not in sample_number_dict:
                sample_number_dict[sample] = asv_number
            sequence_number = asv_table[sample][asv_table[sample] != 0.0].values.sum()
            if sample not in sequence_number_dict:
                sequence_number_dict[sample] = sequence_number

        denoise_path = result_dada + "/Deblur_sequence_info.txt"
        with open(mongo_denoise_stat, 'w') as w:
            w.write("Sample_Name\tAsv_Number\tSeq_Number\n")
            for sample in sample_list:
                if sample in sample_number_dict:
                    asv_num = sample_number_dict[sample]
                if sample in sequence_number_dict:
                    valied_number = sequence_number_dict[sample]
                w.write("{}\t{}\t{}\n".format(sample, asv_num, valied_number))
        if os.path.exists(denoise_path):
            os.remove(denoise_path)
        if os.path.exists(mongo_denoise_stat):
            os.rename(mongo_denoise_stat, denoise_path)
        self.run_convert_qza()

    def run_convert_qza(self):
        """
        转table转为qza文件
        :return:
        """
        qza_table = os.path.join(self.work_dir, "result_dada")
        allfiles = sorted(os.listdir(qza_table))
        for file in allfiles:
            file_path = os.path.join(qza_table, file)
            self.convert_qza = self.add_tool("metaasv.file_to_qzaqzv")
            if re.search(r'ASV_table', file):
                options = {
                "input_file": file_path,
                "type": "table",
                "prefix": "ASV_table"
                }
            elif re.search(r'ASV_reps', file):
                options = {
                "input_file": file_path,
                "type": "fasta",
                "prefix": "ASV_reps"
                }
            else:
                options = {
                    "input_file": file_path,
                    "type": "table",
                    "prefix": "Deblur_stats"
                }
            self.convert_qza.set_options(options)
            self.file_list.append(self.convert_qza)
        if len(self.file_list) > 1:
            self.on_rely(self.file_list, self.set_output)
        else:
            self.file_list[0].on("end", self.set_output)
        for tool in self.file_list:
            tool.run()
            gevent.sleep(0)

    def get_min_seq_length(self, inputfilr):
        """
        根据传入的inputfile获得最小值
        :param inputfilr:
        :return:
        """
        min_number_list = []
        with open(inputfilr, "r") as f:
            for line in f:
                line = line.strip().split("\t")
                sample_min = int(float(line[1]))
                if sample_min not in min_number_list:
                    min_number_list.append(sample_min)
        min_number = min(min_number_list)
        return min_number

    def set_output(self):
        """
        设置结果文件目录
        :return:
        """
        self.logger.info("开始设置结果文件目录！")
        dada2_stat = os.path.join(self.output_dir, "Deblur_sequence_info.txt")
        if not os.path.exists(dada2_stat):
            link_file(os.path.join(self.work_dir,"result_dada", "Deblur_sequence_info.txt"),dada2_stat)
        for tool in self.file_list:
            for file in os.listdir(tool.output_dir):
                file_path = os.path.join(tool.output_dir,file)
                out_path = os.path.join(self.output_dir, file)
                link_file(file_path, out_path)
        # for module in self.merge_tools:
        #     for file in os.listdir(module.output_dir):
        #         file_path = os.path.join(module.output_dir,file)
        #         out_path = os.path.join(self.output_dir, file)
        #         link_file(file_path, out_path)
        self.logger.info("设置结果文件目录成功！")
        self.end()

    def run(self):
        """
        运行
        :return:
        """
        super(DeblurDenoiseSplitModule, self).run()
        if self.option("truc_len") == 0:
            self.select_coverage()
        else:
            self.run_deblur()

    def end(self):
        """
        结束
        :return:
        """
        super(DeblurDenoiseSplitModule, self).end()


from gitlab.base import RequiredOptional, RESTManager, RESTObject
from gitlab.mixins import (
    CreateMixin,
    DeleteMixin,
    GetWithoutIdMixin,
    ObjectDeleteMixin,
    SaveMixin,
    UpdateMixin,
)

__all__ = [
    "ProjectPushRules",
    "ProjectPushRulesManager",
]

class ProjectPushRules(SaveMixin, ObjectDeleteMixin, RESTObject):
    _id_attr = None

class ProjectPushRulesManager(
    GetWithoutIdMixin, CreateMixin, UpdateMixin, DeleteMixin, RESTManager
):
    _path = "/projects/%(project_id)s/push_rule"
    _obj_cls = ProjectPushRules
    _from_parent_attrs = {"project_id": "id"}
    _create_attrs = RequiredOptional(
        optional=(
            "deny_delete_tag",
            "member_check",
            "prevent_secrets",
            "commit_message_regex",
            "branch_name_regex",
            "author_email_regex",
            "file_name_regex",
            "max_file_size",
        ),
    )
    _update_attrs = RequiredOptional(
        optional=(
            "deny_delete_tag",
            "member_check",
            "prevent_secrets",
            "commit_message_regex",
            "branch_name_regex",
            "author_email_regex",
            "file_name_regex",
            "max_file_size",
        ),
    )


# Displays IMDB's Top 100 movies that match a search string.
def main():
    searchWord = getWord()
    file = open("imdb.txt")
    line = search(file, searchWord)

    if(len(line) > 0):
        print("Rating\tYear\tTitle")
        matches = 0
        while(len(line) > 0):
            display(line)
            line = search(file, searchWord)
            matches += 1
        print(matches, "matches.")

def getWord():
    searchWord = input("Movie Name: ").lower()
    print()
    return searchWord

def search(file, searchWord):
    for line in file:
        lineLower = line.lower()
        if (searchWord in line):
            return line
    return ""

def display(line):
    parts = line.split()
    rating = parts[0]
    year = parts[-1]
    title = ""
    for i in range(1, len(parts)-1):
        title += parts[i] + " "
    print(rating + "\t" + year[1:-1] + "\t" + title)

main()


import random

class Movies:
    def __init__(self, tytul, rok, gatunek, odtworzenia):
        self.tytul = tytul
        self.rok = rok
        self.gatunek = gatunek
        self.odtworzenia = odtworzenia

    def play(self, step=1):
        self.odtworzenia += step

    def __str__(self):
        return f"{self.tytul} ({self.rok})"

    def __repr__(self):
        return f"{self.tytul} ({self.rok})"

class Series(Movies):
    def __init__(self, numer_odcinka, numer_sezonu, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.numer_odcinka = numer_odcinka
        self.numer_sezonu = numer_sezonu

    def __str__(self):
        return f"{self.tytul} S{self.numer_sezonu:02}E{self.numer_odcinka:02}"

    def __repr__(self):
        return f"{self.tytul} S{self.numer_sezonu:02}E{self.numer_odcinka:02}"

def get_kind(input_list, class_type):
    filtered_list = []
    for elem in input_list:
        if type(elem) == class_type:
            filtered_list.append(elem)
    filtered_list.sort(key=lambda x: x.tytul)
    return filtered_list

def get_movies(movies_and_series_list):
    return get_kind(movies_and_series_list, Movies)

def get_series(movies_and_series_list):
    return get_kind(movies_and_series_list, Series)

def lista_pozycji(lst_filmow_i_seriali, type):
    if type == 1:
        return get_movies(lst_filmow_i_seriali)
    elif type == 2:
        return get_series(lst_filmow_i_seriali)

def search(title, lista_filmow_i_seriali):
    is_found = False
    for elem in lista_filmow_i_seriali:
        if title == elem.tytul:
            print("Mamy tę pozycję w bibliotece")
            is_found = True
    if is_found == False:
        print("Nie ma takiego tytułu w bibliotece")

def generate_views(lista_filmow_i_seriali):
    n = random.randint(0, len(lista_filmow_i_seriali) - 1)
    m = random.randint(0, 100)
    lista_filmow_i_seriali[n].odtworzenia += m
    print(
        f"Odtworzenia pozycji {lista_filmow_i_seriali[n].tytul}: {lista_filmow_i_seriali[n].odtworzenia}"
    )

def generate_views_x10(lista_filmow_i_seriali):
    for i in range(10):
        generate_views(lista_filmow_i_seriali)

def top_titles(lista_filmow_i_seriali, n, type):
    top_list = []
    lst = []
    if type == 1:
        lst = get_movies(lista_filmow_i_seriali)
    elif type == 2:
        lst = get_series(lista_filmow_i_seriali)
    lst.sort(key=lambda list: list.odtworzenia, reverse=True)
    for i in range(n):
        top_list.append(lst[i])
    return top_list

if __name__ == "__main__":

    filmy_i_seriale = [
        Movies(tytul="Harold and Maude", rok=1984, gatunek="horror", odtworzenia=0),
        Movies(tytul="Odyseja kosmiczna", rok=1969, gatunek="sci-fi", odtworzenia=0),
        Movies(tytul="Abrakdabra", rok=2011, gatunek="sci-fi", odtworzenia=0),
        Series(
            tytul="Hallo allo",
            rok=1984,
            gatunek="horror",
            odtworzenia=0,
            numer_odcinka=3,
            numer_sezonu=4,
        ),
        Series(
            tytul="Breaking bad",
            rok=2000,
            gatunek="horror",
            odtworzenia=0,
            numer_odcinka=1,
            numer_sezonu=5,
        ),
        Series(
            tytul="True detective",
            rok=2001,
            gatunek="horror",
            odtworzenia=0,
            numer_odcinka=2,
            numer_sezonu=2,
        ),
    ]

    print(filmy_i_seriale)
    print()

    print(lista_pozycji(filmy_i_seriale, 1))
    print(lista_pozycji(filmy_i_seriale, 2))
    print()

    search("Hallo allo", filmy_i_seriale)
    print()

    generate_views(filmy_i_seriale)

    generate_views_x10(filmy_i_seriale)
    print()

    print(top_titles(filmy_i_seriale, 3, 2))


from turtle import Turtle, colormode
from random import randrange
SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600

colormode(255)

def rand_color():
    r = randrange(256)
    g = randrange(256)
    b = randrange(256)
    return r, g, b

class Car(Turtle):
    def __init__(self):
        super().__init__()
        self.car_list = []
        self.hideturtle()

    def create_cars(self, MAX_CARS):
        if len(self.car_list) < MAX_CARS:
            for i in range(MAX_CARS):
                a = "car" + f"{i}"
                a = Turtle(shape="square")
                a.penup()
                a.shapesize(stretch_wid=1, stretch_len=2)
                a.color(rand_color())
                a.setheading(180)
                a.goto(x=randrange(320, 1500), y=randrange(-250, 290))
                a.speed("slowest")
                self.car_list.append(a)
        else:
            self.reuse_cars()

    def move_cars(self, CAR_SPEED):
        if self.car_list:
            for i in range(len(self.car_list)):
                self.car_list[i].forward(CAR_SPEED)

    def reuse_cars(self):
        if self.car_list:
            for i in range(len(self.car_list)):
                if self.car_list[i].xcor() < -320:
                    self.car_list[i].hideturtle()
                    self.car_list[i].goto(x=randrange(500, 1500), y=randrange(-250, 290))
                    self.car_list[i].showturtle()
        else:
            print("something broke")