####
# Le parser permet d'aller chercher les éléments qui nous interessent dans la page web

####
from bs4 import BeautifulSoup
import bs4
from itertools import chain
from selenium.webdriver.firefox.webdriver import WebDriver
from selenium.common.exceptions import StaleElementReferenceException, ElementNotInteractableException, \
    ElementNotSelectableException, ElementNotVisibleException
from selenium.webdriver.common.keys import Keys
import traceback
import time
import re

from webcrawler.utils import reorgPaquetGenerator
from webcrawler.log import parse_log
from webcrawler.mapper import mapp
from webcrawler.utils import xpath

class Parse():

    webdriver = WebDriver
    PAUSE = 4
    DOCSTRING_LIST_WEBELEMENT = re.compile('^.*:Returns:.*- (list of WebElement).*$')
    DOCSTRING_WEBELEMENT = re.compile('^.*:Returns:.*- (WebElement).*$')

    def __init__(self, session):
        '''
        Le parser permet de parser une page web en fonction d'une liste de balise et de retourner une selection
        nous pouvons soit parser une liste de balise, soit une seule.
        voir les méthodes : parse et list_parse
        :param session: l'objet session
        '''

        parse_log.debug("Nous parsons la page {}".format(type(session)))
        if isinstance(session, self.webdriver):
            parse_log.debug("Recherche de type selenium")
            self.typeRecherche = self.rechercheSelenium
            self.page = session
        elif isinstance(session, str):
            parse_log.debug("Recherche de type BeautifulSoup")
            self.typeRecherche = self.rechercheBF
            self.page = BeautifulSoup(self.page, 'html.parser')

    def list_parse(self, list_baliz ):
        '''
        Permet de parser une liste de balise en appelant la methode parse

        :param list: parse une liste de kwargs
        :return:

        List_resultat
        '''
        return [self.parse(**baliz) for baliz in list_baliz] if list_baliz else self.page

    def __mapp(self, orig, results):
        '''
        Méthode permettant de mettre en relation les résultats avec les attributs finaux demandés
        dans le dictionnaire de données
        :param orig:
        :param results:
        :return:
        '''
        assert isinstance(orig, dict) == True
        assert isinstance(results, dict) == True
        try:
            return [(v, results[k]) for k, v in orig.items()]
        except(KeyError):
            print("le mapping est incorrect \n-orig : {0}\n-results : {1}".format(orig, results))

    def __getBFmethod(self, resu, cle):
        '''
        Méthode permettant d'accéder aux méthodes de beautifulSoup
        :param resu:
        :param cle:
        :return:
        '''
        if hasattr(resu, cle):
            return getattr(resu, cle)
        return

    def __getSeleniumMethod(self, resu, cle):
        '''
        Méthode permettant d'accéder aux méthodes de beautifulSoup
        :param resu:
        :param cle:
        :return:
        '''
        print(set(map(type, resu)), " : " , cle)
        if hasattr(resu, cle):
            #print('l\'element {} possede la methode {}'.format(resu, cle))
            return getattr(resu, cle)
        else:
            return getattr(self.page, cle)
        return

    def resultSetIter(self, resultSet):
        for result in resultSet:
            yield result
    #
    # def rechercheSelenium(self, motif, element):
    #     continue
    # def rechercheSelenium(self, motif, element):

    @xpath
    def rechercheBF(self, motif, element):
        '''
        Recherche BF est un generateur permettant de lancer
        de manière recursive des coroutines de recherche beautiful soup

        :param motif: tuple typeRecherche, valeursDeRecherche
        :param element: bs4.BeautifulSoup or bs4.element.ResultSet
        :param objetRetour: Variable a laquelle assigner une liste de resultat permettant de
        continuer la recherche
        :return: resultat de recherche
        '''

        typeRecherche, valeursDeRecherche = list(motif.items())[0]
        parse_log.debug("Nous sommes dans la fonction {0} valeursDeRecherche:{1}, element: {2} ".format(typeRecherche, valeursDeRecherche, type(element)))

        try:
            if isinstance(element, bs4.element.ResultSet) or isinstance(element, list):
                parse_log.debug('BeautifulSoup ! 1 ' + type(element) + 'typeRecherche : ' + typeRecherche)
                obj = [ self.rechercheBF(motif, result) for result in element ]
                objetRetour = obj if not isinstance(obj[0], list) else list(chain.from_iterable(obj))#list(chain.from_iterable(obj))
            elif isinstance(element, bs4.BeautifulSoup) or isinstance(element, bs4.element.Tag):
                parse_log.debug('BeautifulSoup ! 2 ' + str(type(element)) + 'typeRecherche : ' + typeRecherche ) #"" element bs :" + str(element))
                if isinstance(valeursDeRecherche, dict):
                    objetRetour = self.__getBFmethod(element, typeRecherche)(**valeursDeRecherche)
                if isinstance(valeursDeRecherche, str):
                    objetRetour = self.__getBFmethod(element, typeRecherche)(valeursDeRecherche)
            return objetRetour
        except(Exception) as e:
            print("Nous sommes dans une exception du parseur {}".format(e))
            raise
        #print(" !!! \n\n Nous sommes dans un cas special ", type(element))

    # def infiniteScrollSearch(self, item, action, args=None):
    #     '''
    #     La methode infinite scroll search permet de faire des recherches d'éléments
    #     en faisant un scroll infini dans toutes la page
    #     :param item:
    #     :param action:
    #     :param args:
    #     :return:
    #     '''
    #     pause = 4 ## 4 secondes de pause pour le chargement
    #     onContinue = True
    #     inter = set([])
    #     ## Nous remontons en haut de la page
    #     self.page.execute_script("window.scrollTo(0, 0)")
    #
    #     #print('nous cherchons dans les éléments {}'.format(type(item), item.text if type(item) != type(self.page) else ''))
    #     while onContinue:
    #         try:
    #             trouve = self.seleniumRechercheBase(item, action, args)
    #             if trouve:
    #                 inter.update(set(trouve))
    #             lastHeight = self.page.execute_script("return document.body.scrollHeight")
    #             self.page.execute_script("window.scrollTo(0, document.body.scrollHeight);")
    #             time.sleep(self.PAUSE)
    #             newHeight = self.page.execute_script("return document.body.scrollHeight")
    #             if newHeight == lastHeight:
    #                 onContinue = False
    #             lastHeight = newHeight
    #
    #         except(Exception) as e:
    #             print(e, traceback.format_exc())
    #             raise
    #
    #     return list(inter)

    # def rechercheNestedSelenium(self, selection, resultats):
    #     '''
    #     Permet d'effecteur une recherche sur les éléments inclus dans des recherches
    #     :param selection:
    #     :param resultats:
    #     :return:
    #     '''
    #
    #     #select = (i for i in selection)
    #     resultat = resultats
    #     parse_log.debug("resultats nested: " + str(resultat))
    #     # try:
    #     for item in resultat:
    #         print("Nous sommes à l'item nested {}".format(item))
    #         select = (i for i in selection)
    #         resultat_inter = ''
    #         while select:
    #             print("PETITE PAUSE \n\n")
    #             time.sleep(self.PAUSE)
    #             try:
    #                 action, args = next(select)
    #                 print("Nous faisons l'action {} {} ".format(action, args))
    #                 if action == "nested":
    #                     self.rechercheNestedSelenium(args, resultat if resultat else None)
    #                 else:
    #                     trouve = self.infiniteScrollLocalize(item, action, args)
    #                 if trouve:
    #                     resultat_inter += trouve
    #             except(TypeError) as e:
    #                 print(e, traceback.format_exc())
    #                 raise
    #             except(StaleElementReferenceException):
    #                 inter = self.infiniteScrollLocalize(item, action, args)
    #                 if not inter:
    #                     print("\n ## Nous n'avons pas trouvé l'élément \n ")
    #             except(StopIteration):
    #                 print('Nous avons chopé l\'exception de sortie')
    #                 break
    #
    #     ## Retour à la page principale
    #     self.page.switch_to_window(self.pagePrincipale)
    #
    #     return resultat_inter

    def scroll(self, lastHeight):
        '''
        Permet le scroll
        :return:
        '''
        try:
            self.page.execute_script("window.scrollTo(0, document.documentElement.scrollHeight);")
            #self.page.implicitly_wait(self.PAUSE)
            time.sleep(self.PAUSE)
            newHeight = self.page.execute_script("return document.documentElement.scrollHeight")
            if newHeight == lastHeight:
                self.page.execute_script("window.scrollTo(0, 0)")
                return False, newHeight
            return True, newHeight
        except(Exception) as e:
            print(e, traceback.format_exc())
            raise

    def seleniumRechercheBase(self, item, action, args=None):

        try:
            methodeSelenium = self.__getSeleniumMethod(item, action)
        except(Exception) as e:
            print(e, traceback.format_exc())
            print("L'objet {} n'a pas de méthode {}".format(item, action))
            raise
        return methodeSelenium(args) if args else methodeSelenium()

    def infiniteScrollLocalize(self, item, action, args=None):
        '''
        Methode permettant de rechercher un élément dans la page en scrollant
        :param item: element selenium
        :param action: Methode selenium a appliquer
        :param args: Arguments accompagnant la methode selenium
        :return:
        '''

        onContinue = True
        inter = set([])
        try:
            itemDoc = item.__doc__.replace('\n', '')
        except(AttributeError):
            itemDoc = item.__doc__
        finally:
            if not itemDoc:
                itemDoc = ''

        ## Nous remontons en haut de la page
        self.page.execute_script("window.scrollTo(0, 0)")
        #print("Remontée en haut de page")
        #print('nous cherchons dans l\'élément {} l\'élément {}'.format(type(item), item.text if type(item)!=type(self.page) else '' ))
        lastHeight = self.page.execute_script("return document.documentElement.scrollHeight")
        while onContinue:
            try:
                trouve = [self.__mapp(self.resultat, {cle: item.get_attribute(cle) or getattr(item, cle, '') if cle != 'text' else item.getText().strip() if hasattr(item, 'getText') else item.text
                                                       for cle in self.resultat.keys()}) for item in self.seleniumRechercheBase(item, action, args) ]

                #print(trouve, self.DOCSTRING_LIST_WEBELEMENT.match(itemDoc), self.DOCSTRING_WEBELEMENT.match(itemDoc))
                if (self.DOCSTRING_LIST_WEBELEMENT.match(itemDoc) or itemDoc is '') and trouve:
                    for item in trouve:
                        inter.update(item)
                elif self.DOCSTRING_WEBELEMENT.match(itemDoc) and trouve:
                    return trouve
                elif item in ('click', 'drag_and_drop'):
                    return None
            except(Exception) as e:
                print(e, traceback.format_exc())
                raise

            onContinue, newHeight = self.scroll(lastHeight)
            lastHeight = newHeight

        #print("List inter :", [i.tag_name for i in inter])
        return list(inter) if inter else None

    def rechercheSelenium(self, selection, resultats=None):
        """
        Nous chainons les methodes selenium les unes aux autres
        Plusieurs recherches différentes peuvent être réalisées
        -1 recherche classiques de plusieurs éléments
        -2 Recherches classique puis à partir des cette dernière -- > recherche d'éléments imbriqués -
        cad que nous allons aller vers un groupe d'éléments puis revenir au principal

        :param methodes: Dictionnaires des méthodes
        :return:
        """
        parse_log.debug('Nous chainons les méthodes selenium')
        # methodes_chaines = "self.page."+ ".".join(["{}(**{})".format(func, args) if isinstance(args, dict) else \
        #     "{}({})".format(func, "'{}'".format(str(args)) if args else '')  for item in selection for func, args in item.items()])
        # parse_log.debug(methodes_chaines)

        ## Page principale de référence
        self.pagePrincipale = self.page.current_window_handle

        # nous faisons un generateur
        select = (i for i in selection)

        if not resultats:
            action_prem, args = next(select)
            resultat = self.infiniteScrollLocalize(self.page, action_prem, args)
        else:
            resultat = resultats
        # try:

        while select:
            resultat_inter = ''
            try:
                action, args = next(select)
                parse_log.debug("action args : {} {}".format(action, args))

                if isinstance(resultat, list) or isinstance(resultat, set):
                    resultat_inter = set([])
                    #parse_log.debug('Nous avons plusieurs resultats :\n{} {}'.format(args, str([i.text for i in resultat])))
                    for result_uniq in resultat:
                        try:
                            resultat_inter.update(self.infiniteScrollLocalize(result_uniq, action, args))
                        except(TypeError):
                            resultat_inter.update([])
                            ## si la liste est vide, nous ne pouvons pas itérer dessus
                elif isinstance(resultat, self.page._web_element_cls):
                    parse_log.debug(
                        'Nous avons un resultat unique :\n{} {}'.format(args, resultat.text))
                    resultat_inter = self.infiniteScrollLocalize(self.page, action, args)
                resultat = resultat_inter if resultat_inter else resultat
                parse_log.debug(
                    'Resultat :\n{}'.format(resultat))
            except(StopIteration):
                parse_log.debug(
                    '''Signal d\'arrêt d\'iteration' :{}\n{}'''.format(args, resultat))
                resultat = resultat_inter if resultat_inter else resultat
                break
            except(Exception) as e:
                print(e, traceback.format_exc())
                raise

        return resultat
        # except(Exception) as e:
        #     print(e, traceback.format_exc())
        #     raise

    def parse(self, **kwargs):

        '''

        Permet de faire de recherche de balise et de les retourner sous forme de dictionnaire
        :param objet: recherche un objet contenu dans une balise
               kwargs : {'selection':{'type':None, 'classe':None, 'value':None, 'regex':None},
                         'resultat':{'text':'', 'attr':['liste des attributs']}}}
               Le selection permet de fair eune selection des balises et le résultat permet
               de faire remonter les données attendues
        :return:

        '''

        # try:
        #     assert type(self.page)==str, "La page doit être de type string"
        # except AssertionError:
        #     return

        selection, self.resultat, with_parents = kwargs['selection'].copy(), kwargs['results'].copy(),\
                                  kwargs.get('with_parents', None)

        #page_bf = self.soup
        result = []
        parse_log.debug("selection :\n" + str(selection))
        #parse_log.debug("page affichée :\n" + self.page)
        #     ##faire un iterateur qui renvoi une exception en cas de fin d'iteration
        self.result_partiel = None
        if isinstance(self.page, self.webdriver):
            self.result_partiel = self.rechercheSelenium(selection)
        elif isinstance(self.page, str):
            for selectionMotif in selection:
                ## Si il existe un resultat partiel alors celui-ci est affecté à l'élément sinon
                ## nous prennons la page bf4
                element = self.result_partiel if self.result_partiel else self.page
                #print("Objet en retour dans boucle des motifs {}, result partiel : {}".format(selectionMotif, type(self.result_partiel)))
                self.result_partiel = self.typeRecherche(selectionMotif, element)

        #Permet de renvoyer des résultats non dupliqués si des balises similaires ressortent
        if kwargs.get('duplicates', None):
            #TODO tester si cela passe au niveau du duplicates
            for item in self.result_partiel:
                if not item in result:
                    result.append(item)
        else:
            result = self.result_partiel

        # for i in result:
        #     print(type(i), i, len(i))
            # for g in i:
            #     print(type(g), g)
        ## TODO : tester avec betclick pour que l'on retourne toutes les valeurs des matchs et developper le mapping fields pour que nous puissions injecter directement avec django
        ##
        if result:
            # print(result)
            #parse_log.debug("resultat du parseur" + str(result) +str([i.__dict__ for i in result])+ " type : "+ str(type(result)))
            #parse_log.debug("{}".format([[(item.__dict__, item.get(cle)) if cle != 'text' else item.getText().strip() for cle in resultat.keys()] for item in result ]))
            # resultat = [self.__mapp(resultat, {cle: item.get_attribute("href") or getattr(item, cle, '') if cle != 'text' else item.getText().strip() if hasattr(item, 'getText') else item.text
            #                                            for cle in resultat.keys()}) for item in result ]
            print(self.resultat)
            return self.resultat
        else:
            parse_log.debug("Le parseur ne trouve pas de résultat")
            return

    def getList(self, list_baliz):
        '''
        Permet d'obtenir une liste des balises demandées
        :param list_baliz:
        :return:
        '''
        recherche = self.list_parse(list_baliz)
        resultante = min([len([item.values() for item in  item_recherche if item.values()]) for item_recherche in recherche])
        return list(zip(*[[j  for j in reorgPaquetGenerator(i, resultante) if j ] for i in recherche]))

