import math
import numpy as np
import os
import shutil
import logging

from osgeo import gdal
from scipy.interpolate import RegularGridInterpolator as rgi

logger = logging.getLogger(__name__)

class GSWInterpolator:
    """ Handle Global Surface Water files

    *Parameters*

    sat_f_name : str
        File path to satellite imagery scene for which water mask is to be interpolated
    gsw_dir : str
        File path to location of global surface water *.tif files
    output_dir : str
        File path to desired location of output files
    data :
    use_cols_vector :
    """
    THRESHOLD = 90 # GSW percent-water threshold to use as training data
    interpolators={}

    def __init__(self,sat_f_name,gsw_dir,output_dir=None,data=None,use_cols_vector=None):
        self.gsw_dir=gsw_dir
        self.sat_f_name=sat_f_name
        self.output_dir=os.getcwd() if not output_dir else output_dir
        self.data = data
        self.use_cols_vector=use_cols_vector

    def get_covering_global_surface_water_file_names(self,min_lat,max_lat,min_lon,max_lon):
        """
        Assuming we're running in the path where there is a 'coverage' directory
        containing all the RS2 BBOX and convex hulls.
        """
        def roundup(value):
            return int(math.ceil(abs(value)/10)*10)

        base_f_name = 'occurrence_{:}W_{:}N.tif'
        gsw_names = []
        limits_lat = roundup(min_lat),roundup(max_lat)
        limits_lon = roundup(min_lon),roundup(max_lon)
        logger.info(f'latitude limits: {limits_lat}')
        logger.info(f'longitude limits : {limits_lon}')

        if limits_lat[0] == limits_lat[1]:
            limits_lat = limits_lat[0],
        if limits_lon[0] == limits_lon[1]:
            limits_lon = limits_lon[0],
        for lat in limits_lat:
            for lon in limits_lon:
                gsw_name = os.path.join(self.gsw_dir,base_f_name.format(lon,lat))
                tmp_name = os.path.join('/tmp', os.path.basename(gsw_name))
                #shutil.copy(gsw_name,tmp_name)
                #gsw_names.append(tmp_name)
                gsw_names.append(gsw_name)
        logger.info('gsw files required:\n'+'\n'.join(str(os.path.basename(c)) for c in gsw_names))

        return gsw_names

    def get_gsw_information(self,rgi_file):
        logger.info(f'Get gsw information: {rgi_file}')

        ds = gdal.Open(rgi_file)
        logger.info(f'DS loaded with gdal: {ds}')
        upper_left_x, x_size, x_rotation, upper_left_y, y_rotation, y_size = ds.GetGeoTransform()
        band = ds.GetRasterBand(1)
        print('a')
        band_data = band.ReadAsArray().astype(np.uint8)
        print('z')
        x = (np.arange(band_data.shape[1],dtype=np.float32) * x_size + upper_left_x + (x_size/2.))
        y = (np.arange(band_data.shape[0],dtype=np.float32) * y_size + upper_left_y + (y_size / 2.))
        band_data[(band_data > 0) & (band_data < self.THRESHOLD)] = 255
        band_data[(band_data >= self.THRESHOLD) & (band_data <=100)] = 1
        band_data[(band_data > 100) | np.isnan(band_data)] = 255
        unique, counts = np.unique(band_data, return_counts=True)
        print('b')
        logger.info(np.asarray((unique, counts)).T)
        logger.info(f'Band data loaded. Shape is: {band_data.shape}')
        logger.info(f'number of water pixels: {np.sum(band_data == 1)}, number of non-water: {np.sum(band_data == 255)}')
        return x, y, band_data

    def get_regular_grid_interpolator(self,rgi_file):
        #SRC
        x, y, band_data = self.get_gsw_information(rgi_file)
        interpolator = rgi(points=(y[::-1], x), values=np.flip(band_data, 0), method='nearest', bounds_error=False, fill_value=255)
        del x, y, band_data
        return interpolator

    def set_least_used_interpolator_key(self):
        lowest=1000
        for k,v in self.interpolators.items():
            if v['uses'] < lowest:
                self.least_used_interpolator=k
                lowest=v['uses']

    def get_data_from_npy(self,f_path,percent_data=1.0):
        use_cols_vector=[]
        input_pos = {'lats':0,
                    'lons':1,
                    'HH':2,
                    'VV':3,
                    'HV':4,
                    'VH':5,
                    'incidence_angle':6,
                    'beam_mode_id':7,
                    'is_water':8 }

        cols_index=np.array([])
        cols=np.array([])
        if f_path.endswith('.npz'):
            data = np.load(f_path)
            final_data=data['data'][:]
            use_cols_vector=data['using_vector']
        else:
            final_data = np.load(f_path)

        return final_data,use_cols_vector

    def get_water_presence_for_points(self, min_lat, max_lat, min_lon, max_lon, pts):
        """ """
        logger.info('DESTINATION COORDINATES:')
        logger.info(pts)
        #SRC:
        rgi_files = self.get_covering_global_surface_water_file_names(min_lat, max_lat, min_lon, max_lon)

        interpolators=[]
        for rgi_file in rgi_files:
            interp_name = os.path.basename(rgi_file)
            lat_lon_items = os.path.splitext(interp_name)[0].split('_')
            lat = int(lat_lon_items[2][:-1])
            lon = int(lat_lon_items[1][:-1])
            interpolators.append((self.interpolators.setdefault(
                                                interp_name,{}).setdefault('interpolator',
                                                self.get_regular_grid_interpolator(rgi_file)
                                                ),
                                  lon,
                                  lat
                                  )
                                )
            logger.info(f'Interpolators created => {interpolators}')
            uses = self.interpolators[interp_name].setdefault('uses',0)
            self.interpolators[interp_name]['uses']+= 1
        logger.info(f'Interpolators check Created: {self.interpolators}')
        water_presence = np.zeros(pts.shape[0])
        if len(rgi_files) > 1:
            for interpolator, lon, lat in interpolators:
                logger.info(f"assigning pixels for latitudes in ({lat - 10}, {lat}) and longitudes in {-lon}, {-lon+10})")
                logger.warning("This assumes surface water index files have negative longitudes (W)")
                idx_valid_points = np.where((pts[:,0] > lat - 10) & (pts[:,0] < lat) & (pts[:,1] > -lon) & (pts[:,1] < -lon + 10))
                logger.info(f"valid indices for pixels using this interpolator")
                logger.info(idx_valid_points)
                logger.info(pts[idx_valid_points[0],:])
                logger.info(interpolator(pts[idx_valid_points[0], :]))
                water_presence[idx_valid_points[0]]=interpolator(pts[idx_valid_points[0], :])
        else:
            interpolator, lon, lat = interpolators[0]
            #print(np.amin(pts[:,0]),np.amax(pts[:,0]))
            #print(np.amin(pts[:,1]),np.amax(pts[:,1]))
            idx_valid_pts=((pts[:,0] != 0.) & (pts[:,1] != 0.))
            water_presence[:] = interpolator(pts[idx_valid_pts])
        logger.info(f'Water presence size: {water_presence.shape[0]}')
        logger.info(f'Points Size : {pts.shape[0]}')
        logger.info(f'Number of water pixels : {np.sum(water_presence==1)}')
        return water_presence

    def array_to_raster(self, array):
        """Array > Raster
        Save a raster from a C order array (column-major).

        *Parameters*

        array : ndarray

        *Returns*

        a tuple of the gdal file handle for the raster dataset and a gdal RasterBand object
        corresponding to the input array
        """
        dst_filename = '/a_file/name.tiff'

        # You need to get those values like you did.
        x_pixels = 16  # number of pixels in x
        y_pixels = 16  # number of pixels in y
        PIXEL_SIZE = 3  # size of the pixel...
        x_min = 553648
        y_max = 7784555  # x_min & y_max are like the "top left" corner.
        wkt_projection = 'a projection in wkt that you got from other file'

        driver = gdal.GetDriverByName('GTiff')

        dataset = driver.Create(
            dst_filename,
            x_pixels,
            y_pixels,
            1,
            gdal.GDT_Float32, )

        dataset.SetGeoTransform((
            x_min,    # 0
            PIXEL_SIZE,  # 1
            0,                      # 2
            y_max,    # 3
            0,                      # 4
            -PIXEL_SIZE))

        dataset.SetProjection(wkt_projection)
        dataset.GetRasterBand(1).WriteArray(array)
        dataset.FlushCache()  # Write to disk.
        return dataset, dataset.GetRasterBand(1)  #If you need to return, remenber to return also the dataset because the band don`t live without dataset

    def interpolate_water_from_points(self,min_lat,max_lat,min_lon,max_lon,pts,water_ratio=0.5,valid_angles_idx=None):
        water_presence = self.get_water_presence_for_points(min_lat,max_lat,min_lon,max_lon,pts)
        """

        """
        logger.info(f'Water presence size: {water_presence.shape[0]}')
        # Water ratio:
        water = water_presence==1
        num_water = np.count_nonzero(water)
        original_ratio=num_water/pts.shape[0]
        land = water_presence==0
        land_idx = np.where(land)[0]
        nb_land_elems=int((num_water/water_ratio)-num_water)
        np.random.shuffle(land_idx)
        keep_idx = land_idx[:nb_land_elems]
        land[:]=False
        land[keep_idx]=True
        idx_valid_pts=(valid_angles_idx&(land|water))
        final_pixel_count=np.count_nonzero(idx_valid_pts)
        logger.info(f'Final pixel count: {final_pixel_count}')
        return np.array(water_presence[idx_valid_pts],dtype=bool),idx_valid_pts,num_water,water_ratio,original_ratio,final_pixel_count

    def interpolate_water_presence(self,min_lat,max_lat,min_lon,max_lon,save=True,get_data=True):
        """ """
        logger.info('Interpolating water presence')
        logger.info(self.sat_f_name)

        # DST
        logger.info("DST")
        npy_file=self.sat_f_name

        if self.data is None:
            data, use_cols_vector = self.get_data_from_npy(npy_file)
        else:
            data, use_cols_vector = self.data,self.use_cols_vector

        logger.info(f'DATA => {data.dtype}')

        pts = data[:,:2]
        logger.info('PTS')
        logger.info(pts)

        #SRC
        logger.info("SRC")
        rgi_files = self.get_covering_global_surface_water_file_names(min_lat,max_lat,min_lon,max_lon)
        logger.info(f'RGI files: {rgi_files}')
        interpolators=[]
        for rgi_file in rgi_files:
            interp_name = os.path.basename(rgi_file)
            lat_lon_items=os.path.splitext(interp_name)[0].split('_')
            lat = int(lat_lon_items[2][:-1])
            lon = int(lat_lon_items[1][:-1])
            interpolators.append((self.interpolators.setdefault(
                                                interp_name,{}).setdefault('interpolator',
                                                self.get_regular_grid_interpolator(rgi_file)
                                                ),
                                  lon,
                                  lat
                                  )
                                )
            logger.info(f'Interpolators created => {interpolators}')
            uses = self.interpolators[interp_name].setdefault('uses',0)
            self.interpolators[interp_name]['uses']+=1
        logger.info(f'Interpolators check Created: {self.interpolators}')

        if len(rgi_files) > 1:
            for interpolator,lat,lon in interpolators:
                idx = np.where((pts[:,0]>lat-10) & (pts[:,0] < lat) & (pts[:,1] > lon-10) & (pts[:,1] < lon))
                data[idx[0],9]=interpolator(pts[idx[0],:])
        else:
            interpolator,lat,lon = interpolators[0]
            idx_valid_pts=((pts[:,0]!=0.)&(pts[:,1]!=0.))
            data[idx_valid_pts,8] = interpolator(pts[idx_valid_pts])
            data=data[idx_valid_pts,:]
            logger.info('Interpolation done')

        # Free some RAM right now
        interpolators=None
        unique, counts = np.unique(data[:,8], return_counts=True)
        logger.info('INTERPOLATED IS_WATER DATA')
        uniques=np.asarray((unique, counts)).T

        try:
            nb_water_px=uniques[uniques[:,0]==1][0][1]
        except IndexError:
            nb_water_px=0
        #data = np.compress((data[:,8] != 255),data,axis=0)
        logger.info('We have enough RAM to compress')
        if save:
            f_name = os.path.join(self.output_dir,f'final_{os.path.basename(npy_file)}.npz')
            logger.info(f'Saving {f_name}')
            np.savez_compressed(f_name,using_vector=use_cols_vector,data=data,nb_water_px=nb_water_px)
            logger.info('Saved')
            if get_data:
                return data,use_cols_vector
            else:
                return
        else:
            if get_data:
                return data,use_cols_vector
            else:
                return


