#This is the Algorithm 2 in the thesis

import numpy as np
import tensorflow as tf
from tensorflow.keras.layers import Input, Dense, Reshape, Softmax
from tensorflow.keras.optimizers import Adam
from collections import deque
import random
import scipy.stats

tf.keras.backend.set_floatx('float64')

# Envrionment
class Env:
    def __init__(self,MAX_t,MAX_S,MAX_H,MAX_v,Strick_price,start_state,SLowerBd,vLowerBd):
        self.MAX_t,self.MAX_S,self.MAX_H,self.MAX_v = MAX_t,MAX_S,MAX_H,MAX_v
        self.start_state = start_state
        self.Strick_price = Strick_price
        self.state = self.start_state
        self.SLowerBd = SLowerBd
        self.vLowerBd = vLowerBd #0.01
        self.c = 0.01

    def step(self,action,r,sigma,rho,kappa,theta,delta_t):
        t,S,H,v = self.state
        t += 1
        if t == 1:
            reward = -(self.SLowerBd+S)*action-self.c*abs((self.SLowerBd+S)*action)
            S,v = self.next_Sv(S,v,r,sigma,rho,kappa,theta,delta_t)
            H = action
            new_state = (t,S,H,v)
        elif ((t>1) and (t<self.MAX_t)):
            reward = (self.SLowerBd+S)*(H-action)-self.c*abs((self.SLowerBd+S)*(H-action))
            S,v = self.next_Sv(S,v,r,sigma,rho,kappa,theta,delta_t)
            H = action
            new_state = (t,S,H,v)
        else:
            call_payoff = (self.SLowerBd+S-self.Strick_price) if (self.SLowerBd+S-self.Strick_price > 0) else 0
            reward = (self.SLowerBd+S)*H-self.c*abs((self.SLowerBd+S)*H)-call_payoff*100 # *100 because we have 100 call options
            new_state = self.start_state

        self.state = new_state
        return reward,new_state

    def next_Sv(self,S0,v0,r,sigma,rho,kappa,theta,delta_t):
        v0 = v0/100 + self.vLowerBd
        randS = np.random.normal(0,1,1)
        randv = rho*randS+np.sqrt(1-rho*rho)*np.random.normal(0,1,1)
        S = (S0+self.SLowerBd)*np.exp((r-0.5*v0)*delta_t+np.sqrt(v0)*np.sqrt(delta_t)*randS)
        v = v0*np.exp((1/v0)*(kappa*(theta-v0)-0.5*sigma*sigma)*delta_t+sigma/np.sqrt(v0)*np.sqrt(delta_t)*randv)
        S = round(S[0])# S is a np.array
        # aussme S is bdd, say 40~60
        S = S if (S<=self.SLowerBd+self.MAX_S-1) else self.SLowerBd+self.MAX_S-1
        S = S if (S>=self.SLowerBd) else self.SLowerBd
        v = round(v[0]*100)
        v = v if (v<=self.vLowerBd*100+self.MAX_v-1) else self.vLowerBd*100+self.MAX_v-1
        v = v if (v>=self.vLowerBd*100) else self.vLowerBd*100
        return int(S-self.SLowerBd), int(v-self.vLowerBd)

class AgentQRDQN:
    def __init__(self,env):
        self.action_number = env.MAX_H
        self.quantile_number = 5
        self.MAX_t = env.MAX_t
        self.MAX_S = env.MAX_S
        self.MAX_H = env.MAX_H
        self.MAX_v = env.MAX_v
        self.state_dim = self.MAX_t+self.MAX_S+self.MAX_H+self.MAX_v
        self.batch_size = 10
        self.learning_rate = 0.0001
        self.memory_size = 1000
        self.memory_counter = 0
        self.MEMORY_POOL = [[(0,0,0,0),0,0,(0,0,0,0)] for j in range(self.memory_size)]
        self.epsilon = 0.1
        self.gamma = 1
        self.tau = np.array([(2*(i-1)+1)/(2*self.quantile_number) for i in range(1, self.quantile_number+1)])
        self.opt = tf.keras.optimizers.Adam(self.learning_rate)
        self.huber_loss = tf.keras.losses.Huber(reduction=tf.keras.losses.Reduction.NONE)
        self.qtarget_update_preiod = 5 # every what number of steps then update q_target network once
        self.q = self.create_MLP() # network used to be trained
        self.q_target = self.create_MLP() # networks to do Q(s,a) approximation

    def create_MLP(self):
        return tf.keras.Sequential([
            Input([self.state_dim, ]),
            Dense(128, activation='relu'),
            Dense(64, activation='relu'),
            Dense(self.action_number * self.quantile_number, activation='linear'),
            Reshape([self.action_number, self.quantile_number])
        ])

    def train_MLP(self,sample):
        state = np.array([data[0] for data in sample])
        action = np.array([data[1] for data in sample])
        reward = np.array([data[2] for data in sample])
        next_state = np.array([data[3] for data in sample])
        state_boolean = np.zeros((len(state),self.MAX_t+self.MAX_S+self.MAX_H+self.MAX_v))
        next_state_boolean = np.zeros((len(next_state),self.MAX_t+self.MAX_S+self.MAX_H+self.MAX_v))
        for i in range(len(state)):
            state_boolean[i][state[i][0]] = 1
            state_boolean[i][state[i][1]+self.MAX_t] = 1
            state_boolean[i][state[i][2]+self.MAX_t+self.MAX_S] = 1
            state_boolean[i][state[i][3]+self.MAX_t+self.MAX_S+self.MAX_H] = 1
        for i in range(len(next_state)):
            next_state_boolean[i][next_state[i][0]] = 1
            next_state_boolean[i][next_state[i][1]+self.MAX_t] = 1
            next_state_boolean[i][next_state[i][2]+self.MAX_t+self.MAX_S] = 1
            next_state_boolean[i][next_state[i][3]+self.MAX_t+self.MAX_S+self.MAX_H] = 1
        # calculate bellman target
        target_theta = self.q_target.predict(next_state_boolean) # this theta is used to calculate bellman target, shpae is batchSize*actionNumber*quantileNumber
        next_action = np.argmax(np.mean(target_theta,axis=2),axis=1) # the action leads to max "mean of quantiles"
        bellman_target = []
        for i in range(self.batch_size):
            if state[i][0] == self.MAX_t-1: # if this is the last step in one trajectory
                bellman_target.append(np.ones(self.quantile_number)*reward[i])
            else:
                bellman_target.append(reward[i]+self.gamma*target_theta[i][next_action[i]])
        bellman_target = tf.constant(bellman_target)

        #calculate the theta to be updated
        with tf.GradientTape() as tape:
            theta_tobeupdated = self.q(state_boolean) # this is a tf, not np.array
            # loss is to measure gaps between bellman_target and theta_tobeupdated
            loss = self.huber_lossfunction(bellman_target,theta_tobeupdated,action)
        gradients = tape.gradient(loss,self.q.trainable_variables)
        self.opt.apply_gradients(zip(gradients, self.q.trainable_variables))
        return loss.numpy()

    def huber_lossfunction(self,target,tf_approx,action):
        action = action.astype("int")
        actionVec = np.zeros((len(action),self.action_number)) # [1,0,0...] represents action"0"; [0,1,0..] represents action"1"...
        for i in range(len(action)):
            actionVec[i][action[i]]=1
        actionVec = actionVec.astype("float64")
        actionTf = tf.expand_dims(actionVec, -1)
        theta_tobeupdated = tf.reduce_sum(actionTf*tf_approx,axis=1) # theta i (x,a)
        theta_tobeupdated_tile = tf.tile(tf.expand_dims(theta_tobeupdated,-1),[1,1,self.quantile_number])
        target_tile = tf.tile(tf.expand_dims(target,1),[1,self.quantile_number,1])
        huber_loss = self.huber_loss(tf.expand_dims(target_tile, -1), tf.expand_dims(theta_tobeupdated_tile, -1))
        error = tf.math.subtract(target_tile, theta_tobeupdated_tile)
        self.tau = self.tau.astype("float64")
        tau = tf.tile(tf.expand_dims(self.tau, 0), [self.batch_size,1])
        tau_tile = tf.tile(tf.expand_dims(tau,-1),[1,1,self.quantile_number])
        inv_tau = tf.tile(1.0-tf.expand_dims(self.tau, 0), [self.batch_size,1])
        inv_tau_tile = tf.tile(tf.expand_dims(inv_tau,-1),[1,1,self.quantile_number])
        loss= tf.where(tf.less(error, 0.0),inv_tau_tile*huber_loss,tau_tile*huber_loss)
        return tf.reduce_mean(tf.reduce_sum(tf.reduce_mean(loss,axis=2),axis=1))

    def update_q_traget(self):
        weights = self.q.get_weights()
        self.q_target.set_weights(weights)

    def update_MEMORY_POOL(self,state,action,reward,next_state):
        if self.memory_counter % self.qtarget_update_preiod == 0:
            self.update_q_traget()

        if self.memory_counter > self.batch_size:
            sample = random.sample(self.MEMORY_POOL,self.batch_size)
            loss = self.train_MLP(sample)
            if self.memory_counter % 100 == 0:
                print(loss)

        memory_index = self.memory_counter % self.memory_size
        self.MEMORY_POOL[memory_index] = [state,action,reward,next_state]
        self.memory_counter += 1

    # the eponsion can be changed
    # argmax the mean of reward
    def make_action(self,state): # the eponsion can be changed
        t,S,H,v = state
        if t == self.MAX_t-1:
            return 0
        else:
            if np.random.rand() < self.epsilon:
                return np.random.randint(0, self.action_number)
            else:
                state_boolean = np.zeros((1,self.MAX_t+self.MAX_S+self.MAX_H+self.MAX_v))
                state_boolean[0][state[0]] = 1
                state_boolean[0][state[1]+self.MAX_t] = 1
                state_boolean[0][state[2]+self.MAX_t+self.MAX_S] = 1
                state_boolean[0][state[3]+self.MAX_t+self.MAX_S+self.MAX_H] = 1
                quantile = self.q.predict([state_boolean])[0]
                return np.argmax(np.mean(quantile,axis=1))

    def DeltaHedging_action(self,state,K,r,delta_t): # the eponsion can be changed
        t,S,H,v = state
        sigma = np.sqrt(v/100)
        if t == self.MAX_t-1:
            action = 0  # in the last step, clean the portfolio
        else:
            time_remain = delta_t*(self.MAX_t-t-1)
            dPlus = (np.log((S+self.SLowerBd)/K)+(r+sigma*sigma/2)*time_remain) / (sigma*time_remain**(1/2))
            Delta = scipy.stats.norm(0,1).cdf(dPlus)
            action = int(round(Delta*100))
        return action

def run_RL(env,agent,number_of_steps,r,sigma,rho,kappa,theta,delta_t,start_state):
    state = env.start_state
    for i in range(number_of_steps):
        action = agent.make_action(state)
        reward,new_state = env.step(action,r,sigma,rho,kappa,theta,delta_t)
        agent.update_MEMORY_POOL(state,action,reward,new_state)
        state = new_state
    return agent.q

def test_env(env,number_of_steps,r,sigma,rho,kappa,theta,delta_t):
    for i in range(number_of_steps):
        action = 0
        reward,new_state = env.step(action,r,sigma,rho,kappa,theta,delta_t)
        print(new_state)

#main
strick_price = 50
MAX_t,MAX_S,MAX_H,MAX_v = 10,21,101,50
number_of_steps = 10**5
SLowerBd,vLowerBd = 40,0.01
K,r,sigma,delta_t = 50,0,0.9,3/252
rho,kappa,theta = -0.7,5,0.2

start_state_action = (0,10,0,9,0)
start_state = start_state_action[:-1]
start_state_boolean = np.zeros((1,MAX_t+MAX_S+MAX_H+MAX_v))
start_state_boolean[0][start_state[0]] = 1
start_state_boolean[0][start_state[1]+MAX_t] = 1
start_state_boolean[0][start_state[2]+MAX_t+MAX_S] = 1
start_state_boolean[0][start_state[3]+MAX_t+MAX_S+MAX_H] = 1

envGBM = Env(MAX_t,MAX_S,MAX_H,MAX_v,strick_price,start_state,SLowerBd,vLowerBd)
#test_env(envGBM,number_of_steps,r,sigma,rho,kappa,theta,delta_t)
QRDQN = AgentQRDQN(envGBM)
trained_model = run_RL(envGBM,QRDQN,number_of_steps,r,sigma,rho,kappa,theta,delta_t,start_state)
quantile = trained_model.predict([start_state_boolean])