class rechercheSelenium():

    '''
    Permet de faire une recherche en chaine d'éléments selenium
    la recherche selenium produit des objets chaineDeRecherche
    '''

    def __init__(self, page, recherche):
        pass

class chaineDeRecherche():
    '''
    La chaîne de recherche permet d'avoir un objet contenant tous les éléments d'une chaîne de recherche
    Le chaine permet de faire toute la recherche en une fois. CAD nous allons tout de suite a l'élément le plus profond.
    Une chaîne est produite par élément recherché. Chaque élément est de type webElement au nous allons ajouter des méthodes
    et attributs.
    La chaîne de recherche permet de rechercher dans une page les éléments et de les comparer
    '''

    CHAINE = set([])

    def scroll(self):
        pass

    def __init__(self, recherches, webdriver):
        self.recherches
        self.webdriver

from types import MethodType
# https://www.ianlewis.org/en/dynamically-adding-method-classes-or-class-instanc

class webElement():
    '''
    L'objet webElement est une classe contenant des méthodes qui seront ajoutés aux objet webelement de selenium
    '''
    def __init__(self):
        self.pere = None
        self.fils = None

    def __eq__(self, objet):
        if self.getText == objet.getText:
            return True
        return False

if __name__=='__main__':
    # heure_debut_rencontre = {'selection':{'type':'span', 'class':'KambiBC-event-item__start-time--time'},
    #                  'resultat':{'attrs':['class', 'text']}}
    # sport = {'selection':{'type':'span', 'class':'KambiBC - modularized - event - path__fragment'},
    #                  'resultat':{'attrs':['class', 'text']}
    #          }
    # competition = {'selection':{'type':'span', 'class':'KambiBC-modularized-event-path__fragment'},
    #                  'resultat':{'attrs':['class', 'text']}
    #          }
    # participants = {'selection': {'type': 'div', 'class':'KambiBC-event-participants__name'},
    #                  'resultat': {'text': '','attrs': ['text']}}
    # paris = {'selection': {'type': 'span', 'class': 'KambiBC-mod-outcome__odds'},
    #                'resultat': {'attrs': ['class', 'text']}}
    # nb_offre_de_paris = {'selection': {'type': 'span', 'class': 'KambiBC-event-item__bet-offer-count'},
    #          'resultat': {'attrs': ['class', 'text']}}
    html ='''
    <html>
       <body>
           <div class="test 1">

                    <h1>Titre esssai</h1>
                    <h2>Sous  titre</h2>

           </div>
           <div class='balise1'>
                <span>
                    <h1>Titre esssai 1</h1>
                    <h2>Sous  titre 1</h2>
                </span>
                <span>
                    <h1>Titre esssai 2</h1>
                    <p><h3 class="type1">La ferme de pigeons</h3><h3 class="type1">Le projet des teubés</h3></p>
                    <h2>Sous  titre 2</h2>
                </span>
           </div>
           <div class="test3">
                <span>
                    <h1>Titre esssai 3</h1>
                    <p><h3 class="type1">La ferme de pigeons 2</h3><h3 class="type1">Le projet des teubés 3</h3></p>
                    <h2>Sous  titre 3</h2>
                </span>
           </div>
           <div></div>
       </body>
    </html>
    '''
    # soup = BeautifulSoup(html, 'html.parser')
    # print(soup.html.body.div.span.__getattribute__('parent'))
    a = Parse(html).parse(duplicates=True, **{'selection': [{'find_all': {'name': 'div',}},
                                           {'find_all': {'name': 'span'}},
                                           {'find_all': {'name': 'h2',}},
                                           {'find_parent': 'div'},
                                           {'find_all': {'name': 'h3'}},
                                                       ],
                                         'results': {'class':'classe', 'name':'name', 'xpath':'xpath', 'text': 'texte'},
                                         'mapping_fields': [],
                                         }
                        )
    print(a)
    # for i in a:
    #     print(i)


#!/usr/bin/env python
import rospy
from geometry_msgs.msg import Twist
from sensor_msgs.msg import LaserScan

ranges = []

def callback(data):
    global ranges
    ranges = data.ranges
    # (data.angle_max - data.angle_min)/data.angle_increment: 638.99
    # len(data.ranges):640

def random_walker():
    pub = rospy.Publisher('/mobile_base/commands/velocity', Twist, queue_size=10)
    sub = rospy.Subscriber('/scan', LaserScan, callback)
    rospy.init_node('turtlebot_random_exploration_node')
    rate = rospy.Rate(10)

    cmd = Twist()

    while not rospy.is_shutdown():
        #data.range_min == 0, can be ignored in this case
        global ranges
        distance_smaller_than_thres = [i for i in ranges if i <= 0.5]

        if( len(distance_smaller_than_thres) > 0):
            cmd.linear.x = 0
            cmd.angular.z = 0.5

            pub.publish(cmd)
            rate = rospy.Rate(1)
            rate.sleep()
        else:
            cmd.linear.x = 0.1
            cmd.angular.z = 0
            pub.publish(cmd)
            rate = rospy.Rate(10)
            rate.sleep()

if __name__ == '__main__':
    try:
        random_walker()
    except rospy.ROSInterruptException:
        pass


# Configuration file for the Sphinx documentation builder.
#
# For the full list of built-in configuration values, see the documentation:
# https://www.sphinx-doc.org/en/master/usage/configuration.html

# -- Project information -----------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information

project = "Aimiko"
copyright = "2023, Noelle"
author = "Noelle"

# -- General configuration ---------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration

extensions = ["sphinx.ext.napoleon", "sphinx_copybutton"]

templates_path = ["_templates"]
exclude_patterns = []

latex_elements = {
    "sphinxsetup": "verbatimwithframe=false",
}

html_title = "Aimiko"

# -- Options for HTML output -------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output

html_theme = "furo"
html_static_path = ["_static"]

html_theme_options = {
    "dark_css_variables": {
        "color-brand-primary": "#A685E2",
        "color-brand-content": "#FFABE1",
    },
    "light_css_variables": {
        "color-brand-primary": "#6867AC",
        "color-brand-content": "#CE7BB0",
    },
}


import uuid
from enum import Enum, unique

from sqlalchemy import (
    Column, MetaData, Table,
    String, DateTime, Enum as PgEnum, Integer,
    ForeignKey, Index, UniqueConstraint
)
from sqlalchemy.dialects.postgresql import UUID
from sqlalchemy_utils import LtreeType

metadata = MetaData()

@unique
class ShopUnitType(Enum):
    CATEGORY = "CATEGORY"
    OFFER = "OFFER"

units_table = Table(
    "units",
    metadata,
    Column("id", UUID(as_uuid=True), primary_key=True, default=uuid.uuid4),
    Column("name", String, nullable=False),
    Column("unit_code", String, nullable=False),
    Column("date", DateTime, nullable=False),
    Column("parent_id", UUID(as_uuid=True), ForeignKey("units.id"), nullable=True),
    Column("type", PgEnum(ShopUnitType, name="type"), nullable=False),
    Column("price", Integer, nullable=True),
    Column("path", LtreeType, nullable=False),
    Index("ix__units__path", "path", postgresql_using="gist"),
    Index("ix__unique_unit_in_category", "name", "unit_code", "parent_id",
          unique=True,
          postgresql_where="parent_id IS NOT NULL"
          ),
    Index("ix__unique_unit_in_root", "name", "unit_code",
          unique=True,
          postgresql_where="parent_id IS NULL"
          ),
)


from django.db import models
import os
from django.conf import settings

#### PyKE import ####
from .models_pyke.knowledge import pyke_load_engine, pyke_calculate_bmr, pyke_calculate_EnergyAmount_kcal, pyke_calculate_Nutrients
pyke_load_engine()

######################################################################
# Initialize the data once when Django loads up
# -- will improve in next iteration
######################################################################

from .models_ortools import readFoodData
csv_file = open(os.path.join(settings.BASE_DIR, 'foodrec/Dataset/foodDataBase_Final.csv'))
readFoodData(csv_file)

