#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Fri Oct  7 09:42:46 2022

Main code to estimate the committor using one of the methods described in the article.
You can choose either the AMOC or double-gyre model
You can choose of one the 5 methods: AMC, KNN, FFN, DGA or RC

@author: Valerian Jacques-Dumas
"""

import Datasets
import numpy as np
import Machine_Learning, AMC
import matplotlib.pyplot as plt
from NewGen_Reservoir import NewGen_ResNet
import Model_Cimatoribus, Model_wind_driven
from Logarithm_score import LogaScore, diff_score
from Dynamical_Galerkin_Approximation import DynGalApp

# Define both models and needed info to load datasets
C = Model_Cimatoribus.CimatoribusModel()
idx, noise = 60, 0.4
p_c = {"idx":idx, "noise":noise}

sigma = 0.45
beta = 0.198
WD = Model_wind_driven.WindDrivenModel(1, sigma=sigma, beta=beta)
p_wd = {"sigma":sigma, "beta":beta}

Cima = {'model':C, 'params':p_c}
Wind = {'model':WD, 'params':p_wd}

models = {'C':Cima, 'WD':Wind}

Nt = [10, 20, 30, 50, 75, 100, 150, 200, 300, 400, 500]

nb_dataset = 1

# Choose the model to use and the method to use

to_use = "WD"
assert to_use in ["AMOC", "WD"]

method = "Reservoir"
assert method in ["AMC", "KNN", "Feedforward NN", "DGA", "Reservoir"]

#Whether to save the results or not
save = False
dir_data #Directory containing the data
base_dir #Directory containing the results
dirsave = base_dir+models[to_use]['model'].name

# We load the data corresponding to the chosen model
par = models[to_use]['params']
handler =  Datasets.DataHandler(models[to_use]['model'], par, np.max(Nt), nb_dataset, dir_data)
# Load the true committor of the largest dataset to define the climatology of the logarithm score
ref_comm = handler.open_data("Committor")
score = LogaScore(ref_comm)

# Load test dataset
test = handler.open_data("Trajectory", test=True)
true_comm = handler.open_data("Committor", test=True)
lab_test = handler.open_data("Labels", test=True)

# For reference and comparison, the logarithm score of the true committor
# We need its average, 5th and 95th percentile
true_scores = score.get_score(test,true_comm,lab_test)
m, e = np.mean(true_scores), np.percentile(true_scores, [5,95])

# Process of each method

if method == "AMC" or method == "KNN":

    var = ["Sdiff", "Sn", "Ss"] if to_use=="C" else ["A1", "A2", "A3", "A4"]
    K = 25 if to_use=="C" else 10
    norm = False if to_use=="C" else True

    name = "K_"+str(K)+"_"+"_".join(var)+"_"+"_".join([str(e).replace(".",",") for i in range(len(par)) for e in list(par.items())[i]])
    dirsave += "/AMC_KNN/"

    #Initialize method
    amc = AMC.AnaloguesMethod(models[to_use]['model'], K)

    if method == "AMC":
        # Compute committor with AMC only
        possible_analogues = np.arange(np.max(test.shape)-1)
        comm_amc = amc.process_AMC(test, possible_analogues, var, norm=norm)

        # Only retain the estimated committors having values in [0,1]
        idx = []
        for i in range(100):
            if np.all((comm_amc[i]>=0)&(comm_amc[i]<=1)):
                idx.append(i)
        print(len(idx)) #Number of retained trajectories

        # Logarithm score
        score_amc = score.get_score(test[idx], comm_amc[idx], lab_test[idx])
        print(np.mean(score_amc), np.std(score_amc))

        # Difference score
        diff_amc = diff_score(comm_amc[idx], true_comm[idx])
        print(np.mean(diff_amc), np.std(diff_amc))

        # Reshape the scores to make plotting easier (see Plot_results.py)
        score_amc = np.repeat(score_amc[np.newaxis], len(Nt), axis=0)
        diff_amc = np.repeat(diff_amc[np.newaxis], len(Nt), axis=0)
        all_times_amc = np.repeat(amc.all_times[idx][np.newaxis], len(Nt), axis=0)
        print(np.mean(all_times_amc), np.std(all_times_amc))

        if save:
            res_amc = {"logscore": np.round(score_amc,decimals=3),
                        "diffscore": np.round(diff_amc,decimals=3),
                        "time_test": np.round(all_times_amc,decimals=3),
                        "time_train": np.full((len(Nt),len(idx)), np.nan)}
            np.save(dirsave+"AMC"+name, res_amc)

    else:
        # Initialize files to save
        score_knn = np.zeros((len(Nt),100))
        diff_knn = np.zeros((len(Nt),100))
        all_times_knn_train = np.zeros((len(Nt),100))
        all_times_knn_test = np.zeros((len(Nt),100))

        # Estimation loop with KNN
        for i, nt in enumerate(Nt):
            print(nt)
            #Get data
            handler.Nt = nt
            train = handler.open_data("Trajectory")
            possible_analogues = np.arange(np.max(train.shape)-1)

            #Compute committor
            comm_knn = amc.process_KNN(train, test, possible_analogues, var, norm=norm)

            #Compute score
            score_knn[i] = score.get_score(test,comm_knn,lab_test)
            diff_knn[i] = diff_score(comm_knn, true_comm)
            print(np.mean(score_knn[i]), np.std(score_knn[i]))
            print(np.mean(diff_knn[i]), np.std(diff_knn[i]))

            #Save committor, time, score
            all_times_knn_train[i] = np.repeat(amc.time_amc, 100)
            all_times_knn_test[i] = amc.time_knn
            print(amc.time_amc)
            print(np.mean(all_times_knn_test[i]), np.std(all_times_knn_test[i]))

            if save:
                res_knn = {"logscore": np.round(score_knn,decimals=3),
                            "diffscore": np.round(diff_knn,decimals=3),
                            "time_train": np.round(all_times_knn_train,decimals=3),
                            "time_test": np.round(all_times_knn_test,decimals=3)}
                np.save(dirsave+"KNN"+name, res_knn)

elif method == "Feedforward NN":

    var = ["Sdiff", "D"] if to_use=="C" else ["A1", 'A2', "A3", "A4"]

    layers = [64,128,256]
    LR = 1e-4

    dirsave += "/ML/"

    name = "_".join([str(l) for l in layers])+"_LR_"+str(LR).replace(".",",")+"_"+"_".join(var)\
        +"_"+"_".join([str(e).replace(".",",") for i in range(len(par)) for e in list(par.items())[i]])

    #Initialize method
    nb_epochs, nb_runs = 30, 20
    # The directory where to save the best state of the NN after each epoch
    dir_ml = dir_data + "/save_best_state_ml/"
    nn = Machine_Learning.NeuralNetworks(nb_epochs, nb_runs, dir_ml, LR=LR)

    test = models[to_use]['model'].select_var(test, var)

    score_ml = np.zeros((len(Nt),nb_runs,100))
    diff_ml = np.zeros((len(Nt),nb_runs,100))
    all_times_train = np.zeros((len(Nt),nb_runs))
    all_times_test = np.zeros((len(Nt),nb_runs,100))

    # Estimation loop
    for i, nt in enumerate(Nt):
        print(nt)
        #Get data
        handler.Nt = nt
        train, lab_train = handler.open_data("Trajectory"), handler.open_data("Labels")
        # If applicable, reduce set of variables of train data
        train = models[to_use]['model'].select_var(train, var)

        #Compute committor
        comm = nn.process(train, lab_train, test, (len(var),layers))

        #Compute score
        for k in range(nb_runs):
            score_ml[i,k] = score.get_score(test,comm[k],lab_test)
            diff_ml[i,k] = diff_score(comm[k],true_comm)
        print(np.mean(score_ml[i]), np.std(score_ml[i]))
        print(np.mean(diff_ml[i]), np.std(diff_ml[i]))

        print(np.mean(diff_ml[i],axis=1))
        k_max = np.argmax(np.mean(diff_ml[i],axis=1))
        for j in range(10):
            plt.plot(true_comm[j],label="Truth")
            plt.plot(comm[k_max,j],label="Prediction")
            plt.ylabel("Committor", fontsize=13)
            plt.xlabel("Time (arbitrary unit)", fontsize=13)
            plt.legend()
            plt.title("Feedforward Network", fontsize=13)
            plt.show()

        #Save committor, time, score
        all_times_train[i] = nn.all_times_train
        all_times_test[i] = nn.all_times_test

        print(np.mean(nn.all_times_train), np.std(nn.all_times_train))
        print(np.mean(nn.all_times_test), np.std(nn.all_times_test))

        if save:
            res_ml = {"logscore": np.round(score_ml,decimals=3),
                      "diffscore": np.round(diff_ml,decimals=3),
                      "time_train": np.round(all_times_train,decimals=3),
                      "time_test": np.round(all_times_test,decimals=3)}
            np.save(dirsave+name, res_ml)

elif method == "DGA":

    dirsave += "/DGA/"

    var = ["Sdiff", "Sn", "Ss"] if to_use=="C" else ["A1", "A2", "A3", "A4"]

    process = "train_in_test"
    assert process in ["full_train", "no_train", "train_in_test"]
    give_params = True

    d, k_eps0, k_eps = None, None, None
    if give_params:
        if to_use == 'C':
            d, k_eps0, k_eps = 0.45, 15, -15
        else:
            d, k_eps0, k_eps = 0.75, 5, -5

    nb_modes = 10

    dga = DynGalApp(M=nb_modes, d=d, k_eps0=k_eps0, k_eps=k_eps)

    if process == "full_train":

        name = "Full_train_"+str(nb_modes)+"_modes_d_"+str(d).replace('.',',')+\
            "_k_eps0_"+str(k_eps0)+"_k_eps_"+str(k_eps)+"_"+"_".join(var)

        score_dga, diff_dga = np.zeros((len(Nt),test.shape[0])), np.zeros((len(Nt),test.shape[0]))
        time_train_dga, time_test_dga = np.zeros((len(Nt),test.shape[0])), np.zeros((len(Nt),test.shape[0]))

        for i, nt in enumerate(Nt[4:]):
            print(nt)
            handler.Nt = nt
            train = handler.open_data("Trajectory")

            comm_dga = dga.process_DGA(models[to_use]['model'], test, train_traj=train, process=process, var=var)

            score_dga[i] = score.get_score(test, comm_dga, lab_test)
            diff_dga[i] = diff_score(comm_dga, true_comm)
            time_train_dga[i] = np.repeat(dga.time_train, test.shape[0])
            time_test_dga[i] = dga.times_test

            print(np.mean(score_dga[i]), np.std(score_dga[i]))
            print(np.mean(diff_dga[i]), np.std(diff_dga[i]))
            print(dga.time_train)
            print(np.mean(time_test_dga), np.std(time_test_dga))
            print()

            if save:
                res_dga= {"logscore": np.round(score_dga,decimals=3),
                          "diffscore": np.round(diff_dga,decimals=3),
                          "time_train": np.round(time_train_dga,decimals=3),
                          "time_test": np.round(time_test_dga,decimals=3)}
                np.save(dirsave+name, res_dga)

    else:

        nb_transi = 3
        if process == "train_in_test":
            name = "Train_in_test_"+str(nb_transi)+"_transi_"+str(nb_modes)+"_modes_d_"+\
                str(d).replace('.',',')+"_k_eps0_"+str(k_eps0)+"_k_eps_"+str(k_eps)+"_"+"_".join(var)
        else:
            name = "No_train_"+str(nb_modes)+"_modes_d_"+str(d).replace('.',',')+\
                "_k_eps0_"+str(k_eps0)+"_k_eps_"+str(k_eps)+"_"+"_".join(var)

        comm_dga = dga.process_DGA(models[to_use]['model'], test, label=lab_test, N_transi=nt, process=process, var=var)

        score_dga = score.get_score(test, comm_dga, lab_test)
        diff_dga = diff_score(comm_dga, true_comm)

        score_dga = np.repeat(score_dga[np.newaxis], len(Nt), axis=0)
        diff_dga = np.repeat(diff_dga[np.newaxis], len(Nt), axis=0)
        all_times_test_dga = np.repeat(dga.times_test[np.newaxis], len(Nt), axis=0)

        print(np.mean(score_dga), np.std(score_dga))
        print(np.mean(diff_dga), np.std(diff_dga))
        print(np.mean(dga.times_test), np.std(dga.times_test))

        if process == "train_in_test":
            all_times_train_dga = np.repeat(dga.times_train[np.newaxis], len(Nt), axis=0)
            print(np.mean(dga.times_train), np.std(dga.times_train))
        else:
            all_times_train_dga = np.repeat(np.nan, len(Nt))

        if save:
            res_dga = {"logscore": np.round(score_dga,decimals=3),
                        "diffscore": np.round(diff_dga,decimals=3),
                        "time_test": np.round(all_times_test_dga,decimals=3),
                        "time_train": np.round(all_times_train_dga,decimals=3)}
            np.save(dirsave+name, res_dga)

elif method == "Reservoir":

    var = ["Sdiff", "Sn", "Ss", "D"] if to_use=="C" else ["A1", "A2", "A3", "A4"]
    if to_use == 'C':
        config = {'k':3, 's':1, 'p':4, 'alpha':1e-9}
    else:
        config = {'k':2, 's':1, 'p':6, 'alpha':1e-6}

    dirsave += "/Reservoir/"
    name = "New_generation_"+"_".join(var)+"_"+"_".join([str(e).replace(".",",") for i in range(len(config)) for e in list(config.items())[i]])

    test = models[to_use]['model'].select_var(test, var)

    score_res, diff_res = np.zeros((len(Nt),100)), np.zeros((len(Nt),test.shape[0]))
    time_train_res, time_test_res = np.zeros(len(Nt)), np.zeros((len(Nt),test.shape[0]))

    for i, nt in enumerate(Nt):
        print(nt)
        handler.Nt = nt
        train, train_comm = handler.open_data("Trajectory"), handler.open_data("Committor")
        train = models[to_use]['model'].select_var(train, var)

        esn = NewGen_ResNet(config['k'], config['s'], config['p'], config['alpha'])
        pred_test = esn.process(train, train_comm, test)
        pred_test[pred_test>1], pred_test[pred_test<0] = 1, 0

        score_res[i] = score.get_score(test, pred_test, lab_test)
        diff_res[i] = diff_score(pred_test, true_comm)
        time_train_res[i] = esn.time_train
        time_test_res[i] = esn.times_test

        for j in range(10):
            plt.plot(true_comm[j],label="Truth")
            plt.plot(pred_test[j], label="NGRN estimate")
            plt.ylabel("Committor", fontsize=13)
            plt.xlabel("Time (arbitrary unit)", fontsize=13)
            plt.legend()
            plt.title("New Generation Reservoir Computing", fontsize=13)
            plt.show()

        m_log, e_log = np.mean(score_res[i]), np.percentile(score_res[i], [5,95])
        m_diff, e_diff = np.mean(diff_res[i]), np.percentile(diff_res[i], [5,95])
        m_test, e_test = np.mean(time_test_res[i]), np.percentile(time_test_res[i], [5,95])
        print(m_log, e_log[0], e_log[1])
        print(m_diff, e_diff[0], e_diff[1])
        print(time_train_res[i])
        print(m_test, e_test[0], e_test[1])
        print()

    if save:
        res_rl= {"logscore": np.round(score_res,decimals=3),
                  "diffscore": np.round(diff_res,decimals=3),
                  "time_train": np.round(time_train_res,decimals=3),
                  "time_test": np.round(time_test_res,decimals=3)}
        np.save(dirsave+name, res_rl)


# Dynamic Programming Solution with Memoization

class Solution:
    def uniquePathsWithObstacles(self, obstacleGrid) -> int:
        self.Memo = {}
        return self.Unique(obstacleGrid)

    def Unique(self, obstacleGrid, m=0, n=0) -> int:
        if (m, n) in self.Memo:
            return self.Memo[(m, n)]
        if obstacleGrid[0][0] == 1:
            return 0
        if m == len(obstacleGrid) - 1 and n == len(obstacleGrid[0]) - 1:
            if obstacleGrid[m][n] != 1:
                return 1
            else:
                return 0
        Tot = 0
        if m + 1 < len(obstacleGrid) and obstacleGrid[m + 1][n] != 1:
            Tot = Tot + self.Unique(obstacleGrid, m + 1, n)
        if n + 1 < len(obstacleGrid[0]) and obstacleGrid[m][n + 1] != 1:
            Tot = Tot + self.Unique(obstacleGrid, m, n + 1)
        self.Memo[(m, n)] = Tot
        return Tot


from nornir import InitNornir
from nornir_napalm.plugins.tasks import napalm_get
from nornir_utils.plugins.functions import print_result
from rich import print as rprint

nr = InitNornir(config_file="config.yaml")

def pull_interfaces_info(task):
    interfaces_result = task.run(task=napalm_get, getters=["get_facts"])
    task.host["facts"] = interfaces_result.result
    uptime = task.host["facts"]["get_facts"]["uptime"]
    model = task.host["facts"]["get_facts"]["vendor"]
    if model == "Juniper":
        rprint(f"{task.host} is a [green]Juniper[/green] device (uptime {uptime})")

    elif model == "Cisco":
        rprint(f"{task.host} is a [yellow]Cisco[/yellow] device (uptime {uptime})")

results = nr.run(task=pull_interfaces_info)
# print_result(results)


import json
import numpy as np
from tqdm import tqdm
import argparse

def get_args():
    parser = argparse.ArgumentParser()
    parser.add_argument('--data_file', type=str, required=True)
    parser.add_argument('--top_n', type=int, required=True)
    args = parser.parse_args()
    return args

def main():
    args = get_args()
    correct_lst = []
    M = args.top_n
    with open(args.data_file) as f:
        for line in tqdm(f):
            item = json.loads(line)
            gold_tables = item['table_id_lst']
            ctx_lst = item['ctxs']
            labels = [int(a['tag']['table_id'] in gold_tables) for a in ctx_lst]
            correct = max(labels[:M])
            correct_lst.append(correct)

    result = np.mean(correct_lst) * 100

    print('p@%s=%.2f' % (M, result))

if __name__ == '__main__':
    main()


import subprocess
import os
import sys
import pystray
import json
import PIL
import PIL.Image
import pyautogui as pag
import ctypes

ctypes.windll.kernel32.SetConsoleTitleW("Cengrum")

def restart_program_fromSysTray(icon, item):
    icon.stop()
    os.execl(sys.executable, sys.executable, *sys.argv)

def quit_program_fromSysTray(icon, item):
    icon.stop()
    os._exit(0)

iconpath = "favicon.ico"
im = PIL.Image.open(iconpath)

def run_program_in_new_window(icon, filepath):
    def real_run_program_in_new_window_func(icon):
        try:
            subprocess.Popen([filepath], shell=True, cwd = os.path.dirname(filepath))
        except Exception as e:
            print(e)
            if type(e).__name__ == "FileNotFoundError":
                pag.alert(text = f"{filepath} not found.", title = "Cengrum")
            else:
                pag.alert(text = e, title = "Cengrum - Error")
    return real_run_program_in_new_window_func

def update_paths():
    if not os.path.isfile("paths.json"):
        f = open("paths.json",'w')
        f.write('{\n\n\n}')
    f = open("paths.json",'r')
    filepaths = json.loads(f.read())
    return filepaths

def build_submenu(filepaths):
    menu = tuple()
    for program_name in list(filepaths.keys()):
        menu =  pystray.Menu(*menu, pystray.MenuItem(program_name, run_program_in_new_window(iconpath, filepaths[program_name])))
    return menu

filepaths_dict = update_paths()
submenu = build_submenu(filepaths_dict)
print(submenu)

def open_pathsjsonfile():
    subprocess.check_output(["notepad.exe", "paths.json"])
    restart_program_fromSysTray(icon, None)

icon_menu = pystray.Menu(
    pystray.MenuItem(
        'Run programs',
        submenu),
    pystray.MenuItem(
        'Add programs',
        open_pathsjsonfile),
    pystray.MenuItem('Restart',
        restart_program_fromSysTray),
    pystray.MenuItem(
        'Quit',
        quit_program_fromSysTray))

icon = pystray.Icon("cengrum-icon",im,"Cengrum", menu=icon_menu)
icon.run()


import json
from collections import defaultdict

with open('../data/flatt_from_openre.json', 'r') as file:
    data = json.load(file)

def remove_empty_dicts(data):
    if isinstance(data, dict):
        # Create a copy of the dictionary to avoid modifying it while iterating
        data_copy = data.copy()

        for key, value in data_copy.items():
            # Recursively call the function to handle nested dictionaries
            if isinstance(value, dict):
                data_copy[key] = remove_empty_dicts(value)

        # Remove keys with empty dictionaries
        return {key: value for key, value in data_copy.items() if value != {}}
    else:
        # For non-dictionary data types, return the value as is
        return data

final_doc = []

grouped_data = defaultdict(list)
for i in data:
    nested_json = {}  # Create a new dictionary for each record
    for key, value in i.items():
        if value is not None:
            key = key.replace('_ - ', '')
            keys = key.split(" - ")  # Split the key into nested levels
            current_level = nested_json
            for k in keys[:-1]:
                current_level = current_level.setdefault(k, {})
            if value is not None:
                if value != {}:
                    current_level[keys[-1]] = value
    grouped_data[nested_json.get('@id')].append(nested_json)
def merge(grouped_data):
    merged_data = []
    for id_group in grouped_data.values():
        merged_doc = {}
        for doc in id_group:
            for key, value in doc.items():
                if key not in merged_doc:
                    # Key does not exist in merged_doc, add it
                    merged_doc[key] = value
                elif merged_doc[key] != value:
                    # Key exists but with different values, convert to a list
                    if not isinstance(merged_doc[key], list):
                        merged_doc[key] = [merged_doc[key]]
                    merged_doc[key].append(value)
        merged_data.append(merged_doc)
    return merged_data
merged_data = merge(grouped_data)

# Convert the nested JSON structure to a JSON string and write it to a file
with open('restructure_from_flat.json', 'w') as file:
    json.dump(merged_data, file, indent=2)


from authority import authority
import requests, time
from utils.utils import check_responseSuccess, check_requestSuccess,  jsonText_2_list_class, jsonText_2_dict_class, logger_debugging
from utils.coinpairs import COINPAIRS
from typing import List, Tuple

URL_BASE = 'https://openapi.bitfront.me'
coinpairs = COINPAIRS()

def get_balances(ID)->Tuple[bool, List]:
    logger_debugging.debug('run')
    request_path='/v1/account/balances'
    parameter={}
    method='GET'
    req = _send_request(request_path, parameter, method, ID)
    if check_requestSuccess(req):
        response = jsonText_2_list_class(req.text)
        if check_responseSuccess(response):
            logger_debugging.debug('success')
            return True, response.responseData
    return False, []

def get_balance(ID, coin)->Tuple[bool, dict]:
    logger_debugging.debug(f'getting balance of {coin}')
    flag, list_balance = get_balances(ID)
    if not flag:
        return False, {}
    for balance_info in list_balance:
        if balance_info.currency == coin:
            logger_debugging.debug(f'{balance_info}')
            return True, balance_info
    return False, {}

def get_order_info(ID, orderID)->Tuple[bool, dict]:
    logger_debugging.debug('run')
    request_path=f'/v2/account/orders/{orderID}'
    parameter={
    }
    method='GET'
    req = _send_request(request_path, parameter, method, ID)
    if check_requestSuccess(req):
        response = jsonText_2_dict_class(req.text)
        if check_responseSuccess(response):
            logger_debugging.debug('success')
            return True, response.responseData
    return False, {}

def get_all_orders_info(ID, coinPair, max=100)->Tuple[bool, List]:
    logger_debugging.info('run')
    request_path='/v1/trade/openOrders'
    method='GET'
    if not coinpairs.check_exist(coinPair):
        logger_debugging.warning(f'no such pair of {coinPair}')
        return False, []
    currency, market = coinPair.split('.')
    parameter={
        'market':market,
        'currency':currency,
        'max':max
    }
    req = _send_request(request_path, parameter, method, ID)
    if check_requestSuccess(req):
        response = jsonText_2_list_class(req.text)
        if check_responseSuccess(response):
            list_order = response.responseData
            if len(list_order) == max:
                logger_debugging.warning(f'{max} order was got, but it may have more')
            logger_debugging.info('success')
            return True, list_order
    return False, []

def buy(ID, coinPair, quantity, price)->Tuple[bool,str]:
    logger_debugging.debug('run')
    orderSide='BUY'
    request_path = '/v1/trade/limitOrders'
    parameter = {
        'quantity':quantity,
        'coinPair':coinPair,
        'price':price,
        'orderSide':orderSide
    }
    method = 'POST'
    if not coinpairs.check_exist(coinPair):
        return False, ''
    req = _send_request(request_path, parameter, method, ID)
    if check_requestSuccess(req):
        response = jsonText_2_dict_class(req.text)
        if check_responseSuccess(response):
            orderID = response.responseData.orderID
            logger_debugging.info(f'{coinPair} buy {quantity} at {price} - {orderID}')
            return True, orderID
    return False, ''

def buy_direct(ID, coinPair, quantity) ->Tuple[bool, str]:
    logger_debugging.debug('run')
    orderSide='BUY'
    request_path = '/v1/trade/marketOrders'
    parameter = {
        'quantity':quantity,
        'coinPair':coinPair,
        'orderSide':orderSide
    }
    method = 'POST'
    if not coinpairs.check_exist(coinPair):
        return False, ''
    req = _send_request(request_path, parameter, method, ID)
    if check_requestSuccess(req):
        response = jsonText_2_dict_class(req.text)
        if check_responseSuccess(response):
            orderID = response.responseData.orderID
            logger_debugging.info(f'{coinPair} buy {quantity} - {orderID}')
            return True, orderID
    return False, ''

def sell(ID, coinPair, quantity, price)->Tuple[bool,str]:
    logger_debugging.debug('run')
    orderSide='SELL'
    request_path = '/v1/trade/limitOrders'
    parameter = {
        'quantity':quantity,
        'coinPair':coinPair,
        'price':price,
        'orderSide':orderSide
    }
    method = 'POST'
    if not coinpairs.check_exist(coinPair):
        return False, ''
    req = _send_request(request_path, parameter, method, ID)
    if check_requestSuccess(req):
        response = jsonText_2_dict_class(req.text)
        if check_responseSuccess(response):
            orderID = response.responseData.orderID
            logger_debugging.info(f'{coinPair} sell {quantity} at {price} - {orderID}')
            return True, orderID
    return False, ''

def sell_direct(ID, coinPair, quantity)->Tuple[bool, str]:
    logger_debugging.info('run')
    orderSide='SELL'
    request_path = '/v1/trade/marketOrders'
    parameter = {
        'quantity':quantity,
        'coinPair':coinPair,
        'orderSide':orderSide
    }
    method = 'POST'
    if not coinpairs.check_exist(coinPair):
        return False, ''
    req = _send_request(request_path, parameter, method, ID)
    if check_requestSuccess(req):
        response = jsonText_2_dict_class(req.text)
        if check_responseSuccess(response):
            orderID = response.responseData.orderID
            logger_debugging.info(f'{coinPair} sell {quantity} - {orderID}')
            return True, orderID
    return False, ''

def cancel(ID, orderID, time_interval=0.5, timeout=2)->bool:
    logger_debugging.info('run')
    request_path=f'/v1/trade/orders/{orderID}'
    parameter={}
    method='DELETE'
    req = _send_request(request_path, parameter, method, ID)
    if check_requestSuccess(req):
        response = jsonText_2_dict_class(req.text)
        if check_responseSuccess(response):
            if _check_cancel(ID, orderID, time_interval, timeout):
                return True
    return False

def _check_cancel(ID, orderID, time_interval, timeout):
    current_time = 0
    while current_time < timeout:
        time.sleep(time_interval)
        current_time += time_interval
        flag, order_info = get_order_info(ID, orderID)
        if not flag:
            logger_debugging.warning(f'fail to check order {orderID}')
            return False
        initialRequestAmount = order_info.initialRequestAmount
        remainAmount = order_info.remainAmount
        filledAmount = order_info.filledAmount
        orderSide = order_info.orderSide
        if filledAmount + remainAmount < initialRequestAmount:
            logger_debugging.info(f'Success - canceled {orderSide} {initialRequestAmount - filledAmount} / {initialRequestAmount}')
            return True
    return False

def cancel_all(ID, coinPair:str, time_interval=0.5, timeout=2)->bool:
    logger_debugging.info('run')
    if not coinpairs.check_exist(coinPair):
        return False
    request_path=f'/v1/trade/openOrders/{coinPair}'
    parameter={}
    method='DELETE'
    req = _send_request(request_path, parameter, method, ID)
    if check_requestSuccess(req):
        response = jsonText_2_dict_class(req.text)
        if check_responseSuccess(response):
            if _check_cancel_all(ID, coinPair, time_interval, timeout):
                return True
    return False

def _check_cancel_all(ID, coinPair, time_interval, timeout):
    current_time = 0
    while current_time < timeout:
        time.sleep(time_interval)
        current_time += time_interval
        flag, list_order = get_all_orders_info(ID, coinPair)
        if not flag:
            logger_debugging.warning('fail to check cancel all')
            return False
        if len(list_order) == 0 :
            logger_debugging.info(f'Success all order from {coinPair} is canceled')
            return True
    logger_debugging.warning(f'"Cancel All" requested, but {len(list_order)} orders remained')
    return False

def _send_request(request_path, parameter, method, ID):
    headers = authority.get_headers(request_path, parameter, method, ID=ID)
    data = authority.reformat_parameter(parameter)
    if method == 'GET':
        url = f'{URL_BASE}{request_path}?{data}'
        req = requests.get(url, headers=headers, data=data)
    elif method == 'POST':
        url = f'{URL_BASE}{request_path}'
        req = requests.post(url, headers=headers, data=data)
    elif method == 'DELETE':
        url = f'{URL_BASE}{request_path}?{data}'
        req = requests.delete(url, headers=headers, data=data)
    return req


resultado = requests.get(url_base.format(1))

sopa= bs4.BeautifulSoup(resultado.text, 'lxml')

libros = sopa.select('.product_pod')

rating = libros[0].select('.star-rating.Four')
titulo = libros[1].select('a')[1]['title']

print(libros)


import apache_beam as beam
import typing
import logging
from helper.argparser import RunParam
import glob
import boto3
from azure.storage.blob import BlobServiceClient
from helper.secret import get_secret
from source_sink import GCSConnector, SFTPConnector
import pandas as pd

class ListFiles(beam.DoFn):
    def _list_files_gcs(self, source: str) -> list:
        bucket_name = source.split('/')[2]
        path_components = source.split('/')
        file_path = '/'.join(path_components[3:-1])
        file_pattern = path_components[-1]
        connector = GCSConnector(bucket_name)
        return connector.list_file(file_path, file_pattern)

    def _list_file_s3(self, source: str, sink_connection_secret: str) -> list:
        secret = get_secret(sink_connection_secret)
        s3 = boto3.resource('s3', **secret)
        bucket_name = source.split('/')[2]
        interface = source.split('/')[0]
        bucket = s3.Bucket(bucket_name)
        obj_list = bucket.objects.filter(Prefix='/'.join(source.split('/')[3:]))
        return [f'{interface}://{bucket_name}/{obj.key}' for obj in obj_list]

    def _list_file_azure(self, source: str, sink_connection_secret: str) -> list:
        secret = get_secret(sink_connection_secret)
        blob_service_client = BlobServiceClient.from_connection_string(source, **secret)
        container_name = source.split('/')[2]
        interface = source.split('/')[0]
        container_client = blob_service_client.get_container_client(container_name)
        blob_list = container_client.list_blobs(name_starts_with='/'.join(source.split('/')[3:]))
        return [f'{interface}://{container_name}/{blob.name}' for blob in blob_list]

    def _list_file_sftp(self, source: str, sink_connection_secret: str) -> list:
        secret = get_secret(sink_connection_secret)
        connector = SFTPConnector(secret)
        path_components = source.split('/')
        file_path = "/".join(path_components[2:-1]) + "/"
        file_pattern = path_components[-1]
        connector.close_connection()
        return connector.list_files(file_path, file_pattern)

    def _list_file_local(self, source: str) -> list:
        return glob.glob(source)

    def _choose_storage_service(self, source: str, sink_connection_secret: str):
        if source.startswith('gs://'):
            return self._list_files_gcs(source)
        elif source.startswith(('s3://', 's3a://', 's3n://')):
            return self._list_file_s3(source, sink_connection_secret)
        elif source.startswith(('az://', 'abfs://', 'abfss://')):
            return self._list_file_azure(source, sink_connection_secret)
        elif source.startswith(('sftp://', 'ftp://')):
            return self._list_file_sftp(source, sink_connection_secret)
        else:
            return self._list_file_local(source)

    def process(self, context: RunParam):
        # Extract info from context
        source = context.source
        source_connection_secret = context.source_connection_secret
        files_list = self._choose_storage_service(source, source_connection_secret)
        logging.info(f"Found {len(files_list)} files matched with pattern {source}")
        return files_list

class ReadCsv(beam.DoFn):
    def __init__(self, source_sink: RunParam, *args, **kwargs) -> None:
        super().__init__(*args, **kwargs)
        self.source_sink = source_sink

    def process(self, context: str):
        # Extract info from attribute & context
        file_path = context
        run_param = self.source_sink

        # Extract info from run_param
        source_connection_secret = run_param.source_connection_secret
        pipeline_options = run_param.pipeline_options
        read_options = pipeline_options.get('read_options', {})

        # Read and return result as pd.DataFrame
        logging.info(f"Reading data from {file_path}")
        if file_path.startswith('sftp://'):
            file_path = file_path.replace('sftp://', '')
            connector = SFTPConnector(get_secret(source_connection_secret))
            df = connector.read_csv(file_path, read_options)
            connector.close_connection()
        else:
            df = pd.read_csv(file_path, **read_options)
        yield df


# -*- coding: utf-8 -*-
"""
Created on Thu Mar 16 10:32:31 2023