'''determines what award a triathlon participant should receive
based on time taken to complete
'''

#set const for qualifying time in minutes
QUAL_TIME = 100

#get times for each event and sum

swimming = float(input("Please input your time in the swimming event in minutes\n"))
cycling = float(input("Please input your time in the cycling event in minutes\n"))
running = float(input("Please input your time in the running event in minutes\n"))

total_time = swimming + cycling + running
print(f"Your total time for the triathlon was {total_time}")

#determine if award achieved
if total_time <= QUAL_TIME:
    print("Congratulations! You have been awarded the Provincial Colours")

elif total_time < (QUAL_TIME + 5):
    print("Congratulations! You have been awarded the Provincial Half Colours")

elif total_time < (QUAL_TIME + 10):
    print("Congratulations! You have been awarded the Provincial Scroll")

else:
    print("You did not achieve an award this time")


from .IFPRI_Reader_base import IFPRIReader
import nltk
import pandas as pd

class IFPRI_ExcelReader_TypeA(IFPRIReader):
    def __init__(self, excel_file, batch_size=32):
        super().__init__(batch_size=batch_size)
        self.ignor_type = ['note', 'begin group', 'start', 'calculate', 'end group', 'end']
        self.selecte_type = ['select_one', 'select_multiple']
        self.readQuestions(excel_file)

    def readQuestions(self, excel_file):
        survy_pd_frame = pd.read_excel(excel_file, sheet_name='survey', header=0)
        choice_pd_frame = pd.read_excel(excel_file, sheet_name='choices', header=0, index_col=0)
        column_list = list(survy_pd_frame.columns)
        print(column_list)
        print(list(survy_pd_frame['type'].unique()))

        begin_read = False
        for eachrow in survy_pd_frame.iterrows():
            row_type = eachrow[1]['type']
            if row_type == 'begin group':
                begin_read = True
            elif row_type == 'end group':
                begin_read = False
            else:
                if begin_read:
                    if row_type not in self.ignor_type:
                        question = str(eachrow[1]['label::English (en)']).strip()
                        if not pd.isna(question):
                            row_type_tok = row_type.split()
                            question_tok = nltk.word_tokenize(question.lower())
                            list_choices = []
                            if row_type_tok[0] in self.selecte_type:
                                choice_type = row_type_tok[1]
                                list_choices = list(choice_pd_frame.loc[choice_type]['name'])
                                list_choices = [str(each_choice).lower() for each_choice in list_choices]

                            self.all_questions_list.append([question_tok, list_choices, None])


import numpy as np
import random
import matplotlib.pyplot as plt

P = np.array([[0, 1, 0, 0], [.25, 0, .5, .25], [0, .5, 0, .5], [0, 0, 0, 1]])

def main():
    dist = []
    for i in range(0, 500):
        dist.append(sample())
    plt.hist(dist)
    plt.show()

def sample(n=1000):
    trials = 0
    Sn = 0
    while trials < n:
        Sn += simulate()
        trials += 1
    return Sn/n

def step(i , P ):
    next_states = np.where(P[i,:] > 0)[0]
    state_dist = P[i,:][next_states]
    cumul = np.cumsum(state_dist)
    rand = random.uniform(0,1)
    for i in range(0,len(next_states)):
        if rand <= cumul[i]:
            return next_states[i]

def simulate():
    count = 0
    state = 0
    while state != 3:
        newState = step(state, P)
        count += 1
        state = newState
    return count

main()


#!/usr/bin/python3
# @Time    : 2022-08-10
# @Author  : Kevin Kong (kfx2007@163.com)

from odoo.addons.base.models.ir_ui_view import (
transfer_field_to_modifiers, transfer_node_to_modifiers, transfer_modifiers_to_node,
)

def setup_modifiers(node, field=None, context=None, in_tree_view=False):
    modifiers = {}
    if field is not None:
        transfer_field_to_modifiers(field, modifiers)
    transfer_node_to_modifiers(
        node, modifiers, context=context)
    transfer_modifiers_to_node(modifiers, node)


def solution(total_sp, skills):
    skillset = {}
    # skillset: id => [preskills]
    skillpointset = {}
    # skillpointset: id => required skillpoints
    for s in skills:
        # s: [skill, preskill]
        if s[0] in skillset:
            skillset[s[0]].append(s[1])
        else:
            skillset[s[0]] = [s[1]]

    answer = []
    skillMultiplierSum = 0
    for n in range(1, len(skills)+2):
        sm = getSkillMultiplier(n, skillset, skillpointset)
        skillMultiplierSum += sm
        answer.append(sm)
    return [x * int(total_sp / skillMultiplierSum) for x in answer]

def getSkillMultiplier(n, skillset, skillpointset):
    if n in skillpointset:
        return skillpointset[n]
    else:
        if n not in skillset:
            skillpointset[n] = 1
            return 1
        else:
            spSum = 0
            for preskill in skillset[n]:
                spSum += getSkillMultiplier(preskill, skillset, skillpointset)
            skillpointset[n] = spSum
            return spSum


class Solution:
    def sortSentence(self, s:str)->str:
        answer = ['','','','','','','','','','']
        for each in s.split(' '):
            answer[int(each[-1])] = each[:-1]
        return ' '.join(answer).strip()

if __name__ == "__main__":
    s = Solution()
    print(s.sortSentence("is2 sentence4 This1 a3")) # This is a sentence
    print(s.sortSentence("Myself2 Me1 I4 and3")) # Me Myself and I
    print(s.sortSentence("QcGZ4 TFJStgu3 HvsRImLBfHd8 PaGqsPNo9 mZwxlrYzanuVOUZoyNjt1 fzhdtYIen6 mV7 LKuaOtefsixxo5 pwdEK2")) # mZwxlrYzanuVOUZoyNjt pwdEK TFJStgu QcGZ LKuaOtefsixxo fzhdtYIen mV HvsRImLBfHd PaGqsPNo


from math import cos
import numpy as np
import matplotlib.pyplot as plt
import math
import sympy as sy
import pandas as pd

class NewtonRapson:
    def __init__(self, funcion):
        self.funcion = funcion
        self.xplt = None
        self.yplt = None
        self.xi = None

    def calculate(self):

        #f = sy.Pow(x, 3) - 6*(sy.Pow(x, 2)) + 11*x - 6.1
        #f = sy.log(x) - sy.cos(x) #función
        #x = sy.symbols('x')
        ldict = {}
        sToCode  = "x = sy.symbols('x')\nf = myExp "
        sToCode = sToCode.replace("myExp", self.funcion)
        exec(sToCode, globals(), ldict)
        f = ldict['f']

        self.xi = 1
        itr = 6 # numero de iteraciones a realizar

        #xplt = np.linspace(-10, 10, 200)  #para funciones normales
        self.xplt = np.linspace(0.00001, 100, 2000) #para funciones con los logs
        self.yplt = np.array([], float)

        dx = sy.diff(f)
        dx = dx.doit()
        v = [f"f(x) = {f}", f"f'(x) = {dx}", f"Xi = {self.xi}"]

        f = str(f)
        dx = str(dx)
        f = f.replace("exp", "math.exp")
        f = f.replace("cos", "math.cos")
        f = f.replace("sin", "math.sin")
        f = f.replace("log", "math.log")

        dx = dx.replace("exp", "math.exp")
        dx = dx.replace("cos", "math.cos")
        dx = dx.replace("sin", "math.sin")
        dx = dx.replace("log", "math.log")

        strCode = """fun = lambda x : myExp"""
        strCode = strCode.replace("myExp", f)
        exec(strCode, globals(), ldict)
        fun = ldict['fun']

        strCode = """fun_der = lambda x : myExp"""
        strCode = strCode.replace("myExp", dx)
        exec(strCode, globals(), ldict)
        fun_der = ldict['fun_der']

        filas = []
        columnas = ['', '']
        xxx = []

        for xp in range(itr):
            self.xi = self.xi - (fun(self.xi) / fun_der(self.xi))
            filas.append(f"X({xp + 1})")
            xxx.append([" ->", self.xi])

        for xp in self.xplt:
            res = fun(xp)
            self.yplt = np.append(self.yplt , res)

        resultadosFinales = pd.DataFrame(xxx, filas, columnas)

        return v, resultadosFinales, f"Raíz -> {self.xi:.5f}"

    def graf(self):
        plt.plot(self.xplt, self.yplt, 'b-')
        plt.plot(self.xi, 0, 'ro')
        plt.xlabel('X')
        plt.ylabel('Y')
        winTitle = plt.gcf()
        winTitle.canvas.set_window_title("Newton - Raphson")
        plt.grid()
        gridSize = [-(10), (10), -(10), (10)] #Limite de ejes
        plt.axis(gridSize)
        plt.show()
'''
#f = sy.log(x) - sy.cos(x) #función
myFunc = NewtonRapson("sy.log(x) - sy.cos(x)")
print(myFunc.calculate())
myFunc.graf()
#myFunc.calculate( "sy.Pow(x, 3) - 6*(sy.Pow(x, 2)) + 11*x - 6.1 ")
'''


import torch
import timm
import argparse
from torch import nn
from torch.nn import functional as F
from torch.utils.data import DataLoader
from torchvision import transforms, models
import pytorch_lightning as pl
from dataset import EmotionDataset
from utils import accuracy

class EmotionModel(pl.LightningModule):
	def __init__(self, num_classes=10, finetune=False, lr=1e-3, wd=0., label_smoothing=0.):
		super().__init__()
		# model = models.resnet18(weights=models.ResNet18_Weights)
		model = timm.create_model('efficientnet_b0', pretrained=True, num_classes=10)

		self.lr = lr
		self.wd = wd
		model.fc = nn.Linear(512, 10)
		self.model = model
		self.loss_func = nn.CrossEntropyLoss(label_smoothing=label_smoothing)

	def forward(self, x):
		out = self.model(x)
		return out

	def configure_optimizers(self):
		optimizer = torch.optim.Adam(self.parameters(), lr=self.lr, weight_decay=self.wd)
		#sched = torch.optim.lr_scheduler.StepLR(optimizer, 10, gamma=0.95)
		#opt_dict = {"optimizer": optimizer, "lr_scheduler": sched}
		return optimizer
	def training_step(self, train_batch, batch_idx):
		x, y = train_batch
		out = self.model(x)
		loss = self.loss_func(out, y)
		self.log('train_loss', loss)
		return loss

	def validation_step(self, val_batch, batch_idx):
		x, y = val_batch
		out = self.model(x)
		loss = self.loss_func(out, y)
		acc = accuracy(out, y)
		self.log('val_loss', loss)
		self.log('val_acc', acc)

def main():
	# args
	parser = argparse.ArgumentParser()
	parser.add_argument(
		"--root_dir",
		type = str,
		help = "Base folder containing the training, validation and testing folder.",
	)

	parser.add_argument(
		"--lr",
		default=1e-3,
		type=float,
		help = "learning rate for model training",
	)

	parser.add_argument(
		"--epochs",
		default=10,
		type=int,
		help = "number of epochs for which the training will be done",
	)

	parser.add_argument(
		"--wd",
		default=0.,
		type=float,
		help = "weight decay",
	)

	parser.add_argument(
		"--label_smoothing",
		default=0.,
		type=float,
		help = "label smoothing",
	)

	args = parser.parse_args()

	# transforms
	mean = [0.485, 0.456, 0.406]
	std = [0.229, 0.224, 0.225]

	val_transform = transforms.Compose([
		transforms.ToTensor(),
		transforms.Normalize(mean, std)
	])

	train_transform = transforms.Compose([
		transforms.ToTensor(),
		transforms.RandomHorizontalFlip(),
		transforms.Resize(size=(96, 96)),
		transforms.RandomResizedCrop(48, scale=(0.75, 1.)),
		transforms.Normalize(mean, std)
	])

	# data
	train_ds = EmotionDataset(
		root=args.root_dir,
		split='train',
		transform=train_transform
	)

	val_ds = EmotionDataset(
		root=args.root_dir,
		split='valid',
		transform=val_transform
	)

	# dataloader
	train_loader = DataLoader(train_ds, shuffle=True, batch_size=64)
	val_loader = DataLoader(val_ds, batch_size=64)

	# model
	model = EmotionModel(finetune=args.finetune, lr=args.lr)
	# model.load_from_checkpoint("/content/Emotion-Recognition/lightning_logs/version_2/checkpoints/epoch=19-step=4460.ckpt")
	# training
	trainer = pl.Trainer(accelerator='gpu', devices=1, max_epochs=args.epochs, limit_train_batches=0.5)
	trainer.fit(model, train_loader, val_loader)

if __name__ == "__main__":
	main()