class Food(models.Model):
    FOOD_GROUPS = sorted(
                    [
                        ("BEVERAGES", "BEVERAGES"),
                        ("CEREAL AND CEREAL PRODUCTS", "CEREAL AND CEREAL PRODUCTS"),
                        ("EGG AND EGG PRODUCTS", "EGG AND EGG PRODUCTS"),
                        ("FAST FOODS", "FAST FOODS"),
                        ("FISH AND FISH PRODUCTS", "FISH AND FISH PRODUCTS"),
                        ("FRUIT AND FRUIT PRODUCTS", "FRUIT AND FRUIT PRODUCTS"),
                        ("HEALTHIER CHOICE SYMBOL (HCS) PRODUCTS", "HEALTHIER CHOICE SYMBOL (HCS) PRODUCTS"),
                        ("MEAT AND MEAT PRODUCTS", "MEAT AND MEAT PRODUCTS"),
                        ("MILK AND MILK PRODUCTS", "MILK AND MILK PRODUCTS"),
                        ("MISCELLANEOUS", "MISCELLANEOUS"),
                        ("MIXED ETHNIC DISHES, ANALYZED IN SINGAPORE", "MIXED ETHNIC DISHES, ANALYZED IN SINGAPORE"),
                        ("NUTS AND SEEDS, PULSES AND PRODUCTS", "NUTS AND SEEDS, PULSES AND PRODUCTS"),
                        ("OILS AND FATS", "OILS AND FATS"),
                        ("OTHER MIXED ETHNIC DISHES", "OTHER MIXED ETHNIC DISHES"),
                        ("SUGARS, SWEETS AND CONFECTIONERY", "SUGARS, SWEETS AND CONFECTIONERY"),
                        ("VEGETABLE AND VEGETABLE PRODUCTS", "VEGETABLE AND VEGETABLE PRODUCTS"),
                    ])

    MEALS = [
                ("BREAKFAST", "BREAKFAST"),
                ("LUNCH", "LUNCH"),
                ("DINNER", "DINNER"),
            ]

    FoodIndex = models.IntegerField()
    FoodName = models.CharField(max_length=100, blank=False)
    FoodGroup = models.CharField(max_length=100, choices=FOOD_GROUPS, default='MISCELLANEOUS')
    CarbohydrateAmount_g = models.FloatField()
    EnergyAmount_kcal = models.FloatField()
    ProteinAmount_g = models.FloatField()
    TotalFatAmount_g = models.FloatField()

    IsVegan = models.BooleanField()
    IsVegetarian = models.BooleanField()
    IsHalal = models.BooleanField()

    FoodMealRanking = models.CharField(max_length=100, choices=MEALS)

    def __repr__(self):
        return self.FoodName

    def __str__(self):
        return self.FoodName

    class Meta:
        ordering = ['FoodName']

#######################################################
# Non-Django classes for now
#######################################################
class Profile:
    # tuple (value, display_text) for GENDER
    GENDER = (
        ('male', 'Male'),
        ('female', 'Female'),
    )

    ACTIVITY = (
        ('sedentary', 'Sedentary'),
        ('lightly_active', 'Lightly Active'),
        ('moderately_active', 'Moderately Active'),
        ('very_active', 'Very Active'),
    )

    DIET = (
        ('standard', 'Standard'),
        ('ketogenic', 'Ketogenic'),
    )

    def __init__(self, gender=None, age=None, height=None, weight=None, activity=None, diet=None):
        self.gender = gender
        self.age = age
        self.height = height
        self.weight = weight
        self.activity = activity
        self.diet = diet
        self.nutrientNeeds = NutrientNeeds(diet=diet,profile=self)    # Initialize an empty NutriendNeeds object

class NutrientNeeds:
    def __init__(self, CarbohydrateAmount_g=None, EnergyAmount_kcal=None, ProteinAmount_g=None, TotalFatAmount_g=None, diet=None, profile=None):
        self.CarbohydrateAmount_g = CarbohydrateAmount_g
        self.EnergyAmount_kcal = EnergyAmount_kcal
        self.ProteinAmount_g = ProteinAmount_g
        self.TotalFatAmount_g = TotalFatAmount_g
        self.diet = diet
        self.profile = profile

    # Calculate the Nutrient Needs
    def calculate(self):
        # Firstly, calculate the BMR
        bmr =float('%.2f' % (pyke_calculate_bmr(self.profile.gender, self.profile.weight, self.profile.height, self.profile.age)))

        # Calculate the Energy
        # EnergyAmount_kcal
        self.EnergyAmount_kcal = pyke_calculate_EnergyAmount_kcal(bmr, self.profile.activity)

        # Calculate the nutrients
        # CarbohydrateAmount_g, TotalFatAmount_g, ProteinAmount_g
        # * Standard diet = balance ratio of Carbs:Fat:Protein = 40%:30%:30%
        # * Keto diet = 75% Fat, 20% Protein, 5% Carb or <50grams
        self.CarbohydrateAmount_g, self.TotalFatAmount_g, self.ProteinAmount_g = pyke_calculate_Nutrients(self.EnergyAmount_kcal, self.diet)


from bs4 import BeautifulSoup
from pprint import pprint
import requests
from queue import Queue
import pandas as pd
import time

def Technology(url):
    news_df = pd.DataFrame()
    html_content = requests.get(url)
    soup = BeautifulSoup(html_content.content, 'lxml')

    ul = soup.find('ul', {"class": "article-list"})

    d = dict()
    for all_li in ul.find_all('li'):
        link = all_li.find("a").get("href")
        print(link)
        d['HEADLINE'] = all_li.text.lstrip().rstrip()
        d['LINK'] = link
        d['IMAGE_LINK'] = all_li.find('img').get('src')

        html_data = requests.get(link)
        soup = BeautifulSoup(html_data.content, 'lxml')
        div_full_content = soup.find('div', {"id": "pcl-full-content"})
        news_content = ''

        for paragraph in div_full_content.find_all('p'):
            news_content += paragraph.text

        d['NEWS'] = news_content

        news_df = news_df.append(d, ignore_index=True)
        d.clear()

    news_df.to_csv('TechnologyNews.csv')

def LifestyleEntertainmentSportsOpinionCities(url, tag):
    print(url)
    df = pd.DataFrame()
    html_content = requests.get(url)
    soup = BeautifulSoup(html_content.content, 'lxml')

    ul = soup.find('div', {"class": "nation"})

    d = dict()
    for all_li in ul.find_all('div'):
        if all_li.get('class') is not None and all_li.get('class')[0].startswith("articles"):

            link = all_li.find("a").get("href")
            d['HEADLINE'] = all_li.text.lstrip().rstrip()
            d['LINK'] = link
            d['IMAGE_LINK'] = all_li.find('img').get('src')

            html_data = requests.get(link)
            soup = BeautifulSoup(html_data.content, 'lxml')
            div_full_content = soup.find('div', {"id": "pcl-full-content"})
            news_content = ''
            print(link)
            try:
                for paragraph in div_full_content.find_all('p'):
                    news_content += paragraph.text
            except AttributeError:
                div_articleBody = soup.find('div', {"itemprop": "articleBody"})
                for paragraph in div_articleBody.find_all('p'):
                    news_content += paragraph.text

            d['NEWS'] = news_content
            # print(d)
            df = df.append(d, ignore_index=True)
            d.clear()

        elif all_li.get('class') is None:
            break

    df.to_csv(tag + 'News.csv')

def main():
    NavbarLinksQueue = Queue()

    # Index page
    index_page_content = requests.get('https://indianexpress.com/')

    index_page_soup = BeautifulSoup(index_page_content.content, 'lxml')
    UL_Navbar = index_page_soup.find('ul', {"id": "navbar"})

    counter = 0
    # Get 8 important links from Navbar
    for ul_li in UL_Navbar.find_all('li'):
        if 1 <= counter <= 8:
            NavbarLinksQueue.put(ul_li.find('a').get('href'))
        counter += 1

    while not NavbarLinksQueue.empty():
        split_links = NavbarLinksQueue.get().split('/')[2]
        if split_links == 'technology':
            Technology(f'https://indianexpress.com/section/{split_links}/')
        elif split_links == 'lifestyle' or split_links == 'entertainment' or \
                split_links == 'sports' or split_links == 'opinions' or split_links == 'cities':
            LifestyleEntertainmentSportsOpinionCities('https://indianexpress.com/section/{}/'.format(split_links),
                                                      split_links)

if __name__ == '__main__':
    start = time.time()
    main()
    print('Time taken', time.time() - start)


from itertools import permutations

def solution(user_id, banned_id):
    answer = []

    for users in list(permutations(user_id, len(banned_id))):
        check = True
        for i in range(len(banned_id)):
            if len(users[i]) != len(banned_id[i]):
                check = False
                break
            for j in range(len(users[i])):
                if users[i][j] == banned_id[i][j] or banned_id[i][j] == '*':
                    continue
                else:
                    check = False
                    break
        if check:
            users = list(users)
            users.sort()
            if users not in answer:
                answer.append(users)
    return len(answer)


"""Represent queries."""
from __future__ import annotations

import strawberry

from pypmanager.helpers import get_general_ledger
from pypmanager.loader_transaction.const import ColumnNameValues

from .models import LedgerRow

@strawberry.type
class Query:
    """GraphQL query."""

    @strawberry.field
    def all_general_ledger(self) -> list[LedgerRow]:
        """Return all general ledger rows."""
        df_general_ledger = get_general_ledger()
        df_general_ledger = df_general_ledger.sort_values(
            [
                ColumnNameValues.TRANSACTION_DATE,
                ColumnNameValues.NAME,
            ],
            ascending=False,
        )
        output_dict = df_general_ledger.reset_index().to_dict(orient="records")

        output_data: list[LedgerRow] = []

        for row in output_dict:
            output_data.append(
                LedgerRow(
                    date=row[ColumnNameValues.TRANSACTION_DATE],
                    broker=row[ColumnNameValues.BROKER],
                    source=row[ColumnNameValues.SOURCE],
                )
            )

        return output_data


from chatterbot import ChatBot
from chatterbot.trainers import ListTrainer
import os
def chatraining():
   bot=ChatBot('andresbot')
   trainer=ListTrainer(bot)

   for files in os.listdir('./andresbot/'):
      data=open('./andresbot/'+files,'r').readlines()
      trainer.train(data)
      trainer.train(data)
      trainer.train(data)

#------------------------------------------------------------
#------------------------------------------------------------
#chat feature
   while True:
      message=input('\t\t\tYou:')
      if message.strip()!='Bye' or 'bye':
         reply=bot.get_response(message)
         print('lopiruz:',reply)
      if message.strip()=='Bye':
         print('lopiruz:Bye')
         break

chatraining()


from django.contrib.auth.decorators import login_required
from django.conf.urls import url, patterns
from .views import *

urlpatterns = patterns('Egresados.apps.home.views',
	url(r'^$', CreateEgresados.as_view(), name = 'crear_egresados'),
	url(r'^message/$', MessageView.as_view(), name = 'message'),
	url(r'^lista/$', login_required(ListEgresados.as_view()), name = 'lista_egresados'),
	url(r'^egresado/(?P<numero_documento>\d+)/$', UpdateEgresados.as_view(), name = 'actualizar_egresado'),
	url(r'^listado/$', ImprimirListado.as_view(), name = 'listado_egresado')
)


#!/usr/bin/env python
# coding: utf-8

# In[76]:

class Table():
    def __init__(self, group):
        self.group = group
        self.bill = []

    def order(self, item_name:str, price:float, quantity:int):
        new_item = {
            'item': item_name,
            'price': price,
            'quantity': quantity
        }

        is_new_item = True
        for bill_item in self.bill:
            if bill_item['item'] == new_item['item']:
                bill_item['quantity'] += new_item['quantity']
                is_new_item = False

        if is_new_item == True:
            self.bill.append(new_item)

    def remove(self, item_name:str, price:float, quantity:int):
        new_item = {
            'item': item_name,
            'price': price,
            'quantity': quantity
        }

        for bill_item in self.bill:
            if bill_item['item'] == new_item['item']:
                bill_item['quantity'] -= new_item['quantity']
                if bill_item['quantity'] <= 0:
                    self.bill.remove(bill_item)

    def get_subtotal(self):
        subtotal = 0
        for bill_item in self.bill:
            subtotal += bill_item['price'] * bill_item['quantity']

        return round(subtotal, 2)

    def get_total(self, service_charge_percent:float = 0.10):
        subtotal = self.get_subtotal()
        service_charge = round(subtotal * service_charge_percent, 2)
        total = round(subtotal + service_charge, 2)

        return {
            'Sub Total': f'£{subtotal}',
            'Service Charge': f'£{service_charge}',
            'Total': f'£{total}'
        }

    def split_bill(self):
        subtotal = self.get_subtotal()
        split_total = round(subtotal / self.group)

        return split_total

# In[77]:

table01 = Table(5)
table01.order("Risotto", 12.50, 2)
print(table01.bill)
table01.order("Burrito", 20.43, 3)
table01.remove("Burrito", 20.43, 2)
print(table01.bill)
print(table01.get_subtotal())
print(table01.get_total(0.15))
print(table01.split_bill())


import difflib
from pprint import pprint as pp