import numpy as np
import redpitaya_scpi as scpi
import matplotlib.pyplot as plt

#-----------------------------------------------------------------------------

'''Create figure please'''
plt.ion()
fig = plt.figure(figsize=(8,6))
ax = fig.add_subplot(111)
ax.set_ylabel('Voltage(V)')
ax.set_xlabel('Time(ms)')

#-----------------------------------------------------------------------------

rp_s = scpi.scpi('152.78.193.126') #connect to red pitaya ip

timescale = 1 #timescale of x-axis in ms

sample_rate_dict = {'125':'125MHz', '15.6': '15_6MHz', '1.9': '1_9MHz'} #possible sample rates

rp_s.tx_txt('ACQ:DEC 64') #decimation
rp_s.tx_txt('ACQ:SRAT '+ sample_rate_dict['125']) #sample rate
rp_s.tx_txt('ACQ:TRIG:LEV 0') #trigger level in mV
rp_s.tx_txt('ACQ:TRIG:DLY 8192') #trigger delay in sample steps
rp_s.tx_txt('ACQ:AVG OFF')

#-----------------------------------------------------------------------------

'''Function to read data from Red Pitaya and return as array'''
def getdata(ch=1, tch=2):
    rp_s.tx_txt('ACQ:START')
    rp_s.tx_txt('ACQ:TRIG CH%d_PE' % tch)
    while 1:
        rp_s.tx_txt('ACQ:TRIG:STAT?')
        if rp_s.rx_txt() == 'TD':
            break
    rp_s.tx_txt('ACQ:SOUR%d:DATA:LAT:N? 16384' % ch)
    buff_string = rp_s.rx_txt()
    buff_string = buff_string.strip('{}\n\r').replace("  ", "").split(',')
    buff = map(float, buff_string)
    return buff

#-----------------------------------------------------------------------------

buff = getdata() #get data from red pitaya
#time = np.linspace(0, timescale, len(buff))
l, = ax.plot(buff) #plot data
plt.show()

while 1:
    try:
        buff = getdata() #get new set of data
        l.set_ydata(buff) #updata graph
        ax.set_ylim([0.97*np.min(buff), np.max(buff)])
        #ax.set_ylim([0.28, 0.32])
        plt.draw()
        plt.pause(0.00001)
    except KeyboardInterrupt:
        rp_s.tx_txt('ACQ:RST')   #reset acqusition
        break


class Solution(object):
    def maxOperations(self, nums, k):
        """
        :type nums: List[int]
        :type k: int
        :rtype: int
        """
        nums=sorted(nums)
        left=0
        right=len(nums)-1
        count=0
        while(left<right):
            x=nums[left]+nums[right]
            if(x==k):
                count+=1
                left+=1
                right-=1
            elif(x<k):
                left+=1
            elif(x>k):
                right-=1
        return count

LeetCode 75/Two Pointers/Max Number of K-Sum Pairs.py


from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from urllib.parse import urlparse
import json
import re
import requests
import jsonpickle

# Récupère le lien du profil LinkedIn de toutes les entreprises à scrapper
def GetAllCompaniesToSearch(driver):
    request: requests.Response = requests.get("http://127.0.0.1/LinkedInScraper/ajax/GetAllCompaniesToSearch.php")
    allURLs = json.loads(request.text)
    return allURLs

# Formatte l'url de façon à ce qu'elle pointe à la page "À propos"
def FormatURL(url):
    if "/about" not in url:
        url += "/about"
    return url

# Set le cookie d'authentification LinkedIn
def SetupLinkedinCookies(driver):
    # Il faut être se trouver sur le domaine pour pouvoir set le cookie de connexion
    driver.get("http://www.linkedin.com")
    driver.add_cookie({
        "name": "li_at",
        "value": "AQEDAS918EkFQdfBAAABc3rYJU8AAAF0ufblKk0AOzgbhvFbAqxOisgkpzu-nJA19YF5oZ5KN993SJdQIbceEdPawXXqQxLF-gM6cVTGPbqMZe6l_KrOpG7w7XbMXObG5LlKq3je7vgoztpz-xTj4mf8"
    })

# Prend une liste de WebElement, et retourne une liste contenant le texte de chaque élément
def GetAllTextFromWebElementList(elements):
    result = list()
    for el in elements:
        result.append(el.text)
    return result

# Le sélécteur CSS de la section contenant les infos de l'entreprise
SECTION_CSS_SELECTOR = ".org-grid__core-rail--no-margin-left > section[id^=ember]"
# Le sélécteur CSS lorsque l'entreprise ne possède pas de desc
INFO_CSS_SELECTOR = ".org-grid__core-rail--wide section"
# Prend un lien linkedin, et retourne les informations de l'entreprise associée
def GetDataFromURL(driver, url: str):
    if "linkedin.com/in/" in url:
        return None
    result = Company(url)
    url = FormatURL(url)
    driver.get(url)
    ##
    #   Data layout
    #   Section
    #       h4 -> "Présentation"
    #       p -> desc
    #
    #       dl -> other infos
    #           dt -> header
    #           dd -> data
    ##
    try:
        infosPanel = WebDriverWait(driver, 10).until(
            EC.presence_of_element_located(
                (By.CSS_SELECTOR, SECTION_CSS_SELECTOR))
        )
        result.desc = infosPanel.find_element(By.TAG_NAME, "p").text
    except:
                infosPanel = WebDriverWait(driver, 10).until(
            EC.presence_of_element_located(
                (By.CSS_SELECTOR, INFO_CSS_SELECTOR))
        )

    remainingInfo = infosPanel.find_element(By.TAG_NAME, "dl")
    remainingCategories = remainingInfo.find_elements(By.TAG_NAME, "dt")
    remainingData = remainingInfo.find_elements(By.TAG_NAME, "dd")

    filteredRemainingData = list()
    for d in remainingData:
        # Nombre d'employés : 50-200
        # Dont 75 sur LinkedIn
        # ^^^^^^^^^^^^^^^^^^^^
        # Saute la ligne ci-dessus car inutile
        if("sur LinkedIn" in d.text):
            continue
        try:
            potentialChild = d.find_element(By.TAG_NAME, 'span')
            filteredRemainingData.append(potentialChild)
        except:
            filteredRemainingData.append(d)

    remainingCategories = GetAllTextFromWebElementList(remainingCategories)
    filteredRemainingData = GetAllTextFromWebElementList(filteredRemainingData)
    dictionary = dict(list(zip(remainingCategories, filteredRemainingData)))
    for cat in remainingCategories:
        data:dict = dictionary[cat]
        if(cat.startswith("Site")):
            result.website = data
        elif(cat == "Téléphone"):
            result.phone = data
        elif(cat == "Secteur"):
            result.industry = data
        elif(cat.startswith("Taille")):
            # /!\ Ce n'est pas un espace entre 10 et 000 mais un demi-espace (" " vs " ") /!\
            if(" " in data):
                if("10 001" in data):
                    data = "10001"
                # IDEM
                elif("10 000" in data):
                    data = "10000"
                elif("5 000" in data):
                    data = "5000"
                elif("1 000" in data):
                    data = "1000"
            else:
                # XX-XXX Employés
                #  ^   ^
                upperBoundStartIndex = data.index('-') + 1
                upperBoundStopIndex = data.index(' ')
                data = data[upperBoundStartIndex:upperBoundStopIndex]
            result.nbEmployees = data
        elif(cat == "Type"):
            result.compType = data
        elif(cat == "Fondée en"):
            result.year = data
        elif(cat == "Spécialisations"):
            result.spec = data
    return result

# Structure de donnée contenant les champs de la base de donnée
class Company:
    linkedin = None
    desc = None
    website = None
    phone = None
    industry = None
    nbEmployees = 0
    compType = None
    year = 0
    spec = None

    def __init__(self, linkedin):
        self.linkedin = linkedin

# Insère un {Company} en base de donnée
def SaveDataInDB(driver, data:Company):
    baseURL = "http://127.0.0.1/LinkedInScraper/ajax/SaveCompanyInfo.php"
    encodedData:str = jsonpickle.encode(data)
    print(requests.post(baseURL, {'json':encodedData}).text)

driver = webdriver.Chrome()
URLs = GetAllCompaniesToSearch(driver)
companies = list()
SetupLinkedinCookies(driver)
for u in URLs:
    data = GetDataFromURL(driver, u)
    if data == None:
        continue

    if(len(list(vars(data).keys())) >= 2):
        SaveDataInDB(driver, data)
    else:
        print(f"{data.website};{data.phone};{data.industry};{data.nbEmployees};{data.compType};{data.year};{data.spec}")


import csv
import json
input_file_name = "data.json"
output_file_name = "data.csv"
with open(input_file_name, "r", encoding="utf-8", newline="") as input_file, \
        open(output_file_name, "w", encoding="utf-8", newline="") as output_file:
    data = json.load(input_file)

    csvwriter = csv.writer(output_file, delimiter=',', quoting=csv.QUOTE_NONE)
    keys = list(data[0].keys())
    csvwriter.writerow(keys)
    print(keys)
    for line in data:
        print(line)
        form = {}
        for key in keys:
            form[key] = line[key] if key in line else None
        csvwriter.writerow(form.values())


from utils import file_to_list

outcome_points = {
    'victory': 6,
    'draw': 3,
    'loss': 0
}

definitions = {
    'A': 'rock',
    'B': 'paper',
    'C': 'scissors'
}

plays = {
    'rock': {
        'score': 1,
        'rock': 'draw',
        'paper': 'loss',
        'scissors': 'victory'
    },
    'paper': {
        'score': 2,
        'rock': 'victory',
        'paper': 'draw',
        'scissors': 'loss'
    },
    'scissors': {
        'score': 3,
        'rock': 'loss',
        'paper': 'victory',
        'scissors': 'draw'
    }
}

def part1(lines):
    definitions['X'] = 'rock'
    definitions['Y'] = 'paper'
    definitions['Z'] = 'scissors'

    total_points = 0

    for line in lines:
        player_1 = definitions[line[0]] # rock
        player_2 = definitions[line[1]] # paper
        player_2_play = plays[player_2]
        total_points += outcome_points[player_2_play[player_1]] + player_2_play['score']
    return total_points

def part2(lines):
    definitions['X'] = ('loss', 'victory')
    definitions['Y'] = ('draw', 'draw')
    definitions['Z'] = ('victory', 'loss')

    total_points = 0
    for line in lines:
        player_1 = definitions[line[0]]

        player_2_outcome_inv = definitions[line[1]][1]
        player_2_outcome = definitions[line[1]][0]
        player_2 = [k for k in plays.keys() if plays[player_1][k] == player_2_outcome_inv][0]

        player_2_play = plays[player_2]
        total_points += outcome_points[player_2_outcome] + player_2_play['score']
    return total_points

if __name__ == '__main__':
    lines = file_to_list('day02.txt', test=False)
    lines = [line.split() for line in lines]

    result1 = part1(lines)
    print("Day 2, part 1:", result1)

    result2 = part2(lines)
    print("Day 2, part 2:", result2)


import sys
import sqlite3
from PySide6.QtCore import Qt
from PySide6.QtWidgets import QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout, QPushButton, QLabel, QLineEdit, QListWidget, QMessageBox

