#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Tue Feb 25 20:03:31 2020

@author: b
"""

import numpy as np
values = [1, 2.4, 234, 112, 345]
array = np.array(values)
A = np.arange(1, 10, 1).reshape(3,3)
b = np.ones((3,6))

# indexing
A[0, 1]

# Slicing
# A[debut:fin:pas, debut:fin:pas]
A[:, 0]

# Subsetting
B = A[0:2, 0:2]

C = np.zeros((4, 4))
C[1:3, 1:3] = 1
C

A = np.random.randint(0, 10, [5, 5])
A

# Booelan indexing
A[A < 5] = 10
A[(A<5) & (A>2)] = 12

# Masking
A[A>5]

#Tableau de fonctions
def f(i,j):
    return 10*i +j
np.fromfunction(f,(4,5),dtype =int)

###############################################
# NUMPY STATISTIQUE ET MATHEMATIQUE
###############################################
# Méthode appartenant à la classe ndarray
A = np.random.randint(0, 10, [10, 3])
np.random.rand(6)   # tableaux aléatoires de 6 nombres
A.sum(axis=0)
A.cumsum()
A.prod() # produit entre les coefficients
A.min(axis=0) #minimum selon l'axe zéro
A.argmin(axis=0) # Position du minimum
A.sort()
A.argsort() # retourne la façon dont les éléments doient être ordonnés pour trier les éléments
A.mean() #variance
A.std() # écart type
A.var() #variance
A

np.corrcoef(A) #permet de tracer une matrice de corrélation
values, counts = np.unique(A, return_counts=True) #renvoie les entités et leur répétition
counts.argsort()
values[counts.argsort()] #liste dans l'ordre les éléments les plus fréquents

# Affiche les valeurs des plus fréquentes au moins fréquentes
for i, j in zip(values[counts.argsort()], counts[counts.argsort()]):
    print(f'valeur {i} apparait {j}')

#NAN Corrections
# les fonctions suivantes permettent de calculer une moyennes même avec une valeur nan
A = np.random.randn(5, 5)
A[2, 2] = np.nan
A[4, 1] = np.nan
np.nanmean(A)
np.nanstd(A)
np.isnan(A) #Masque numpy avec la présence des nan
np.isnan(A).sum()
np.isnan(A).sum()/A.size
A[np.isnan(A)]=0

###############################################
# NUMPY ALGEBRE LINEAIRE
###############################################
A = np.ones((2, 3))
B = np.ones((3, 2))
A.T #Transposé

A.dot(B) #Produit matricielle

# Inversion de matrice carré de déterminant non null
A = np.random.randint(0, 10, [3, 3])
A
np.linalg.det(A)
np.linalg.inv(A)
np.linalg.pinv(A) #permet d'inverser une matrice avec qq différences
# Principale Component Analysis utilise les valeurs propres
np.linalg.eig(A)

# Exercice: standardiser une matrice A
np.random.seed(0)
A = np.random.randint(0, 100, [10, 5])
A
# Ma solution
moy = A.mean(axis=0)
ecart = A.std(axis=0)
for col in range(5):
    A[:,col] = (A[:,col] - moy[col])/ecart[col]
#La solution de Guillaume
D = (A - A.mean(axis=0)) / A.std(axis=0)
D.mean(axis=0)
D.std(axis=0)

###############################################
# NUMPY BROADCASTING
###############################################
    # Le broadcasting consiste à étendre les dimensions d'un tableau
    # Il faut faire attention aux dimensions de nos jeux de données !!!
np.random.seed(0)
A = np.random.randint(0, 10, [2, 3])
B = np.ones((2, 1))

A + 2
A + B # Les colonnes de B ont été étendues selon les colonnes
# pour faire du broadcasting, il y a des règles
# A et B dimensions égales ou égales à 1
A = np.random.randint(0, 10, [4, 1])
B = np.ones((1, 3))
A + B #les dimensions des vecteurs ont été étendues


# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
from collections import deque

class Solution:
    def isSymmetrical(self, pRoot):
        if pRoot == None:
            return True

        queue = deque()
        stack = []
        queue.append(pRoot)
        stack.append(-1) # 注意这里，由于测试用例中有与根节点相同的val，所以这里设置为-1，避免根的val被栈弹出。

        while len(queue) > 0:
            elem = queue.popleft()
            if elem == None:
                continue
            else:
                queue.append(elem.left)
                if elem.left == None:
                    if elem.left == stack[-1]:
                        stack.pop()
                    else:
                        stack.append(None)
                elif elem.left.val == stack[-1]:
                    stack.pop()
                else:
                    stack.append(elem.left.val)

                queue.append(elem.right)
                if elem.right == None:
                    if elem.right == stack[-1]:
                        stack.pop()
                    else:
                        stack.append(None)
                elif elem.right.val == stack[-1]:
                    stack.pop()
                else:
                    stack.append(elem.right.val)

        if len(stack) == 1:
            return True
        return False

# 借鉴了层次遍历的思想，使用Python额外的数据结构双端队列deque，栈中保存遍历的元素的值，如果有两个值相等就弹栈，最后留下根节点的值，个人认为比较好理解。


#Korean vowel combination
con_dict = [

    ['ㅏㅣ','ㅐ'], ['ㅑㅣ','ㅒ'], ['ㅓㅣ','ㅔ'],
    ['ㅕㅣ','ㅖ'], ['ㅗㅣ','ㅚ'], ['ㅗㅐ','ㅙ'],
    ['ㅜㅓ','ㅝ'], ['ㅜㅔ','ㅞ'], ['ㅡㅣ','ㅢ'],
    ['ㅣㅏ','ㅑ'], ['ㅣㅓ','ㅕ'], ['ㅣㅗ','ㅛ'],
    ['ㅣㅜ','ㅠ'], ['ㅡㅓ','ㅓ'], ['ㅗㅏ','ㅘ'],

]

#jongsung_list = [ 'ㄱ', 'ㄲ', 'ㄳ', 'ㄴ', 'ㄵ', 'ㄶ', 'ㄷ', 'ㄹ', 'ㄺ', 'ㄻ', 'ㄼ', 'ㄽ', 'ㄾ', 'ㄿ', 'ㅀ', 'ㅁ', 'ㅂ', 'ㅄ', 'ㅅ', 'ㅆ', 'ㅇ', 'ㅈ', 'ㅊ', 'ㅋ', 'ㅌ', 'ㅍ', 'ㅎ']

# lis_beta = ['EP+EF', 'VCP+EF', 'B+EF', 'B+EP+EF', 'B+VCP+EF', 'EF','EP']

# lis_beta = ['EP+EF', 'EF', 'B+EF', 'B+EP+EF']

#어말을 처리해 주기 위한 것으로, 나중에 EC등이 필요해 진다면 이 부분에 EC 등을 집어넣어준다. 참고로 이는 문장의 마지막에 위치해야한다.
#특이 바로 밑의 이 부분은 형태소 태그가 이 리스트 안의 것과 일치하는 경우 단순 삭제를 하는 것
lis_beta_ef = ['EP+EP+EF', 'EP+EF', 'EF', 'UNKNOWN']
lis_beta_ef_h = ['EF', 'UNKNOWN']

lis_tag_last = ['EF', 'UNKNOWN']

# 존칭 명사 동사를 낮추기 위한 list
lis_wk = [

    ['ㄱㅖ', 'ㅇㅣㅆㅇㅡ'], ['ㅈㅜㅁㅜ','ㅈㅏ'], ['ㅈㅏㅂㅅㅜ','ㅁㅓㄱㅇㅡ']

]
# 존칭 종결어미
lis_end = [

    'ㅅㅡㅂㄴㅣㄷㅏ', 'ㅅㅡㅂㄴㅣㄲㅏ',
    'ㅂㄴㅣㄷㅏ', 'ㄴㅣㄷㅏ', 'ㅂㅅㅣㄷㅏ', 'ㅅㅣㄷㅏ', 'ㄹㄹㅐㅇㅛ','ㄹㅐㅇㅛ',
    'ㅇㅡㅅㅔㅇㅛ', 'ㅅㅔㅇㅛ', 'ㄷㅔㅇㅛ', 'ㅇㅔㅇㅛ', 'ㅇㅖㅇㅛ', 'ㄴㅏㅇㅛ', 'ㅇㅡㄹㄲㅏㅇㅛ', 'ㅇㅣㄹㄲㅏㅇㅛ', 'ㄹㄲㅏㅇㅛ', 'ㅇㅡㄴㄱㅏㅇㅛ', 'ㅇㅣㄴㄱㅏㅇㅛ','ㄱㅜㄴㅇㅛ','ㄴㄱㅏㅇㅛ',
    'ㄱㅗㅇㅛ','ㅇㅛ',
    'ㅈㅛ',
    'ㅅㅣㅂㅅㅣㅇㅗ', 'ㅅㅣㅇㅗ', 'ㅇㅗ',
    'ㅂㄴㅣㄲㅏ',

]

# 반말 종결어미
lis_end_2low = [

    'ㄷㅓㄹㅏ','ㄴㄷㅏ', 'ㅆㄷㅏ', 'ㄹㅗㄷㅏ', 'ㄷㅏ', 'ㄱㅔ', 'ㄴㅡㄴㄷㅏ',
    'ㄹㅏ',
    'ㅇㅑ',
    'ㄴㅣㄲㅏ', 'ㄲㅏ', 'ㄹㄲㅏ', 'ㅈㅣ',
    'ㄴㅣ',
    'ㅇㅏ', 'ㅇㅓ',
    'ㄷㅔ', 'ㄱㅏ','ㄹㅐ',
    'ㅈㅏㄶㅇㅏ', 'ㄴㅔ','ㅇㅕ', 'ㄴㅏ','ㄱㅜㄴ','ㄱㅗ',
    'ㅈㅣㅁㅏㄴ', 'ㅇㅡㄴㄷㅔ', 'ㅅㅓ', 'ㄷㅐ',
    'ㄱㅓㄹ','ㄲㅔ', 'ㄴㅑ',
]

lis_ic = ['ㅇㅖ', 'ㄴㅔ', 'ㅇㅏㄴㅣㅇㅗ', 'ㅇㅏㄴㅣㅇㅛ']

P_LIST = ['.', '?', '!', '\'', '\"', 'ᆞ', 'ᆢ', 'ㆍ',  '”', '’',')', '(', ',', '”']

SV_LIST = ['\'', '\"', ':', ';']

lis_plus = [

    'EP', 'VCP',

]
############################## EF Dictionary ##############################
###########################################################################

############ 높임말 -> 반말 ############
#현재 만들어진 것은 EF만 잘라낼 것이다.
#원래 ef사전에 mapping 되는 것을 찾아낸다.
#python dictionary로 접근
#종결어미 처리
EF = {
    ###하십시오체###
    #평서문
    #'ㅂㄴㅣㄷㅏ': 'ㄷㅏ',
    'ㅂㄴㅣㄷㅏ': 'special3',
    'ㅅㅡㅂㄴㅣㄷㅏ':'special2',
    'ㅇㅗㄹㅅㅣㄷㅏ':'ㄷㅏ', #**
    'ㅂㅈㅣㅇㅛ':'지', #**
    'ㅅㅣㅂㄴㅣㄷㅏ':'special1',
    'ㅇㅡㅅㅣㅂㄴㅣㄷㅏ':'ㅇㅡㅅㅣㄴㄷㅏ',
    'ㅇㅡㅅㅣㅂㄴㅣㄲㅏ':'ㅇㅡㅅㅣㄴㅣ',

    #의문문
    'ㅅㅡㅂㄴㅣㄲㅏ':'ㄴㅣ',
    'ㅂㄴㅣㄲㅏ': 'ㄴㅣ',
    'ㅅㅣㅂㄴㅣㄲㅏ':'special1', #EP+EF
    #명령법
    'ㅇㅡㅅㅔㅇㅛ': 'special0',
    'ㅅㅔㅇㅛ':'special1',
    'ㅅㅣㅇㅓㅇㅛ': 'special1',
    'ㅅㅣㅂㅅㅣㅇㅗ':'ㅅㅣㅇㅗ',
    #청유법
    'ㅂㅅㅣㄷㅏ':'special4',
    'ㅇㅡㅂㅅㅣㄷㅏ':'special4',
    ###하오체###

    ###해요체###
    #평서문
    'ㅇㅓㅇㅛ':'ㅇㅓ',
    'ㅇㅏㅇㅛ':'ㅇㅏ',
    'ㅈㅛ':'ㅈㅣ',
    'ㅇㅔㅇㅛ':'ㅇㅑ',
    'ㅇㅖㅇㅛ':'ㅇㅑ',
    'ㅇㅛ':'special5',
    'ㄷㅐㅇㅛ':'ㄷㅐ',
    'ㄷㅔㅇㅛ':'ㄷㅔ',
    'ㄴㅔㅇㅛ':'ㄴㅔ',
    'ㄴㅡㄴㄷㅔㅇㅛ':'ㄴㅡㄴㄷㅔ',
    'ㄱㅓㄷㅡㄴㅇㅛ':'ㄱㅓㄷㅡㄴ',
    'ㄱㅜㄴㅇㅛ': 'ㄱㅜㄴㅏ',
    'ㅇㅡㄴㄷㅔㅇㅛ':'ㅇㅡㄴㄷㅔ',
    'ㅈㅏㄱㅜㅇㅛ':'ㅈㅏㄱㅜ',
    'ㄴㅣㄲㅏㅇㅛ': 'ㄴㅣㄲㅏ',
    'ㅈㅣㅇㅛ':'ㅈㅣ',

    #의문문
    'ㄴㅏㅇㅛ':'special6',
    'ㄹㄲㅏㅇㅛ':'ㄹㄲㅏ',
    'ㅇㅡㄹㄲㅏㅇㅛ':'ㅇㅡㄹㄲㅏ',
    'ㄴㄱㅏㅇㅛ':'ㄴㄱㅏ',
    'ㄹㄹㅐㅇㅛ':'ㄹㄹㅐ',
    'ㄹㅐㅇㅛ':'ㄹㅐ',
    'ㄱㅗㅇㅛ':'ㄱㅗ',
    'ㅇㅡㄴㄱㅏㅇㅛ':'ㅇㅡㄴㄱㅏ',
    'ㅇㅣㄴㄱㅏㅇㅛ':'ㅇㅣㄴㄱㅏ',
}
need_origin_EF = {
    'ㅂㅅㅣㄷㅏ':'ㅈㅏ',
}
#'ㄹ'규칙 활용 -> ㄹ 규칙 활용이 일어나는 동사들을 최대한 모아둔 Dictionary
EF_R_rule= {
    'ㄱㅜ':'ㄹ',
    'ㄴㅗ':'ㄹ',
    'ㄴㅏ':'ㄹ',
    'ㄷㅗ':'ㄹ',
    'ㄷㅡ':'ㄹ',
    'ㄷㅏ':'ㄹ',
    'ㄷㅜ':'ㄹ',
    'ㅂㅜ':'ㄹ',
    'ㄲㅗ':'ㄹ',
    'ㅁㅣ':'ㄹ',
    'ㅁㅜ':'ㄹ',
    #'ㅂㅗㅍㅜ':'ㄹ', #error predicate 수정
    'ㅂㅜ':'ㄹ',
    'ㅅㅡ':'ㄹ',
    'ㄸㅓ':'ㄹ',
}

IC = {'ㅇㅖ':'ㅇㅡㅇ', 'ㄴㅔ':'ㅇㅡㅇ', 'ㅇㅏㄴㅣㅇㅗ':'ㅇㅏㄴㅣ', 'ㅇㅏㄴㅣㅇㅛ':'ㅇㅏㄴㅣ'}

formal_vv ={
    'ㄱㅖ':'ㅇㅣㅆㅇㅡ',
    'ㅈㅜㅁㅜ':'ㅈㅏ',
    'ㅈㅏㅂㅅㅜ':'ㅁㅓㄱㅇㅡ'
}


# Python XML DOM Minidom
# xml.dom.minidom — Minimal DOM implementation.
# xml.dom.minidom is a minimal implementation of the Document Object Model interface, with an API similar to that in other languages.
# It is intended to be simpler than the full DOM and also significantly smaller.
# Users who are not already proficient with the DOM should consider using the xml.etree.ElementTree module for their XML processing instead.
#

#
# Warning:
# The xml.dom.minidom module is not secure against maliciously constructed data.
# If you need to parse untrusted or unauthenticated data see XML vulnerabilities.
#

#
# This example program is a fairly realistic example of a simple program.
# In this particular case, we do not take much advantage of the flexibility of the DOM.
#

import xml.dom.minidom

document = """\
<slideshow>
<title>Demo slideshow</title>
<slide><title>Slide title</title>
<point>This is a demo</point>
<point>Of a program for processing slides</point>
</slide>