class RegionToDraw(object):
    def __init__(self, line_number, start):
        self.line_number = line_number
        self.start = start

    def get_data(self):
        return (self.line_number, self.start)

    def __str__(self):
        return ""

    def __repr__(self):
        return self.__str__()

class LineToDraw(RegionToDraw):
    def __init__(self, line_number, start):
        super(LineToDraw, self).__init__(line_number, start)

    def get_region(self, view):
        point = view.text_point(self.line_number, 0)
        return view.line(point)

    def __str__(self):
        return "LineToDraw: {line_number}".format(line_number=self.line_number)

class WordToDraw(RegionToDraw):
    def __init__(self, line_number, start, end):
        super(WordToDraw, self).__init__(line_number, start)
        self.end = end

    def get_region(self, view):
        point_start = view.text_point(self.line_number, self.start)
        point_end = view.text_point(self.line_number, self.end)

        #take advantage of sublime's API to highlight a word
        return view.word(point_start)

    def __str__(self):
        return "WordToDraw: {line_number}: ({start}, {end})".format(line_number=self.line_number,start=self.start, end=self.end)

class Diffy(object):
    def parse_diff_list(self, lst):
        #add a sentinal at the end
        lst.append("$3nt1n3L\n")

        #variables
        diff = []
        line_num = -1
        pre_diff_code = ""
        pre_line = ""

        for line in lst:
            line_num += 1
            diff_code = line[0]

            #the content of the original line
            pre_line_content = pre_line[2:]
            line_content = line[2:]

            #detect a change
            if diff_code == '?':
                line_num -= 1
                continue
            elif diff_code == '+': line_num -= 1

            if pre_diff_code == '-' and diff_code == '+':
                if line_content == "" or line_content.isspace():
                    r = LineToDraw(line_num - 1, 0)
                    diff.append(r)
                else:
                    s = difflib.SequenceMatcher(None, pre_line_content, line_content)
                    for tag, i1, i2, j1, j2 in s.get_opcodes():
                        if tag == 'insert':
                            r = WordToDraw(line_num, j1, j2)
                            diff.append(r)
                        elif tag == 'delete' or tag == 'replace':
                            r = WordToDraw(line_num, i1, i2)
                            diff.append(r)
            elif pre_diff_code == '-':
                r = LineToDraw(line_num - 1, 0)
                diff.append(r)

            #tracking
            pre_line = line
            pre_diff_code = diff_code

        return diff

    def calculate_diff(self, text1, text2):
        d = difflib.Differ()
        result1 = list(d.compare(text1, text2))
        diff_1 = self.parse_diff_list(result1)

        result2 = list(d.compare(text2, text1))
        diff_2 = self.parse_diff_list(result2)

        return diff_1, diff_2


##===============================01: Odd or Even===============================
num = int(input("输入一个数字: "))
if (num % 2) == 0:
    print("{0} 是偶数".format(num))
else:
    print("{0} 是奇数".format(num))

##===============================02: Mad Libs===============================
#story = input ("请问需要建造几次模板故事：")
num2 = input ("请输入课程期数：")
classname = input ("请输入课程名称：")
name = input ("请输入姓名：")
background = input ("请输入您的背景(科系或职业)：")
expect = input ("请简述对于本课程得期望(列出几点修完课程想得到的技能/对自己未来的规划)：")
print ("------------------------------------------")
print ("第", num2, "期 - ", classname)
print ("姓名：", name)
print ("学生背景：", background)
print ("==========================================")
print (name, "修习完课程[", classname, "]后，")
print ("结业成果获得：", expect)
print ("Well Done.")

##===============================03: Guess the number===============================
import random
ans3 = random.randint(1,100)
#print (ans3)
min = 1
max = 100
count = 0
while True:
    print ("请猜", min, "~", max, "之间的数字：", end='')
    try:
        num3 = int(input ())
        count += 1
        if num3 == ans3:
            print ("恭喜答对！你猜了", count, "次！",)
            break
        elif num3 < ans3:
            min = num3
            print ("答错！你猜了", count, "次！", end='')
            yn = input("是否要继续猜?(Y/N)：").upper()
            if yn == "Y":
                continue
            else:
                break
        elif num3 > ans3:
            max = num3
            print ("答错！你猜了", count, "次！", end='')
            yn = input("是否要继续猜?(Y/N)：").upper()
            if yn == "Y":
                continue
            else:
                break
    except:
        print ("你输入的并非1~100之间的整数，请重新输入")

##===============================04: Word Count===============================
#### 使用者输入一段文字或读取一档案，程式统计字数。
##输入(Input):我要成为写程式的专家
##输出(Output):你用了 10 个文字述说内心的想法
#### 在特定的文章字串中搜寻输入的特定字，请使用者输入欲搜寻的文字，印出总共有几个。
##输入(Input):天
##输出(Output): 9
    ##* 进阶:计算文章中去除标点符号后的字数，找出文章中出现最多的字与次数

#04-1:
word = input ("请输入想法： ")
print ("你用了%d个文字来形容你的想法"% (len(word)))

#04-2:
s = '''汉皇重色思倾国，御宇多年求不得。
杨家有女初长成，养在深闰人未识。
天生丽质难自弃，一朝选在君王侧。
回眸一笑百媚生，六宫粉黛无颜色。
春寒赐浴华清池，温泉水滑洗凝脂；
侍儿扶起娇无力，始是新承恩泽时。
云鬓花颜金步摇，芙蓉帐暖度春宵；
春宵苦短日高起，从此君王不早朝。
承欢侍宴无闲暇，春从春游夜专夜。
后宫佳丽三千人，三千宠爱在一身。
金屋妆成娇侍夜，玉楼宴罢醉和春。
姊妹弟兄皆列士，可怜光彩生门户。
遂令天下父母心，不重生男重生女。
骊宫高处入青云，仙乐风飘处处闻。
缓歌慢舞凝丝竹，尽日君王看不足。
渔阳鼙鼓动地来，惊破霓裳羽衣曲。
九重城阙烟尘生，千乘万骑西南行。
翠华摇摇行复止，西出都门百余里；
六军不发无奈何？宛转蛾眉马前死。
花钿委地无人收，翠翘金雀玉搔头。
君王掩面救不得，回看血泪相和流。
黄埃散漫风萧索，云栈萦纡登剑阁。
峨嵋山下少人行，旌旗无光日色薄。
蜀江水碧蜀山青，圣主朝朝暮暮情。
行宫见月伤心色，夜雨闻铃肠断声。
天旋地转回龙驭，到此踌躇不能去。
马嵬坡下泥土中，不见玉颜空死处。
君臣相顾尽沾衣，东望都门信马归。
归来池苑皆依旧，太液芙蓉未央柳；
芙蓉如面柳如眉，对此如何不泪垂？
春风桃李花开日，秋雨梧桐叶落时。
西宫南内多秋草，落叶满阶红不扫。
梨园子弟白发新，椒房阿监青娥老。
夕殿萤飞思悄然，孤灯挑尽未成眠。
迟迟钟鼓初长夜，耿耿星河欲曙天。
鸳鸯瓦冷霜华重，翡翠衾寒谁与共？
悠悠生死别经年，魂魄不曾来入梦。
临邛道士鸿都客，能以精诚致魂魄；
为感君王辗转思，遂教方士殷勤觅。
排空驭气奔如电，升天入地求之遍；
上穷碧落下黄泉，两处茫茫皆不见。
忽闻海上有仙山，山在虚无缥缈间。
楼阁玲珑五云起，其中绰约多仙子。
中有一人字太真，雪肤花貌参差是。
金阙西厢叩玉扃，转教小玉报双成。
闻道汉家天子使，九华帐里梦魂惊；
揽衣推枕起徘徊，珠箔银屏迤逦开。
云鬓半偏新睡觉，花冠不整下堂来。
风吹仙袂飘飘举，犹似霓裳羽衣舞。
玉容寂寞泪阑干，梨花一枝春带雨。
含情凝睇谢君王，一别音容两渺茫。
昭阳殿里恩爱绝，蓬莱宫中日月长。
回头下望人寰处，不见长安见尘雾。
唯将旧物表深情，钿合金钗寄将去。
钗留一股合一扇，钗擘黄金合分钿。
但教心似金钿坚，天上人间会相见。
临别殷勤重寄词，词中有誓两心知，
七月七日长生殿，夜半无人私语时：“
在天愿作比翼鸟，在地愿为连理枝。”
天长地久有时尽，此恨绵绵无绝期。
'''
word4 = input ("请输入欲搜寻的文字来计算出现次数：")
count4=s.count(word4)
print (word4,"的出现次数为", count4)

##===============================05: Email slicer===============================
### 05 - Email 域名判断器（Email slicer）
#### 请用户输入 Email 地址，然后判断它是自定义域名还是热门域名。
## > 题目：

## 输入(Input):shelly200318@hotmail.com.tw

## 输出(Output):Your username is 'shelly200318' and your domain name is 'hotmail.com.tw'

    ## * 进阶：把常用的信箱存成字典，加入判断是否为
    ## >输入(Input):mary.jane@gmail.com

    ## 输出(Output):这是注册在 Google 之下的 Email 地址

    ## 输入(Input):matt.pan@myfantasy.com

    ## 输出(Output):这是在 myfantasy 之下自定义域

email = input ("please enter your email: ").strip()
usr = email [0:email.index("@")]
domain = email [email.index("@")+1: ]
print ("your username is '{}' and your doamin name is '{}'.".format(usr,domain))

##===============================06: Pass List===============================
### 06 - 及格名单（Pass list）
#### 请使用集合功能来完成各科级名单的判断
##米花市帝丹小学一年级B班正举办期中考试
##数学及格的有：柯南、灰原、步美、美环、光彦
##英文及格的有：柯南、灰原、丸尾、野口、步美
##以上已列出全班所有人
##请分别列出

##数学及格但英文不及格的同学名单

##数学不及格但英文及格的同学名单

##两者皆及格名单

##* Hint:差集(减法)、交集

mathpass = {"柯南", "灰原", "步美", "美环", "光彦"}
engpass = {"柯南", "灰原", "丸尾", "野口", "步美"}
print ("班上所有人:", mathpass | engpass)
print ("数学及格但英文不及格的同学: ", mathpass - engpass)
print ("数学不及格但英文及格的同学: ", engpass - mathpass)
print ("两者皆及格的同学: ", mathpass & engpass)

##===============================07: Search File===============================
### 07 - 查询路径下所有档案
#### 请使用者输入路径，自动抓取路径下所有档案名称
##输入(Input):data\testfile 或 D:\code\ML_202105\data\testfile

##输出(Output):
    ##* 进阶: 把file的学号抓出来，另存成一个新的csv档

import os

# 指定要查询的路径
yourPath = input("enter path: ")
# 列出指定路径底下所有档案(包含资料夹)
allFileList = os.listdir(yourPath)
# print (allFileList)

# 逐一查询档案清单
for file in allFileList:
    if os.path.isdir(os.path.join(yourPath,file)):
        print("I'm a directory: " + file)
    #   使用isfile判断是否为档案
    elif os.path.isfile(os.path.join(yourPath,file)):
        print("I'm a File: " + file)

        #file = file.split('_')
        #print(file[1])

##===============================08: Shutil===============================
##在目前所在的目录下建立一files资料夹
##令使用者输入一数字N，并在files资料夹中建立f1, f2… fN等N个资料夹后列出files的资料夹内容
##将files资料夹里的f1资料夹重新命名成folder1后再列出files的资料夹内容
##移除files资料夹中的folder1后再列出files的资料夹内容
##最后移除files资料夹
## ※须先退出files资料夹(os.chdir(../)) ![image.png](attachment:image.png)
import os
import shutil

#先判断files存不存在
if os.path.exists('files'):
    shutil.rmtree('files')

os.mkdir('files')

n = int(input("please enter numbers of files: "))

os.chdir('files')
for i in range (1,n+1):
    os.mkdir('f'+str(i))
print(sorted(os.listdir()))
a = input ("Enter")  #设停损点等使用者按enter后才会进行之后的程式码，debug时可用

os.rename ('f1','folder1')
print (sorted(os.listdir()))
a = input ("Enter")

os.rmdir('folder1')
print (sorted(os.listdir()))
a = input ("Enter")

os.chdir('../')  #同层路径: ./ 可省略不写；上一层路径: ../
shutil.rmtree('files')

##===============================09: palindrome===============================
#### 请使用者输入单字，判断它是否为回文，也就是该单字前后对称，例如 madam，从前读到后或是从后读到前的顺序都是 madam。
##输入(Input): 雨 滋 春 树 碧 连 天  天 连 碧 树 春 滋 雨