# Definindo a classe principal do aplicativo
class AgendaDeContatos(QMainWindow):
    def __init__(self):
        super().__init__()

        # Configurações iniciais da janela principal
        self.setWindowTitle("Agenda de Contatos")  # Define o título da janela
        self.setGeometry(100, 100, 400, 400)  # Define a posição e o tamanho da janela

        central_widget = QWidget(self)
        self.setCentralWidget(central_widget)  # Define o widget central

        layout = QVBoxLayout(central_widget)  # Cria um layout de grade vertical para organizar os elementos

        # Elementos da interface gráfica
        self.nome_input = QLineEdit(self)
        self.nome_input.setPlaceholderText("Nome")  # Placeholder para o campo de nome
        self.telefone_input = QLineEdit(self)
        self.telefone_input.setPlaceholderText("Telefone")  # Placeholder para o campo de telefone
        self.adicionar_button = QPushButton("Adicionar", self)
        self.adicionar_button.clicked.connect(self.adicionar_contato)  # Conecta o botão ao método adicionar_contato

        # Área de pesquisa
        self.pesquisa_input = QLineEdit(self)
        self.pesquisa_input.setPlaceholderText("Pesquisar Contato")  # Placeholder para a área de pesquisa
        self.pesquisa_input.textChanged.connect(self.filtrar_contatos)  # Conecta a área de pesquisa ao método filtrar_contatos

        self.contatos_list = QListWidget(self)  # Lista de contatos

        # Botão para deletar contato
        self.deletar_button = QPushButton("Deletar", self)
        self.deletar_button.clicked.connect(self.deletar_contato)  # Conecta o botão ao método deletar_contato

        # Adiciona os elementos ao layout vertical
        layout.addWidget(self.nome_input)
        layout.addWidget(self.telefone_input)
        layout.addWidget(self.adicionar_button)
        layout.addWidget(self.pesquisa_input)  # Adicione a área de pesquisa
        layout.addWidget(self.contatos_list)
        layout.addWidget(self.deletar_button)  # Adicione o botão "Deletar"

        # Cria uma conexão com o banco de dados SQLite3
        self.conexao = sqlite3.connect("agenda.db")
        self.criar_tabela_contatos()  # Chama o método para criar a tabela de contatos no banco de dados

        self.carregar_contatos()  # Chama o método para carregar os contatos existentes

    # Método para criar a tabela de contatos no banco de dados
    def criar_tabela_contatos(self):
        cursor = self.conexao.cursor()
        cursor.execute('''
            CREATE TABLE IF NOT EXISTS contatos (
                id INTEGER PRIMARY KEY,
                nome TEXT,
                telefone TEXT
            )
        ''')
        self.conexao.commit()

    # Método para adicionar um contato
    def adicionar_contato(self):
        nome = self.nome_input.text()
        telefone = self.telefone_input.text()
        if nome and telefone:
            cursor = self.conexao.cursor()
            cursor.execute("INSERT INTO contatos (nome, telefone) VALUES (?, ?)", (nome, telefone))
            self.conexao.commit()

            contato = f"Nome: {nome}, Telefone: {telefone}"
            self.contatos_list.addItem(contato)
            self.nome_input.clear()
            self.telefone_input.clear()
        else:
            self.mostrar_mensagem("Erro", "Preencha todos os campos.")

    # Método para exibir uma mensagem de erro em uma caixa de diálogo
    def mostrar_mensagem(self, titulo, mensagem):
        mensagem_box = QMessageBox(self)
        mensagem_box.setWindowTitle(titulo)
        mensagem_box.setText(mensagem)
        mensagem_box.setStandardButtons(QMessageBox.Ok)
        mensagem_box.exec()

    # Método para filtrar contatos com base na pesquisa
    def filtrar_contatos(self):
        filtro = self.pesquisa_input.text().strip().lower()
        self.contatos_list.clear()
        cursor = self.conexao.cursor()
        cursor.execute("SELECT nome, telefone FROM contatos WHERE LOWER(nome) LIKE ?", ('%' + filtro + '%',))
        for row in cursor.fetchall():
            contato = f"Nome: {row[0]}, Telefone: {row[1]}"
            self.contatos_list.addItem(contato)

    # Método para deletar um contato
    def deletar_contato(self):
        item_selecionado = self.contatos_list.currentItem()
        if item_selecionado:
            item_text = item_selecionado.text()
            nome = item_text.split(",")[0].split(":")[1].strip()
            cursor = self.conexao.cursor()
            cursor.execute("DELETE FROM contatos WHERE nome=?", (nome,))
            self.conexao.commit()
            self.contatos_list.takeItem(self.contatos_list.row(item_selecionado))

    # Método para carregar contatos existentes no banco de dados
    def carregar_contatos(self):
        cursor = self.conexao.cursor()
        cursor.execute("SELECT nome, telefone FROM contatos")
        for row in cursor.fetchall():
            contato = f"Nome: {row[0]}, Telefone: {row[1]}"
            self.contatos_list.addItem(contato)

# Função principal
if __name__ == "__main__":
    app = QApplication(sys.argv)
    agenda = AgendaDeContatos()
    agenda.show()
    sys.exit(app.exec())


from input_data import *

for key in input_data:
    if input_data[key] is None or input_data[key] == '\"\"':
        input_data[key] = ""
    input_data[key] = ''.join(i for i in input_data[key] if i not in '"')

total_price = input_data['total_price']
subtotal_price = input_data['subtotal_price']
total_discounts = input_data['total_discounts']
state = input_data['state']
total_tax = input_data['total_tax']

def get_taxable(code_state):
    if code_state == "CA":
        return True
    else:
        return False

def get_calculated_total(price, discounts):
    total = round(float(price) - float(discounts), 2)
    return total

def get_tax_percent(tax, is_taxable, subtotal, discounts):
    if is_taxable:
        final_tax_percent = round(tax / (subtotal - discounts) * 100, 2)
    else:
        final_tax_percent = round(tax / subtotal * 100, 2)

    return final_tax_percent

def get_formatted_discount_text(discounts):
    if discounts > 0:
        formatted = -discounts
    else:
        formatted = discounts
    return formatted

taxable = get_taxable(state)
calculated_total = float(total_price) - float(total_discounts)
tax_percent = get_tax_percent(float(total_tax), taxable, float(subtotal_price), float(total_discounts))
formatted_discount_text = get_formatted_discount_text(float(total_discounts))

output = [{'taxable': taxable, 'calculated_total': calculated_total, 'tax_percent': tax_percent, 'formatted_discount_text': formatted_discount_text}]


import os
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
from matplotlib import cm
from matplotlib.colors import ListedColormap, LinearSegmentedColormap
from matplotlib.ticker import ScalarFormatter
from matplotlib.ticker import MultipleLocator
# Specify the directory to start the iteration from
# start_directory = 'path/to/start/directory'

#BENCHMARK
# start_directory = r"C:\Users\valde\OneDrive - Danmarks Tekniske Universitet\GitHub\OGF\results\Belgian case study\Benchmark models\job_logs_nt6_NNOGF_vs_PLA"

#FEASIBLE TRAINNG DATA/EACH PIPE
# start_directory = r"C:\Users\valde\OneDrive - Danmarks Tekniske Universitet\GitHub\OGF\results\Belgian case study\each_pipe_nb"

#BOUND TIGHTENING UNIFORM VS LINSPACE
# start_directory = r"C:\Users\valde\OneDrive - Danmarks Tekniske Universitet\GitHub\OGF\results\Belgian case study\Bound tightening"

#used pla vs nnogf:
start_directory =r"C:\Users\valde\OneDrive - Danmarks Tekniske Universitet\GitHub\OGF\results\Belgian case study\Benchmark models\in_report"

#used architecture test:
# start_directory =r"C:\Users\valde\OneDrive - Danmarks Tekniske Universitet\GitHub\OGF\results\arch_tests\used_models"

pipe_knm = np.array([255.5169343, 255.5169343, 208.6287032,208.6287032,100.2219872,26.8636084,32.71143353,40.41306369,
                     68.90779278,114.2706469,13.94307458,102.2067737,12.47106503,78.85423786,80.8015493,
                    228.5412938,161.6030986,102.2067737,19.24327111,3.501408717,14.15077486])
p_map= [[1,  1  ,2],
        [2,  1  ,2],
        [3,  2  ,3],
        [4,  2  ,3],
        [5,  3  ,4],
        [6,  5  ,6],
        [7,  6  ,7],
        [8,  7  ,4],
        [9,  4  ,14],
        [10, 9  ,10],
        [11, 9  ,10],
        [12, 10, 11],
        [13, 10, 11],
        [14, 11, 12],
        [15, 12, 13],
        [16, 13, 14],
        [17, 14, 15],
        [18, 15, 16],
        [19, 11, 17],
        [20, 18, 19],
        [21, 19, 20]]

# p_map = [[1,1,2],
#         [2,	2,3],
#         [3,	2,4]]

# pipe_knm = np.array([2.591141949,2.591141949,6.346975626])

# excel_theo_wey = pd.DataFrame()
# for p in p_map:
#     excel_theo_wey[str(p[0])] = (excel_pressure[str(p[1])]**2-excel_pressure[str(p[2])]**2)*pipe_knm[p[0]-1]**2

err_dict = {}

# Iterate over subfolders
for foldername in os.listdir(start_directory):
    folder_path = os.path.join(start_directory, foldername)

    # Check if the item is a subfolder
    if os.path.isdir(folder_path):
        excel_file_path = os.path.join(folder_path, foldername +"_results"+ '.xlsx')

        # Check if the corresponding Excel file exists
        if os.path.isfile(excel_file_path):
            # Load the Excel file and read the 'feasibility_gap' sheet

            excel_parameters = pd.read_excel(excel_file_path, sheet_name='parameters')
            m = excel_parameters["keys"] == "mae"
            print(foldername)
            print(excel_parameters[m])

            excel_feas = pd.read_excel(excel_file_path, sheet_name='feasibility_gap')

            excel_qnm = pd.read_excel(excel_file_path, sheet_name='Q_nm')
            excel_parameters = pd.read_excel(excel_file_path, sheet_name='parameters')
            excel_pressure = pd.read_excel(excel_file_path, sheet_name='pr')

            excel_theo_wey = pd.DataFrame()
            for p in p_map:
                excel_theo_wey[str(p[0])] = (excel_pressure[str(p[1])]**2-excel_pressure[str(p[2])]**2)*pipe_knm[p[0]-1]**2

            mask = excel_parameters["keys"] =="obj_val"
            # Extract the data values from the DataFrame
            feas_values = np.transpose(excel_feas.values)
            qnm_sq_values = np.transpose(excel_qnm.values*abs(excel_qnm.values)) #should this be ^2 ???
            # theo_values = qnm_sq_values-feas_values
            theo_values = np.transpose(excel_theo_wey.values)
            rel_error = ((abs(qnm_sq_values-theo_values)+1e-9)/(theo_values+1e-9))*100

            # print(foldername)
            # print(f'max: {np.max(abs(feas_values)/1000)}, min: {np.min(abs(feas_values)/1000)}, mean: {np.mean(abs(feas_values)/1000)}') #maybe take square root of this...
            print(f'rel_error; max: {np.max(rel_error)}, min: {np.min(rel_error)}, mean: {np.mean(rel_error)}')
            # print(f'obj:{excel_parameters[mask]}\n')
            # print(f'rel_error; max: {np.max(rel_error)}, min')
            # scale = 10000

            nrmse_v2 = np.sqrt(np.mean(rel_error)**2)
            nrmse = np.sqrt(np.mean(rel_error**2))
            print(f'nrmse: {nrmse}, nrmse_v2: {nrmse_v2}')
            err_dict[foldername] = nrmse

            h = 8; w = 6
            fs = 18
            fig, ax = plt.subplots(figsize=(h, w))
            im_ratio = h/w
            # heatmap = ax.imshow(abs(feas_values)/scale, cmap='gist_yarg', interpolation='nearest', vmin=0, vmax=50000//scale) #absolut error
            # heatmap = ax.imshow(rel_error, interpolation='nearest', vmin=-4,vmax = 4) #relativ error
            # heatmap = ax.imshow(rel_error, cmap='bwr', interpolation='nearest', vmin=-1,vmax = 1) #relativ error
            # heatmap = ax.imshow(rel_error, cmap='coolwarm', interpolation='nearest', vmin=-1,vmax = 1) #relativ error
            heatmap = ax.imshow(rel_error, cmap='coolwarm', interpolation='nearest', vmin=-100,vmax = 100) #relativ error

            # ax.set_title("Absolute Error Heat Map - {}".format(foldername))
            ax.set_xlabel(r"Time [hours]", fontsize=fs)
            ax.set_ylabel(r"Pipe $\mathcal{P}$", fontsize=fs)
            # cbar = plt.colorbar(heatmap, shrink = 0.89)
            cbar = plt.colorbar(heatmap, fraction=0.047*im_ratio)
            # cbar = plt.colorbar(heatmap, extend='both', shrink=0.8, ticks=range(1, feas_values.max()+1))

            # Format the y-axis ticks
            # ax.set_yticks(np.arange(feas_values.shape[0]), labels=np.arange(1,feas_values.shape[0]+1)[::-1])
            ax.set_yticks(np.arange(feas_values.shape[0]), labels=np.arange(1,feas_values.shape[0]+1))
            ax.set_xticks(np.arange(feas_values.shape[1]), labels=np.arange(1,feas_values.shape[1]+1))

            # Set the x-axis ticks to show every 3rd tick
            ax.xaxis.set_major_locator(MultipleLocator(3))

            # Set the y-axis ticks to show every 3rd tick
            ax.yaxis.set_major_locator(MultipleLocator(4))
            ax.tick_params(axis='y', labelsize=fs-2)
            ax.tick_params(axis='x', labelsize=fs-2)
            cbar.ax.tick_params(labelsize=fs-2)

            # legend_text = r'Absolute error [MNm$^3$/h]'#check the units...
            # legend_text = r'Absolute error [kg$/h]'
            legend_text = r'Relative error [%]' # [MNm$^3$/h]'
            # cbar.ax.text(0.5, -0.1, legend_text, va='center', ha='center')
            cbar.ax.set_ylabel(legend_text, rotation=90, fontsize=fs)
            # cbar.ax.yaxis.set_label_coords(-.1, .5)
            # Format colorbar values as integers

            # plt.show()
            # Save the plot in the associated subfolder
            save_path = os.path.join(start_directory, 'heatmap_'+foldername+'.png')
            plt.savefig(save_path,bbox_inches="tight",)
            # Close the plot to free up memory
            plt.close()

