# Blog post article https://bhrnjica.net/2017/11/12/using-cntk-2-2-and-python-to-learn-from-iris-data/
#
import os, sys
import numpy as np
import cntk

# The data in the file must satisfied the following format:
#
# |labels 0 0 1 |features 2.1 7.0 2.2  - the format consist of 4 features and one 3 component hot vector
#
#represents the iris flowers
def create_reader(path, randomize, input_dim, num_label_classes):

    #create the streams separately for the label and for the features
    labelStream = cntk.io.StreamDef(field='label', shape=num_label_classes, is_sparse=False)
    featureStream = cntk.io.StreamDef(field='features', shape=input_dim, is_sparse=False)

   #create deserializer by providing the file path, and related streams
    deserailizer = cntk.io.CTFDeserializer(path, cntk.io.StreamDefs(labels = labelStream, features = featureStream))

    #create mini batch source as function return
    mb = cntk.io.MinibatchSource(deserailizer, randomize = randomize, max_sweeps = cntk.io.INFINITELY_REPEAT if randomize else 1)
    return mb

# Function that prints the training progress
def print_training_progress(trainer, mb, frequency, verbose=1):
    training_loss = "NA"
    eval_error = "NA"

    if mb%frequency == 0:
        training_loss = trainer.previous_minibatch_loss_average
        eval_error = trainer.previous_minibatch_evaluation_average
        print ("Minibatch: {0}, Loss: {1:.4f}, Accuracy: {2:.2f}%".format(mb, training_loss,(1 - eval_error)*100))
    return mb, training_loss, eval_error

#model creation
# FFNN with one input, one hidden and one output layer
def create_model(features, hid_dim, out_dim):
    #perform some parameters initialization
    with cntk.layers.default_options(init = cntk.glorot_uniform() ):
        #hidden layer with hid_def number of neurons and tanh activation function
        h1=cntk.layers.Dense(hid_dim, activation= cntk.ops.tanh, name='hidLayer')(features)
        #output layer with out_dim neurons
        o = cntk.layers.Dense(out_dim, activation = cntk.ops.softmax)(h1)
        return o

input_dim=4
hidden_dim = 50
output_dim=3

input = cntk.input_variable(input_dim)
label = cntk.input_variable(output_dim)

#
train_file = os.path.join(os.path.dirname(os.path.abspath(__file__)), r"../data/IRIS-TrainData.txt")

# Create the reader to training data set
reader_train= create_reader(train_file,True,input_dim, output_dim)
z= create_model(input, hidden_dim,output_dim)
loss = cntk.cross_entropy_with_softmax(z, label)
label_error = cntk.classification_error(z, label)

# Instantiate the trainer object to drive the model training
learning_rate = 0.2
lr_schedule = cntk.learning_parameter_schedule(learning_rate)
learner = cntk.sgd(z.parameters, lr_schedule)
trainer = cntk.Trainer(z, (loss, label_error), [learner])

# Initialize the parameters for the trainer
minibatch_size = 120 #mini batch size will be full data set
num_iterations = 20 #number of iterations

# Map the data streams to the input and labels.
input_map = {
label  : reader_train.streams.labels,
input  : reader_train.streams.features
}

# Run the trainer on and perform model training
training_progress_output_freq = 1

plotdata = {"batchsize":[], "loss":[], "error":[]}

for i in range(0, int(num_iterations)):
        # Read a mini batch from the training data file
        data=reader_train.next_minibatch(minibatch_size, input_map=input_map)
        trainer.train_minibatch(data)
        batchsize, loss, error = print_training_progress(trainer, i, training_progress_output_freq)
        if not (loss == "NA" or error =="NA"):
            plotdata["batchsize"].append(batchsize)
            plotdata["loss"].append(loss)
            plotdata["error"].append(error)

# Plot the training loss and the training error
import matplotlib.pyplot as plt

plt.figure(1)
plt.subplot(211)
plt.plot(plotdata["batchsize"], plotdata["loss"], 'b--')
plt.xlabel('Minibatch number')
plt.ylabel('Loss')
plt.title('Minibatch run vs. Training loss')

plt.show()

plt.subplot(212)
plt.plot(plotdata["batchsize"], plotdata["error"], 'r--')
plt.xlabel('Minibatch number')
plt.ylabel('Label Prediction Error')
plt.title('Minibatch run vs. Label Prediction Error')
plt.show()

# Read the training data
test_file = os.path.join(os.path.dirname(os.path.abspath(__file__)), r"../data/IRIS-TestData.txt")

reader_test = create_reader(test_file,False, input_dim, output_dim)

test_input_map = {
    label  : reader_test.streams.labels,
    input  : reader_test.streams.features,
}

# Test data for trained model
test_minibatch_size = 20
num_samples = 20
num_minibatches_to_test = num_samples // test_minibatch_size
test_result = 0.0

for i in range(num_minibatches_to_test):

    data = reader_test.next_minibatch(test_minibatch_size,input_map = test_input_map)
    eval_error = trainer.test_minibatch(data)
    test_result = test_result + eval_error

# Average of evaluation errors of all test minibatches
print("Average test error: {0:.2f}%".format(test_result*100 / num_minibatches_to_test))


import numpy
from sklearn.metrics import r2_score
import matplotlib.pyplot as plt

x = [1,2,3,5,6,7,8,9,10,12,13,14,15,16,18,19,21,22]
y = [100,90,80,60,60,55,60,65,70,70,75,76,78,79,90,99,99,100]

mymodel = numpy.poly1d(numpy.polyfit(x, y, 3))

#this r2_score gives how much the given data fit in polynomial regression.
#Values range from 0 t 1  where 100 is perfect fit and 0 is not fit.
print(r2_score(y, mymodel(x)))

#Drawing the line of polynomial regression
myline = numpy.linspace(1, 22, 100)
plt.scatter(x, y)
plt.plot(myline, mymodel(myline))
plt.show()

#predicting the speed of a car that passes around at 17. hours
speed = mymodel(17)
print(speed)


import requests
import json
from bs4 import BeautifulSoup
import subprocess
import os
from clint.textui import progress

class CoubDownloader:
    def __init__(self, url):
        if "embed" in url:
            self.url = url.replace("embed", "view")
        else:
            self.url = url
        self.coubid = self.url[22:]
        self.videoname = self.coubid+"_video"
        self.audioname = self.coubid+"_audio.mp3"

    def datadl(self, url, filetype):
        filename = self.audioname if filetype == "audio" else self.videoname
        r = requests.get(url, allow_redirects=True, stream=True)
        with open(filename, 'wb') as f:
            total_length = int(r.headers.get('content-length'))
            for chunk in progress.bar(r.iter_content(chunk_size=1024), expected_size=(total_length / 1024) + 1):
                if chunk:
                    f.write(chunk)
                    f.flush()
        return filename

    def fixencoding(self):
        filename = self.videoname
        with open(filename, 'rb') as f1:
            f1.seek(2)
            with open(filename + ".mp4", 'wb') as f2:
                f2.write(b'\x00\x00')
                for chunk in iter(lambda: f1.read(16384), ''):
                    if chunk == b'':
                        break
                    f2.write(chunk)
        self.videoname = filename + ".mp4"
        return None

    def retrieve_data(self, json, filetype):
        filename = ''
        if "high" in json:
            try:
                url = json["high"]["url"]
                print(url)
                filename = self.datadl(url, filetype)
            except Exception as e:
                print(e)

        elif "med" in json:
            try:
                url = json["med"]["url"]
                filename = self.datadl(url, filetype)
            except Exception as e:
                print(e)
        else:
            print("Error type not found in json (no high/med quality)")
            exit(1)
        return filename

    def merge(self):
        cmd = 'ffmpeg -i {0} -i {1} -filter_complex " [1:0] apad " -shortest {2}.mp4'.format(
            self.videoname, self.audioname, self.coubid)
        subprocess.call(cmd, shell=False)
        os.remove(self.videoname.replace(".mp4", ""))
        os.remove(self.videoname)
        os.remove(self.audioname)
        print('Muxing Done with ffmpeg')

    def dl(self):
        r = requests.get(self.url)
        html = BeautifulSoup(r.text, features="html.parser")
        assert r.status_code == 200
        cbdata = html.find(id="coubPageCoubJson").get_text()
        cbdata = json.loads(cbdata)
        html5 = cbdata["file_versions"]["html5"]
        video = html5["video"]
        audio = html5["audio"]
        self.retrieve_data(video, "video")
        self.retrieve_data(audio, "audio")
        self.fixencoding()


from PIL import Image, ImageDraw

# 1. Write the following code: a = 1/0;
# 2. Build a corresponding try-except block toavoid exception.
def func_1():
    try:
        a = 1 / 0
        print(a)
    except ZeroDivisionError as err:
        print(err)

# 3. Is the following code legal? yes
def func_2():
    try:
        x = 1
        print(x)
    finally:
        print('finally')

# 4. What exception types can be caught by thefollowing handler?
# Except:
# 5. What is wrong with using the above type ofexception handler?