##输出(Output):The text you have entered is a palindrome!

##输入(Input): 资工训练班

##输出(Output):The text you have entered is not a palindrome.

#请使用者输入一串字串，先转换字串为统一小写
def convertInputString():
    rawInput = input("\nPlease enter a word, phrase, or a sentence \nto check if it is a palindrome: ")
    rawString = rawInput.lower()
    rawList = list(rawString)
    return rawList

#去除相关标点符号
def stripAnalphabetics(dirtyList):
    analphabeticList = [" ", "-", ".", ",", ":", ";", "!", "?", "'", "\""]
    for character in analphabeticList:
        if character in dirtyList:
            dirtyList.remove(character)   #是list时才能用replace，这里是string用remove
            return stripAnalphabetics(dirtyList)  #自己呼叫自己
    return dirtyList

def runPalindromeCheck(straightList):
    reversedList = straightList[::-1] #相当于[0::-1], 从[0]的位置到著看? [1,2,3,4]  --> [4,3,2,1] 若[2::-1]-->[3,2,1]
    if reversedList == straightList:
        return "The text you have entered is a palindrome!"
    else:
        return "The text you have entered is not a palindrome."

#建立主程式
def main():
    print("\nPalindrome checker")
    originalList = convertInputString()
    originalList = stripAnalphabetics(originalList)
    PalindromeCheck = runPalindromeCheck(originalList)
    print (PalindromeCheck)

#呼叫主程式
main()

##===============================10: 总成绩计算===============================
##请读取 `data/english_list.csv`与`data/math_list.csv`档案(`utf-8`)后，将每位同学的英文与数学成绩加总起来，并将档案写入至 `./Score.csv`中，编码成`utf-8`

##最后打印出每位学生姓名与加总后的分数

fin_E = open('data/english_list.csv',"r",encoding='UTF-8')
fin_M = open('data/math_list.csv',"r",encoding='UTF-8')
lisE=[]
lisM=[]
name=[]
for line in fin_E.readlines():
    #print (line,end='')
    line = line.strip().split(",")
    #print (line)
    lisE.append(line[1])
    name.append(line[0])

for line in fin_M.readlines():
    #print (line,end='')
    line = line.strip().split(",")
    #print (line)
    lisM.append(line[1])

score=[]
fout = open("Score.csv","w")
line=''
for i in range(1,len(lisE)):
    score.append(int(lisE[i])+int(lisM[i]))
    list1 = [name[i],str(score[i-1]),"\n"]
    print(name[i],str(score[i-1]))
    line = ",".join(list1)
    fout.write(line)
fin_E.close()
fin_M.close()
fout.close()
# '''
# line=''
# fout = open("Score.csv","r")
# for i in (len(name)):
#     print()
# '''


def initialise_frequency_array():
    array = []
    return array

def simulate_die_throwing(array):
    import random
    for count in range(6):
        number = random.randint(1,6)
        array.append(number)
    return array

def display_result_array(array,number):
    count = 0
    count1 = 0
    print("{0:^2} {1:^2}".format("Score","Frequency"))
    for each in array:
        print("{0:>3} {1:>7}".format(count+1,array[count1]))
        count = count+1
        count1=count1+1

def Frequency_of_die_score():
    array = initialise_frequency_array()
    number = simulate_die_throwing(array)
    display_result_array(array,number)

Frequency_of_die_score()


from itertools import *

def solution(S):
    li = []
    for x,y in combinations(range(len(S)),r=2):
        #print(S[x:y])
        li.append(S[x:y])

    for i in li:
        print(f'{i}        : {li.count(i)} times')
    #return li

#print(count_substring('ABCDCDC','CDC'))
print(solution('abaaba'))


##
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
##

"""
Run test:
>> mpirun -n 2 python -m pytest --with-mpi -q python/pycylon/test/test_cylon_table_conversion.py
"""

import os
import pytest
from pycylon.io import read_csv
from pycylon import Table
from pycylon.net import MPIConfig
from pycylon import CylonContext
from pycylon.io import CSVReadOptions
import pandas as pd
import numpy as np

@pytest.mark.mpi
def test_conversion_check():
    mpi_config = MPIConfig()
    ctx: CylonContext = CylonContext(config=mpi_config, distributed=True)

    rank, size = ctx.get_rank(), ctx.get_world_size()
    assert 0 <= rank < size and size > 0

    assert size == 2

    table1_path = f'data/input/user_usage_tm_{rank + 1}.csv'
    table2_path = f'data/input/user_device_tm_{rank + 1}.csv'

    assert os.path.exists(table1_path)
    assert os.path.exists(table2_path)

    csv_read_options = CSVReadOptions().use_threads(True).block_size(1 << 30)

    tb1: Table = read_csv(ctx, table1_path, csv_read_options)

    tb2: Table = read_csv(ctx, table2_path, csv_read_options)

    tb3: Table = tb1.distributed_join(table=tb2, join_type='inner', algorithm='sort', left_on=[3],
                                      right_on=[0])

    # pdf: pd.DataFrame = tb3.to_pandas()
    npy: np.ndarray = tb3.to_numpy(order='C')

    # Cylon table rows must be equal to the rows of pandas dataframe extracted from the table
    # assert tb3.rows == pdf.shape[0]
    # Cylon table columns must be equal to the columns of pandas dataframe extracted from the table
    # assert tb3.columns == pdf.shape[1]
    # Cylon table rows must be equal to the rows of numpy ndarray extracted from the table
    assert tb3.row_count == npy.shape[0]
    # Cylon table columns must be equal to the columns of numpy ndarray extracted from the table
    assert tb3.column_count == npy.shape[1]

    print(f"Rank[{ctx.get_rank()}]: Table.Rows={tb3.row_count}, Table.Columns={tb3.column_count}, "
          f"Numpy Array Shape = {npy.shape}")

    print(f"Array Config Rank[{ctx.get_rank()}], {npy.flags} {npy.dtype}")

    # Note: Not needed when using PyTest with MPI
    # ctx.finalize()


from typing import Any, Text, Dict, List

from rasa_sdk import Action, Tracker
from rasa_sdk.executor import CollectingDispatcher
from rasa_sdk.events import SlotSet, FollowupAction
from db_api.product import search_products, get_product_by_id
from db_api.product_variant import search_product_variants, get_product_variant_by_id
from db_api.schema import Product

def get_color_product(product_id):
    variants = search_product_variants(product_id)
    colors = []
    for variant in variants:
        if variant.color and variant.color not in colors:
            colors.append(variant.color)
    return colors

class ActionRequestColor(Action):
    def name(self) -> Text:
        return "action_request_color"

    async def run(self, dispatcher: CollectingDispatcher, tracker: Tracker,
                  domain: Dict[Text, Any]) -> List[Dict[Text, Any]]:
        event = []
        product = None
        product_other = False

        pre_product_id = tracker.get_slot("product_id")
        if pre_product_id:
            pre_product = get_product_by_id(pre_product_id)
        else:
            pre_product = None

        object_types = list(tracker.get_latest_entity_values(entity_type="object_type"))

        if len(object_types) == 0:
            if pre_product:
                product = pre_product
            else:
                dispatcher.utter_message(text="Bạn muốn xem màu sản phẩm nào ạ")
        else:
            # Nếu có object type kèm theo, kiểm tra xem có phải đang nhắc tới sản phẩm trước đó hay ko
            object_type_level = Product.get_level_of_object_type(object_types[0])

            if object_type_level > 0:
                # Nếu có nhắc tới, thì trả về màu sp trước đó, còn nếu là object type chung chung mà không
                # nhắc tới sp trước đó thì chuyển sang action request product
                if pre_product and pre_product.check_is_general_of_product(object_types[0]):
                    product = pre_product
                else:
                    dispatcher.utter_message(text="Có phải bạn đang tìm kiếm sản phẩm không ạ")
                    event.append(FollowupAction("action_request_product"))
                    return event
            else:
                # Nếu là một sp khác thì trả về sản phẩm tương ứng
                products = search_products(product_type=object_types[0])
                if products:
                    product = products[0]
                    event.append(SlotSet("object_type", object_types))
                    event.append(SlotSet("product_id", product.id))
                    product_other = True
                else:
                    dispatcher.utter_message(text="Bạn muốn hỏi màu sản phẩm nào ạ")
                    return event

        if product is None:
            dispatcher.utter_message(text="Bạn muốn hỏi màu sản phẩm nào ạ")
            return event

        colors = get_color_product(product.id)
        if len(colors) == 0:
            dispatcher.utter_message(response="utter_fall_back_1")
        else:
            color_text = ", ".join(colors).strip(',')
            text = f"Dạ, Sản phâm {product.title} bên mình đang còn màu: {color_text} ạ"
            dispatcher.utter_message(text)
            if product_other:
                variant_dict = {}
                for color in colors:
                    variants = search_product_variants(product_id=product.id, color=color)
                    if variants:
                        variant_dict[color] = variants[0]
                elements = []
                for color, variant in variant_dict.items():
                    element = variant.to_messenger_element()
                    elements.append(element)

                if elements:
                    message = {
                        "attachment": {
                            "type": "template",
                            "payload": {
                                "template_type": "generic",
                                "elements": elements
                            }
                        }
                    }
                    dispatcher.utter_message(json_message=message)
        return event


#!/usr/bin/env python
# coding: utf-8

# # Modelo - Pipeline classificação
# - Marketing campaign

# In[1]:

from platform import python_version

print('Versão python neste Jupyter Notebook:', python_version())

# In[2]:

import sklearn
import matplotlib
import pandas as pd
import seaborn as sns
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
import matplotlib as m
import warnings

import missingno as msno
import plotly.graph_objects as go
import plotly.express as px
from yellowbrick.cluster import KElbowVisualizer

warnings.filterwarnings("ignore")

# In[3]:

get_ipython().run_line_magic('reload_ext', 'watermark')

get_ipython().run_line_magic('watermark', '-a "Rafael Gallo" --iversions')

# In[5]:

# Configuração para os gráficos largura e layout dos graficos

plt.rcParams["figure.figsize"] = (18, 5)

plt.style.use('fivethirtyeight')
pd.set_option('display.expand_frame_repr', False)
pd.set_option('display.max_columns', 500)
pd.set_option('display.width', 1000)

m.rcParams['axes.labelsize'] = 25
m.rcParams['xtick.labelsize'] = 25
m.rcParams['ytick.labelsize'] = 25
m.rcParams['text.color'] = 'k'

# # Base dados

# In[6]:

# Carregando base dados
data = pd.read_csv("marketing_campaign.csv", sep='\t')
data

# In[7]:

# Visualizando os 5 primeiros dados
data.head()

# In[8]:

# Visualizando os 5 cinco últimos dados
data.tail()

# In[9]:

# Visualizando os infos dados
data.info()

# In[10]:

# Tipos de dados
data.dtypes

# In[11]:

# Visualizando linhas colunas
data.shape

# In[12]:

# Total de colunas e linhas - data_train

print("Números de linhas: {}" .format(data.shape[0]))
print("Números de colunas: {}" .format(data.shape[1]))

# In[13]:

# Exibindo valores ausentes e valores únicos

print("\nMissing values :  ", data.isnull().sum().values.sum())
print("\nUnique values :  \n",data.nunique())

# In[14]:

# Verificando dados duplicados
data.duplicated()

# In[15]:

# Visualizando dados nulos
data.isnull().sum()

# # Estatística descritiva

# In[16]:

# Exibindo estatísticas descritivas visualizar alguns detalhes estatísticos básicos como percentil, média, padrão, etc.
# De um quadro de dados ou uma série de valores numéricos.

data.describe().T

# In[17]:

# Matriz correlação de pares de colunas, excluindo NA / valores nulos.

corr = data.corr()
corr

# In[18]:

plt.figure(figsize=(18.2, 8))

ax = sns.distplot(data['Year_Birth']);
plt.title("Distribuição normal", fontsize=20)
plt.axvline(data['Year_Birth'].mean(), color='k')
plt.axvline(data['Year_Birth'].median(), color='r')
plt.axvline(data['Year_Birth'].mode()[0], color='g');

# In[19]:

# Verificando os dados no boxplot valor total verificando possíveis outliers
plt.figure(figsize=(18.2, 8))

sns.boxplot(x="Income", y="Education", data = data)
plt.title("Educação dos consumidores")
plt.xlabel("Total")
plt.ylabel("Educação")

# In[20]:

plt.figure(figsize=(14, 10))
sns.heatmap(data.corr(), cmap="Blues")
plt.title("Correlations", size=16)
plt.show()