# print(feas_values)
# excel_data
# 8.099855885404184

# {
# 'G_case_Gas_tree_compr_CB_f_mt_NN_constrained_ps1': 0.3574593125620862,

# 'seq_1l_4n':  0.3859170302593904,
# 'seq_1l_10n': 0.2792529415612169,
# 'seq_2l_2n':  0.4695616425808823,
# 'seq_2l_5n':  0.3574593125620862,
#  'seq_2l_8n': 0.3108519789541147,
# 'seq_3l_3n':  0.32482734209948505,
# 'seq_3l_5n':  0.2373738481148868
# }

# {
# 'uni_1m_b4_Av1':        0.5829626824080487,
# 'pla_Av1_V6':           0.5436736635261323,
# 'pla_Av1_nt3_V10':      0.4028391245645183,
# 'uni_1m_b6_Av1':        0.45654220457504,
# 'FOP_each_pipe_Av1_v2': 0.28239578548380734,

# 'uni_1m_b3_Av1_nt3':    0.4512698212402897,
# 'uni_1m_b4_Av1':        0.5829626824080487,
# 'uni_1m_b6_Av1':        0.45654220457504,
# 'uni_1m_nb_Av1':        0.4593950775860708
# }


#finf the pivot in the matrix
def find_pivot(matrix):
    m = len(matrix)
    IDMatrix = [[float(i ==j) for i in range(m)] for j in range(m)]
    for j in range(m):
        row = max(range(j, m), key=lambda i: abs(matrix[i][j]))
        if j != row:
            # Swap the rows
            IDMatrix[j], IDMatrix[row] = IDMatrix[row], IDMatrix[j]
    return IDMatrix

#A function that copies the matrix it receives to a new matrix and returns the new matrix
def copy_matrix(mat,size):
    len_rows = len_cols=size; #Length of the line and the column

    new_mat = zero_matrix(len_rows, len_cols)

    for i in range(len_rows):
        for j in range(len_rows):
            new_mat[i][j] = mat[i][j]

    return new_mat

def mul_mat_veq(matrix_A, b):
    x = []
    for i in range(len(matrix_A[0])):  # this loops through columns of the matrix
         total = 0
         for j in range(len(matrix_A[0])):  # this loops through vector coordinates & rows of matrix
            total += b[j] * matrix_A[i][j]
         x.append(total)

    return x

#A function that receives rows and columns and returns a new matrix the size
# of the rows and columns it received and all its members are equal to 0

def zero_matrix(rows, cols):
    zeroM= [[0.0] * rows for i in range(cols)]
    return zeroM

def unitmatrix(matrix,size):
    IDMatrix = [[float(i == j) for i in range(size)] for j in range(size)]
    return IDMatrix

#A function that multiplies between two matrices and returns
# a new matrix which is the value of the two doubled matrices

def matrix_multiply(A,B):
    len_rowsA = len(A)  #Length of the line In matrix A
    len_colsA = len(A[0])  #Length of the column In matrix A

    len_rowsB = len(B) #Length of the line In matrix B
    len_colsB = len(B[0])  #Length of the column In matrix B

    if len_colsA != len_rowsB: #Test that matrix A and matrix B have the same size
        print('The matrix has be a square matrix')
        exit()

    new_mat = zero_matrix(len_rowsA, len_colsB)

    for i in range(len_rowsA):
        for j in range(len_colsB):
            sum = 0
            for k in range(len_colsA):
                sum += A[i][k] * B[k][j]
            new_mat[i][j] = sum

    return new_mat

#Solving a system of equations using an elementary matrix
def Solve_elementary_matrices_Gauss(MatrixA, B, size):

    matrix_A = copy_matrix(MatrixA,size)
    matrix_I = unitmatrix(MatrixA,size)

    len_mat_A = size# The length of a matrix A

    index = 0 # index stands for focus diagonal OR the current diagonal
    #Check the first value in the matrix is different from 0 and if so we will switch between the rows
    for i in range(len_mat_A):
        max =  abs(matrix_A[i][i])
        for j in range(i,len_mat_A):
            if abs(matrix_A[i][j])>max:
                temp = matrix_A[j]
                matrix_A[j]= matrix_A[i]
                matrix_A[i]= temp
                max = abs(matrix_A[i][i])

    diagonal = 1. / matrix_A[index][index]# Current diagonal or diagonal

    for j in range(len_mat_A): # using j to indicate cycling thru columns
        matrix_A[index][j] = diagonal* matrix_A[index][j]
        matrix_I[index][j] = diagonal * matrix_I[index][j]

    list_of_len = list(range(len_mat_A))

    for i in list_of_len[0:index] + list_of_len[index + 1:]:  # * skip row with fd in it.
        cr = matrix_A[i][index]  # cr stands for "current row".
        for j in range(len_mat_A):  # cr - cr * fdRow, but one element at a time.
            matrix_A[i][j] = matrix_A[i][j] - cr * matrix_A[index][j]
            matrix_I[i][j] = matrix_I[i][j] - cr * matrix_I[index][j]

    for index in range(1, len_mat_A):  # stands for focus diagonal
        diagonal= 1.0 / matrix_A[index][index]
        # FIRST: scale fd row with fd inverse.
        for j in range(len_mat_A):  # Use j to indicate column looping.
            matrix_A[index][j] *= diagonal
            matrix_I[index][j] *= diagonal

        # SECOND: operate on all rows except cd row.
        for i in list_of_len[:index] + list_of_len[index + 1:]:  # * skip row with fd in it.
            cr = matrix_A[i][index]  # cr stands for "current row".
            for j in range(len_mat_A):  # cr - cr * fdRow, but one element at a time.
                matrix_A[i][j] = matrix_A[i][j] - cr * matrix_A[index][j]
                matrix_I[i][j] = matrix_I[i][j] - cr * matrix_I[index][j]

    x = mul_mat_veq(matrix_I, B)

    return  x

#Decomposition into L or  method
def find_L_U(matrix,size):
    #Replace rows
    #the row with the highest member in the first column will be in first row
    max = matrix[0]
    d = 0
    for i in range(size):
         if abs(matrix[i][d])>max[d]:
             max = matrix[i]
             k = i

    temp = matrix[0]
    matrix[0]=max
    matrix[k]= temp

    len_matrix = size
    L = [[0.0] * len_matrix for i in range(len_matrix)]#Building and resetting L matrix
    U = [[0.0] * len_matrix for i in range(len_matrix)]#Building and resetting U matrix
    piv = find_pivot(matrix) #pivot
    mul_piv_mat = matrix_multiply(piv, matrix)
    for j in range(len_matrix):
        L[j][j] = 1.0
        for i in range(j+1):
            sum1 = sum(U[k][j] * L[i][k] for k in range(i))
            U[i][j] = mul_piv_mat[i][j] - sum1
        for i in range(j, len_matrix):
            sum2 = sum(U[k][j] * L[i][k] for k in range(j))
            if U[j][j] != 0:
                L[i][j] = (mul_piv_mat[i][j] - sum2) / U[j][j]
    return (L, U)

matrix_A = [[0,1,1,1], [1,1,2,1], [2,2,4,0],[1,2,1,1]]# matrix A
B = [1,1,1]
size_matrix_A=4;

if size_matrix_A<4: #if the size of the matrix is less then 4 solve in Gauss method
        x = Solve_elementary_matrices_Gauss(matrix_A, B, size_matrix_A)  # Reverse matrix A^-1
        print("The solve is: ",x)
else:#if the size of the matrix is more then 4 solve in Decomposition into L or  method
        l, u = find_L_U(matrix_A,size_matrix_A)
        print("The solve is:\nL= ",l)
        print("U= ",u)


import csv
import os
import pandas as pd
from glob import glob
from PIL import Image
import numpy as np
import imghdr

# Define folders
# folder = "E:\\bird img\\"

dB_location = "E:\\ML Training Data\\"
dB_filename = "dB of all bird images from all datasets 3.csv"

# Load data into data frames
image_db = pd.read_csv(dB_location + dB_filename, index_col=None, header=0)
ML_training_map = pd.read_csv(dB_location + 'ML training map.csv', index_col=None, header=0)

fileNum = '13'

doExtract = True

if doExtract:

    try:
        # Generate IDs
        full_bird_list_df = pd.DataFrame(columns=['Label', 'ID'])
        ID = -1
        for i in range(len(ML_training_map)):

            if not ML_training_map['Include'][i]:
                continue

            common_name = ML_training_map['Common name'][i]

            if ML_training_map['Unisex'][i]:

                label = common_name
                ID += 1

                # Add to dataframe
                full_bird_list_df = full_bird_list_df.append({'Label': label, 'ID': ID}, ignore_index=True)

            if ML_training_map['Male'][i]:

                label = common_name + ' Male'
                ID += 1

                # Add to dataframe
                full_bird_list_df = full_bird_list_df.append({'Label': label, 'ID': ID}, ignore_index=True)

            if ML_training_map['Female'][i]:

                label = common_name + ' Female'
                ID += 1

                # Add to dataframe
                full_bird_list_df = full_bird_list_df.append({'Label': label, 'ID': ID}, ignore_index=True)

        full_bird_list_df.to_csv(r'E:\ML Training Data\\' + 'Class label to ID map.csv', index=False)

        birds = full_bird_list_df['Label'].unique()
        # with open('E:\\ML Training Data\\bird list.csv', 'w') as f:
        #     csv.writer(f).writerow(birds)

        image_db = image_db[image_db['Common name'] != 'Yellow-rumped Warbler']
        image_db = image_db[image_db['Common name'] != 'Yellow-rumped Warbler (Myrtle)']
        image_db = image_db.reset_index(drop=True)

        partial_load = False
        if partial_load:
            df_train_formatted = pd.read_csv(dB_location + 'files extracted for training 12.csv', index_col=None, header=0)

            where_were_we = len(df_train_formatted)
            last_image_path_and_filename = df_train_formatted['path_and_filename'].iloc[-1]
            while last_image_path_and_filename != image_db['Full Path'].iloc[where_were_we]:
                where_were_we += 1
            else:
                where_were_we += 1

        else:
            where_were_we = 0
            df_train_formatted = pd.DataFrame(columns=['Label', 'path_and_filename', 'ID'])

        # Process each DB entry and make a new CSV
        for i in range(where_were_we, len(image_db)):

            path_filename = image_db['Full Path'][i]

            test_read_image = True
            if test_read_image:
                try:
                    # Check if PIL can read it without error
                    image = Image.open(path_filename)
                    if image.format not in ['JPEG', 'PNG', 'GIF']:
                        print('PIL test: wrong filetype, skipping ' + path_filename + ' (' + image.format + ')')
                        continue

                    # Check for filetype
                    filetype = imghdr.what(path_filename)
                    if filetype not in ['jpeg', 'png', 'gif']:
                        print('IMGHDR test: wrong filetype, skipping ' + path_filename + ' (' + filetype + ')')
                        continue

                except:
                    print("Can't read " + path_filename + ". Skipping")
                    continue

            sex = image_db['Sex'][i]

            common_name = image_db['Common name'][i]

            # Get map for current species
            map = ML_training_map[ML_training_map['Common name'] == common_name]

            if map['Unisex'].values:

                label = common_name

            elif map['Male'].values == 1 and sex == 'Male':

                label = common_name + ' Male'

            elif map['Female'].values == 1 and sex == 'Female':

                label = common_name + ' Female'

            else:
                # print(str(i) + ": skipping " + common_name + " | " + path_filename)

                continue
                # raise Exception("Not able to categorize entry. Sumthin's bad wrong!")

            tmp_ID = full_bird_list_df[full_bird_list_df['Label'] == label]['ID'].values
            if tmp_ID.size == 0:
                continue
            else:
                ID = int(tmp_ID)

            data_dict = {'Label': label, 'path_and_filename': path_filename, 'ID': ID}
            df_train_formatted = df_train_formatted.append(data_dict, ignore_index=True)

            if (i % 1000) == 0:
                print(str(i) + ": " + label)

                df_train_formatted.to_csv(r'E:\ML Training Data\\' + 'files extracted for training ' + fileNum + '.csv',
                                          index=False)

    except:
        print("Mofo exeption")
        print("Saving what can be saved ... ")
        df_train_formatted.to_csv(r'E:\ML Training Data\\' + 'files extracted for training ' + fileNum + '.csv',
                                  index=False)
        print('Bye')
        raise