exam_hour = int(input())
exam_min = int(input())
arrival_hour = int(input())
arrival_min = int(input())

late = 'Late'
on_time = 'On time'
early = 'Early'
result = None

exam_time = (exam_hour * 60) + exam_min
arrival_time = (arrival_hour * 60) + arrival_min

total_min = arrival_time - exam_time
stud_arrival = late

if total_min < -30:
    stud_arrival = early
elif total_min <= 0:
    stud_arrival = on_time

if total_min != 0:
    hour_diff = abs(total_min) // 60
    min_diff = abs(total_min) % 60

    if hour_diff > 0:
        result = f'{hour_diff}:{min_diff:02} hours'
    else:
        result = f'{min_diff} minutes'

    if total_min < 0:
        result = result + ' before the start'
    else:
        result = result + ' after the start'
print(stud_arrival)
if result != None:
    print(result)
else:
    pass


#!/usr/bin/python3
# -*- coding: utf-8; tab-width: 4; indent-tabs-mode: t -*-

import os
import json
import strict_hdds
from fm_util import FmUtil
from fm_util import ParallelRunSequencialPrint
from fm_param import FmConst
from client_build_server import BuildServerSelector
from helper_bbki import BbkiWrapper
from helper_bbki import BootDirWriter
from helper_pkg_warehouse import PkgWarehouse
from helper_pkg_warehouse import CloudOverlayDb
from helper_dyncfg import DynCfgModifier

class FmSysUpdater:

    def __init__(self, param):
        self.param = param
        self.infoPrinter = self.param.infoPrinter

        self.opSync = os.path.join(FmConst.libexecDir, "op-sync.py")
        self.opFetch = os.path.join(FmConst.libexecDir, "op-fetch.py")
        self.opInstallKernel = os.path.join(FmConst.libexecDir, "op-install-kernel.py")
        self.opEmergeWorld = os.path.join(FmConst.libexecDir, "op-emerge-world.py")
        self.opEmerge9999 = os.path.join(FmConst.libexecDir, "op-emerge-9999.py")

    def update(self, bSync, bFetchAndBuild):
        if self.param.runMode in ["normal", "setup"]:
            layout = strict_hdds.get_storage_layout()
        else:
            layout = None
        bbkiObj = BbkiWrapper(layout)
        pkgwh = PkgWarehouse()
        overlayDb = CloudOverlayDb()

        # set system to unstable status
        if self.param.runMode in ["normal", "setup"]:
            if bbkiObj.isStable():
                with BootDirWriter(layout):
                    bbkiObj.setStable(False)

        # modify dynamic config
        self.infoPrinter.printInfo(">> Preparing...")
        if True:
            dcm = DynCfgModifier()
            dcm.updateMirrors()
            dcm.updateDownloadCommand()
            dcm.updateParallelism(self.param.machineInfoGetter.hwInfo())
            dcm.updateCcache()
        print("")

        # get build server
        if BuildServerSelector.hasBuildServerCfgFile():
            self.infoPrinter.printInfo(">> Selecting build server...")
            buildServer = BuildServerSelector.selectBuildServer()
            print("")
        else:
            buildServer = None

        # sync up and start working
        if buildServer is not None:
            self.infoPrinter.printInfo(">> Synchronizing up...")
            buildServer.syncUp()
            buildServer.startWorking()
            print("")

        # do sync
        if bSync:
            # sync bbki repositories
            with ParallelRunSequencialPrint() as prspObj:
                if buildServer is not None:
                    startCoro = buildServer.asyncStartSshExec
                    waitCoro = buildServer.asyncWaitSshExec
                else:
                    startCoro = FmUtil.asyncStartCmdExec
                    waitCoro = FmUtil.asyncWaitCmdExec
                for repo in bbkiObj.repositories:
                    prspObj.add_task(
                        startCoro, [self.opSync, self.param.runMode, "sync-bbki-repo", repo.name],
                        waitCoro,
                        pre_func=lambda x=repo.name: self.infoPrinter.printInfo(">> Synchronizing BBKI repository \"%s\"..." % (x)),
                        post_func=lambda: print(""),
                    )
            # FIXME: there should be no sync down after realtime network filesystem support is done
            if buildServer is not None:
                buildServer.syncDownDirectory(FmConst.portageDataDir)

            # sync repository directories
            for repoName in pkgwh.repoman.getRepositoryList():
                repoDir = pkgwh.repoman.getRepoDir(repoName)
                self.infoPrinter.printInfo(">> Synchronizing repository \"%s\"..." % (repoName))
                self._execAndSyncDownQuietly(buildServer, self.opSync, self.param.runMode, "sync-repo", repoName, directory=repoDir)
                print("")

            # update cloud overlay db
            self.infoPrinter.printInfo(">> Synchronizing cloud overlay database...")
            overlayDb.update()
            print("")

            # sync overlay directories
            with ParallelRunSequencialPrint() as prspObj:
                if buildServer is not None:
                    startCoro = buildServer.asyncStartSshExec
                    waitCoro = buildServer.asyncWaitSshExec
                else:
                    startCoro = FmUtil.asyncStartCmdExec
                    waitCoro = FmUtil.asyncWaitCmdExec
                for repo in pkgwh.layman.getOverlayList():
                    if pkgwh.layman.getOverlayType(repo) == "static":
                        continue
                    prspObj.add_task(
                        startCoro, [self.opSync, self.param.runMode, "sync-overlay", repo],
                        waitCoro,
                        pre_func=lambda x=repo: self.infoPrinter.printInfo(">> Synchronizing overlay \"%s\"..." % (x)),
                        post_func=lambda: print(""),
                    )
            # FIXME: there should be no sync down after realtime network filesystem support is done
            if buildServer is not None:
                buildServer.syncDownDirectory(FmConst.portageDataDir)

            # add pre-enabled overlays
            for repo, ourl in pkgwh.getPreEnableOverlays().items():
                if not pkgwh.layman.isOverlayExist(repo):
                    self.infoPrinter.printInfo(">> Installing overlay \"%s\"..." % repo)
                    vcsType = "git"
                    if overlayDb.hasOverlay(repo):
                        vcsType, ourl = overlayDb.getOverlayVcsTypeAndUrl(repo)
                    if ourl is None:
                        raise Exception("no URL for overlay %s" % repo)
                    if buildServer is None:
                        FmUtil.cmdExec(self.opSync, self.param.runMode, "add-trusted-overlay", repo, vcsType, ourl)
                    else:
                        buildServer.sshExec(self.opSync, "add-trusted-overlay", repo, vcsType, ourl)
                        buildServer.syncDownWildcardList([
                            os.path.join(pkgwh.layman.getOverlayFilesDir(repo), "***"),
                            pkgwh.layman.getOverlayDir(repo),
                            pkgwh.layman.getOverlayCfgReposFile(repo),
                        ], quiet=True)
                    print("")

            # add pre-enabled overlays by pre-enabled package
            for repo, data in pkgwh.getPreEnablePackages().items():
                ourl = data[0]
                if not pkgwh.layman.isOverlayExist(repo):
                    self.infoPrinter.printInfo(">> Installing overlay \"%s\"..." % repo)
                    vcsType = "git"
                    if overlayDb.hasOverlay(repo):
                        vcsType, ourl = overlayDb.getOverlayVcsTypeAndUrl(repo)
                    if ourl is None:
                        raise Exception("no URL for overlay %s" % repo)
                    if buildServer is None:
                        FmUtil.cmdExec(self.opSync, self.param.runMode, "add-transient-overlay", repo, vcsType, ourl)
                    else:
                        buildServer.sshExec(self.opSync, self.param.runMode, "add-transient-overlay", repo, vcsType, ourl)
                        buildServer.syncDownWildcardList([
                            os.path.join(pkgwh.layman.getOverlayFilesDir(repo), "***"),
                            pkgwh.layman.getOverlayDir(repo),
                            pkgwh.layman.getOverlayCfgReposFile(repo),
                        ], quiet=True)
                    print("")

            # add pre-enabled packages
            for repo, data in pkgwh.getPreEnablePackages().items():
                tlist = [x for x in data[1] if not pkgwh.layman.isOverlayPackageEnabled(repo, x)]
                if tlist != []:
                    self.infoPrinter.printInfo(">> Enabling packages in overlay \"%s\"..." % repo)
                    self._exec(buildServer, self.opSync, self.param.runMode, "enable-overlay-package", repo, *tlist)
                    print("")
            if buildServer is not None:
                buildServer.syncDownDirectory(os.path.join(FmConst.portageDataDir, "overlay-*"), quiet=True)

            # refresh package related stuff
            self._execAndSyncDownQuietly(buildServer, self.opSync, self.param.runMode, "refresh-package-related-stuff", directory=FmConst.portageCfgDir)

            # eliminate "Performing Global Updates"
            self._execAndSyncDownQuietly(buildServer, self.opSync, self.param.runMode, "touch-portage-tree", directory=FmConst.portageDbDir)     # FIXME

        # do fetch and build
        if True:
            resultFile = os.path.join(self.param.tmpDir, "result.txt")
            kernelCfgRules = json.dumps(self.param.machineInfoGetter.hwInfo().kernelCfgRules)

            # install kernel, initramfs and bootloader
            with BootDirWriter(layout):
                self.infoPrinter.printInfo(">> Installing %s-%s..." % (bbkiObj.get_kernel_atom().fullname, bbkiObj.get_kernel_atom().ver))
                if True:
                    self._exec(buildServer, self.opInstallKernel, self.param.runMode, kernelCfgRules, resultFile)
                    # kernelBuilt, postfix = self._parseKernelBuildResult(self._readResultFile(buildServer, resultFile))
                    print("")

                    if buildServer is not None:
                        self.infoPrinter.printInfo(">> Synchronizing down /boot, /lib/modules and /lib/firmware...")
                        buildServer.syncDownKernel()
                        print("")

                self.infoPrinter.printInfo(">> Creating initramfs...")
                if True:
                    if self.param.runMode in ["normal", "setup"]:
                        bbkiObj.installInitramfs()
                    else:
                        print("WARNING: Running in \"%s\" mode, do NOT create initramfs!!!" % (self.param.runMode))
                    print("")

                self.infoPrinter.printInfo(">> Updating boot-loader...")
                if self.param.runMode in ["normal", "setup"]:
                    bbkiObj.updateBootloader()
                else:
                    print("WARNING: Running in \"%s\" mode, do NOT maniplate boot-loader!!!" % (self.param.runMode))
                print("")

            # synchronize boot partitions
            if layout.name in ["efi-btrfs", "efi-bcache-btrfs", "efi-bcachefs"]:
                dstList = layout.get_pending_esp_list()
                if len(dstList) > 0:
                    with self.infoPrinter.printInfoAndIndent(">> Synchronizing boot partitions..."):
                        for dst in dstList:
                            self.infoPrinter.printInfo("        - %s to %s..." % (layout.get_esp(), dst))
                            layout.sync_esp(dst)
                    print("")

            # emerge @world
            self.infoPrinter.printInfo(">> Updating @world...")
            if buildServer is not None:
                try:
                    buildServer.sshExec(self.opEmergeWorld)
                finally:
                    self.infoPrinter.printInfo(">> Synchronizing down system files...")
                    buildServer.syncDownSystem()
                    print("")
            else:
                FmUtil.cmdExec(self.opEmergeWorld)

            # re-emerge all "-9999" packages
            self.infoPrinter.printInfo(">> Updating all \"-9999\" packages...")
            if buildServer is not None:
                try:
                    buildServer.sshExec(self.opEmerge9999)
                finally:
                    self.infoPrinter.printInfo(">> Synchronizing down system files...")
                    buildServer.syncDownSystem()
                    print("")
            else:
                FmUtil.cmdExec(self.opEmerge9999)

        # end remote build
        if buildServer is not None:
            buildServer.dispose()

    def stablize(self):
        layout = strict_hdds.get_storage_layout()
        bbkiObj = BbkiWrapper(layout)

        self.infoPrinter.printInfo(">> Stablizing...")
        with BootDirWriter(layout):
            bbkiObj.setStable(True)
        print("")

        if layout.name in ["efi-btrfs", "efi-bcache-btrfs", "efi-bcachefs"]:
            dstList = layout.get_pending_esp_list()
            if len(dstList) > 0:
                with self.infoPrinter.printInfoAndIndent(">> Synchronizing boot partitions..."):
                    for dst in dstList:
                        self.infoPrinter.printInfo("        - %s to %s..." % (layout.get_esp(), dst))
                        layout.sync_esp(dst)
                print("")

    def updateAfterHddAddOrRemove(self, hwInfo, layout, bbkiObj):
        pendingBe = bbkiObj.get_pending_boot_entry()
        if pendingBe is None:
            raise Exception("No boot entry found!")

        # re-create initramfs
        with BootDirWriter(layout):
            self.infoPrinter.printInfo(">> Recreating initramfs...")
            bbkiObj.installInitramfs()
            print("")

            self.infoPrinter.printInfo(">> Updating boot-loader...")
            bbkiObj.updateBootloader()
            print("")

        # synchronize boot partitions
        if layout.name in ["efi-btrfs", "efi-bcache-btrfs", "efi-bcachefs"]:
            dstList = layout.get_pending_esp_list()
            if len(dstList) > 0:
                with self.infoPrinter.printInfoAndIndent(">> Synchronizing boot partitions..."):
                    for dst in dstList:
                        self.infoPrinter.printInfo("        - %s to %s..." % (layout.get_esp(), dst))
                        layout.sync_esp(dst)
                print("")

    def _exec(self, buildServer, *args, base64=False):
        if buildServer is None:
            FmUtil.cmdExec(*args)
        else:
            buildServer.sshExec(*args, base64=base64)

    def _readResultFile(self, buildServer, resultFile):
        if buildServer is None:
            with open(resultFile, "r", encoding="iso8859-1") as f:
                return f.read()
        else:
            return buildServer.getFile(resultFile).decode("iso8859-1")

    def _execAndSyncDownQuietly(self, buildServer, *args, directory=None):
        if buildServer is None:
            FmUtil.cmdExec(*args)
        else:
            buildServer.sshExec(*args)
            buildServer.syncDownDirectory(directory, quiet=True)

    def _parseKernelBuildResult(self, result):
        lines = result.split("\n")
        lines = [x.rstrip() for x in lines if x.rstrip() != ""]
        assert len(lines) == 2
        return (lines[0] != "0", lines[1])       # (kernelBuilt, postfix)