# In[21]:

# Gráfico da matriz de correlação

plt.figure(figsize=(35.5,30))
ax = sns.heatmap(corr, annot=True, cmap='YlGnBu');
plt.title("Matriz de correlação")

# In[22]:

plt.figure(figsize=(30.5,20))

mask = np.triu(np.ones_like(corr, dtype = bool))
sns.heatmap(corr, mask = mask, annot = True, fmt = '.2g', linewidths = 1)
plt.show()

# # Análise dados

# In[23]:

plt.figure(figsize=(20, 10))

plt.title("Educação dos consumidores")
sns.countplot(data["Education"])
plt.xlabel("Educação")
plt.ylabel("Total")

# In[24]:

plt.figure(figsize=(20, 10))

sns.histplot(data["Year_Birth"])
plt.title("Ano de nascimento dos consumidores")
plt.xlabel("Ano")
plt.ylabel("Idades")

# In[25]:

plt.figure(figsize=(20, 10))

sns.histplot(data["Income"])
plt.title("Renda dos consumidores")
plt.xlabel("Total da renda")
plt.ylabel("Total")

# In[26]:

# Gráfico condições de vida por valor do imóvel
plt.figure(figsize=(35.5, 15))

plt.title("Formações dos consumidores")
ax = sns.barplot(x="Education", y="Income", data = data, hue="Marital_Status")
plt.ylabel("Valor")
plt.xlabel("Formações")

# In[27]:

# Região das vendas dos imóveis pela área
plt.figure(figsize=(18.2, 8))

plt.title("Renda dos consumidores")
ax = sns.scatterplot(x="MntWines", y="Income", data = data, hue = "Marital_Status")
plt.xlabel("Renda ")
plt.ylabel("Valor")

# In[28]:

plt.figure(figsize=(20, 10))

# Graduation, PHD, master, basic, 2n cycle

plt.pie(data.groupby("Education")['Education'].count(), labels=["Graduation", "PHD", "master", "basic", "2n_cycle"], autopct = "%1.1f%%");
plt.title("Perfil de escolariedade dos consumidores")
plt.xlabel("Total consumidores")
plt.ylabel("Total")

# # Análise de dados = Univariada

# In[29]:

data.hist(bins = 40, figsize=(20.2, 20))
plt.show()

# In[30]:

fig1 , axes = plt.subplots(nrows=3,ncols=3 , figsize = (20,20))

sns.distplot(data["NumWebVisitsMonth"] , ax=axes[0, 0] )
sns.distplot(data["AcceptedCmp1"] ,  ax=axes[0, 1])
sns.distplot(data["AcceptedCmp2"] , ax=axes[0, 2])
sns.distplot(data["AcceptedCmp3"], ax=axes[1, 0])
sns.distplot(data["AcceptedCmp4"] , ax=axes[1, 1])
sns.distplot(data["AcceptedCmp5"] , ax=axes[1, 2])
sns.distplot(data["Recency"] , ax=axes[2, 0])
sns.distplot(data["MntWines"], ax=axes[2, 1])
sns.countplot(data["Education"], ax=axes[2, 2])

plt.show()

# In[31]:

# Nós imputamos os valores omissos na coluna "Renda" com a mediana dessa coluna em particular

data["Income"].fillna(data["Income"].median(), inplace=True)
data

# # Feature Engineering

# In[32]:

data["Age"] = 2022 - data["Year_Birth"]

data["Money_Spent"] = (data["MntWines"] + data["MntFruits"] + data["MntMeatProducts"] + data["MntFishProducts"] + data["MntSweetProducts"] + data["MntGoldProds"])
data["PurchaseNum"] = data["NumWebPurchases"] + data["NumCatalogPurchases"] + data["NumStorePurchases"]
data["Children"] = data["Kidhome"] + data["Teenhome"]
data["Marital_Status"] = data["Marital_Status"].replace({"Married": "Together", "Alone": "Single", "Absurd": "Single", "Divorced": "Single", "Widow": "Single", "Divorced": "Single", "YOLO": "Single"})

# exluindo coluna
data.drop(["Education", "Marital_Status", "Dt_Customer"], axis=1, inplace=True)
data

# # Treino e Teste
#
# - Treino e teste da base de dados da coluna price e idade

# In[47]:

x = data.drop('Response',axis=1).values
y = data['Response'].values

# In[48]:

# Total de linhas e colunas dados variável x
x.shape

# In[49]:

# Total de linhas e colunas dados variável y
y.shape

# # Escalonamento
#
# - Escalonamento uma forma de contornar os problemas relacionados à escala, mantendo a informação estatística dos dados. O procedimento consiste em realizar uma transformação sobre o conjunto original dos dados de modo que cada variável apresente média zero e variância unitária.

# In[50]:

# Escalonamento dos dados

# Importando biblioteca a biblioteca
from sklearn.preprocessing import StandardScaler

# Criando o escalonamento
model_scaler = StandardScaler()

# Treinamneto do escalonamento
model_scaler_fit = model_scaler.fit_transform(x)

# Visualizando linhas e colunas do escalonamento
model_scaler_fit.shape

# In[51]:

# Importação da biblioteca sklearn para treino e teste do modelo

from sklearn.model_selection import train_test_split

x_train, x_test, y_train, y_test = train_test_split(x, # Variável x
                                                    y, # Variável y
                                                    test_size=0.2, # Divivindo os dados em 20% para treino e 80% para teste
                                                    random_state = 0) # Random state igual a zero

# In[42]:

# Total de linhas e colunas e linhas dos dados de treino x
x_train.shape

# In[43]:

# Total de linhas dos dados de treino y
y_train.shape

# In[44]:

# Total de linhas e colunas dos dados de treino x teste
x_test.shape

# In[45]:

# Total de linhas e colunas dos dados de treino y teste
y_test.shape

# # Model pipeline

# In[52]:

# Modelo pipeline

from sklearn.feature_selection import VarianceThreshold
from sklearn.pipeline import Pipeline
from sklearn.neighbors import KNeighborsClassifier

data_pipeline = Pipeline([
    ("scaler", StandardScaler()), # Scaler : Para pré-processamento de dados, ou seja, transforme os dados em média zero e variância de unidade usando o StandardScaler ().
    ("selector", VarianceThreshold()), # Seletor de recurso : Use VarianceThreshold () para descartar recursos cuja variação seja menor que um determinado limite definido.
    ("classifier", KNeighborsClassifier()) # Classificador : KNeighborsClassifier (), que implementa o classificador de k-vizinho mais próximo e seleciona a classe dos k pontos principais, que estão mais próximos do exemplo de teste.
])

data_pipeline_fit = data_pipeline.fit(x_train, y_train)
data_pipeline_score = data_pipeline.score(x_train, y_train)

print('Treinamento base treino - Pipeline: ' + str(data_pipeline.score(x_train,y_train)))
print('Treinamento base teste - Pipeline: ' + str(data_pipeline.score(x_test,y_test)))

# In[54]:

# Previsão do pipeline do modelo
data_pipeline_pred_1 = data_pipeline.predict(x_test)

# In[55]:

# Matrix confusion ou Matriz de Confusão
from sklearn.metrics import confusion_matrix
from mlxtend.plotting import plot_confusion_matrix

matrix_1 = confusion_matrix(y_test, data_pipeline_pred_1)
plot_confusion_matrix(matrix_1, show_normed=True, colorbar=False, class_names=['Acesso', 'Não acesso'])

# In[56]:

# Accuracy do pipeline
from sklearn.metrics import accuracy_score

accuracy_pipeline_1 = accuracy_score(y_test, data_pipeline_pred_1)
print("Accuracy KNN - Pipeline: %.2f" % (accuracy_pipeline_1 * 100))

# In[57]:

# Curva ROC do modelo
from sklearn.metrics import roc_curve, roc_auc_score

roc = data_pipeline.predict_proba(x_test)[:,1]
tfp, tvp, limite = roc_curve(y_test, roc)
print('roc_auc', roc_auc_score(y_test, roc))

plt.subplots(1, figsize=(5,5))
plt.title('Curva ROC')
plt.plot(tfp,tvp)
plt.xlabel('Especifidade')
plt.ylabel('Sensibilidade')
plt.plot([0, 1], ls="--", c = 'red')
plt.plot([0, 0], [1, 0], ls="--", c = 'green'), plt.plot([1, 1], ls="--", c = 'green')
plt.show()

# In[58]:

# Classification report
from sklearn.metrics import classification_report

classification = classification_report(y_test, data_pipeline_pred_1)
print("Modelo - Pipeline 1")
print()
print(classification)

# In[59]:

# Métricas do modelo
from sklearn.metrics import precision_score
from sklearn.metrics import recall_score
from sklearn.metrics import recall_score
from sklearn.metrics import f1_score

precision = precision_score(y_test, data_pipeline_pred_1)
Recall = recall_score(y_test, data_pipeline_pred_1)
Accuracy = accuracy_score(y_test, data_pipeline_pred_1)
F1_Score = f1_score(y_test, data_pipeline_pred_1)

precisao = pd.DataFrame({

    "Metricas" : ["precision",
                 "Recall",
                  "Accuracy",
                  "F1_Score"],

    "Resultado": [precision,
                Recall,
                Accuracy,
                F1_Score]})

precisao.sort_values(by = "Resultado", ascending = False)

# # Pipeline 2
# **Pipeline 2 - Decision Tree Classifier**

# In[60]:

# Pipeline decision Tree Classifier
from sklearn.tree import DecisionTreeClassifier

data_pipeline_2 = Pipeline([
    ("scaler", StandardScaler()), # Scaler : Para pré-processamento de dados, ou seja, transforme os dados em média zero e variância de unidade usando o StandardScaler ().
    ("selector", VarianceThreshold()), # Seletor de recurso : Use VarianceThreshold () para descartar recursos cuja variação seja menor que um determinado limite definido.
    ("classifier", DecisionTreeClassifier(max_depth=4, random_state=0)) # Classificador : DecisionTreeClassifier (), que implementa o classificador de árvore decisão Árvores de decisão são métodos de classificação que podem extrair regras simples sobre os recursos de dados que são inferidos do conjunto de dados de entrada
])

data_pipeline2_fit = data_pipeline_2.fit(x_train, y_train)
data_pipeline2_score = data_pipeline_2.score(x_train, y_train)

print('Treinamento base treino - Pipeline: ' + str(data_pipeline_2.score(x_train,y_train)))
print('Treinamento base teste - Pipeline: ' + str(data_pipeline_2.score(x_test,y_test)))

# In[61]:

# Previsão do pipeline
data_pipeline_pred_2 = data_pipeline_2.predict(x_test)
data_pipeline_pred_2

# In[62]:

# Accuracy do pipeline
accuracy_pipeline_2 = accuracy_score(y_test, data_pipeline_pred_2)
print("Accuracy Pipeline 2: %.2f" % (accuracy_pipeline_2 * 100))

# In[63]:

# A matrix confusion do modelo
matrix_confusion_1 = confusion_matrix(y_test, data_pipeline_pred_2)
plot_confusion_matrix(matrix_confusion_1, show_normed=True, colorbar=False, class_names=['Acesso', 'Não acesso'])

# In[64]:

# Curva ROC do modelo
roc = data_pipeline_2.predict_proba(x_test)[:,1]
tfp, tvp, limite = roc_curve(y_test, roc)
print('roc_auc', roc_auc_score(y_test, roc))

plt.subplots(1, figsize=(5,5))
plt.title('Curva ROC')
plt.plot(tfp,tvp)
plt.xlabel('Especifidade')
plt.ylabel('Sensibilidade')
plt.plot([0, 1], ls="--", c = 'red')
plt.plot([0, 0], [1, 0], ls="--", c = 'green'), plt.plot([1, 1], ls="--", c = 'green')
plt.show()

# In[65]:

# Classification_report
classification = classification_report(y_test, data_pipeline_pred_2)
print("Modelo Pipeline 2")
print()
print(classification)

# In[67]:

# Méricas do modelo
precision = precision_score(y_test, data_pipeline_pred_2)
Recall = recall_score(y_test, data_pipeline_pred_2)
Accuracy = accuracy_score(y_test, data_pipeline_pred_2)
F1_Score = f1_score(y_test, data_pipeline_pred_2)

precisao = pd.DataFrame({

    "Metricas" : ["precision",
                 "Recall",
                  "Accuracy",
                  "F1_Score"],

    "Resultado": [precision,
                Recall,
                Accuracy,
                F1_Score]})

precisao.sort_values(by = "Resultado", ascending = False)

# **Pipeline 3 - Naive bayes**