<slide><title>Another demo slide</title>
<point>It is important</point>
<point>To have more than</point>
<point>one slide</point>
</slide>
</slideshow>
"""

dom = xml.dom.minidom.parseString(document)

def getText(nodelist):
    rc = []

    for node in nodelist:

        if node.nodeType == node.TEXT_NODE:
            rc.append(node.data)

    return ''.join(rc)

def handleSlideshow(slideshow):
    print("")

    handleSlideshowTitle(slideshow.getElementsByTagName("title")[0])
    slides = slideshow.getElementsByTagName("slide")

    handleToc(slides)
    handleSlides(slides)

    print("")

def handleSlides(slides):
    for slide in slides:

        handleSlide(slide)

def handleSlide(slide):
    handleSlideTitle(slide.getElementsByTagName("title")[0])

    handlePoints(slide.getElementsByTagName("point"))

def handleSlideshowTitle(title):
    print("<title>%s</title>" % getText(title.childNodes))

def handleSlideTitle(title):
    print("
%s
" % getText(title.childNodes))

def handlePoints(points):
    print("
")

    for point in points:
        handlePoint(point)

    print("
")

def handlePoint(point):
    print("
%s
" % getText(point.childNodes))

def handleToc(slides):

    for slide in slides:
        title = slide.getElementsByTagName("title")[0]

        print("
%s
" % getText(title.childNodes))

handleSlideshow(dom)


from llama_index import ServiceContext, VectorStoreIndex, StorageContext
from llama_index.node_parser import SentenceWindowNodeParser
from llama_index.indices.postprocessor import MetadataReplacementPostProcessor
from llama_index.indices.postprocessor import SentenceTransformerRerank
from llama_index import load_index_from_storage
import os

def read_file(name):
    with open(name, "r") as file:
        return file.read()

def read_eval_questions(filename='./mi_questions.txt'):
    eval_questions = read_file(filename)
    eval_questions = [q for q in eval_questions.split('\n') if q]
    return eval_questions

def build_sentence_window_index(
    document, llm, embed_model="local:BAAI/bge-small-en-v1.5", save_dir="sentence_index"
):
    # create the sentence window node parser w/ default settings
    node_parser = SentenceWindowNodeParser.from_defaults(
        window_size=3,
        window_metadata_key="window",
        original_text_metadata_key="original_text",
    )
    sentence_context = ServiceContext.from_defaults(
        llm=llm,
        embed_model=embed_model,
        node_parser=node_parser,
    )
    if not os.path.exists(save_dir):
        sentence_index = VectorStoreIndex.from_documents(
            [document], service_context=sentence_context
        )
        sentence_index.storage_context.persist(persist_dir=save_dir)
    else:
        sentence_index = load_index_from_storage(
            StorageContext.from_defaults(persist_dir=save_dir),
            service_context=sentence_context,
        )

    return sentence_index

def get_sentence_window_query_engine(
    sentence_index,
    similarity_top_k=6,
    rerank_top_n=2,
):
    # define postprocessors
    postproc = MetadataReplacementPostProcessor(target_metadata_key="window")
    rerank = SentenceTransformerRerank(
        top_n=rerank_top_n, model="BAAI/bge-reranker-base"
    )

    sentence_window_engine = sentence_index.as_query_engine(
        similarity_top_k=similarity_top_k, node_postprocessors=[postproc, rerank]
    )
    return sentence_window_engine


import numpy as np
import findiff

def curl_2d (x,y,u,v):
  d_dy = findiff.FinDiff(0, y, acc=10)
  d_dx = findiff.FinDiff(1, x, acc=10)
  dv_dx = d_dx(v)
  du_dy = d_dy(u)
  curl_2d = dv_dx - du_dy
  # (nul, nul, D) = Derivative_Calc.cheb_derivative(velocity)
  # curl_2d = np.matmul(-v , D.transpose()) - np.matmul(D, u)
  return (curl_2d)


class Solution:
    def toGoatLatin(self, sentence: str) -> str:
        sentence = sentence.split()
        vowels = "aeiou"
        final = ""
        for i, word in enumerate(sentence):
            if word[0].lower() not in vowels:
                word = word[1:] + word[0] + "ma"
                print(word)
            elif word[0].lower() in vowels:
                word += "ma"
            word += ("a" * (i + 1))
            final += word + " "
        return final.strip()


def createTreeItem(key, value):
    """
    Maakt een nieuwe BST item aan met self.key=key en self.Root=value
    :param key: De zoeksleutel van het item.
    :param value: De waarde van het item.
    :return: Geeft de gemaakte BST terug.
    """
    Tree = BST()
    Tree.key = key
    Tree.Root = value
    return Tree

class BST:
    def __init__(self):  # Maakt een lege boom aan.
        """
        Maakt een boomklasse aan
        Preconditie:/
        Postconditie: Boomklasse gemaakt
        """
        self.Root = None
        self.left = None
        self.right = None
        self.key = None
        self.parent = None

    def isEmpty(self):  # Controleert of de boom leeg is, Zo ja geeft het True terug. Anders geeft het false terug.
        if self.Root == None:
            return True
        return False

    def searchTreeInsert(self, TreeItem):  # Insert een treeitem in de boom.
        """
        Insert een node
        :param TreeItem: De nieuweTreeitem
        :return: True of False afhankelijk of de node er al in zit of niet.

        Preconditie: Je kan geen node toevoegen met een key die al in de boom zit.
        Postconditie: Node is toegevoegd.
        """
        if BST.isEmpty(self):  # Als de boom leeg, is het nieuwe item de root.
            self.Root = TreeItem.Root
            self.key = TreeItem.key
            return True
        if BST.searchTreeRetrieve(self, TreeItem.key)[1]:  # Als er een item gevonden kan worden met dezelfde searchkey, dan kan je deze node niet toevoegen aan de boom.
            return False
        if self.key > TreeItem.key:  # Als  de key van het nieuwe item kleiner is controleren we of er een linkerkind is of niet. Zo ja, dan gaan we recursief tot we een plek vinden voor het nieuwe item. Zo nee, is het nieuwe item het linkerkind. En de ouder van het nieuwe item is de tree zelf.
            if self.left:
                return BST.searchTreeInsert(self.left, TreeItem)
            else:
                self.left = TreeItem
                self.left.parent = self
                return True
        else:
            if self.right:  # Als  de key van het nieuwe item groter is controleren we of er een rechterkind is of niet. Zo ja, dan gaan we recursief tot we een plek vinden voor het nieuwe item. Zo nee, is het nieuwe item het rechterkind. En de ouder van het nieuwe item is de tree zelf.
                return BST.searchTreeInsert(self.right, TreeItem)
            else:
                self.right = TreeItem
                self.right.parent = self
                return True

    def searchTreeRetrieve(self, key):
        """
        Zoekt een key in de tree en geeft de value terug.
        :param key: De searchkey van het item dat gevonden moet worden.
        :return:(value),True/False

        Precondities: Er mogen geen items in de boom zijn met eenzelfde zoeksleutel.
        Precondities: Geeft de value van de gezochte zoeksleutel terug.
        """
        if BST.isEmpty(self):  # Als de boom leeg is geeft het none terug als value en false als bool.
            return None, False
        if self.key == key:  # Als de huidige root dezelfde zoeksleutel heeft als de gezochte, wordt de waarde van de root samen met True teruggegeven.
            return self.Root, True
        if self.key > key:  # Als de key kleiner is dan de key van de huidige root, kijken we of er een linkerdeelboom is. Stel van wel, dan gaan we recursief op zoek naar ons item. Anders geven we None terug met bool false.
            if self.left:
                return BST.searchTreeRetrieve(self.left, key)
            return None, False
        if self.key < key:  # Als de key groter is dan de key van de huidige root, kijken we of er een rechterdeelboom is. Stel van wel, dan gaan we recursief op zoek naar ons item. Anders geven we None terug met bool false.
            if self.right:
                return BST.searchTreeRetrieve(self.right, key)
            return None, False

    def inorderTraverse(self, Functie=None,Traversed=[]):
        """
        Traversed de boom op inorder wijze. En afhankelijk van de functie doet het iets met die waarde.
        :param Functie: Wat er met de inorder waarden moet gebeuren. Print/Return/....., Als het niet ingevoerd wordt neemt de functie automatisch aan dat het een return is. Bij een return geven we de waarden gelijst terug, bij een print geven we ze gewoon afgedrukt terug.
        :param Traversed: Deze parameter wordt alleen maar gebruikt bij de return.
        :return:(Compleet afhankelijk van functie)

        Precondities:/
        Postcondities: Functie wordt uitgevoerd op de inorder items.
        """
        if (Functie!=None):
            if self.left != None:
                BST.inorderTraverse(self.left, Functie)
            Functie(self.key)
            if self.right != None:
                BST.inorderTraverse(self.right, Functie)
        else:
            if self.left != None:
                BST.inorderTraverse(self.left)
            Traversed.append(self.key)
            if self.right != None:
                BST.inorderTraverse(self.right)
        return Traversed

    def inorderSuccesor(self, Succ=True):
        if Succ:
            return BST.inorderSuccesor(self.right, False)  # Gaat recursief rechts af en kijkt bij de volgende recursie of er een node links is.
        if self.left:  # Zo ja recurseert hij over de linkse node anders geeft hij gewoon de current node terug.
            return BST.inorderSuccesor(self.left, False)
        return self
    def searchTreeDelete(self, item):
        """
        Delete een node uit een boom
        :param item: De te verwijderen node
        :return: (value/None,True/False)

        Preconditie: Als de root de enige node is mag je ze niet verwijderen
        Postconditie: Node is verwijdert
        """
        if not self.isEmpty():  # Kijkt of de boom leeg is of niet. Als die wel leeg is geeft hij gewoon false terug anders gaat hij verder.
            if item == self.key:  # Kijkt of de item gelijk is aan de huidige node zijn key.
                if self.left == None and self.right == None:  # Zo ja, controleert het of het een rechter kind of linker kind heeft,beiden of geen een.
                    if self.parent.left == self:
                        self.parent.left = None
                    elif self.parent.right == self:
                        self.parent.right = None
                elif self.right == None:  # Bij Als het linkerkind bestaat wisselt de methodie die van plaats met de parent en verwijderen we het item dat nu in een blad zit.
                    if self == self.parent.left:
                        self.parent.left = self.left
                    else:
                        self.parent.right = self.left
                elif self.left == None:  # Bij Als het rechterkind bestaat wisselt de methodie die van plaats met de parent en verwijderen we het item dat nu in een blad zit.
                    if self.parent:
                        if self == self.parent.right:
                            self.parent.right = self.right
                        else:
                            self.parent.left = self.right
                    else:
                        Succ = self.inorderSuccesor()
                        self.Root = Succ.Root
                        self.key = Succ.key
                        Succ.key = item
                        return Succ.searchTreeDelete(item)
                else:  # Vindt de inordersuccesor en wisselt die om met het te verwijderen item. Verwijder dan het item wanneer het een blad is. Dit is als er 2 kinderen zijn.
                    Succ = self.inorderSuccesor()
                    self.Root = Succ.Root
                    self.key = Succ.key
                    Succ.key = item
                    return Succ.searchTreeDelete(item)
                return True
            if item < self.key:  # Als item niet overeenkomt met self.key controleren we of deze groter of kleiner is dan de key en voeren we een recursief uit afhankelijk of het groter of kleiner is en of het linker of rechterkind bestaat.
                if self.left:
                    return BST.searchTreeDelete(self.left, item)
                return False
            if item > self.key:
                if self.right:
                    return BST.searchTreeDelete(self.right, item)
                return False
        return False

    def save(self):
        """
        Slaat de huidige boom op in een dict.
        :return: (Dict)

        Precondities:/
        Postcondities: Geeft de dictionary terug die van de boom is opgesteld.
        """
        Boompje = {"Root": None, "Children": []}  # Maakt een lege boomdict aan.
        if self.Root != None:  # Als de root in die boomdict leeg is wordt de root gelijkgesteld aan self.root.
            Boompje["Root"] = self.key
        if self.left != None:  # Als het linkerkind niet none is kijken we of het rechterkind none is. Zo ja voegen we een none waarde toe op de positie van het rechterkind. Anders niet
            if self.right == None:
                Boompje["Children"].append(self.left.save())
                Boompje["Children"].append(None)
            else:
                Boompje["Children"].append(self.left.save())
        if self.right != None:  # Exact hetzelfde als hierboven alleen omgedraaide volgorde.
            if self.left == None:
                Boompje["Children"].append(None)
                Boompje["Children"].append(self.right.save())
            else:
                Boompje["Children"].append(self.right.save())
        if len(Boompje["Children"]) == 0:  # Als de boom geen kinderen heeft wordt gewoon de onderstaande dict teruggegeven.
            return {"Root": self.key}
        if self == None:
            return {}
        return Boompje

    def emptyTree(self):  # Maakt de boom leeg.
        """
        Maakt de boom leeg voor het geval dat wij een nieuwe willen loaden.
        :return: /

        Precondities:/
        Postcondities: Maakt de boom leeg.
        """
        self.left=None
        self.right=None
        self.Root=None
        self.key=None

    def load(self, dict, NotEmpty=True):
        """
        Maakt de boom leeg en load een nieuwe daar in plaats.
        :param dict: De boom die moet worden ingeladen.
        :param Empty: Controleert of het leeg moet worden gemaakt of niet.
        :return:/

        Precondities:/
        Postcondities:Maakt de boom leeg en laad een nieuwe boom..
        """
        if NotEmpty:  # Als de boom niet leeg is wordt die leeggemaakt.
            BST.emptyTree(self)
        if len(dict) == 0 or dict=={}:  # Als de dict leeg is geeft het een lege boom terug.
            return BST.emptyTree(self)
        self.Root = dict["root"]  # Stelt de root gelijk aan de root van de dict.
        self.key = self.Root  # Stelt de key gelijk aan de root.
        if "children" in dict:  # Kijkt of het kinderen heeft.
            if dict['children'][
                0]:  # Als er een linkerkind is wordt self.left een bst klasse met parent de huidige root en worden de waarden recursief ingeladen.
                self.left = BST()
                self.left.parent = self
                self.left.load(dict['children'][0], False)
            if dict['children'][
                1]:  # Als er een rechterkind is wordt self.right een bst klasse met parent de huidige root en worden de waarden recursief ingeladen.
                self.right = BST()
                self.right.parent = self
                self.right.load(dict['children'][1], False)

class Table:
    def __init__(self):
        self.tree=BST()
    def tableIsEmpty(self):
        return self.tree.isEmpty()
    def tableInsert(self,key,Treeitem):
        return self.tree.searchTreeInsert(createTreeItem(key,Treeitem))
    def tableRetrieve(self,key):
        return self.tree.searchTreeRetrieve(key)
    def traverseTable(self,Func=None):
        return self.tree.inorderTraverse(Func)
    def load(self,NewTabel):
        return self.tree.load(NewTabel)
    def save(self):
        return self.tree.save()
    def tableDelete(self,key):
        return self.tree.searchTreeDelete(key)


#https://open.kattis.com/problems/detaileddifferences

#setting test case variable
testCase = input()

#creating for loop in range of test case
for i in range(int(testCase)):

    #get line 1 from user and then print
    line1 = input()
    print(line1)
    #get line 2 from user and then print
    line2 = input()
    print(line2)

    #make list from both lines in order to test each character
    line1 = list(line1)

    line2 = list(line2)

    #create a difference list
    diff = []

    #for in in range of line 1 (doesn't matter because each line is same length)
    for i in range(0, len(line1)):
        #if line 1 [i] is equal to line 2 [i], append the diff list with "."
        if line1[i] == line2[i]:
          diff.append(".")

        #else, append the diff list with "*"
        else:
          diff.append("*")

    #print the list after joining each character in list as a string
    print("".join([str(i) for i in diff]))


# 2023.09.19
# 빅데이터개론
# userListHeader.py
# zip, enumerate 함수를 구현

"""
    myZip function
    parameter: *args 가변인자, 매개변수의 수가 변할 수 있음
    여러 데이터가 합쳐진 형태를 튜플로 리턴 // list가 아니어도 묶을 수 있다
    이때 가장 짧은 길이의 데이터에 맞춤