from typing import Optional, Union
import pytorch3d
from pytorch3d.common.datatypes import Device
from pytorch3d.renderer.blending import BlendParams, _get_background_color
from pytorch3d.renderer.materials import Materials
from pytorch3d.renderer.mesh import shader
from pytorch3d.renderer.mesh.rasterizer import Fragments
from pytorch3d.renderer.utils import TensorProperties
from pytorch3d.structures.utils import padded_to_list
from pytorch3d.ops import interpolate_face_attributes
import torch
from pytorch3d.structures.meshes import Meshes
from BRDF import brdf_shading

class NeuralTextureShader(shader.ShaderBase):
    """
    The texels are retreived from a neural represented texture
    """
    def __init__(self,
        diff_tex = None,
        device: Device = "cpu",
        cameras: Optional[TensorProperties] = None,
        light_enable = True,
        lights: Optional[TensorProperties] = None,
        materials: Optional[Materials] = None,
        blend_params: Optional[BlendParams] = None,
        mesh_data = None,
        rand_back = False,
        depth_render = False,
        depth_value_inverse = False,
        field_sample = False,
        shading_method = 'phong' #phong or brdf
        ):
        super().__init__(device, cameras, lights, materials, blend_params)
        self.diff_tex = diff_tex
        self.mesh = mesh_data['mesh_obj']
        self.verts = mesh_data['verts']
        self.aux = mesh_data['aux']
        self.faces = mesh_data['faces']
        self.light_enable = light_enable
        self.rand_back = rand_back
        self.depth_render = depth_render
        self.depth_value_inverse = depth_value_inverse
        self.field_sample = field_sample
        self.shading_method = shading_method
        self.device = device

    def forward(self, fragments: Fragments, meshes: Meshes, **kwargs) -> torch.Tensor:
        cameras = super()._get_cameras(**kwargs)
        #texels = self.texture_sample(fragments)
        #texels = self.pixel_coordinate_color(fragments=fragments)
        #texels = self.world_coordinate_color(fragments=fragments)
        if self.depth_render:
            texels_z = self.z_coordinate_color(fragments=fragments)
            texels = texels * texels_z
        elif self.field_sample:
            texels = self.field_texture_sample(fragments=fragments)
        else:
            texels = self.texture_sample(fragments=fragments)

        #texels = self.norm_color(fragments=fragments)
        #texels = self.texture_uv_color(fragments=fragments)
        #texels = torch.tensor([1, 0, 0], dtype=torch.float32, device=self.device, requires_grad=True)
        #texels = texels.repeat(torch.unsqueeze(fragments.pix_to_face, 4).size())
        #print("texels:",texels.size())
        #print("test:",test.size())

        lights = kwargs.get("lights", self.lights)
        materials = kwargs.get("materials", self.materials)
        blend_params = kwargs.get("blend_params", self.blend_params)
        #print(texels.size())
        if self.light_enable:
            if self.shading_method == 'phong':
            #do not support rendering in latent space
                colors = shader.phong_shading(
                    meshes=meshes,
                    fragments=fragments,
                    texels=texels[:, :, :, :, 0:3],
                    lights=lights,
                    cameras=cameras,
                    materials=materials
                )
            elif self.shading_method == 'brdf':
                colors = brdf_shading(
                    meshes=meshes,
                    fragments=fragments,
                    texels=texels[:, :, :, :, 0:8],
                    lights=lights,
                    cameras=cameras,
                    materials=materials,
                    device=self.device
                )
            elif self.shading_method == 'norm':
                colors = self.norm_shading(
                    meshes=meshes,
                    fragments=fragments,
                    texels=texels
                )
            else:
                colors = texels

        else:
            colors = texels # no lighting

        znear = kwargs.get("znear", getattr(cameras, "znear", 1.0))
        zfar = kwargs.get("zfar", getattr(cameras, "zfar", 100.0))
        images = self.softmax_rgb_blend_custom(
            colors, fragments, blend_params, znear=znear, zfar=zfar
        )
        return images

    def pixel_coordinate_color(self, fragments: Fragments):
        #r represent the indice i, and g represent the indice j
        N, H, W, K = fragments.pix_to_face.size()
        r = (torch.arange(start=0, end=H, device=self.device)/H).unsqueeze(0).transpose(0, 1).repeat(1, W)
        g = (torch.arange(start=0, end=W, device=self.device)/W).unsqueeze(0).repeat(H, 1)
        grid = torch.ones((H, W, 3), device=self.device)
        grid[:, :, 0] *= r
        grid[:, :, 1] *= g
        grid[:, :, 2] = 0
        texels = grid.unsqueeze(0).unsqueeze(3).repeat(N, 1, 1, K, 1)
        return texelsphong

    def z_coordinate_color(self, fragments: Fragments):
        #r represent the indice i, and g represent the indice j
        N, H, W, K = fragments.pix_to_face.size()
        z = fragments.zbuf
        z_max = z.max().item()
        z_min = z[z>-1].min().item()
        if self.depth_value_inverse:
            z[z>-1] = (z_max + 0.5*(z_max - z_min) - z[z>-1]) / ((z_max - z_min) * 1.5)
        else:
            z[z>-1] = (z[z>-1] - z_min + 0.5*(z_max - z_min)) / ((z_max - z_min) * 1.5)

        texels = torch.zeros((N, H, W, K, 3), device=self.device)
        texels[:, :, :, :, 0] = z
        texels[:, :, :, :, 1] = z
        texels[:, :, :, :, 2] = z

        return texels

    def ndc_coordinate_color(self, fragments: Fragments):
        N, H, W, K = fragments.pix_to_face.size()
        z_near = self.cameras.znear
        z_far = self.cameras.zfar - 94
        depth = (fragments.zbuf - z_near) / (z_far - z_near)
        #ndc coord
        h = ((torch.arange(start=0, end=H, device=self.device) * 2 + 1.0) / H - 1.0).unsqueeze(0).transpose(0, 1).repeat(1, W)
        w = ((torch.arange(start=0, end=W, device=self.device) * 2 + 1.0) / W - 1.0).unsqueeze(0).repeat(H, 1)
        ndc_coordinate = torch.ones((H, W, 3), device=self.device)
        ndc_coordinate[:, :, 0] *= (-w + 1) / 2
        ndc_coordinate[:, :, 1] *= (-h + 1) / 2
        ndc_coordinate[:, :, 2] *= depth.reshape(H, W)
        texels = ndc_coordinate.unsqueeze(0).unsqueeze(3).repeat(N, 1, 1, K, 1)

        return texels

    def world_coordinate_color(self, fragments: Fragments):
        #r represent the indice x, g represent the indice y, b represent the indice z
        N, H, W, K = fragments.pix_to_face.size()
        depth = fragments.zbuf
        packing_list = [
            i[j] for i, j in zip([self.verts.to(self.device)], [self.faces.verts_idx.to(self.device)])
        ]
        faces_verts = torch.cat(packing_list)
        pixel_verts = interpolate_face_attributes(
            fragments.pix_to_face, fragments.bary_coords, faces_verts
        ).reshape(-1, 3)

        colors = pixel_verts + 0.5
        texels = colors.reshape(N, H, W, K, 3)
        return texels

    def texture_uv_color(self, fragments: Fragments):
        N, H, W, K = fragments.pix_to_face.size()
        packing_list = [
            i[j] for i, j in zip([self.aux.verts_uvs.to(self.device)], [self.faces.textures_idx.to(self.device)])
        ]
        faces_verts_uvs = torch.cat(packing_list)
        pixel_uvs = interpolate_face_attributes(
            fragments.pix_to_face, fragments.bary_coords, faces_verts_uvs
        ).reshape(-1, 2) #range [0, 1]
        zero_temp = torch.zeros((H*W, 1), device=self.device)
        colors = torch.cat((pixel_uvs, zero_temp), dim=1)
        texels = colors.reshape(N, H, W, K, 3)
        return texels

    def norm_color(self, fragments: Fragments):
        N, H, W, K = fragments.pix_to_face.size()
        packing_list = [
            i[j] for i, j in zip([self.aux.normals.to(self.device)], [self.faces.normals_idx.to(self.device)])
        ]
        faces_normals = torch.cat(packing_list)
        pixel_normals = interpolate_face_attributes(
            fragments.pix_to_face, fragments.bary_coords, faces_normals
        ).reshape(-1, 3)
        colors = pixel_normals
        texels = colors.reshape(N, H, W, K, 3)
        return texels

    def norm_shading(self, meshes, fragments, texels):
        """
        Input:
            texels: (N, H, W, K, C)

        Returns:
            colors: (N, H, W, K, 3), range[0, 1] (mapped from [-1, 1])
        """

        N, H, W, K, C = texels.size()
        # if there is a normal texture
        norm_bias = texels[:, :, :, :, 5:8] if C==8 else torch.zeros((N, H, W, K, C), dtype=torch.float32, device=self.device)

        verts = meshes.verts_packed()  # (V, 3)
        faces = meshes.faces_packed()  # (F, 3)
        vertex_normals = meshes.verts_normals_packed()  # (V, 3)
        faces_normals = vertex_normals[faces]

        pixel_normals = interpolate_face_attributes(
            fragments.pix_to_face, fragments.bary_coords, faces_normals
        ) # pixel_normals (1, H, W, 1, 3)

        #colors = ((pixel_normals + norm_bias) + 1) / 2
        colors = (pixel_normals + 1)/2

        return colors

    def field_texture_sample(self, fragments: Fragments, nearest=False):
        N, H, W, K = fragments.pix_to_face.size()
        depth = fragments.zbuf
        packing_list = [
            i[j] for i, j in zip([self.verts.to(self.device)], [self.faces.verts_idx.to(self.device)])
        ]
        faces_verts = torch.cat(packing_list)
        pixel_verts = interpolate_face_attributes(
            fragments.pix_to_face, fragments.bary_coords, faces_verts
        ).reshape(-1, 3)

        pixel_verts = pixel_verts * 2.0 #range [-1, 1]
        colors = self.diff_tex(pixel_verts)

        if colors.size()[1] == 3:
            colors = (colors + 1) / 2
        elif colors.size()[1] == 8:
            colors[:, 0:5] = (colors[:, 0:5] + 1) / 2

        colors = colors.reshape(N, H, W, colors.size()[1])
        texels = colors.unsqueeze(3).repeat(1, 1, 1, K, 1)
        return texels

    def texture_sample(self, fragments: Fragments, nearest=False):
        N, H, W, K = fragments.pix_to_face.size()
        packing_list = [
            i[j] for i, j in zip([self.aux.verts_uvs.to(self.device)], [self.faces.textures_idx.to(self.device)])
        ]
        faces_verts_uvs = torch.cat(packing_list)

        pixel_uvs = interpolate_face_attributes(fragments.pix_to_face, fragments.bary_coords, faces_verts_uvs).reshape(-1, 2) #range [0, 1]

        pixel_uvs = pixel_uvs * 2.0 - 1.0 #range [-1, 1]
        temps = pixel_uvs[:, 0].clone()
        pixel_uvs[:, 0] = -pixel_uvs[:, 1]
        pixel_uvs[:, 1] = temps
        colors = self.diff_tex(pixel_uvs)
        if colors.size()[1] == 3:
            colors = (colors + 1) / 2
        elif colors.size()[1] == 8:
            colors[:, 0:5] = (colors[:, 0:5] + 1) / 2
        colors = colors.reshape(N, H, W, colors.size()[1])
        texels = colors.unsqueeze(3).repeat(1, 1, 1, K, 1)
        return texels

    def field_sample(self, fragments: Fragments, nearest=False):
        N, H, W, K = fragments.pix_to_face.size()
        packing_list = [
            i[j] for i, j in zip([self.aux.verts_uvs.to(self.device)], [self.faces.textures_idx.to(self.device)])
        ]
        faces_verts_uvs = torch.cat(packing_list)
        pixel_uvs = interpolate_face_attributes(fragments.pix_to_face, fragments.bary_coords, faces_verts_uvs).reshape(-1, 2) #range [0, 1]

        pixel_uvs = pixel_uvs * 2.0 - 1.0 #range [-1, 1]
        temps = pixel_uvs[:, 0].clone()
        pixel_uvs[:, 0] = -pixel_uvs[:, 1]
        pixel_uvs[:, 1] = temps
        colors = self.diff_tex(pixel_uvs)
        if colors.size()[1] == 3:
            colors = (colors + 1) / 2
        elif colors.size()[1] == 8:
            colors[:, 0:5, :, :] = (colors[:, 0:5, :, :] + 1) / 2
        colors = colors.reshape(N, H, W, colors.size()[1])
        #print(colors[256, 256, :])
        texels = colors.unsqueeze(3).repeat(1, 1, 1, K, 1)
        return texels

    def verts_uvs_list(self):
        if self._verts_uvs_list is None:
            if self.isempty():
                self._verts_uvs_list = [
                    torch.empty((0, 2), dtype=torch.float32, device=self.device)
                ] * self._N
            else:
                # The number of vertices in the mesh and in verts_uvs can differ
                # e.g. if a vertex is shared between 3 faces, it can
                # have up to 3 different uv coordinates.
                self._verts_uvs_list = list(self._verts_uvs_padded.unbind(0))
        return self._verts_uvs_list

    def faces_uvs_list(self):
        if self._faces_uvs_list is None:
            if self.isempty():
                self._faces_uvs_list = [
                    torch.empty((0, 3), dtype=torch.float32, device=self.device)
                ] * self._N
            else:
                self._faces_uvs_list = padded_to_list(
                    self._faces_uvs_padded, split_size=self._num_faces_per_mesh
                )
        return self._faces_uvs_list

    def softmax_rgb_blend_custom(
        self,
        colors: torch.Tensor,
        fragments,
        blend_params: BlendParams,
        znear: Union[float, torch.Tensor] = 1.0,
        zfar: Union[float, torch.Tensor] = 100
    ) -> torch.Tensor:
        """
        RGB and alpha channel blending to return an RGBA image based on the method
        proposed in [1]
        - **RGB** - blend the colors based on the 2D distance based probability map and
            relative z distances.
        - **A** - blend based on the 2D distance based probability map.

        Args:
            colors: (N, H, W, K, 3) RGB color for each of the top K faces per pixel.
            fragments: namedtuple with outputs of rasterization. We use properties
                - pix_to_face: LongTensor of shape (N, H, W, K) specifying the indices
                of the faces (in the packed representation) which
                overlap each pixel in the image.
                - dists: FloatTensor of shape (N, H, W, K) specifying
                the 2D euclidean distance from the center of each pixel
                to each of the top K overlapping faces.
                - zbuf: FloatTensor of shape (N, H, W, K) specifying
                the interpolated depth from each pixel to to each of the
                top K overlapping faces.
            blend_params: instance of BlendParams dataclass containing properties
                - sigma: float, parameter which controls the width of the sigmoid
                function used to calculate the 2D distance based probability.
                Sigma controls the sharpness of the edges of the shape.
                - gamma: float, parameter which controls the scaling of the
                exponential function used to control the opacity of the color.
                - background_color: (3) element list/tuple/torch.Tensor specifying
                the RGB values for the background color.
            znear: float, near clipping plane in the z direction
            zfar: float, far clipping plane in the z direction

        Returns:
            RGBA pixel_colors: (N, H, W, 4)

        [0] Shichen Liu et al, 'Soft Rasterizer: A Differentiable Renderer for
        Image-based 3D Reasoning'
        """

        N, H, W, K = fragments.pix_to_face.shape
        D = (colors.size()[4] + 1) #pixel buffer depth
        pixel_colors = torch.ones((N, H, W, D), dtype=colors.dtype, device=colors.device)
        #pixel_colors = torch.ones((N, H, W, 4), dtype=colors.dtype, device=colors.device)
        background_color = torch.ones(D-1, dtype=colors.dtype, device=colors.device) * 0.0
        if self.rand_back:
            background_color =  torch.rand(D-1, dtype=colors.dtype, device=colors.device) * 2 - 1#random background color

        #background_color = _get_background_color(blend_params, fragments.pix_to_face.device)

        # Weight for background color
        eps = 1e-10

        # Mask for padded pixels.
        mask = fragments.pix_to_face >= 0

        # Sigmoid probability map based on the distance of the pixel to the face.
        prob_map = torch.sigmoid(-fragments.dists / blend_params.sigma) * mask

        # The cumulative product ensures that alpha will be 0.0 if at least 1
        # face fully covers the pixel as for that face, prob will be 1.0.
        # This results in a multiplication by 0.0 because of the (1.0 - prob)
        # term. Therefore 1.0 - alpha will be 1.0.
        alpha = torch.prod((1.0 - prob_map), dim=-1)

        # Weights for each face. Adjust the exponential by the max z to prevent
        # overflow. zbuf shape (N, H, W, K), find max over K.
        # TODO: there may still be some instability in the exponent calculation.

        # Reshape to be compatible with (N, H, W, K) values in fragments
        if torch.is_tensor(zfar):
            # pyre-fixme[16]
            zfar = zfar[:, None, None, None]
        if torch.is_tensor(znear):
            # pyre-fixme[16]: Item `float` of `Union[float, Tensor]` has no attribute
            #  `__getitem__`.
            znear = znear[:, None, None, None]

        z_inv = (zfar - fragments.zbuf) / (zfar - znear) * mask
        z_inv_max = torch.max(z_inv, dim=-1).values[..., None].clamp(min=eps)
        weights_num = prob_map * torch.exp((z_inv - z_inv_max) / blend_params.gamma)

        # Also apply exp normalize trick for the background color weight.
        # Clamp to ensure delta is never 0.
        # pyre-fixme[6]: Expected `Tensor` for 1st param but got `float`.
        delta = torch.exp((eps - z_inv_max) / blend_params.gamma).clamp(min=eps)

        # Normalize weights.
        # weights_num shape: (N, H, W, K). Sum over K and divide through by the sum.
        denom = weights_num.sum(dim=-1)[..., None] + delta

        # Sum: weights * textures + background color
        weighted_colors = (weights_num[..., None] * colors).sum(dim=-2)
        weighted_background = delta * background_color
        pixel_colors[..., :(D-1)] = (weighted_colors + weighted_background) / denom
        pixel_colors[..., D-1] = 1.0 - alpha

        return pixel_colors