else:
    df_train_formatted = pd.read_csv(dB_location + 'files extracted for training ' + fileNum + '.csv',
                                     index_col=None, header=0)

# df_train_formatted['ID'] = pd.to_numeric(df_train_formatted['ID'])

# Create train, eval, and test CSVs

num_images = len(df_train_formatted)
train_eval_test_proportions = [0.7, 0.2, 0.1]
filenames = ['train', 'eval', 'test']
high_idx = 0

birds = df_train_formatted['Label'].unique()
print("")
print("*********************")
print("List of the " + str(len(birds)) + " classes:")
for b in birds:
    print(b)
print("*********************")
print("")

# Randomly shuffle dataset
df_train_formatted = df_train_formatted.sample(frac=1).reset_index(drop=True)

for i, fn in enumerate(filenames):

    low_idx = high_idx
    high_idx = low_idx + int(train_eval_test_proportions[i] * num_images)

    df = df_train_formatted.iloc[low_idx : high_idx]
    csv_filename = filenames[i] + '.csv'
    df.to_csv(r'E:\ML Training Data\\' + csv_filename, index=False)

print("Done!")


import pyautogui
from skimage.measure import compare_ssim as ssim
from skimage import img_as_float
import time

import spanish_typewritter
import start
import util
from cts import *

if __name__ == '__main__':

    contact_y_delta = 120
    start.erase_search_bar(SEARCH_BAR_COORDINATES)

    message_queue = ['prúébá ññññ del robot (que pena molestarlo, jajajaj)1',
                     'prúébá ññññ del robot (que pena molestarlo, jajajaj)2',
                     'prúébá ññññ del robot (que pena molestarlo, jajajaj)3',
                     'prúébá ññññ del robot (que pena molestarlo, jajajaj)4',
                     'prúébá ññññ del robot (que pena molestarlo, jajajaj)5',
                     'prúébá ññññ del robot (que pena molestarlo, jajajaj)6',
                     'prúébá ññññ del robot (que pena molestarlo, jajajaj)7 TERMINO',
                     ]

    while len(message_queue) > 0:
        if util.messenger_running(SEARCH_BAR_COORDINATES):

            # Removes any double spacing
            user_name = 'Santiago Paisa Nuevo Gonzales'

            text = message_queue[0]
            message_queue = message_queue[1:]

            pyautogui.moveTo(*SEARCH_BAR_COORDINATES)

            pyautogui.click()
            pyautogui.click()
            pyautogui.typewrite(user_name, interval=start.get_random_interval())

            contact_coordinates = SEARCH_BAR_COORDINATES[0], SEARCH_BAR_COORDINATES[1] + contact_y_delta
            pyautogui.moveTo(*contact_coordinates)
            pyautogui.click(interval=1)

            spanish_typewritter.type(text)
            pyautogui.press('enter')

            start.erase_search_bar(SEARCH_BAR_COORDINATES)
        time.sleep(1)


from collections import Counter

strings = ["eat", "tea", "tan", "ate", "nat", "bat"]
test_output = [["bat"], ["nat", "tan"], ["ate", "eat", "tea"]]

def anagrams(str1, str2):
    return Counter(str1) == Counter(str2)

def group_anagrams(strs):
    """Group into anagrams"""
    output = []
    for string in strs:
        found = False
        for words in output:
            if anagrams(string, words[0]):
                words.append(string)
                found = True
                break
        if not found:
            output.append([string])
    return output


import torch
from torch.utils.data import Dataset, DataLoader
from torchvision.transforms import functional as F
import json
import random
import os
import cv2

class FishDataset(Dataset):
    def __init__(self, img_dir, lab_path, transforms, keypoint_names=("Head", "Dorsal1", "Dorsal2", "Pectoral", "Gluteal", "Caudal")):
        self.img_dir = img_dir
        with open(lab_path, "r") as f:
            lab = json.load(f)
        lab = [v for k, v in lab.items() if
               len([reg for reg in v["regions"] if reg["shape_attributes"]["name"] == "rect"]) > 0]
        self.imgs = []
        self.boxess = []
        self.keypointsss = []
        for e in lab:
            img = e["filename"]
            self.imgs.append(img)
            boxes = [[region["shape_attributes"]["x"],
                      region["shape_attributes"]["y"],
                      region["shape_attributes"]["x"] + region["shape_attributes"]["width"],
                      region["shape_attributes"]["y"] + region["shape_attributes"]["height"]]
                     for region in e["regions"] if region["shape_attributes"]["name"] == "rect"]
            self.boxess.append(boxes)
            keypointss = []
            for box in boxes:
                xmin, ymin, xmax, ymax = box
                keypoints = [[0, 0, 0] for k in keypoint_names]
                for i, k in enumerate(keypoint_names):
                    for region in e["regions"]:
                        if region["shape_attributes"]["name"] == "point":
                            key = region["region_attributes"]["Keypoint"]
                            x, y = region["shape_attributes"]["cx"], region["shape_attributes"]["cy"]
                            if key == k and xmin <= x <= xmax and ymin <= y <= ymax:
                                keypoints[i] = [x, y, 1]  # 1 means visibility = True
                keypointss.append(keypoints)
            self.keypointsss.append(keypointss)
        self.transforms = transforms

    def __getitem__(self, idx):
        img_path = os.path.join(self.img_dir, self.imgs[idx])
        image = cv2.imread(img_path)
        b, g, r = cv2.split(image)
        image = cv2.merge([r, g, b])
        boxes = self.boxess[idx].copy()
        keypointss = self.keypointsss[idx].copy()
        labels = torch.ones((len(boxes),), dtype=torch.int64)  # Only have one class
        boxes = torch.as_tensor(boxes, dtype=torch.float32)
        keypointss = torch.as_tensor(keypointss, dtype=torch.float32)
        image_id = torch.tensor([idx])
        target = {}
        target["boxes"] = boxes
        target["labels"] = labels
        target["keypoints"] = keypointss
        target["image_id"] = image_id
        if self.transforms is not None:
            image, target = self.transforms(image, target)
        return image, target

    def __len__(self):
        return len(self.imgs)

class ToTensor(object):
    def __call__(self, image, target):
        image = F.to_tensor(image)
        return image, target

class RandomHorizontalFlip(object):
    def __init__(self, prob):
        self.prob = prob

    def __call__(self, image, target):
        if random.random() < self.prob:
            height, width = image.shape[-2:]
            image = image.flip(-1)

            bbox = target["boxes"]
            bbox[:, [0, 2]] = width - bbox[:, [2, 0]]
            target["boxes"] = bbox
            keypoints = target["keypoints"]
            for keypoint in keypoints:
                for kp in keypoint:
                    kp[0] = width - kp[0]
            target["keypoints"] = keypoints
        return image, target

class Compose(object):
    def __init__(self, transforms):
        self.transforms = transforms

    def __call__(self, image, target):
        for t in self.transforms:
            image, target = t(image, target)
        return image, target

def get_transforms(train):
    transforms = []
    transforms.append(ToTensor())
    if train:
        transforms.append(RandomHorizontalFlip(0.5))
    return Compose(transforms)

def collate_fn(batch):
    return tuple(zip(*batch))  # Default collate_fn needs same size of images, so should re-define it here

def get_dataloader(train, batch_size, val_split=0.0, shuffle=True, num_workers=0):
    dataset = FishDataset("data/Frames", "data/Annotation/annotation_keypoint.json", get_transforms(train=train))
    if val_split == 0.0:
        dataset_train = dataset
        dataloader_train = DataLoader(dataset_train, batch_size=batch_size, shuffle=shuffle, num_workers=num_workers, collate_fn=collate_fn)
        dataloader_val = None
    else:
        indices = torch.randperm(len(dataset)).tolist()
        where_train = int(len(dataset) * (1 - val_split))
        dataset_train = torch.utils.data.Subset(dataset, indices[:where_train])
        dataset_val = torch.utils.data.Subset(dataset, indices[where_train:])
        dataloader_train = DataLoader(dataset_train, batch_size=batch_size, shuffle=shuffle, num_workers=num_workers, collate_fn=collate_fn)
        dataloader_val = DataLoader(dataset_val, batch_size=batch_size, shuffle=shuffle, num_workers=num_workers, collate_fn=collate_fn)
    return dataloader_train, dataloader_val

if __name__ == '__main__':
    dataset = FishDataset("data/Frames", "data/Annotation/annotation_keypoint.json", get_transforms(train=True))
    a = next(iter(dataset))
    pass


# -*- coding: utf-8 -*-
#include "windows.h"

# GPIOを制御するライブラリ
import wiringpi
# タイマーのライブラリ
import time
import cv2
import sys
# ボタンを繋いだGPIOの端子番号
button_pin1 = 17 # 11番端子
button_pin2 = 27 # 11番端子

img1 = cv2.imread("right2.jpg")
img2 = cv2.imread("turnright2.jpg")
img3 = cv2.imread("switchoff-1.jpg")
# GPIO初期化
wiringpi.wiringPiSetupGpio()
# GPIOを出力モード（1）に設定
wiringpi.pinMode( button_pin1, 0 )
wiringpi.pinMode( button_pin2, 0 )

# 端子に何も接続されていない場合の状態を設定
# 3.3Vの場合には「2」（プルアップ）
# 0Vの場合は「1」と設定する（プルダウン）
wiringpi.pullUpDnControl( button_pin1, 2 )
wiringpi.pullUpDnControl( button_pin2, 2 )

#cv2.namedWindow("img", cv2.WINDOW_KEEPRATIO | cv2.WINDOW_NORMAL)
# cv2.namedWindow("img", cv2.WND_PROP_FULLSCREEN)
# cv2.setWindowProperty("img", cv2.WND_PROP_FULLSCREEN, cv2.cv.CV_WINDOW_FULLSCREEN)

# whileの処理は字下げをするとループの範囲になる（らしい）
while True:
    # GPIO端子の状態を読み込む
    # ボタンを押すと「0」、放すと「1」になる
    # GPIOの状態が0V(0)であるか比較
    if( wiringpi.digitalRead(button_pin1) == 0 ):
        # 0V(0)の場合に表示
        print ("Switch1 ON")
        cv2.imshow('img',img1)
        cv2.waitKey(1000)
    if( wiringpi.digitalRead(button_pin2) == 0 ):
        print ("Swich2 ON")
        cv2.imshow('img',img2)
        cv2.waitKey(1000)
    else:
        print ("Switch OFF")
        cv2.imshow('img',img3)
        cv2.waitKey(1000)
    time.sleep(0.05)

    if cv2.waitKey(-1) &  0xFF == ord('q'):
        break


#excercise 1: Event listener

# from turtle import Turtle,Screen

# timmy = Turtle()
# screen = Screen()

# def move_forward():
#     timmy.forward(10)

# screen.listen()
# screen.onkey(key="space",fun=move_forward)

# screen.exitonclick()

#excercise 2: Make an etch-a-sketch app

# from turtle import Turtle,Screen
# timmy = Turtle()
# screen = Screen()

# def move_forward():
#     timmy.forward(10)

# def move_backward():
#     timmy.backward(10)

# def move_right():
#     timmy.right(10)

# def move_left():
#     timmy.left(10)

# def clear_screen():
#     timmy.clear()
#     timmy.penup()
#     timmy.home()
#     timmy.pendown()

# screen.listen()
# screen.onkey(key="w",fun=move_forward)
# screen.onkey(key="s",fun=move_backward)
# screen.onkey(key="a",fun=move_right)
# screen.onkey(key="d",fun=move_left)
# screen.onkey(key="c",fun=clear_screen)

# screen.exitonclick()

#excercise 3: Build a turtle race

from  turtle import Turtle,Screen
import random

is_race_on = False
screen = Screen()
screen.setup(width = 500,height = 400)
user_input = screen.textinput(title = "Make your Bet", prompt = "Which turtle will win the race? Enter a color: ")
colors = ["red", "orange", "yellow", "green", "blue", "purple"]
all_turtles = []
x=-230
y=-100

