# -*- coding: utf-8 -*-
"""
Created on Mon Jul 31 10:17:47 2017

@author: user
"""
#import matplotlib.pyplot as plt
import pywt
import time as sys_time
import sys
import os
import numpy as np
import h5py
import Read_Data
import Process_Data
import Diagnostics

#from Single_Particle import Statistics
from mpi4py import MPI

tstart = sys_time.time()

#MPI communicator object:
mpi_comm = MPI.COMM_WORLD
#ID number of the particular MPI process (one out of mpi_size):
mpi_rank = mpi_comm.Get_rank()
#Total number of MPI processes:
mpi_size = mpi_comm.Get_size()

def MPI_mean_array(local_array, root=0):
    """Obtain the global mean from all the MPI tasks and collect the info on the root node."""
    global_array = np.zeros_like(local_array)
    mpi_comm.Reduce(local_array, global_array, op=MPI.SUM, root=root)
    return global_array/float(mpi_size)

def Diffusion(v_input,ref,N):
    '''Takes in an input vector array, selects time data from t=ref to end of simulation.
    Subtracts from each component their value at t=ref, and takes the rms of the vector magnitude.'''
    v_input = v_input[:,ref:N]

    v_diff = np.zeros_like(v_input)

    v_ref= v_input.T[0]

    v_diff= v_input.T-v_ref

    v_diff=np.linalg.norm(v_diff.T,axis=0)

    return MPI_mean_array(v_diff)

#Read input arguments
wavelet = str(sys.argv[1])
data_dir = str(sys.argv[2])  # root directory with the trajectory files
species = str(sys.argv[3])   # species to analyse
fraction = float(sys.argv[4])  # number between 0 and 1 to represent a fraction of N_part_total

"""
For the 'beta0p5' simulation data, use Omega_c = 0.3536 for electrons and Omega_c = 0.00553 for ions.
For the 'beta0p2' simulation data, use Omega_c = 0.528 for electrons and Omega_c = 0.00825 for ions.
"""

if data_dir=='beta0p5_eps0p4':
    if species=='electrons':
        #q=-0.015625
        q=-1
        Omega_c=0.3536
        m=1
    else:
        q=1
        Omega_c=0.00533
        m=1*64
else:
    if species=='electrons':
        q=-1
        Omega_c=0.528
        m=1
    else:
        q=1
        Omega_c=0.00825
        m=1*64

#Choose a given wavelet and edge mode:
wavelet = pywt.Wavelet(wavelet)
mode = 'periodization'

#Get total number of particles:
cwd = os.getcwd()
dset = 't'
path = cwd + '/' + data_dir +'/'
base_name = species+ '-tracks-'
f=h5py.File(path + base_name + dset + '.h5', 'r')
N_part_total = f.attrs['NTRACKS']
f.close()

N_part = int(fraction*N_part_total)

#Print some stuff from the process with rank 0:
if mpi_rank==0:
    print("Running on " + str(mpi_size) + " MPI processes.")
    print("Input data = "+species+" from " + data_dir)
    print("Total no. of particles =" +str(N_part_total))
    print("No. of particles used =" +str(N_part))

#Partition the total input file with N particles into mpi_size parts:
mpi_borders = np.linspace(0, N_part, mpi_size + 1).astype('int')

my_border_low = mpi_borders[mpi_rank]
my_border_high = mpi_borders[mpi_rank+1]

#Redefining N_part as number of particles analysed per processor
N_part = my_border_high - my_border_low

#Read Trajectory Data
time, U, E, B, Energy = Read_Data.Read_Trajectory_Data(my_border_low, my_border_high, data_dir, species)
#Comment: U is used to denote the proper relativistic velocity, which is U = gamma*V

N = len(time)

#Process Trajectory Data using chosen wavelet and edge mode
if mpi_rank==0:
    print('Processing Data for particles...')

#Transfrom the data and compute new quantities:
time, V, E, b, V_par, V_perp, vpar, vperp, Acc_mag, Acc_par, Acc_perp1, Acc_perp2 = Process_Data.Process_raw(time, U, E, B, Omega_c, q, m)
N_pad = len(vpar[0,:])

ref=int(np.ceil(N/4))

#vpar_Global=Diffusion(vpar,ref,N)
#vperp_Global=Diffusion(vperp,ref,N)
#
#if mpi_rank==0:
#    np.savetxt(path+'/'+species+'/Diffusion/v_par_rms_raw.dat', np.c_[time[ref:N], vpar_Global])
#    np.savetxt(path+'/'+species+'/Diffusion/v_perp_rms_raw.dat', np.c_[time[ref:N], vperp_Global])

#Compute wavelet coefficeints:
coefs_V = Process_Data.Process_coef(V, wavelet, mode)
coefs_E = Process_Data.Process_coef(E, wavelet, mode)
coefs_b = Process_Data.Process_coef(b, wavelet, mode)
coefs_V_par = Process_Data.Process_coef(V_par, wavelet, mode)
coefs_V_perp = Process_Data.Process_coef(V_perp, wavelet, mode)
coefs_vpar = Process_Data.Process_coef(vpar, wavelet, mode)
coefs_vperp = Process_Data.Process_coef(vperp, wavelet, mode)
#coefs_energy = Process_Data.Process_coef(Energy, wavelet, mode)
#coefs_Acc_mag = Process_Data.Process_coef(Acc_mag, wavelet, mode)
#coefs_Acc_par = Process_Data.Process_coef(Acc_par, wavelet, mode)
#coefs_Acc_perp1 = Process_Data.Process_coef(Acc_perp1, wavelet, mode)
#coefs_Acc_perp2 = Process_Data.Process_coef(Acc_perp2, wavelet, mode)

J = len(coefs_vpar)

if mpi_rank==0:
    print('Processing done!')
    print('Number of time steps in the original signal:' + str(N))
    print('Number of time steps in the padded array:' + str(N_pad))
    print('Number of scales for the orthogonal transform:' + str(J-1))

#Prepare the arrays to hold all the moments:
V_moments_vs_j = np.zeros((3,J, 3, 5)) #at 3 times, for all 3 components, versus J for 5 different moments (2nd, 3rd, 4th, 5th, 6th)
vpar_moments_vs_j = np.zeros((3,J, 5))
vperp_moments_vs_j = np.zeros((3,J, 5))
scale_j = np.zeros(J) #approximate time scale corresponding to some given J in the real physical units

for j in range(J):
    """Extract that selected scale for all the particles and all the vector components over
    a given time window specified by t_ind_low and t_ind_high:"""

#    Mu_j_full= Diagnostics.new_extract_scale(coefs_mu, j, wavelet, mode, 0 ,N)
    V_j_full = Diagnostics.new_extract_scale(coefs_V, j, wavelet, mode, 0, N)
    E_j_full = Diagnostics.new_extract_scale(coefs_E, j, wavelet, mode, 0, N)
    b_j_full = Diagnostics.new_extract_scale(coefs_b, j, wavelet, mode, 0, N)

    V_par_j_full = Diagnostics.new_extract_scale(coefs_V_par, j, wavelet, mode, 0, N)
    V_perp_j_full = Diagnostics.new_extract_scale(coefs_V_perp, j, wavelet, mode, 0, N)

    vpar_j_full = Diagnostics.new_extract_scale(coefs_vpar, j, wavelet, mode, 0, N)
    vperp_j_full = Diagnostics.new_extract_scale(coefs_vperp, j, wavelet, mode, 0, N)