def main():
    from pytorch3d import renderer
    from pytorch3d import io
    import matplotlib.pyplot as plt
    import torch
    from Neural_Texture_Shader import NeuralTextureShader
    from utils import device
    from Neural_Texture_Field import NeuralTextureField
    #mesh
    mesh_path = "./Assets/3D_Model/Cow/cow.obj"
    #mesh_path = "./Assets/3D_Model/Cow/cow.obj"
    mesh_obj = io.load_objs_as_meshes([mesh_path], device=device)
    verts, faces, aux = io.load_obj(mesh_path)
    tex_net = NeuralTextureField(width=512, depth=3, input_dim=2, pe_enable=True)
    tex_net.load_state_dict(torch.load("./Experiments/mlp_represented_image_training _entire_image/test5_validate/nth.pth"))

    #camera
    R, T = renderer.look_at_view_transform(2.3, 0, 135)
    camera = renderer.FoVPerspectiveCameras(R=R, T=T, device=device)

    #light
    light = renderer.PointLights(device=device, location=[[0.0, 10.0, 10.0]])

    #renderer
    raster_setting = renderer.RasterizationSettings(image_size=512, blur_radius=0.0, faces_per_pixel=1)

    mesh_renderer = renderer.MeshRenderer(
        rasterizer=renderer.MeshRasterizer(
            cameras=camera,
            raster_settings=raster_setting
        ),
        shader = NeuralTextureShader(
            tex_net=tex_net,
            device=device,
            cameras=camera,
            light_enable=True,
            lights=light,
            aux=aux,
            faces=faces
        )
    )

    #rendering
    image_tensor = mesh_renderer(mesh_obj)
    #loss = image_tensor.sum()
    #loss.backward()
    img = image_tensor[0, :, :, 0:3].cpu().detach().numpy()
    plt.imshow(img)
    plt.show()

def main_2():
    from pytorch3d import renderer
    from pytorch3d import io
    import matplotlib.pyplot as plt
    import torch
    from Neural_Texture_Shader import NeuralTextureShader
    from utils import device
    from Differentiable_Texture import DiffTexture
    #mesh
    mesh_path = "./Assets/3D_Model/Cow/cow.obj"
    mesh_obj = io.load_objs_as_meshes([mesh_path], device=device)
    verts, faces, aux = io.load_obj(mesh_path)
    diff_tex = DiffTexture(size=(2048, 2048))

    #camera
    R, T = renderer.look_at_view_transform(2.3, 0, 135)
    camera = renderer.FoVPerspectiveCameras(R=R, T=T, device=device)

    #light
    light = renderer.PointLights(device=device, location=[[0.0, 10.0, 10.0]])

    #renderer
    raster_setting = renderer.RasterizationSettings(image_size=512, blur_radius=0.0, faces_per_pixel=1)

    mesh_renderer = renderer.MeshRenderer(
        rasterizer=renderer.MeshRasterizer(
            cameras=camera,
            raster_settings=raster_setting
        ),
        shader = NeuralTextureShader(
            diff_tex=diff_tex,
            device=device,
            cameras=camera,
            light_enable=True,
            lights=light,
            aux=aux,
            faces=faces
        )
    )

    #rendering
    image_tensor = mesh_renderer(mesh_obj)
    #loss = image_tensor.sum()
    #loss.backward()
    img = image_tensor[0, :, :, 0:3].cpu().detach().numpy()
    plt.imshow(img)
    plt.show()

if __name__ == "__main__":
    main_2()


import sys
import http.client
import urllib
import json
import hashlib
import hmac
import time
import requests

def get_highest_price(ask):
    best = ask[0][0]
    for a in ask:
        if best < a[0]:
            best = a[0]
    return best

def get_lowest_price(ask):
    best = ask[0][0]
    for a in ask:
        if best > a[0]:
            best = a[0]
    return best

def get_prices():
    r = requests.get('https://api.exmo.com/v1/order_book?pair=LTC_BTC')
    return r.json()['LTC_BTC']

class ExmoAPI:
    def __init__(self, API_KEY, API_SECRET, API_URL = 'api.exmo.com', API_VERSION = 'v1'):
        self.API_URL = API_URL
        self.API_VERSION = API_VERSION
        self.API_KEY = API_KEY
        self.API_SECRET = bytes(API_SECRET, encoding='utf-8')
        self.nonce = int(time.time() * 1000)
        self.btc_balance = 0.00050614
        self.ltc_balance = 0.05890065
        print(self.nonce)

    def sha512(self, data):
        H = hmac.new(key = self.API_SECRET, digestmod = hashlib.sha512)
        H.update(data.encode('utf-8'))
        return H.hexdigest()

    def api_query(self, api_method, params = {}):
        params['nonce'] = self.nonce
        self.nonce += 1
        params =  urllib.parse.urlencode(params)

        sign = self.sha512(params)
        headers = {
            "Content-type": "application/x-www-form-urlencoded",
            "Key": self.API_KEY,
            "Sign": sign
        }
        conn = http.client.HTTPSConnection(self.API_URL)
        conn.request("POST", "/" + self.API_VERSION + "/" + api_method, params, headers)
        response = conn.getresponse().read()

        conn.close()

        try:
            obj = json.loads(response.decode('utf-8'))
            if 'error' in obj and obj['error']:
                print(obj['error'])
                raise sys.exit()
            return obj
        except json.decoder.JSONDecodeError:
            print('Error while parsing response:', response)
            raise sys.exit()