for color in colors:
    new_turtle = Turtle(shape = "turtle")
    new_turtle.color(color)
    new_turtle.penup()
    new_turtle.goto(x, y)
    y = y + 40
    all_turtles.append(new_turtle)

if user_input:
    is_race_on = True

while is_race_on:
    for turtle in all_turtles:
        if turtle.xcor() > 230:
            is_race_on = False
            winning_color = turtle.pencolor()
            if winning_color == user_input:
                print(f"You've won! The {winning_color} turtle is the winner!")
            else:
                print(f"You've lost! The {winning_color} turtle is the winner!")
        rand_distance = random.randint(0,10)
        turtle.forward(rand_distance)

screen.exitonclick()


import argparse
import re
import shutil
import time

digit_to_glyph: dict[str, str] = {
    "0": "██████\n██  ██\n██  ██\n██  ██\n██████",
    "1": "   ██ \n  ███ \n   ██ \n   ██ \n   ██ ",
    "2": "██████\n    ██\n██████\n██    \n██████",
    "3": "██████\n    ██\n █████\n    ██\n██████",
    "4": "██  ██\n██  ██\n██████\n    ██\n    ██",
    "5": "██████\n██    \n██████\n    ██\n██████",
    "6": "██████\n██    \n██████\n██  ██\n██████",
    "7": "██████\n    ██\n   ██ \n  ██  \n  ██  ",
    "8": " ████ \n██  ██\n ████ \n██  ██\n ████ ",
    "9": "██████\n██  ██\n██████\n    ██\n █████",
    ":": "  \n██\n  \n██\n  ",
}

CLEAR = "\033[H\033[J"  # Move cursor to top corner and clear screen

def duration(duration_str: str) -> int:
    match = re.search(r"^(?:(\d+)m)?(?:(\d+)s)?$", duration_str)

    if match is None:
        raise ValueError("Invalid duration: {duration_str}")

    minutes, seconds = match.groups(default=0)

    return 60 * int(minutes) + int(seconds)

def get_number_lines(seconds: int) -> list[str]:
    timestamp = f"{seconds//60:02d}:{seconds%60:02d}"
    return [" ".join(line_parts) for line_parts in zip(*[digit_to_glyph[char].splitlines() for char in timestamp])]

def print_full_screen(lines: list[str]) -> None:
    term_width, term_height = shutil.get_terminal_size()
    text_width, text_height = len(lines[0]), len(lines)
    lines_before = (term_height-text_height) // 2
    indentation = (term_width-text_width) // 2

    print(CLEAR, end="")
    print("\n" * lines_before, end="")
    for line in lines:
        print(" " * indentation + line)

def assert_equal(res: object, expected_res: object) -> None:
    assert res == expected_res, f"Wrong result, got:\n\t{res}\nbut expected\n\t {expected_res}"

def main_morsels(countdown: str) -> None:
    seconds = duration(countdown)

    print("\x1b[?25l", end="")  # Hide cursor
    try:
        for remaining_time in range(seconds, -1, -1):
            print_full_screen(get_number_lines(remaining_time))
            time.sleep(1)
    finally:
        print("\x1b[?25h", end="")  # Show cursor

def main_test():
    # Base exercise:
    print("Testing the base exercise.")
    assert_equal(duration("5m"), 300)
    assert_equal(duration("2m30s"), 150)
    assert_equal(duration("5s"), 5)
    assert_equal(duration("10m"), 600)
    try:
        duration("100xy")
        print("Should have raised a ValueError but did not.")
    except ValueError:
        pass

    assert_equal(get_number_lines(15),
                 ["██████ ██████       ██  ██████",
                  "██  ██ ██  ██ ██   ███  ██    ",
                  "██  ██ ██  ██       ██  ██████",
                  "██  ██ ██  ██ ██    ██      ██",
                  "██████ ██████       ██  ██████"])
    assert_equal(get_number_lines(754),
                 ["   ██  ██████    ██████ ██  ██",
                  "  ███      ██ ██     ██ ██  ██",
                  "   ██  ██████     █████ ██████",
                  "   ██  ██     ██     ██     ██",
                  "   ██  ██████    ██████     ██"])

    print("Not testing the bonuses.")
    print("Passed the tests!")

if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument("countdown", type=str, help="Countdown duration, format <min>m<seconds>s")
    parser.add_argument("--local_tests", "-t", action="store_true",
                        help="Use this flag to run some tests on the base exercise.")
    args = parser.parse_args()

    countdown: str = args.countdown
    local_testing: bool = args.local_tests

    if local_testing:
        main_test()
    else:
        main_morsels(countdown)


# Zope2 stuff
EditorRate = "Content Ratings: Editor Rate"
ViewEditorialRating = "Content Ratings: View Editorial Rating"
UserRate = "Content Ratings: User Rate"
ViewUserRating = "Content Ratings: View User Rating"

try:
    # Set some default roles for zope2
    import Products
    from AccessControl.Permission import _registeredPermissions
    from AccessControl.Permission import pname
    from Globals import ApplicationDefaultPermissions

    def setDefaultRoles(permission, roles):
        '''
        Sets the defaults roles for a permission.
        '''
        # XXX This ought to be in AccessControl.SecurityInfo.
        registered = _registeredPermissions
        if permission not in registered:
            registered[permission] = 1
            ac_permissions = getattr(Products, '__ac_permissions__', ())
            Products.__ac_permissions__ = ac_permissions + (
                (permission, (), roles), )
            mangled = pname(permission)
            setattr(ApplicationDefaultPermissions, mangled, roles)

    setDefaultRoles(EditorRate, ('Manager', 'Reviewer'))
    setDefaultRoles(ViewEditorialRating, ('Anonymous', 'Authenticated',))
    setDefaultRoles(UserRate, ('Anonymous', 'Authenticated',))
    setDefaultRoles(ViewUserRating, ('Anonymous', 'Authenticated',))
except ImportError:
    pass


from typing import Optional

class TreeNode:
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right

# O(n) time | O(h) space, h --> height of the tree
class Solution:
    def isBalanced(self, root: Optional[TreeNode]) -> bool:

        def dfs(node):
            if node is None:
                return 0, True
            left, left_balanced = dfs(node.left)
            right, right_balanced = dfs(node.right)
            return (
                1 + max(left, right),
                left_balanced and right_balanced and abs(left - right) <= 1
            )

        _, balanced = dfs(root)
        return balanced


import socket, getopt
from sys import argv, exit

def clientSTREAM(host, port):
    print("TCP Protocol Selected")
    host = host
    port = port
    try:
        client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        client.connect((host, port))
        time = client.recv(1024).decode()
        try:
            print("Time:", time)
        except UnicodeDecodeError:
            print("Error of decoding")
    except socket.error:
        print("Failed to create socket", socket.error)
        exit()

def clientDGRAM(host, port):
    print("UDP Protocol Selected")
    host = host
    port = port
    try:
        client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        client.sendto("".encode(), (host, port))
    except socket.error:
        print("Failed to create socket", socket.error)
        exit()
    client.sendto("".encode(), (host, port))
    time, addr = client.recvfrom(1024).decode()
    try:
        print("Time:", time)
    except UnicodeDecodeError:
        print("Error of decoding")

def main():
    def getOpts():
        try:
            (opts, args) = getopt.getopt(argv[1:], 'h:t:p:', [])
            return opts
        except getopt.GetoptError as err:
            print('Error: ' + str(err))
            exit()
    options = getOpts()
    for (opts, args) in options:
        if opts == '-p':
            port = int(args)
        if opts == '-t':
            protocol = args
        if opts == '-h':
            host = args

    if protocol == "tcp" or protocol == "TCP":
        clientSTREAM(host,port)
    elif protocol == "udp" or protocol == "UDP":
        clientDGRAM(host, port)
    else:
        print("Only enter 'UDP' or 'TCP'")

if __name__ == '__main__':
    main()


# Determinants
# Author: Nagabhushan S N
# Last Modified: 23/02/2022

import numpy

def compute_determinant(matrix: numpy.ndarray):
    m, n = matrix.shape
    assert m == n, "matrix should be square"

    if m == 1:
        determinant = matrix[0,0]
    else:
        determinant = 0
        for i in range(m):
            sub_matrix = numpy.concatenate([matrix[1:, 0:i], matrix[1:, i+1:]], axis=1)
            determinant += ((-1)**i) * matrix[0, i] * compute_determinant(sub_matrix)
    return determinant

def demo1():
    matrix = numpy.random.random(size=(3, 3))
    print(compute_determinant(matrix))
    print(numpy.linalg.det(matrix))
    return

def main():
    demo1()
    return

if __name__ == '__main__':
    main()


# -*- coding: UTF-8 -*-
"""
title: 标记所有元素后数组的分数
You are given an array nums consisting of positive integers.
Starting with score = 0, apply the following algorithm:
    Choose the smallest integer of the array that is not marked. If there is a tie, choose the one with the smallest index.
    Add the value of the chosen integer to score.
    Mark the chosen element and its two adjacent elements if they exist.
    Repeat until all the array elements are marked.
Return the score you get after applying the above algorithm.

Example 1:
Input: nums = [2,1,3,4,5,2]
Output: 7
Explanation: We mark the elements as follows:
- 1 is the smallest unmarked element, so we mark it and its two adjacent elements: [2,1,3,4,5,2].
- 2 is the smallest unmarked element, so we mark it and its left adjacent element: [2,1,3,4,5,2].
- 4 is the only remaining unmarked element, so we mark it: [2,1,3,4,5,2].
Our score is 1 + 2 + 4 = 7.

Example 2:
Input: nums = [2,3,5,1,3,2]
Output: 5
Explanation: We mark the elements as follows:
- 1 is the smallest unmarked element, so we mark it and its two adjacent elements: [2,3,5,1,3,2].
- 2 is the smallest unmarked element, since there are two of them, we choose the left-most one, so we mark the one at index 0 and its right adjacent element: [2,3,5,1,3,2].
- 2 is the only remaining unmarked element, so we mark it: [2,3,5,1,3,2].
Our score is 1 + 2 + 2 = 5.

Constraints:
1 <= nums.length <= 10^5
1 <= nums[i] <= 10^6
"""
from typing import List

class Solution:
    def findScore(self, nums: List[int]) -> int:
        """稳定性排序 + 哈希表"""
        res = 0
        visited = set()
        for num, i in sorted((num, i) for i, num in enumerate(nums)):
            if i not in visited:
                res += num
                # i 本身没必要加入了，因为之后不会再访问i了
                visited.add(i - 1)
                visited.add(i + 1)
        return res

if __name__ == '__main__':
    print(Solution().findScore(nums=[2, 1, 3, 4, 5, 2]))


from Addition import addition
from Subtraction import subtraction
from Division import division

def median(data):
    #data.sort()

    numValues = len(data)
    indexValues = int(subtraction(1, numValues))

    midNum = int(division(2, indexValues))

    if numValues % 2 == 0:
        midNumTwo = int(addition(1, midNum))
        twoMids = addition(data[midNum], data[midNumTwo])
        return division(2, twoMids)
    else:
        return data[midNum]


# -*- coding: utf-8 -*-
"""Created on Wed Oct 28 05:21:08 2020.

@author: ben
"""
import pytest
import logging
import pathlib
import context
from dataclasses import asdict
from typing import List, Dict, Tuple
from palitype.txt_files \
    import build_path, read_file, read_grammar, write_file, readfile
from palitype.strings import camel_to_snake
from palitype.palilex import delimiter_locations
from palitype.palilex import group_into_sections, get_settings
from palitype.db_ref import populate_sections
from palitype.palilex import markup_substitution
from palitype.classes import Delim, ModCounter, Setting
from palitype.constants import VERSE_DELIM

#import lark
#lark.logger.setLevel(logging.DEBUG)
import re
from hypothesis import given
import hypothesis.strategies as st
d = context.set_path()
log_fn = d / 'tests' / 'error.log'
logging.basicConfig(filename=log_fn, level=logging.DEBUG, filemode='w')

# ONLY APPEND NEW TEXT TO THE END OTHERWISE EXISTING TESTS WILL FAIL!!!
def get_pali_shorthand(file_nr: int = 0):
    """Example text.

    Notes:
        1. extra '{' before 'striving' that has no '}'
    """
    _l = (('{', '=', '}'), read_file(f"input_text_{file_nr}.txt", 'tests'))
    return _l