#    Acc_mag_j_full = Diagnostics.new_extract_scale(coefs_Acc_mag, j, wavelet, mode ,0 ,N)
#    Acc_par_j_full = Diagnostics.new_extract_scale(coefs_Acc_par, j, wavelet, mode ,0 ,N)
#    Acc_perp1_j_full = Diagnostics.new_extract_scale(coefs_Acc_perp1, j, wavelet, mode ,0 ,N)
#    Acc_perp2_j_full = Diagnostics.new_extract_scale(coefs_Acc_perp2, j, wavelet, mode ,0 ,N)
#
    scale_j[j] = time[int(N_pad//len(coefs_vpar[j][0]))] - time[0]
#
    #Specify the time window over which to average:
    for i in range(3):
        t_ind_low = i*N//4
        t_ind_high = (i+2)*N//4

        V_j = V_j_full[:, :, t_ind_low : t_ind_high]
        E_j = E_j_full[:, :, t_ind_low : t_ind_high]
        b_j = b_j_full[:, :, t_ind_low : t_ind_high]
        V_par_j = V_par_j_full[:, :, t_ind_low : t_ind_high]
        V_perp_j = V_perp_j_full[:, :, t_ind_low : t_ind_high]
        vpar_j = vpar_j_full[:, t_ind_low : t_ind_high]
        vperp_j = vperp_j_full[:, t_ind_low : t_ind_high]
#
#        Acc_mag_j = Acc_mag_j_full[:, t_ind_low : t_ind_high]
#        Acc_par_j = Acc_par_j_full[:, t_ind_low : t_ind_high]
#        Acc_perp1_j = Acc_perp1_j_full[ :, t_ind_low : t_ind_high]
#        Acc_perp2_j = Acc_perp2_j_full[ :, t_ind_low : t_ind_high]
#
#        # Evaluate the net,parallel, and perpendicular instantaneous power ( P = time deriv. of energy) at scale j
#        P_j_net = q*(V_j[0]*E_j[0] + V_j[1]*E_j[1] + V_j[2]*E_j[2])
#        P_j_par = q*(V_par_j[0]*E_j[0] + V_par_j[1]*E_j[1] + V_par_j[2]*E_j[2])
#        P_j_perp = q*(V_perp_j[0]*E_j[0] + V_perp_j[1]*E_j[1] + V_perp_j[2]*E_j[2])
#
#        #Calculate the PDFs
#        norm_t = 1./float(t_ind_high - t_ind_low)
#        P_net_PDF_tavg, PDF_bins = Diagnostics.PDF_nomean(P_j_net[:,0])
#        P_par_PDF_tavg, PDF_bins = Diagnostics.PDF_nomean(P_j_par[:,0])
#        P_perp_PDF_tavg, PDF_bins = Diagnostics.PDF_nomean(P_j_perp[:,0])
#        P_net_PDF_tavg *= norm_t
#        P_par_PDF_tavg *= norm_t
#        P_perp_PDF_tavg *= norm_t
#
#        acc_mag_PDF_tavg, PDF_bins = Diagnostics.PDF_nomean(Acc_mag_j[:,0])
#        acc_par_PDF_tavg, PDF_bins = Diagnostics.PDF_nomean(Acc_par_j[:,0])
#        acc_perp1_PDF_tavg, PDF_bins = Diagnostics.PDF_nomean(Acc_perp1_j[:,0])
#        acc_perp2_PDF_tavg, PDF_bins = Diagnostics.PDF_nomean(Acc_perp2_j[:,0])
#
#        acc_mag_PDF_tavg *= norm_t
#        acc_par_PDF_tavg *= norm_t
#        acc_perp1_PDF_tavg *= norm_t
#        acc_perp2_PDF_tavg *= norm_t
#
#        for t_ind in range(1, t_ind_high-t_ind_low):
#            P_net_PDF, PDF_bins = Diagnostics.PDF_nomean(P_j_net[:,t_ind])
#            P_par_PDF, PDF_bins = Diagnostics.PDF_nomean(P_j_par[:,t_ind])
#            P_perp_PDF, PDF_bins = Diagnostics.PDF_nomean(P_j_perp[:,t_ind])
#            P_net_PDF_tavg += P_net_PDF*norm_t
#            P_par_PDF_tavg += P_par_PDF*norm_t
#            P_perp_PDF_tavg += P_perp_PDF*norm_t
#
#            acc_mag_PDF, PDF_bins = Diagnostics.PDF_nomean(Acc_mag_j[:,t_ind])
#            acc_par_PDF, PDF_bins = Diagnostics.PDF_nomean(Acc_par_j[:,t_ind])
#            acc_perp1_PDF, PDF_bins = Diagnostics.PDF_nomean(Acc_perp1_j[:,t_ind])
#            acc_perp2_PDF, PDF_bins = Diagnostics.PDF_nomean(Acc_perp2_j[:,t_ind])
#            acc_mag_PDF_tavg += acc_mag_PDF*norm_t
#            acc_par_PDF_tavg += acc_par_PDF*norm_t
#            acc_perp1_PDF_tavg += acc_perp1_PDF*norm_t
#            acc_perp2_PDF_tavg += acc_perp2_PDF*norm_t
#
#        P_net_PDF_global = MPI_mean_array(P_net_PDF_tavg)
#        P_par_PDF_global = MPI_mean_array(P_par_PDF_tavg)
#        P_perp_PDF_global = MPI_mean_array(P_perp_PDF_tavg)
#
#        acc_mag_PDF_global = MPI_mean_array(acc_mag_PDF_tavg)
#        acc_par_PDF_global = MPI_mean_array(acc_par_PDF_tavg)
#        acc_perp1_PDF_global = MPI_mean_array(acc_perp1_PDF_tavg)
#        acc_perp2_PDF_global = MPI_mean_array(acc_perp2_PDF_tavg)
#
#        Num_bins=len(PDF_bins)/2
#        First_half_net=P_net_PDF_global[:Num_bins]
#        Second_half_net=P_net_PDF_global[Num_bins:]
#        Skewness_net=np.log10(First_half_net[::-1]/Second_half_net)
#
#        First_half_par=P_par_PDF_global[:Num_bins]
#        Second_half_par=P_par_PDF_global[Num_bins:]
#        Skewness_par=np.log10(First_half_par[::-1]/Second_half_par)
#
#        First_half_perp=P_perp_PDF_global[:Num_bins]
#        Second_half_perp=P_perp_PDF_global[Num_bins:]
#        Skewness_perp=np.log10(First_half_perp[::-1]/Second_half_perp)
#
#        if mpi_rank==0:
#            np.savetxt(path+'/'+species+'/PDFs/pdf_P_j' + str(j) + '_net_t'+str(i+1)+'.dat', np.c_[PDF_bins, P_net_PDF_global])
#            np.savetxt(path+'/'+species+'/PDFs/pdf_P_j' + str(j) + '_par_t'+str(i+1)+'.dat', np.c_[PDF_bins, P_par_PDF_global])
#            np.savetxt(path+'/'+species+'/PDFs/pdf_P_j' + str(j) + '_perp_t'+str(i+1)+'.dat', np.c_[PDF_bins, P_perp_PDF_global])
#
#            np.savetxt(path+'/'+species+'/PDFs/pdf_Acc_j' + str(j) + '_mag_t'+str(i+1)+'.dat', np.c_[PDF_bins, acc_mag_PDF_global])
#            np.savetxt(path+'/'+species+'/PDFs/pdf_Acc_j' + str(j) + '_par_t'+str(i+1)+'.dat', np.c_[PDF_bins, acc_par_PDF_global])
#            np.savetxt(path+'/'+species+'/PDFs/pdf_Acc_j' + str(j) + '_perp1_t'+str(i+1)+'.dat', np.c_[PDF_bins, acc_perp1_PDF_global])
#            np.savetxt(path+'/'+species+'/PDFs/pdf_Acc_j' + str(j) + '_perp2_t'+str(i+1)+'.dat', np.c_[PDF_bins, acc_perp2_PDF_global])
#
#            np.savetxt(path+'/'+species+'/Skewness/P_net_j'+str(j)+'_t'+str(i+1)+'.dat', np.c_[PDF_bins[Num_bins:], Skewness_net])
#            np.savetxt(path+'/'+species+'/Skewness/P_par_j'+str(j)+'_t'+str(i+1)+'.dat', np.c_[PDF_bins[Num_bins:], Skewness_par])
#            np.savetxt(path+'/'+species+'/Skewness/P_perp_j'+str(j)+'_t'+str(i+1)+'.dat', np.c_[PDF_bins[Num_bins:], Skewness_perp])

        #Calculate all the moments at scale j
        if mpi_rank==0:
            print("Calculating moments at scale "+str(j))
        V_moments = Diagnostics.Averaged_Moments(V_j)
        V_moments_global = MPI_mean_array(V_moments)
        V_moments_vs_j[i][j] = V_moments_global

        vpar_moments = Diagnostics.Averaged_Moments(vpar_j)
        vpar_moments_global = MPI_mean_array(vpar_moments)
        vpar_moments_vs_j[i][j] = vpar_moments_global

        vperp_moments = Diagnostics.Averaged_Moments(vperp_j)
        vperp_moments_global = MPI_mean_array(vperp_moments)
        vperp_moments_vs_j[i][j] = vperp_moments_global

    ##Calculate Ensemble Average of Mu
    #Mu_global=MPI_mean_array(np.mean(Mu_j_full,axis=0))

    #Output Full trace of Moments for calculating Flatness
#    if mpi_rank == 0:
#        np.savetxt(path+'/'+species+'/Moments/Mu_'+str(j)+'_trace.dat', np.c_[time, Mu_global])
#        moments_par=Diagnostics.Moment(vpar_j_full,N)
#        moments_perp=Diagnostics.Moment(vperp_j_full,N)
#        np.savetxt(path+'/'+species+'/Moments/v_par_j'+str(j)+'_trace.dat', np.c_[time, moments_par])
#        np.savetxt(path+'/'+species+'/Moments/v_perp_j'+str(j)+'_trace.dat', np.c_[time, moments_perp])

#    #Calculate velocity diffusion
#    vpar_j_Global=Diffusion(vpar_j_full, ref, N)
#    vperp_j_Global=Diffusion(vperp_j_full,ref, N)
#
#    if mpi_rank==0:
#        np.savetxt(path+'/'+species+'/Diffusion/v_par_rms_j'+str(j)+'.dat', np.c_[time[ref:N], vpar_j_Global])
#        np.savetxt(path+'/'+species+'/Diffusion/v_perp_rms_j'+str(j)+'.dat', np.c_[time[ref:N], vperp_j_Global])
#
for i in range(3):
    np.savetxt(path+'/'+species+'/Moments/moments_vpar_t'+str(i+1)+'.dat', np.c_[scale_j, vpar_moments_vs_j[i]])
    np.savetxt(path+'/'+species+'/Moments/moments_vperp_t'+str(i+1)+'.dat', np.c_[scale_j, vperp_moments_vs_j[i]])

#Specify the time window over which to average:

#    Energy_j_full = Diagnostics.new_extract_scale(coefs_energy, j, wavelet, mode, 0, N)
#    for i in range(3):
#        t_ind_low = i*N//4
#        t_ind_high = (i+2)*N//4
#
#        Energy_j = Energy_j_full[:, t_ind_low : t_ind_high]
#
#        norm_t = 1./float(t_ind_high - t_ind_low)
#        E_j_PDF_tavg, PDF_bins = Diagnostics.PDF(Energy_j[:,0])
#
#        E_j_PDF_tavg *= norm_t
#
#        for t_ind in range(1, t_ind_high-t_ind_low):
#            E_j_PDF, PDF_bins = Diagnostics.PDF(Energy_j[:,t_ind])
#
#            E_j_PDF_tavg += E_j_PDF*norm_t
#
#        E_j_PDF_global = MPI_mean_array(E_j_PDF_tavg)
#
#        if mpi_rank == 0:
#            np.savetxt(path+'/'+species+'/PDFs/pdf_energy_j'+str(j)+'_t'+str(i+1)+'.dat', np.c_[PDF_bins, E_j_PDF_global])
#
#        #Calculating the skewness
#        Num_bins=len(PDF_bins)/2
#        First_half=E_j_PDF_global[:Num_bins]
#        Second_half=E_j_PDF_global[Num_bins:]
#        Skewness=np.log10(First_half[::-1]/Second_half)
#        if mpi_rank == 0:
#            np.savetxt(path+'/'+species+'/Skewness/energy_j'+str(j)+'_t'+str(i+1)+'.dat', np.c_[PDF_bins[Num_bins:], Skewness])
#
#for i in range(3):
#    t_ind_low = i*N//4
#    t_ind_high = (i+2)*N//4
#
#    Energy_fraction = Energy[:, t_ind_low : t_ind_high]
#
#    norm_t = 1./float(t_ind_high - t_ind_low)
#    E_PDF_tavg, PDF_bins = Diagnostics.PDF_nomean(Energy_fraction[:,0])
#
#    E_PDF_tavg *= norm_t
#
#    for t_ind in range(1, t_ind_high-t_ind_low):
#        E_PDF, PDF_bins = Diagnostics.PDF_nomean(Energy_fraction[:,t_ind])
#
#        E_PDF_tavg += E_PDF*norm_t
#
#    E_PDF_global = MPI_mean_array(E_PDF_tavg)
#
#    if mpi_rank == 0:
#        np.savetxt(path+'/'+species+'/PDFs/pdf_energy_raw_t'+str(i+1)+'.dat', np.c_[PDF_bins, E_PDF_global])
#
#    #Calculating the skewness
#    Num_bins=len(PDF_bins)/2
#    First_half=E_j_PDF_global[:Num_bins]
#    Second_half=E_j_PDF_global[Num_bins:]
#    Skewness=np.log10(First_half[::-1]/Second_half)
#    if mpi_rank == 0:
#        np.savetxt(path+'/'+species+'/Skewness/energy_raw_t'+str(i+1)+'.dat', np.c_[PDF_bins[Num_bins:], Skewness])

if mpi_rank==0:
    print('Moments and PDFs exported')
    t2 = (sys_time.time()-tstart)
    print('Diagnostics complete; time taken = ' + str(np.round(t2/60,decimals=1)) + ' minutes')
sys.exit(0)


import torch
import math
import torch.nn as nn
from torch.autograd import Variable

class PositionalEncoding(nn.Module):
    def __init__(self, d_model, dropout, max_len=5000):
        """
        :param d_model: pe编码维度，一般与word embedding相同，方便相加
        :param dropout: dorp out
        :param max_len: 语料库中最长句子的长度，即word embedding中的L
        """
        self.out_dim = d_model
        super(PositionalEncoding, self).__init__()
        # 定义drop out
        self.dropout = nn.Dropout(p=dropout)
        # 计算pe编码
        pe = torch.zeros(max_len, d_model)  # 建立空表，每行代表一个词的位置，每列代表一个编码位
        position = torch.arange(0, max_len).unsqueeze(1)  # 建个arrange表示词的位置以便公式计算，size=(max_len,1)
        div_term = torch.exp(torch.arange(0, d_model, 2) *    # 计算公式中10000**（2i/d_model)
                             -(math.log(10000.0) / d_model))
        pe[:, 0::2] = torch.sin(position * div_term)  # 计算偶数维度的pe值
        pe[:, 1::2] = torch.cos(position * div_term)  # 计算奇数维度的pe值
        pe = pe.unsqueeze(0)  # size=(1, L, d_model)，为了后续与word_embedding相加,意为batch维度下的操作相同
        self.register_buffer('pe', pe)  # pe值是不参加训练的

    def forward(self, x):
        # 输入的最终编码 = word_embedding + positional_embedding
        x = x + Variable(self.pe[:, :x.size(0)], requires_grad=False).reshape(x.size(0), self.out_dim)  # size = [batch, L, d_model]
        return self.dropout(x)  # size = [batch, L, d_model]


#!/usr/bin/python3

# ## {R2D2919B742E} ##
# ###########################################################################
# What if magic existed?
# What if a place existed where your every thought and dream come to life.
# There is only one catch: it has to be written down.
# Such a place exists, it is called programming.
#    - Scott Taylor Reph, RightThumb.com
# ###########################################################################
# ## {C3P0D40fAe8B} ##

##################################################
import os, sys, time
##################################################
import _rightThumb._construct as __
appDBA=__.clearFocus(__name__,__file__);__.appReg=appDBA;
def focus(parentApp='',childApp='',reg=True):
	global appDBA;f=__.appName(appDBA,parentApp,childApp);
	if reg:__.appReg=f;
	return f
import _rightThumb._base3 as _
fieldSet=_.l.vars(focus(),__name__,__file__,appDBA)
_.load()
##################################################
_v = __.imp('_rightThumb._vars')
_str = __.imp('_rightThumb._string')
##################################################

def sw():
	pass
	#b)--> examples
	_.switches.register( 'Requests', '-r' )
	_.switches.register( 'Print', '-print' )
	#e)--> examples
	# _.switches.register( 'Files', '-f,-fi,-file,-files','file.txt', isData='glob,name,data,clean', description='Files', isRequired=False )

# __.setting('require-list',['Files,Plus','File,Has']) # todo
# __.setting('require-list',['Pipe','Files'])
__.setting('receipt-log')
__.setting('receipt-file')
__.setting('myFileLocations-skip-validation',False)
__.setting('require-pipe',False)
__.setting('require-pipe||file',False)
__.setting('pre-error',False)
__.setting('switch-raw',[])

_.appInfo[focus()] = {
	# 'app': '8facG-jo0Cxk',
	'file': 'thisApp.py',
	'liveAppName': __.thisApp( __file__ ),
	'description': 'Changes the world',
		# _.ail(1,'subject')+
		# _.aib('one')+
	'categories': [
						'DEFAULT',
				],
	'usage': [
						# 'epy another',
						# 'e nmap',
						# '',
	],
	'relatedapps': [
						# 'p another -file file.txt',
						# '',
	],
	'prerequisite': [
						# 'p another -file file.txt',
						# '',
	],
	'examples': [
						_.hp('p thisApp -file file.txt'),
						_.linePrint(label='simple',p=0),
						'',
	],
	'columns': [
					# { 'name': 'name', 'abbreviation': 'n' },
					# { 'name': '{1}', 'abbreviation': '{0}', 'sort': '{2}' },
	],
	'aliases': [
					# 'this',
					# 'app',
	],
	'notes': [
					# {},
	],
}

_.appData[focus()] = {
		'start': __.startTime,
		'uuid': '',
		'audit': [],
		'pipe': False,
		'data': {
					'field': {'sent': [], 'received': [] }, # { 'label': '', 'context': [],  }
					'table': {'sent': [], 'received': [] },
		},
	}

def triggers():
	_.switches.trigger( 'Files', _.myFileLocations, vs=True )
	_.switches.trigger( 'Ago', _.timeAgo )
	_.switches.trigger( 'Folder', _.myFolderLocations )
	_.switches.trigger( 'URL', _.urlTrigger )
	_.switches.trigger( 'Duration', _.timeFuture )

_.l.conf('clean-pipe',True)
_.l.sw.register( triggers, sw )

########################################################################################
#b)--> examples
#d)--> code hints to quickly get started
	#n)--> inline examples
		# any(ele in 'scott5' for ele in list('0123456789'))
		# if _.switches.isActive('Test'): test(); return None;
		# result=[]; result=[ _.pr(line) for i, line, bi in _.numerate( _.isData(r=0) )]
		# bk=[];[  bk.append(rec['backup']) for rec in backupLog if path == rec['file']]; bk=bk[-1];
		# a=(1 if True else 0) <--#
		#!)--> m=[[row[i] for row in matrix] for i in range(4)]

	#n)--> python globals
		# for k in globals(): print(k, eval(k) )

	#n)--> webpage from url
		# for subject in _.caseUnspecific( line, needle ): line = line.replace( subject, _.colorThis( subject, 'green', p=0 ) )

	#n)--> webpage from url
		# requests=__.imp('requests.post')
		#!)--> data=str(requests.post(url,data={}).content,'iso-8859-1')

	#n)--> import and backup example
		# _bk = _.regImp( __.appReg, 'fileBackup' ); _bk.switch( 'Silent' ); _bk.switch( 'isRunOnce' ); _bk.switch( 'Flag', 'APP' ); _bk.switch( 'DoNotSchedule' )
		# _bk.switch( 'Input', path ); bkfi = _bk.action();

	#n)--> inline
		# for rel in [ subject for subject in _.isData(r=0) if _.showLine(subject) ]: print(rel)

	#n)--> banner
		# banner=_.Banner(app); goss=banner.goss;
#e)--> examples
########################################################################################
#n)--> start

def _listener_():
	global hk
	# hkr.do("beepy.note('d',3,'dotted_eigth')") # (:g e:) c,    c#, d, d#, e, f, f#, g, g#, a, a#
	# sys.exit()
	hk.beepy.note('d',3,'dotted_eigth')
	r = sr.Recognizer()
	with sr.Microphone() as source:
		if _.switches.isActive('Print'):
			print("Talk")
		# audio = r.listen(source,timeout=1)
		audio = r.listen(source)
	try:
		# beepy.note('f')
		_translate_(r.recognize_google(audio))
		# hk.beepy.note('d')
		# beepy.note('a')

	except Exception as e:
		print(e)
		pass
		if _.switches.isActive('Print'):
			print('translate failure')
		hk.beepy.note('d',4,'dotted_eigth')

def _translate_(speech):
	global hk
	speech=speech.lower()

	finagled=False
	for finagle in _.v.finagling['_replace']:
		if not finagled and finagle in speech: speech=speech.replace(finagle,_.v.finagling['_replace'][finagle]); finagled=True;
	for finagle in _.v.finagling['_startswith']:
		if not finagled and speech.startswith(finagle): speech=speech=_.v.finagling['_startswith'][finagle]; finagled=True;

	# os.system('say '+speech)
	if _.switches.isActive('Print'):
		print('said:',speech)
	_.v.prompt=speech
	subject=None
	def check(tst): return tst if not subject and len(tst.split(' ')) == sum(1 for y in tst.split(' ') if ' ' + y + ' ' in ' ' + speech + ' ') else None
	def checkAll(dic):
		subject=None
		for sub in dic:
			if not subject:
				if check(sub):
					if _.switches.isActive('Print'):
						print(0,dic[sub])
					subject = sub
					# print(99,sub,sub in _.v.local)
					if not sub in _.v.local:
						hkr.do(dic[sub])
					else:
						exec(dic[sub])
					if _.switches.isActive('Print'):
						print(1,dic[sub])
			# if subject: print(dic[sub])
		return subject

	global dic

	subject = checkAll(dic)
	if subject:
		# hkr.do("beepy.note('d',3,'dotted_eigth')")
		run='say '+subject
		if _.switches.isActive('Print'):
			print(run)
		# os.system(run)
		hk.beepy.note('d',3,'whole')
	else:
		print('no subject')
		hk.beepy.note('d',2,'half')
		# hkr.do("beepy.note('d',2,'dotted_eigth')")
		# print('no subject')

# sub='explode'
# elif check(sub):
#     subject=sub
#     Clip.explode()

# sub='implode'
# if check(sub):
#     subject=sub
#     Clip.implode()

	# print(speech)

def action():
	if _.switches.isActive('Requests'):
		global dic
		table=[]
		for k in dic:
			rec={ 'request': k, 'action': dic[k] }
			if _.showLine(str(rec)):
				table.append(rec)
		_.pt(table)
	else:
		_listener_()

# print(1)
# hkr.do('_test_()')
# print(2)
# sys.exit()
# import hotkeys as hk

def ai():

	max_tokens=1024
	if _.switches.isActive('Print'):
		print('ai: initialization')
		print(_.v.prompt)
	global interact
	# Sally paste  convert the folling python to a single line
	prompt = _.v.prompt.replace('sally','')
	if 'unlimited tokens' in _.v.prompt:
		_.v.prompt.replace('max tokens','')
		max_tokens=int(max_tokens*2)
	if 'paste' in prompt:
		prompt=prompt.replace('paste','')
		_paste = _.regImp( __.appReg, '-paste' )
		lines=[]
		lines.append(prompt.strip()+': ')
		for line in _paste.imp.paste().replace('\r','').split('\n'):
			if 'python' in prompt.lower(): line=line.split('#')[0]
			if 'javascript' in prompt.lower(): line=line.split('//')[0]
			line=line.replace('    ','\t').rstrip()
			if line: lines.append(line)
		prompt = '\n'.join(lines)
	import openai

	if _.switches.isActive('Print'):
		print('_________________')
		print(prompt)
		print('_________________')
	# Apply the API key
	# openai.api_key = _blowfish.decrypt('+WDUtsrHiXMJ2Rk2Z7QMSyoo+xzLW/BhSw/kTcUwPmZGQBDpZs7LcGpy2hm+rAWQ+ZtzKKLFVO8=', _vault.key() )
	# openai.api_key = os.environ['OPENAI_API_KEY']
	openai.api_key = _keychain.imp.key('open-ai-api')

	# Define your prompt
	# prompt = "Write a short story about a person who finds a treasure."

	# Request a response from the API
	response = openai.Completion.create(
		# https://platform.openai.com/docs/models/codex
		# engine="code-davinci-002",
		# engine="text-davinci-002",
		engine="text-davinci-003",
		prompt=prompt,
		temperature=0.9,
		top_p=1,
		frequency_penalty=0.0,
		presence_penalty=0.6,
		# max_tokens=150,
		# stop=[" Human:", " AI:"],
		max_tokens=max_tokens,
		# n=1,
		stop=None,
		# temperature=0.5,
	)

	# def process_prompt_chunk(chunk,max_tokens):
	# 	return openai.Completion.create(
	# 		engine="text-davinci-003",
	# 		prompt=chunk,
	# 		temperature=0.9,
	# 		top_p=1,
	# 		frequency_penalty=0.0,
	# 		presence_penalty=0.6,
	# 		max_tokens=max_tokens,
	# 		stop=None,
	# 	)

	# def process_large_prompt(large_prompt, chunk_size,max_tokens):
	# 	responses = []
	# 	for i in range(0, len(large_prompt), chunk_size):
	# 		chunk = large_prompt[i:i+chunk_size]
	# 		response = process_prompt_chunk(chunk,max_tokens)
	# 		responses.append(response)
	# 	return responses

	# large_prompt = prompt
	# chunk_size = 2048  # adjust based on your needs and API limitations
	# responses = process_large_prompt(large_prompt, chunk_size,max_tokens)

	# Print the response
	if not 'listen' in interact: interact['listen']=[]
	interact['listen'].append({'epoch': time.time(), 'prompt': prompt, 'response': response["choices"][0]["text"]})
	_.saveTable(interact,'ai-bot-interaction.index',p=0)
	if _.switches.isActive('Print'):
		print(response["choices"][0]["text"])
	_copy = _.regImp( __.appReg, '-copy' )
	_copy.imp.copy( response["choices"][0]["text"] )

##################################################
# https://nitratine.net/blog/post/simulate-mouse-events-in-python/

# _code = _.regImp( __.appReg, '_rightThumb._auditCodeBase' )
# _code.imp.validator.register( 'data', 'javascript' )
# _code.imp.validator.createIndex( data, 'javascript', skipLoad=True, simple=False, B=True )
# c = _code.imp.validator.identity['location']['open'][o]

# _.pv(selectors)
# sys.exit()

def cp():
	global keyboard
	with keyboard.pressed(Key.ctrl): vVv='c'; keyboard.press(vVv); keyboard.release(vVv);
def pa():
	global keyboard
	with keyboard.pressed(Key.ctrl): vVv='v'; keyboard.press(vVv); keyboard.release(vVv);

def aquire_snippets():
	print('aquire_snippets')
	global keyboard
	global ti
	snippets=[]
	i=0
	while not i==3:
		i+=1
		time.sleep(ti['min'])
		cp()
		time.sleep(ti['min'])
		snippets.append( _paste.imp.paste() )
		time.sleep(ti['min'])
		keyboard.press(Key.up)
		time.sleep(ti['tiny'])
		keyboard.release(Key.up)
		time.sleep(ti['min'])
	return snippets

# def probable_selectors(snippets):

#     _code.imp.validator.register( 'data', 'javascript' )

#     selectors=[]
#     for snip in snippets:
#         snip=snip.replace('\r','')
#         lines=snip.split('\n')
#         _code.imp.validator.createIndex( data, 'javascript', skipLoad=True, simple=False, B=True )
#         c = _code.imp.validator.identity['location']['open'][o]

def snippet_to_selector(snippets):
	print('snippet_to_selector')
	payload=[]
	profiles = {
					'tag':     {
							'definitive': [
											'pre',
											'code',
											'h3',
							],
							'common': [
											'div',
											'td',
							],
							'parent': [
							],
							'children': [
											'a',
							],
							'omit': [
											'span',
											'tbody',
											'thead',
							],
					},
					# 'attributes':     {},
	}
	proDex={}
	omit=[]
	yTag=[]
	# profiles['tag']['definitive']
	for sec in profiles['tag']:
		for tag in profiles['tag'][sec]:
			if sec == 'omit':
				omit.append(tag)
			else:
				proDex[tag]=sec
				if sec == 'children' or sec == 'parent':
					yTag.append(tag)

	_.pv(proDex)
	# sys.exit()

	results=[]
	for snip in snippets:
		code=snip.replace('\r','').split('\n')[0]
		simpin = {
					' ': 'bc05cdf4',
					'\\"': 'fa9509d9',
		}
		# code='<td class="titleColumn another yet" test="a a\\"s s\\"ds f" yy="abc 123 def 456">'
		sel={}
		selectors={}
		selectors['tag']='err'
		selectors['classes']=''
		selectors['attributes']={}
		selectors['selectors']=[]
		if not '"' in code: selectors['tag']=code.split(' ')[0][1:]
		elif '"' in code:
			code=code.replace('\\"',simpin['\\"'])
			parts=code.split('"')
			key=''
			isNext=False
			for i,x in enumerate(parts):
				if not i:
					_.pr(x,c='green')
					y=x.split(' ')[0]
					selectors['tag']=y[1:]
					_.pr(y,c='purple')
				if x.endswith('='):
					isNext=True
					# print(i,'=',x)
					if ' ' in x: key=x.split(' ')[1]
					else: key=x
					key=key.replace('=','')
				elif isNext:
					sel[key]=x.replace(simpin['\\"'],'\\"')
					isNext=False
					# print(i,'Y',x)
				# else: print(i,'N',x)
			# _.pv(sel)
			if 'class' in sel:
				_classes=[]
				for cl in sel['class'].split(' '): _classes.append('.'+cl)
				selectors['classes']=' '.join(_classes)

			selectors['attributes']=sel
			selectors['selectors'].append(selectors['tag']+' '+selectors['classes'])
			tcl=selectors['tag']+' '+selectors['classes'].split(' ')[0]
			if not tcl in selectors['selectors']: selectors['selectors'].append(tcl)
			for cl in selectors['classes'].split(' '): selectors['selectors'].append(cl)
			results.append(selectors)
	# _.saveTable2(results,'listen_snippet_to_selector.json')
	# _.pv(results)
	refined=[]
	for rec in results:
		refined.append(rec)
		if rec['tag'] in proDex and proDex[rec['tag']] == 'parent':
			break
		if rec['classes']: break
	refined.reverse()
	for rec in refined:
		if rec['tag'] in profiles['tag']['definitive']: return rec['tag']
		tag=rec['tag']
		classy=rec['classes']
		_sel_=''
		started=True
		if not tag in omit:
			if tag in proDex: started=True
			if started:
				if tag in proDex:
					if tag in yTag:
						_sel_+=tag
					if classy:
						_sel_+=' '+classy

		if _sel_: payload.append(_sel_)
	_.pv(results)
	_.pv(yTag)
	print('snippet_to_selector')
	return '  '.join(payload)

def code_scanner():
	print('code_scanner')
	global keyboard
	global ti
	def _scan_(code,r=False):
		global keyboard
		_copy.imp.copy( code )
		with keyboard.pressed(Key.ctrl): vVv='`'; keyboard.press(vVv); keyboard.release(vVv);

		time.sleep(ti['abit1'])
		pa()
		time.sleep(ti['min'])
		keyboard.press(Key.enter); keyboard.release(Key.enter);

		clip=_paste.imp.paste()
		while clip==code:
			time.sleep(ti['min'])
			clip=_paste.imp.paste()

		return clip
	snippets=aquire_snippets()
	# result=_scan_('_skimmer_=123; copy(_skimmer_);')
	# _.pv(snippets)
	# _.saveTable2(snippets,'listen_snippets.json')
	# print('_skimmer_:',result)
	# _.pv(snippets)
	selector = snippet_to_selector(snippets)
	time.sleep(ti['min'])
	keyboard.press(Key.f12)
	keyboard.release(Key.f12)
	time.sleep(ti['abit2'])
	print('selector:',selector)
	if not selector:
		_.e('unable to copy','selector is empty')
	_copy.imp.copy( selector )
	time.sleep(ti['abit1'])
	hkr.do('Clip.browser_f12_tooljs_text()')

ti={
		'tiny': .05,
		'min': .2,
		'abit1': .3,
		'abit2': .6,
}

def clean_text():
	lines = _paste.imp.paste().replace('\r','').split('\n')
	_copy.imp.copy(' '.join(lines))

def auto_scrape():

	# prompt
	# i created an algorithm where i can put my mouse over an element on a webpage and it automatically right clicks, goes to inspect, collects element information, goes up an element more than once. It then tries to identify how to extract information from that webpage.

	print('auto_scrape')
	global mouse
	global keyboard
	global ti
	# time.sleep(3)
	mouse.click(Button.right, 1)
	time.sleep(ti['min'])
	keyboard.press(Key.up)
	keyboard.release(Key.up)
	time.sleep(ti['min'])
	keyboard.press(Key.enter)
	keyboard.release(Key.enter)
	time.sleep(ti['abit1'])
	code_scanner()
	lines=[]
	count={}
	for line in _paste.imp.paste().replace('\r','').split('\n'):
		line=line.strip()
		if line:
			if not line in count:
				count[line]=0
			count[line]+=1
	for line in lines:
		line=line.strip()
		if line:
			if not count[line] > 2:
				lines.append(line)
	_copy.imp.copy('\n'.join(lines))

def ipsum():
	print('ipsum')
	import lorem
	lines=[]
	lines.append(lorem.paragraph())
	lines.append(lorem.paragraph())
	lines.append(lorem.paragraph())
	lines.append(lorem.paragraph())
	lines.append(lorem.paragraph())
	_copy.imp.copy('\n\n'.join(lines))

# time.sleep(ti['min'])
# keyboard.press(Key.f12)
# keyboard.release(Key.f12)

def randomize_text():
	_paste = _.regImp( __.appReg, '-paste' )
	text = _paste.imp.paste()
	_copy = _.regImp( __.appReg, '-copy' )

	import re
	import random
	import string
	def randomize(match):
		domains = ['domain.com', 'domain.net', 'domain.org', 'domain.quest', 'domain.xyz', 'domain.guru', 'domain.cx', 'domain.ac', 'domain.work', 'domain.app', 'domain.vip', 'example.com', 'example.net', 'example.org', 'example.quest', 'example.xyz', 'example.guru', 'example.cx', 'example.ac', 'example.work', 'example.app', 'example.vip', 'site.com', 'site.net', 'site.org', 'site.quest', 'site.xyz', 'site.guru', 'site.cx', 'site.ac', 'site.work', 'site.app', 'site.vip']
		firsts = ['Emma', 'Liam', 'Olivia', 'Ava', 'Isabella', 'Sophia', 'Mia', 'Charlotte', 'Amelia', 'Evelyn', 'Emily', 'Sofia', 'Avery', 'Ella', 'Grace', 'Madison', 'Aiden', 'Lucas', 'Ethan', 'Sebastian', 'Jack', 'Daniel', 'Samuel', 'Matthew', 'Michael', 'Andrew', 'Joshua', 'Ryan', 'Nathan', 'Adam', 'Robert', 'Nicholas', 'Anthony', 'John', 'Thomas', 'Charles', 'Zachary', 'Aaron', 'Jacob', 'Justin', 'Tyler', 'Austin', 'Jordan', 'Kyle']
		s = match.group(0)
		if re.match(r'[\'\"]\+?\d+[\'\"]', s):
			phone_number = s.strip('\'\"')
			area_code, rest = phone_number[:4], phone_number[4:]
			randomized_rest = ''.join(random.choice(string.digits) for _ in range(len(rest)))
			return f'"{area_code}{randomized_rest}"'
		elif re.match(r'[\'\"].+?@.+?[\'\"]', s):
			local, domain = s.strip('\'\"').split('@')
			domain = random.choice(domains)
			# local = ''.join(random.choice(string.ascii_letters + string.digits) for _ in range(len(local)))
			local = random.choice(firsts)

			return f'"{local}@{domain}"'
		else:
			randomized = ''.join(random.choice(string.ascii_letters + string.digits) for _ in range(len(s) - 2))
			return f'{s[0]}{randomized}{s[-1]}'

	pattern = r'[\'\"].+?[\'\"]'
	result = re.sub(pattern, randomize, text)
	_copy.imp.copy( result )
	return result

# sys.exit()

##################################################
# _var='''
# _v.stmp={home}/.rt/profile/temp
# _v.tempFile={home}/.rt/profile/temp/{8E3F33E4-86AB-AB1E-6219-801DE111D9AF}
# _v.terminal={home}/.rt/profile/vars/terminal/
# _v.terminal_variables={home}/.rt/profile/vars/terminal/16910
# _v.text_temp={home}/.rt/profile/temp/_temp.txt
# _v.thisHost={home}/.rt/profile
# _v.tmpbat={home}/.rt/profile/temp/44E28BDF-8269-EEAE-D1DC-9B05B63E5F93.bat
# _v.tmpf={home}/.rt/profile/temp/{8E3F33E4-86AB-AB1E-6219-801DE111D9AF}
# _v.tmpf0={home}/.rt/profile/temp/{B820137A-79B8-45E3-BCBD-A6CAC50892D0}
# _v.tmpf2={home}/.rt/profile/temp/{5FBF34C0-9A95-4C7E-BA53-44F84ECECCB5}
# _v.tmpf3={home}/.rt/profile/temp/{F139D191-FA1A-44D5-855C-7E5141B30E0D}
# _v.tmpf4={home}/.rt/profile/temp/{AA8EC8E1-EA9D-460D-A593-7B0FAEB9243E}
# _v.tmpf5={home}/.rt/profile/temp/{201D82D6-2DC0-4552-A598-54F5481399A1}
# _v.tmpf6={home}/.rt/profile/temp/{26B3B9C6-0A59-432A-9386-D432B53001CB}
# _v.tmpf7={home}/.rt/profile/temp/{C03C0132-CFFC-4E3A-8F0F-614BB95164C7}
# _v.tmpf8={home}/.rt/profile/temp/{4CCA3EBD-4535-42B7-9C75-05EFAACB00E0}
# _v.tmpf9={home}/.rt/profile/temp/{DF1D4EBC-838E-419C-9C58-943C1767391A}
# _v.tt={home}/.rt/profile/tables
# _v.tvy={home}/.rt/profile/vars/terminal/16910.yml
# _v.txt_temp={home}/.rt/profile/temp/_temp.txt
# _v.umlHtml={home}/.rt/profile/json-uml-tree/index.htm
# _v.umlJson={home}/.rt/profile/json-uml-tree/data.js
# _v.unixID_path={home}/.rt/profile/config/.unix_id
# _v.vault_path={home}/.rt/profile/config/.vault
# _v.wprofile={home}/.rt/profile

# _v.t={w}
# _v.ta={w}/techApps
# _v.tablesDB={w}/widgets/databank/tables
# _v.techDrive={w}
# _v.techFolder={w}
# _v.ttt={w}/widgets/databank/tables
# _v.updates={w}/widgets/project/updates
# _v.w={w}
# _v.webapp={w}/widgets/servers/web/crud
# _v.widgets={w}
# _v.ww={w}/widgets
# '''.strip().replace('\r','').replace('\n\n','\n').replace('/',os.sep).split('\n')

# _vTerm='''
# stmp={home}/.rt/profile/temp
# h={home}/.rt/profile
# pr={home}/.rt/profile/projects
# rt={home}/.rt
# tt={home}/.rt/profile/tables
# tmpf8={home}/.rt/profile/temp/{4CCA3EBD-4535-42B7-9C75-05EFAACB00E0}
# tmpf9={home}/.rt/profile/temp/{DF1D4EBC-838E-419C-9C58-943C1767391A}
# tmpf6={home}/.rt/profile/temp/{26B3B9C6-0A59-432A-9386-D432B53001CB}
# tmpf7={home}/.rt/profile/temp/{C03C0132-CFFC-4E3A-8F0F-614BB95164C7}
# tmpf4={home}/.rt/profile/temp/{AA8EC8E1-EA9D-460D-A593-7B0FAEB9243E}
# tmpf5={home}/.rt/profile/temp/{201D82D6-2DC0-4552-A598-54F5481399A1}
# tmpf2={home}/.rt/profile/temp/{5FBF34C0-9A95-4C7E-BA53-44F84ECECCB5}
# tmpf3={home}/.rt/profile/temp/{F139D191-FA1A-44D5-855C-7E5141B30E0D}
# tmpf0={home}/.rt/profile/temp/{B820137A-79B8-45E3-BCBD-A6CAC50892D0}
# tmpf1={home}/.rt/profile/temp/{C0FA8E56-8426-46BB-9CE8-4A14C51EA261}
# wprofile={home}/.rt/profile
# config={home}/.rt/profile/config

# ttt={w}/widgets/databank/tables
# db={w}/widgets/databank
# w={w}
# s={w}/widgets/batch
# bash={w}/widgets/bash
# ps={w}/widgets/powershell
# bat={w}/widgets/batch
# ww={w}/widgets
# widgets={w}
# js={w}/widgets/javascript
# '''.strip().replace('\r','').replace('\n\n','\n').replace('/',os.sep).split('\n')

# def variable():
#     global _var
#     global _vTerm
#     _paste = _.regImp( __.appReg, '-paste' )
#     data = _paste.imp.paste()
#     l=data.count('l')
#     w=data.count('\\')
#     if l > w: lw = '/'
#     else:     lw = '\\'
#     data = data.replace(lw,os.sep)
#     for line in data.split('\n'):
#         has1=[]
#         has2=[]
#         for li in _var:
#             if li in line: has1.append({'line':line,'cnt':len(li)},'li':li)
#         has1 = _.sort(has1,'cnt')
#         for li in _vTerm:
#             if li in line: has2.append({'line':line,'cnt':len(li)},'li':li)
#         has2 = _.sort(has2,'cnt')

#         for x in has1: print(x)
#         _.pr(line=1)
#         for x in has2: print(x)

##################################################
_.v.local=[
				'variable',
				'sally',
				'auto scrape',
				'ipsum',
				'lorem',
				'secure',
				'clean text',
		]

dic = {
			'variable': 'variable()',
			'sally': 'ai()',
			'auto scrape': 'auto_scrape()',
			'clean text': 'clean_text()',

			'secure': 'randomize_text()',

			'ipsum': 'ipsum()',
			'lorem': 'ipsum()',

			'center comment': 'Clip.center_to_top_comment()',

			'md5': 'Clip.md5()',
			'explode': 'Clip.explode()',
			'implode': 'Clip.implode()',
			'first': 'Clip.first()',
			'lower case': 'Clip.toLower()',
			'upper case': 'Clip.toUpper()',
			'randomize case': 'Clip.toRandomCase()',

			'scrape text': 'Clip.browser_f12_tooljs_text()',
			'extract text': 'Clip.browser_f12_tooljs_text()',

			'extract table': 'Clip.browser_f12_tooljs_table()',
			'scrape table': 'Clip.browser_f12_tooljs_table()',

			'markdown link': 'Clip.browser_f12_gen_md_link()',
			'markdown url': 'Clip.browser_f12_gen_md_link()',

			'scrape table no header': 'Clip.browser_f12_tooljs_table0()',
			'extract table no header': 'Clip.browser_f12_tooljs_table0()',

			'remove duplicate spaces': 'Clip.dup_space()',

			'convert': 'Clip.auto_yaml_json_converter()',
			# 'yaml to json': 'Clip.yaml2json()',
			# 'json to yaml': 'Clip.json2yaml()',

			'strip': 'Clip.strip1()',
			'clean up': 'Clip.strip2()',

			'space to underscore': 'Clip.space_2_underscore_text()',

			'reverse lines': 'Clip.reverse_lines()',

			'double space': 'Clip.space_double()',
			'single space': 'Clip.space_single()',

			'invert quotes': 'Clip.quote_inverter()',

			'dirty eval': 'Clip.dirty_eval()',

			'build app': 'Clip.SQL_to_crud()',

			'decrypt': 'Clip.decrypt_lines()',
			'encrypt lines': 'Clip.encrypt_lines()',
			'encrypt': 'Clip.encrypt_all()',

			'remove comments and spaces': 'Clip.remove_py_comments_spaces()',
			'remove comments': 'Clip.remove_py_comments()',

			'encode': 'Clip.base64_encode()',
			'decode': 'Clip.base64_decode()',

			'encrypt': 'Clip.encrypt_all()',
			'decrypt': 'Clip.decrypt_lines()',

			'math': 'Clip.math()',

}

_.v.finagling={
	'_replace': {
		'epsom': 'ipsum',
		'lauren': 'lorem',
		'floor m': 'lorem',
		'cobalt': 'kobold',
		'auto script': 'auto scrape',
	},
	'_startswith': {
		'auto scr': 'auto scrape',
		'autoscr': 'auto scrape',
		'andcode': 'encode',
	},
}

##################################################

# sally paste  convert the folling python to a single line

##################################################
from pynput.mouse import Button, Controller
from pynput.keyboard import Key
from pynput.keyboard import Controller as mController
mouse = Controller()
keyboard = mController()

##################################################

try: import speech_recognition as sr
except: pass

hkr = _.regImp( __.appReg, 'KeyWise' )
hk=hkr.imp

_paste = _.regImp( __.appReg, '-paste' )
_copy = _.regImp( __.appReg, '-copy' )

# ipsum()

##################################################
# import _rightThumb._vault as _vault
# import _rightThumb._encryptString as _blowfish
_keychain = _.regImp( __.appReg, 'keychain' )
interact=_.getTable('ai-bot-interaction.index')
if not 'success' in interact: interact = {'success':[],'failure':[],'chat':[]}
if not 'listen' in interact: interact['listen']=[]
########################################################################################
if __name__ == '__main__':
	#b)--> examples

	# banner.pr()
	# if len(_.switches.all())==0: banner.gossip()

	#e)--> examples
	action()
	_.isExit(__file__)

# https://www.imdb.com/chart/top/

# _.v.local


'''Message related operations'''
import os

from datetime import datetime
from uuid import uuid4
import boto3

DDB_TABLE_NAME = os.environ.get('DDB_TABLE_NAME')
ddb_res = boto3.resource('dynamodb')
ddb_table = ddb_res.Table(DDB_TABLE_NAME)

def create_message(item: dict) -> dict:
    '''Transform item to put into DDB'''
    dt = datetime.utcnow()
    item['pk'] = str(uuid4())
    item['sk'] = 'v0'
    item['timestamp'] = int(dt.timestamp())

    r = ddb_table.put_item(
        Item=item
    )
    return {'message_id': item['pk']}

def retrieve_message(message_id: str) -> dict:
    '''Get item in DDB'''
    r = ddb_table.get_item(
        Key={
            'pk': message_id,
            'sk': 'v0'
        }
    )
    item = r.get('Item', {})

    return item

def update_message(message_id: str, item: dict) -> dict:
    '''Update item in DDB'''
    attribute_updates = {}
    for key in item.keys():
        attribute_updates[key] = {'Action': 'PUT', 'Value': item.get(key)}

    r = ddb_table.update_item(
        Key={
            'pk': message_id,
            'sk': 'v0'
        },
        AttributeUpdates=attribute_updates
    )
    return r

def delete_message(message_id: str) -> dict:
    '''Delete item in DDB'''
    r = ddb_table.delete_item(
        Key={
            'pk': message_id,
            'sk': 'v0'
        },
    )
    return r


import pandas as pd

from stochastic.noise import GaussianNoise

from tensortrade.stochastic.processes.heston import geometric_brownian_motion_jump_diffusion_levels
from tensortrade.stochastic.utils.helpers import get_delta, scale_times_to_generate
from tensortrade.stochastic.utils.parameters import ModelParameters, default

def merton(base_price: int = 1,
           base_volume: int = 1,
           start_date: str = '2010-01-01',
           start_date_format: str = '%Y-%m-%d',
           times_to_generate: int = 1000,
           time_frame: str = '1h',
           params: ModelParameters = None):

    delta = get_delta(time_frame)
    times_to_generate = scale_times_to_generate(times_to_generate, time_frame)

    params = params or default(base_price, times_to_generate, delta)

    prices = geometric_brownian_motion_jump_diffusion_levels(params)

    volume_gen = GaussianNoise(t=times_to_generate)
    volumes = volume_gen.sample(times_to_generate) + base_volume

    start_date = pd.to_datetime(start_date, format=start_date_format)
    price_frame = pd.DataFrame([], columns=['date', 'price'], dtype=float)
    volume_frame = pd.DataFrame([], columns=['date', 'volume'], dtype=float)

    price_frame['date'] = pd.date_range(start=start_date, periods=times_to_generate, freq="1min")
    price_frame['price'] = abs(prices)

    volume_frame['date'] = price_frame['date'].copy()
    volume_frame['volume'] = abs(volumes)

    price_frame.set_index('date')
    price_frame.index = pd.to_datetime(price_frame.index, unit='m', origin=start_date)

    volume_frame.set_index('date')
    volume_frame.index = pd.to_datetime(volume_frame.index, unit='m', origin=start_date)

    data_frame = price_frame['price'].resample(time_frame).ohlc()
    data_frame['volume'] = volume_frame['volume'].resample(time_frame).sum()

    return data_frame


output
# [[9, 8, 1], [15, 2, 1], [9, 7, 2], [8, 7, 3],
# [9, 6, 3], [8, 6, 4], [9, 5, 4], [7, 6, 5]]

# Using set
arr=[1,2,3,4,5,6,7,8,9,15]
target = 18
i=0
res=[]
while i < len(arr):
    new_target = target-arr[i]
    r=[]
    j=i+1
    s1=set()
    for j in range(i+1,len(arr)):
        if new_target - arr[j] in s1:
            r.append(arr[j])
            r.append(new_target - arr[j])
            r.append(arr[i])
            res.append(r)
            r=[]
        else:
            s1.add(arr[j])
        j+=1
    i+=1
print(res)

# Implementing with sorting and two pointer
# sorting --> NlogN, iteration --> N^2,
# total --> N^2 + NlogN
# [[9, 8, 1], [15, 2, 1], [9, 7, 2], [8, 7, 3],
# [9, 6, 3], [8, 6, 4], [9, 5, 4], [7, 6, 5]]

arr=[1,8,9,15,2,3,4,5,6,7]
arr.sort()
target = 18
i=0
res=[]
while i < len(arr):
    new_target=target-arr[i]
    # Pair sum problem
    # apply two pointer approch

    r=[]
    left=i+1
    right=len(arr)-1
    while left < right:
        if new_target-arr[left] == arr[right]:
            r.append(arr[i])
            r.append(arr[left])
            r.append(arr[right])
            res.append(r)
            r=[]
            left+=1
            right-=1
        elif new_target-arr[left] > arr[right]:
            left+=1
        elif new_target-arr[left] < arr[right]:
            right-=1
    i+=1


from django.urls import path, include
from . import views

urlpatterns = [

	path('dashboard/', views.get_dashboard, name='dashboard'),
	path('accounts/', include('django.contrib.auth.urls')),
	path('register/', views.register_user, name='register'),
	path('', views.landingPage, name='landingPage'),

]


from django.urls import path
from .views import AcademyDetailView, AcademyCreateView, AcademyUpdateView, AcademyDeleteView, SkillsCreateView, SkillsUpdateView, SkillsDeleteView, HistoryCreateView, HistoryUpdateView, HistoryDeleteView, ProjectCreateView, ProjectUpdateView, ProjectDeleteView, StackCreateView, FactsCreateView, FactsUpdateView, FactsDeleteView, get_job_data

urlpatterns =[
    path('academy/<int:pk>/', AcademyDetailView.as_view(), name= 'academy-detail'),
    path('academy-add/', AcademyCreateView.as_view(), name= 'academy-create'),
    path('academy-upd/<int:pk>/', AcademyUpdateView.as_view(), name= 'academy-update'),
    path('academy-del/<int:pk>/', AcademyDeleteView.as_view(), name= 'academy-delete'),
    path('skills-add/', SkillsCreateView.as_view(), name= 'skills-create'),
    path('skills-upd/<int:pk>/', SkillsUpdateView.as_view(), name= 'skills-update'),
    path('skills-del/<int:pk>/', SkillsDeleteView.as_view(), name= 'skills-delete'),
    path('history-add/', HistoryCreateView.as_view(), name= 'history-create'),
    path('history-upd/<int:pk>/', HistoryUpdateView.as_view(), name= 'history-update'),
    path('history-del/<int:pk>/', HistoryDeleteView.as_view(), name= 'history-delete'),
    path('project-add/', ProjectCreateView.as_view(), name= 'project-create'),
    path('project-upd/<int:pk>/', ProjectUpdateView.as_view(), name= 'project-update'),
    path('project-del/<int:pk>/', ProjectDeleteView.as_view(), name= 'project-delete'),
    path('stack-add/', StackCreateView.as_view(), name= 'stack-create'),
    path('fact-add/', FactsCreateView.as_view(), name= 'fact-create'),
    path('fact-upd/<int:pk>/', FactsUpdateView.as_view(), name= 'fact-update'),
    path('fact-del/<int:pk>/', FactsDeleteView.as_view(), name= 'fact-delete'),
    path('api/job-data/', get_job_data, name='get_job_data'),
]


import re
from string import Template
from typing import List

import matplotlib as mpl
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd

from roveranalyzer.tempaltes import read_tmpl_str

# fixme: are they different? (sca, vec)
_scave_cols = ["run", "type", "module", "name", "attrname", "attrvalue"]

def is_scave_df(obj: pd.DataFrame):
    return all([c in obj.columns for c in _scave_cols])

class Opp:
    """
    Handle OMNeT++ module strings and transformations
    """

    @staticmethod
    def root_mod(module, level: int):
        if not type(module) == str:
            return "notAModule"

        module_elements = module.split(".")
        if len(module_elements) >= level:
            return ".".join(module_elements[:level])
        else:
            return ""

    @staticmethod
    def subframe_match(subframe, df_match):
        run = subframe["run"].unique()[0]
        return subframe.loc[
            subframe["root_module"].isin(
                df_match.loc[df_match["run"] == run, "root_module"]
            )
        ]

    @staticmethod
    def filter_by(df, module, name, value, apply_to_module_level=1):
        """
        Each  statistic is uniquely identified by its run, module and name values.
        a module consists of point separated 'sub-modules'. eg.
        run1#mod1.mod2.mod3:name1 = 42 defines a statistic with with name 'name1' and the
        value '42'. The statistic is generated by the module mod3 which is a submodule of mod3 etc.

        This method allows to filter out modules starting with some submodule mod1 based on the
        value of a statistic hold by the submodule mod3.

        Example: select all statistics of all host which have an active app.
        run1#network.host1.app.applicationActive = 1.0
        run1#network.host1.mac.pktCount = 33.0
        run1#network.host2.app.applicationActive = 0.0
        run1#network.host2.mac.pktCount = 33.0
        run1#network.host2.ip.pktLoss = 0.03
        Result:
        run1#network.host1.app.applicationActive = 1.0
        run1#network.host1.mac.pktCount = 33.0

        module_level:
        run1#mod1.mod2.mod3.mod4:name1
          level0 ^
          level1      ^
          level2           ^
        """
        mod = df.loc[
            (df["name"] == name) & (df["value"] == value), ("run", "module")
        ].copy()
        mod["root_module"] = df.run.apply(
            lambda x: Opp.root_mod(x, apply_to_module_level)
        )
        dfg = df.copy()
        dfg["root_module"] = dfg["module"].apply(
            lambda x: Opp.root_mod(x, apply_to_module_level)
        )
        dfg = dfg.groupby("run")
        dfg = dfg.filter()
        return dfg

    @staticmethod
    def module_path(m_path, index, tuple_on_vector=False):
        """

        :param m_path: some string representing a module name. Each path element is separated by dots
        :param index: 0-Based index of path element to return
        :param tuple_on_vector: If true a vector path element is returned as a tuple. Otherwise as a string
        :return: string of module path element or
                 tuple if tuple_on_vector is true an selected path element is a vector or
                 full path as list of tuples of size 1 or 2.
        """
        if m_path is np.nan:
            return np.nan
        items = m_path.split(".")
        if index > len(items):
            raise IndexError(f"m_path has no index {index}. Path was {m_path}")
        match = re.compile("(?P<base>.*?)(?P<vector>\[\d+\])")
        path_list = []
        for i in items:
            m = match.findall(i)
            if m:
                path_list.append((m[0][0], m[0][1]))
            else:
                path_list.append((i,))
        if index == -1:
            return path_list

        ret = path_list[index]
        if tuple_on_vector:
            if len(ret) == 2:
                return ret
            else:
                return f"{ret[0]}{ret[1]}"
        else:
            if len(ret) == 2:
                return f"{ret[0]}{ret[1]}"
            else:
                return ret[0]

    @staticmethod
    def normalize_vectors(df_vec, axis=0):
        """
        def_vec data frame of opp vector values only. This will transform the values into normalized
        column vectors  ['time', 'value']
        """
        frames = []
        time_name = "time"
        value_name = "value"
        for idx in df_vec.index:
            if axis == 1:
                mod_name = f"{Opp.module_path(df_vec.loc[idx]['module'], index=1)}"
                stat_name = df_vec.loc[idx]["name"].split(":")[0]
                time_name = f"{mod_name}.{stat_name}.time"
                value_name = f"{mod_name}.{stat_name}.value"

            data = df_vec.loc[idx]["vectime"].copy()
            data = np.append(data, df_vec.loc[idx]["vecvalue"].copy())
            data = data.reshape((-1, 2), order="F")
            tmp_d = pd.DataFrame(data, columns=[time_name, value_name])
            tmp_d.reset_index(drop=True, inplace=True)
            frames.append(tmp_d)

        df_n = pd.concat(frames, axis=axis, ignore_index=True if axis == 0 else False)

        return df_n

class OppTex:
    def __init__(self, opp=None):
        self._opp = opp

    @staticmethod
    def esc_tex(val: str):
        val = val.replace("&", "\&")
        val = val.replace("%", "\%")
        val = val.replace("$", "\$")
        val = val.replace("#", "\#")
        val = val.replace("_", "\_")
        val = val.replace("{", "\{")
        val = val.replace("}", "\}")
        val = val.replace("~", "\~")
        val = val.replace("^", "\^")
        val = val.replace("\\", "\\")

        return val

    @classmethod
    def write_module_summary(cls, run_id, module_dict: dict):

        module_list = []
        tex_mod_item = read_tmpl_str("module_item.tex")
        for _, v in module_dict.items():
            module_list.append(
                Template(tex_mod_item,).substitute(
                    module=cls.esc_tex(str(v["module"])),
                    scalar=cls.esc_tex(str(v["scalar"])),
                    vector=cls.esc_tex(str(v["vector"])),
                    histogram=cls.esc_tex(str(v["histogram"])),
                )
            )

        tex_mod = read_tmpl_str("module.tex")
        return Template(tex_mod).substitute(
            run=cls.esc_tex(run_id), module_items="".join(module_list)
        )

    @classmethod
    def write_attribute_tabular(cls, run_id, runattr_dict, itervars_dict, param_dict):
        tex_tmpl = read_tmpl_str("tabular.tex")

        runattrs = "   \\\\ \n".join(
            [
                f"\t\t{cls.esc_tex(k)} & {cls.esc_tex(str(v))}"
                for (k, v) in runattr_dict.items()
            ]
        )

        itervars = "   \\\\ \n".join(
            [
                f"\t\t{cls.esc_tex(k)} & {cls.esc_tex(str(v))}"
                for (k, v) in itervars_dict.items()
            ]
        )

        params = "   \\\\ \n".join(
            [
                f"\t\t{cls.esc_tex(k)} & {cls.esc_tex(str(v))}"
                for (k, v) in param_dict.items()
            ]
        )

        return Template(tex_tmpl).substitute(
            runattrs=runattrs,
            itervars=itervars,
            params=params,
            run=cls.esc_tex(run_id),
        )

    def create_module_summary(self, run_id, output_file=None):
        """
        Create latex table for module summary.
        :param run_id:      run_id for which tex is created
        :param output_file: if not set use to stdout
        """

        modType = np.array(self._opp._obj[["module", "type"]])
        module_dict = {}
        for m in modType:
            data = module_dict.get(
                m[0], {"module": m[0], "scalar": 0, "vector": 0, "histogram": 0}
            )
            data[m[1]] = data.get(m[1], 0) + 1
            module_dict.setdefault(m[0], data)

        tmpl = self.write_module_summary(run_id=run_id, module_dict=module_dict)

        if output_file is None:
            print(tmpl)
        else:
            with open(output_file, "w") as f:
                f.write(tmpl)

    def create_attribute_tabular(self, run_id, output_file=None):
        """
        Create latex table for attribute data.
        :param run_id:      run_id for which tex is created
        :param output_file: if not set use to stdout
        """

        tmpl = self.write_attribute_tabular(
            run_id=run_id,
            runattr_dict=self._opp.attr.run_attr_dict(run_id),
            itervars_dict=self._opp.attr.run_itervar_dict(run_id),
            param_dict=self._opp.attr.run_parameter_dict(run_id),
        )

        if output_file is None:
            print(tmpl)
        else:
            with open(output_file, "w") as f:
                f.write(tmpl)

class OppFilterItem:
    """
    Filter item applicable to OMNeT++ based data frame. #name corresponds to column of df.
    """

    @classmethod
    def list_filter(cls, name, value):
        ret = cls(name, value, regex=False)
        ret.is_list = True
        return ret

    def __init__(self, name, value, regex):
        self.name = name
        self.value = value
        self.regex = regex
        self.is_list = False

    def __str__(self):
        return self.value

    def __repr__(self) -> str:
        return (
            f"FilterItem(name: {self.name}, value: {self.value}, regex: {self.regex})"
        )

class OppFilter:
    """
    Builder pattern for OMNeT based data frames. This allows simplified selection of
    rows of the dataframe. Most columns of the data frame has two methods.
    <column_name> and <column_name>_regex. The former accepts only perfect matches
    whereas the later accepts a regex matter. If allow_number_range=True of the
    regex method is True number ranges such as '.*foo\[3..5\]\.bar\.baz' will be accepted
    and replaced with '.*foo\[\[3|4|5]]\.bar\.baz'.
    Note: All special characters must be escaped if literal brackets or dots should be matched.
    """

    def __init__(self, df: pd.DataFrame = None, data_only=True):
        self._filter_dict = {}
        self._name = None
        self._name_regex = None
        self._run = None
        self._run_regex = None
        self._type = None
        self._module = None
        self._module_regex = None
        self._data_only = data_only
        self._number_range_pattern = re.compile(
            "(?P<n_range>(?P<start>\d+)\.\.(?P<end>\d+))"
        )
        self._df = df
        if data_only:
            self._add_filter(
                OppFilterItem("type", "(scalar|vector|histogram)", regex=True)
            )

    def _apply_number_range(self, val):
        matches = re.findall(self._number_range_pattern, val)
        for match in matches:
            old_range = match[0]
            start = int(match[1])
            end = int(match[2])
            if start < end:
                range_new = (
                    "[" + "|".join([str(i) for i in range(start, end + 1)]) + "]"
                )
                val = val.replace(old_range, range_new)
            else:
                raise ValueError(f"number range in regex {val} invalid")
        return val

    def _add_filter(self, f: OppFilterItem):
        self._filter_dict[f.name] = f

    def name_in(self, name_list):
        self._add_filter(OppFilterItem.list_filter("name", name_list))
        return self

    def name(self, name):
        self._add_filter(OppFilterItem("name", name, False))
        return self

    def name_regex(self, name: str, allow_number_range=True):
        if allow_number_range:
            name = self._apply_number_range(name)

        self._add_filter(OppFilterItem("name", name, True))
        return self

    def run(self, run):
        self._add_filter(OppFilterItem("run", run, False))
        return self

    def run_regex(self, run: str, allow_number_range=True):
        if allow_number_range:
            run = self._apply_number_range(run)

        self._add_filter(OppFilterItem("run", run, True))
        return self

    def module(self, module):
        self._add_filter(OppFilterItem("module", module, False))
        return self

    def module_in(self, module_list):
        self._add_filter(OppFilterItem.list_filter("module", module_list))
        return self

    def module_regex(self, module: str, allow_number_range=True):
        if allow_number_range:
            module = self._apply_number_range(module)

        self._add_filter(OppFilterItem("module", module, True))
        return self

    def scalar(self):
        self._add_filter(OppFilterItem("type", "scalar", False))
        return self

    def vector(self):
        self._add_filter(OppFilterItem("type", "vector", False))
        return self

    def apply(self, df: pd.DataFrame = None, columns=None, copy=False):

        if df is not None:
            self._df = df

        if self._df is None:
            raise ValueError("no Dataframe set")

        bool_filter = pd.Series(
            [True for _ in range(0, self._df.shape[0])], self._df.index
        )
        for key, filter_item in self._filter_dict.items():
            if filter_item.regex:
                bool_filter = bool_filter & self._df.loc[:, key].str.match(
                    filter_item.value
                )
            elif filter_item.is_list:
                bool_filter = bool_filter & (
                    self._df.loc[:, key].isin(filter_item.value)
                )
            else:
                bool_filter = bool_filter & (self._df.loc[:, key] == filter_item.value)
        if columns is not None:
            ret = self._df.loc[bool_filter, columns]
        else:
            ret = self._df.loc[bool_filter]

        return ret.copy() if copy else ret

    def normalize_vectors(self, axis=0):
        """
        transform to column based vectors.
        axis=0 creates a (n, 2)-shaped data frame with columns ['time', 'value']
        axis=1 column based data frame with two columns ['time', 'value'] for each vector.
        """
        _df = self.apply()
        return Opp.normalize_vectors(_df, axis)

    def __str__(self) -> str:
        return self._filter_dict.__str__()

    def __repr__(self) -> str:
        ret = "Filter: "
        for key, value in self._filter_dict.items():
            ret += f"\n   {value.__repr__()}"
        return ret

class OppAttributes:
    """
    Helper to access Attributes from OMNeT++ DataFrame
    """

    def __init__(self, df):
        self._df = df

    def run_parameter(self, run, deep=True):
        ret = self._df.loc[
            (self._df["run"] == run) & (self._df["type"] == "param"),
            ("attrname", "attrvalue"),
        ]
        if ret.shape[0] == 0:
            raise ValueError(f"no data for run={run}")
        return ret.copy(deep=deep)

    def run_parameter_dict(self, run):
        ret = self.run_parameter(run)
        return {r[1][0]: r[1][1] for r in ret.iterrows()}

    def run_attr(self, run, deep=True):
        ret = self._df.loc[
            (self._df["run"] == run) & (self._df["type"] == "runattr"),
            ("attrname", "attrvalue"),
        ]
        if ret.shape[0] == 0:
            raise ValueError(f"no data for run={run}")

        return ret.copy(deep=deep)

    def run_itervar(self, run, deep=True):
        ret = self._df.loc[
            (self._df["run"] == run) & (self._df["type"] == "itervar"),
            ("attrname", "attrvalue"),
        ]
        if ret.shape[0] == 0:
            raise ValueError(f"no data for run={run}")
        return ret.copy(deep=deep)

    def run_itervar_dict(self, run):
        ret = self.run_itervar(run)
        return {r[1][0]: r[1][1] for r in ret.iterrows()}

    def run_attr_dict(self, run):
        ret = self.run_attr(run)
        return {r[1][0]: r[1][1] for r in ret.iterrows()}

    def statistics_meta_data(self, run, module, stat_name):
        r = {
            "run": run,
            "module": module,
            "name": stat_name,
            "title": "???",
            "unit": "???",
        }
        ret = self._df.loc[
            (self._df["run"] == run)
            & (self._df["type"] == "attr")
            & (self._df["module"] == module)
            & (self._df["name"] == stat_name),
            ("attrname", "attrvalue"),
        ]
        if ret.shape[0] == 0:
            raise ValueError(
                f"no meta data for run={run}, module={module}, name={stat_name}"
            )
        r.update({r[1][0]: r[1][1] for r in ret.iterrows()})
        return r

    def attr_for_series(self, s: pd.Series):
        return self.statistics_meta_data(
            run=s["run"], module=s["module"], stat_name=s["name"]
        )

class OppPlot:
    """
    Plot helper functions.
    todo: All based on OMNeT++ csv file structure
    set_xlabel
    set_xlimit(left, right)
    set_xscale() [linear, log, symlog, logit]
    set_xlimit
    set_xmargin

    set_xticks
    set_xticklabels

    """

    default_plot_args = {"linewidth": 0, "markersize": 3, "marker": ".", "color": "b"}

    plot_marker = [".", "*", "o", "v", "1", "2", "3", "4"]
    plot_color = ["b", "g", "r", "c", "m", "y", "k", "w"]

    @classmethod
    def marker(cls, idx):
        return cls.plot_marker[idx % len(cls.plot_marker)]

    @classmethod
    def color(cls, idx):
        return cls.plot_color[idx % len(cls.plot_color)]

    @classmethod
    def plt_args(cls, idx=0, *args, **kwargs):
        ret = dict(cls.default_plot_args)
        if "label" not in kwargs.keys():
            ret.setdefault("label", f"{idx}-data")

        ret.update(
            {
                "marker": cls.marker(idx),
                "color": cls.color(idx),
            }
        )
        if kwargs:
            ret.update(kwargs)
        return ret

    @classmethod
    def create_label(cls, lbl_str: str, remove_filter: List[str] = None):

        if remove_filter is not None:
            for rpl in remove_filter:
                lbl_str = lbl_str.replace(rpl, "")

        return lbl_str

    def __init__(self, accessor):
        self._opp = accessor

    def _set_labels(self, ax: plt.axes, s: pd.Series, xlabel="time [s]"):
        ax.set_xlabel(xlabel)
        attr = self._opp.attr.attr_for_series(s)
        ax.set_ylabel(f"[{attr['unit']}]")
        ax.set_title(attr["title"])

    def create_time_series(
        self, ax: plt.axes, s: pd.Series, auto_labels: bool = True, *args, **kwargs
    ):
        # Note: automatic label setting currently does not work with measurement traces,
        #       therefore we allow to turn if off by the auto_labels switch
        if auto_labels:
            self._set_labels(ax, s)
        if "label" not in kwargs:
            kwargs.setdefault("label", self.create_label(s.module, []))

        if "vecvalue" in s.index and "vectime" in s.index:
            # omnetpp based Series with Index(['vectime', 'vecvalue'], dtype='object')
            return ax.plot(s.vectime, s.vecvalue, **self.plt_args(idx=0, **kwargs))
        else:
            # standardized Series with shape (XXX,)
            return ax.plot(s, **self.plt_args(idx=0, **kwargs))

    def create_histogram(
        self,
        ax: plt.axes,
        s: pd.Series,
        bins=40,
        use_path_in_title=-1,
        attr_override=None,
        auto_labels: bool = True,
        **kwargs,
    ):
        if "density" not in kwargs:
            kwargs.setdefault("density", True)

        if "vecvalue" in s.index:
            # omnetpp based Series with Index(['vectime', 'vecvalue'], dtype='object')
            ret = ax.hist(
                s.vecvalue,
                bins,
                **kwargs,
            )
        else:
            # standardized Series with shape (XXX,)
            ret = ax.hist(s, bins, **kwargs)

        if auto_labels:
            attr = self._opp.attr.attr_for_series(s)
            if attr_override is not None:
                attr.update(attr_override)
            if use_path_in_title != -1:
                attr[
                    "title"
                ] += f" - {Opp.module_path(s['module'], use_path_in_title, tuple_on_vector=False)}"

            ax.set_title(attr["title"])
            ax.set_xlabel(f"[{attr['unit']}]")

        if "cumulative" in kwargs and kwargs["cumulative"] == True:
            # cumulative histograms sometimes have a bug which shows an annoying line down to
            # zero at the end - this removes the invalid line at the end
            axpolygons = [
                poly
                for poly in ax.get_children()
                if isinstance(poly, mpl.patches.Polygon)
            ]
            for poly in axpolygons:
                poly.set_xy(poly.get_xy()[:-1])

        return ret

@pd.api.extensions.register_dataframe_accessor("opp")
class OppAccessor:
    """
    see https://pandas.pydata.org/pandas-docs/stable/development/extending.html
    opp namespace to access attribute information for scalar, vector and
    histogram types, helpers to access data via filters and helpers to create
    simple plots like time series and histogram plots.

    See classes #OppAttributes, #OppFilter, OppFilterItem and #OppPlot for more detail.
    """

    def __init__(self, pandas_obj):
        self._validate(pandas_obj)
        self._obj: pd.DataFrame = pandas_obj
        self.plot: OppPlot = OppPlot(self)
        self.tex: OppTex = OppTex(self)
        self.attr: OppAttributes = OppAttributes(self._obj)

    @staticmethod
    def _validate(obj: pd.DataFrame):
        if not is_scave_df(obj):
            raise AttributeError(
                f"Not all columns found. expected: ['{' '.join(_scave_cols)}'] column. "
                f"got: [{' '.join(obj.columns)}] "
            )

    def module_summary(self):
        ret = self._obj[
            self._obj.type.isin(["scalar", "histogram", "vector"])
        ].module.unique()
        ret.sort()
        return ret

    def name_summary(self):
        ret = self._obj[
            self._obj.type.isin(["scalar", "histogram", "vector"])
        ].name.unique()
        ret.sort()
        return ret

    def info(self):
        runs = self._obj.loc[:, "run"].unique()
        unique_scalars = (
            self._obj.loc[self._obj["type"] == "scalar", ("module", "name")]
            .drop_duplicates()
            .shape[0]
        )
        all_scalars = self._obj.loc[
            self._obj["type"] == "scalar", ("module", "name")
        ].shape[0]
        unique_vectors = (
            self._obj.loc[self._obj["type"] == "vector", ("module", "name")]
            .drop_duplicates()
            .shape[0]
        )
        all_vectors = self._obj.loc[
            self._obj["type"] == "vector", ("module", "name")
        ].shape[0]
        print(f"shape: {self._obj.shape}")
        print(f"runs: {', '.join(list(runs))}")
        print(f"unique_scalars: {unique_scalars}")
        print(f"all_scalars: {all_scalars}")
        print(f"unique_vectors: {unique_vectors}")
        print(f"all_vectors: {all_vectors}")

    def filter(self, f: OppFilter = None, data_only=True):
        if f is not None:
            return f.apply(self._obj)
        else:
            return OppFilter(self._obj, data_only)


# https://school.programmers.co.kr/learn/courses/30/lessons/120913
'''
문자열 my_str과 n이 매개변수로 주어질 때, my_str을 길이 n씩 잘라서 저장한 배열을 return하도록 solution 함수를 완성해주세요.

1 ≤ my_str의 길이 ≤ 100
1 ≤ n ≤ my_str의 길이
my_str은 알파벳 소문자, 대문자, 숫자로 이루어져 있습니다.
'''
def solution(my_str, n):
    answer = []
    for i, e in enumerate(my_str):
        if i % n == 0:
            answer.append(e)
        else:
            answer[-1] += e
    return answer


"""
Guessing Game
Author: Tyler Johnson

Player needs to guess the # the computer is thinking
Computer needs to pick a number between range of 1 - 100
Needs to request the player to input a number
Computer needs to inform player wether the guess is too high or too low
Needs to keep track of how many guesses it has taken

"""
import random

number = random.randint(1, 100)
numberGuess = 0

print ("Let's play a game. I'm gonna come up with a random number between 1 and 100 and you guess!")
print()
guess = int(input("Okay, what is your guess? "))

while number != "guess":

    if guess > number:
        print()
        print (str(guess) + " Is too high!")
        guess = int(input("Try again! "))
        numberGuess += 1

    elif guess < number:
        print()
        print (str(guess) + " Is too low!")
        guess = int(input("Try again! "))
        numberGuess += 1

    else:
        numberGuess += 1
        print()
        print (str(guess) + " Was it! Look at you go! It took you " + str(numberGuess) + " tries!")
        break


class InfectionData(object):
    """
    Hold the data relevant to the infection of some person.
    We use it to track the infection source and the environment where each person got infected.
    """
    __slots__ = ("date", "environment", "transmitter", "infected")

    def __init__(self, infected, date, environment, transmitter):
        """
        Save the infection data
        :param infected: Person, the one that got infected
        :param date: datetime Date object that states the date of the infection
        :param environment: Environment where the person got infected
        :param transmitter: Person who infected
        """
        self.date = date
        self.environment = environment
        self.transmitter = transmitter
        self.infected = infected

    def __eq__(self, other):
        if other is None:
            return False
        return self.date == other.date and self.environment == other.environment and self.transmitter == other.transmitter and self.infected == other.infected

    def get_stats(self):
        """
        Get more detailed dict with data about the infection, like age and names.
        :return: dict
        """
        # env, transmitter age, transmitter disease state
        if self.transmitter is None:
            return {
                "infection_env_short": self.environment.name,
                "infection_env_long": self.environment._full_name,
                "infected_age": self.infected.get_state().age,
                "infector_age": None,
                "infector_disease_state": None
            }
        return {
            "infection_env_short": self.environment.name,
            "infection_env_long": self.environment._full_name,
            "infected_age": self.infected.get_state().age,
            "infector_age": self.transmitter.get_state().age,
            "infector_disease_state": self.transmitter.get_state().disease_state
        }

    @staticmethod
    def get_keys():
        """
        :return: get the keys of the detailed infection data dict
        """
        return ("infection_env_short", "infected_age", "infector_age", "infector_disease_state")


import sys

N, M = map(int, sys.stdin.readline().split())

graph = [[] for i in range(N)]

for i in range(M):
  a, b = map(int, sys.stdin.readline().rstrip().split())
  graph[a].append(b)
  graph[b].append(a)

def dfs(v, depth, visited):
    global N
    global ans
    visited[v] = True
    if depth >= 4:
      ans = True
    else:
      for nxt in graph[v]:
        if not visited[nxt]:
            dfs(nxt, depth + 1, visited)
            visited[nxt] = False

ans = False

result = 0
for i in range(N):
  visited = [False] * N
  dfs(i, 0, visited)
  if ans:
    result = 1
    break

print(result)


# coding: utf-8

import os.path as osp
import pandas as pd
import json
import requests
from ddf_utils.str import to_concept_id

UN_SDG_URL = 'https://unstats.un.org/SDGAPI/v1/sdg/GeoArea/Tree'

# Most SDG Regions are not official UN regions (M49) and should be divided into Subregions so we can read what countries belong to it.
# This subdivision is not given in the API/Data, so we manually do it here.
region_composition = {
    202: [],           # Sub-Saharan Africa
    747: [15, 145],    # Northern Africa and Western Asia. 15 northern africa, 145 western asia
    62:  [143, 34],    # Central and Southern Asia. 143 central asia, 34 southern asia
    753: [35, 30],     # Eastern and South-Eastern Asia. 35 south-eastern asia, 30 eastern asia
    543: [54, 57, 61], # Oceania excluding Australia and New Zealand. 54 Melanesia, 57 Micronesia, 61 Polynesia
                        # assumption: Christmas Island, Cocos Islands, Heard & McDonald Islands and Norfolk Islands are part of Australia & New Zealand
    419: [],           # Latin America and the Caribbean
    53:  [],           # Australia and New Zealand
    513: [150, 21]     # Europe and Northern America. 150 Europe, 21 Northern America
}

# Colors picked from https://unstats.un.org/sdgs/indicators/regional-groups/
region_color = {
    202: 'e11484', # Sub-Saharan Africa
    747: 'f99d26', # Northern Africa and Western Asia
    62:  'f36d25', # Central and Southern Asia
    753: '279b48', # Eastern and South-Eastern Asia
    543: '8f1838', # Oceania excluding Australia and New Zealand
    419: '00aed9', # Latin America and the Caribbean
    53:  'eb1c2d', # Australia and New Zealand
    513: '02558b'  # Europe and Northern America
}

def flatten(node):
    node_id = node['geoAreaCode']
    new_children = []
    flattened = {
        node_id: node
    }
    if node['children'] is not None:
        for childNode in node['children']:
            if childNode['type'] == 'Country':
                new_children.append(childNode)
            else:
                flatChild = flatten(childNode)
                flattened.update(flatChild)
                child_id = childNode['geoAreaCode']
                new_children += flatChild[child_id]['children']
    flattened[node_id]['children'] = new_children
    return flattened

def csv_to_dict(csv, keyCol, valCol):
    import csv

    data={}
    with open(csv) as fin:
        reader=csv.reader(fin, skipinitialspace=True, quotechar="'")
        for row in reader:
            data[row[0]]=row[1:]
    return data

def main():
    country_df = pd.read_csv('../../ddf--entities--geo--country.csv', dtype=str)
    synonyms_dict = pd.read_csv('../../ddf--synonyms--geo.csv', dtype=str).set_index('synonym').geo.to_dict()

    r = requests.get(UN_SDG_URL)
    regions_tree = r.json()
    regions_flat = flatten(regions_tree[0]) # 0 = world

    # Least Developed Countries
    ldc_entities = [ {
        'un_sdg_ldc': 'un_least_developed',
        'name': regions_tree[1]['geoAreaName'],
        'is--un_sdg_ldc': 'TRUE'
    },{
        'un_sdg_ldc': 'un_not_least_developed',
        'name': 'Other UN Countries',
        'is--un_sdg_ldc': 'TRUE'
    }]
    ldc_countries = []
    ldc_set = set()
    for country in regions_tree[1]['children']:
        code = str(country['geoAreaCode'])
        if code in synonyms_dict:
            ldc_countries.append({
                'country': synonyms_dict[code],
                'un_sdg_ldc': 'un_least_developed'
            })
            ldc_set.add(code)
        else:
            print('Could not find synonym for ', country)
    for country in regions_flat[1]['children']:
        code = str(country['geoAreaCode'])
        if code in synonyms_dict and code not in ldc_set:
            ldc_countries.append({
                'country': synonyms_dict[code],
                'un_sdg_ldc': 'un_not_least_developed'
            })

    # SDG Regions
    regions = []
    region_countries = []
    for region_id, subregions in region_composition.items():
        region_name = regions_flat[region_id]['geoAreaName']
        region_entity_id = 'un_' + to_concept_id(region_name)
        region = {
            'un_sdg_region': region_entity_id,
            'name': region_name,
            'color': '#' + region_color[region_id],
            'is--un_sdg_region': 'TRUE'
        }
        regions.append(region)

        subregions.append(region_id)
        for subregion in subregions:
            for country in regions_flat[subregion]['children']:
                code = str(country['geoAreaCode'])
                if code in synonyms_dict:
                    region_countries.append({
                        'country': synonyms_dict[code],
                        'un_sdg_region': region_entity_id
                    })
                else:
                    print('Could not find synonym for ', country)

    # un sdg region entity set
    regions_df = pd.DataFrame.from_records(regions)
    regions_df.to_csv('../../ddf--entities--geo--un_sdg_region.csv', index=False)

    # un sdg ldc entity set
    ldc_df = pd.DataFrame.from_records(ldc_entities)
    ldc_df.to_csv('../../ddf--entities--geo--un_sdg_ldc.csv', index=False)

    # update country properties
    country_df = country_df.set_index('country')
    region_countries = pd.DataFrame.from_records(region_countries).set_index('country')
    ldc_countries = pd.DataFrame.from_records(ldc_countries).set_index('country')

    country_df['un_sdg_region'] = region_countries.reindex(country_df.index)['un_sdg_region']
    country_df['un_sdg_ldc'] = ldc_countries.reindex(country_df.index)['un_sdg_ldc']
    country_df.to_csv('../../ddf--entities--geo--country.csv')

if __name__ == '__main__':
    main()
    print('Concept file was not manipulated. Please update concepts and their properties (e.g. colors) manually if needed.')
    print('Done.')


def myBigSum (n):
    num, nums = 0, []

    while num < n:
        nums.append(num)
        num += 1

    return nums

def myBigSumGenerator (n):
    num = 0

    while num < n:
        yield num
        num += 1

print (sum(myBigSum(10000000)))
print (sum(myBigSumGenerator(10000000)))


from pathlib import Path
from unittest.mock import patch

import pytest
from requests import Response

from pcapi.core.testing import override_settings

import tests
from tests.conftest import TestClient

pytestmark = pytest.mark.usefixtures("db_session")

class VerifyIdentityDocumentTest:
    IMAGES_DIR = Path(tests.__path__[0]) / "files"

    @override_settings(ID_CHECK_MIDDLEWARE_TOKEN="fake_token")
    @patch("pcapi.core.users.api.delete_object")
    @patch("pcapi.core.users.api._get_identity_document_informations")
    @patch("pcapi.connectors.beneficiaries.id_check_middleware.requests.post")
    def test_ask_for_document_verification(
        self,
        mocked_middleware_post,
        mocked_get_identity_document_informations,
        mocked_delete_object,
        app,
    ):
        identity_document = (self.IMAGES_DIR / "mouette_small.jpg").read_bytes()
        storage_path = "fake_storage_path.jpg"
        mocked_get_identity_document_informations.return_value = ("fake@email.com", identity_document)
        mocked_response = Response()
        mocked_response.status_code = 200
        mocked_response._content = b'{"code": "registration:completed"}'
        mocked_middleware_post.return_value = mocked_response
        json_data = {"image_storage_path": storage_path}
        test_client = TestClient(app.test_client())
        response = test_client.post(
            "/cloud-tasks/verify_identity_document",
            json=json_data,
            headers={"AUTHORIZATION": "Bearer cloud-task-bearer-token"},
        )

        assert response.status_code == 204
        mocked_get_identity_document_informations.assert_called_once_with(storage_path)
        mocked_middleware_post.assert_called_once_with(
            "https://id-check-middleware-dev.passculture.app/simple-registration-process",
            headers={
                "X-Authentication": "fake_token",
            },
            data={"email": "fake@email.com"},
            files=[("file", identity_document)],
        )
        mocked_delete_object.assert_called_once_with(storage_path)

    def test_bad_requests_parameters(self, app):
        test_client = TestClient(app.test_client())
        response = test_client.post("/cloud-tasks/verify_identity_document")

        assert response.status_code == 400


import pandas
import os

def extract_employee_sets(
    ad_employee_data,
    odoo_employee_list
):
    ad_email_addresses = list(ad_employee_data["E-mail Address"].unique())

    odoo_email_set = set(odoo_employee_list)
    ad_email_set = set(ad_email_addresses)
    odoo_only = odoo_email_set - ad_email_set
    ad_only = ad_email_set - odoo_email_set
    intersection = odoo_email_set.intersection(ad_email_set)

    return [
        list(odoo_only),
        list(intersection),
        list(ad_only)
    ]


from copy import deepcopy
from enum import Enum
from time import perf_counter_ns
from typing import List

# Ignore below

def format_ns(time: int) -> str:
    lengths = [1, 1000, 1000, 1000, 60, 60, 24]
    units = ["ns", "μs", "ms", "s", "minutes", "hours", "days"]
    idx = 0
    prev = 0
    while time > lengths[idx+1]:
        idx += 1
        time, prev = time//lengths[idx], time%lengths[idx]

    out = f"{time}{units[idx]}"
    if 0 < prev and time < 100:
        out += f" {prev}{units[idx-1]}"
    return out

def read_data(filename="input.txt"):
    with open(filename) as file:
        content = file.read().strip()

    return process_data(content)

# Ignore above

class Field(Enum):
    EMPTY = 0
    SOLID = 1
    SAND  = 2 # There is no real difference to SOLID
    SOURCE  = 3

    def __str__(self) -> str:
        if self == Field.EMPTY:
            return " "
        elif self == Field.SOLID:
            return "#"
        elif self == Field.SAND:
            return "o"
        elif self == Field.SOURCE:
            return "+"
        else:
            raise NotImplementedError("Unknown Type")

def process_data(content):
    data = [line.split("->") for line in content.split("\n")]
    # calculate min/max in each dimension, choose sand origin (500, 0)
    # as starting point
    xmin = 500
    xmax = 500
    ymin = 0
    ymax = 0
    for i in range(len(data)):
        for j in range(len(data[i])):
            a, b = data[i][j].split(",")
            a, b, = int(a), int(b)
            data[i][j] = (a, b)
            xmin = min(xmin, a)
            xmax = max(xmax, a)
            ymin = min(ymin, b)
            ymax = max(ymax, b)
    # spatial resolution is low -> can convert to dense matrix
    area = [[Field.EMPTY for _ in range(1+ymax-ymin)] for _ in range(1+xmax - xmin)]
    for line in data:
        for (x1, y1), (x2, y2) in zip(line[:-1], line[1:]):
            if x1 == x2:
                for t in range(min(y1, y2), max(y1, y2)+1):
                    area[x1-xmin][t-ymin] = Field.SOLID
            else:
                for t in range(min(x1, x2), max(x1, x2)+1):
                    area[t-xmin][y1-ymin] = Field.SOLID
    area[500 - xmin][0 - ymin] = Field.SOURCE
    return area, 500 - xmin, 0 - ymin

def check_data(data):
    pass

def out_of_bounds(x, y, n, m):
    return x < 0 or n <= x or y < 0 or m <= y

def simulate_and_place(area: List[List[Field]], x: int, y: int):
    n, m = len(area), len(area[0])
    while True:
        if out_of_bounds(x, y, n, m):
            # free-fall
            return False
        if out_of_bounds(x, y+1, n, m) or area[x][y+1] == Field.EMPTY:
            y = y+1
        elif out_of_bounds(x-1, y+1, n, m) or area[x-1][y+1] == Field.EMPTY:
            x, y = x-1, y+1
        elif out_of_bounds(x+1, y+1, n, m) or area[x+1][y+1] == Field.EMPTY:
            x, y = x+1, y+1
        else:
            area[x][y] = Field.SAND
            return True

def task1(data):
    area, source_x, source_y = data
    n = 0
    while simulate_and_place(area, source_x, source_y):
        n += 1
    return n

def task2(data):
    area, source_x, source_y = data
    for line in area:
        line.append(Field.EMPTY)
        line.append(Field.SOLID)
    # extend lines at the left and right
    area.append([Field.EMPTY for _ in range(len(area[0])-1)] + [Field.SOLID])
    area.append([Field.EMPTY for _ in range(len(area[0])-1)] + [Field.SOLID])
    new_area = [[Field.EMPTY for _ in range(len(area[0])-1)] + [Field.SOLID]
                for _ in range(2)]
    new_area.extend(area)
    area = new_area
    source_x += 2

    n = 0
    while area[source_x][source_y] == Field.SOURCE:
        if not simulate_and_place(area, source_x, source_y):
            for j in range(len(area[0])):
                print("".join(str(area[i][j]) for i in range(len(area))))
            assert False
        n += 1
        if area[1][-2] != Field.EMPTY:
            new_area = [[Field.EMPTY for _ in range(len(area[0])-1)] + [Field.SOLID]]
            new_area.extend(area)
            area = new_area
            source_x += 1
        if area[-2][-2] != Field.EMPTY:
            area.append([Field.EMPTY for _ in range(len(area[0])-1)] + [Field.SOLID])
    return n

def main():
    # fn = "input_bsp.txt"
    fn = "input.txt"
    t0 = perf_counter_ns()
    data = read_data(fn)
    check_data(data)
    t1 = perf_counter_ns()
    result1 = task1(deepcopy(data))
    t2 = perf_counter_ns()
    result2 = task2(data)
    t3 = perf_counter_ns()

    print(f"Data preprocessing in {format_ns(t1 - t0)}")
    print(f"Task 1: {result1} in {format_ns(t2 - t1)}")
    print(f"Task 2: {result2} in {format_ns(t3 - t2)}")

if __name__ == "__main__":
    main()


import sys
import os
import math
from statistics import mode
KVALUE = 3
headers = []
trainingWineList = []
testWineList = []
distanceList = []
rangeList = []
accuracy = []

def findRange():
    for i in range (len(headers)-1):
        currList = []
        for wine in trainingWineList:
            currList.append(wine[i])
        rangeList.append(max(currList)-min(currList))

def findClosestK(testAnswer):
    newList = sorted(distanceList)
    kList = []
    for wine in newList[0:KVALUE]:
        kList.append(wine[1])
    print("Guess:",int(mode(kList)),"Answer:",int(testAnswer))
    if mode(kList)==testAnswer:
        accuracy.append(0)
    else:
        accuracy.append(1)

def findDistance(testList, trainingList):
    distance=0
    for i in range (len(headers)-1):
        distance += pow(testList[i] - trainingList[i], 2)/pow(rangeList[i], 2)
    return math.sqrt(distance)

def loadSets(loadFile, selectedList):
    os.chdir("../../ass1_data/part1")
    with open(loadFile) as file:
        line = file.readline()
        if not len(headers):
            headers.extend(line.split(" "))
        while line:
            line = file.readline().replace("\n", "")
            if line=='':
                continue
            selectedList.append(list(map(float, line.split(" "))))

def search():
    findRange()
    for testWine in testWineList:
        distanceList.clear()
        for trainWine in trainingWineList:
            distanceList.append([findDistance(testWine, trainWine), trainWine[-1]])
        findClosestK(testWine[-1])
    print('Where k=',KVALUE)
    print('Accuracy: ',accuracy.count(0)/len(accuracy)*100,' == ',accuracy.count(0),'/',len(accuracy))

def main():
    loadSets(sys.argv[1], trainingWineList)
    loadSets(sys.argv[2], testWineList)
    search()
    print(rangeList)

if __name__ == "__main__":
    main()