@author: Harisudhan Ramaswamy
"""
import cv2
import numpy as np
import time

# recording from camera (input)
vid = cv2.VideoCapture(0)

timeout = time.time() + 60*1   # 1 minute from now

# loop runs for given time (ie) 1 min

while True:
    test = 0
    # capturing the current frame
    _, frame = vid.read()

    # displaying the current frame
    cv2.imshow("frame", frame)

    # setting values for base colors
    b = frame[:, :, :1]
    g = frame[:, :, 1:2]
    r = frame[:, :, 2:]

    # computing the mean
    b_mean = np.mean(b)
    g_mean = np.mean(g)
    r_mean = np.mean(r)

    # here i shall only display the most prominent color in the frame
    if (b_mean > g_mean and b_mean > r_mean):
        print("Blue")
    if (g_mean > r_mean and g_mean > b_mean):
        print("Green")
    else:
        print("Red")

    if test == 1 or time.time() > timeout:
        print("Program ended....")
        break
    test = test - 1


# -*- coding: utf-8 -*-
"""
Created on Wed Aug 06 17:51:05 2014

@author: Gael P Alamancos
@email: gael.perez[at]upf.edu
"""

import fileMerger as joinFiles
import psiPerGene as psiPerIsoform
import psiCalculator as psiPerEvent
import eventGenerator as generateEvents
import eventClusterer as clusterAnalysis
import significanceCalculator as diffSplice
import logging
import argparse
import sys

description = "Description:\n\n" + \
              "SUPPA allows you to generate all the possible Alternative Splicing events from an annotation file, \n" \
              "calculate the PSI values per event, calculate differential splicing across multiple conditions \n" \
              "with replicates, and cluster events across conditions \n" \
              "For further information, see the help of each subcommand."

parser = argparse.ArgumentParser(description=description, formatter_class=argparse.RawTextHelpFormatter, prog='SUPPA')
# Version
parser.add_argument('-v','--version', action='version', version='%(prog)s 2.3')
subparsers = parser.add_subparsers()

# EventGenerator parser
eventGeneratorSubparser = subparsers.add_parser(
    "generateEvents", parents=[generateEvents.parser],
    help="Calculates the Alternative Splicing events from an annotation file.")
eventGeneratorSubparser.set_defaults(which="generateEvents")

# psiCalculator parser
psiCalculatorSubparser = subparsers.add_parser(
    "psiPerEvent", parents=[psiPerEvent.parser],
    help="Calculates the PSI value for each event previously generated.")
psiCalculatorSubparser.set_defaults(which="psiPerEvent")

# psiPerGene parser
psiPerGeneSubparser = subparsers.add_parser(
    "psiPerIsoform", parents=[psiPerIsoform.parser],
    help="Calculates the PSI value for each isoform.")
psiPerGeneSubparser.set_defaults(which="psiPerIsoform")

# significanceCalculator parser
significanceCalculatorSubparser = subparsers.add_parser(
    "diffSplice", parents=[diffSplice.parser],
    help="Calculates differentially spliced events across multiple conditions.")
significanceCalculatorSubparser.set_defaults(which="diffSplice")

# eventClusterer parser
eventClustererSubparser = subparsers.add_parser(
    "clusterEvents", parents=[clusterAnalysis.parser],
    help="Calculates clusters of events across conditions.")
eventClustererSubparser.set_defaults(which="clusterEvents")

# fileMerger parser
fileMergerSubparser = subparsers.add_parser(
    "joinFiles", parents=[joinFiles.parser],
    help="Join multiple tab separated files into a single file.")
fileMergerSubparser.set_defaults(which="joinFiles")

# Setting logging preferences
logger = logging.getLogger(__name__)

def main():

    if len(sys.argv) == 1:
        parser.print_help()
        sys.exit(1)

    try:
        args = parser.parse_args()
        if args.which == "generateEvents":
            generateEvents.parser = parser  # Setting the module aparser
            generateEvents.main()
        elif args.which == "psiPerEvent":
            psiPerEvent.parser = parser  # Setting the module parser
            psiPerEvent.main()
        elif args.which == "psiPerIsoform":
            psiPerIsoform.parser = parser  # Setting the module parser
            psiPerIsoform.main()
        elif args.which == "diffSplice":
            diffSplice.parser = parser  # Setting the module parser
            diffSplice.main()
        elif args.which == "clusterEvents":
            clusterAnalysis.parser = parser  # Setting the module parser
            clusterAnalysis.main()
        elif args.which == "joinFiles":
            joinFiles.parser = parser  # Setting the module parser
            joinFiles.main()
    except Exception:
        logger.error("Unknown error: {}".format(sys.exc_info()))
        sys.exit(1)

if __name__ == '__main__':
    main()


"""
variable : A name which can store a value
     in python there is no need to declare any variable

     e.g.... name = "python" here , name is a variable name and python is a value
     """
num1 = 56
num2 = 20

print(num1 + num2)


#!/usr/bin/python3
# <xbar.title>CoreAudio Samplerate Display</xbar.title>
# <xbar.version>v1.0</xbar.version>
# <xbar.author>Anthony Lauzon</xbar.author>
# <xbar.author.github>anthonylauzon</xbar.author.github>
# <xbar.desc>Displays current samplerate for an audio device.</xbar.desc>
# <xbar.dependencies>bash</xbar.dependencies>
# <xbar.abouturl></xbar.abouturl>

import json
import os

gFileName = "/Users/mmora/audiodevice.txt"

itemsWalked = 0
indentCount = 0
logOutput = False
gInUSBDeviceNode = False
incAmt = 0
hasidProductNameString = False
hasidVendorNameString = False
hasIOAudioEngineGlobalUniqueID = False
hasAudioClassNum = False
hasIOAudioDeviceName = False
gInUSBDeviceNode = False
gInIOAudioDevice = False
gInIOAudioEngine = False
AMSCommand = '| param1="/System/Applications/Utilities/Audio\ MIDI\ Setup.app" '

def printFoundItem(in_item,in_str):
    print(f'{in_item}: {in_str}')
# ----------------------------------------------------------------------------------------------------------------
# function for looking for our USB Audio components and properties
# ----------------------------------------------------------------------------------------------------------------

def findOurComponents(item, key, node):
    global hasidProductNameString
    global hasidVendorNameString
    global hasIOAudioEngineGlobalUniqueID
    global hasAudioClassNum
    global hasIOAudioDeviceName
    global gInUSBDeviceNode
    global gInIOAudioDevice
    global gInIOAudioEngine

    if '_name' in key:  # logic is wrong here. It should look for a key that is only in a USB audio device node then iterate finding values.
        keyContents = item

        for usb_items, usb_value in node.items():
            if isinstance(usb_value, bytes):
                value_str = usb_value.decode('latin-1')
            else:
                value_str = str(usb_value)

            if '_name' == usb_items:

                if value_str != "coreaudio_device":
                    print("---")
                    value_str += "| shell=open " + AMSCommand

                    printFoundItem('Name', value_str )
                continue

            if '_properties' == usb_items:
                if value_str == "coreaudio_default_audio_system_device":
                    printFoundItem(":bell: Default System Alert Device", "Yes")
                else:
                    printFoundItem("Properties", value_str)

                continue
            if 'coreaudio_input_source' == usb_items:
                if value_str == "spaudio_default":
                    value_str = "Default"
                printFoundItem("Input Source", value_str)
                continue
            if 'coreaudio_output_source' == usb_items:
                if value_str == "spaudio_default":
                    value_str = "Default"
                printFoundItem("Output Source", value_str)
                continue
            if 'coreaudio_device_transport' == usb_items:
                tmpStr = ""
                if value_str == "coreaudio_device_type_AVB":
                    tmpStr = "AVB"
                if value_str == "coreaudio_device_type_firewire":
                    tmpStr = "Firewire"
                if value_str == "coreaudio_device_type_usb":
                    tmpStr = "USB"
                if value_str == "coreaudio_device_type_displayport":
                    tmpStr = "DisplayPort"
                if value_str == "coreaudio_device_type_builtin":
                    tmpStr = "Built-in"

                printFoundItem("Transport", tmpStr)

                continue
            if 'coreaudio_default_audio_output_device' == usb_items:

                if value_str == "spaudio_yes":
                    printFoundItem(":speaker: Default Output Device", "Yes")

                continue
            if 'coreaudio_default_audio_input_device' == usb_items:

                if value_str == "spaudio_yes":
                    printFoundItem(":microphone: Default Input Device", "Yes")

                continue
            if 'coreaudio_default_audio_system_device' == usb_items:
                if value_str == "spaudio_yes":
                    printFoundItem("Default System Output Device", "Yes")
                continue
            if 'coreaudio_device_manufacturer' == usb_items:
                printFoundItem("Manufacturer", value_str)

                continue
            if 'coreaudio_device_srate' == usb_items:
                printFoundItem("Current Sample Rate", value_str)
                continue
            if 'coreaudio_device_output' == usb_items:
                printFoundItem("Output Channels", value_str)
                continue
            if 'coreaudio_device_input' == usb_items:
                printFoundItem("Input Channels", value_str)
                continue

    return

# ----------------------------------------------------------------------------------------------------------------
# function for walking the plist and looking for USB audio
# components in a ioreg dump in plist format
# ----------------------------------------------------------------------------------------------------------------
def walk(node):
    global itemsWalked
    global indentCount
    global logOutput
    global gInUSBDeviceNode
    global incAmt

    try:
        pad = ' '

        indentCount += incAmt
        for key, item in node.items():
            # print(indentCount * pad + '%s :' % key) if logOutput else None
            keyStr = indentCount * pad + '%s' % key
            if isinstance(item, dict):
                print('%s {' % keyStr) if logOutput else None
                walk(item)
                print(indentCount * pad + '};') if logOutput else None
            if isinstance(item, list):
                printKeyStr = True
                for index, val in enumerate(item):
                    if isinstance(val, dict):
                        print('%s: {' % keyStr) if logOutput else None
                        walk(val)
                        print(indentCount * pad + '};') if logOutput else None

                    else:
                        if printKeyStr:
                            print('%s:' % keyStr) if logOutput else None
                            printKeyStr = False
                        if isinstance(val, bytes):
                            theLen = val.__len__()
                            if theLen < 9:
                                valStr = val.hex()
                                print(
                                    (indentCount + incAmt) * pad + '%d): 0x%s' % (index, valStr)) if logOutput else None
                            else:
                                if theLen > 64:
                                    valStr = val.hex()[0:63] + '…'
                                else:
                                    valStr = val.hex()

                                print((indentCount + incAmt) * pad + '%d): size = %d 0x%s' % (
                                index, theLen, valStr)) if logOutput else None
                        else:
                            print((indentCount + incAmt) * pad + '%d): %s' % (index, val)) if logOutput else None
            else:
                if isinstance(item, bytes):
                    theLen = item.__len__()
                    if theLen < 9:
                        itemStr = item.hex()
                        print(f'{keyStr}: 0x{itemStr}') if logOutput else None
                    else:
                        if theLen > 64:
                            itemStr = item.hex()[0:63] + '…'
                        else:
                            itemStr = item.hex()

                        print(f'{keyStr}: size = {theLen} [0x{itemStr}]') if logOutput else None
                else:
                    if not isinstance(item, dict):
                        print(f"{keyStr}: {item}") if logOutput else None

            # main function to check for our USB audio Components
            findOurComponents(item, key, node)

            itemsWalked += 1
    except UnboundLocalError:
        print(traceback.format_exc())
    except:
        print(traceback.format_exc())
        print('in Walk Oops!', sys.exc_info()[0], 'occurred.')
        print('exception in walk')
        pass
    if indentCount > 0:
        indentCount -= incAmt

    return

data = os.popen('/usr/sbin/system_profiler -json SPAudioDataType').read()
devices = json.loads(data)
#print(devices)
print(":microphone: :speaker:")
walk(devices)

# with open(gFileName) as f:
#     data = f.read()
#     devices = json.loads(data)
#     #print(devices)
#
#     print(":microphone:")
#
#     walk(devices)


import os
import sys
import numpy as np
import pandas as pd
from Backend.Chip.chip import Chip
from Backend.Chip.controller import Controller
from inst_gen import InstructionGenerator
from operations import *
from Backend.reg import Reg
from reg_allocate import RegAllocator
from C_Graph.variable import Variable, GLOBAL_VARIABLE_SCOPE
from C_Graph.operator import Operator
from weight_converter import WeightConverter
from data_converter import DataConverter

class ModelImpl():
    convertedW = None
    convertedData = None
    input_variable = None
    chip = Chip(id=0)
    chipController = Controller()
    instGenerator = InstructionGenerator()
    reg_allocator = RegAllocator()
    weightConverter = WeightConverter()
    dataConverter = DataConverter()
    layer_params = {}
    layer_size = 0

    def __init__(self, input_variable, file_path):
        self.input_variable = input_variable  # 需要一个数据拆分模块，根据batch_size来拆分数据，现在假设input_variable是一个batch的数据
        if not os.path.exists(file_path):
            print("ERROR: File {} does not exist".format(file_path))
            sys.exit(1)
        self.file_path = file_path

    # 输入数据分配，编译时进行
    def assignInputResource(self, W_size, stride, padding):
        self.convertedData = self.dataConverter.getConvertedData(self.input_variable, W_size, stride, padding)
        addrs = self.chip.assignInput2Mem(self.convertedData, W_size)  # 整个batch的数据被分配到的物理tile/IPU地址
        return addrs

    def assignOutputResource(self, input_shape: list, W_shape: list, input_addrs: list):  # 预分配输出特征图的内存地址
        """
        param input_shape: im2col之后的shape
        :param p_addrs:
        :param W_shape: converted之后的shape
        :param input_addrs: input的地址，output和input放在一个tile的rf中
        :return:
        """

        self.output_shape = (input_shape[0], input_shape[1], W_shape[0])  # 64*784*128
        self.chip.assignOutput2Mem(self.output_shape, input_addrs)

    # deploy weight to IPU，编译时进行
    def deployWeight(self, W, base_size, input_addrs:list):
        self.convertedW = self.weightConverter.getConvertedWeight(W, base_size)
        if len(self.convertedW) == 1:
            self.convertedW = self.convertedW[0]
            for addr in input_addrs:
                tile_id, IPU_id = addr.split("_")
                # print(f"tile_id: {tile_id}      IPU_id: {IPU_id}")
                tile_id, IPU_id = int(tile_id), int(IPU_id)
                self.chip.deployWeight(tile_id, IPU_id, self.convertedW)
        # else: # weight多于一个IPU的情况

    # generate assembly instructions (string type) for each layer
    def generateAssemblyInstruction(self, op_code, input_shape: list, input_addrs, last_layer=False):
        """
        :param op_code:
        :param input_shape: im2col之后的shape
        :param input_addrs:
        :return:
        """
        inst_list = []
        batch_size = input_shape[0]
        V_num = input_shape[1]  # 输入电压向量的个数同时也是计算的分组数，如784, == I_num
        V_depth = input_shape[2]

        I_depth = self.output_shape[2]

        if op_code == "conv":
            for i in range(batch_size):
                tile_id, IPU_id = input_addrs[i].split("_")
                tile_id, IPU_id = int(tile_id), int(IPU_id)
                input_index_reg_addrs = self.chip.tile_list[tile_id].input_indexReg[i]  # 该样本的输入索引寄存器地址列表
                output_index_reg_addrs = self.chip.tile_list[tile_id].output_indexReg[i]  # 该样本的输出索引寄存器地址列表
                # 找到这些index regs，取出值，得到掩码，load进入掩码指示的data_reg
                mask = ""
                for index_reg_addr in input_index_reg_addrs:
                    mask += self.chip.tile_list[tile_id].rf.index_reg[int(index_reg_addr, 2)].read()  # 连成一个256位的掩码
                mask = list(mask)
                input_data_regs = []  # input data的data reg是固定复用的，用于存储数据寄存器的下标
                for j in range(len(mask)):
                    if mask[j] == '1':
                        input_data_regs.append(j)
                if V_depth != len(input_data_regs):
                    raise Exception(f"V_depth {V_depth} does not equal to len(input_data_regs) {len(input_data_regs)}!")
                # 找到输出电流向量的索引寄存器，得到掩码
                mask = ""
                for index_reg_addr in output_index_reg_addrs:
                    mask += self.chip.tile_list[tile_id].rf.index_reg[int(index_reg_addr, 2)].read()  # 连成一个256位的掩码
                mask = list(mask)
                output_data_regs = []  # output data的data reg是固定复用的，用于存储数据寄存器的下标
                for j in range(len(mask)):
                    if mask[j] == '1':
                        output_data_regs.append(j)
                if I_depth != len(output_data_regs):
                    raise Exception(f"I_depth {I_depth} does not equal to len(output_data_regs) {len(output_data_regs)}!")
                row_index_reg_addrs = self.chip.tile_list[tile_id].row_indexReg

                input_start_addr = self.chip.dmem_input_table[i]  # 该输入样本在数据内存中的起始地址
                output_start_addr = self.chip.dmem_output_table[i]  # 该输出样本在数据内存中的起始地址
                mem_data_depth = self.chip.dataMemory.data_depth
                word_addr_offset = mem_data_depth // 8  # 每个字的地址偏移量

                for V_i in range(V_num):  # 按输入电压向量分组
                    # 将input data load进相应的数据寄存器中

                    # for j in range(V_depth):
                    #     mem_j_addr = input_start_addr + V_i * V_depth * word_addr_offset + j * word_addr_offset
                    #     # rd_bin = "11" + bin(input_data_regs[j])[2:]
                    #     rd = hex(input_data_regs[j])[2:].zfill(3)  # 3位十六进制寄存器地址
                    #     mem_j_addr = hex(mem_j_addr)[2:].zfill(8)  # 8位十六进制存储器地址
                    #     inst = "lw " + rd + " " + mem_j_addr
                    #     inst_list.append(inst)

                    # SIMD格式，假定向量寄存器和数据在内存中都是连续的
                    mem_j_addr = input_start_addr + V_i * V_depth * word_addr_offset
                    rd = hex(input_data_regs[0])[2:].zfill(3)  # 3位十六进制寄存器地址
                    mem_j_addr = hex(mem_j_addr)[2:].zfill(8)  # 8位十六进制存储器地址
                    vec_width = hex(V_depth)[2:].zfill(3)  # 3位十六进制向量长度参数
                    inst = "load " + rd + " " + mem_j_addr + " " + vec_width
                    inst_list.append(inst)

                    inst = "dot " + hex(int(row_index_reg_addrs[0], 2))[2:].zfill(3) + " " + hex(int(input_index_reg_addrs[0], 2))[2:].zfill(3) \
                           + " " + hex(int(output_index_reg_addrs[0], 2))[2:].zfill(3)
                    inst_list.append(inst)
                    # Version 1，将结果移动回data memory
                    # for j in range(I_depth):
                    #     mem_j_addr = output_start_addr + V_i * I_depth * word_addr_offset + j * word_addr_offset
                    #     mem_j_addr = hex(mem_j_addr)[2:].zfill(8)  # 8位十六进制存储器地址
                    #     # rs_bin = "11" + bin(output_data_regs[j])[2:]
                    #     rs = hex(output_data_regs[j])[2:].zfill(3)  # 3位十六进制寄存器地址
                    #     inst = "sw " + rs + " " + mem_j_addr
                    #     inst_list.append(inst)
                        # SIMD格式，假定向量寄存器和数据在内存中都是连续的
                    mem_j_addr = output_start_addr + V_i * I_depth * word_addr_offset
                    mem_j_addr = hex(mem_j_addr)[2:].zfill(8)  # 8位十六进制存储器地址
                    rs = hex(output_data_regs[0])[2:].zfill(3)  # 3位十六进制寄存器地址
                    vec_width = hex(I_depth)[2:].zfill(3)  # 3位十六进制向量长度参数
                    inst = "store " + rs + " " + mem_j_addr + " " + vec_width
                    inst_list.append(inst)

            return inst_list

        elif op_code == "linear":
            dotOperation = DotOperation()
            movOperation = MovOperation()
            # schedule registers
            src1_reg, src2_reg, dst_reg = self.reg_allocator.allocate(3)
            dotOperation.setSrc1Reg(src1_reg)
            dotOperation.setSrc2Reg(src2_reg)
            dotOperation.setDstReg(dst_reg)
            movOperation.setSrcReg(dst_reg)
            movOperation.setDstReg(src1_reg)
            dot = self.instGenerator.instGen(dotOperation)
            mov = self.instGenerator.instGen(movOperation)
            return dot, mov
        elif op_code == "max_pool":  # move to some digital circuit
            movOperation = MovOperation()
            src_reg, dst_reg = self.reg_allocator.allocate(2)
            movOperation.setSrcReg(src_reg)
            movOperation.setDstReg(dst_reg)
            mov = self.instGenerator.instGen(movOperation)
            return mov
        elif op_code == "de_conv":
            dotOperation1 = DotOperation()  # for the previous diff
            dotOperation2 = DotOperation()  # for gradient of W
            updateOperation = UpdateOperation() # update W
            movOperation = MovOperation()  # move the previous diff to the previous layer
            # schedule registers
            src1_reg, src2_reg, dst1_reg = self.reg_allocator.allocate(3)
            dotOperation1.setSrc1Reg(src1_reg)
            dotOperation1.setSrc2Reg(src2_reg)
            dotOperation1.setDstReg(dst1_reg)
            src3_reg, src4_reg, dst2_reg = self.reg_allocator.allocate(3)  # 需要再向上层抽象，比如由controller来schedule
            dotOperation2.setSrc1Reg(src3_reg)
            dotOperation2.setSrc2Reg(src4_reg)
            dotOperation2.setDstReg(dst2_reg)
            movOperation.setSrcReg(dst1_reg)
            movOperation.setDstReg(src1_reg)
            dot1 = self.instGenerator.instGen(dotOperation1)
            dot2 = self.instGenerator.instGen(dotOperation2)
            update = self.instGenerator.instGen(updateOperation)
            mov = self.instGenerator.instGen(movOperation)
            return dot1, dot2, update, mov
        elif op_code == "de_linear":
            dotOperation1 = DotOperation()  # for the previous diff
            dotOperation2 = DotOperation()  # for gradient of W
            updateOperation = UpdateOperation()  # update W
            movOperation = MovOperation()  # move the previous diff to the previous layer
            # schedule registers
            src1_reg, src2_reg, dst1_reg = self.reg_allocator.allocate(3)
            dotOperation1.setSrc1Reg(src1_reg)
            dotOperation1.setSrc2Reg(src2_reg)
            dotOperation1.setDstReg(dst1_reg)
            src3_reg, src4_reg, dst2_reg = self.reg_allocator.allocate(3)  # Compiler的Register allocator 感知寄存器分配情况
            dotOperation2.setSrc1Reg(src3_reg)
            dotOperation2.setSrc2Reg(src4_reg)
            dotOperation2.setDstReg(dst2_reg)
            movOperation.setSrcReg(dst1_reg)
            movOperation.setDstReg(src1_reg)
            dot1 = self.instGenerator.instGen(dotOperation1)
            dot2 = self.instGenerator.instGen(dotOperation2)
            update = self.instGenerator.instGen(updateOperation)
            mov = self.instGenerator.instGen(movOperation)
            return dot1, dot2, update, mov

    def fileInterpreter(self, file_path):
        df = pd.read_csv(file_path)
        max_flag = False
        average_flag = False
        for i, row in df.iterrows():
            # for each layer i
            if row['kernel height'] == 1 and row['kernel width'] == 1:  # linear layer
                self.layer_size += 1
            elif max_flag:
                self.layer_size += 1
            elif average_flag:
                self.layer_size += 1
            else:  # which is a conv layer
                kernel_shape = [row['kernel depth'], row['IFM channel depth'], row['kernel height'],
                                row['kernel width']]
                stride = row['stride']
                if isinstance(stride, str):  # 2,1
                    stride = tuple(map(int, stride.split(",")))
                padding = row['padding']
                if isinstance(padding, str):  # 1,2
                    padding = tuple(map(int, padding.split(",")))
                layer_params = {}
                layer_params["op_code"] = "conv"
                layer_params["kernel_shape"] = kernel_shape
                layer_params['stride'] = stride
                layer_params['padding'] = padding

                # activation
                if not pd.isna(row['activation']) and row['activation'].lower() == 'relu':
                    layer_params["act"] = "relu"

                self.layer_params[i] = layer_params
                self.layer_size += 1

    def storeInstructions(self, inst_list):  # store instructions to InstructionMemory
        return self.chip.storeInstructions(inst_list)

    def inference(self):
        self.fileInterpreter(self.file_path)
        for layer in range(self.layer_size):
            layer_params = self.layer_params[layer]
            W_size = layer_params["kernel_shape"]
            W = Variable(W_size, "test_W")
            W.data = np.random.standard_normal(W_size)  # make weight
            print(f"convolutional kernel W: {W.data}")
            input_addrs = self.assignInputResource(W_size, layer_params["stride"], layer_params["padding"])
            self.assignOutputResource(input_variable.shape, W_size, input_addrs)
            self.deployWeight(W, base_size=256, input_addrs=input_addrs)
            last_layer = True if layer==self.layer_size-1 else False
            inst_list = self.generateAssemblyInstruction(layer_params["op_code"], self.convertedData.shape, input_addrs, last_layer)
            istart_addr, iend_addr = self.storeInstructions(inst_list)
            # i=0
            # for inst in inst_list[:150]:
            #     print("PC:  0x" + hex(i)[2:].zfill(8) + "  inst:  " + inst)
            #     i += 1
            # print(f"Total number of instructions: {len(inst_list)}")

            result = self.chip.execute(istart_addr, iend_addr)

            print(f"Shape of the result: {result.shape}")
            # print(f"Result: {result.T.reshape((1, 3, 7, 7))}")
            print(f"Result: {result}")

if __name__ == "__main__":
    # make some data
    data = np.random.normal(10, 1, (64, 1, 28, 28))
    # data = np.random.normal(10, 1, (1, 1, 7, 7))
    print(f"input data: {data}")
    input_variable = Variable(list(data.shape), "test")
    input_variable.data = data
    model = ModelImpl(input_variable, file_path="../NetWork5.csv")
    model.inference()


import re
from abc import ABC, abstractmethod
import typing as ty
import ast

import lava.magma.core.learning.string_symbols as str_symbols

class Symbol(ABC):
    """Super class for all possible symbols."""

    def __init__(self, expr: ty.Optional[str] = "") -> None:
        """Initialize a Symbol.

        Parameters
        ----------
        expr : str
            String expression.
        """
        self._expr = expr

    @property
    def expr(self) -> str:
        """Get expression of the Symbol.

        Returns
        ----------
        expr : str
            String expression.
        """
        return self._expr

    @expr.setter
    def expr(self, expr: str) -> None:
        """Set expression of the Symbol.

        Parameters
        ----------
        expr : str
            String expression.
        """
        self._expr = expr

    @abstractmethod
    def __str__(self):
        pass

    @staticmethod
    def find_expr(expr: str,
                  reg_expr: str,
                  symbol: "Symbol") -> ty.Tuple[ty.Optional["Symbol"], str]:
        """Factory method for creating symbols.

        Matches an expression to a regular expression and if there is a match,
        return a symbol of the matching part of the expression
        as well as the rest of the expression.

        Parameters
        ----------
        expr : str
            String expression.
        reg_expr: str
            Regular expression.
        symbol: Symbol
            Uninitialized symbol

        Returns
        ----------
        symbol : Symbol, optional
            Symbol matching regular expression.
        expr : str
            Remaining string expression after extraction of the symbol.
        """
        p = re.compile(reg_expr)
        m = p.match(expr)

        if m is None:
            return None, expr

        match_len = m.span()[1]
        symbol.expr = m.group()

        return symbol, expr[match_len:]

class SymbolList(Symbol):
    """Represents as list of Symbols."""

    def __init__(self):
        super(SymbolList, self).__init__('')

        self._list = []

    @property
    def list(self) -> ty.List[Symbol]:
        """Get list of the SymbolList.

        Returns
        ----------
        list : list
            List of Symbol objects.
        """
        return self._list

    def append(self, symbol: Symbol) -> None:
        """Append a Symbol to the SymbolList's list and the Symbol's
        expression to the SymbolList's expression.

        Parameters
        ----------
        symbol : Symbol
            Symbol object.
        """
        self._list.append(symbol)
        self._expr += symbol.expr

    def __str__(self) -> str:
        res = "["

        for idx, symbol in enumerate(self.list):
            res = res + symbol.__str__()
            if idx != len(self.list) - 1:
                res = res + ", "

        res = res + "]"

        return res

class Operator(Symbol):
    """Abstract super class for operator Symbols."""

class Addition(Operator):
    """Symbol representing the addition operator."""

    @staticmethod
    def find(expr: str) -> ty.Tuple[ty.Optional["Addition"], str]:
        r"""Factory method for creating Addition symbols.

        Matches an expression to the regular expressions
        "\+".

        Return a Addition Symbol if there is a match and the rest of the
        expression.

        Parameters
        ----------
        expr : str
            String expression.

        Returns
        ----------
        symbol : Addition, optional
            Symbol matching regular expression.
        expr : str
            Remaining string expression after extraction of the symbol.
        """
        return Symbol.find_expr(expr, r"\+", Addition())

    def __str__(self):
        return "Addition(" + self._expr + ")"

class Subtraction(Operator):
    """Symbol representing the subtraction operator."""

    @staticmethod
    def find(expr: str) -> ty.Tuple[ty.Optional["Subtraction"], str]:
        r"""Factory method for creating Subtraction symbols.

        Matches an expression to the regular expressions
        "\-".

        Return a Subtraction Symbol if there is a match and the rest of the
        expression.

        Parameters
        ----------
        expr : str
            String expression.

        Returns
        ----------
        symbol : Subtraction, optional
            Symbol matching regular expression.
        expr : str
            Remaining string expression after extraction of the symbol.
        """
        return Symbol.find_expr(expr, r'\-', Subtraction())

    def __str__(self):
        return "Subtraction(" + self._expr + ")"

class Multiplication(Operator):
    """Symbol representing the multiplication operator."""

    @staticmethod
    def find(expr: str) -> ty.Tuple[ty.Optional["Multiplication"], str]:
        r"""Factory method for creating Multiplication symbols.

        Matches an expression to the regular expressions
        "\*".

        Return a Multiplication Symbol if there is a match and the rest of the
        expression.

        Parameters
        ----------
        expr : str
            String expression.

        Returns
        ----------
        symbol : Multiplication, optional
            Symbol matching regular expression.
        expr : str
            Remaining string expression after extraction of the symbol.
        """
        return Symbol.find_expr(expr, r'\*', Multiplication())

    def __str__(self):
        return "Multiplication(" + self._expr + ")"

class FactorSym(Symbol):
    """Abstract super class for factor Symbols."""

class Dependency(FactorSym):
    """Abstract super class for dependency Symbols."""

class X0(Dependency):
    """Symbol representing the x0 dependency."""

    @staticmethod
    def find(expr: str) -> ty.Tuple[ty.Optional["X0"], str]:
        """Factory method for creating X0 symbols.

        Matches an expression to the regular expressions
        "x0".

        Return a X0 Symbol if there is a match and the rest of the
        expression.

        Parameters
        ----------
        expr : str
            String expression.

        Returns
        ----------
        symbol : X0, optional
            Symbol matching regular expression.
        expr : str
            Remaining string expression after extraction of the symbol.
        """
        return Symbol.find_expr(expr, str_symbols.X0, X0())

    def __str__(self):
        return "X0(" + self._expr + ")"

class Y0(Dependency):
    """Symbol representing the y0 dependency."""

    @staticmethod
    def find(expr: str) -> ty.Tuple[ty.Optional["Y0"], str]:
        """Factory method for creating Y0 symbols.

        Matches an expression to the regular expressions
        "y0".

        Return a Y0 Symbol if there is a match and the rest of the
        expression.

        Parameters
        ----------
        expr : str
            String expression.

        Returns
        ----------
        symbol : Y0, optional
            Symbol matching regular expression.
        expr : str
            Remaining string expression after extraction of the symbol.
        """
        return Symbol.find_expr(expr, str_symbols.Y0, Y0())

    def __str__(self):
        return "Y0(" + self._expr + ")"

class Uk(Dependency):
    """Symbol representing the uk dependency."""

    def __init__(self):
        super().__init__()
        self._decimate_exponent = None

    @property
    def decimate_exponent(self) -> ty.Optional[int]:
        """Get decimate exponent of this Uk.

        Returns
        ----------
        decimate_exponent : int
            Decimate exponent.
        """
        return self._decimate_exponent

    @decimate_exponent.setter
    def decimate_exponent(self, decimate_exponent: int) -> None:
        """Set decimate exponent of this Uk.

        Parameters
        ----------
        decimate_exponent : int
            Decimate exponent.
        """
        self._decimate_exponent = decimate_exponent

    @staticmethod
    def find(expr: str) -> ty.Tuple[ty.Optional["Uk"], str]:
        r"""Factory method for creating Uk symbols.

        Matches an expression to the regular expressions
        "u\d".

        Return a Uk Symbol if there is a match and the rest of the
        expression.

        Parameters
        ----------
        expr : str
            String expression.

        Returns
        ----------
        symbol : Uk, optional
            Symbol matching regular expression.
        expr : str
            Remaining string expression after extraction of the symbol.
        """
        symbol, expr = Symbol.find_expr(expr, r'u\d', Uk())

        if symbol is not None:
            symbol.decimate_exponent = int(symbol.expr[1:])

        return symbol, expr

    def __str__(self):
        return "Uk(" + self._expr + ")"

class Variable(FactorSym):
    """Symbol representing traces and synaptic variable factors."""

    @staticmethod
    def find(expr: str) -> ty.Tuple[ty.Optional["Variable"], str]:
        """Factory method for creating Variable symbols.

        Matches an expression to the regular expressions
        "x[12]", "y[123]", "w", "d", "t".

        Return a Variable Symbol if there is a match and the rest of the
        expression.

        Parameters
        ----------
        expr : str
            String expression.

        Returns
        ----------
        symbol : Variable, optional
            Symbol matching regular expression.
        expr : str
            Remaining string expression after extraction of the symbol.
        """
        v = Variable()

        symbol, expr = Symbol.find_expr(expr, 'x[12]', v)
        if not isinstance(symbol, Variable):
            symbol, expr = Symbol.find_expr(expr, 'y[123]', v)
        if not isinstance(symbol, Variable):
            symbol, expr = Symbol.find_expr(expr, str_symbols.W, v)
        if not isinstance(symbol, Variable):
            symbol, expr = Symbol.find_expr(expr, str_symbols.D, v)
        if not isinstance(symbol, Variable):
            symbol, expr = Symbol.find_expr(expr, str_symbols.T, v)

        return symbol, expr

    def __str__(self):
        return "Variable(" + self._expr + ")"

class Expression(FactorSym):
    """Abstract super class for multi-symbol Symbols."""

    def __init__(self):
        super().__init__()
        self._sub_expr = None
        self._symbol_list = None

    @property
    def sub_expr(self) -> ty.Optional[str]:
        """Get sub-expression of this Expression.

        Returns
        ----------
        sub_expr : str
            String sub-expression.
        """
        return self._sub_expr

    @sub_expr.setter
    def sub_expr(self, sub_expr: str) -> None:
        """Set sub-expression of this Expression.

        Parameters
        ----------
        sub_expr : str
            String sub-expression.
        """
        self._sub_expr = sub_expr

    @property
    def symbol_list(self) -> ty.Optional[SymbolList]:
        """Get SymbolList associated with sub-expression of this Expression.

        Returns
        ----------
        symbol_list : SymbolList
            SymbolList.
        """
        return self._symbol_list

    @symbol_list.setter
    def symbol_list(self, symbol_list: SymbolList) -> None:
        """Set SymbolList associated with sub-expression of this Expression.

        Parameters
        ----------
        symbol_list : SymbolList
            SymbolList.
        """
        self._symbol_list = symbol_list

    @staticmethod
    def _find_closing_bracket_idx(expr: str) -> ty.Optional[int]:
        """Find closing bracket associated with the first found opening bracket
        and return its index.

        Return None if closing index was found matching the first found
        opening bracket.

        Parameters
        ----------
        expr : str
            String expression.

        Returns
        ----------
        closing_bracket_idx : int
            Index of closing bracket.
        """
        idx = [(1 if i.group() == '(' else -1, i.start()) for i in
               re.finditer('[()]', expr)]
        sum_res = 0
        closing_idx = None

        for i in idx:
            sum_res += i[0]
            if sum_res == 0:
                closing_idx = i[1]
                break

        return closing_idx

    @abstractmethod
    def find_sub_expr(self, expr: str) -> str:
        pass

class BracketExpression(Expression):
    """Symbol representing a bracket expression of the form : (...)."""

    def find_sub_expr(self, expr: str) -> str:
        """Find sub-expression of an expression, assuming the expression is
        of the form "(...)", representing a BracketExpression.

        Parameters
        ----------
        expr : str
            String expression.

        Returns
        ----------
        sub_expr : str
            String sub-expression.
        """
        try:
            idx = self._find_closing_bracket_idx(expr)
            self._sub_expr = expr[1:idx]

            expr = expr[idx + 1:]

            return expr
        except TypeError:
            raise ValueError("Bracket expression missing closing bracket.")

    @staticmethod
    def find(expr: str) -> ty.Tuple[ty.Optional["BracketExpression"], str]:
        r"""Factory method for creating BracketExpression symbols.

        Matches an expression to the regular expression
        "\(". If there is a match, find the sub expression.

        Return a BracketExpression Symbol if there is a match and
        closing bracket and the rest of the expression.

        Parameters
        ----------
        expr : str
            String expression.

        Returns
        ----------
        symbol : BracketExpression, optional
            Symbol matching regular expression.
        expr : str
            Remaining string expression after extraction of the symbol.
        """
        init_expr = expr

        symbol, expr = Symbol.find_expr(expr, r'\(', BracketExpression())

        if isinstance(symbol, BracketExpression):
            expr = symbol.find_sub_expr('(' + expr)

            symbol.expr = init_expr

        return symbol, expr

    def __str__(self):
        return "BracketExpression(" + self._symbol_list.__str__() + ")"

class SgnExpression(Expression):
    """Symbol representing a sign expression of the form :  sgn(...)."""

    def find_sub_expr(self, expr: str) -> str:
        """Find sub-expression of an expression, assuming the expression is
        of the form "sgn(...)", representing a SgnExpression.

        Parameters
        ----------
        expr : str
            String expression.

        Returns
        ----------
        sub_expr : str
            String sub-expression.
        """
        try:
            idx = self._find_closing_bracket_idx(expr)
            self.sub_expr = expr[4:idx]

            expr = expr[idx + 1:]

            return expr
        except TypeError:
            raise ValueError("Bracket expression missing closing bracket.")

    @staticmethod
    def find(expr: str) -> ty.Tuple[ty.Optional["SgnExpression"], str]:
        r"""Factory method for creating SgnExpression symbols.

        Matches an expression to the regular expression
        "sgn\(". If there is a match, find the sub expression.

        Return a SgnExpression Symbol if there is a match and
        closing bracket and the rest of the expression.

        Parameters
        ----------
        expr : str
            String expression.

        Returns
        ----------
        symbol : SgnExpression, optional
            Symbol matching regular expression.
        expr : str
            Remaining string expression after extraction of the symbol.
        """
        init_expr = expr

        symbol, expr = Symbol.find_expr(expr, r'sgn\(', SgnExpression())

        if isinstance(symbol, SgnExpression):
            expr = symbol.find_sub_expr('sgn(' + expr)

            symbol.expr = init_expr

        return symbol, expr

    def __str__(self):
        return "SgnExpression(" + self._symbol_list.__str__() + ")"

class Literal(Symbol):
    """Symbol representing a literal."""

    def __init__(self):
        super().__init__()
        self._mantissa = 0
        self._base = 1
        self._exponent = 0
        self._literal_type = None

    @property
    def mantissa(self) -> int:
        """Get mantissa of this Literal.

        Returns
        ----------
        mantissa : int
            Mantissa of this literal.
        """
        return self._mantissa

    @property
    def base(self) -> int:
        """Get base of this Literal.

        Returns
        ----------
        base : int
            Base of this literal.
        """
        return self._base

    @property
    def exponent(self) -> int:
        """Get exponent of this Literal.

        Returns
        ----------
        exponent : int
            Exponent of this literal.
        """
        return self._exponent

    @property
    def literal_type(self) -> int:
        """Get literal type of this Literal.

        Returns
        ----------
        literal_type : int
            Literal type of this literal.
        """
        return self._literal_type

    @literal_type.setter
    def literal_type(self, literal_type: int) -> None:
        """Set literal type of this Literal.

        Parameters
        ----------
        literal_type : int
            Literal type of this literal.
        """
        self._literal_type = literal_type

    def to_int(self) -> None:
        """Extract mantissa, base and exponent of this Literal from string
        expression and store them."""
        if self._literal_type == 0:
            # Convert [+/-]x*2^[+/0]y
            val = self._expr.split('^')
            self._mantissa = ast.literal_eval(val[0][:-2])
            self._base = 2
            self._exponent = ast.literal_eval(val[1])
        elif self._literal_type == 1:
            # Convert [+/-]2^[+/0]y
            val = self._expr.split('^')
            self._mantissa = int(ast.literal_eval(val[0]) / 2)
            self._base = 2
            self._exponent = ast.literal_eval(val[1])
        elif self._literal_type == 2:
            # Convert [+/-]x
            self._mantissa = ast.literal_eval(self._expr)
            self._base = 1
            self._exponent = 0

    @property
    def val(self) -> int:
        """Get the integer value represented by this Literal.

        Returns
        ----------
        val : int
            Integer value of this Literal.
        """
        return int(self._mantissa * self._base ** self._exponent)

    @staticmethod
    def find(expr):
        r"""Factory method for creating Literal symbols.

        Matches an expression to the regular expressions
        "[\+\-]?\d+\*2\^[\+\-]?\d+", "[\+\-]?2\^[\+\-]?\d+", "[\+\-]?\d+".

        Return a Literal Symbol if there is a match and
        closing bracket and the rest of the expression.

        Parameters
        ----------
        expr : str
            String expression.

        Returns
        ----------
        symbol : Literal, optional
            Symbol matching regular expression.
        expr : str
            Remaining string expression after extraction of the symbol.
        """
        # Match x*2^y
        symbol, expr = Symbol.find_expr(expr, r'[\+\-]?\d+\*2\^[\+\-]?\d+',
                                        Literal())
        if isinstance(symbol, Literal):
            symbol.literal_type = 0
        else:
            # Match 2^y
            symbol, expr = Symbol.find_expr(expr, r'[\+\-]?2\^[\+\-]?\d+',
                                            Literal())
            if isinstance(symbol, Literal):
                symbol.literal_type = 1
            else:
                # Match x
                symbol, expr = Symbol.find_expr(expr, r'[\+\-]?\d+',
                                                Literal())
                if isinstance(symbol, Literal):
                    symbol.literal_type = 2

        if isinstance(symbol, Literal):
            symbol.to_int()

        return symbol, expr

    def __str__(self):
        return "Literal(" + self._expr + ")"

SYMBOL_CLASSES = [Addition, Subtraction, Multiplication, X0, Y0, Uk,
                  Variable, BracketExpression, SgnExpression, Literal]

class SymbolicEquation:
    """The SymbolicEquation represents a learning rule as a set of symbols.

    It provides means to generate a SymbolicEquation from a string following
    a fixed syntax.

    Parameters
    ----------
    target : str
        Target of the learning rule to be represented by this SymbolicEquation.
    str_learning_rule : str
        Learning rule in string format to be represented by
        this SymbolicEquation.
    """

    def __init__(self, target: str, str_learning_rule: str) -> None:
        self._target = target
        self._str_learning_rule = str_learning_rule

        self._symbol_list = self._generate_symbol_list_from_string()

    @property
    def target(self) -> str:
        """Get target of this SymbolicEquation.

        Returns
        ----------
        target : str
            Target of this SymbolicEquation.
        """
        return self._target

    @property
    def symbol_list(self) -> SymbolList:
        """Get SymbolList of this SymbolicEquation.

        Returns
        ----------
        symbol_list : SymbolList
            SymbolList of this SymbolicEquation.
        """
        return self._symbol_list

    def _find_next_symbol(self, expression: str) \
            -> ty.Tuple[ty.Optional[Symbol], str]:
        """Find next symbol in a string expression.

        If the new symbol is of type Expression, apply parse to
        its sub-expression.

        Parameters
        ----------
        expression : str
            String expression.

        Returns
        ----------
        new_symbol : Symbol
            Found new symbol.
        expression : str
            Remaining string expression after extraction of the new symbol.
        """
        new_symbol = None

        for symbol in SYMBOL_CLASSES:
            new_symbol, expression = symbol.find(expression)

            if isinstance(new_symbol, Expression):
                new_symbol.symbol_list = self._parse(new_symbol.sub_expr)

            if new_symbol is not None:
                break

        return new_symbol, expression

    def _parse(self, expression: str) -> SymbolList:
        """Parse a string expression to yield a SymbolList representation.

        Finds next symbols in the string expression one by one until
        the string expression is empty.

        Parameters
        ----------
        expression : str
            String expression.

        Returns
        ----------
        symbol_list : SymbolList
            SymbolList object resulting from the string parsing operation.
        """
        done = False
        symbol_list = SymbolList()

        while not done:
            new_symbol, expression = self._find_next_symbol(expression)
            symbol_list.append(new_symbol)
            done = not (len(expression) > 0)

        return symbol_list

    def _generate_symbol_list_from_string(self) -> SymbolList:
        """Generate a SymbolList representation from a string representation.

        Returns
        ----------
        symbol_list : SymbolList
            Learning rule in SymbolList representation.
        """
        learning_rule = re.sub(' ', '', self._str_learning_rule)

        symbol_list = self._parse(learning_rule)

        return symbol_list


import time
from datetime import datetime
import asyncio
import nextcord
from nextcord.ext import commands
from core.classes import Cog_Extension

routine = True
GRADUATE_DATE = datetime(2023, 6, 30)
WIFE_CHANNEL_ID = 1118725524974489770

class Routine(Cog_Extension):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

    @commands.Cog.listener()
    async def on_ready(self):
        try:
            WIFE_CHANNEL = self.bot.get_channel(WIFE_CHANNEL_ID)
            while routine:
                # get current time (date and time)
                now = time.strftime('%Y/%m/%d %H:%M:%S', time.localtime())
                # get current time (only date)
                now_hr = time.strftime("%H", time.localtime())

                delta = datetime.now() - GRADUATE_DATE  # get delta time
                days, seconds = delta.days, delta.seconds  # convert seconds to days
                hours, seconds = divmod(seconds, 3600)  # convert seconds to hours
                minutes, seconds = divmod(seconds, 60)  # convert seconds to minutes
                delta_time = f"{days}天{hours}小時{minutes}分{seconds}秒"   # convert to str

                if now_hr == "08":
                    await WIFE_CHANNEL.send(f"現在是 {now}，距離賤臣老婆畢業已經過了 {delta_time} ，記得提醒賤臣醒來！")
                    print(f"<>老婆貓已經畢業 {delta_time} 了")
                await asyncio.sleep(3600)  # wait for 1 hour

        except Exception as err:
            await WIFE_CHANNEL.send(f"Routine catch error: ```{err}```")
            print(f">err< Routine: ```{err}```")

def setup(bot):
    bot.add_cog(Routine(bot))


from django.shortcuts import render
from .models import ServiceCategory, ServiceSubcategory
from offers.models import ServiceOffer
from django.shortcuts import get_object_or_404

# Create your views here.
def list_service_categories(request):
    return render(request, "services/categories.html",
                  {"service_categories": ServiceCategory.objects.all()})

def detail_service_categories(request, id):
    #   service_subcategory_list = list(get_object_or_404(ServiceSubcategory, service_category_id=id))
    #   service_subcategory_list = get_object_or_404(ServiceSubcategory, service_category_id=id)
    service_subcategory_list = ServiceSubcategory.objects.filter(service_category_id=id)
    return render(request, "services/details.html",
                  {"service_subcategory_list": service_subcategory_list})

def search_for_service(request):
    categories = ServiceCategory.objects.all()
    cities = ServiceOffer.objects.values_list("service_city", flat=True).distinct()
    return render(request, "services/service_search.html",
                  {"categories": categories, "cities": cities})

def list_according_to_service_category(request, id):
    offers = ServiceOffer.objects.all().filter(service_category_id=id)
    service_category = get_object_or_404(ServiceCategory, id=id)
    user = request.user
    return render(request, "services/acc_to_category.html",
                  {"offers": offers, "category": service_category, "user": user})

def list_according_to_city_category(request, city):
    offers = ServiceOffer.objects.all().filter(service_city=city)
    city = city
    user = request.user
    return render(request, "services/acc_to_city.html",
                  {"offers": offers, "user": user, "city": city})

def list_all_services(request):
    offers = ServiceOffer.objects.all()
    return render(request, "services/acc_to_all.html", {"offers": offers})


from macgyver.constants import NUM_ITEMS

class Hero:

    def __init__(self, position, labyrinth):

        self.position = position
        self.catch_items = []
        self.make_syringe = None
        self.labyrinth = labyrinth
        self.status = "running"

    def fight(self):
        if len(self.catch_items) == NUM_ITEMS:
            self.status = "won"
        else :
            self.status = "lost"

    def move(self, direction):
        """Create the starting position of the hero and the positions after movement."""
        new_position = direction(self.position)
        if new_position in self.labyrinth.paths:
            self.position = new_position
        if new_position in self.labyrinth.item_positions:
            self.catch_item()
        if new_position == self.labyrinth.guardian.position:
            self.fight()
            return False
        return True

    def catch_item(self):
        """Moving items after picking them up."""
        self.catch_items.append(self.position)
        i = self.labyrinth.item_positions.index(self.position)
        self.labyrinth.items[i].position = (self.labyrinth.height, i)


import sqlite3

conn = sqlite3.connect('emailDB.sqlite')  # make a connection
cur = conn.cursor()  # send SQL command to the cursor and get the results back through the same cursor

cur.execute('DROP TABLE IF EXISTS Counts')  # use cur.execute('') for the SQL command

cur.execute('CREATE TABLE Counts (email TEXT, count INTEGER)')

fname = input('Enter file name: ')
if len(fname) < 1:
    fname = 'mbox1.txt'
fh = open(fname)
for line in fh:
    if not line.startswith('From: '):
        continue
    pieces = line.split()
    email = pieces[1]
    # If we just want to know the user name, use:  email.split('@')[1]

    #  this question mark is a placeholder
    #  And this is a way to basically make sure that we don't allow SQL injection
    cur.execute('SELECT count FROM Counts WHERE email = ?', (email, ))

    # another way to write the following code, see
    # https://www.coursera.org/learn/python-databases/lecture/18SJ4/worked-example-counting-email-in-a-database
    try:
        #  FYI: https://blog.csdn.net/Jian_Yun_Rui/article/details/73692331
        count = cur.fetchone()[0]  # take the count value, if None, then break
        cur.execute('UPDATE Counts SET count = count + 1 WHERE email = ?', (email, ))
    except:
        cur.execute('INSERT INTO Counts (email, count) VALUES (?, 1)', (email, ))
    conn.commit()

# print out contants of the table in emailDB in order

sqlstr = 'SELECT email, count FROM Counts ORDER BY count DESC LIMIT 10'
for row in conn.execute(sqlstr):
    print(row[0], row[1])

conn.close()  # close the connection