def test_write_read_file():
    """Test read_file()"""

    filename = "test.txt"
    dir_name = pathlib.Path(__file__).parent
    delimiters, text = get_pali_shorthand()
    nr_char = write_file(text, filename, dir_name)
    _fn = build_path(filename, dir_name)
    assert nr_char == len(text) and _fn.is_file()
    file_text = read_file(filename, dir_name)
    logging.info('test')
    assert file_text[0] == text[0]
    _fn.unlink()
    assert not _fn.is_file()

    grammar = read_grammar('restructuredtext.grammar')
    assert grammar[0] == '/'

def test_camel_to_snake():
    """
    Tests:
        Changing camel style strings to snake-style strings.
    """
    test_str = "sectionElement"
    assert camel_to_snake(test_str) == "section_element"
    assert test_str == "sectionElement"
    test_str = "SectionElement"
    assert camel_to_snake(test_str) == "Section_element"
    grammar = read_grammar('restructuredtext.grammar')
    new_grammar = camel_to_snake(grammar)
    assert re.search('comment_line', new_grammar)
    assert re.search('Line_break', new_grammar)

def group_id_loop(delims, tokens):
    counter = -1
    for token in delims:
        if token.str == tokens[-1]:  # end delimiter
            counter += 1
            assert token.group_id == counter
    assert counter > -1

def test_group_sections():
    delimiters, text = get_pali_shorthand()
    delims = delimiter_locations(delimiters, text)
    delims = group_into_sections(delimiters, delims)
    assert len(delims) > 0
    group_id_loop(delims, delimiters)

pattern = re.compile(r".*v=[^=]*?e=[^=]*?p=[^=]*?\.=[^=]*")
verse_pattern = [st.from_regex(pattern, fullmatch=True)]

@given(*verse_pattern)
def test_group_sections2(text):
    delimiters = ['v=', 'e=', "p=", ".="]
    delims = delimiter_locations(delimiters, text)
    delims = group_into_sections(delimiters, delims)
    assert len(delims) > 0
    group_id_loop(delims, delimiters)

@pytest.mark.parametrize('filename, directory',
                         [('palitype_instr_0.yml', 'tests')])
def test_settings(filename, directory):
    yaml_text = read_file(filename, directory)
    delim_dict = get_settings(yaml_text).delim_dict
    assert delim_dict['==.'].tag == "Pali"

@pytest.mark.parametrize(
    'text, text_to_markup, finished_text, tok',
    [("""Appatiṭṭhaṃ khvāhaṃ anāyūhaṃ
[#āyūhaṃ] ogham atari ti.""", """anāyūhaṃ
[#āyūhaṃ]_ ogham atari""", """Appatiṭṭhaṃ khvāhaṃ anāyūhaṃ
[#āyūhaṃ] ogham atari ti.""", '*'),
     ("""e=By not reaching out, is the flood crossed.
      p=Appatiṭṭhaṃ khvāhaṃ anāyūhaṃ [#āyūhaṃ]_ ogham atari.=.i=SN1.1.1
      e=By not reaching out, is the flood crossed.""",
      """Appatiṭṭhaṃ khvāhaṃ anāyūhaṃ [#āyūhaṃ]_ ogham atari.""",
      """e=By not reaching out, is the flood crossed.
      p=*Appatiṭṭhaṃ khvāhaṃ anāyūhaṃ [#āyūhaṃ]_ ogham atari.*=.i=SN1.1.1
      e=By not reaching out, is the flood crossed.""", '*')])
def test_surround(text, text_to_markup, finished_text, tok):

    istart = text.find(text_to_markup)
    iend = istart + len(text_to_markup)
    mu = Delim.surround(tok, text[istart:iend])
    print(mu, istart, iend)
    assert text.replace(text[istart:iend], mu) == finished_text

def verse_line(start_whitesp: str,
               phrases: str,
               end_whitesp: str,
               markup: str = '',
               verse: str = '') -> str:

    return '\n'.join(
        [start_whitesp + verse + markup + p + markup + end_whitesp for p in phrases])

def make_verse(start_whitesp: str,
               phrases: List[str],
               end_whitesp: str,
               m: str = '',
               verse: str = '') -> Tuple[str, str]:
    """Make a verse and its corresponding marked-up version.

    Parameters
    ----------
    start_whitesp : str
    phrases : List[str]
    end_whitesp : str
    m : str
        The token for inline markup.

    Returns
    -------
    test_text : str
        Original text.
    answer : str
        Marked-up version
    """

    answer = verse_line(start_whitesp, phrases, end_whitesp, markup=m, verse=verse)
    test_text = verse_line(start_whitesp, phrases, end_whitesp)
    return test_text, answer

def verse_n_lang(delims: Dict[str, Delim],
                 start_whitesp: str,
                 phrases: List[str],
                 end_whitesp: str,
                 verse: str = '') -> Tuple[str, str]:
    orig_tot = []
    marked_tot = []
    for delim in list(delims.values())[:-1]:
        orig, marked = make_verse(start_whitesp,
                                  phrases,
                                  end_whitesp,
                                  m=delim.inline_markup,
                                  verse=verse)
        orig_tot.append(
            orig.replace(orig.strip(), delim.token + orig.strip(), 1))
        marked_tot.append(marked)
    orig_tot.append(delims[list(delims.keys())[-1]].token)

    return '\n'.join(orig_tot), '\n'.join(marked_tot)

INLINE_MARKUP = '*'

def make_delims(nr_lang: int) -> Dict[str, Delim]:
    """Make `nr_lang` delims plus verse delimiter and end delimiter.

    The first delimiter is the verse delimiter.
    The second last delimiter has inline markup '*'.
    The last delimiter is the end delimiter.

    Parameters
    ----------
    nr_lang : int
        Number of languages.

    Returns
    -------
    delim : Delim
        DESCRIPTION.
    """

    if nr_lang > 24:
        nr_lang = 24
    elif not nr_lang:
        nr_lang = 1
    inline_markup = [''] * (nr_lang + 2)  # extra verse and end delimiters
    inline_markup[-2] = INLINE_MARKUP  # 2nd last delimiter has inline markup
    verse_token = 'VT='
    VERSE_DELIM.token = 'VT='
    delim = {verse_token: Delim(**asdict(VERSE_DELIM))}
    for lang_ix, m in enumerate(inline_markup[1:]):
        ix_s = ord('a') + lang_ix
        token = chr(ix_s) + '='
        delim[token] = (Delim(token=token,
                              tag=''.join(
                                  [chr(i) for i in range(ix_s, ix_s + 3)]),
                              inline_markup=m))
    return delim

phrase_pattern = re.compile(r"[^\s=|]+[ \w]+[^\s=|]+")
white_space_pattern = re.compile(r" +")
verse_pattern = [
    st.from_regex(white_space_pattern, fullmatch=True),
    st.lists(st.from_regex(phrase_pattern, fullmatch=True), min_size=1),
    st.from_regex(white_space_pattern, fullmatch=True)
]

@given(*verse_pattern)  # type: ignore
def test_delim_modify_lines(start_whitesp, phrases, end_whitesp):
    delim = Delim()
    delim.inline_markup = '*'
    test_text, answer = make_verse(start_whitesp, phrases, end_whitesp,
                                   delim.inline_markup)
    mod = ModCounter()
    mod_text = delim.get_modified_lines(test_text, mod)
    assert mod_text == answer
    assert getattr(mod, "inline_markup", 0) == 1

@given(*verse_pattern)  # type: ignore
def test_verse_n(start_whitesp, phrases, end_whitesp):
    settings = Setting({})
    settings.delim_dict = make_delims(2)
    next(iter(settings.delim_dict.values())).tag = 'dont add verse'
    test_text, answer = verse_n_lang(settings.delim_dict, start_whitesp,
                                     phrases, end_whitesp)
    mod = ModCounter()

    delims = list(settings.delim_dict.keys())
    mod_text, mod = markup_substitution(
        settings,
        group_into_sections(delims, delimiter_locations(delims, test_text)),
        test_text)
    assert mod_text == answer

def delims_1(delim_dict):
    tokens = list(delim_dict.keys())
    assert delim_dict[tokens[0]].tag == VERSE_DELIM.tag
    assert delim_dict[tokens[-2]].inline_markup == INLINE_MARKUP
    return

@given(*verse_pattern)  # type: ignore
def test_verse_markup(start_whitesp, phrases, end_whitesp):
    settings = Setting({})
    delim_dict = make_delims(2)
    delims_1(delim_dict)
    test_text, answer = verse_n_lang(delim_dict,
                                     start_whitesp,
                                     phrases,
                                     end_whitesp,
                                     verse='| ')
    mod = ModCounter()
    settings.delim_dict = delim_dict
    delims = list(delim_dict.keys())
    delim_list = group_into_sections(delims,
                                     delimiter_locations(delims, test_text))
    group_id_loop(delim_list, delims)
    mod_text, mod = markup_substitution(settings, delim_list, test_text)
    assert mod_text == answer

@pytest.mark.parametrize('filename, directory, nr_pali',
                         [('palitype_instr_1.yml', 'tests', 3),
                          ('palitype_instr_0.yml', 'tests', 7)])
def test_inline_markup(filename, directory, nr_pali):
    yaml_text = read_file(filename, directory)
    settings = get_settings(yaml_text)
    delim_dict = settings.delim_dict
    _, text = get_pali_shorthand()
    delims = list(delim_dict.keys())
    d = delimiter_locations(delims, text)
    group_into_sections(delims, d)
    mod_text, mod = markup_substitution(settings, d, text)
    assert mod.inline_markup == nr_pali

@pytest.mark.parametrize('filename, directory', [
    ('input_text_0.txt', 'tests'),
])
def test_newlines(filename, directory):
    t, n = readfile(filename, directory)
    assert True


# !/usr/bin/python3
# AdventOfCode2019 - Day10part2

from math import gcd, degrees, atan2

print("Paste the input here and press [Enter] twice: ")
end = ""
data = '\n'.join(iter(input, end)).split("\n")
options = []  # list of maps with potential monitoring locations indicated by O
solutions = []  # list of solutions corresponding to different monitoring locations
nr_asteroids = []  # list containing the number of visible asteroids per monitoring locations

def replace_ch(data, nr_col, nr_row, ch):
    # replaces the character in the data input (list of strings) located at nr_row, nr_col to ch
    line_to_modify = list(data[nr_row])
    line_to_modify[nr_col] = ch
    data[nr_row] = "".join(line_to_modify)
    return data

def generate_coordinate_pairs(absolute_max):
    # generate coordinate pairs that can be used as coordinate offsets relative to a potential monitoring location
    # to identify visible asteroids
    coordinate_pairs = []
    for i in range(1, absolute_max + 1):
        for j in range(i + 1):
            for k in range(4):
                coordinate_pairs.append((i, j))
            if i != j and j != 0:
                for k in range(4):
                    coordinate_pairs.append((j, i))
    # alternate the coordinates
    for i in range(0, len(coordinate_pairs), 2):
        coordinate_pairs[i + 1] = (coordinate_pairs[i + 1][1], coordinate_pairs[i + 1][0])
    # mask them as positive and negative ((+,+); (-,+); (-,-); (+,-))
    for i in range(0, len(coordinate_pairs), 4):
        coordinate_pairs[i + 1] = (-coordinate_pairs[i + 1][0], coordinate_pairs[i + 1][1])
        coordinate_pairs[i + 2] = (-coordinate_pairs[i + 2][0], -coordinate_pairs[i + 2][1])
        coordinate_pairs[i + 3] = (coordinate_pairs[i + 3][0], -coordinate_pairs[i + 3][1])
    return coordinate_pairs

def count_asteroids(data):
    nr = 0
    for i in data:
        nr += i.count("#")
    return nr

def find_O(data):
    nr_row_O, nr_col_O = None, None
    for nr_row, row in enumerate(data):
        for nr_col, column in enumerate(row):
            if data[nr_row][nr_col] == "O":  # locate O
                nr_row_O = nr_row
                nr_col_O = nr_col
                break  # from the inner for first
        if nr_col_O is not None:
            break  # from the outer for as well
    return nr_row_O, nr_col_O

def determine_directions(data, nr_col_O, nr_row_O):
    directions = []
    for nr_row, row in enumerate(data):
        for nr_col, column in enumerate(row):
            if data[nr_row][nr_col] == "#":
                dx = nr_col - nr_col_O
                dy = nr_row - nr_row_O
                q = gcd(dx, dy)
                dx = dx // q
                dy = dy // q
                if (dx, dy, degrees(atan2(dy, dx)) + 90) not in directions:
                    directions.append((dx, dy, degrees(atan2(dy, dx)) + 90))
    for i, direction in enumerate(directions):
        if direction[2] < 0:
            directions[i] = (directions[i][0], directions[i][1], 90 + direction[2] + 270)
    directions.sort(key=lambda x: x[2])
    return directions