# 6. What exceptions can be caught by the following handlers?
# except IOError
# except ZeroDivisionError
def func_6():
    try:
        file = open('test.txt', 'r')
        print(file.read())
    except IOError as err:
        print(err)

    try:
        x = 10/0
        print(x)
    except ZeroDivisionError as err:
        print(err)

# 7. Create a text file named “words.txt” programmatically
# 8. Write your name into the file
# 9. Read your file content and print it
# 10. Write Hebrew content into your text file and print its content programmatically.
def func_7():
    file = open('words.txt', 'w+', encoding='utf-8')  # 7
    file.write('nir')  # 8
    file.seek(0)  # 9
    print(file.read())

    file.write('ניר')  # 10
    file.seek(0)
    print(file.read())

    file.close()

# 11. Create an image from code (png file) Hint: use Pillow
def func_11():
    img = Image.new('RGB', (100, 100), color='green')
    d = ImageDraw.Draw(img)
    d.text((20, 20), 'Hello World', fill='yellow')
    img.save('pil_green.png')

def main():
    # func_1()
    # func_2()
    # func_6()
    # func_7()
    func_11()

if __name__ == "__main__":
    main()


import os
import nltk
print(os.listdir("../input"))
path = '../input/fradulent_emails.txt'

def parse_raw_message(raw_message):
    lines = raw_message.split('\n')
    email = {}
    message = ''
    keys_to_extract = ['from', 'to']
    for line in lines:
        if ':' not in line:
            message += line.strip()
            email['body'] = message
        else:
            pairs = line.split(':')
            key = pairs[0].lower()
            val = pairs[1].strip()
            if key in keys_to_extract:
                email[key] = val
    return email

with open(path, mode= 'r', errors='ignore') as f:
    mail_list = f.read().split('From')
    tokens = []
    print(len(mail_list))
    for i, x in enumerate(mail_list):
        print(i+1)
        raw_message = parse_raw_message('from:' + x.lower()).get('body')
        if raw_message is not None:
            untagged = nltk.word_tokenize(raw_message)
            tagged = nltk.pos_tag(untagged)
            for term, pos in tagged:
                if len(term) > 2 and pos in ['JJ', 'NN',"NNP"]:
                    tokens.append(term)
    freq = nltk.FreqDist(tokens)
    print(freq.most_common(1000))


from collections.abc import Iterable

from django import forms
from django.template.loader import render_to_string

from kitsune.products.models import Topic
from kitsune.wiki.models import Document

class ProductTopicsAndSubtopicsWidget(forms.widgets.SelectMultiple):
    """A widget to render topics organized by product and with subtopics."""

    def render(self, name, value, attrs=None, renderer=None):
        topics_and_subtopics = Topic.objects.all()
        topics = [t for t in topics_and_subtopics if t.parent_id is None]

        for topic in topics:
            self.process_topic(value, topic)

            topic.my_subtopics = [t for t in topics_and_subtopics if t.parent_id == topic.id]

            for subtopic in topic.my_subtopics:
                self.process_topic(value, subtopic)

        return render_to_string(
            "wiki/includes/product_topics_widget.html",
            {
                "topics": topics,
                "name": name,
            },
        )

    def process_topic(self, value, topic):
        if isinstance(value, int) and topic.id == value:
            topic.checked = True
        elif not isinstance(value, str) and isinstance(value, Iterable) and topic.id in value:
            topic.checked = True
        else:
            topic.checked = False

class RelatedDocumentsWidget(forms.widgets.SelectMultiple):
    """A widget to render the related documents list and search field."""

    def render(self, name, value, attrs=None, renderer=None):
        if isinstance(value, int):
            related_documents = Document.objects.filter(id__in=[value])
        elif not isinstance(value, str) and isinstance(value, Iterable):
            related_documents = Document.objects.filter(id__in=value)
        else:
            related_documents = Document.objects.none()

        return render_to_string(
            "wiki/includes/related_docs_widget.html",
            {"related_documents": related_documents, "name": name},
        )


import metview as mv

# Note: at least Metview version 5.16.0 is required

# getting data
use_mars = False

filename = "vert_hovm_ml_w.grib"

# getting forecast data from MARS
if use_mars:
    ret_core = {
        "type": "fc",
        "date": 20171016,
        "time": 0,
        "step": list(range(0, 132, 12)),
        "levtype": "ml",
        "grid": [1, 1],
        "area": [45, -10, 55, 5],
    }
    w = mv.retrieve(param="w", levelist=list(range(50, 138)), **ret_core)
    lnsp = mv.retrieve(param="lnsp", levelist=1, **ret_core)
    g = mv.merge(w, lnsp)
# read data from file
else:
    if mv.exist(filename):
        g = mv.read(filename)
    else:
        g = mv.gallery.load_dataset(filename)

# define time axis
time_axis = mv.maxis(
    axis_type="date",
    axis_tick_label_height=0.4,
    axis_date_type="hours",
    axis_days_label_height=0.4,
)

# define vertical axis
vertical_axis = mv.maxis(
    axis_type="position_list",
    axis_tick_position_list=[
        1000,
        925,
        850,
        700,
        500,
        400,
        300,
        250,
        200,
        150,
        100,
    ],
    axis_tick_label_height=0.4,
    axis_title_text="Pressure (hPa)",
    axis_title_height=0.5,
)

# define vertical Hovmoeller with pressure axis for model level
# data for a given location (at least Metview version 5.16.0 is required)
hov = mv.mhovmoellerview(
    type="vertical_hovm",
    input_mode="nearest_gridpoint",
    point=[52, -7],
    vertical_level_type="pressure",
    top_level=100,
    bottom_level=1010,
    vertical_coordinate_extrapolate="on",
    vertical_coordinate_extrapolate_mode="constant",
    time_axis=time_axis,
    vertical_axis=vertical_axis,
)

# define contour shading
w_shade = mv.mcont(
    contour_automatic_setting="style_name",
    contour_style_name="sh_viobrn_fM5t5lst",
    legend="on",
)

# define legend
legend = mv.mlegend(legend_text_font_size=0.3, legend_text_colour="charcoal")

# define the output plot file
mv.setoutput(mv.pdf_output(output_name="vert_hovm_ml_in_pressure"))

# generate plot
mv.plot(hov, g, w_shade, legend)


import cv2

face_cascade = cv2.CascadeClassifier('haarcascade_frontalcatface.xml')

img = cv2.imread('cat.png')
faces = face_cascade.detectMultiScale(img, 1.1, 6)

for (a,b,c,d) in faces:
    img = cv2.rectangle(img,(a,b),(a+c,b+d),(255,255,0),3)

cv2.imshow('img',img)
cv2.waitKey(0)
cv2.destroyAllWindows()


from MyHandler import MyHandler
import helpers.DynamoDB as db
from http.server import HTTPServer
from pyngrok import ngrok

PORT_NUMBER = 8080
ngrok_path = "/usr/bin/ngrok"	# NGROK PATH

# GET URL WITHOUT PYNGROK
# def start_ngrok():
#	r = requests.get( "http://localhost:4040/api/tunnels")
#  	data = r.json()
#	return data["tunnels"][1]["public_url"]
def start_ngrok():
    print("Starting ngrok")
    url = ngrok.connect(port=8080, ngrok_path=ngrok_path)
    return url

if __name__ == '__main__':
    try:
        public_url = start_ngrok()
        db.write_url(public_url)
        print(f"{public_url} write on DynamoDB")
        server = HTTPServer(('', PORT_NUMBER), MyHandler)
        print('Server started on port:{}'.format(PORT_NUMBER))
        server.serve_forever()
    except KeyboardInterrupt:
        print('^C received, shutting down server')
        server.socket.close()
        ngrok.kill(ngrok_path=ngrok_path)


from django.contrib import admin
from django.urls import path, include
from django.views.generic import TemplateView
from django.conf.urls.static import static
from django.conf import settings
from django.contrib.staticfiles.urls import staticfiles_urlpatterns
from rest_framework_simplejwt.views import (
    TokenObtainPairView,
    TokenRefreshView,
    TokenVerifyView
)
# from myapp.views import ConfigView