"""
def myZip(*args):
    min_length = min(len(arg) for arg in args)  # len()은 이전에 구현했으니, 메소드를 바로 사용

    result = []
    for i in range(min_length):
        result.append(tuple(arg[i] for arg in args))

    return result

"""
    myEnumerate function
    parameter: <list> list_a
    여러 데이터가 합쳐진 형태를 리스트로 리턴
"""
def myEnumerate(list_a):
    index = 0
    enumerate_list = []

    for i in list_a:
        enumerate_list.append([index, i])
        index += 1

    return enumerate_list


class Solution:
    def taskSchedulerII(self, tasks: list[int], space: int) -> int:
        day = 0
        history: dict[int, int] = {}

        for task_i, task in enumerate(tasks):
            if task in history and day - history[task] <= space:
                day += space - (day - history[task]) + 1
            history[task] = day
            day += 1

        return day


'''
Given the heads of two singly linked-lists headA and headB, return the node at which the two lists intersect. If the two linked lists have no intersection at all, return null.
'''
# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution(object):
    def getIntersectionNode(self, headA, headB, s=None):
        """
        :type head1, head1: ListNode
        :rtype: ListNode
        """
        if not s:
            s = set()

        if not headA and not headB:
            return None

        if headA:
            if headA in s:
                return headA
            s.add(headA)
            headA = headA.next

        if headB:
            if headB in s:
                return headB
            s.add(headB)
            headB = headB.next

        return self.getIntersectionNode(headA, headB, s)

160. Intersection of Two Linked Lists.py


# -*- coding: utf-8 -*-
"""
Created on Thu Oct 25 15:04:22 2018