def vaporize(data, directions, nr_col_O, nr_row_O):
    vaporization_sequence = []
    while count_asteroids(data) > 0:
        for j in directions:
            x = nr_col_O + j[0]
            y = nr_row_O + j[1]
            while (x <= nr_col_max) and (x >= 0) and (y <= nr_row_max) and (y >= 0):
                if data[y][x] == "#":
                    replace_ch(data, x, y, ".")
                    vaporization_sequence.append((x, y))
                    # this value is just to jump out of the while loop after one asteroid was found & continue rotating
                    j = (-99999999, -9999999)
                x += j[0]
                y += j[1]
    return vaporization_sequence

def solve_map(data):

    def identify_non_visible_asteroids(data, x, y):
        dx = x - nr_col_O
        dy = y - nr_row_O
        q = gcd(dx, dy)
        dx = dx // q
        dy = dy // q

        newX = nr_col_O + dx
        newY = nr_row_O + dy
        while (newX <= nr_col_max) and (newX >= 0) and (newY <= nr_row_max) and (newY >= 0):
            if data[newY][newX] == "#":
                if not (newX == x and newY == y):
                    replace_ch(data, newX, newY, "*")
            newX += dx
            newY += dy
        return data

    nr_row_O, nr_col_O = find_O(data)
    right_max_delta = nr_col_max - nr_col_O
    left_max_delta = nr_col_O
    up_max_delta = nr_row_O
    down_max_delta = nr_row_max - nr_row_O
    absolute_max = max(right_max_delta, left_max_delta, up_max_delta, down_max_delta)
    coordinate_pairs = generate_coordinate_pairs(absolute_max)
    for i in coordinate_pairs:
        if ((nr_col_O + i[0]) <= nr_col_max) and ((nr_col_O + i[0]) >= 0) and \
                ((nr_row_O + i[1]) <= nr_row_max) and ((nr_row_O + i[1]) >= 0):
            if data[nr_row_O + i[1]][nr_col_O + i[0]] == "#":
                data = identify_non_visible_asteroids(data, nr_col_O + i[0], nr_row_O + i[1])
    return data

# generate list of maps with potential monitoring locations indicated by "O"
nr_row_max = len(data) - 1
nr_col_max = len(data[-1]) - 1
for nr_row, row in enumerate(data):
    for nr_col, column in enumerate(row):
        if data[nr_row][nr_col] == "#":
            options.append(data.copy())
            options[-1] = replace_ch(options[-1], nr_col, nr_row, "O")

for option in options:
    solutions.append(solve_map(option))

for solution in solutions:
    nr_asteroids.append(count_asteroids(solution))

nr_row_O, nr_col_O = find_O(solutions[nr_asteroids.index(max(nr_asteroids))])
print("\nThe coordinates of the best monitoring station location: ", "(" + str(nr_col_O) + "," + str(nr_row_O) + ")")
print("The number of asteroids visible from the monitoring station: ", max(nr_asteroids))

laser_map = replace_ch(data, nr_col_O, nr_row_O, "O")

directions = determine_directions(laser_map, nr_col_O, nr_row_O)

vaporization_sequence = vaporize(laser_map, directions, nr_col_O, nr_row_O)
print("The 200th asteroid to be vaporized by the rotating laser is: ", vaporization_sequence[199])
print("The answer is: ", vaporization_sequence[199][0] * 100 + vaporization_sequence[199][1])


import pandas as pd
from datetime import datetime
import backtrader as bt
import Strategy
import sqlite3

#set the period
start = datetime(2020, 1, 1)
end = datetime(2020, 12, 31)
d1=start.strftime('%Y-%m-%d')
d2=end.strftime('%Y-%m-%d')
stock_tag = "MSFT"
#collect to historical data
db = sqlite3.connect('db3.db')
msft = pd.read_sql(con=db, sql=f'SELECT Date, Open, High, Low, Close, Volume  FROM "{stock_tag}" WHERE Date BETWEEN  "{d1}" and "{d2}" ')

msft.index = pd.to_datetime(msft['Date'])
msft['openinterest'] = 0
msft = msft[['Open', 'High', 'Low', 'Close','Volume', 'openinterest']]

#feed the data to dataframe
data = bt.feeds.PandasData(dataname=msft,fromdate=start,todate=end)

#initial the cilent
cerebro = bt.Cerebro()
cerebro.adddata(data)
cerebro.addstrategy(Strategy.OldBuyAndHold)
startCash = 100000
cerebro.broker.setcash(startCash)
cerebro.broker.setcommission(commission=0.0005)
print(f'Initial cash: { startCash }')

cerebro.addanalyzer(bt.analyzers.SharpeRatio, _name = 'SharpeRatio')
cerebro.addanalyzer(bt.analyzers.SQN, _name='SQN')

results = cerebro.run()
portValue = cerebro.broker.getvalue()
netProfit = portValue - startCash
strat = results[0]
print('Final Portfolio Value: %.2f' % portValue)
print('SR:', strat.analyzers.SharpeRatio.get_analysis())
print('SQN:', strat.analyzers.SQN.get_analysis())
print(f'Net Profit: {round(netProfit,2)}')
print(f'Profit Rate: {round(netProfit/startCash,3)}')

cerebro.plot()


import numpy as np
from collections import deque
from tqdm import tqdm_notebook as tqdm
from wutils import prepare_actions, prepare_state
from itertools import combinations
import random
from models.o2actions import o2actions

import torch
import torch.nn as nn
import torch.optim as optim
import torch.nn.functional as F
from torch.autograd import Variable

class BaseComparableModel:
    def __init__(self, name):
        self.name = name

    def __str__(self):
        return self.name

class RandomActionsModel(BaseComparableModel):
    def __init__(self, possible_actions, seq_len=45):
        super(RandomActionsModel, self).__init__("Random Actions with len={}".format(seq_len))
        self.len = seq_len
        self.possible_actions = possible_actions
        self.call_cnt = 0

    def __call__(self, state):
        self.call_cnt += 1
        if self.call_cnt == self.len:
            self.call_cnt = 0
            return "terminal"
        else:
            return np.random.choice(self.possible_actions)

class O2ActionsModel(BaseComparableModel):
    def __init__(self):
        super(O2ActionsModel, self).__init__("O2 Actions")
        self.call_cnt = 0
        self.o2actions = o2actions

    def __call__(self, state):
        action = self.o2actions[self.call_cnt]
        if action == "terminal":
            self.call_cnt = 0
        else:
            self.call_cnt += 1
        return action

class O0ActionsModel(BaseComparableModel):
    def __init__(self):
        super(O0ActionsModel, self).__init__("O0 Actions")

    def __call__(self, state):
        return "terminal"

class DropKeepActorCriticActionsModel(BaseComparableModel):
    def __init__(self, actor_critic, o2dict):
        super(DropKeepActorCriticActionsModel, self).__init__("DropKeepActorCriticActionsModel")
        self.actor_critic = actor_critic
        self.o2dict = o2dict
        self.o2seq = o2actions
        self.step_counter = 0

    def __call__(self, state):
        value, policy_dist = self.actor_critic(torch.tensor(state,
                                                            dtype=torch.long).view(1, len(state)),
                                               torch.tensor(self.o2dict[self.o2seq[self.step_counter]],
                                                            dtype=torch.long).view(1, 1))
        value = value.detach().numpy()[0,0]
        dist = policy_dist.detach().numpy()
        skip = np.random.choice(2, p=np.squeeze(dist))
        if self.step_counter >= len(self.o2seq) - 1:
            action = "terminal"
            self.step_counter = -1
        elif skip:
            action = self.o2seq[self.step_counter]
        else:
            action = "empty"
        self.step_counter += 1
        return action

class SupervisedActionsGenerator(BaseComparableModel):
    """ Generates action sequence given initial state """
    def __init__(self, action_state_estimator, possible_actions,
                 state_vocab, actions_vocab, bpe_order, batch_size, model_action_len=3, pieces=15, state_len_thres=800):
        super(SupervisedActionsGenerator, self).__init__("Supervised Actions with len={} and pieces={}".format(model_action_len,
                                                                                pieces))
        self.model = action_state_estimator
        self.possible_actions = possible_actions
        self.state_vocab = state_vocab
        self.actions_vocab = actions_vocab
        self.bpe_order = bpe_order
        self.model_action_len = model_action_len
        self.pieces = pieces
        self.state_len_thres = state_len_thres
        self.batch_size = batch_size
        self.left_actions = deque()

    def _choose_best_actions(self, state):
        possible_combs = list(combinations(self.possible_actions, self.model_action_len))
        random.shuffle(possible_combs)
        possible_combs = np.array(possible_combs)
        possible_combs = possible_combs[:3200]
        total_size = len(possible_combs)
        model_inp_state, model_inp_lengths = prepare_state(state, self.bpe_order, self.state_vocab,
                                                           self.state_len_thres, repeat=self.batch_size)
        all_estimates = []
        for i in tqdm(range(total_size // self.batch_size)):
            i1 = i * self.batch_size
            i2 = (i + 1) * self.batch_size
            model_inp_actions = prepare_actions(possible_combs[i1:i2], self.actions_vocab)
            estimates = self.model(model_inp_state, model_inp_actions, model_inp_lengths.view(self.batch_size, 1))
            all_estimates.append(estimates.detach().numpy())
        all_estimates = np.concatenate(all_estimates)
        idx = np.argpartition(all_estimates, self.pieces)
        return np.append(np.concatenate(possible_combs[idx[:self.pieces]]), "terminal")

    def __call__(self, state):
        if not self.left_actions:
            best_actions = self._choose_best_actions(state)
            self.left_actions.extend(best_actions)
        next_action = self.left_actions.popleft()
        return next_action


from Config import EXCEL_DIR
from Config import UNITY_TABLE_ROOT_DIR
from Config import UNITY_TABLE_DATA_DIR
from Config import UNITY_TABLE_DATA_EXT
from Config import UINTY_TABLE_USE_RESOURCE_PATH_READ
from Config import UINTY_RESOURCE_PATH_NAME
from Config import UNITY_TABLE_CONFIG_DIR
from Gen.DataGen import DataGen
import os

class UnityDataGen(DataGen):

	# 文件生成函数
	def process(self, filename, fields, table):
		# 创建输出路径
		path = filename.replace(EXCEL_DIR, "")

		if UINTY_TABLE_USE_RESOURCE_PATH_READ == True:
			rootpath = UNITY_TABLE_ROOT_DIR + UINTY_RESOURCE_PATH_NAME
		else:
			rootpath = UNITY_TABLE_ROOT_DIR

		path = rootpath + UNITY_TABLE_DATA_DIR + UNITY_TABLE_CONFIG_DIR + path
		path = os.path.splitext(path)[0]
		path += UNITY_TABLE_DATA_EXT

		# 生成文件目录, 不重复创建目录
		filedir = os.path.dirname(path)
		if os.path.exists(filedir) == False:
			os.makedirs(filedir)

		# 生成数据
		fileContent = ""
		for row in range(5, table.nrows):
			for col in range(table.ncols):
				if col in fields:
					fieldtype = table.cell(2, col).value
					fieldtype = fieldtype.lower()
					fieldvalue = table.cell(row, col).value
					if fieldtype == "int":
						fieldvalue = int(fieldvalue)

					fileContent += ("{0}\t").format(fieldvalue)

			fileContent += "\n"

		# 保存
		file = open(path, "wb")
		file.write(fileContent.encode())
		file.close()


from typing import List

class Solution:
    def grayCode(self, n: int) -> List[int]:
        res_list = []
        res_set = set()

        def inner(root):
            if root in res_set:
                return
            else:
                res_list.append(int(root, 2))
                res_set.add(root)
            if len(res_list) == (2**n):
                return
            for i in range(len(root)):
                temp_val = root[len(root) - i - 1]
                temp_val = "0" if temp_val == "1" else "1"
                temp_root = (
                    root[0 : len(root) - i - 1] + temp_val + root[len(root) - i :]
                )
                inner(temp_root)

        inner("0" * n)

        return res_list


# Write a Python function to calculate the factorial of a number (a nonnegative integer).
# Factorial = 6*5*4*3*2*1

# Function For Find Factorial of Number
def factorial(num):

    factorial = 1
    for i in range(num):
        factorial = factorial * num
        num = num - 1
    print(factorial)

# Taken Input from the user
num = int(input("Enter Factorial of a Number : "))
print("The Factorial of",num,"is : ",end='')
factorial(num)