# Example
api = ExmoAPI(
                            'K-b90680b171c69ac996a55a2066f8d38d0a50b9d4',
                            'S-7c2e02d07fd2dab84eef46e0606dc0f6e7e9173a'
)
while True:
    prices = get_prices()
    balances = api.api_query('user_info')['balances']
    print('LTC: ', balances['LTC'], '  BTC: ', balances['BTC'])
    highest_price = get_highest_price(prices['bid'])
    lowest_price = get_lowest_price(prices['ask'])
    print('sell: ', highest_price, 'buy: ', lowest_price)
    if float(balances['LTC']) > .04:
        print(
              'amount_btc: ',
              float(balances['LTC']) * float(highest_price) * .99,
              ' cur_balance:',
              api.btc_balance,
              '\n'
        )
    if float(balances['BTC']) > .0004:
        print(
              'amount_ltc: ',
              '{:.9f}'.format(float(balances['BTC']) / float(lowest_price) * .99),
              ' cur_balance:',
              api.ltc_balance,
              '\n'
        )
    if float(balances['LTC']) * float(highest_price) * .99 > api.btc_balance:
        api.api_query(
                'order_create',
                {
                    'pair': 'LTC_BTC',
                    'quantity': balances['LTC'],
                    'price': highest_price,
                    'type': 'sell'
        })
        print('selled ', balances['LTC'], '  price: ', highest_price, '\n')
        api.btc_balance = float(balances['LTC']) * float(highest_price)
    if float(balances['BTC']) / float(lowest_price) * .99 > api.ltc_balance:
        api.api_query(
                'order_create',
                {
                    'pair': 'LTC_BTC',
                    'quantity': balances['BTC'],
                    'price': lowest_price,
                    'type': 'buy'
        })
        print('bought ', balances['BTC'], '  price: ', lowest_price, '\n')
        api.ltc_balance = float(balances['BTC']) / float(lowest_price)
    time.sleep(1)


import itertools

def stars_basic(n):
    for numStars in range(1, n):
        for _ in range(numStars):
            print('* ', end='')
        print()
    for numStars in range(n, 0, -1):
        for _ in range(numStars):
            print('* ', end='')
        print()

def stars_fancy(n):
    for numStars in itertools.chain(range(1, n), range(n, 0, -1)):
        print('* ' * numStars)

def up_and_down(start, top, end):
    for i in range(start, top):
        yield i
    for i in range(top, end - 1, -1):
        yield i

def stars_custom(n):
    for numStars in up_and_down(1, n, 1):
        for _ in range(numStars):
            print('* ', end='')
        print()


class Solution:
    def countBattleships(self, board):
        """
        :type board: List[List[str]]
        :rtype: int
        """
        height = len(board)

        if height == 0:
            return 0

        width = len(board[0])
        count = 0
        for i in range (0, height, 1):
            for j in range (0, width, 1):
                if board[i][j] == "X":
                    adjacentX = i > 0 and board[i - 1][j] == "X"
                    adjacentY = j > 0 and board[i][j - 1] == "X"
                    if not adjacentX and not adjacentY:
                        count += 1
        return count

if __name__ == "__main__":
    target = Solution()
    board = []
    board.append(["X",".",".","X"])
    board.append([".",".",".","X"])
    board.append([".",".",".","X"])
    print(target.countBattleships(board))


#!/usr/bin/env python
# -*- coding: utf-8 -*-
import unittest
from datetime import datetime, time

from pandas.core.frame import DataFrame

from Env.TimeConstants import BA
from Framing.Specifics import BAFormatFinalizer
from config import LOGGER

class BAFormatFinalizerTest(unittest.TestCase):

    def setUp(self):
        self.df = DataFrame({BA.Duration: [59, 0],
                             BA.Pause: [305, 80],
                             BA.BeginTime: [time(12, 15), time(13, 15)],
                             BA.EndTime: [time(15, 15), time(16, 15)],
                             BA.BuildDate: [datetime(2000, 1, 1).date(),
                                            datetime(2022, 1, 1).date()]})

    def tearDown(self):
        pass

    def testName(self):
        builder = BAFormatFinalizer()
        df = builder.build_frame(self.df)
        LOGGER.info(df)
        assert df.get_value(0, BA.Duration) == "01:00"

    def testName2(self):
        builder = BAFormatFinalizer()
        df = builder.build_frame(self.df)
        LOGGER.info(df)
        assert df.get_value(0, BA.Pause) == "05:15"

    def testName3(self):
        builder = BAFormatFinalizer()
        df = builder.build_frame(self.df)
        LOGGER.info(df)
        assert df.get_value(0, BA.BuildDate) == "01.01.2000"

    def testName4(self):
        builder = BAFormatFinalizer()
        df = builder.build_frame(self.df)
        LOGGER.info(df)
        assert df.get_value(0, BA.BeginTime) == "12:15"

if __name__ == "__main__":
    # import sys;sys.argv = ['', 'Test.testName']
    unittest.main()


import tkinter as tk
import const as Const
import window_child as Child_window
import window_side
import window_splash
import drawble as r
import util
from config import Config
from tkinter import messagebox
from tkinter import filedialog
from file_name import FileName
import os
import webbrowser
import winsound

class Main(tk.Tk):
    def __init__(self):
        # CREATE MAIN WINDOW
        tk.Tk.__init__(self)
        self.title("Busload Calc " + Const.__version__)
        self.option_add('*tearOff', False)
        self.geometry('900x600')
        self.minsize(480, 600)
        self.iconbitmap(util.get_icon(r.ICO_MAIN))
        self.wm_protocol("WM_DELETE_WINDOW", lambda: self.quit())

        # CREATE MAIN MENU OBJECT
        self.menu = CreateMenu(self)

        # CREATE STATUS BAR
        self.status_bar = StatusBar(self)

        # SET GLOBAL PARAMETERS
        self.pos = []  # main window position
        self.init_position = 0  # initial position for new child window
        self.child_windows = []  # list of child windows
        self.configs = []  # list of configurations
        self.init_config = []
        self.side_is_open = False

        self.default_status_bar_message()

        self._apply_file_init()
        self.status_bar.responsible.set(self.init_config.get('responsible'))

        if self.init_config.get('see_welcome') == '0':
            self.open_welcome_window()

    def _apply_file_init(self):
        config = util.reading_json(Const.BUSLOAD_INIT, self)
        if not self._is_valide_init_config(config):
            config = self._get_default_init()

        self.init_config = config
        config = self._check_file_name(self.init_config['recent_config'])
        report = self._check_file_name(self.init_config['recent_report'])
        side = self._check_file_name(self.init_config['recent_side'])
        self.menu.recent_menu_update_config(config, self)
        self.menu.recent_menu_update_report(report, self)
        self.menu.recent_menu_update_side(side, self)

    def _check_file_name(self, file_list):
        return [file for file in file_list if os.path.exists(file)]

    def _is_valide_init_config(self, config):
        if config:
            if 'version' in config.keys():
                config_version = config['version'].split('.')
                version = Const.__version__.split('.')
                if int(config_version[0])*10 + int(config_version[1]) >= 21:
                    # The config file over 2.1 has particular features not compatible with 2.0
                    return True
        return False

    def _get_default_init(self):
        if not os.path.exists('dbc'):
            os.mkdir('dbc')
        if not os.path.exists('configs'):
            os.mkdir('configs')
        if not os.path.exists('output'):
            os.mkdir('output')

        config = {
            "Busload Calc configuration": "2020",
            "version": Const.__version__[:-2],
            "responsible": "@Responsible name",
            "index_title": 0,
            "index_side_title": 0,
            "max_recent": 20,
            "see_welcome": "0",
            "yellow_region": "50",
            "red_region": "70",
            "recent_side": [],
            "recent_config": [],
            "recent_report": []
        }
        self.main_mesage_box ('File "{}" created successfully.'.format(Const.BUSLOAD_INIT))
        return config

    def add_recent_config(self, file):
        if file and file not in self.init_config['recent_config']:
            self.menu.recent_menu_update_config([file], self)
            if len(self.init_config['recent_config']) > self.init_config['max_recent']:
                self.init_config['recent_config'].pop(0)
                self.menu.remove_config()
            self.init_config['recent_config'].append(file)

    def add_recent_side(self, file):
        if file and file not in self.init_config['recent_side']:
            self.menu.recent_menu_update_side([file], self)
            if len(self.init_config['recent_side']) > self.init_config['max_recent']:
                self.init_config['recent_side'].pop(0)
                self.menu.remove_side()
            self.init_config['recent_side'].append(file)

    def add_recent_report(self, file):
        if file and file not in self.init_config['recent_report']:
            self.menu.recent_menu_update_report([file], self)
            if len(self.init_config['recent_report']) > self.init_config['max_recent']:
                self.init_config['recent_report'].pop(0)
                self.menu.remove_report()
            self.init_config['recent_report'].append(file)

    def run_calc(self, config):
        util.apply_config(config)
        self.status_bar.set_status_msg('Calculating Busload...')
        config.yellow = self._define_region(self.init_config.get('yellow_region'))
        config.red =self._define_region(self.init_config.get('red_region'))

        try:
            util.calc_busload(config)
            return config
        except Exception as e:
            self.main_mesage_box('Error during busload calculation. \nDBC format not supported.\n\n{}'.format(e))
            return []

    def _define_region(self, value):
        try:
            result = int(value) * 2 + 110
        except:
            result = 210
        return result

    def get_child_window_position(self):
        x, y = self.winfo_rootx() + self.init_position, self.winfo_rooty() + (self.init_position % 50)
        self.init_position += 20
        return '+{}+{}'.format(x, y)

    def open_side_by_side_window(self):
        if not self.side_is_open:
            self.side_is_open = True
            self.child_windows.append(window_side.SideWindow(self, len(self.child_windows)))
            self.bind('<Configure>', self.state_main)

    def config_status_to_calc(self, turn_on=True):
        if turn_on:
            self.status_bar.set_timeout_off()
        else:
            self.status_bar.set_timeout_on()

    def default_status_bar_message(self):
        self.status_bar.set_list(['Start a new configuration on New Config menu',
                                  'Open an existing configuration on Open Config menu',
                                  'Put your name on the Responsible status bar to auto fulfill the New config'
                                  'Busload Calc 2.0'])

    def menu_new_config(self):
        self.configs.append(Config())
        self.child_windows.insert(-1, Child_window.Child(self, self.configs[-1]))
        self.bind('<Configure>', self.state_main)

    def menu_save_as(self, title):
        if not title.file_extension:
            title.file_extension = '.cnf'
        file = filedialog.asksaveasfilename(initialdir="configs/", initialfile=title.file_name + title.file_extension,
                                            title="Save as a configuration file",
                                            filetypes=[("Busload config", "*.cnf")])
        title = FileName(file)
        if not title.file_extension:
            title.file_extension = '.cnf'
        return title

    def _is_config_already_open(self, title):
        for child in self.child_windows:
            short_name = title.lower().split('/')
            short_name = short_name[-1].split('.')
            if child.title() == short_name[-2]:
                return True
        return False

    def open_welcome_window(self):
        self.welcome = window_splash.Splash(self, Const.WDW_WELCOME)

    def open_about_window(self):
        self.welcome = window_splash.Splash(self, Const.WDW_ABOUT)

    def open_tutorial_window(self):
        self.welcome = window_splash.Splash(self, Const.WDW_TUTORIAL)

    def open_duplicated_config(self, config):
        self.configs.append(Config())
        self.configs[-1].cnf = config
        self.configs[-1].config_name = ""
        self.child_windows.append(Child_window.Child(self,
                                                     self.configs[-1]))

    def open_config(self, title):
        if os.path.exists(title):
            if not self._is_config_already_open(title):
                self.configs.append(Config())
                self.configs[-1].config_name = FileName(title)
                self.child_windows.append(Child_window.Child(self,
                                                             self.configs[-1],
                                                             self.configs[-1].config_name.file_name))
                self.bind('<Configure>', self.state_main)
                self.add_recent_config(title)
            else:
                self.main_mesage_box('File "{}" already open.'.format(title))
        else:
            self.main_mesage_box('File "{}" not found.'.format(title), Const.MSG_ERROR)

    def open_html(self, file):
        try:
            webbrowser.open('file://' + os.path.realpath(file))
        except Exception as e:
            self.main_mesage_box('Error opening {}\n{}'.format(file, e))

    def open_csv(self, file):
        file_name = ''
        for char in file:
            if char == '/':
                file_name += '\\'
            else:
                file_name += char
        try:
            os.startfile(file_name)
        except Exception as e:
            self.main_mesage_box('Error opening {}\n{}'.format(file_name, e))

    def menu_open_dbc(self):
        title = filedialog.askopenfilename(initialdir="dbc/",
                                           title="Select dbc file",
                                           filetypes=[("Busload config", "*.dbc")])
        return FileName(title)

    def menu_open_config(self):
        title = filedialog.askopenfilename(initialdir="configs/",
                                           title="Select configuration file",
                                           filetypes=[("Busload config", "*.cnf")])

        if title:
            title = FileName(title)
            self.open_config(title.get_full_name())

    def state_main(self, *args):
        if self.pos:
            dx = self.pos[0] - self.winfo_x()
            dy = self.pos[1] - self.winfo_y()
            wd = self.winfo_width()
            he = self.winfo_height()
            for c in self.child_windows:
                cwd = c.winfo_width()
                che = c.winfo_height()
                cwd = cwd if cwd + 30 < wd else wd - 30
                che = che if che + 70 < he else he - 70
                c.geometry("{}x{}+{}+{}".format(cwd, che, c.winfo_x() - dx, c.winfo_y() - dy))

        self.pos = [self.winfo_x(), self.winfo_y()]

    def state_child(self, event, *args):
        min_w = self.winfo_rootx()
        min_h = self.winfo_rooty()
        max_w = self.winfo_rootx() + self.winfo_width() - 10
        max_h = self.winfo_rooty() + self.winfo_height() - 65

        for child_window in self.child_windows:
            if child_window.winfo_x() < min_w:
                child_window.geometry("+{0}+{1}".format(min_w, event.y))
                # app.event_generate('<Motion>', warp=True, x = pos[2] + 1, y = pos[3] + pos[5])
            if child_window.winfo_y() < min_h:
                child_window.geometry("+{0}+{1}".format(event.x, min_h))
            if child_window.winfo_x() + child_window.winfo_width() > max_w:
                child_window.geometry("+{0}+{1}".format(max_w - event.width, event.y))
            if child_window.winfo_y() + child_window.winfo_height() > max_h:
                child_window.geometry("+{0}+{1}".format(event.x, max_h - event.height))

    def quit_child(self, child_id, *args):
        for i in range(len(self.child_windows)):
            if child_id == self.child_windows[i].winfo_id():
                self.child_windows[i].destroy()
                del self.child_windows[i]
                if len(self.child_windows) == 0:
                    self.unbind('<Configure>')
                    self.default_status_bar_message()
                break

    def quit(self, *args):
        for child in self.child_windows:
            if not child.saved:
                child.ask_to_save()

        util.writing_json(self.init_config, Const.BUSLOAD_INIT, self)
        self.destroy()

    def main_mesage_box(self, message, box_type=Const.MSG_INFO):
        winsound.Beep(5800, 50)
        if box_type == Const.MSG_INFO:
            return messagebox.showinfo("Attention", message)
        if box_type == Const.MSG_ERROR:
            return messagebox.showerror("Error", message)
        if box_type == Const.MSG_QUESTION:
            return messagebox.askquestion("Buload Calc", message)
        if box_type == Const.MSG_WARNING:
            return messagebox.showwarning("Warning", message)
        if box_type == Const.MSG_OK_CANCEL:
            return messagebox.askokcancel("Busload Calc", message)
        if box_type == Const.MSG_YES_NO:
            return messagebox.askyesno("Busload Calc", message)
        if box_type == Const.MSG_RETRY:
            return messagebox.askretrycancel("Retry", message)