urlpatterns = [
    path('api/token/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
    path('api/token/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
    path('api/token/verify/', TokenVerifyView.as_view(), name='token_verify'),
    path("", TemplateView.as_view(template_name="testcase/tchome.html"), name="home"),
    path("admin/", admin.site.urls),
    path("io_module/", include("io_module.urls"), name="io_module"),
    path("api/", include("api.urls"), name='api'),
    path("auth/", include("users.urls"), name='users'),
    path("restapi/", include('rest_framework.urls'), name="rest_framework"), # UserRegistrationViewSet
    path("config/", include("config.urls"), name='config'),
    path("testcase/", include("testcase.urls"), name='testcase'),
] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)

urlpatterns += staticfiles_urlpatterns()

# path("", TemplateView.as_view(template_name="index.html"), name="home"),
    # path("", TemplateView.as_view(template_name="index.html"), name="home"),

    # path("myapp/", include("myapp.urls")),
    # path("myapp/", ConfigView.as_view(), name="config_api_view"),
    # path("testcase/", include("testcase.urls")),


'''Given a collection of numbers, return all possible permutations.

Example:

[1,2,3] will have the following permutations:

[1,2,3]
[1,3,2]
[2,1,3]
[2,3,1]
[3,1,2]
[3,2,1]
NOTE

No two entries in the permutation sequence should be the same.
For the purpose of this problem, assume that all the numbers in the collection are unique.
Warning : DO NOT USE LIBRARY FUNCTION FOR GENERATING PERMUTATIONS.

Example : next_permutations in C++ / itertools.permutations in python.

If you do, we will disqualify your submission retroactively and give you penalty points.'''

# Sol:1
class Solution:
    # @param A : list of integers
    # @return a list of  integers
    def permute(self, A):
        ans = []

        visited = [False] * len(A)
        self.solve(A, ans, visited, [])
        return ans

def solve(self, A, ans, visited, ssf):
    if len(ssf) == len(A):
        ans.append(ssf[:])
        return
    for i in range(len(A)):
        if visited[i] == False:
            visited[i] = True
            self.solve(A, ans, visited, ssf + [A[i]])
            visited[i] = False

# Official Sol:
class Solution:
    # @param A : list of integers
    # @return a list of list of integers
    def permute(self, A):
        if(len(A) == 1):
            return [A]
        res = []
        for i in range(len(A)):
            nxt = self.permute(A[:i] + A[i+1:])
            for j in nxt:
                res.append([A[i]] + j)
        return res


""" Auteur :        André Da Costa Dias (DACA22099407)
    Date et lieu :  23 mai 2023, Ecole de technologie de Montréal
    Description :   Ce script permet à l'utilisateur de jouer en ligne de commande au jeu du pendu contre
                    le programme. Ce dernier sélectionne aléatoirememnt un mot à partir du fichier texte
                    "mots_pendu.txt" (qui doit obligatoirement être dans le même sous-dossier que ce script
                    "jeu_du_pendu.py"). et guide l'utilisateur sur les actions à mener pour jouer.
"""

import random

def selectionner_mot():
    """ Sélectionne un mot aléatoire à partir du fichier "mots_pendu.txt" contenant une liste de mots """
    with open("mots_pendu.txt", 'r') as fileToRead:
        mots = fileToRead.readlines()
    return random.choice(mots).strip()          # strip() = sécurité qui supprime les éventuels espaces en début et en fin de mot choisi

def initialiser_jeu(mot_a_deviner):
    """ Initialise les variables du jeu en créant les deux listes permettant d'afficher les lettres trouvées et les lettres erronées """
    bonnes_lettres = []
    mauvaises_lettres = []
    for _ in range(len(mot_a_deviner)):
        bonnes_lettres.append("_")              # Prépare le mot à deviner en fonction du nombre de lettres à deviner que compose le mot séléctionné aléatoirement
    return bonnes_lettres, mauvaises_lettres

def afficher_etat_jeu(bonnes_lettres, mauvaises_lettres):
    """ Affiche les états actuels du jeu en affichant les deux listes (lettre trouvées et lettres erronées)"""
    print("\n**************************************************************\n")
    print("Mot à deviner : " + " ".join(bonnes_lettres))    # join() concatène la liste des caractères séparés en une chaîne de caractères avec un espace entre chaque
    if mauvaises_lettres:                                   # teste si la liste des mauvaises lettres entrées n'est plus vide pour commencer à afficher ce message
        print("Ces lettres précédemment entrées qui ne font pas partis du mot : " + " ".join(mauvaises_lettres))

def entrer_lettre(numero_tentative):
   """ Demande à l'utilisateur d'entrer la lettre qu'il souhaite vérifier et retourne la lettre en minuscule et le numéro de la tentative  """
   numero_tentative += 1
   lettre_utilisateur = input(f"Tentative n°{numero_tentative} - Entrez une lettre : ")
   while not lettre_utilisateur.isalpha():      # vérifie que le caractère entré par l'utilisateur est bien une lettre de l'alphabète, sinon demande d'entrer à nouveau une lettre
        print("/!\ Le caractère entré n'est pas une lettre de l'alphabète. Réessayez : ") # Je considère ceci la même tentative
        lettre_utilisateur = input("Entrez à nouveau une lettre : ")
   return numero_tentative, lettre_utilisateur.lower() # Convertit en minuscule au cas ou l'utilisateur a entré une majuscule

def vérifier_lettre(lettre_utilisateur, mot_a_deviner, bonnes_lettres, mauvaises_lettres):
   """ Vérifie et indique si la lettre entrée par l'utilisateur fait partie du mot ou non. """
   if lettre_utilisateur in mot_a_deviner:
       for i in range(len(mot_a_deviner)):              # Afin d'ajouter la bonne lettre utilisateur partout où elle apparait dans le mot à deviner
           if mot_a_deviner[i] == lettre_utilisateur:
               bonnes_lettres[i] = lettre_utilisateur   # Ajoute le bonne lettre utilisateur à l'intérieur de la liste du mot à trouver
       return bonnes_lettres, mauvaises_lettres         # Retourne les deux listes mises-à-jour contenant les lettres trouvées et les lettres manquées
   else:
       mauvaises_lettres.append(lettre_utilisateur)     # Ajoute la mauvaise lettre en fin de liste des mauvaises lettres
       return bonnes_lettres, mauvaises_lettres         # Retourne les deux listes mise-à-jour contenant les lettres trouvées et les lettres manquées

def jouer_au_pendu():
   mot_a_deviner = selectionner_mot()                                   # un mot aléatoire est séléctionné
   bonnes_lettres, mauvaises_lettres = initialiser_jeu(mot_a_deviner)   # initialisation des états du jeu
   numero_tentative = 0
   nb_chances_restantes = 6

   # Jeu qui boucle tant que l'utilisateur n'a pas commis 6 erreurs ou qu'il a fini par trouver toutes les lettres
   while nb_chances_restantes > 0:
       afficher_etat_jeu(bonnes_lettres, mauvaises_lettres)                     # Affiche l'état courant des deux listes
       numero_tentative, lettre_utilisateur = entrer_lettre(numero_tentative)   # Demande à l'utilisateur de rentrer une lettre et retourne le numéro de tentative mis-à-jour
       bonnes_lettres, mauvaises_lettres = vérifier_lettre(lettre_utilisateur, mot_a_deviner, bonnes_lettres, mauvaises_lettres) # Vérification de la lettre entrée pas l'utilisateur
       if "_" not in bonnes_lettres:  # vérifie s'il n'y a plus de lettres manquantes dans le mot a deviner, si c'est le cas, l'utilisateur a gagné
           print("\n------------------------------------------------------------------------------------------------------------------")
           print(f"Félicitation, vous avez trouvez le bon mot. Le mot était effectivement '{mot_a_deviner}' et il vous restait {nb_chances_restantes} chance(s).")
           print("------------------------------------------------------------------------------------------------------------------")
           return   # Met fin au programme si l'utilisateur a gagné (plus de '_')
       if lettre_utilisateur not in bonnes_lettres:     # Si la lettre entrée n'est pas dans le mot à deviner,
           nb_chances_restantes -= 1                    # réduit la nb de chances restantes, afficher les messages à l'utilisateur et reboucle
           print(f"Incorrect, la lettre '{lettre_utilisateur}' ne fait pas partie du mot.")
           print(f"Il vous reste {nb_chances_restantes} chance(s).")
       # Si nb_chance_restante n'est pas encore 0 et qu'il reste des '_' à trouver (condition précédente, ligne 63), boucle ici.
   # Si nb_chance_restante est égal à 0, sort de la boucle et l'utilisateur a perdu.
   print("\n-------------------------------------------------------------------------------------------------------")
   print(f"Vous avez perdu. Il ne vous reste plus de chance. Le mot qu'il fallait deviner était : {mot_a_deviner}")
   print("-------------------------------------------------------------------------------------------------------")

jouer_au_pendu()


## System Imports

## Application Imports
from broker import app

## Library Imports

def test_client():
    flask_app = app.flask_app

    with flask_app.test_client() as testing_client:
        with flask_app.app_context():
            return testing_client


from src.core.domain.target import Target
from src.interfaces.subdomain_enumerator import SubdomainEnumerator

class CrtEnumerationUseCase:
    """This is the SubdomainEnumerator Enumeration Use Case.\n
    it will be used to enumerate subdomains using search engine dorks
    """

    def __init__(self, crt: SubdomainEnumerator) -> None:
        """Inject a search engine dork to be used

        Args:
            crt (SubdomainEnumerator): crt search.Must implement SubdomainEnumerator interface
        """

        if not isinstance(crt, SubdomainEnumerator):
            raise ValueError(f'crt param should be a SubdomainEnumerator instance, not a {type(crt)}')

        self._crt = crt

    def execute(self, target: Target):
        """Execute method will run the enumeration process

        Args:
            target (Target): url or domain to enumerate
        """

        if not isinstance(target, Target):
            raise ValueError(f'target param should be a Target instance, not a {type(target)}.')

        self._crt.target_uri = target.target_uri.uri

        return self._crt.run()


'''
Thoughts:

The basic idea is to partition an array using a value, put all the values smaller than the value given on the left and put all the values greater than the value given on the right
This is done by partition(), since compare.cmp() can only compare nuts and bolts, we will pick up one bolt from bolts and partition nuts using bolt
Return nut and pos
Here nut matches bolt and pos is the index of nut after nuts have been partitioned
nut is then used to partition bolts
nuts and bolts are then splitted into two, nuts[left : pos] and nuts[pos + 1 : right] and helper() is applied to both subarrays

'''

class Compare:
	def cmp(self, a, b):
		if a > b:
			return 1
		if a < b:
			return -1
		return 0

class Solution:
	def sortNutsAndBolts(self, nuts, bolts, compare):
		self.helper(nuts, bolts, 0, len(nuts) - 1, compare)

	def helper(self, nuts, bolts, left, right, compare):
		if left >= right:
			return
		bolt = bolts[left]
		nut, pos = self.partition(nuts, left, right, bolt, compare)
		self.partition(bolts, left, right, nut, compare)
		self.helper(nuts, bolts, left, pos - 1, compare)
		self.helper(nuts, bolts, pos + 1, right, compare)

	def partition(self, A, left, right, b, compare):
		while left < right:
			while left < right and compare.cmp(b, A[left]) == 1:
				left += 1
			while right > left and compare.cmp(A[right], b) == 1:
				right -= 1
			if left < right:
				A[left], A[right] = A[right], A[left]
			if compare.cmp(A[left], b) != 0:
				left += 1
			if compare.cmp(A[right], b) != 0:
				right -= 1
		# print(A, left, right)
		return A[left], left

import random
nuts = [1, 2, 3, 4]
bolts = [5, 3, 2, 1]
random.shuffle(nuts)
random.shuffle(bolts)
print(nuts, bolts)
compare = Compare()

inst = Solution()
inst.sortNutsAndBolts(nuts, bolts, compare)
print(nuts, bolts)


# -*- coding: utf-8 -*-
# 2020-04-13
# author Liu,Yuxin

# 1
'''

n = int(input())
applst = [int(i) for i in list(input().split())]
hmax = int(input())
hmax += 30
cnt = 0
for apple in applst:
    if hmax >= apple:
        cnt += 1
print(cnt)
'''

# 2
'''
n = int(input())
if n == 1:
    print('YES')
else:
    menulst = [int(i) for i in list(input().split())]
    menudic = {}
    for i in range(len(menulst)):
        menudic[menulst[i]] = menudic.get(menulst[i], 0)+1
    differenttype = len(menudic)
    if differenttype == 1:
        print('NO')
    else:
        value = menudic.values()
        maxkey = max(value)
        if maxkey >= n/2+1:
            print('NO')
        else:
            print('YES')
'''

# 3
'''

s = input().split()
n = int(s[0])
k = int(s[1])
lst = []
for i in range(n):
    lst.append(int(input()))
lst.sort()
maxlength = 0
if n >= k :
    maxlength = lst[n-k]
elif n < k:
    maxlength = lst[0]
    while True:
        klst = [lst[i]//maxlength for i in range(len(lst))]
        sumklst = sum(klst)
        if sumklst == k:
            break
        else:
            maxlength -= 1
        if maxlength <= 1:
            break
print(maxlength)

'''

# 4
s = input().split()
n = int(s[0])
q = int(s[1])
nlst = []
for i in range(n):
    day = [int(i) for i in input().split()]
    day = day[1::]
    day.sort()
    nlst.append(day)
daydic = {}
for i in range(len(nlst)):
    for j in range(len(nlst[i])):
        daydic[nlst[i][j]] = daydic.get(nlst[i][j], 0)+1
daylst = []
for key in daydic:
    if daydic[key]>=q:
        daylst.append(key)
if len(daylst) == 0:
    print(0)
else:
    print(min(daylst))


# Given a binary tree, return the inorder traversal of its nodes' values.
# For example:
# Given binary tree [1,null,2,3],
#    1
#     \
#      2
#     /
#    3
# return [1,3,2].
# Note: Recursive solution is trivial, could you do it iteratively?

# Trivial Recursive Solution

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution(object):
    def iot(self, root, nodes):
        if not root:
            return
        self.iot(root.left, nodes)
        nodes.append(root.val)
        self.iot(root.right, nodes)
        return

    def inorderTraversal(self, root):
        """
        :type root: TreeNode
        :rtype: List[int]
        """
        self.nodes = []
        self.iot(root, self.nodes)
        return self.nodes

# Not so Trivial, Iterative Solution


#A program to compute the first intersection of v=0
import matplotlib.pyplot as plt
import numpy as np
import scipy.stats as st
import sdeint
from scipy import integrate

def f_SDE(x,t):
    v=x[0]
    e=x[1]
    g_val = -k* np.abs(v)/(1+mu*abs(e)**gamma)
    dvdt=-alpha*(v-e)
    dedt=g_val
    return np.array([dvdt,dedt])

def sigma_SDE(x,t):
    return B

v0_init = np.array([0.1, 1])

numtests=100
#Use numtests=1 if plot_histograms = True;
#Use numtests = the desired number of points (e.g., 100) if producing the mean zero crossing plots
to_plot_histogram=False #Make this True to plot the histogram

num_tries=100 #Number of tries for each histogram:
    #1000 if PlotHistogram = True; 100 if PlotHistogram = False

#alpha and k are fixed to the values in the paper
# Time is measured in units of 1/alpha, so t=1 is equivalent to 1 month
alpha = 0.5 #1/alpha is response time in months
k = 0.05
alpha_arr = alpha*np.ones(numtests)
k_arr     = k*np.ones(numtests)

# sigma_arr = 0.01*np.ones(numtests)
# mu_arr    = 0.1*np.ones(numtests)
# gamma_arr = 1*np.ones(numtests)
# v0_arr    = -0.1*np.ones(numtests)

sigma_arr = np.random.uniform(0.01,0.1,numtests)
mu_arr    = np.random.uniform(0.1,2,numtests)
gamma_arr = np.random.uniform(0.5,1.5,numtests)
v0_arr    = np.random.uniform(0.1,1,numtests)

A=np.array([[1,-1],[k,0]])
lam,v = np.linalg.eig(A)
vi=np.linalg.inv(v)
sigma_0=np.matmul(vi,np.array([[1],[0]]))
max_eig_index=np.argmax(lam)

t_end=100.0 #Number in months
num_pts_sim = int(t_end*30) #Delta t is 1 day

t_cross=np.zeros((numtests,num_tries))
t_predict=np.zeros(numtests)

t_times_p = lambda t , x, lam_val: t*np.abs(x)/np.sqrt(2*np.pi)*(lam_val/np.sinh(lam_val*t))**(3./2) \
                        *np.exp(- lam_val*x**2*np.exp(-lam_val*t)/(2*np.sinh(lam_val*t)) \
                                + lam_val*t/2)

for m in range (0,numtests):

    sigma_transform=sigma_0[max_eig_index]*sigma_arr[m] #The real value of sigma

    if (to_plot_histogram):
        sigma=0.1
        k=0.05
        alpha=0.5
        mu=1
        gamma=1
        v0=v0_init[1] #Use either 0 or 1 to produce results with different initial values
        lam_val = lam[max_eig_index]*alpha
        sigma_transform=sigma_0[max_eig_index]*sigma
    else:
        sigma = sigma_arr[m]
        k = k_arr[m]
        alpha = alpha_arr[m]
        mu = mu_arr[m]
        gamma = gamma_arr[m]
        v0=v0_arr[m]
        sigma_transform=sigma_0[max_eig_index]*sigma_arr[m] #The real value of sigma

    B=np.diag([sigma,0])
    e0=0
    x0=np.array([v0,e0])
    for j in range(0,num_tries):

        tspan=np.linspace(0,t_end,num_pts_sim)
        result = sdeint.itoint(f_SDE, sigma_SDE, x0, tspan)
        v=result[:,0]
        e=result[:,1]
        t=tspan
        #Find the first occurrence where v changes sign the first time
        ind_change = np.where(v[:-1] * v[1:] < 0 )[0][0]
        t_cross[m,j]=tspan[ind_change]

    print("Test group number ",m," Change of sign occurred at t=",np.mean(t_cross[m,:]))
    if (to_plot_histogram):
        lam_val=lam[max_eig_index]*alpha
    else:
        lam_val=lam[max_eig_index]*alpha_arr[m]

    xi0_vec=np.matmul(vi,np.array([[v0],[0]]))
    x=xi0_vec[max_eig_index]/sigma_transform

    #computing mean exit from the formula
    t_predict[m], err = integrate.quad(t_times_p, 0, 100, args=(x,lam_val))
    if ((m==0) and to_plot_histogram):
        #Plot histogram of solutions
        plt.figure(1)
        plt.clf()
        plt.figure(constrained_layout=True)
        tmax=10
        plt.hist(t_cross[0,:],bins=40,density=True,range=[0,tmax])
        #Plotting theoretical graph of probability transition from v0 to 0
        # Formula (2.8) from L. Alili, P. Patie and J.L. Pedersen

        t1=t[1:]
        p=np.abs(x)/np.sqrt(2*np.pi)*(lam_val/np.sinh(lam_val*t1))**(3./2) \
            *np.exp(\
                - lam_val*x**2*np.exp(-lam_val*t1)/(2*np.sinh(lam_val*t1)) \
                + lam_val*t1/2 \
            )
        #Done in order to avoid singularity at t=0
        p=np.insert(p,0,0) #inserting value of 0 in the beginning
        #plt.figure(1)
        plt.plot(t,p,'r-')
        plt.xlim([0,tmax])
        plt.title('Histogram of first time crossing with v(0)='+str(v0),fontsize=12)
        plt.xlabel('First crossing time, months',fontsize=12)
        plt.ylabel('Probability density',fontsize=12)
        plt.legend(['Theory','Simulation'],fontsize=12)
        plt.yticks(fontsize=12)
        plt.xticks(fontsize=12)
        plt.savefig('HistogramFirstCrossing_v0_'+str(v0)+'.pdf')

mean_t_cross=np.mean(t_cross,axis=1)

valmax=np.max([np.max(mean_t_cross),np.max(t_predict)])+0.2
t1=np.linspace(0,valmax,10)
fig=plt.figure(2)
plt.clf()
fig, ax = plt.subplots(1, 1)
ax.plot(mean_t_cross,t_predict,'bo',t1,t1,'r-')
# x=np.linspace(0,valmax,10)
# plt.plot(t_predict1,mean_t_cross,'ro',x,x,'k-')

ax.set_title('Mean zero crossing time for v(0)>0',fontsize=12)
plt.xlabel('Measured',fontsize=12)
plt.ylabel('Predicted',fontsize=12)
ax.legend(['Experiment','Ideal'],fontsize=12)
ax.set(xlim=(0, valmax), ylim=(0, valmax))
ax.set_aspect('equal')
fig.tight_layout()
plt.yticks(fontsize=12)
plt.xticks(fontsize=12)
if (not(to_plot_histogram)):
    plt.savefig('Predicted_vs_measured_zero_crossing.pdf')

# plt.hist(t_cross,bins=50, density=True)
# plt.xlabel("Time, first crossing v=0")
# plt.ylabel("Frequency")

# valmax=5
# #plt.plot(mean_t_cross,t_predict1,'ro',mean_t_cross,t_predict2,'bx')
# x=np.linspace(0,valmax,10)
# plt.plot(t_predict1,t_cross,'ro',x,x,'k-')
# plt.title('Mean zero crossing time for v(0)<0')
# plt.ylabel('Measured')
# plt.xlabel('Predicted')

# plt.xlim([0,valmax])
# plt.ylim([0,valmax])
# ax.set_aspect('equal')
# plt.savefig('Predicted_vs_measured_zero_crossing_all.pdf')


n=int(input())
count=0
flag=0
for _ in range(n):
    s=input().rstrip()
    stack=[]
    for i in range(len(s)):
        stack.append(s[i])
        if s[i] in stack[:i-1]:
            if s[i]==stack[i-1]:
                flag=1
            else:
                flag=0
                break
        else:
            flag=1
    if flag:
        count+=1

print(count)


import math

# calcola i coefficienti di bezout ax + by = mcd(a,b)
# restituisce una tupla (x, y ,mcd(a,b))
def bezout(a,b):
    x = [1,0]
    y = [0,1]
    i = 2
    while (b != 0):
        q = a//b
        x.append(x[i-2] - q * x[i-1])
        y.append(y[i-2] - q * y[i-1])
        a,b = b,a%b
        i += 1
    return (x[-2], y[-2], a)

# calcola l'inverso modulo n utilizzando la funzione bezout()
def inverse(a, n):
    if math.gcd(a, n) != 1:
        raise Exception(f"L'inverso di {a} mod {n} non esiste!")
    else:
        return bezout(a, n)[0]

# risolve il sistema di congruenze x ≡ a[i] (mod n[i])
# utilizzando il teorema cinese del resto
def cinese(a, n):
    if (len(a) != len(n)):
        raise Exception(f"Le due list {a} e {n} non hanno la stessa dimensione")
    x = 0
    N = math.prod(n)
    for i in range(0,len(n)):
        Ni = N//n[i]
        x += (a[i]*Ni*inverse(Ni, n[i])) % N
    return x % N


# -*- coding: utf-8 -*-
import pytest
import logging

@pytest.fixture(scope='session', autouse=True)
def init_logger():
    logger = logging.getLogger()
    logger.setLevel(logging.DEBUG)
    logger.setLevel(logging.INFO)
    logger.setLevel(logging.DEBUG)
    fh = logging.FileHandler('test_flow.log')
    fh.setLevel(logging.INFO)
    ch = logging.StreamHandler()
    ch.setLevel(logging.INFO)
    formatter = logging.Formatter('%(asctime)s : %(levelname)s : %(message)s')
    fh.setFormatter(formatter)
    ch.setFormatter(formatter)
    logger.addHandler(fh)
    logger.addHandler(ch)
    logger.info("\n\n     ##########   NEW TEST SESSION STARTED   ########## \n")

@pytest.fixture(scope='function', autouse=True)
def log_test_case(request):
    logging.info('Test "%s" started', request.module.__name__ + "." + request.function.__name__)
    def log_finish():
        logging.info('Test "%s" finished \n', request.module.__name__ + "." + request.function.__name__)
    request.addfinalizer(log_finish)


# 3. a. Search in a sorted array (produce code ex3.5.a.py)

import timeit
import matplotlib.pyplot as plt

# Create a sorted list with 1000 elements
array = []
for i in range(0, 1000):
    array.append(i)

# Efficient method: Binary Search
# Worst case complexity: O(log n)
def binarySearch(arr, low, high, key):
    if high >= low:
        mid = (high + low) // 2

        if arr[mid] == key:
            return mid

        elif arr[mid] > key:
            return binarySearch(arr, low, mid - 1, key)

        else:
            return binarySearch(arr, mid + 1, high, key)

    else:
        return -1

#Inefficient method: Linear Search
# Worst case complexity: O(n)
def linearSearch(arr, n, key):
    for i in range(0, n):
        if arr[i] == key:
            return i
    return -1

def main():
    # Provide the code for an experiment that demonstrates the difference. The experiment should:
    # (i) time the execution of both implementations on realistic, large inputs (1000 elements or above);
    # (ii) plot the distribution of measured values across multiple measurements (>= 100 measurements per task); and
    # (iii) print an aggregate of the measured values (min or average as appropriate).

    # (i) time the execution of both implementations on realistic, large inputs (1000 elements or above);
    binaryTimes = []
    linearTimes = []
    for task in array:
        elapsed_time_binary = timeit.timeit(lambda: binarySearch(array, 0, len(array) - 1, task), number=100)
        binaryTimes.append(elapsed_time_binary)

        elapsed_time_linear = timeit.timeit(lambda: linearSearch(array, len(array), task), number=100)
        linearTimes.append(elapsed_time_linear)

    # (ii) plot the distribution of measured values across multiple measurements (>= 100 measurements per task);
    plt.plot(array, binaryTimes)
    plt.plot(array, linearTimes)
    plt.xlabel('Tasks')
    plt.ylabel('Elapsed Time')
    plt.title('Binary Search vs. Linear Search')
    plt.legend(['Binary Search', 'Linear Search'])
    plt.tight_layout()
    plt.show()

    # (iii) print an aggregate of the measured values (min or average as appropriate).
    print("Binary Search Avg Elapsed Time:", sum(binaryTimes) / len(binaryTimes))
    print("Linear Search Avg Elapsed Time:", sum(linearTimes) / len(linearTimes))

if __name__ == '__main__':
    main()


import pygame

class MainWindow:
    def __init__(self, config):
        self.cnf = config

        pygame.init()
        pygame.display.set_caption("Sorts")
        self.screen = pygame.display.set_mode((self.cnf.window.width, self.cnf.window.height))
        self.clock = pygame.time.Clock()

    def run(self, state):
        self.screen.fill(self.cnf.window.background)  # clear screen

        if state.is_worked and not state.is_sorted:  # check statuses and run iteration of sorting
            state.positions = state.algorithm.sort()
            state.iterations += 1
        state.is_sorted = state.algorithm.is_sorted()

        self._render_layout(state=state)
        self._render_array_elements(state=state)

        pygame.display.flip()

        self.clock.tick(self.cnf.main_loop.fps)

        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                return False
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_SPACE:
                    state.is_worked = not state.is_worked
                if event.key == pygame.K_r:
                    state.reset()
                if event.key == pygame.K_q:
                    return False
                if event.key == pygame.K_UP:
                    state.next_algorithm()
                if event.key == pygame.K_DOWN:
                    state.previous_algorithm()

        return True

    def _render_array_elements(self, state):
        chart_width = self.cnf.window.width - self.cnf.paddings.left - self.cnf.paddings.right
        chart_height = self.cnf.window.height - self.cnf.paddings.bottom - self.cnf.paddings.top
        offset_x = self.cnf.paddings.left
        bar_width = (chart_width - self.cnf.paddings.inner * len(state.data) - 1) / len(state.data)

        for index, el in enumerate(state.data):
            # bars
            bar_height = el * chart_height / state.max_el
            rect = pygame.Rect(
                offset_x,
                self.cnf.window.height - self.cnf.paddings.bottom - bar_height,
                bar_width,
                bar_height
            )
            # borders
            if index in state.positions:
                pygame.draw.rect(
                    self.screen,
                    self.cnf.figure.border_color,
                    pygame.Rect(
                        offset_x - self.cnf.figure.border_width,
                        self.cnf.window.height - self.cnf.paddings.bottom - bar_height - self.cnf.figure.border_width,
                        bar_width + self.cnf.figure.border_width + self.cnf.figure.border_width,
                        bar_height + self.cnf.figure.border_width
                    )
                )

            pygame.draw.rect(
                self.screen,
                self.cnf.figure.bar_color,
                rect
            )

            offset_x = offset_x + self.cnf.paddings.inner + bar_width

    def _render_layout(self, state):
        font_main = pygame.font.Font(
            'freesansbold.ttf',
            self.cnf.window.main_font.size,
        )
        font_secondary = pygame.font.Font(
            'freesansbold.ttf',
            self.cnf.window.secondary_font.size,
        )

        self._aside(state=state, font=font_secondary)
        self._header(state=state, font=font_main)
        self._footer(state=state, font=font_main)

    def _header(self, state, font):
        text_header = font.render(
            f"Iterations: {state.iterations} | " + ('Sorted Successfully' if state.is_sorted else 'Not sorted'),
            True,
            self.cnf.window.main_font.color,
            self.cnf.window.background
        )
        text_rect_header = text_header.get_rect()
        text_rect_header.center = (
            (self.cnf.paddings.left + (self.cnf.window.width - self.cnf.paddings.left)) // 2,
            self.cnf.paddings.top // 2
        )
        self.screen.blit(text_header, text_rect_header)

    def _footer(self, state, font):
        text_footer = font.render(
            ' '.join(
                f"""
                    Space: {'Pause' if state.is_worked else 'Start'},
                    {'UP: Next algorythm,' if state.algorithms.index(state.algorithm.__class__ ) < len(state.algorithms) - 1 else ''}
                    {'DOWN: Previous algorythm,' if state.algorithms.index(state.algorithm.__class__ ) > 0 else ''}
                    R: Reset,
                    Q: Exit
                """.split()
            ),
            True,
            self.cnf.window.main_font.color,
            self.cnf.window.background
        )
        text_rect_footer = text_footer.get_rect()
        text_rect_footer.center = (
            self.cnf.window.width // 2,
            self.cnf.window.height - (self.cnf.paddings.bottom // 2)
        )
        self.screen.blit(text_footer, text_rect_footer)

    def _aside(self, state, font):
        self._aside_header(state=state, font=font)
        self._aside_body(state=state, font=font)

    def _aside_header(self, state, font):
        text_aside_header = font.render(
            state.algorithm.name,
            True,
            self.cnf.window.secondary_font.color,
            self.cnf.window.background
        )
        text_rect_aside_header = text_aside_header.get_rect()
        text_rect_aside_header.center = (
            (self.cnf.paddings.left - (self.cnf.paddings.inner * 2)) // 2,
            self.cnf.paddings.top // 2
        )

        self.screen.blit(text_aside_header, text_rect_aside_header)

    def _aside_body(self, state, font):
        start_y = self.cnf.paddings.top + self.cnf.paddings.inner
        height = self.cnf.window.secondary_font.size
        start_x = self.cnf.paddings.inner
        width = self.cnf.paddings.left - self.cnf.paddings.inner * 2
        lines = []
        arr = []

        for word in state.algorithm.description.split():
            arr.append(word)
            if font.size(' '.join(arr))[0] > width:
                arr.pop()
                lines.append(' '.join(arr))
                arr = [word]
        if len(arr) > 0:
            lines.append(lines.append(' '.join(arr)))

        for line in lines:
            text_aside_body = font.render(
                line,
                True,
                self.cnf.window.secondary_font.color,
                self.cnf.window.background
            )
            text_rect_aside_body = text_aside_body.get_rect()
            text_rect_aside_body.topleft = (
                start_x,
                start_y + height
            )
            self.screen.blit(text_aside_body, text_rect_aside_body)
            start_y += height


class Solution:
    def trapwater(self, arr):
        l= len(arr)
        maxwater = 0
        for i in range(1, l-1):
            left = arr[i]
            for j in range(i):
                left = max(arr[j], left)

            right = arr[i]
            for j in range(i+1, l):
                right = max(arr[j], right)

            maxwater = maxwater + (min(left, right) - arr[i])

        return maxwater

output = Solution()
arr = [0,1,0,2,1,0,1,3,2,1,2,1]
print(output.trapwater(arr))


from typing import Optional

# Definition for a binary tree node.
class TreeNode:
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right
class Solution:
    def sufficientSubset(self, root: Optional[TreeNode], limit: int) -> Optional[TreeNode]:
        if not root:
            return root

        if not root.left and not root.right:
            if root.val < limit:
                return None
            else:
                return root
        else:
            root.left = self.sufficientSubset(root.left, limit - root.val)
            root.right = self.sufficientSubset(root.right, limit - root.val)
            if not root.left and not root.right:
                return None
            else:
                return root

    # def sufficientSubset(self, root: Optional[TreeNode], limit: int) -> Optional[TreeNode]:
    #     def dfs(root: TreeNode, total: int):
    #         if not root:
    #             return None

    #         left = dfs(root.left, total + root.val)
    #         right = dfs(root.right, total + root.val)

    #         if not left and not right:
    #             if total + root.val < limit:
    #                 return None
    #             if root.left or root.right:
    #                 return None

    #         root.left = left
    #         root.right = right

    #         return root

    #     return dfs(root, 0)


def countSort(arr, maxi):
    n = len(arr)
    count = [0 for _ in range(maxi+1)]
    result = [0 for _ in range(n)]
    for number in arr:
        count[number] += 1
    for i in range(1, maxi+1):
        count[i] += count[i-1]
    for i in range(n-1, -1, -1):
        count[arr[i]] -= 1
        result [count[arr[i]]] = arr[i]
    return result

arr=[1,4,3,5,6,2,7,19,3,10,22,15,4]
maxi = max(arr)
print(arr)
print(countSort(arr, maxi))


from random import randint
import os
import math
print(os.path.basename(__file__))
childname = list(os.path.basename(__file__))
random0 = randint(0,len(childname)-4)
random1 = randint(1,36)
newChar = ""
if(random1 == 1):
	newChar = "a"
elif(random1 == 2):
	newChar = "b"
elif(random1 == 3):
	newChar = "c"
elif(random1 == 4):
	newChar = "d"
elif(random1 == 5):
	newChar = "e"
elif(random1 == 6):
	newChar = "f"
elif(random1 == 7):
	newChar = "g"
elif(random1 == 8):
	newChar = "h"
elif(random1 == 9):
	newChar = "i"
elif(random1 == 10):
	newChar = "j"
elif(random1 == 11):
	newChar = "k"
elif(random1 == 12):
	newChar = "l"
elif(random1 == 13):
	newChar = "m"
elif(random1 == 14):
	newChar = "n"
elif(random1 == 15):
	newChar = "o"
elif(random1 == 16):
	newChar = "p"
elif(random1 == 17):
	newChar = "q"
elif(random1 == 18):
	newChar = "r"
elif(random1 == 19):
	newChar = "s"
elif(random1 == 20):
	newChar = "t"
elif(random1 == 21):
	newChar = "u"
elif(random1 == 22):
	newChar = "v"
elif(random1 == 23):
	newChar = "w"
elif(random1 == 24):
	newChar = "x"
elif(random1 == 25):
	newChar = "y"
elif(random1 == 26):
	newChar = "z"
elif(random1 == 27):
	newChar = "0"
elif(random1 == 28):
	newChar = "1"
elif(random1 == 29):
	newChar = "2"
elif(random1 == 30):
	newChar = "3"
elif(random1 == 31):
	newChar = "4"
elif(random1 == 32):
	newChar = "5"
elif(random1 == 33):
	newChar = "6"
elif(random1 == 34):
	newChar = "7"
elif(random1 == 35):
	newChar = "8"
elif(random1 == 36):
	newChar = "9"
while newChar == list(childname)[random0]:
	random1 = randint(1,36)
	if(random1 == 1):
		newChar = "a"
	elif(random1 == 2):
		newChar = "b"
	elif(random1 == 3):
		newChar = "c"
	elif(random1 == 4):
		newChar = "d"
	elif(random1 == 5):
		newChar = "e"
	elif(random1 == 6):
		newChar = "f"
	elif(random1 == 7):
		newChar = "g"
	elif(random1 == 8):
		newChar = "h"
	elif(random1 == 9):
		newChar = "i"
	elif(random1 == 10):
		newChar = "j"
	elif(random1 == 11):
		newChar = "k"
	elif(random1 == 12):
		newChar = "l"
	elif(random1 == 13):
		newChar = "m"
	elif(random1 == 14):
		newChar = "n"
	elif(random1 == 15):
		newChar = "o"
	elif(random1 == 16):
		newChar = "p"
	elif(random1 == 17):
		newChar = "q"
	elif(random1 == 18):
		newChar = "r"
	elif(random1 == 19):
		newChar = "s"
	elif(random1 == 20):
		newChar = "t"
	elif(random1 == 21):
		newChar = "u"
	elif(random1 == 22):
		newChar = "v"
	elif(random1 == 23):
		newChar = "w"
	elif(random1 == 24):
		newChar = "x"
	elif(random1 == 25):
		newChar = "y"
	elif(random1 == 26):
		newChar = "z"
	elif(random1 == 27):
		newChar = "0"
	elif(random1 == 28):
		newChar = "1"
	elif(random1 == 29):
		newChar = "2"
	elif(random1 == 30):
		newChar = "3"
	elif(random1 == 31):
		newChar = "4"
	elif(random1 == 32):
		newChar = "5"
	elif(random1 == 33):
		newChar = "6"
	elif(random1 == 34):
		newChar = "7"
	elif(random1 == 35):
		newChar = "8"
	elif(random1 == 36):
		newChar = "9"
childname[random0] = newChar
childname = "".join(childname)
child = open(childname, "w")
parent = open(os.path.basename(__file__), "r")
parentString = parent.read()
random3 = randint(0,1)
random0 = abs(math.floor(randint(0,len(parentString)-1)**(1/2.5)/2 - 2))
random1 = randint(0,len(parentString)-1)
parentString = list(parentString)
newChars = []
for x in range(0, random0):
	random2 = randint(1, 57)
	if(random2 == 1):
		newChars.append("a")
	elif(random2 == 2):
		newChars.append("b")
	elif(random2 == 3):
		newChars.append("c")
	elif(random2 == 4):
		newChars.append("d")
	elif(random2 == 5):
		newChars.append("e")
	elif(random2 == 6):
		newChars.append("f")
	elif(random2 == 7):
		newChars.append("g")
	elif(random2 == 8):
		newChars.append("h")
	elif(random2 == 9):
		newChars.append("i")
	elif(random2 == 10):
		newChars.append("j")
	elif(random2 == 11):
		newChars.append("k")
	elif(random2 == 12):
		newChars.append("l")
	elif(random2 == 13):
		newChars.append("m")
	elif(random2 == 14):
		newChars.append("n")
	elif(random2 == 15):
		newChars.append("o")
	elif(random2 == 16):
		newChars.append("p")
	elif(random2 == 17):
		newChars.append("q")
	elif(random2 == 18):
		newChars.append("r")
	elif(random2 == 19):
		newChars.append("s")
	elif(random2 == 20):
		newChars.append("t")
	elif(random2 == 21):
		newChars.append("u")
	elif(random2 == 22):
		newChars.append("v")
	elif(random2 == 23):
		newChars.append("w")
	elif(random2 == 24):
		newChars.append("x")
	elif(random2 == 25):
		newChars.append("y")
	elif(random2 == 26):
		newChars.append("z")
	elif(random2 == 27):
		newChars.append("0")
	elif(random2 == 28):
		newChars.append("1")
	elif(random2 == 29):
		newChars.append("2")
	elif(random2 == 30):
		newChars.append("3")
	elif(random2 == 31):
		newChars.append("4")
	elif(random2 == 32):
		newChars.append("5")
	elif(random2 == 33):
		newChars.append("6")
	elif(random2 == 34):
		newChars.append("7")
	elif(random2 == 35):
		newChars.append("8")
	elif(random2 == 36):
		newChars.append("9")
	elif(random2 == 37):
		newChars.append("(")
	elif(random2 == 38):
		newChars.append(")")
	elif(random2 == 39):
		newChars.append("=")
	elif(random2 == 40):
		newChars.append("-")
	elif(random2 == 41):
		newChars.append("+")
	elif(random2 == 42):
		newChars.append("/")
	elif(random2 == 43):
		newChars.append("*")
	elif(random2 == 44):
		newChars.append(":")
	elif(random2 == 45):
		newChars.append("&")
	elif(random2 == 46):
		newChars.append("#")
	elif(random2 == 47):
		newChars.append("'")
	elif(random2 == 48):
		newChars.append(",")
	elif(random2 == 49):
		newChars.append("^")
	elif(random2 == 50):
		newChars.append("|")
	elif(random2 == 51):
		newChars.append('"')
	elif(random2 == 52):
		newChars.append("\n")
	elif(random2 == 53):
		newChars.append("")
	elif(random2 == 54):
		newChars.append(" ")
	elif(random2 == 55):
		newChars.append("_")
	elif(random2 == 56):
		newChars.append("~")
	elif(random2 == 57):
		newChars.append("!")
if(random3 == 0):
	for x in range(0, random0):
		if(len(newChars) != 0):
			parentString.insert(random1+x, newChars[x])
	parentString = "".join(parentString)
	print("inserted")
elif(random3 == 1):
	for x in range(0, random0):
		if(len(newChars) != 0):
			parentString[random1+x] = newChars[x]
	parentString = "".join(parentString)
	print("replaced")
print("new charset = ", newChars)
print("mutation ammount = ", random0)
print("mutation place = ", random1)
print("child = "+childname)
child.write(parentString)
os.system("start python "+childname+" 1")
os.system("start python "+os.path.basename(__file__)+" 1")


from imblearn.over_sampling import SMOTE
from imblearn.under_sampling import ClusterCentroids
from imblearn.combine import SMOTETomek
from raych.util import logger

"""
Method 1: over_sampling, under_sampling

Method 2: eg. Focal loss

Method 3: unbalanced cost for each type of prediction
"""

"""
Package Doc Link: https://imbalanced-learn.org/dev/references/generated/imblearn.combine.SMOTETomek.html

SMOTE: Use neighbors to interpolate new samples.
Tomek: Use Tomek Links to remove the pairs of two classes samples that are around the classification boundary.
ClusterCentroids: Use N cluster centroids to replace the origin samples.

NearMiss:
    (Negative sample refers to the samples from the minority class.)
    NearMiss-1 selects the positive samples for which the average distance to the N closest samples of the negative class is the smallest.
    NearMiss-2 selects the positive samples for which the average distance to the N farthest samples of the negative class is the smallest.
    NearMiss-3：对于每个少数类样本选择K个最近的多数类样本，目的是保证每个少数类样本都被多数类样本包围.

More choices:
    over_sampling: https://imbalanced-learn.org/dev/over_sampling.html#
    under_sampling: https://imbalanced-learn.org/dev/under_sampling.html
    Classifier including inner balancing samplers: https://imbalanced-learn.org/dev/ensemble.html
"""

def unbalance_helper(X_train, X_test, y_train, y_test,
                     imbalance_method='under_sampling'):
    """
    Args:
        imbalance_method (str, optional): over_sampling, or under_sampling. Defaults to 'under_sampling'.

    Returns:
        processed data
    """
    # 是否使用不平衡数据处理方式，上采样， 下采样， ensemble
    if imbalance_method == 'over_sampling':
        print("Use SMOTETomek deal with unbalance data ")
        # 插值生成新样本
        X_train, y_train = SMOTETomek().fit_resample(X_train, y_train)
        X_test, y_test = SMOTETomek().fit_resample(X_train, y_train)
    elif imbalance_method == 'under_sampling':
        print("Use ClusterCentroids deal with unbalance data ")
        X_train, y_train = ClusterCentroids(random_state=0).fit_resample(X_train, y_train)
        X_test, y_test = ClusterCentroids(random_state=0).fit_resample(X_test, y_test)

    return X_train, y_train, X_test, y_test


# Given Data
process_names = ["P1", "P2", "P3", "P4"]
arrival_times = [0, 4, 5, 6]
burst_times = [24, 3, 3, 12]
priorities = [3, 1, 4, 2]
num_processes = len(process_names)

# Define functions to compute waiting time and turnaround time
def calculate_waiting_time(burst_time, waiting_time, turnaround_time):
    waiting_time[0] = 0
    for i in range(1, num_processes):
        waiting_time[i] = turnaround_time[i-1] - burst_time[i-1]

def calculate_turnaround_time(burst_time, waiting_time, turnaround_time):
    for i in range(num_processes):
        turnaround_time[i] = burst_time[i] + waiting_time[i]

# 1. First Come First Serve
def fcfs_scheduling():
    waiting_time, turnaround_time = [0] * num_processes, [0] * num_processes
    total_waiting_time, total_turnaround_time = 0, 0

    # Calculate waiting time
    for i in range(1, num_processes):
        waiting_time[i] = burst_times[i-1] + waiting_time[i-1]

    # Calculate turnaround time
    calculate_turnaround_time(burst_times, waiting_time, turnaround_time)

    return waiting_time, turnaround_time

# 2. Shortest Job First
def sjf_scheduling():
    waiting_time, turnaround_time = [0] * num_processes, [0] * num_processes
    total_waiting_time, total_turnaround_time = 0, 0

    # Calculate waiting time
    for i in range(num_processes):
        waiting_time[i] = 0
        for j in range(i):
            waiting_time[i] += burst_times[j]

    # Calculate turnaround time
    calculate_turnaround_time(burst_times, waiting_time, turnaround_time)

    return waiting_time, turnaround_time

# 3. Priority Scheduling
def priority_scheduling():
    waiting_time, turnaround_time = [0] * num_processes, [0] * num_processes
    total_waiting_time, total_turnaround_time = 0, 0

    # Calculate waiting time
    for i in range(1, num_processes):
        waiting_time[i] = burst_times[i-1] + waiting_time[i-1]

    # Calculate turnaround time
    calculate_turnaround_time(burst_times, waiting_time, turnaround_time)

    return waiting_time, turnaround_time

# 4. Round Robin
def round_robin_scheduling(time_quantum):
    waiting_time, turnaround_time = [0] * num_processes, [0] * num_processes
    total_waiting_time, total_turnaround_time = 0, 0
    remaining_burst_time = [0] * num_processes

    for i in range(num_processes):
        remaining_burst_time[i] = burst_times[i]

    current_time = 0
    while True:
        done = True
        for i in range(num_processes):
            if remaining_burst_time[i] > 0:
                done = False

                if remaining_burst_time[i] > time_quantum:
                    current_time += time_quantum
                    remaining_burst_time[i] -= time_quantum
                else:
                    current_time += remaining_burst_time[i]
                    waiting_time[i] = current_time - burst_times[i]
                    remaining_burst_time[i] = 0

        if done:
            break

    # Calculate turnaround time
    calculate_turnaround_time(burst_times, waiting_time, turnaround_time)

    return waiting_time, turnaround_time

# Perform scheduling and calculate waiting times and turnaround times
fcfs_waiting_time, fcfs_turnaround_time = fcfs_scheduling()
sjf_waiting_time, sjf_turnaround_time = sjf_scheduling()
ps_waiting_time, ps_turnaround_time = priority_scheduling()
rr_waiting_time, rr_turnaround_time = round_robin_scheduling(4)

# Calculate and display average waiting time and average turnaround time for each scheduling algorithm
def calculate_average(values):
    return sum(values) / num_processes

average_waiting_time_fcfs = calculate_average(fcfs_waiting_time)
average_turnaround_time_fcfs = calculate_average(fcfs_turnaround_time)

average_waiting_time_sjf = calculate_average(sjf_waiting_time)
average_turnaround_time_sjf = calculate_average(sjf_turnaround_time)

average_waiting_time_ps = calculate_average(ps_waiting_time)
average_turnaround_time_ps = calculate_average(ps_turnaround_time)

average_waiting_time_rr = calculate_average(rr_waiting_time)
average_turnaround_time_rr = calculate_average(rr_turnaround_time)

print("FCFS Scheduling:")
print("Process\t\tWT\t\tTAT")
for i in range(num_processes):
    print(f"{process_names[i]}\t\t{fcfs_waiting_time[i]}\t\t{fcfs_turnaround_time[i]}")
print(f"Average WT: {average_waiting_time_fcfs}")
print(f"Average TAT: {average_turnaround_time_fcfs}")

print("\nSJF Scheduling:")
print("Process\t\tWT\t\tTAT")
for i in range(num_processes):
    print(f"{process_names[i]}\t\t{sjf_waiting_time[i]}\t\t{sjf_turnaround_time[i]}")
print(f"Average WT: {average_waiting_time_sjf}")
print(f"Average TAT: {average_turnaround_time_sjf}")

print("\nPriority Scheduling:")
print("Process\t\tWT\t\tTAT")
for i in range(num_processes):
    print(f"{process_names[i]}\t\t{ps_waiting_time[i]}\t\t{ps_turnaround_time[i]}")
print(f"Average WT: {average_waiting_time_ps}")
print(f"Average TAT: {average_turnaround_time_ps}")

print("\nRound Robin Scheduling:")
print("Process\t\tWT\t\tTAT")
for i in range(num_processes):
    print(f"{process_names[i]}\t\t{rr_waiting_time[i]}\t\t{rr_turnaround_time[i]}")
print(f"Average WT: {average_waiting_time_rr}")
print(f"Average TAT: {average_turnaround_time_rr}")

# Determine the most suitable scheduling algorithm based on average waiting time
average_waiting_times = {
    "FCFS": average_waiting_time_fcfs,
    "SJF": average_waiting_time_sjf,
    "PS": average_waiting_time_ps,
    "RR": average_waiting_time_rr
}

most_suitable_algorithm = min(average_waiting_times, key=average_waiting_times.get)
print(f"\nMost suitable scheduling algorithm is {most_suitable_algorithm} with average waiting time of {average_waiting_times[most_suitable_algorithm]}")


#백준0406 - 황준성

#---1904 – 01 타일---

n = int(input())

T = [0] * (n+1)        #인덱스 0은 사용하지 않고 1부터 시작
T[1] = 1

if n >= 2:
    T[2] = 2

for i in range(3, n+1):
    T[i] = (T[i-1] + T[i-2]) % 15746

# i-1 길이의 모든 2진 수열에서 마지막에 1을 추가한 경우의 수
# i-2 길이의 모든 2진 수열에서 마지막에 00을 추가한 경우의 수

print(T[n])

#100000007은 소수이긴 하지만 이 값으로 나누면
#나머지가 0이 되는 경우가 발생할 수 있습니다
#그리고 이 경우에는 잘못된 결과를 출력하게 됩니다
#반면에 15746은 소수가 아니지만 문제에서 주어진 조건 중 하나인
# "나머지를 출력한다"를 고려하면 15746으로 나누는 것이 올바른 방법입니다

#---1026 – 보물---

n = int(input())
A = list(map(int, input().split()))
B = list(map(int, input().split()))

A.sort()
B.sort(reverse=True)

S = 0
for i in range(n):
    S += A[i] * B[i]

print(S)

#---14495 – 피보나치 비스무리한 수열---

n = int(input())

fib_b = [1, 1, 1]     # f(1), f(2), f(3)

for i in range(3, n):
    fib_b.append(fib_b[i-1] + fib_b[i-3])

print(fib_b[n-1])


from util import each_file, rename, file_exists, drop_prefix, delete, file_empty
from config import temp_folder, consec_folder, merge_temp_folder
import pandas
import os
import log

# merges two data files and overwrites the first file
def merge_data_files(path_to_overwrite, path_other):
    # load the files into dataframes
    frames = [pandas.read_csv(path_to_overwrite), pandas.read_csv(path_other)]

    # merge data into one dataframe
    df = pandas.concat(frames)

    # sort the dataframe by TMSTAMP
    df = df.sort_values(by=["TMSTAMP"])

    # remove any duplicate rows
    df = df.drop_duplicates()

    # save the file back to the path we want to overwrite
    df.to_csv(path_to_overwrite, index=False, header=True)

# this function takes every cleaned data file in
def run():
    log.main("merge cleaned data")

    # delete all empty files in consecutive folder
    for path in each_file(consec_folder):
        if file_empty(path):
            delete(path)

    for path in each_file(merge_temp_folder):
        if file_empty(path):
            delete(path)
            continue

        # remove the directory info to get just the filename and extension
        filename = drop_prefix(path, merge_temp_folder + os.path.sep)
        has_txt_extension = filename.endswith(".txt")
        has_dat_extension = filename.endswith(".dat")

        # if path doesnt have .txt or .dat extension, delete and raise an exception
        # definitely should never happen by the time this function is called
        if not (has_txt_extension or has_dat_extension):
            raise Exception("Invalid data in temp folder after data insertion")

        # get the name of what the corresponding txt/dat file would be in consecutive folder
        if has_txt_extension:
            corresponding_txt = os.path.join(consec_folder, filename)
            corresponding_dat = corresponding_txt.replace("txt", "dat")
        else:
            # has dat extension
            corresponding_dat = os.path.join(consec_folder, filename)
            corresponding_txt = corresponding_dat.replace("dat", "txt")

        # booleans that hold whether corresponding txt/dat files exist
        txt_exists = file_exists(corresponding_txt)
        dat_exists = file_exists(corresponding_dat)

        # if both exist, merge them into the txt and delete the dat
        if txt_exists and dat_exists:
            merge_data_files(corresponding_txt, corresponding_dat)
            delete(corresponding_dat)

        # get the corresponding path if it exists
        # corresponding path is the path to the file that will store data until consecutive value checking is performed
        if txt_exists:
            corresponding_path = corresponding_txt
        elif dat_exists:
            corresponding_path = corresponding_dat
        else:
            corresponding_path = None

        # corresponding file doesn't exist, so just move current file there as a txt file
        if corresponding_path is None:
            rename(path, corresponding_txt)
        else:
            # if the corresponding file exists,
            # merge the data from the files and overwrite corresponding file
            merge_data_files(corresponding_path, path)