@author: Nagano Masatoshi
"""

import cv2
import os
#import ffmpeg as fp

def main():
    #動画を読み込む
    filename = './movie/output.mp4'
    video = cv2.VideoCapture(filename)

    path = 'movie2'
    if not os.path.exists(path):
        os.mkdir(path)

    savepath = 'image2'
    if not os.path.exists(savepath):
        os.mkdir(savepath)

    #フレーム数確認
    frames = int(video.get(7))
    print ('frame rate:',frames)

    for i in range(0,frames):
        _, frame = video.read()
        cv2.imwrite(savepath+"/%d.png"%i,frame)

if __name__ == '__main__':
    main()


class Solution(object):
    def maxArea(self, height):
        """
        :type height: List[int]
        :rtype: int
        """
        # start at both ends
        L = 0
        R = len(height)-1
        res = 0

        # consider conditions that can never have a maximum
        ## bottom length continues to decrease, key is height
        while L < R:
            area = (R-L)*min(height[R], height[L])
            res = max(res, area)

            # move the small y-axis value inward
            if height[L] > height[R]:
                R -= 1
            elif height[L] < height[R]:
                L += 1
            else:
                R -= 1
                L += 1

        return res


# from django.http import HttpResponse
from django.shortcuts import render
# from random import randint
# Create your views here.
from . models import Article # 같은 폴더 안의 models에서 Article을 사용할거야

def index(request):
    # random_number = randint(1,18)
    # return HttpResponse("Hello, word {}".format(random_number))

    # name = "Jay"
    # return render(request, "index.html", {"name" : name})

    article_list = Article.objects.all()

    # Article.objects.create(
    #     title = "hello^^",
    #     contents = "test",
    #     view_count = 0
    # )
    ctx = {
        "article_list" : article_list
    }
    return render(request, "index.html", ctx)


# -*- coding:utf-8 -*-
import os
from os import path
import random

def check_file(path='./',ext=''):
    _filelist = os.listdir(path)
    ch_e = []
    for _file in _filelist:
        _root, _ext = os.path.splitext(_file)
        if  _ext == ext:
            ch_e.append(_file)
        else:
            pass
    return ch_e

rootpath = path.dirname(path.abspath(__file__)) + '/'
#imagepaths = os.listdir(rootpath+'dataset')
path = rootpath + 'dataset'
imagepaths = check_file(path=path, ext='.jpg')
print(imagepaths)
val = random.sample(imagepaths,int(len(imagepaths)/5))
train = imagepaths
for item in val:
    train.remove(item)
with open('train.txt','w')as trainfile:
    for path in train:
        abspath = rootpath+'dataset/'+path+'\n'
        trainfile.write(abspath)

with open('val.txt','w')as valfile:
    for path in val:
        abspath = rootpath+'dataset/'+path+'\n'
        valfile.write(abspath)


def snail(arr):
    global N
    newX, newY = 0, 0
    dx = [1, 0, -1, 0]
    dy = [0, 1, 0, -1]
    dr_s = 0
    num = 1

    for i in range(N*N):
        X, Y = newX, newY
        arr[Y][X] = num
        newX = dx + dx[dr_s]
        newY = dy + dy[dr_s]

        if newX >= N or newX < 0 or newY >= N or newY < 0 or arr[newY][newX] != 0:
            dr_s = (dr_s + 1) % 4

import sys
sys.stdin = open('dfs.txt')

T = int(input())
for tc in range(1, T+1):
    N = int(input())
    arr = [[0 for _ in range(N)] for _ in range(N)]

    snail(arr)

    print('#{}'.format(tc))

    for i in range(N):
        for j in range(N):
            print(arr[i][j], end=" ")
        print()


import cv2
import os
import torch
import torch.nn as nn
import torchvision
import argparse
import numpy as np
import copy
from torch.autograd import Variable

pa = argparse.ArgumentParser()
pa.add_argument("--input_row", type=int, default=0)
pa.add_argument("--input_col", type=int, default=0)
pa.add_argument("--input_channel", type=int, default=0)

opt = pa.parse_args()
opt.input_row = 24
opt.input_col = 32
opt.input_channel = 1
print(opt)
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
# device = torch.device("cpu")
print("++++++++++Your CUDA is available!++++++++++" if torch.cuda.is_available() else "----------No CUDA available!----------")

def readDataL(num):
    paths = os.getcwd() + "/RobomasterNumData/" + str(num) + "L/"
    filelist = os.listdir(paths)
    AllDataSub = torch.rand(len(filelist), 1, 24, 32)
    for i in range(len(filelist)):
        I = cv2.imread(paths + filelist[i])
        I = cv2.resize(I, (opt.input_col, opt.input_row))
        I = cv2.cvtColor(I, cv2.COLOR_BGRA2GRAY)  # 原始图竟然是四通道的！！
        temp = torch.from_numpy(I)
        AllDataSub[i, 0, :, :] = temp
        # cv2.imshow("1", I)
        # cv2.waitKey(1)
    return AllDataSub

def readDataS(num):
    paths = os.getcwd() + "/RobomasterNumData/" + str(num) + "S/"
    filelist = os.listdir(paths)
    AllDataSub = torch.rand(len(filelist), 1, 24, 32)
    for i in range(len(filelist)):
        I = cv2.imread(paths + filelist[i])
        I = cv2.resize(I, (opt.input_col, opt.input_row))
        I = cv2.cvtColor(I, cv2.COLOR_BGRA2GRAY)  # 原始图竟然是四通道的！！
        temp = torch.from_numpy(I)
        AllDataSub[i, 0, :, :] = temp
        # cv2.imshow("1", I)
        # cv2.waitKey(1)
    return AllDataSub

class Num_Reg(nn.Module):
    def __init__(self):
        super(Num_Reg, self).__init__()
        self.convA = nn.Sequential(
            nn.Conv2d(
                in_channels=opt.input_channel,
                out_channels=10,
                kernel_size=5,
                stride=1,
                padding=2
            ),
            nn.ReLU(),
            nn.MaxPool2d(kernel_size=2)
        )
        self.convB = nn.Sequential(
            nn.Conv2d(
                in_channels=10,
                out_channels=30,
                kernel_size=5,
                stride=1,
                padding=2
            ),
            nn.ReLU(),
            nn.MaxPool2d(kernel_size=2)
        )
        self.f1 = nn.Linear(8 * 6 * 1 * 30, 200)
        self.f2 = nn.Linear(200, 16)

    def forward(self, x):
        x = self.convA(x)
        x = self.convB(x)
        x = x.view(x.size(0), -1)  # why it's -1
        x = self.f1(x)
        x = self.f2(x)
        return x

Recognizer = Num_Reg()
print("Your Model's structure: ", Recognizer)

# prepare the data
AllData1 = readDataL(1)
AllData2 = readDataL(2)
AllData3 = readDataL(3)
AllData4 = readDataL(4)
AllData5 = readDataL(5)
AllData6 = readDataL(6)
AllData7 = readDataL(7)
AllData8 = readDataL(8)

AllData1s = readDataS(1)
AllData2s = readDataS(2)
AllData3s = readDataS(3)
AllData4s = readDataS(4)
AllData5s = readDataS(5)
AllData6s = readDataS(6)
AllData7s = readDataS(7)
AllData8s = readDataS(8)
AllData = torch.cat((AllData1, AllData2, AllData3, AllData4, AllData5, AllData6, AllData7, AllData8,
                     AllData1s, AllData2s, AllData3s, AllData4s, AllData5s, AllData6s, AllData7s, AllData8s), 0)

# prepare the label
label = np.zeros((50 * 16), int)
k = 0
for i in range(16):
    for j in range(50):
        label[k] = i
        k = k + 1
        # print(k, "  ", label[k])
label = torch.from_numpy(label)

# test your label and your data
for j in range(800):
    cv2.imwrite("./TestImage/" + str(j) + "-" + str(label.numpy()[j]) + ".jpg", AllData[j, 0, :, :].numpy())
print("Here is your data's shape", AllData.shape)
print("Here is your label's shape", label.shape)

# exit(128)
# shuffle it
shuffle_kernel = np.arange(0, 800, 1)
np.random.shuffle(shuffle_kernel)

labeltemp = label.numpy()
labeltemp1 = copy.deepcopy(labeltemp)

AllDataTemp = copy.deepcopy(AllData)
for n in range(800):
    AllDataTemp[n, :, :, :] = AllData[shuffle_kernel[n], :, :, :]
    labeltemp1[n] = labeltemp[shuffle_kernel[n]]

label = torch.from_numpy(labeltemp1)
for n in range(800):
    cv2.imwrite("./TestImage2/" + str(n) + "-" + str(label.numpy()[n]) + ".jpg", AllDataTemp[n, 0, :, :].numpy())
AllData = copy.deepcopy(AllDataTemp)
# print("labeltemp1", labeltemp1)
# print("label", label)
# exit(255)

# optimizer = torch.optim.Adam(cnn.parameters(), lr=LR)   # optimize all cnn parameters
optimizer = torch.optim.Adam(Recognizer.parameters(), lr=0.001)  # optimize all cnn parameters
loss_func = nn.CrossEntropyLoss()  # the target label is not one-hotted
loss_func.cuda(device)
Recognizer.cuda(device)
for num in range(750):
    xx = AllData[num, :, :, :]
    x = torch.rand(1, 1, 24, 32)
    x[0, 0, :, :] = xx
    x = x / 255.0
    x = x.cuda(device)
    # print(type(x), x.is_floating_point(), x.dtype)

    label = label.cuda(device)
    y = Recognizer(x)[0]
    y = y.reshape(1, 16)
    y = y.cuda(device)
    # print(type(y), y.is_floating_point(), y.dtype)

    labelv = Variable(label[num])
    labelv = labelv.reshape(1)
    # labelv = labelv.to(torch.int64)
    labelv = labelv.cuda(device)
    # print(type(labelv), labelv.is_floating_point(), labelv.dtype)

    # print(y.shape, labelv)
    loss = loss_func(y, labelv)  # cross entropy loss
    optimizer.zero_grad()  # clear gradients for this training step
    loss.backward()  # backpropagation, compute gradients
    optimizer.step()  # apply gradients
    print("num: ", num)
print("OVER! ")

for rr in range(50):
    rrr = rr+750
    xx = AllData[rrr, :, :, :]
    x = torch.rand(1, 1, 24, 32)
    x[0, 0, :, :] = xx
    x = x/255.0
    # print(x.shape)
    x = x.cuda()
    test_output = Recognizer(x)[0]

    test_output = test_output.cpu()
    test_output = test_output.reshape(1, 16)
    # print(test_output)
    pred_y = torch.max(test_output, 1)[1].data.numpy()
    label = label.cpu()
    # print(rr, 'prediction number', pred_y, 'real number', label[rrr], test_output, pred_y == label[rrr].numpy())
    print(rr, 'prediction number', pred_y, 'real number', label[rrr], pred_y == label[rrr].numpy())

torch.save(Recognizer, "./RoboMaterData.t7")
print("OVER! ")


def reverse_string_1(s):
    return ' '.join(reversed(s.split()))

def reverse_string(s):
    length = len(s)

    words = list()
    spaces = [' ']
    i = 0
    while i < length:
        if s[i] not in spaces:
            word_start = i
            while i < length and i not in spaces:
                i += 1
            words.append(s[word_start:i])
        i += 1
    # print(f'show me i = {i} and coutner = {counter}')
    return words
    # while len(words) > 0:
    #     temp = words.pop(-1)
    #     print(temp)
    #     result = result + ' ' + temp
    # return result

# print(reverse_string_1('Hello World this is Sam'))
# print(reverse_string('Hello World this is Sam'))
# st = []
# lst = 'abcdefghi'
# st.append(lst[0:2])
# st.append(lst[2:4])
# print(st)

# def rev(s):
#     return s.split()[::-1]

# print(rev('Hello World this is Sam'))

ls = [1,1,2]
s = set()
for i in ls:
    s.add(i)
print(len(s))


"""
This unit test tests the uri resolver.
It is often the case, that a taxonomy schema imports another taxonomy using a relative path.
i.e:
<link:linkbaseRef [..] xlink:href="./../example_lab.xml" [..]/>
The job of the uri resolver is to resolve those relative paths and urls and return an absolute path or url
"""
import logging
import sys
import unittest

from xbrl.transformations import normalize, TransformationException

logging.basicConfig(stream=sys.stdout, level=logging.INFO)

testTransforms = {
    "http://www.xbrl.org/inlineXBRL/transformation/2010-04-20": [
        # [format,value,expected]
        ['datedoteu', '17.07.22', '2022-07-17'],
        ['datedoteu', '17.07.2022', '2022-07-17'],

        ['datedotus', '07.17.22', '2022-07-17'],
        ['datedotus', '07.17.2022', '2022-07-17'],

        ['datelonguk', '17 July 2022', '2022-07-17'],
        ['datelonguk', '17 July 22', '2022-07-17'],
        ['datelonguk', '7 February 2022', '2022-02-07'],

        ['datelongus', 'July 17, 2022', '2022-07-17'],
        ['datelongus', 'July 17, 22', '2022-07-17'],
        ['datelongus', 'February 7, 2022', '2022-02-07'],

        ['dateshortuk', '17 Jul. 2022', '2022-07-17'],
        ['dateshortuk', '17 Jul. 22', '2022-07-17'],
        ['dateshortuk', '7 Feb. 2022', '2022-02-07'],

        ['dateshortus', 'Jul. 17, 2022', '2022-07-17'],
        ['dateshortus', 'Jul. 17, 22', '2022-07-17'],
        ['dateshortus', 'Feb. 7, 2022', '2022-02-07'],

        ['dateslasheu', '17/07/2022', '2022-07-17'],
        ['dateslasheu', '17/07/22', '2022-07-17'],

        ['dateslashus', '07/17/2022', '2022-07-17'],
        ['dateslashus', '07/17/22', '2022-07-17'],

        ['datelongdaymonthuk', '17 July', '--07-17'],
        ['datelongdaymonthuk', '7 February', '--02-07'],

        ['datelongmonthdayus', 'July 17', '--07-17'],
        ['datelongmonthdayus', 'February 7', '--02-07'],

        ['dateshortdaymonthuk', '17 Jul.', '--07-17'],
        ['dateshortdaymonthuk', '7 Feb', '--02-07'],

        ['dateshortmonthdayus', 'Jul. 17', '--07-17'],
        ['dateshortmonthdayus', 'Feb 7', '--02-07'],

        ['dateslashdaymontheu', '7/2', '--02-07'],
        ['dateslashdaymontheu', '07/02', '--02-07'],

        ['dateslashmonthdayus', '2/7', '--02-07'],
        ['dateslashmonthdayus', '02/07', '--02-07'],

        ['datelongyearmonth', '22 February', '2022-02'],
        ['datelongyearmonth', '2022 February', '2022-02'],

        ['dateshortyearmonth', '22 Feb.', '2022-02'],
        ['dateshortyearmonth', '2022 Feb', '2022-02'],

        ['datelongmonthyear', 'February 22', '2022-02'],
        ['datelongmonthyear', 'February 2022', '2022-02'],

        ['dateshortmonthyear', 'Feb. 22', '2022-02'],
        ['dateshortmonthyear', 'Feb 2022', '2022-02'],

        ['numcomma', '1400,40', '1400.40'],
        ['numcomma', '1,40', '1.40'],

        ['numcommadot', '1,400.40', '1400.40'],
        ['numcommadot', '1,000,400.40', '1000400.40'],

        ['numdash', 'any value', '0'],

        ['numdotcomma', '123.123.123,12', '123123123.12'],

        ['numspacecomma', '123 123 123,12', '123123123.12'],

        ['numspacedot', '123 123 123.12', '123123123.12']
    ],
    "http://www.xbrl.org/inlineXBRL/transformation/2011-07-31": [
        # [format,value,expected]
        ['booleanfalse', 'any string', 'false'],

        ['booleantrue', 'any string', 'true'],

        ['datedaymonth', '2.1', '--01-02'],
        ['datedaymonth', '02*01', '--01-02'],

        ['datedaymonthen', '2. January', '--01-02'],
        ['datedaymonthen', '02*Jan', '--01-02'],

        ['datedaymonthyear', '2*1*22', '2022-01-02'],
        ['datedaymonthyear', '02 01 2022', '2022-01-02'],

        ['datedaymonthyearen', '2*Jan*22', '2022-01-02'],
        ['datedaymonthyearen', '02 January 2022', '2022-01-02'],

        ['datemonthday', '2 1', '--02-01'],
        ['datemonthday', '02-01', '--02-01'],

        ['datemonthdayen', 'Feb. 1', '--02-01'],
        ['datemonthdayen', 'February 1', '--02-01'],

        ['datemonthdayyear', '12.01.99', '1999-12-01'],
        ['datemonthdayyear', '12.01.1999', '1999-12-01'],

        ['datemonthdayyearen', 'Dec. 1 99', '1999-12-01'],
        ['datemonthdayyearen', 'December 01 99', '1999-12-01'],

        ['datemonthyearen', 'Dec. 99', '1999-12'],
        ['datemonthyearen', 'December 1999', '1999-12'],

        ['dateyearmonthen', '99 Dec.', '1999-12'],
        ['dateyearmonthen', '1999 December', '1999-12'],

        ['nocontent', 'any string', ''],

        ['numcommadecimal', '123 123 123,123', '123123123.123'],
        ['numcommadecimal', '123.123.123,123', '123123123.123'],

        ['numdotdecimal', '123 123 123.123', '123123123.123'],
        ['numdotdecimal', '123,123,123.123', '123123123.123'],

        ['zerodash', '-', '0'],
    ],
    "http://www.xbrl.org/inlineXBRL/transformation/2015-02-26": [
        # [format,value,expected]
        ['booleanfalse', 'nope', 'false'],

        ['booleantrue', 'yeah', 'true'],

        ['datedaymonth', '11.12', '--12-11'],
        ['datedaymonth', '1.2', '--02-01'],

        ['datedaymonthen', '2. December', '--12-02'],
        ['datedaymonthen', '2 Sept.', '--09-02'],
        ['datedaymonthen', '14.    april', '--04-14'],

        ['datedaymonthyear', '2.12.2021', '2021-12-02'],
        ['datedaymonthyear', '1.1.99', '1999-01-01'],
        ['datedaymonthyear', '18. 02 2022', '2022-02-18'],

        ['datedaymonthyearen', '02. December 2021', '2021-12-02'],
        ['datedaymonthyearen', '13. Dec. 21', '2021-12-13'],
        ['datedaymonthyearen', '1 Feb 99', '1999-02-01'],

        ['datemonthday', '1.2', '--01-02'],
        ['datemonthday', '12-1', '--12-01'],
        ['datemonthday', '1.30', '--01-30'],

        ['datemonthdayen', 'Jan 02', '--01-02'],
        ['datemonthdayen', 'February 13', '--02-13'],
        ['datemonthdayen', 'sept. 1', '--09-01'],

        ['datemonthdayyear', '12-30-2021', '2021-12-30'],
        ['datemonthdayyear', '2-16-22', '2022-02-16'],
        ['datemonthdayyear', '2-1-2019', '2019-02-01'],

        ['datemonthdayyearen', 'March 31, 2021', '2021-03-31'],
        ['datemonthdayyearen', 'Dec. 31, 22', '2022-12-31'],
        ['datemonthdayyearen', 'april 12 2021', '2021-04-12'],

        ['datemonthyear', '12 2021', '2021-12'],
        ['datemonthyear', '1 22', '2022-01'],
        ['datemonthyear', '02-1999', '1999-02'],

        ['datemonthyearen', 'December 2021', '2021-12'],
        ['datemonthyearen', 'apr. 22', '2022-04'],
        ['datemonthyearen', 'Sept. 2000', '2000-09'],

        ['dateyearmonthday', '2021.12.31', '2021-12-31'],
        ['dateyearmonthday', '2021 1  31', '2021-01-31'],
        ['dateyearmonthday', '22-1-1', '2022-01-01'],

        ['dateyearmonthen', '2021 December', '2021-12'],
        ['dateyearmonthen', '22 sept.', '2022-09'],
        ['dateyearmonthen', '21.apr.', '2021-04'],

        ['nocontent', 'Bla bla', ''],

        ['numcommadecimal', '1.499,99', '1499.99'],
        ['numcommadecimal', '100*499,999', '100499.999'],
        ['numcommadecimal', '0,5', '0.5'],

        ['numdotdecimal', '1,499.99', '1499.99'],
        ['numdotdecimal', '1*499', '1499'],
        ['numdotdecimal', '1,000,000.5', '1000000.5'],

        ['zerodash', '--', '0'],
    ],
    "http://www.xbrl.org/inlineXBRL/transformation/2020-02-12": [
        # [format,value,expected]
        ['date-day-month', '1.1', '--01-01'],
        ['date-day-month', '31-12', '--12-31'],
        ['date-day-month', '27*2', '--02-27'],

        ['date-day-month-year', '1-2-20', '2020-02-01'],
        ['date-day-month-year', '1-02-20', '2020-02-01'],
        ['date-day-month-year', '01 02 2020', '2020-02-01'],

        ['date-day-monthname-en', '1. sept.', '--09-01'],
        ['date-day-monthname-en', '01. sep.', '--09-01'],
        ['date-day-monthname-en', '30 August', '--08-30'],

        ['date-day-monthname-year-en', '30 August 22', '2022-08-30'],
        ['date-day-monthname-year-en', '01 Aug 22', '2022-08-01'],
        ['date-day-monthname-year-en', '1 Aug 2022', '2022-08-01'],

        ['date-month-day', '1 31', '--01-31'],
        ['date-month-day', '01-31', '--01-31'],
        ['date-month-day', '12.1', '--12-01'],

        ['date-month-day-year', '12. 1 22', '2022-12-01'],
        ['date-month-day-year', '01/12/2022', '2022-01-12'],
        ['date-month-day-year', '01.12.2022', '2022-01-12'],

        ['date-month-year', '1*22', '2022-01'],
        ['date-month-year', '01  22', '2022-01'],
        ['date-month-year', '12.2022', '2022-12'],

        ['date-monthname-day-en', 'April/1', '--04-01'],
        ['date-monthname-day-en', 'Sept./20', '--09-20'],
        ['date-monthname-day-en', 'december 31', '--12-31'],

        ['date-monthname-day-year-en', 'december 31, 22', '2022-12-31'],
        ['date-monthname-day-year-en', 'dec. 31, 2022', '2022-12-31'],
        ['date-monthname-day-year-en', 'dec. 1, 2022', '2022-12-01'],

        ['date-year-month', '99/1', '1999-01'],
        ['date-year-month', '2022 - 12', '2022-12'],
        ['date-year-month', '2022 -/ 1', '2022-01'],

        ['date-year-month-day', '   22-1-2 ', '2022-01-02'],
        ['date-year-month-day', ' 2022/1/2 ', '2022-01-02'],
        ['date-year-month-day', '  22/01/02 ', '2022-01-02'],

        ['date-year-monthname-en', '22/december', '2022-12'],
        ['date-year-monthname-en', '22/dec.', '2022-12'],
        ['date-year-monthname-en', '2022-dec', '2022-12'],

        ['fixed-empty', 'some text', ''],
        ['fixed-false', 'some text', 'false'],
        ['fixed-true', 'some text', 'true'],
        ['fixed-zero', 'some text', '0'],

        ['num-comma-decimal', '1.499,99', '1499.99'],
        ['num-comma-decimal', '100*499,999', '100499.999'],
        ['num-comma-decimal', '0,5', '0.5'],

        ['num-dot-decimal', '1,499.99', '1499.99'],
        ['num-dot-decimal', '1*499', '1499'],
        ['num-dot-decimal', '1,000,000.5', '1000000.5'],

    ],
    "http://www.sec.gov/inlineXBRL/transformation/2015-08-31": [
        # [format,value,expected]
        ['duryear', '-22.3456', '-P22Y4M4D'],
        ['duryear', '21.84480', 'P21Y10M5D'],
        ['duryear', '+0.3456', 'P0Y4M4D'],

        ['durmonth', '22.3456', 'P22M10D'],
        ['durmonth', '-0.3456', '-P0M10D'],

        ['durwordsen', 'Five years, two months', 'P5Y2M0D'],
        ['durwordsen', '9 years, 2 months', 'P9Y2M0D'],
        ['durwordsen', '12 days', 'P0Y0M12D'],
        ['durwordsen', 'ONE MONTH AND THREE DAYS', 'P0Y1M3D'],

        ['numwordsen', 'no', '0'],
        ['numwordsen', 'None', '0'],
        ['numwordsen', 'nineteen hundred forty-four', '1944'],
        ['numwordsen', 'Seventy Thousand and one', '70001'],

        ['boolballotbox', '☐', 'false'],
        ['boolballotbox', '☐', 'false'],
        ['boolballotbox', '☑', 'true'],
        ['boolballotbox', '☑', 'true'],
        ['boolballotbox', '☒', 'true'],
        ['boolballotbox', '☒', 'true'],

        ['exchnameen', 'The New York Stock Exchange', 'NYSE'],
        ['exchnameen', 'New York Stock Exchange LLC', 'NYSE'],
        ['exchnameen', 'NASDAQ Global Select Market', 'NASDAQ'],
        ['exchnameen', 'The Nasdaq Stock Market LLC', 'NASDAQ'],
        ['exchnameen', 'BOX Exchange LLC', 'BOX'],
        ['exchnameen', 'Nasdaq BX, Inc.', 'BX'],
        ['exchnameen', 'Cboe C2 Exchange, Inc.', 'C2'],
        ['exchnameen', 'Cboe Exchange, Inc.', 'CBOE'],
        ['exchnameen', 'Chicago Stock Exchange, Inc.', 'CHX'],
        ['exchnameen', 'Cboe BYX Exchange, Inc.', 'CboeBYX'],
        ['exchnameen', 'Cboe BZX Exchange, Inc.', 'CboeBZX'],
        ['exchnameen', 'Cboe EDGA Exchange, Inc.', 'CboeEDGA'],
        ['exchnameen', 'Cboe EDGX Exchange, Inc.', 'CboeEDGX'],
        ['exchnameen', 'Nasdaq GEMX, LLC', 'GEMX'],
        ['exchnameen', 'Investors Exchange LLC', 'IEX'],
        ['exchnameen', 'Nasdaq ISE, LLC', 'ISE'],
        ['exchnameen', 'Miami International Securities Exchange', 'MIAX'],
        ['exchnameen', 'Nasdaq MRX, LLC', 'MRX'],
        ['exchnameen', 'NYSE American LLC', 'NYSEAMER'],
        ['exchnameen', 'NYSE Arca, Inc.', 'NYSEArca'],
        ['exchnameen', 'NYSE National, Inc.', 'NYSENAT'],
        ['exchnameen', 'MIAX PEARL, LLC', 'PEARL'],
        ['exchnameen', 'Nasdaq PHLX LLC', 'Phlx'],

        ['stateprovnameen', 'Alabama', 'AL'],
        ['stateprovnameen', 'Alaska', 'AK'],
        ['stateprovnameen', 'Arizona', 'AZ'],
        ['stateprovnameen', 'Arkansas', 'AR'],
        ['stateprovnameen', 'California', 'CA'],
        ['stateprovnameen', 'Colorado', 'CO'],
        ['stateprovnameen', 'Connecticut', 'CT'],
        ['stateprovnameen', 'Delaware', 'DE'],
        ['stateprovnameen', 'Florida', 'FL'],
        ['stateprovnameen', 'Georgia', 'GA'],
        ['stateprovnameen', 'Hawaii', 'HI'],
        ['stateprovnameen', 'Idaho', 'ID'],
        ['stateprovnameen', 'Illinois', 'IL'],
        ['stateprovnameen', 'Indiana', 'IN'],
        ['stateprovnameen', 'Iowa', 'IA'],
        ['stateprovnameen', 'Kansas', 'KS'],
        ['stateprovnameen', 'Kentucky', 'KY'],
        ['stateprovnameen', 'Louisiana', 'LA'],
        ['stateprovnameen', 'Maine', 'ME'],
        ['stateprovnameen', 'Maryland', 'MD'],
        ['stateprovnameen', 'Massachusetts', 'MA'],
        ['stateprovnameen', 'Michigan', 'MI'],
        ['stateprovnameen', 'Minnesota', 'MN'],
        ['stateprovnameen', 'Mississippi', 'MS'],
        ['stateprovnameen', 'Missouri', 'MO'],
        ['stateprovnameen', 'Montana', 'MT'],
        ['stateprovnameen', 'Nebraska', 'NE'],
        ['stateprovnameen', 'Nevada', 'NV'],
        ['stateprovnameen', 'New Hampshire', 'NH'],
        ['stateprovnameen', 'New Jersey', 'NJ'],
        ['stateprovnameen', 'New Mexico', 'NM'],
        ['stateprovnameen', 'New York', 'NY'],
        ['stateprovnameen', 'North Carolina', 'NC'],
        ['stateprovnameen', 'North Dakota', 'ND'],
        ['stateprovnameen', 'Ohio', 'OH'],
        ['stateprovnameen', 'Oklahoma', 'OK'],
        ['stateprovnameen', 'Oregon', 'OR'],
        ['stateprovnameen', 'Pennsylvania', 'PA'],
        ['stateprovnameen', 'Rhode Island', 'RI'],
        ['stateprovnameen', 'South Carolina', 'SC'],
        ['stateprovnameen', 'South dakota', 'SD'],
        ['stateprovnameen', 'Tennessee', 'TN'],
        ['stateprovnameen', 'Texas', 'TX'],
        ['stateprovnameen', 'Utah', 'UT'],
        ['stateprovnameen', 'Vermont', 'VT'],
        ['stateprovnameen', 'Virginia', 'VA'],
        ['stateprovnameen', 'Washington', 'WA'],
        ['stateprovnameen', 'Washington D.C.', 'DC'],
        ['stateprovnameen', 'West Virginia', 'WV'],
        ['stateprovnameen', 'Wisconsin', 'WI'],
        ['stateprovnameen', 'Wyoming', 'WY'],

        ['entityfilercategoryen', 'accelerated filer', 'Accelerated Filer']
    ]
}

class TransformationTest(unittest.TestCase):

    def test_normalize(self):
        """
        :return:
        """
        for namespace in testTransforms:
            for i, testCase in enumerate(testTransforms[namespace]):
                formatCode, testInput, expected = testCase
                if expected == 'exception':
                    try:
                        testOutput = normalize(namespace, formatCode, testInput)
                        self.fail('Expected Transformation Exception, received ' + testOutput)
                    except TransformationException:
                        pass
                else:
                    testOutput = normalize(namespace, formatCode, testInput)
                    self.assertEqual(expected, testOutput, msg=f'Failed at test case {testCase} of registry {namespace}')

if __name__ == '__main__':
    unittest.main()


#! //Users/tyt15771/miniconda3/envs/pymol/bin/python

from pymol import cmd
import json
import os
import argparse

parser = argparse.ArgumentParser()
parser.add_argument(
    "-l",
    "--lig_path", required=True,
    )
parser.add_argument(
    "-p",
    "--prot_path", required=True,
    )

parser.add_argument(
    "-t",
    "--target", required=True,
    )

args = vars(parser.parse_args())

lig = args["lig_path"]
prot = args["prot_path"]
target = args["target"]

bits = json.load(open('bits.json', 'r'))

dirname = f'{os.getcwd()}/{target}_complexes'

def extend_save(filepath, moltype, atom, depth, num, bit):
    struc = filepath.split('/')[-1].split('.')[0]
    cmd.reinitialize()
    cmd.load(filepath)
    cmd.select('root', f'index {atom}')
    cmd.select('ext', f'root extend {depth}')
    cmd.save(f'{dirname}/{bit}/{struc}_{moltype}{num}.pdb', 'ext')

for bit in bits:
    num = 0
    for pair in bits[bit]:

        if not os.path.isdir(f'{dirname}/{bit}'):
            os.mkdir(f'{dirname}/{bit}')
        lig_atom = pair[0]
        lig_depth = pair[1]
        prot_atom = pair[2]
        prot_depth = pair[3]

        extend_save(lig, 'lig', lig_atom, lig_depth, num, bit)
        extend_save(prot, 'prot', prot_atom, prot_depth, num, bit)

        num += 1


import cv2
import os
import re
import mediapipe as mp
import pandas as pd

# Initialize mediapipe lib
mpPose = mp.solutions.pose
pose = mpPose.Pose()
mpDraw = mp.solutions.drawing_utils

lm_list = []
label = "FALLBACK"
no_of_frames = 200

def make_landmark_timestep(results):
    c_lm = []
    for id, lm in enumerate(results.pose_landmarks.landmark):
        c_lm.append(lm.x)
        c_lm.append(lm.y)
        c_lm.append(lm.z)
        c_lm.append(lm.visibility)
    return c_lm

def draw_landmark_on_image(mpDraw, results, frame):
    # Draw the line to connect the landmarks
    mpDraw.draw_landmarks(frame, results.pose_landmarks, mpPose.POSE_CONNECTIONS)

    # Draw the landmarks on the frame
    for id, lm in enumerate(results.pose_landmarks.landmark):
        h, w, c = frame.shape
        cx, cy = int(lm.x * w), int(lm.y * h)
        cv2.circle(frame, (cx, cy), 5, (255, 0, 0), cv2.FILLED)
    return frame

# Set the path of all the videos
video_folder_fallback = '/home/yuu/Documents/PBL5-demo/Data/Fall_backwards'
video_folder_fallforward = '/home/yuu/Documents/PBL5-demo/Data/Fall_forward'
video_folder_fallleft = '/home/yuu/Documents/PBL5-demo/Data/Fall_left'
video_folder_fallright = '/home/yuu/Documents/PBL5-demo/Data/Fall_right'
video_folder_fallsitting = '/home/yuu/Documents/PBL5-demo/Data/Fall_sitting'
video_folder_walk = '/home/yuu/Documents/PBL5-demo/Data/Walk'

# Read video from the folder and save the landmarks to a csv file
def read_video(video_folder):
    for video in os.listdir(video_folder):
        video_path = os.path.join(video_folder, video)
        cap = cv2.VideoCapture(video_path)

        if (cap.isOpened() == False):
            print("Error opening video stream or file")

        while cap.isOpened():
            ret, frame = cap.read()

            if ret:
                # Recognize the pose
                frameRGB = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
                results = pose.process(frameRGB)

                if results.pose_landmarks:
                    # Read the value of the landmarks
                    lm = make_landmark_timestep(results)
                    lm_list.append(lm)

                    # Draw the landmarks on the frame
                    frame = draw_landmark_on_image(mpDraw, results, frame)

                cv2.imshow('frame', frame)
                if cv2.waitKey(1) == ord('q'):
                    break

            else:
                break

        cap.release()
        cv2.destroyAllWindows()

# Save the landmarks to a csv file
def save_landmark_to_csv(label):
    df = pd.DataFrame(lm_list)
    df.to_csv(label + '.csv')


#!/usr/bin/python
# -*- coding: utf-8 -*-
from scrapy.contrib.spiders import CrawlSpider, Rule
from scrapy.contrib.linkextractors.sgml import SgmlLinkExtractor
from scrapy.selector import Selector
from score.items import ScoreItem
from sunburnt import SolrInterface

class ScoreSpider(CrawlSpider):
    name = 'score'
    allowed_domains = ['matchendirect.fr']
    start_urls = ['http://www.matchendirect.fr/hier/']
    rules = [Rule(SgmlLinkExtractor(allow=(r'/live-score/[a-z0-9\-]+\.html$', r'/foot-score/[a-z0-9\-]+\.html$')), 'parse_score')]

    # init solr instance
    def __init__(self, *args, **kwargs):
        super(ScoreSpider, self).__init__(*args, **kwargs)
        self.si = SolrInterface('http://localhost:8080/solr')

    # called on start urls
    # get host, visitor, scores
    def parse_start_url(self, response):
        sel = Selector(response)
        leagues = sel.xpath('//h3')
        docs = []
        for league in leagues:
            table = league.xpath('following-sibling::table[@class="tableau"][1]')
            rows = table.xpath('tr')
            for row in rows:
                # if match has has started & is finished
                scoring = row.xpath('td[@class="lm4"]/a[not(span)]/text()').extract()
                isPlaying = row.xpath('td[@class="lm2_1"]').extract()
                if scoring and not isPlaying:
                    score = ScoreItem()
                    score['id'] = 'http://www.matchendirect.fr' + row.xpath('td[@class="lm4"]/a/@href').extract().pop()
                    score['host'] = row.xpath('td[@class="lm3"]/a/text()').extract().pop()
                    score['visitor'] = row.xpath('td[@class="lm5"]/a/text()').extract().pop()

                    scoringArr = scoring.pop().split(' - ')
                    score['scorehost'] = int(scoringArr[0])
                    score['scorevisitor'] = int(scoringArr[1])
                    if score['scorehost'] > score['scorevisitor']:
                        score['winner'] = score['host']
                    elif score['scorehost'] < score['scorevisitor']:
                        score['winner'] = score['visitor']

                    leagueArr = league.xpath('a[1]/text()').extract().pop().split(' : ')
                    score['country'] = leagueArr[0]
                    score['league'] = leagueArr[1]

                    docs.append(dict(score))

        # index crawled games
        self.si.add(docs)
        self.si.commit()

    # called on followed urls
    # get game details (goal scorer & time)
    def parse_score(self, response):
        sel = Selector(response)
        # if match has started & is finished
        scorehost = sel.xpath('//div[@id="match_score"]/div[@class="col2"]/text()').extract().pop().strip()
        scorevisitor = sel.xpath('//div[@id="match_score"]/div[@class="col3"]/text()').extract().pop().strip()
        isPlaying = sel.xpath('//div[@id="match_entete_2"]/img').extract()

        if scorehost and scorevisitor and not isPlaying:
            score = ScoreItem()

            # get already indexed data
            solr_doc = self.si.query(id=response.url).execute()
            if list(solr_doc):
                doc = solr_doc[0]
            else:
                doc = {}
                score['id'] = response.url

            # get goals
            table = sel.xpath('//table[@class="tableau match_evenement"]')
            rows = table.xpath('tr')
            score['goalscorershost'], score['goalscorersvisitor'], score['goaltimeshost'], score['goaltimesvisitor'] = ([], [], [], [])
            score['penaltytimeshost'], score['penaltytimesvisitor'], score['ogtimeshost'], score['ogtimesvisitor'] = ([], [], [], [])
            for row in rows:
                tdgoalhost = row.xpath('td[@class="c1" and span[@class="ico_evenement1"]]')
                tdpenaltyhost = row.xpath('td[@class="c1" and span[@class="ico_evenement2"]]')
                tdowngoalhost = row.xpath('td[@class="c1" and span[@class="ico_evenement7"]]')
                tdgoalvisitor = row.xpath('td[@class="c3" and span[@class="ico_evenement1"]]')
                tdpenaltyvisitor = row.xpath('td[@class="c3" and span[@class="ico_evenement2"]]')
                tdowngoalvisitor = row.xpath('td[@class="c3" and span[@class="ico_evenement7"]]')
                tdgoalhost = tdgoalhost or tdpenaltyhost or tdowngoalhost
                tdgoalvisitor = tdgoalvisitor or tdpenaltyvisitor or tdowngoalvisitor
                if tdgoalhost:
                    time = tdgoalhost.xpath('following-sibling::td[@class="c2"][1]/text()').extract().pop().rstrip("'")
                    if tdpenaltyhost:
                        score['penaltytimeshost'].append(time)
                    elif tdowngoalhost:
                        score['ogtimeshost'].append(time)
                    score['goaltimeshost'].append(time)
                    score['goalscorershost'].append(tdgoalhost.xpath('a/text()').extract().pop())
                elif tdgoalvisitor:
                    time = tdgoalvisitor.xpath('preceding-sibling::td[@class="c2"][1]/text()').extract().pop().rstrip("'")
                    if tdpenaltyvisitor:
                        score['penaltytimesvisitor'].append(time)
                    elif tdowngoalvisitor:
                        score['ogtimesvisitor'].append(time)
                    score['goaltimesvisitor'].append(time)
                    score['goalscorersvisitor'].append(tdgoalvisitor.xpath('a/text()').extract().pop())

            # get time, refree & stadium
            matchinfos = sel.xpath('//table[@id="match_entete_1"]/tr/td[@class="info"]/text()').extract()
            matchinfos.pop()
            matchinfos = [x.lstrip('\n\t\r') for x in matchinfos]
            if u'Arbitre : - ' in matchinfos:
                matchinfos.remove(u'Arbitre : - ')
            date = format_date(matchinfos[0])
            time = matchinfos[1].split(' ')[-1].replace('h', ':') + ':00'
            score['date'] = "%sT%sZ" % (date, time)
            if len(matchinfos) >= 3:
                score['stadium'] = matchinfos[2]
                if len(matchinfos) == 4:
                    score['referee'] = matchinfos[3].split(' : ')[1]

            # index all datas
            doc = dict(doc.items() + dict(score).items())
            self.si.add(doc)
            self.si.commit()

def format_date(date):
    months = {
        u'janvier': '01',
        u'février': '02',
        u'mars': '03',
        u'avril': '04',
        u'mai': '05',
        u'juin': '06',
        u'juillet': '07',
        u'août': '08',
        u'septembre': '09',
        u'octobre': '10',
        u'novembre': '11',
        u'décembre': '12'
    }
    date_list = date.split(' ')[1:]
    date_list.reverse()
    date_list[1] = months[date_list[1]]
    formatted_date = '-'.join(date_list)

    return formatted_date


from fastapi import APIRouter, HTTPException, status, Body
from fastapi.param_functions import Depends
from fastapi.security.oauth2 import OAuth2PasswordRequestForm
from sqlalchemy.orm.session import Session
from db.database import get_db
from auth import oauth2
from utils.hash import Hash
from jose import jwt
from jose.exceptions import JWTError
from db.db_role import get_role_by_userID
from db.db_function import get_func_by_roleID
from db.db_user import get_user_by_username
from schemas import RefreshTokenRequest

router = APIRouter(
  prefix='/auth',
  tags=['authentication']
)

@router.post('/login')
def login(request: OAuth2PasswordRequestForm = Depends(), db: Session = Depends(get_db)):
  try:
    connection = db.connection().connection
    cursor = connection.cursor()
  except Exception as e:
    raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail='Cannot connect to database.')

  try:
    user = get_user_by_username(request.username, db)
    if not user or not Hash.verify(user.PASSWORD, request.password):
      raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Invalid credentials")
    user_role = get_role_by_userID(user, db)
    result = get_func_by_roleID(user_role, db)

    access_token = oauth2.create_access_token(data={'sub': user.USER_NAME, 'role_id': user_role.ROLE_ID })
    refresh_token = oauth2.create_refresh_token(data={'sub': user.USER_NAME, 'role_id': user_role.ROLE_ID})

    return {
    'accessToken': access_token,
    'refreshToken': refresh_token,
    'username': user.USER_NAME,
    'fullName': user.FULL_NAME,
    'acceptUrl': [
      func.API_PATH
      for func in result
    ]
}
  except JWTError as e:
    raise HTTPException(status_code=status.HTTP_404_NOT_FOUND,
        detail=f'Refresh token has expired or invalid')
  finally:
    cursor.close()
    connection.close()

@router.post('/refresh-token')
def refresh_token(request_body: RefreshTokenRequest , db: Session = Depends(get_db)):
  try:
    payload = jwt.decode(request_body.refresh_Token, oauth2.SECRET_KEY_ACCESS, algorithms=[oauth2.ALGORITHM])
    username: str = payload.get("sub")
    user = get_user_by_username(username, db)
    if not user:
      raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Refresh token has expired or invalid")
    user_role = get_role_by_userID(user, db)
    result = get_func_by_roleID(user_role, db)

    access_token = oauth2.create_access_token(data={'sub': user.USER_NAME, 'role_id': user_role.ROLE_ID})
    refresh_token = oauth2.create_refresh_token(data={'sub': user.USER_NAME, 'role_id': user_role.ROLE_ID})

    return {
    'accessToken': access_token,
    'refreshToken': refresh_token,
    'username': user.USER_NAME,
    'fullName': user.FULL_NAME,
    'acceptUrl': [
      func.API_PATH
      for func in result
    ]
    }
  except JWTError:
    raise HTTPException(status_code=status.HTTP_404_NOT_FOUND,
      detail=f'Refresh token has expired or invalid')


import re
import duckduckgo

def duckduck_regex(message):
    regex = "^\/duckduck\s+(?P<data>[a-zA-Z0-9\s]+)"
    m = re.match(regex, message)
    if not m:
        return None
    else:
        return m.groupdict()["data"]

def ddg(query):
    """
    DuckDuckGo search
    """
    return duckduckgo.get_zci(query)


import moviepy.editor as mp
from assembly_api import *
def convert(name):
    video = mp.VideoFileClip(name)
    video.audio.write_audiofile("converted.wav")

print("Please enter the name of video file you want to summarize along with its type...... eg: test.mp4")
name = input()
convert(name)
def start():
    filename = "converted.wav"
    audio_url = upload(filename)

    save_transcript(audio_url, "output1")
print("The video has been converted to wav format successfully.")
start()


from libqtile.lazy import lazy
from libqtile.config import Key

mod = "mod4"
terminal = "kitty"
filemanager = "thunar"
browser = "brave"

keys = [
    # window controls
    Key([mod], "j", lazy.layout.down(), desc="Move focus down"),
    Key([mod], "k", lazy.layout.up(), desc="Move focus up"),
    Key([mod, "shift"], "j", lazy.layout.shuffle_down(), lazy.layout.section_down(), desc="Move windows down in current stack"),
    Key([mod, "shift"], "k", lazy.layout.shuffle_up(), lazy.layout.section_up(), desc="Move windows up in current stack"),
    Key([mod], "h", lazy.layout.shrink(), lazy.layout.decrease_nmaster(), desc="Shrink window (MonadTall), decrease number in master pane (Tile)"),
    Key([mod], "l", lazy.layout.grow(), lazy.layout.increase_nmaster(), desc="Expand window (MonadTall), increase number in master pane (Tile)"),
    Key([mod, "shift"], "f", lazy.window.toggle_floating(), desc="toggle floating"),
    Key([mod], "f", lazy.window.toggle_fullscreen(), desc="toggle fullscreen"),
    Key([mod], "n", lazy.layout.normalize(), desc="Reset all window sizes"),
    Key([mod], "space", lazy.layout.next(), desc="Move window focus to other window"),
    Key([mod], "q", lazy.window.kill(), desc="Kill focused window"),

    # media bindings
    Key([], "XF86AudioRaiseVolume", lazy.spawn("amixer set Master 3%+")),
    Key([], "XF86AudioLowerVolume", lazy.spawn("amixer set Master 3%-")),
    Key([], "XF86AudioMute", lazy.spawn("amixer set Master toggle")),
    Key([], "XF86AudioPlay", lazy.spawn("playerctl play-pause"), desc="Play/Pause player"),
    Key([], "XF86AudioNext", lazy.spawn("playerctl next"), desc="Skip to next"),
    Key([], "XF86AudioPrev", lazy.spawn("playerctl previous"), desc="Skip to previous"),

    # launchers
    Key([mod], "r", lazy.spawn("rofi -show combi"), desc="spawn rofi"),
    Key([mod, "shift"], "r", lazy.spawncmd(), desc="Spawn a command using a prompt widget"),

    # applications
    Key([mod], "F12", lazy.spawn(terminal), desc="Launch terminal"),
    Key([mod], "F1", lazy.spawn(browser), desc="Launches web browser"),
    Key([mod], "F2", lazy.spawn(filemanager), desc="Launches File Manager"),

    # system bindings
    Key([mod], "F10", lazy.spawn("xscreensaver-command -lock"), desc="Locks screen"),
    Key([mod], "F11", lazy.spawn("clipmenu"), desc="Show clipboard history"),
    Key([mod, "shift"], "F10", lazy.spawn("~/.config/rofi/powermenu.sh"), desc="Suspends system"),
    Key([mod, "control"], "r", lazy.restart(), desc="Restart Qtile"),
    Key([mod, "control"], "q", lazy.shutdown(), desc="Shutdown Qtile"),

    # layouts
    Key([mod], "Tab", lazy.next_layout(), desc="Toggle between layouts"),
    Key([mod, "shift", "control"], "h", lazy.layout.swap_column_left()),
    Key([mod, "shift", "control"], "l", lazy.layout.swap_column_right()),
    Key([mod, "shift"], "space", lazy.layout.flip()),

    # Monitors
    Key([mod], "w", lazy.to_screen(0), desc="Keyboard focus to monitor 1"),
    Key([mod], "e", lazy.to_screen(1), desc="Keyboard focus to monitor 2"),
    Key([mod], "period", lazy.next_screen(), desc="Move focus to next monitor"),
    Key([mod], "comma", lazy.prev_screen(), desc="Move focus to prev monitor"),

]


import pickle
import numpy as np
import matplotlib.pyplot as plt
import os

#global a,b,c,aami
data_sys = './diadata/'
filelist=['data1.txt','data2.txt','data3.txt','data4.txt','data5.txt','data6.txt','data7.txt','data8.txt','data9.txt','data10.txt'
        ,'data11.txt','data12.txt','data13.txt','data14.txt','data15.txt','data16.txt','data17.txt','data18.txt','data19.txt','data20.txt','data21.txt'
    , 'data22.txt','data23.txt','data24.txt','data25.txt','data26.txt','data27.txt','data28.txt','data29.txt','data30.txt']

a = 0
b = 0
c = 0
aami = 0

#for ii in range(len(filelist)):

filepath=os.path.join(data_sys+'data30.txt')
f=open(filepath,'rb+')
data_sys=f.read()
f.close()
data=pickle.loads(data_sys)

pred_sys=data["pred"]

real_sys=data["real"]

error = np.array(pred_sys).reshape(-1) - np.array(real_sys).reshape(-1)

num_5 = 0
num_10 = 0
num_15 = 0
for ii in error:
    if abs(ii) <= 5:
        num_5 += 1
for ii in error:
    if abs(ii) <= 10:
        num_10 += 1
for ii in error:
    if abs(ii) <= 15:
        num_15 += 1

num = len(error)
rate_5 = num_5 / num
rate_10 = num_10 / num
rate_15 = num_15 / num

#global a, b, c, aami
if rate_5 >= 0.65 and rate_10 >= 0.85 and rate_15 >= 0.95:
    a += 1
elif rate_5 >= 0.5 and rate_10 >= 0.75 and rate_15 >= 0.90:
    b += 1
elif rate_5 >= 0.4 and rate_10 >= 0.65 and rate_15 >= 0.85:
    c += 1

mean_val = np.mean(error)
std_val = np.std(error)
if mean_val <= 5 and std_val <= 8:
    aami += 1

print(a,b,c,aami)


import pandas as pd
#%%
#1a opción Rutas de importación y exportación
synergy_dataframe = pd.read_csv('synergy_logistics_database.csv',
                                index_col=0, encoding='utf-8', parse_dates=[4, 5])

#Definir apartados
combinaciones1 = synergy_dataframe.groupby(by=['direction', 'origin',
                                               'destination','transport_mode'])

#Agregamos el apartado Total value, el cual nos servirá para filtrar las 10
#mejores rutas de importación y exportación
descripcion = combinaciones1.describe()['total_value']
#print (descripcion)

#Ordenamos con base en el número de exportaciones e importaciones realizadas
count = descripcion['count']

#Ordenaremos la serie de mayor a menor
count_sort = count.sort_values(ascending=False)

#Transformamos la serie a un dataframe
count_sort = count_sort.to_frame().reset_index()
#print (count_sort)

#%%

#2a opción Medio de transporte utilizado
synergy_dataframe2 = pd.read_csv('synergy_logistics_database.csv',
                                index_col=0, encoding='utf-8', parse_dates=[4, 5])

#Definimos apartados, si eliminamos 'direction' podremos ver un score general
#de los medios de transporte.
combinaciones2 = synergy_dataframe2.groupby(by=['direction',
                                               'transport_mode'])

#Agregamos el apartado Total value para considerar el valor de
#las imp. y exp.
descripcion2=combinaciones2.describe()['total_value']

#Obtenemos el promedio
count2=descripcion2['mean']
count_sort2=count2.sort_values(ascending=False)
count_sort2=count_sort2.to_frame().reset_index()
#print (count_sort2)

#%%

#3a opción Valor total de importaciones y exportaciones

synergy_dataframe3 = pd.read_csv('synergy_logistics_database.csv',
                                index_col=0, encoding='utf-8', parse_dates=[4, 5])

#Definimos variables de imp. y exp.
exports=synergy_dataframe3[synergy_dataframe3['direction']=='Exports']
imports=synergy_dataframe3[synergy_dataframe3['direction']=='Imports']

#Función para obtener el porcentaje acumulado y países pertenecientes
#al 85%
def sol_3 (df,p):
    total_value_origin=df.groupby('origin').sum()['total_value'].reset_index()
    total_value_percent=total_value_origin['total_value'].sum()
    total_value_origin['percent']=100*total_value_origin['total_value']/total_value_percent
    total_value_origin.sort_values(by='percent',ascending=False,inplace=True)
    total_value_origin['cumsum']=total_value_origin['percent'].cumsum()
    lista=total_value_origin[total_value_origin['cumsum']<p]
    return lista

res_exports=sol_3(exports, 85)
res_imports=sol_3(imports, 85)

#Se grafican en un pie chart acorde a su número de índice
plot=res_exports.plot.pie(y='total_value')
#print (plot)
plot2=res_imports.plot.pie(y='total_value')
#print (plot2)

#Definimos apartados y realizamos sumatoria por país incluyendo
#imp. y exp.
combinaciones3=(synergy_dataframe3.groupby(by=['origin'])
                .sum().groupby(level=[0]).cumsum())
#print (combinaciones3)

plot3=combinaciones3.plot.pie(y='total_value')
#print (plot3)

ANALISIS_02_ HUEZO VAPNIK_INGRID/ANALISIS_02_ HUEZO VAPNIK_INGRID.py


# -*- coding: utf-8 -*-
"""
Custom scripts to plot DISCO profiles to a passed plot axis.
"""
import matplotlib.pyplot as plt
import pandas as pd
import seaborn as sns
import os
import numpy as np
from utils.plotting_helpers import annotate_sig_buildup_points
from utils.wrangle_data import flatten_multicolumns, calculate_abs_buildup_params

# set default style params
plt.style.use(['science', 'discolib'])
plt.rcParams.update({'font.family': 'sans-serif'})
plt.rcParams.update({'font.size': 6})

# for use in more specific plotting
custom_colors = ['#377eb8', '#984ea3', '#ff7f00', '#e41a1c', '#f781bf',
    '#ffff33', '#4daf4a', '#a65628', '#999999']

# must install LaTex before you can use Science Plots
os.environ["PATH"] += os.pathsep + '/Library/TeX/texbin'

def add_fingerprint_toax(df, ax, **kwargs):
    '''Adds DISCO AF0 fingerprints of all binding protons for one polymer to the plot axis passed.

    Parameters:
    -----------
    df: pandas.DataFrame
        "replicate" raw data for one polymer (raw file containing all technical AF0 replicates for only the polymers binding protons)
    ax: matplotlib axis
        axis of the plot to contain the DISCO fingerprint

    **kwargs: dict {"custom_palette": [list, of, colourcodes]} (optional, if desired)
        custom plotting palette containing a unique color code for each proton

    Returns:
    --------
    None, adds DISCO AF0 fingerprint to plot axis passed

    Example:
    -------
    >>> import pandas as pd
    >>> import matplotlib.pyplot as plt

    >>> # read the per-replicate data table, containing information from only the binding protons in HPC
    >>> hpc_df_replicates = pd.read_excel("../data/raw/stats_analysis_output_replicate_HPC_370k_20uM.xlsx", index_col=[0], header=[0]).reset_index()
    >>> fig, ax = plt.subplots(figsize=(5, 5))
    >>> add_fingerprint_toax(df=hpc_df_replicates, ax=ax)
    >>> plt.show()

    The binding AF0 fingerprint for HPC will appear on the passed plot axis.
    '''

    ppm = np.round(df.copy().groupby(by='proton_peak_index')['ppm'].mean(), 2)
    ppm_ix = np.unique(df['proton_peak_index'].values)

    # map ppm to proton peak index incase multi ppms per proton peak index
    ppm_mapper = dict(zip(ppm_ix, ppm))
    df['ppm'] = df['proton_peak_index'].map(ppm_mapper)

    # remove duplicates from df
    df_plot = df[['ppm', 'AFo']].drop_duplicates()

    # take absolute value of AFo
    df_plot['AFo'] = df_plot['AFo'].abs()

    #create plot, use custom palette if there is one
    try:
        custom_palette = kwargs.pop("custom_palette")
        sns.barplot(data=df_plot, x='ppm', y='AFo', ax=ax,
                    edgecolor='k',errcolor='black',palette=custom_palette)
        sns.stripplot(data=df_plot, x='ppm', y='AFo', ax=ax, edgecolor='k',
                      linewidth=0.5, jitter=False, palette=custom_palette)

    except KeyError: # executes if there is no custom palette
        pass
        sns.barplot(data=df_plot, x='ppm', y='AFo', ax=ax, edgecolor='k', errcolor='black')
        sns.stripplot(data=df_plot, x='ppm', y='AFo', ax=ax,
                      edgecolor='k', linewidth=0.5, jitter=False)

    # reformat x axis
    ax.invert_xaxis()  # invert to match NMR spectrum

    return

def add_buildup_toax(df, ax):
    '''Adds the Absolute DISCO Effect(t) buildup curves for all protons in
    a polymer to an existing plot axis.

    Parameters:
    -----------
    df: pandas.DataFrame
        mean raw data file for one polymer, containing mean DISCO Effects(t)
        (corr % attuenation) for /only/ the binding protons

    ax: matplotlib axis
        plot axis to contain the buildup curves

    Returns:
    --------
    None, adds buildup curves to axis

    Example:
    --------
    >>> import matplotlib.pyplot as plt
    >>> import pandas as pd
    >>> # read the mean data table, containing information from only the binding protons in HPC
    >>> hpc_df = pd.read_excel("../data/raw/stats_analysis_output_mean_HPC_370k_20uM.xlsx", index_col=[0, 1, 2, 3], header=[0, 1]).reset_index()
    >>> fig, ax = plt.subplots(figsize = (5,5))
    >>> add_buildup_toax(df = hpc_df, ax = ax)
    >>> plt.show()

    The buildup curves for all binding peaks in HPC will appear on the plot axis.
    '''

    if type(df.columns) == pd.MultiIndex:
        df = flatten_multicolumns(df)  # make data indexable if it is not already

    ppm_labels = np.round(df['ppm'], 2)
    df_plot = df.copy()
    groups = df_plot.groupby([ppm_labels])

    # plot DISCO effect build up curve, absolute values
    for ppm, group in groups:
        sat_time, disco_effect, y1, y2 = calculate_abs_buildup_params(group)
        ax.plot(sat_time, disco_effect, markeredgecolor='k', markeredgewidth=0.35,
                marker='o', linestyle='', ms=5, label="%.2f" % ppm)
        ax.fill_between(sat_time, y1, y2, alpha=0.25)
        ax.legend(loc='lower right', title="Peak ($\delta$, ppm)")
        ax.axhline(y=0.0, color="0.8", linestyle='dashed')

    return

def add_overlaid_buildup_toax_customlabels(df_list, ax, **kwargs):
    '''Adds buildup curve(s) to a plot. Allows control of individual proton buildup curves when designing a buildup curve plot,
    for use cases where only specific subsets of buildup curves are desired to be plotted.

    Parameters:
    -----------
    df_list: list
        list of one "mean" raw dataframe for every polymer whose data is to be used in the plot

    ax: matplotlib axis
        location for the plot

    **kwargs: dict
        any desired custom plotting parameters

    Notes:
    ------
    * To add new custom properties, simply add another kwargs.pop statement below, and pass a new kwarg to the dict

    Example:
    -------
    >>> import matplotlib.pyplot as plt
    >>> import pandas as pd
    >>> from utils.plotting_helpers import assemble_peak_buildup_df
    >>> from utils.wrangle_data import generate_disco_effect_mean_diff_df, generate_subset_sattime_df

    >>> # read data
    >>> low_hpc_replicate_all = pd.read_excel("../data/raw/stats_analysis_output_replicate_all_HPC_80k_20uM.xlsx", index_col=[0], header=[0]).reset_index(drop=True)
    >>> high_hpc_replicate_all = pd.read_excel("../data/raw/stats_analysis_output_replicate_all_HPC_370k_20uM.xlsx", index_col=[0], header=[0]).reset_index(drop=True)

    >>> # grab the desired proton to plot by their proton peak index
    >>> ppi_1_low = assemble_peak_buildup_df(low_hpc_replicate_all, 1)
    >>> ppi_1_high = assemble_peak_buildup_df(high_hpc_replicate_all, 1)

    >>> # compute change significance between proton buildup curves
    >>> hpc_effect_size_df = generate_disco_effect_mean_diff_df(low_hpc_replicate_all, high_hpc_replicate_all)
    >>> hpc_subset_sattime_df = generate_subset_sattime_df(hpc_effect_size_df, 0.25)
    >>> kwargs = {"labels": ["80", "370"],
    >>>       "dx": 0.003,
    >>>       "dy": 0.010,
    >>>       "change_significance": hpc_effect_size_df,
    >>>       "annot_color": "#000000",
    >>>       "custom_colors": ['#b3cde3', '#377eb8']}

    >>> # construct and display peak overlay plot w/ annotated change significance
    >>> fig, ax = plt.subplots(figsize = (5,2))
    >>> df_list = [ppi_1_low, ppi_1_high]
    >>> add_overlaid_buildup_toax_customlabels(df_list, ax, **kwargs)
    >>> plt.show()
    '''

    # extract custom properties
    custom_labels = kwargs.pop("labels")
    dx = kwargs.pop("dx")
    dy = kwargs.pop("dy")
    change_sig_df = kwargs.pop("change_significance")
    buildup_colors = kwargs.pop("custom_colors")
    annot_color = kwargs.pop("annot_color")

    # plot overlaid buildups using the correct custom properties
    color_count = 0
    for ix, df in enumerate(df_list):
        plot_label = custom_labels[ix]

        if type(df.columns) == pd.MultiIndex:
            df = flatten_multicolumns(df)  # make data indexable if it is not already

        ppm_labels = np.round(df['ppm'], 2)
        df_plot = df.copy()
        groups = df_plot.groupby([ppm_labels])

        # plot DISCO effect build up curve, absolute values
        for _, group in groups:
            sat_time, disco_effect, y1, y2 = calculate_abs_buildup_params(group)

            full_plot_label = f"{plot_label}"
            ax.plot(sat_time, disco_effect, markeredgecolor='k', markeredgewidth=0.35, color=buildup_colors[color_count],
                    marker='o', linestyle='', ms=5, label=full_plot_label)
            ax.fill_between(sat_time, y1, y2, color=buildup_colors[color_count],
                            alpha=0.25)
            ax.axhline(y=0.0, color="0.8", linestyle='dashed')
        color_count += 1

    # annotate significance of change in disco effect (NOT disco adhesion interaction significance)
    key = group['proton_peak_index'].unique()[0]
    change_sig_subset = change_sig_df.loc[change_sig_df['proton_peak_index'] == key]

    # annotate change sig points
    significance = change_sig_subset['changed_significantly']
    annotate_sig_buildup_points(ax, significance, sat_time, disco_effect, dx, dy, color=annot_color)

    return

def add_difference_plot(df, ax, dy, **kwargs):
    '''Add a proton-wise difference profile plot to a plot axis (Vertical Orientation).

    Parameters:
    -----------
    df: Pandas.DataFrame
        "subset_sattime_df" for a polymer comparison, contains change effect data computed only at
        the desired sat time t for this plot

    ax: matplotlib axis
        plot destination

    dy: float
        y distance for significance marker away from datapoint

    **kwargs: dict {"custom_colors":[list, with, one, custom, color, per, proton]} (optional)

    Returns:
    --------
    None, adds difference profile to a plot

    Theory Notes:
    -------------
    * Proton-wise difference profile plot shows the change effect size and significance of any changes in mean DISCO effect(t) between all
    the protons from two polymer test groups. In this work, test groups were low mW vs high mW versions of the same polymer.

    * Selected sat time for the difference plot is determined when the subset_sattime_df is computed. Lower sat times are more
    representative as there is the least influence from rebinding.

    Example:
    --------
    >>> import pandas as pd
    >>> import matplotlib.pyplot as plt
    >>> from utils.plotting import add_difference_plot
    >>> from utils.wrangle_data import generate_disco_effect_mean_diff_df, generate_subset_sattime_df

    >>> # we use "replicate all" data as we are considering both binding and non-binding protons
    >>> low_HPC = pd.read_excel("../data/raw/stats_analysis_output_replicate_all_HPC_80k_20uM.xlsx", index_col=[0], header=[0]).reset_index(drop=True)
    >>> high_HPC = pd.read_excel("../data/raw/stats_analysis_output_replicate_all_HPC_370k_20uM.xlsx", index_col=[0], header=[0]).reset_index(drop=True)

    >>> # first compute HPC's difference profile from the raw data
    >>> hpc_effect_size_df = generate_disco_effect_mean_diff_df(low_HPC, high_HPC)

    >>> # subset HPC's difference profile to the desired sat time Disco Effect(t = 0.25)
    >>> hpc_subset_sattime_df = generate_subset_sattime_df(hpc_effect_size_df, 0.25)

    >>> kwargs = {"custom_colors": ['#377eb8', '#984ea3', '#ff7f00', '#e41a1c', '#f781bf', '#ffff33', '#4daf4a', '#a65628', '#999999']}

    >>> fig, ax = plt.subplots(figsize = (3,5))
    >>> add_difference_plot(df=hpc_subset_sattime_df, dy= 0.010,  ax=ax, **kwargs)
    >>> plt.show()
    '''
    custom_colors = kwargs.pop("custom_colors")

    plot_range = range(1, (df.shape[0])+1)

    # zero line
    ax.axvline(x=0.0, color="0.8", linestyle='dashed')

    # error bars
    ax.hlines(y=plot_range, xmin=df['effect_sem_lower'],
              xmax=df['effect_sem_upper'], color='black', linewidth=2, zorder=1)

    # data
    ax.scatter(df['effect_size'], plot_range, s=(40,), color=custom_colors[:df.shape[0]],
               alpha=1, label='Effect Size', marker='o', linewidths=0.35, edgecolors='k', zorder = 2)
    ax.set_yticks(plot_range, np.round(df['ppm'].values, 2))

    # annotate significance
    df['annotation'] = df['changed_significantly'].map({True: "*", False: ""})

    for ix, value in enumerate(list(plot_range)):
        x = df['effect_size'].iloc[ix]
        y = value + dy
        marker = df['annotation'].iloc[ix]
        ax.annotate(marker, (x, y), c='#000000')

    return

def add_difference_plot_transposed(df, ax, dy, **kwargs):
    '''Add a proton-wise difference profile plot to a plot axis (Horizontal Orientation).

    Parameters:
    -----------
    df: Pandas.DataFrame
        "subset_sattime_df" for a polymer comparison, contains change effect data computed only at
        the desired sat time t for this plot

    ax: matplotlib axis
        plot destination

    dy: float
        y distance for significance marker away from datapoint

    **kwargs: dict {"custom_colors":[list, with, one, custom, color, per, proton]} (optional)

    Returns:
    --------
    None, adds difference profile to a plot

    Theory Notes:
    -------------
    * Proton-wise difference profile plot shows the change effect size and significance of any changes in mean DISCO effect(t) between all
    the protons from two polymer test groups. In this work, test groups were low mW vs high mW versions of the same polymer.

    * Selected sat time for the difference plot is determined when the subset_sattime_df is computed.

    Example:
    --------
    >>> import pandas as pd
    >>> import matplotlib.pyplot as plt
    >>> from utils.plotting import add_difference_plot_transposed
    >>> from utils.wrangle_data import generate_disco_effect_mean_diff_df, generate_subset_sattime_df

    >>> # we use "replicate all" data table as we are considering both binding and non-binding protons
    >>> low_HPC = pd.read_excel("../data/raw/stats_analysis_output_replicate_all_HPC_80k_20uM.xlsx", index_col=[0], header=[0]).reset_index(drop=True)
    >>> high_HPC = pd.read_excel("../data/raw/stats_analysis_output_replicate_all_HPC_370k_20uM.xlsx", index_col=[0], header=[0]).reset_index(drop=True)

    >>> # first compute HPC's difference profile from the raw data
    >>> hpc_effect_size_df = generate_disco_effect_mean_diff_df(low_HPC, high_HPC)

    >>> # subset HPC's difference profile to the desired sat time Disco Effect(t = 0.25)
    >>> hpc_subset_sattime_df = generate_subset_sattime_df(hpc_effect_size_df, 0.25)

    >>> kwargs = {"custom_colors": ['#377eb8', '#984ea3', '#ff7f00', '#e41a1c', '#f781bf', '#ffff33', '#4daf4a', '#a65628', '#999999']}

    >>> fig, ax = plt.subplots(figsize=(3, 5))
    >>> add_difference_plot_transposed(df=hpc_subset_sattime_df, dy=0.010, ax=ax, **kwargs)
    >>> plt.show()
    '''

    custom_colors = kwargs.pop("custom_colors")

    plot_domain = range(1, df.shape[0]+1)

    # zero line
    ax.axhline(y=0.0, color="0.8", linestyle='dashed')

    # error bars
    ax.vlines(x=plot_domain, ymin=df['effect_sem_lower'],
              ymax=df['effect_sem_upper'], color='black', linewidth=2, zorder = 1)

    # data
    ax.scatter(plot_domain, df['effect_size'], s = (40,), color=custom_colors[:df.shape[0]],
               alpha=1, label='effect size', marker = 'o', linewidths = 0.35, edgecolors = 'k', zorder = 2)
    ax.set_xticks(plot_domain, np.round(df['ppm'].values,2))

    # annotate significance
    df['annotation'] = df['changed_significantly'].map({True: "*", False: ""})

    for ix, value in enumerate(list(plot_domain)):
            y = df['effect_size'].iloc[ix] + dy
            x = value + 0.05
            marker = df['annotation'].iloc[ix]
            ax.annotate(marker, (x,y), c = '#000000')

    return


import os
import sys
from typing import Callable

from utils.inputs import int_input
from utils.prints import Color, print_line, print_result

def get_exercices_count() -> int:
	"""
	Retourne le nombre d'exercices.
	:return: Le nombre d'exercices.
	:rtype: int
	"""

	# count the number of files with pattern "ex[number].py" in directory ../src
	return len([name for name in os.listdir('src') if name.startswith('ex') and name.endswith('.py')])

def get_exercice(number: int) -> tuple[str, str, Callable[[], None]]:
	"""
	Retourne le tuple contenant le nom, la consigne et la fonction à exécuter.
	:param number: Le numéro de l'exercice.
	:type number: int
	:return: Le tuple contenant le nom, la consigne et la fonction à exécuter.
	:rtype: tuple[str, str, Callable[[], None]]
	"""
	file: object = __import__(f"src.ex{number}")
	module: object = getattr(file, f"ex{number}")
	function: Callable[[], None] = getattr(module, f"ex{number}")
	return getattr(module, "__title__"), str(function.__doc__), function

def get_instructions_from_docstring(function: tuple[str, str, Callable[[], None]]) -> str:
	"""
	Retourne la consigne de l'exercice.
	:param function: L'exercice.
	:type function: tuple[str, str, Callable[[], None]]
	:return: La consigne de l'exercice depuis le docstring.
	:rtype: str
	"""
	return function[1].split(':return:')[0].strip().replace('\t', '')

def print_menu() -> None:
	"""
	Affiche le menu de sélection des exercices.
	:return: None
	:rtype: None
	"""
	print_line("Menu", color = Color.YELLOW)
	exercices: list[tuple[str, str, Callable[[], None]]] = [get_exercice(i) for i in range(1, get_exercices_count() + 1)]
	list_exercices: str = '\n'.join([f"Exercice {Color.cyan(i + 1)} - {Color.green(exercices[i][0])}" for i in range(len(exercices))])
	list_exercices += Color.red('\n\nSTOP pour arrêter.')
	print(list_exercices)

def menu() -> None:
	"""
	Lance le programme.
	:return: None
	:rtype: None
	"""
	print(Color.red('Bienvenue dans le menu du TP 3'))
	while True:
		print_menu()
		try:
			input1: int = int_input(Color.blue('Veuillez choisir un exercice : '), 1, lambda _: get_exercices_count(), True)
			exercice: tuple[str, str, Callable[[], None]] = get_exercice(input1)
			print(exercice)
			print_line(f"Exercice n°{input1}", color = Color.YELLOW)
			print_result(f"{get_instructions_from_docstring(exercice)}\n", Color.BLUE)
			exercice[2]()
			input(Color.cyan('Appuyez sur ENTRÉE pour continuer...'))
		except:
			print(Color.cyan('\nAu revoir :)'))
			sys.exit(1)

if __name__ == '__main__':
	menu()