class CreateMenu(tk.Menu):
    def __init__(self, main):
        tk.Menu.__init__(self, main)

        self.main_menu = self
        self.menu_open = tk.Menu(self)
        self.menu_recent_report = tk.Menu(self)
        self.menu_recent_config = tk.Menu(self)
        self.menu_report = tk.Menu(self)
        self.menu_recent_side = tk.Menu(self)
        self.menu_help = tk.Menu(self)

        # MAIN MENU OPTIONS
        self.main_menu.add_cascade(label="Open", menu=self.menu_open)
        self.main_menu.add_command(label="Side-by-side report", command=main.open_side_by_side_window)
        self.main_menu.add_cascade(label="Open recent report", menu=self.menu_report)
        self.main_menu.add_cascade(label="Help", menu=self.menu_help)
        self.main_menu.add_command(label="Exit", command=main.quit)

        # OPEN OPTIONS
        self.menu_open.add_command(label="New config", command=main.menu_new_config)
        self.menu_open.add_command(label="Open config", command=main.menu_open_config)
        self.menu_open.add_separator()
        self.menu_open.add_cascade(label="Recent config", menu=self.menu_recent_config)

        self.menu_help.add_command(label="Welcome", command=lambda: self.menu_welcome(main))
        self.menu_help.add_command(label="Tutorial", command=lambda: self.menu_tutorial(main))
        self.menu_help.add_command(label="About", command=lambda: self.menu_about(main))

        self.menu_report.add_cascade(label="Busload report", menu=self.menu_recent_report)
        self.menu_report.add_cascade(label="Side_by_side report", menu=self.menu_recent_side)

        self.menu_recent_config.add_command(label="Clear list", command=lambda: self._clear_recent_config(main))
        self.menu_recent_config.add_separator()

        self.menu_recent_report.add_command(label="Clear list", command=lambda: self._clear_recent_report(main))
        self.menu_recent_report.add_separator()

        self.menu_recent_side.add_command(label="Clear list", command=lambda: self._clear_recent_side(main))
        self.menu_recent_side.add_separator()

        main.config(menu=self)

    def menu_welcome(self, main):
        main.open_welcome_window()

    def menu_tutorial(self, main):
        main.open_tutorial_window()

    def menu_about(self, main):
        main.open_about_window()

    def _clear_recent_config(self, main):
        self.menu_recent_config.delete(2, self.menu_recent_config.index(tk.END))
        main.init_config['recent_config'] = []

    def _clear_recent_report(self, main):
        self.menu_recent_report.delete(2, self.menu_recent_report.index(tk.END))
        main.init_config['recent_report'] = []

    def _clear_recent_side(self, main):
        self.menu_recent_side.delete(2, self.menu_recent_side.index(tk.END))
        main.init_config['recent_side'] = []

    def menu_enable(self, item):
        self.entryconfig(item, state=tk.NORMAL)

    def recent_menu_update_config(self, config, main):
        for menu_item in config:
            self.menu_recent_config.add_command(label=menu_item, command=lambda sv=menu_item: main.open_config(sv))

    def recent_menu_update_report(self, config, main):
        for menu_item in config:
            self.menu_recent_report.add_command(label=menu_item, command=lambda sv=menu_item: main.open_html(sv))

    def recent_menu_update_side(self, config, main):
        for menu_item in config:
            self.menu_recent_side.add_command(label=menu_item, command=lambda sv=menu_item: main.open_html(sv))

    def remove_config(self):
        self.menu_recent_config.delete(2)

    def remove_report(self):
        self.menu_recent_report.delete(2)

    def remove_side(self):
        self.menu_recent_report.delete(2)

class StatusBar(tk.Frame):
    def __init__(self, main):
        tk.Frame.__init__(self, main, bd=1, relief=tk.SUNKEN)
        self.pack(side=tk.BOTTOM, fill=tk.X)
        internal_frame = tk.Frame(self)
        internal_frame.grid(column=0, row=0, sticky='wens')
        internal_frame.columnconfigure(0, weight=1)
        internal_frame.rowconfigure(0, weight=0)
        self.responsible = tk.StringVar()
        self.msg = tk.StringVar()
        self._timeout = True
        self._list = []
        self._timeoutDefault = 3000
        self._timeoutValue = 3000
        self.list_mode = 0  # 0 = cyclic, 1 = pop
        self._list_index = 0
        self.msg.set('Busload Calc 2.1')
        self._jumpNext = False
        self._main = main
        self.msg_color = tk.StringVar()
        self.msg_color.set('black')
        tk.Label(internal_frame, text='Responsible').grid(row=0, column=0, padx=(10, 5), sticky='e')
        tk.Entry(internal_frame, width=25, textvariable=self.responsible).grid(row=0, column=1, padx=(0, 10),
                                                                               sticky='e')
        tk.Label(internal_frame, text='Hint:').grid(row=0, column=2, padx=5, sticky='e')
        tk.Label(internal_frame, textvariable=self.msg, fg=self.msg_color.get()).grid(row=0, column=3, columnspan=2, sticky='w')
        self.responsible.trace('w', lambda name, index, mode, sv=self.responsible: self.on_modify_entry(sv, main))
        self._call_timer()

    def on_modify_entry(self, sv, main, *args):
        main.init_config['responsible'] = self.responsible.get()

    def set_status_msg(self, text, time=0):
        self.msg.set(text)
        winsound.Beep(800, 50)

    def set_list(self, status_list):
        self._list = status_list
        self._list_index = 0

    def set_timeout(self, time):
        self._timeoutValue = time

    def set_timeout_on(self):
        self._timeout = True

    def set_timeout_off(self):
        self._timeout = False

    def set_time_default(self):
        self._timeoutValue = self._timeoutDefault

    def _call_timer(self):
        if self._timeout:
            if self._list:
                self._call_show_list()
            elif self.msg.get():
                self.msg.set('')

        self._main.after(self._timeoutValue, self._call_timer)

    def _call_show_list(self):
        self.msg_color.set('black')
        if self.list_mode == 0:
            i = len(self._list)
            if self._list_index >= i:
                self._list_index = 0
            self.msg.set(self._list[self._list_index])
            self._list_index += 1
        else:
            if self._list:
                self.msg.set(self._list.pop(0))


import numpy as np
import pandas as pd
import pathlib

def panda_to_sql_types_mapper(value_to_map):
    mapper = {
        "float" : "NUMERIC",
        "int":"INTEGER",
        "object":"VARCHAR"
    }

    for key in mapper:
        if key in value_to_map.name:
            return mapper.get(key)

    raise NameError('No mapping found this type')

#specify data folder
data_path = pathlib.Path('data')

#specify pattern to look in data_path, we use wildcard.
#data_path.glob('*') return a generator
files = data_path.glob('*')

mapping_output_dir = "mapping_classes"
if not pathlib.Path(mapping_output_dir).exists():
    pathlib.Path(mapping_output_dir).mkdir()

for file_path in files:

    df = pd.read_csv(file_path,nrows=100_000,keep_default_na=False)
    df = df.apply(pd.to_numeric, errors='ignore',downcast='integer')
    # schema = pd.io.json.build_table_schema(df)
    custom_schema_for_sql = df.dtypes.to_dict().items()

    core_class_list = []
    for key,value in custom_schema_for_sql:

        core_class_list.append("""{0} = Column({1})""".format(key,panda_to_sql_types_mapper(value)))

    #class generation
    class_name = file_path.stem

    item_types = set([panda_to_sql_types_mapper(_type) for _type in set(map(lambda item: item[1],custom_schema_for_sql))])

    item_types = ",".join(item_types)

    list_header = ["import sqlalchemy",f"from sqlalchemy import Column,{item_types}",f"from {mapping_output_dir} import Base"]

    class_import_header = "\n".join(list_header)

    class_body = ["\nclass {0}(Base):".format(class_name),"__tablename__ = '{0}'".format(class_name)]

    class_body =  class_body + core_class_list

    class_body = "\n\t".join(class_body)

    class_generated =f"""{class_import_header}
        {class_body}
        """
    #write generated classes for mapping, generated classes need to be however changed for specifying Primary Keys and more
    with open(f'{mapping_output_dir}\\class_{class_name}.py','w') as output_class:
        output_class.writelines(class_generated)

    print(f"Class {class_name} generated")

print("Base file generated")
base_def = ["from sqlalchemy.ext.declarative import declarative_base","Base = declarative_base()"]
base_def = "\n".join(base_def)

#write __init__.py
with open(f'{mapping_output_dir}\\__init__.py','w') as output_class:
        output_class.writelines(base_def)


import scrapy
from DiveSiteScraping.items import AquanautDiveClubItems