# In[68]:

# Modelo naive bayes

# Importando biblioteca ML naive bayes
from sklearn.naive_bayes import GaussianNB

# Pipeline Naive bayes
data_pipeline_3 = Pipeline([
    ("scaler", StandardScaler()),
    ("selector", VarianceThreshold()),
    ("classifier", GaussianNB())])

data_pipeline3_fit = data_pipeline_3.fit(x_train, y_train)
data_pipeline3_score = data_pipeline_3.score(x_train, y_train)

print('Treinamento base treino - Pipeline: ' + str(data_pipeline_3.score(x_train,y_train)))
print('Treinamento base teste - Pipeline: ' + str(data_pipeline_3.score(x_test,y_test)))

# In[69]:

# Previsão do modelo - Naive bayes

# Previsão do pipeline
data_pipeline_pred_3 = data_pipeline_3.predict(x_test)
data_pipeline_pred_3

# In[70]:

# Accuracy do pipeline
accuracy_pipeline_3 = accuracy_score(y_test, data_pipeline_pred_3)
print("Accuracy pipeline 3: %.2f" % (accuracy_pipeline_3 * 100))

# In[71]:

# A matrix confusion pipeline
matrix_confusion_4 = confusion_matrix(y_test, data_pipeline_pred_3)
plot_confusion_matrix(matrix_confusion_4, show_normed=True, colorbar=False, class_names=['Acesso', 'Não acesso'])

# In[72]:

# Curva ROC do pipeline
roc = data_pipeline_3.predict_proba(x_test)[:,1]
tfp, tvp, limite = roc_curve(y_test, roc)
print('roc_auc', roc_auc_score(y_test, roc))

plt.subplots(1, figsize=(5,5))
plt.title('Curva ROC')
plt.plot(tfp,tvp)
plt.xlabel('Especifidade')
plt.ylabel('Sensibilidade')
plt.plot([0, 1], ls="--", c = 'red')
plt.plot([0, 0], [1, 0], ls="--", c = 'green'), plt.plot([1, 1], ls="--", c = 'green')
plt.show()

# In[73]:

# Classification report do modelo
class_report = classification_report(y_test, data_pipeline_pred_3)
print("Modelo 03 - Pipeline")
print("\n")
print(class_report)

# In[74]:

# Metricas do pipeline
precision = precision_score(y_test, data_pipeline_pred_3)
Recall = recall_score(y_test, data_pipeline_pred_3)
Accuracy = accuracy_score(y_test, data_pipeline_pred_3)
F1_Score = f1_score(y_test, data_pipeline_pred_3)

precisao = pd.DataFrame({

    "Metricas" : ["precision",
                 "Recall",
                  "Accuracy",
                  "F1_Score"],

    "Resultado": [precision,
                Recall,
                Accuracy,
                F1_Score]})

precisao.sort_values(by = "Resultado", ascending = False)

# In[75]:

# Resultados - Modelos machine learning

modelos = pd.DataFrame({

    "Models" :["Pipeline 1: K-NN",
               "Pipeline 2: Decision tree",
               "Pipeline 3: Naive bayes"],

    "Acurácia" :[accuracy_pipeline_1,
                      accuracy_pipeline_2,
                      accuracy_pipeline_3]})

modelos_2 = modelos.sort_values(by = "Acurácia", ascending = False)
modelos_2.to_csv("modelos_2.csv")
modelos_2

# In[76]:

# Salvando pipeline Machine learning

import pickle

with open('data_pipeline_pred_1.pkl', 'wb') as file:
    pickle.dump(data_pipeline_pred_1, file)

with open('data_pipeline_pred_2.pkl', 'wb') as file:
    pickle.dump(data_pipeline_pred_2, file)

with open('data_pipeline_pred_3.pkl', 'wb') as file:
    pickle.dump(data_pipeline_pred_3, file)

Jupyter Notebook/Customer Personality Analysis/SRC/pipeline_model.py


#!/usr/bin/env python

"""
crawl thread function
"""

import os
import time
import logging
import threading

from logger import Logger
from webpage_save import Saver
from webpage_parse import Parser
from url_table import UrlTable

SPIDER_ROOT = os.path.join(os.path.dirname(__file__), '.')

lock = threading.Lock()

crawled_url = UrlTable()

class CrawlThread(threading.Thread):
    """
    based on threading.Thread
    """

    def __init__(self, config, queue):
        """
        constructor
        """
        threading.Thread.__init__(self)
        self.config = config
        self.queue = queue
        self.crawl_timeout = int(config['crawl_timeout'])
        self.crawl_interval = int(config['crawl_interval'])

        Logger.config(
            log_file=os.path.join(SPIDER_ROOT, 'log/crawl_thread.log'),
            use_stdout=True,
            log_level=logging.DEBUG)
        self.logger = Logger.get_logger(tag="CrawlThead")
        self.logger.info('Init logger')

    def run(self):
        """
        threading.Thread api run
        @parameter url, crawled_url, parent_depth
        """
        while not self.queue.empty():
            # get queue payload
            payload = self.queue.get()
            url = payload[0]
            parent_depth = payload[1]
            self.logger.debug("working with queue: %s, and with %s" % (payload, self.name))

            # page crawl max_depth check
            link_depth = parent_depth + 1
            if link_depth > int(self.config['max_depth']):
                self.logger.error("Touch the max depth: %s when crawled url %s" %
                                  (self.config['max_depth'], url))

            global crawled_url
            url_table = crawled_url.get()

            # check crawled_url
            # 多线程中的数据互斥访问, 使用threading.Lock()
            if lock.acquire():
                if url in url_table:
                    self.logger.error("This url have been crawled : %s" % url)

                # Parse url
                parser = Parser(self.crawl_timeout)
                a_elements = parser.parse(url, self.config['target_url'])

                url_dict = {}
                href = []
                if a_elements:
                    for link in a_elements:
                        self.queue.put([link, link_depth])
                        href.append(link)
                    url_dict[url] = href
                    page_save = Saver(self.config['output_directory'])
                    page_save.save(url_dict)
                    self.logger.debug("saved crawled data:%s" % url_dict)

                self.queue.task_done()

                crawled_url.set(url)
                self.logger.debug("updated crawled_url: %s" % crawled_url.get())
                lock.release()

            time.sleep(self.crawl_interval)
        self.queue.join()


import uuid

import dash_auth
import pandas as pd
from dash import dash, html, dcc
import dash_bootstrap_components as dbc
from collections import defaultdict
from dash_extensions.enrich import Output, DashProxy, Input, MultiplexerTransform

import db
import job

app = DashProxy(external_stylesheets=[dbc.themes.SOLAR, dbc.icons.BOOTSTRAP], transforms=[MultiplexerTransform()])

VALID_USERNAME_PASSWORD_PAIRS = {
    'hello': 'world'
}

# globals
df_full = pd.DataFrame()
df_preprocessed = pd.DataFrame()
df_feature_extraction = pd.DataFrame()
df_feature_selection = pd.DataFrame()
run_jobs = pd.DataFrame(columns=["algorithm", "config", "best_score", "time"])
connection = db.connection
current_job = job.Job(datasets=[], preprocessing_steps=[], feature_extraction_method='',
                      feature_selection_percent=0)

# from sklearn import datasets
# df_feature_selection = datasets.load_iris()
# df_feature_selection['category'] = [1 for _ in range df_feature_selection.sh]
df1 = pd.read_csv('./datasets/Tweets1.csv')
df2 = pd.read_csv('./datasets/Reddit_Data.csv')
df3 = pd.read_csv('./datasets/apple-twitter-sentiment-texts.csv')
df3 = df3[['clean_text', 'category']]
df1.dropna(axis=0, inplace=True)
df2.dropna(axis=0, inplace=True)
df3.dropna(axis=0, inplace=True)

auth = dash_auth.BasicAuth(
    app,
    VALID_USERNAME_PASSWORD_PAIRS
)

def render_alert(message: str, link: str, color: str, url: str):
    return dbc.Alert(
        [
            html.I(className="bi bi-x-octagon-fill me-2"),
            html.P(message), dcc.Link(link, url)
        ],
        color=color,
        className="d-flex align-items-center",
    )


name = "Como"
age = 16
hobby = "studying"
address = "Pisay CRC"
core = "Physics"
coreLevel = 2
elective = "ComSci"
favoriteFood = "Caviar"
section = "Mars"
gradeLevel = 11

userName = input("Hi! I'm " + name + " from " + address + ". I like " + hobby + " What's your name?")
input("Hi " + userName + "! Nice to meet you. How old are you?")
print("Nice! I'm ", age,  " years old!")
print("I'm Grade ", gradeLevel, " from section " + section)
print("My elective is Level ", coreLevel, " " + core)
userFavFood = input("What is your favorite food?")
print(userFavFood + ", huh? Well, I personally like " + favoriteFood)


import csv
import sys

def main():

    # Ensure correct usage
    if (len(sys.argv)) != 3:
        sys.exit("Usage: python dna.py data.csv sequence.txt")

    # Read data into memory from data.csv
    data = []
    with open(sys.argv[1], "r") as file:
        reader = csv.DictReader(file)
        for row in reader:
            data.append(row)

    # Record types of STR that we need to check.
    STRs = list(data[0].keys())
    STRs.pop(0)

    # Read data into memory from sequence.txt
    dna = []
    with open(sys.argv[2], "r") as file:
        dna = file.read()

    # Record repeated times of each STR in the DNA sequence.
    count_number = {}
    for STR in STRs:
        count_number[STR] = str(count_str(dna, STR))

    # Print out the name of the matching individual or no match.
    for person in data:
        flag = 0
        for STR in STRs:
            if person[STR] != count_number[STR]:
                flag = 1
                break
        if flag == 0:
            print(person['name'])
            return
    print("No match")

    return

def count_str(dna, STR):
    """Count the maximum number of times that the STR repeats in the DNA sequence."""
    i = 0
    count = 0
    count_max = 0
    n = len(STR)
    while i < len(dna):
        if dna[i:i+n] == STR:
            i += n
            count += 1
            while dna[i:i+n] == STR:
                i += n
                count += 1
            if count_max < count:
                count_max = count
            count = 0

        else:
            i += 1

    return count_max

if __name__ == "__main__":
    main()


#!/usr/bin/python3
"""
Module 5-text_indetation
ptints two new line after each of [".", ",", ":"]
"""

def text_indentation(text):
    """
    """
    if type(text) is not str:
        raise TypeError("text must a string")
    else:
        for char in ".?:":
            text = text.replace(char, char + "\n\n")
        list_lines = [lines.strip(' ') for lines in text.split('\n')]
        rev = "\n".join(list_lines)
        print(rev, end='')


# import kubernetes
#
# kubernetes.config.load_kube_config()
#
# v1 = kubernetes.client.CoreV1Api
# pods = v1.list_pod_for_all_namespaces(watch=False)
# for i in pods.items():
#     print(i)

from kubernetes import config, client,watch

config.load_config()
pods = client.CoreV1Api().list_pod_for_all_namespaces()
for i in pods.items:
    print(i.metadata.name)


class Solution:
    def isAnagram(self, s: str, t: str) -> bool:
        if len(t) < len(s):
            return False
        while t:

            if t[0] in s:
                replace = t[0]
                t = self.shrink(t, replace)
                s = self.shrink(s, replace)
            else:

                return False
        if not t:
            return True

    def shrink(self, st, to_replace):
        return st.replace(to_replace, '', 1)


import sys

class Step:
    char: str
    to_node: int
    to_accept: bool = False

    def __init__(self, char, to_node):
        self.char = char
        self.to_node = to_node

    def __hash__(self):
        return hash((self.char, self.to_node, self.to_accept))

    def __eq__(self, other):
        if not isinstance(other, type(self)): return NotImplemented
        return self.char == other.char and self.to_node == other.to_node and self.to_accept == other.to_accept

class Node:
    ind: int
    accept = False
    steps = set()
    char: str
    isRecursive = False
    isRecursive2 = False
    isSubStarter = False
    isSubRecursive = False
    accept = False
    nfa = None
    emptyNfa = False
    recursed = False
    recursedForisRecursive = False
    finisher = -1

    def __init__(self, ind, accept, steps):
        self.ind = ind
        self.accept = accept
        self.steps = steps
        self.steps = set()

    def __init__(self, ind, accept, char):
        self.ind = ind
        self.accept = accept
        self.char = char
        self.steps = set()

    def addStep(self, char, to_node):
        self.steps.add(Step(char=char, to_node=to_node))

    def addRecursion(self):
        self.isRecursive = True
        self.steps.add(Step(char=self.char, to_node=self.ind))