class OcascubaSpider(scrapy.Spider):
    name = "ocascuba"
    allowed_domains = ["www.ocascuba.org"]
    start_urls = ["http://www.ocascuba.org/links_dive_other.php"]

    def parse(self, response):

        club_items = AquanautDiveClubItems()

        clubs = {
            'MetroWest Dive Club': {
                'club_name': 'MetroWest Dive Club',
                'city': 'Framingham',
                'contact': 'Jack Sargentn,Frances Antonelli,Bill Borek',
                'email': 'president@mwdc.org,vicepresident@mwdc.org,treasurer@mwdc.org',
                'club_url': 'http://www.mwdc.org/index.html',
                'country': 'USA'
            },
            'New England Aquarium Dive Club': {
                'club_name': 'New England Aquarium Dive Club',
                'city': 'Boston, MA',
                'contact': 'Uma Mirani,Greg Hunter',
                'email': 'president@neadc.org,vicepresident@neadc.org',
                'club_url': 'http://www.neadc.org/',
                'country': 'USA'
            },
            'North Shore Divers Club': {
                'club_name': 'North Shore Divers Club',
                'city': 'Revere, MA',
                'contact': None,
                'email': None,
                'club_url': 'https://www.northshorediversclub.com/cgi-sys/suspendedpage.cgi',
                'country': 'USA'
            },
            'North Shore Frogmen': {
                'club_name': 'North Shore Frogmen',
                'city': 'Beverly, MA',
                'contact': 'Dylan Langelier',
                'email': 'officers@northshorefrogmen.com',
                'club_url': 'http://www.northshorefrogmen.com/',
                'country': 'USA'
            },
            'Old Colony Amphibians Club': {
                'club_name': 'Old Colony Amphibians Club',
                'city': 'South Attleboro, MA',
                'contact': None,
                'email': None,
                'club_url': 'http://www.ocascuba.org/index.php',
                'country': 'USA'
            },
            'South Shore Neptunes': {
                'club_name': 'South Shore Neptunes',
                'city': 'Quincy, MA',
                'contact': None,
                'email': 'info@southshoreneptunes.org',
                'club_url': 'http://www.southshoreneptunes.org/index.html',
                'country': 'USA'
            }
        }

        for key in clubs.keys():
            club = clubs[key]

            club_items['url'] = response.url
            club_items['tag'] = None
            club_items['date'] = None
            club_items['club_name'] = club.get('club_name')
            club_items['building'] = None
            club_items['city'] = club.get('location')
            club_items['country'] = club.get('country')
            club_items['club_url'] = club.get('club_url')
            club_items['contact'] = club.get('contact')
            club_items['phone'] = None
            club_items['email'] = club.get('email')

            yield club_items


"""
with driver.session() as session:
    with session.begin_transaction() as tx:
        tx.run(sql)
"""

from neo4j.v1 import GraphDatabase, basic_auth

query = "match p=(n)-[:is_symptom_of]->(d:Disease) " \
        "return p "
insert_sql = "merge(s:Symptom{name:'胸痛'}) " \
            "merge(d:Disease{name:'胸膜炎'})" \
            "merge(s)-[:is_symptom_of]->(d) "

driver = GraphDatabase.driver("bolt://10.68.4.55:7687", auth=basic_auth("neo4j", "neo4j55"))

# 1. 常规调用
# session = driver.session()
# results = session.run(query)
#
# for res in results:
#     print(res["p"])
#
# session.close()

# 2 事务
# 2.1 自动提交
with driver.session() as sess:
    sess.run(query)

# 2.2 显示提交
with driver.session() as sess:
    tx = sess.begin_transaction()
    tx.run(query)
    tx.commit()

# 2.3 函数提交 推荐
def find_symps(tx, name):
    result_list = tx.run(insert_sql)
    for item in result_list:
        print(item["p"])

with driver.session() as sess:
    """ read_transaction  write_transaction """
    sess.read_transaction(find_symps, 'name')

# driver.close()


# coding=utf-8
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.action_chains import ActionChains
from time import gmtime, strftime
import time
import random
import subprocess
import os
import urllib

#definitions
NUMBER_OF_RESULTS_PER_PAGE = 20;
NUMBER_OF_RESULTS_PER_PAGE_FIRST = NUMBER_OF_RESULTS_PER_PAGE - 1;
TIMEOUT_AFTER_VISITING_PAGE = 2;
TIMEOUT_BROWSING_THROUGH_RESULTS = 1;
WAITING_TIME_FOR_PAGE_LOAD = 2;
WAITING_TIME_FOR_VPN_AGENT_START = 35;
WAITING_TIME_FOR_BROWSER_START = 4;
NUMBER_OF_PAGE_RESULTS_CHECKED = 10;
NUMBER_OF_INTERNAL_LINKS = 3;
NUMBER_OF_EXTERNAL_LINKS = 1;
TIME_SPENT_ON_A_LINK_WHILE_BROWSING = 5;

def get_external_id_address():
	external_ip = urllib.urlopen('https://ident.me').read();
	return external_ip;
#creating and opening the log file
logfile = open("./logs/logfile_" + strftime("%Y%m%d%H%M%S", gmtime()) + ".txt","w+");
logfile.write(strftime("%Y-%m-%d %H:%M:%S  ", gmtime()) + "Starting the TorGuard Agent...\n");
print(strftime("%Y-%m-%d %H:%M:%S  ", gmtime()) + "Starting the TorGuard Agent...\n");
#start the TorGuard Agent
proc = subprocess.Popen(['C:\\Program Files (x86)\\VPNetwork LLC\\TorGuard\\TorGuardDesktopQt.exe'], shell=True);
time.sleep(WAITING_TIME_FOR_VPN_AGENT_START);
current_ip_address = get_external_id_address();
logfile.write(strftime("%Y-%m-%d %H:%M:%S  ", gmtime()) + "The current external IP address is:" + current_ip_address + "\n");
print(strftime("%Y-%m-%d %H:%M:%S  ", gmtime()) + "The current external IP address is:" + current_ip_address + "\n");
logfile.write(strftime("%Y-%m-%d %H:%M:%S  ", gmtime()) + "Starting the browser...\n");
#make the google search using mozilla firefox
#profile = webdriver.FirefoxProfile("C:/Users/uidk4225/AppData/Roaming/Mozilla/Firefox/Profiles/i4bd3u2x.default");
profile = webdriver.FirefoxProfile("C:/Users/mihai/AppData/Roaming/Mozilla/Firefox/Profiles/18w4rpcq.default");
driver = webdriver.Firefox(firefox_profile=profile);
url = 'http://www.google.com/#q=';
expression = 'vulcanizari';
target_url = 'timexpres.ro';
driver.get(url + expression + "&num=" + str(NUMBER_OF_RESULTS_PER_PAGE));
time.sleep(WAITING_TIME_FOR_BROWSER_START);

def url_parser( url ):
	start_position = url.find('//');
	end_position = url.find('/', start_position + 2);
	url_extracted = url[start_position + 2: end_position];
	www_exists = url_extracted.find('www.');
	if www_exists !=-1:
		url_extracted = url_extracted[(www_exists + 4):];
	return url_extracted;

def user_browses_internal_links(NUMBER_OF_INTERNAL_LINKS, TIME_SPENT_ON_A_LINK_WHILE_BROWSING, driver):
	number_of_executed_links = 0;
	while (number_of_executed_links < NUMBER_OF_INTERNAL_LINKS):
		all_the_links = driver.find_elements_by_tag_name("a");
		total_number_of_files = len(all_the_links);
		#determine randomly a valid internal link
		invalid = 1;
		while(invalid == 1):
			link_to_visit = random.randint(0, total_number_of_files);
			current_link = all_the_links[link_to_visit].get_attribute("href");
			if url_parser(url) == url_parser(current_link) and valid_link_exceptions(current_link) == 1:
				invalid = 0;
		time.sleep(4);
		all_the_links[link_to_visit].click();
		time.sleep(TIME_SPENT_ON_A_LINK_WHILE_BROWSING);
		driver.back();
		time.sleep(5);
		number_of_executed_links = number_of_executed_links + 1;

def user_browses_external_links(NUMBER_OF_EXTERNAL_LINKS, TIME_SPENT_ON_A_LINK_WHILE_BROWSING, driver):
	number_of_executed_links = 0;
	while (number_of_executed_links < NUMBER_OF_EXTERNAL_LINKS):
		all_the_links = driver.find_elements_by_tag_name("a");
		total_number_of_files = len(all_the_links);
		#determine randomly a valid internal link
		invalid = 1;
		while(invalid == 1):
			link_to_visit = random.randint(0, total_number_of_files);
			current_link = all_the_links[link_to_visit].get_attribute("href");
			if url_parser(url) != url_parser(current_link):
				invalid = 0;
		print("Found external link: " + current_link);
		time.sleep(4);
		all_the_links[link_to_visit].click();
		time.sleep(TIME_SPENT_ON_A_LINK_WHILE_BROWSING);
		number_of_executed_links = number_of_executed_links + 1;

def visit_pages(iteration, target_url):
	#search the next valid result
	while (iteration > 0):
		actions = ActionChains(driver);
		actions.send_keys(u'\ue015');
		actions.perform();
		actions.reset_actions();
		time.sleep(TIMEOUT_BROWSING_THROUGH_RESULTS);
		iteration = iteration-1;
	actions = ActionChains(driver);
	actions.send_keys(u'\ue007');
	actions.perform();
	actions.reset_actions();
	time.sleep(WAITING_TIME_FOR_PAGE_LOAD);
	url = driver.current_url;
	TIME_SPENT_ON_THE_PAGE = 0;
	parsed_url = url_parser( url );
	logfile.write(strftime("%Y-%m-%d %H:%M:%S  ", gmtime()) + "Visiting domain " + parsed_url + "\n");
	print(strftime("%Y-%m-%d %H:%M:%S  ", gmtime()) + "Visiting domain " + parsed_url + "\n");
	if parsed_url == target_url:
		TIME_SPENT_ON_THE_PAGE = 20;
		logfile.write(strftime("%Y-%m-%d %H:%M:%S  ", gmtime()) + "Target domain found\n");
		print(strftime("%Y-%m-%d %H:%M:%S  ", gmtime()) + "Target domain found\n");
		user_browses_internal_links(NUMBER_OF_INTERNAL_LINKS, TIME_SPENT_ON_A_LINK_WHILE_BROWSING, driver);
		user_browses_external_links(NUMBER_OF_EXTERNAL_LINKS, TIME_SPENT_ON_A_LINK_WHILE_BROWSING, driver);
	else:
		TIME_SPENT_ON_THE_PAGE = 1;
	time.sleep(TIME_SPENT_ON_THE_PAGE);
	driver.back();
	return;

logfile.write(strftime("%Y-%m-%d %H:%M:%S  ", gmtime()) + "Starting the search results browsing...\n");
print(strftime("%Y-%m-%d %H:%M:%S  ", gmtime()) + "Starting the search results browsing...\n");
numberOfTabs = 1;
j=1;
while(numberOfTabs<=NUMBER_OF_PAGE_RESULTS_CHECKED):
	i = 1;
	if numberOfTabs == 1:
		NUMBER_OF_RESULTS_USED = NUMBER_OF_RESULTS_PER_PAGE_FIRST;
	else:
		NUMBER_OF_RESULTS_USED = NUMBER_OF_RESULTS_PER_PAGE;
	while( i < NUMBER_OF_RESULTS_USED ):
		visit_pages(i, target_url);
		time.sleep(TIMEOUT_AFTER_VISITING_PAGE);
		i = i + 1;
	numberOfTabs = numberOfTabs + 1;
	actions = ActionChains(driver);
	actions.key_down(Keys.ALT).send_keys(u'\u004E');
	actions.perform();
	actions.reset_actions();
	time.sleep(5);

logfile.write(strftime("%Y-%m-%d %H:%M:%S  ", gmtime()) + "Ending session...\n");
print(strftime("%Y-%m-%d %H:%M:%S  ", gmtime()) + "Ending session...\n");
time.sleep(30);
logfile.write(strftime("%Y-%m-%d %H:%M:%S  ", gmtime()) + "Closing the browser...\n");
print(strftime("%Y-%m-%d %H:%M:%S  ", gmtime()) + "Closing the browser...\n");
driver.close();
logfile.write(strftime("%Y-%m-%d %H:%M:%S  ", gmtime()) + "Closing TorGuard...\n");
print(strftime("%Y-%m-%d %H:%M:%S  ", gmtime()) + "Closing TorGuard...\n");
os.system("TASKKILL /F /IM TorGuardDesktopQt.exe");
logfile.write(strftime("%Y-%m-%d %H:%M:%S  ", gmtime()) + "Closing the logfile...\n");
print(strftime("%Y-%m-%d %H:%M:%S  ", gmtime()) + "Closing the logfile...\n");
logfile.close();