class Nfa:
    curInd: int = 0
    regex: str = ""
    openedCures: int = 0
    nodeList = []
    activeBranches = set()
    newBranches = set()
    newNfa = set()
    lastOperation: str = ""
    acceptStates = set()
    starterInd = 0
    finisherSize = 0

    def __init__(self, curInd, regex, openedCures, nodeList):
        self.curInd = curInd
        self.regex = regex
        self.openedCures = openedCures
        self.nodeList = nodeList
        self.activeBranches = set()
        self.newBranches = set()
        self.newNfas = set()
        self.acceptStates = set()

    def convert(self):
        for i in range(self.curInd, len(self.regex)):
            curChar = self.regex[i]
            if i >= self.curInd:
                self.curInd = i

                if curChar == "." or curChar == "|":
                    self.lastOperation = curChar
                elif curChar == "*":
                    nextChar = ""
                    if i + 1 != len(self.regex):
                        nextChar = self.regex[i + 1]

                elif curChar == ")":
                    self.openedCures -= 1
                    self.joinBranches()
                    if len(self.activeBranches) == 0:
                        self.nodeList[self.starterInd].emptyNfa = True
                        self.activeBranches.add(self.starterInd)
                    self.setAccepters()
                    nextChar = ""
                    if i + 1 != len(self.regex):
                        nextChar = self.regex[i + 1]
                    self.curInd += 1
                    self.finisherSize = len(self.nodeList)
                    self.nodeList[self.starterInd].nfa = self
                    if nextChar == "*":
                        self.nodeList[self.starterInd].isSubRecursive = True
                        self.nodeList[self.starterInd].finisher = self.finisherSize-1
                        self.addSubRecursionNfa()
                        self.nodeList[self.finisherSize-1].isRecursive2 = True
                    return
                elif curChar == "(":
                    self.openedCures += 1
                    nd = Node(ind=len(self.nodeList), accept=False, char="")
                    nd.isSubStarter = True
                    self.nodeList.append(nd)
                    newNfa = Nfa(curInd=i + 1, regex=self.regex, openedCures=1, nodeList=self.nodeList)
                    newNfa.activeBranches.add(nd.ind)
                    newNfa.starterInd = nd.ind
                    newNfa.convert()
                    self.curInd = newNfa.curInd
                    self.addNewNfa(self.lastOperation, newNfa)

                else:
                    nextChar = ""
                    if i+1 != len(self.regex):
                        nextChar = self.regex[i+1]
                    newNode = Node(ind=len(self.nodeList), accept=False, char=curChar)
                    if nextChar == "*":
                        newNode.addRecursion()
                    self.nodeList.append(newNode)
                    self.addNewNode(self.lastOperation, newNode)

        self.joinBranches()
        self.setAccepters()

    def addNewNode(self, lastOperation, newNode):
        if lastOperation == "." or lastOperation == "(" or lastOperation == ")":
            self.joinBranches()
            self.newBranches.add(newNode.ind)
        elif lastOperation == "":
            self.newBranches.add(newNode.ind)
        elif lastOperation == "|":
            self.newBranches.add(newNode.ind)

    def addNewNfa(self, lastOperation, newNode):
        if lastOperation == "." or lastOperation == "(" or lastOperation == ")":
            self.joinBranches()
            self.newNfas.add(newNode)
        elif lastOperation == "":
            self.newNfas.add(newNode)
        elif lastOperation == "|":
            self.newNfas.add(newNode)

    def joinBranches(self):
        for ind in self.activeBranches:
            for i in self.newBranches:
                self.nodeList[ind].addStep(self.nodeList[i].char, self.nodeList[i].ind)
            for i in self.newNfas:
                self.nodeList[ind].addStep("",i.starterInd)

        self.activeBranches.clear()
        self.activeBranches.update(self.newBranches)
        self.newBranches.clear()

        for nf in self.newNfas:
            for k in nf.acceptStates:
                self.activeBranches.add(k)
        self.newNfas.clear()

    def setAccepters(self):
        for st in self.activeBranches:
            self.acceptStates.add(st)

    def addSubRecursionNfa(self):

        for st in self.acceptStates:
            for ste in self.nodeList[self.starterInd].steps:
                self.nodeList[st].addStep(self.nodeList[ste.to_node].char,ste.to_node)

    def getAllChildSteps(self, ind):
        nd: Node = self.nodeList[ind]
        steps = set()
        changed = False
        for st in nd.steps:
            if self.nodeList[st.to_node].isRecursive and nd.ind != st.to_node:
                childs, ch = self.getAllChildSteps(st.to_node)
                if not childs.issubset(steps):
                    changed = True
                    steps.update(childs)
            elif self.nodeList[st.to_node].isSubStarter and nd.ind != st.to_node:
                if self.nodeList[st.to_node].isSubRecursive:
                    self.updateSubRecursion(st.to_node,nd.ind)
                    #childs, ch = self.getAllChildSteps(self.nodeList[st.to_node].finisher)
                    #changed = True
                    #steps.update(childs)
                childs, ch = self.getAllChildSteps(st.to_node)
                if not childs.issubset(steps):
                    changed = True
                    steps.update(childs)
            else:
                if not steps.__contains__(st):
                    changed = True
                    steps.add(st)

        return steps, changed

    def printNfaFull(self):
        acc = ""
        nd: Node
        pr = ""
        stepCounter  = 0
      #  self.putInSteps()
        for nd in self.nodeList:
            steps = set()

            for st in nd.steps:
                if self.nodeList[st.to_node].isRecursive:
                    childs,ch = self.getAllChildSteps(st.to_node)
                    steps.update(childs)
                elif self.nodeList[st.to_node].isSubStarter:
                    if self.nodeList[st.to_node].isSubRecursive or self.nodeList[st.to_node].emptyNfa:
                        self.updateSubRecursion(st.to_node,nd.ind)
                        #childs, ch = self.getAllChildSteps(self.nodeList[st.to_node].finisher)
                        #steps.update(childs)
                    childs,ch = self.getAllChildSteps(st.to_node)
                    steps.update(childs)
                else:
                    steps.add(st)

            pr += len(steps).__str__()
            #pr += nd.ind.__str__()
            stepCounter += len(steps)
            for st in steps:
                pr = pr + " " + st.char.__str__() + " " + st.to_node.__str__()
            pr += "\n"
        self.antiRecursion()
        self.antiRecursionForRecusive()

        for ind in self.acceptStates:
            acc = acc + ind.__str__() + " "
        header = ""
        header += len(self.nodeList).__str__() +" " + len(self.acceptStates).__str__() + " " + stepCounter.__str__()
        sys.stdout.write((header) +"\n")
        sys.stdout.write((acc) +"\n")
        sys.stdout.write((pr))

    def antiRecursionForRecusive(self):
        for nd in self.nodeList:
            for st in nd.steps:
                if self.nodeList[st.to_node].isRecursive and self.acceptStates.__contains__(st.to_node) and (not self.nodeList[st.to_node].recursedForisRecursive):
                    self.acceptStates.add(nd.ind)
                    self.nodeList[st.to_node].recursedForisRecursive = True
                    self.antiRecursionForRecusive()

    def antiRecursion(self):
        nd: Node
        for nd in self.nodeList:
            for st in nd.steps:
                if  (not self.nodeList[nd.ind].recursed)  and self.nodeList[st.to_node].isSubStarter and self.nodeList[st.to_node].emptyNfa and self.acceptStates.__contains__(st.to_node):
                    self.acceptStates.add(nd.ind)
                    self.nodeList[nd.ind].recursed = True
                    self.antiRecursion()
                if (not self.nodeList[nd.ind].recursed) and self.nodeList[st.to_node].isSubStarter and self.acceptStates.__contains__(st.to_node):
                    self.acceptStates.add(nd.ind)
                    self.nodeList[nd.ind].recursed = True
                    self.antiRecursion()

    def updateSubRecursion(self,index,starterInd):
        if self.nodeList[index].nfa.finisherSize == len(self.nodeList):
            self.acceptStates.add(starterInd)
        else:
            for accepters in self.nodeList[index].nfa.acceptStates:
                self.nodeList[index].steps.update(self.nodeList[accepters].steps)

def addPlus(regex):

    con = ""
    opened = False
    for i, v in enumerate(regex):
        if regex[i] == "|" or regex[i] == "*" or regex[i] == "(" or regex[i] == ")":
            if opened:
                opened = False
                con = con + ")" + v
            else:
                con += v
        else:
            if opened:
                con = con + v
            else:
                opened = True
                con = con + "(" + v
    if opened:
        con += ")"
    regex = con

    ret = ""
    for i, v in enumerate(regex):
        if regex[i] == "|" or regex[i] == "(":
            ret += v
        elif regex[i] == ")":
            if i + 1 != len(regex):
                if regex[i + 1] == "*" or regex[i+1] == "|":
                    ret += v
                else:
                    ret = ret + v + "."
            else:
                ret += v
        elif regex[i] == "*":
            if i + 1 != len(regex):
                if regex[i + 1] == "|":
                    ret += v
                else:
                    ret = ret + v + "."
            else:
                ret += v
        elif i + 1 != len(regex):
            if regex[i + 1] == "|" or regex[i + 1] == ")" or regex[i + 1] == "*":
                ret += v
            else:
                ret = ret + v + "."
        else:
            ret += v

    return ret

def main():
    regex = sys.stdin.readline().strip()
    regex = addPlus(regex)
    nodeList = []
    nodeList.append(Node(ind=0, accept=False, char=""))
    nfa = Nfa(curInd=0, regex=regex, openedCures=0, nodeList=nodeList)
    nfa.isSubStarter = True
    nfa.activeBranches.add(0)
    nfa.convert()
    nfa.printNfaFull()

if __name__ == "__main__":
    main()


# Code to simulate the environment when trained
import gym

from stable_baselines3 import PPO
from stable_baselines3.ppo import MlpPolicy
from stable_baselines3.common.env_util import make_vec_env
from quadcoptV1 import QuadcoptEnvV1

env = QuadcoptEnvV1()

model = PPO.load("ppo_Quad_1Attempt")

obs = env.reset()
info_u=[0]
info_w=[0]
info_Z=[0]
for i in range(1000):
    action, _state = model.predict(obs, deterministic=True) # Add deterministic true for PPO to achieve better performane

    obs, reward, done, info = env.step(action)
    info_u.append(info["u"])
    info_w.append(info["w"])
    info_Z.append(info["Z"])

    #env.render()
    if done:
      # obs = env.reset()
      break

#print(info_u)
print(info_w)
print(info_w.__len__())


import io
import sys

_INPUT = """\
6
7 0 6 30
7 30 7 30
0 0 23 59
"""

sys.stdin = io.StringIO(_INPUT)
case_no=int(input())
for __ in range(case_no):
  A,B,C,D=map(int,input().split())
  if A*60+B<=C*60+D: print('Takahashi')
  else: print('Aoki')


"""
There are a total of n courses you have to take, labeled from 0 to n-1.
Some courses may have prerequisites, for example to take course 0 you have
to first take course 1, which is expressed as a pair: [0,1]
Given the total number of courses and a list of prerequisite pairs, is it
possible for you to finish all courses?
LeetCode Rating: Medium
Link: https://leetcode.com/problems/course-schedule/
"""

from collections import defaultdict
from collections import deque

# this is basically a topological sort question
# top sort is a cycle detection algo
def canFinish(numCourses, prerequisites):
    # using the adjacency list rep of a graph (note the use if defualtdict)
    graph = defaultdict(list)
    # map to track the indegrees of the courses
    indegrees = [0 for i in range(numCourses)]
    # populate the above two data structures
    for pair in prerequisites:
        graph[pair[0]].append(pair[1])
        indegrees[pair[0]] += 1
    # init topSorted list
    topSorted = []
    # init queue of nodes with zero degrees
    zeroDegree = deque()
    for i in range(numCourses):
        if indegrees[i] == 0:
            zeroDegree.append(i)
    while zeroDegree:
        node = zeroDegree.popleft()
        topSorted.append(node)
        # now for each node M with an edge E from N to M do
        for m in graph.keys():
            if graph[m] is not None:
                if node in graph[m]:
                    lst = graph[m]
                    lst.remove(node)
                    graph[m] = lst
                    if graph[m] == []:
                        zeroDegree.append(m)
    # now if the graph has even a single edge --> it has a cycle
    for m in graph.keys():
        if graph[m] != []:
            return False
    return True

if __name__ == "__main__":
    num, pres = 3, [[1, 0], [2, 0]]
    print(canFinish(num, pres))