import keras
import random
import numpy as np

import tensorflow as tf
from keras.layers import Dense, Input, Flatten, BatchNormalization,Dropout
from keras.optimizers import Adam
import tensorflow.keras.initializers as init
from collections import namedtuple

from utils_global import remove_illegal
import agents.non_rl.rule_based_agent as rule_based_agent
import envs.mydoudizhu as env
import utils.logger_hypernetwork as logger
from utils_global import set_global_seed, tournament

Transition = namedtuple('Transition', ['state', 'action', 'reward', 'next_state', 'done', 'legal_actions'])

class Agent():

    def __init__(self,
                 epochs,
                 mini_batch_size,
                 learning_rate,
                 lamBda,
                 decay_rate,
                 weights_init,
                 pretraining_steps,
                 batch_size,
                 kl_diversity,
                 cosine_diversity,
                 path,
                 row,
                 config,
                 state_shape):

        discount_factor=0.99
        batch_size=1
        state_shape=None
        decay_steps=20
        decay_rate=0.99998
        gamma = 0.95
        evaluate_num = 50
        evaluate_every = 100
        training_steps = 5000
        memory_length = 10000
        seed = 42

        self.discount_factor = discount_factor
        self.batch_size = 1
        self.action_num = 309
        self.train_every = 1
        self.state_shape = state_shape
        self.config = config

        self.epochs = epochs
        self.mini_batch_size = mini_batch_size
        self.learning_rate = learning_rate
        self.lamBda = lamBda
        self.decay_rate = decay_rate
        self.weights_init = weights_init
        self.pretraining_steps = pretraining_steps
        self.batch_size = batch_size
        self.kl_diversity = kl_diversity
        self.cosine_diversity = cosine_diversity
        self.path = path
        self.row = row

        self.seed = seed
        self.input_noise_size = 10
        self.gamma = gamma
        self.training_steps = training_steps
        self.memory_length = memory_length
        self.epochs = epochs
        self.mini_batch_size = mini_batch_size
        self.decay_steps = decay_steps
        self.decay_rate = decay_rate
        self.evaluate_num = evaluate_num
        self.evaluate_every = evaluate_every
        self.state_shape = state_shape

        self.lr_schedule = tf.keras.optimizers.schedules.ExponentialDecay(self.learning_rate, self.decay_steps, self.decay_rate)
        self.optimizer = tf.keras.optimizers.Adam(learning_rate=self.lr_schedule)
        self.critic = self.create_critic(1, self.state_shape)
        self.actor = self.create_actor(self.action_num, self.state_shape)
        self.env = env.DoudizhuEnv(self.config, self.state_shape)
        self.eval_env = env.DoudizhuEnv(self.config, self.state_shape)
        self.rule_based_agent = rule_based_agent.DouDizhuRuleAgentV1(action_num=self.eval_env.action_num)
        self.hypernetwork = Hypernetwork(self.input_noise_size, self.env.action_num, self.seed)
        self.logger = logger.Logger(self.log_dir_random,self.row)

        self.total_t = 0
        self.zero_fixer = 1e-9
        self.scores, self.average = [], []

    def step(self, state):

        A = self.predict(state['obs'])
        A = remove_illegal(A, state['legal_actions'])
        action = np.random.choice(np.arange(len(A)), p=A)
        return action

    def eval_step(self, state):

        prediction = self.actor(np.expand_dims(state['obs'], 0))[0]
        probs = remove_illegal(np.exp(prediction), state['legal_actions'])
        best_action = np.argmax(probs)
        return best_action, probs

    def predict(self, state):

        prediction = self.actor(np.expand_dims(state,0))[0].numpy()
        return prediction

    def save_to_memory(self, ts, thread):

        (state, action, reward, next_state, done) = tuple(ts)
        transition = Transition(state['obs'], action, reward, next_state['obs'], done, state['legal_actions'])
        self.scores[thread].append(reward)
        self.average[thread].append(sum(self.scores[thread][-50:]) / len(self.scores[thread][-50:]))
        self.memory[thread].append(transition)

    def clear_memory(self):

        self.memory = [[] for _ in range(self.batch_size)]
        self.scores = [[] for _ in range(self.batch_size)]
        self.average = [[] for _ in range(self.batch_size)]

    def train_hypernetwork(self):

        # Before the training loop is entered, a first set of workers needs to be generated. Otherwise the loop for training
        # with tf.GradientTape() can't track the gradients
        z = np.random.uniform(low = -1, high = 1, size = [self.batch_size,10])
        w1, w2, w3, w4, w5, w6 = self.hypernetwork(z,self.batch_size)

        # Reshape it for actor and critic
        weights_actor = tf.concat(concat_dim=1, values=[tf.reshape(w1,(self.batch_size,-1)), tf.reshape(w2,(self.batch_size,-1)),tf.reshape(w3,(self.batch_size,-1))])
        weights_critic = tf.concat(concat_dim=1, values=[tf.reshape(w4,(self.batch_size,-1)), tf.reshape(w5,(self.batch_size,-1)),tf.reshape(w6,(self.batch_size,-1))])

        # Start the actual hypernetwork training loop
        for episode in range(self.training_steps):

            # In the beginning always clear the memory and the score
            self.clear_memory()
            self.score = 0

            # Play a game for ever generated worker
            for thread in range(self.batch_size):

                self.set_weights(weights_actor, weights_critic, thread)
                self.play_game(thread)

            # Now train hypernetwork for each worker for predefined number of epochs
            for e in range(self.epochs):

                with tf.GradientTape() as tape:

                    # In the beginning of the gradient, the accuracy loss is set to zero and new weights generated
                    # Also make new lists for the cosine calculation of the probabilites
                    self.cosine_probs = [[] for _ in range(self.batch_size)]
                    self.loss_acc = 0
                    z = np.random.uniform(low = -1, high = 1, size = [self.batch_size,10])
                    w1, w2, w3, w4, w5, w6 = self.hypernetwork(z,self.batch_size)

                    # Reshape it for actor and critic
                    weights_actor = tf.concat(concat_dim=1, values=[tf.reshape(w1,(self.batch_size,-1)), tf.reshape(w2,(self.batch_size,-1)),tf.reshape(w3,(self.batch_size,-1))])
                    weights_critic = tf.concat(concat_dim=1, values=[tf.reshape(w4,(self.batch_size,-1)), tf.reshape(w5,(self.batch_size,-1)),tf.reshape(w6,(self.batch_size,-1))])

                    # For each worker first the weights are set and then one batch calculated and added to the overall loss
                    for thread in range(self.batch_size):

                        self.set_weights(weights_actor, weights_critic, thread)
                        self.update_weights(thread)

                    # If the number of workers generated is greater than one, diversity is calculated
                    if self.batch_size > 1:

                        # Calculate the cosine similarity of the actions and the diversity of the weights
                        # To do that, first the predictions have to be chosen for the same states
                        self.evaluate_actions(weights_actor, weights_critic)
                        cos = self.cosine_similarity_actions()
                        dvd = self.kernel_similarity()

                        # It is checked, which diversity shall be calculated
                        if self.kernel_diversity:
                            self.loss_div = dvd * self.lamBda
                        elif self.cosine_diversity:
                            self.loss_div = cos * self.lamBda
                        else:
                            self.loss_div = tf.constant(0.)

                        # And the overall loss is:
                        loss = self.loss_acc + self.loss_div

                    # Otherwise the diversity loss term is set to zero
                    else:
                        self.loss_div = tf.constant(0.)
                        loss = self.loss_acc
                        kl, cos = tf.constant(0.), tf.constant(0.)

                    # Finally, the hypernetwork is updated
                    grads = tape.gradient(loss, self.hypernetwork.trainable_weights)
                    self.optimizer.apply_gradients(zip(grads, self.hypernetwork.trainable_weights))

            # Evaluate the performance. Play with random agents.
            if episode % self.evaluate_every == 0:

                self.eval_env.set_agents([self, self.rule_based_agent, self.rule_based_agent])

                self.logger.log_performance(episode, tournament(self.eval_env, self.evaluate_num, self)[0],\
                    self.history_actor, self.history_critic, self.optimizer._decayed_lr(tf.float32).numpy(), self.actions, self.predictions)

    def evaluate_actions(self, weights_actor, weights_critic):

        idx = np.random.randint(0,self.batch_size)
        states = self.memory[idx][0][0:10]

        for num in range(self.batch_size):

            self.set_weights(weights_actor, weights_critic, num)
            predictions = self.actor(states)
            self.cosine_probs[num] = predictions

    def play_game(self, thread):

        self.env.set_agents([self, self.rule_based_agent, self.rule_based_agent])
        length = 0
        while length < self.memory_length:
            trajectories, _ = self.env.run(is_training=True)
            for ts in trajectories[0]:
                self.save_to_memory(ts, thread)
                length += 1

    def update_weights(self, thread):

        self.states, self.actions, self.rewards, self.next_states, self.dones, self.legal_actions = zip(*self.memory[thread][0:self.memory_length])
        self.rewards = self.discounted_rewards(self.rewards)

        self.states = np.stack(self.states, axis=0)
        self.actions = np.stack(self.actions, axis=0)
        self.rewards = np.stack(self.rewards, axis=0)
        self.next_states = np.stack(self.next_states, axis=0)
        self.dones = np.stack(self.dones, axis=0)

        index = np.arange(len(self.rewards))
        np.random.shuffle(index)
        step_size = len(self.rewards)// self.mini_batch_size

        for start in range(0,len(self.rewards), step_size):

            end = start + step_size
            idx = index[start:end]

            states = self.states[idx]
            actions = self.actions[idx]
            rewards = self.rewards[idx]
            next_state = self.next_states[idx]
            done = self.dones[idx]

            self.values = self.critic(states)
            values_next = self.critic(next_state)
            self.loss_critic = tf.math.reduce_mean(tf.math.square(self.values-rewards))
            gamma = 0.95
            advantages = rewards - tf.reshape(self.values,-1) + gamma*tf.reshape(values_next, -1)*np.invert(done).astype(np.float32)

            self.probs = self.actor(states)

            entropy_coeff = 0.1
            z0 = tf.reduce_sum(self.probs, axis = 1)
            p0 = self.probs / tf.reshape(z0, (-1,1))
            entropy = tf.reduce_sum(p0 * (tf.math.log(p0 + self.zero_fixer)), axis=-1)
            mean_entropy = tf.reduce_mean(entropy)
            self.entropy_loss =  mean_entropy * entropy_coeff

            action_one_hot = tf.one_hot(actions, 309, on_value=1,off_value=0).numpy().astype(np.float32)
            actions_prob = tf.reduce_sum(tf.multiply(self.probs,action_one_hot), axis=1)
            action_log_probs =  tf.math.log(actions_prob+self.zero_fixer)

            actor_loss1 = action_log_probs * advantages
            actor_loss1 = - tf.reduce_mean(actor_loss1)

            self.loss_actor = actor_loss1 + self.entropy_loss

            # Total loss
            self.loss_acc += self.loss_actor + self.loss_critic * 0.5

        self.history_actor = self.loss_actor
        self.history_critic =  self.loss_critic
        self.actions = actions
        self.predictions  = tf.argmax(self.probs, axis=1).numpy()

    def cosine_similarity_actions(self):

        cosine_actions = np.zeros([self.batch_size, self.batch_size])

        for i in range(self.batch_size):
            for j in range(self.batch_size):
                score = 0
                v1, v2 = self.cosine_probs[i], self.cosine_probs[j]

                for x in range(10):
                    score += self.cos_between(v1[x],v2[x])

                cosine_actions[i][j] = score
                cosine_actions[j][i] = cosine_actions[i][j]

        return tf.reduce_sum(cosine_actions)

    def cos_between(self, v1, v2):

        v1_u = v1 / tf.norm(v1)
        v2_u = v2 / tf.norm(v2)

        return tf.tensordot(v1_u, v2_u, axes=1)

    def kernel_similarity():

        pass

    def set_weights(self, weights_actor, weights_critic, num):

        # This part is used to set the weights for the Actor
        last_used = 0
        weights = weights_actor[num]
        for i in range(len(self.actor.layers)):
            if 'conv' in self.actor.layers[i].name or  'dense' in self.actor.layers[i].name:
                weights_shape = self.actor.layers[i].kernel.shape
                no_of_weights = tf.reduce_prod(weights_shape)
                new_weights = tf.reshape(weights[last_used:last_used+no_of_weights], weights_shape)
                self.actor.layers[i].kernel = new_weights
                last_used += no_of_weights

                if self.actor.layers[i].use_bias:
                    weights_shape = self.actor.layers[i].bias.shape
                    no_of_weights = tf.reduce_prod(weights_shape)
                    new_weights = tf.reshape(weights[last_used:last_used+no_of_weights], weights_shape)
                    self.actor.layers[i].bias = new_weights
                    last_used += no_of_weights

        # This part is the same, but for the Critic
        last_used = 0
        weights = weights_critic[num]
        for i in range(len(self.critic.layers)):

            if 'conv' in self.critic.layers[i].name or  'dense' in self.critic.layers[i].name:
                weights_shape = self.critic.layers[i].kernel.shape
                no_of_weights = tf.reduce_prod(weights_shape)
                new_weights = tf.reshape(weights[last_used:last_used+no_of_weights], weights_shape)
                self.critic.layers[i].kernel = new_weights
                last_used += no_of_weights

                if self.critic.layers[i].use_bias:
                    weights_shape = self.critic.layers[i].bias.shape
                    no_of_weights = tf.reduce_prod(weights_shape)
                    new_weights = tf.reshape(weights[last_used:last_used+no_of_weights], weights_shape)
                    self.critic.layers[i].bias = new_weights
                    last_used += no_of_weights

    def discounted_rewards(self, reward):

        gamma = 0.95  # discount rate
        running_add = 0
        discounted_r = np.zeros_like(reward, dtype='float64')
        for i in reversed(range(0,len(reward))):
            if reward[i] != 0: # reset the sum, since this was a game boundary (pong specific!)
                running_add = 0
            running_add = running_add * gamma + reward[i]
            discounted_r[i] = running_add

        discounted_r -= np.mean(discounted_r) # normalizing the result
        discounted_r /= np.std(discounted_r) + self.zero_fixer
        return discounted_r

    def create_actor(self, action_num, state_shape):

        input_x = Input(state_shape)
        x = Flatten()(input_x)
        x = Dense(512,activation='relu')(x)
        x = Dense(512,activation='relu')(x)
        output = Dense(action_num, activation='softmax')(x)
        network = keras.Model(inputs = input_x, outputs=output)

        return network

    def create_critic(self, action_num, state_shape):

        input_x = Input(state_shape)
        x = Flatten()(input_x)
        x = Dense(512,activation='relu')(x)
        x = Dense(512,activation='relu')(x)
        output = Dense(action_num)(x)
        network = keras.Model(inputs = input_x, outputs=output)

        return network

class Hypernetwork(keras.Model):

    def __init__(self, input_size, output_size, seed):
        super().__init__()

        self.input_size = input_size
        self.output_size = output_size
        self.seed = seed

        x = (512/2 + 512/2 +309/3 + 512/2 + 512/2 + 1)*15

        kernel_init = tf.keras.initializers.glorot_uniform(seed = self.seed)
        bias_init = tf.keras.initializers.constant(0)

        self.dense_1 = Dense(300, activation="elu", kernel_initializer=kernel_init, bias_initializer=bias_init)
        self.dense_2 = Dense(x, activation="elu", kernel_initializer=kernel_init, bias_initializer=bias_init)

        self.dense_w1_1 = Dense(300, activation="elu", kernel_initializer=kernel_init, bias_initializer=bias_init)
        self.dense_w1_2 = Dense(601*2, activation="elu", kernel_initializer=kernel_init, bias_initializer=bias_init)

        self.dense_w2_1 = Dense(300, activation="elu", kernel_initializer=kernel_init, bias_initializer=bias_init)
        self.dense_w2_2 = Dense(513*2, activation="elu", kernel_initializer=kernel_init, bias_initializer=bias_init)

        self.dense_w3_1 = Dense(300, activation="elu", kernel_initializer=kernel_init, bias_initializer=bias_init)
        self.dense_w3_2 = Dense(513*3, activation="elu", kernel_initializer=kernel_init, bias_initializer=bias_init)

        self.dense_w4_1 = Dense(300, activation="elu", kernel_initializer=kernel_init, bias_initializer=bias_init)
        self.dense_w4_2 = Dense(601*2, activation="elu", kernel_initializer=kernel_init, bias_initializer=bias_init)

        self.dense_w5_1 = Dense(300, activation="elu", kernel_initializer=kernel_init, bias_initializer=bias_init)
        self.dense_w5_2 = Dense(513*2, activation="elu", kernel_initializer=kernel_init, bias_initializer=bias_init)

        self.dense_w6_1 = Dense(300, activation="elu", kernel_initializer=kernel_init, bias_initializer=bias_init)
        self.dense_w6_2 = Dense(513, activation="elu", kernel_initializer=kernel_init, bias_initializer=bias_init)

    def call(self, inputs, batch_size):

        layer_1 = 256 #512/2
        layer_2 = 256 #512/2
        layer_3 = 103 #309/3
        layer_4 = 1

        embedding = 15

        index1 = layer_1*embedding
        index2 = index1 +layer_2*embedding
        index3 = index2 + layer_3*embedding
        index4 = index3 + layer_1*embedding
        index5 = index4 + layer_2*embedding
        #index6 = index5 + layer_4*embedding

        x = self.dense_1(inputs)
        x = self.dense_2(x)

        input_w1 = x[:,:index1]
        input_w1 = tf.reshape(input_w1,(batch_size,layer_1,-1))
        w1 = self.dense_w1_1(input_w1)
        w1 = self.dense_w1_2(w1)

        input_w2 = x[:,index1:index2]
        input_w2 = tf.reshape(input_w2,(batch_size,layer_2,-1))
        w2 = self.dense_w2_1(input_w2)
        w2 = self.dense_w2_2(w2)

        input_w3 = x[:,index2:index3]
        input_w3 = tf.reshape(input_w3,(batch_size,layer_3,-1))
        w3 = self.dense_w3_1(input_w3)
        w3 = self.dense_w3_2(w3)

        input_w4 = x[:,index3:index4]
        input_w4 = tf.reshape(input_w4,(batch_size,layer_1,-1))
        w4 = self.dense_w4_1(input_w4)
        w4 = self.dense_w4_2(w4)

        input_w5 = x[:,index4:index5]
        input_w5 = tf.reshape(input_w5,(batch_size,layer_2,-1))
        w5 = self.dense_w5_1(input_w5)
        w5 = self.dense_w5_2(w5)

        input_w6 = x[:,index5]
        input_w6 = tf.reshape(input_w6,(batch_size,layer_4,-1))
        w6 = self.dense_w6_1(input_w6)
        w6 = self.dense_w6_2(w6)

        return w1, w2, w3, w4, w5, w6


from django.shortcuts import render,get_object_or_404
from django.core.paginator import Paginator
from .models import Listings

# Create your views here.
def index(request):
	listing = Listings.objects.order_by('-list_date').filter(is_published=True)
	paginator = Paginator(listing,6)
	page = request.GET.get('page')
	paged_listings = paginator.get_page(page)

	context = { 'listing': paged_listings }
	return render(request,'listings/listings.html',context)

def listing(request,list_id):

	list_fetch = get_object_or_404(Listings,pk=list_id)

	context={
		'list':list_fetch
	}
	return render(request,'listings/listing.html',context)

def search(request):

	return render(request,'listings/search.html')


from datetime import datetime

import pytest
from freezegun import freeze_time

from hr_core.constants.enums import AttendanceStatusType
from hr_core.models.attendance import Attendance
from hr_core.models.employee import Employee
from hr_core.storages.storage_implementation import StorageImplementation

class TestCreateAndGetClockoutAttendance:
    @pytest.mark.django_db
    @freeze_time(str(datetime.now()))
    def test_create_and_get_clockout_attendance(self, create_employees):
        # Arrange
        sql_storage = StorageImplementation()
        employee_obj = Employee.objects.get(employee_id="1")
        Attendance.objects.create(
            employee=employee_obj,
            clock_in_datetime=datetime.now(),
            status=AttendanceStatusType.PRESENT.value
        )

        # Act
        attendance_dto = sql_storage.create_and_get_clockout_attendance(employee_id="1")
        attendance_obj = Attendance.objects.get(id=attendance_dto.attendance_id)

        # Assert
        assert attendance_obj.clock_out_datetime == datetime.now()
        assert attendance_obj.employee.employee_id == "1"
        assert attendance_dto.attendance_id == attendance_obj.id
        assert attendance_dto.clock_out_date_time == attendance_obj.clock_out_datetime


from unittest.mock import patch

from simba_ml.prediction.logging import wandb_logger
from simba_ml.prediction.logging import logging_config

class Mock:
    """Magic mock class for testing purposes."""

    def __init__(self, *args, **kwargs):
        self.calls = [("__init__", args, kwargs)]

    def __getattr__(self, name):
        def method(*args, **kwargs):
            self.calls.append((name, args, kwargs))

        return method

@patch("simba_ml.prediction.logging.wandb_logger.wandb", Mock())
def test_wandb_logger():
    with patch(
        "simba_ml.prediction.logging.wandb_logger.wandb",
        Mock(),
    ):
        # pylint: disable=import-outside-toplevel
        from simba_ml.prediction.logging.wandb_logger import wandb

        config = logging_config.LoggingConfig(project="simba-ml", entity="tests")
        logger = wandb_logger.WandbLogger(config)
        logger.login()
        logger.init(12, 34, name="NAME")
        logger.log({"loss": 0.5})
        logger.log({"ratio": 1.0})

        actual = wandb.calls  # pylint: disable=no-member
        assert actual == [
            ("__init__", (), {}),
            ("login", (), {}),
            (
                "init",
                (12, 34),
                {"name": "NAME", "project": "simba-ml", "entity": "tests"},
            ),
            ("log", ({"loss": 0.5},), {}),
            ("log", ({"ratio": 1.0},), {}),
        ]


# This Python 3 environment comes with many helpful analytics libraries installed
# It is defined by the kaggle/python docker image: https://github.com/kaggle/docker-python
# For example, here's several helpful packages to load in

import numpy as np # linear algebra
import pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)

# Input data files are available in the "../input/" directory.
# For example, running this (by clicking run or pressing Shift+Enter) will list the files in the input directory

import os
print(os.listdir("../input"))

# Any results you write to the current directory are saved as output.
# import numpy library
import numpy as np

# numpy array
array = [[1,2,3],[4,5,6]]
first_array = np.array(array) # 2x3 array
print("Array Type: {}".format(type(first_array))) # type
print("Array Shape: {}".format(np.shape(first_array))) # shape
print(first_array)
# import pytorch library
import torch

# pytorch array
tensor = torch.Tensor(array)
print("Array Type: {}".format(tensor.type)) # type
print("Array Shape: {}".format(tensor.shape)) # shape
print(tensor)
# numpy ones
print("Numpy {}\n".format(np.ones((2,3))))

# pytorch ones
print(torch.ones((2,3)))
# numpy random
print("Numpy {}\n".format(np.random.rand(2,3)))

# pytorch random
print(torch.rand(2,3))
# random numpy array
array = np.random.rand(2,2)
print("{} {}\n".format(type(array),array))

# from numpy to tensor
from_numpy_to_tensor = torch.from_numpy(array)
print("{}\n".format(from_numpy_to_tensor))

# from tensor to numpy
tensor = from_numpy_to_tensor
from_tensor_to_numpy = tensor.numpy()
print("{} {}\n".format(type(from_tensor_to_numpy),from_tensor_to_numpy))
# create tensor
tensor = torch.ones(3,3)
print("\n",tensor)

# Resize
print("{}{}\n".format(tensor.view(9).shape,tensor.view(9)))

# Addition
print("Addition: {}\n".format(torch.add(tensor,tensor)))

# Subtraction
print("Subtraction: {}\n".format(tensor.sub(tensor)))

# Element wise multiplication
print("Element wise multiplication: {}\n".format(torch.mul(tensor,tensor)))

# Element wise division
print("Element wise division: {}\n".format(torch.div(tensor,tensor)))

# Mean
tensor = torch.Tensor([1,2,3,4,5])
print("Mean: {}".format(tensor.mean()))

# Standart deviation (std)
print("std: {}".format(tensor.std()))
# import variable from pytorch library
from torch.autograd import Variable

# define variable
var = Variable(torch.ones(3), requires_grad = True)
var
# lets make basic backward propagation
# we have an equation that is y = x^2
array = [2,4]
tensor = torch.Tensor(array)
x = Variable(tensor, requires_grad = True)
y = x**2
print(" y =  ",y)

# recap o equation o = 1/2*sum(y)
o = (1/2)*sum(y)
print(" o =  ",o)

# backward
o.backward() # calculates gradients

# As I defined, variables accumulates gradients. In this part there is only one variable x.
# Therefore variable x should be have gradients
# Lets look at gradients with x.grad
print("gradients: ",x.grad)
# As a car company we collect this data from previous selling
# lets define car prices
car_prices_array = [3,4,5,6,7,8,9]
car_price_np = np.array(car_prices_array,dtype=np.float32)
car_price_np = car_price_np.reshape(-1,1)
car_price_tensor = Variable(torch.from_numpy(car_price_np))

# lets define number of car sell
number_of_car_sell_array = [ 7.5, 7, 6.5, 6.0, 5.5, 5.0, 4.5]
number_of_car_sell_np = np.array(number_of_car_sell_array,dtype=np.float32)
number_of_car_sell_np = number_of_car_sell_np.reshape(-1,1)
number_of_car_sell_tensor = Variable(torch.from_numpy(number_of_car_sell_np))

# lets visualize our data
import matplotlib.pyplot as plt
plt.scatter(car_prices_array,number_of_car_sell_array)
plt.xlabel("Car Price $")
plt.ylabel("Number of Car Sell")
plt.title("Car Price$ VS Number of Car Sell")
plt.show()
# Linear Regression with Pytorch

# libraries
import torch
from torch.autograd import Variable
import torch.nn as nn
import warnings
warnings.filterwarnings("ignore")

# create class
class LinearRegression(nn.Module):
    def __init__(self,input_size,output_size):
        # super function. It inherits from nn.Module and we can access everythink in nn.Module
        super(LinearRegression,self).__init__()
        # Linear function.
        self.linear = nn.Linear(input_dim,output_dim)

    def forward(self,x):
        return self.linear(x)

# define model
input_dim = 1
output_dim = 1
model = LinearRegression(input_dim,output_dim) # input and output size are 1

# MSE
mse = nn.MSELoss()

# Optimization (find parameters that minimize error)
learning_rate = 0.02   # how fast we reach best parameters
optimizer = torch.optim.SGD(model.parameters(),lr = learning_rate)

# train model
loss_list = []
iteration_number = 1001
for iteration in range(iteration_number):

    # optimization
    optimizer.zero_grad()

    # Forward to get output
    results = model(car_price_tensor)

    # Calculate Loss
    loss = mse(results, number_of_car_sell_tensor)

    # backward propagation
    loss.backward()

    # Updating parameters
    optimizer.step()

    # store loss
    loss_list.append(loss.data)

    # print loss
    if(iteration % 50 == 0):
        print('epoch {}, loss {}'.format(iteration, loss.data))

plt.plot(range(iteration_number),loss_list)
plt.xlabel("Number of Iterations")
plt.ylabel("Loss")
plt.show()
# predict our car price
predicted = model(car_price_tensor).data.numpy()
plt.scatter(car_prices_array,number_of_car_sell_array,label = "original data",color ="red")
plt.scatter(car_prices_array,predicted,label = "predicted data",color ="blue")

# predict if car price is 10$, what will be the number of car sell
#predicted_10 = model(torch.from_numpy(np.array([10]))).data.numpy()
#plt.scatter(10,predicted_10.data,label = "car price 10$",color ="green")
plt.legend()
plt.xlabel("Car Price $")
plt.ylabel("Number of Car Sell")
plt.title("Original vs Predicted values")
plt.show()
# Import Libraries
import torch
import torch.nn as nn
import torchvision.transforms as transforms
from torch.autograd import Variable
import pandas as pd
from sklearn.model_selection import train_test_split
# Prepare Dataset
# load data
train = pd.read_csv(r"../input/train.csv",dtype = np.float32)

# split data into features(pixels) and labels(numbers from 0 to 9)
targets_numpy = train.label.values
features_numpy = train.loc[:,train.columns != "label"].values/255 # normalization

# train test split. Size of train data is 80% and size of test data is 20%.
features_train, features_test, targets_train, targets_test = train_test_split(features_numpy,
                                                                             targets_numpy,
                                                                             test_size = 0.2,
                                                                             random_state = 42)

# create feature and targets tensor for train set. As you remember we need variable to accumulate gradients. Therefore first we create tensor, then we will create variable
featuresTrain = torch.from_numpy(features_train)
targetsTrain = torch.from_numpy(targets_train).type(torch.LongTensor) # data type is long

# create feature and targets tensor for test set.
featuresTest = torch.from_numpy(features_test)
targetsTest = torch.from_numpy(targets_test).type(torch.LongTensor) # data type is long

# batch_size, epoch and iteration
batch_size = 100
n_iters = 10000
num_epochs = n_iters / (len(features_train) / batch_size)
num_epochs = int(num_epochs)

# Pytorch train and test sets
train = torch.utils.data.TensorDataset(featuresTrain,targetsTrain)
test = torch.utils.data.TensorDataset(featuresTest,targetsTest)

# data loader
train_loader = torch.utils.data.DataLoader(train, batch_size = batch_size, shuffle = False)
test_loader = torch.utils.data.DataLoader(test, batch_size = batch_size, shuffle = False)

# visualize one of the images in data set
plt.imshow(features_numpy[10].reshape(28,28))
plt.axis("off")
plt.title(str(targets_numpy[10]))
plt.savefig('graph.png')
plt.show()
# Create Logistic Regression Model
class LogisticRegressionModel(nn.Module):
    def __init__(self, input_dim, output_dim):
        super(LogisticRegressionModel, self).__init__()
        # Linear part
        self.linear = nn.Linear(input_dim, output_dim)
        # There should be logistic function right?
        # However logistic function in pytorch is in loss function
        # So actually we do not forget to put it, it is only at next parts

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

# Instantiate Model Class
input_dim = 28*28 # size of image px*px
output_dim = 10  # labels 0,1,2,3,4,5,6,7,8,9

# create logistic regression model
model = LogisticRegressionModel(input_dim, output_dim)

# Cross Entropy Loss
error = nn.CrossEntropyLoss()

# SGD Optimizer
learning_rate = 0.001
optimizer = torch.optim.SGD(model.parameters(), lr=learning_rate)
# Traning the Model
count = 0
loss_list = []
iteration_list = []
for epoch in range(num_epochs):
    for i, (images, labels) in enumerate(train_loader):

        # Define variables
        train = Variable(images.view(-1, 28*28))
        labels = Variable(labels)

        # Clear gradients
        optimizer.zero_grad()

        # Forward propagation
        outputs = model(train)

        # Calculate softmax and cross entropy loss
        loss = error(outputs, labels)

        # Calculate gradients
        loss.backward()

        # Update parameters
        optimizer.step()

        count += 1

        # Prediction
        if count % 50 == 0:
            # Calculate Accuracy
            correct = 0
            total = 0
            # Predict test dataset
            for images, labels in test_loader:
                test = Variable(images.view(-1, 28*28))

                # Forward propagation
                outputs = model(test)

                # Get predictions from the maximum value
                predicted = torch.max(outputs.data, 1)[1]

                # Total number of labels
                total += len(labels)

                # Total correct predictions
                correct += (predicted == labels).sum()

            accuracy = 100 * correct / float(total)

            # store loss and iteration
            loss_list.append(loss.data)
            iteration_list.append(count)
        if count % 500 == 0:
            # Print Loss
            print('Iteration: {}  Loss: {}  Accuracy: {}%'.format(count, loss.data, accuracy))
# visualization
plt.plot(iteration_list,loss_list)
plt.xlabel("Number of iteration")
plt.ylabel("Loss")
plt.title("Logistic Regression: Loss vs Number of iteration")
plt.show()
# Import Libraries
import torch
import torch.nn as nn
import torchvision.transforms as transforms
from torch.autograd import Variable
# Create ANN Model
class ANNModel(nn.Module):
    def __init__(self, input_dim, hidden_dim, output_dim):
        super(ANNModel, self).__init__()
        # Linear function 1: 784 --> 100
        self.fc1 = nn.Linear(input_dim, hidden_dim)
        # Non-linearity 1
        self.relu1 = nn.ReLU()

        # Linear function 2: 100 --> 100
        self.fc2 = nn.Linear(hidden_dim, hidden_dim)
        # Non-linearity 2
        self.tanh2 = nn.Tanh()

        # Linear function 3: 100 --> 100
        self.fc3 = nn.Linear(hidden_dim, hidden_dim)
        # Non-linearity 3
        self.elu3 = nn.ELU()

        # Linear function 4 (readout): 100 --> 10
        self.fc4 = nn.Linear(hidden_dim, output_dim)

    def forward(self, x):
        # Linear function 1
        out = self.fc1(x)
        # Non-linearity 1
        out = self.relu1(out)

        # Linear function 2
        out = self.fc2(out)
        # Non-linearity 2
        out = self.tanh2(out)

        # Linear function 2
        out = self.fc3(out)
        # Non-linearity 2
        out = self.elu3(out)

        # Linear function 4 (readout)
        out = self.fc4(out)
        return out

# instantiate ANN
input_dim = 28*28
hidden_dim = 150 #hidden layer dim is one of the hyper parameter and it should be chosen and tuned. For now I only say 150 there is no reason.
output_dim = 10

# Create ANN
model = ANNModel(input_dim, hidden_dim, output_dim)

# Cross Entropy Loss
error = nn.CrossEntropyLoss()

# SGD Optimizer
learning_rate = 0.02
optimizer = torch.optim.SGD(model.parameters(), lr=learning_rate)
# ANN model training
count = 0
loss_list = []
iteration_list = []
accuracy_list = []
for epoch in range(num_epochs):
    for i, (images, labels) in enumerate(train_loader):

        train = Variable(images.view(-1, 28*28))
        labels = Variable(labels)

        # Clear gradients
        optimizer.zero_grad()

        # Forward propagation
        outputs = model(train)

        # Calculate softmax and ross entropy loss
        loss = error(outputs, labels)

        # Calculating gradients
        loss.backward()

        # Update parameters
        optimizer.step()

        count += 1

        if count % 50 == 0:
            # Calculate Accuracy
            correct = 0
            total = 0
            # Predict test dataset
            for images, labels in test_loader:

                test = Variable(images.view(-1, 28*28))

                # Forward propagation
                outputs = model(test)

                # Get predictions from the maximum value
                predicted = torch.max(outputs.data, 1)[1]

                # Total number of labels
                total += len(labels)

                # Total correct predictions
                correct += (predicted == labels).sum()

            accuracy = 100 * correct / float(total)

            # store loss and iteration
            loss_list.append(loss.data)
            iteration_list.append(count)
            accuracy_list.append(accuracy)
            if count % 500 == 0:
                # Print Loss
                print('Iteration: {}  Loss: {}  Accuracy: {} %'.format(count, loss.data[0], accuracy))
# visualization loss
plt.plot(iteration_list,loss_list)
plt.xlabel("Number of iteration")
plt.ylabel("Loss")
plt.title("ANN: Loss vs Number of iteration")
plt.show()

# visualization accuracy
plt.plot(iteration_list,accuracy_list,color = "red")
plt.xlabel("Number of iteration")
plt.ylabel("Accuracy")
plt.title("ANN: Accuracy vs Number of iteration")
plt.show()
# Import Libraries
import torch
import torch.nn as nn
import torchvision.transforms as transforms
from torch.autograd import Variable
# Create CNN Model
class CNNModel(nn.Module):
    def __init__(self):
        super(CNNModel, self).__init__()

        # Convolution 1
        self.cnn1 = nn.Conv2d(in_channels=1, out_channels=16, kernel_size=5, stride=1, padding=0)
        self.relu1 = nn.ReLU()

        # Max pool 1
        self.maxpool1 = nn.MaxPool2d(kernel_size=2)

        # Convolution 2
        self.cnn2 = nn.Conv2d(in_channels=16, out_channels=32, kernel_size=5, stride=1, padding=0)
        self.relu2 = nn.ReLU()

        # Max pool 2
        self.maxpool2 = nn.MaxPool2d(kernel_size=2)

        # Fully connected 1
        self.fc1 = nn.Linear(32 * 4 * 4, 10)

    def forward(self, x):
        # Convolution 1
        out = self.cnn1(x)
        out = self.relu1(out)

        # Max pool 1
        out = self.maxpool1(out)

        # Convolution 2
        out = self.cnn2(out)
        out = self.relu2(out)

        # Max pool 2
        out = self.maxpool2(out)
        out = out.view(out.size(0), -1)

        # Linear function (readout)
        out = self.fc1(out)

        return out

# batch_size, epoch and iteration
batch_size = 100
n_iters = 2500
num_epochs = n_iters / (len(features_train) / batch_size)
num_epochs = int(num_epochs)

# Pytorch train and test sets
train = torch.utils.data.TensorDataset(featuresTrain,targetsTrain)
test = torch.utils.data.TensorDataset(featuresTest,targetsTest)

# data loader
train_loader = torch.utils.data.DataLoader(train, batch_size = batch_size, shuffle = False)
test_loader = torch.utils.data.DataLoader(test, batch_size = batch_size, shuffle = False)

# Create ANN
model = CNNModel()

# Cross Entropy Loss
error = nn.CrossEntropyLoss()

# SGD Optimizer
learning_rate = 0.1
optimizer = torch.optim.SGD(model.parameters(), lr=learning_rate)

# CNN model training
count = 0
loss_list = []
iteration_list = []
accuracy_list = []
for epoch in range(num_epochs):
    for i, (images, labels) in enumerate(train_loader):

        train = Variable(images.view(100,1,28,28))
        labels = Variable(labels)

        # Clear gradients
        optimizer.zero_grad()

        # Forward propagation
        outputs = model(train)

        # Calculate softmax and ross entropy loss
        loss = error(outputs, labels)

        # Calculating gradients
        loss.backward()

        # Update parameters
        optimizer.step()
        count += 1
        if count % 50 == 0:
            # Calculate Accuracy
            correct = 0
            total = 0
            # Iterate through test dataset
            for images, labels in test_loader:

                test = Variable(images.view(100,1,28,28))

                # Forward propagation
                outputs = model(test)

                # Get predictions from the maximum value
                predicted = torch.max(outputs.data, 1)[1]

                # Total number of labels
                total += len(labels)

                correct += (predicted == labels).sum()

            accuracy = 100 * correct / float(total)

            # store loss and iteration
            loss_list.append(loss.data)
            iteration_list.append(count)
            accuracy_list.append(accuracy)
            if count % 500 == 0:
                # Print Loss
                print('Iteration: {}  Loss: {}  Accuracy: {} %'.format(count, loss.data[0], accuracy))
# visualization loss
plt.plot(iteration_list,loss_list)
plt.xlabel("Number of iteration")
plt.ylabel("Loss")
plt.title("CNN: Loss vs Number of iteration")
plt.show()

# visualization accuracy
plt.plot(iteration_list,accuracy_list,color = "red")
plt.xlabel("Number of iteration")
plt.ylabel("Accuracy")
plt.title("CNN: Accuracy vs Number of iteration")
plt.show()


import copy
def rotate90(array) :
    lentgh = len(array)
    result = []
    for _ in range(lentgh) :
        result.append([])
    for i in range(lentgh-1, -1, -1) :
        j = 0
        for c in array[i] :
            result[j].append(c)
            j += 1
    return result

def makeCompArray(lock) :
    N = len(lock)
    T = N*3
    result = [[0 for _ in range(T)] for _ in range(T)]
    for i in range(N,N+N) :
        for j in range(N,N+N) :
            result[i][j] = lock[i-(N)][j-(N)]
    return result

def unlock(key, comp, x, y) :
    result = copy.deepcopy(comp)
    for i in range(x, x + len(key)) :
        for j in range(y, y + len(key)) :
            result[i][j] += key[i-x][j-y]
    return result

def checkIsUnlock(array, N) :
    for i in range(N,N+N) :
        for j in range(N,N+N) :
            if array[i][j] != 1 :
                return False
    return True

def solution(key, lock):
    answer = True
    compArray = makeCompArray(lock)
    for _ in range(4) :
        for i in range(len(lock) -len(key) + 1, len(lock)*2 + 1):
            for j in range(len(lock) -len(key) + 1, len(lock)*2 + 1):
                temp = unlock(key, compArray, i, j)
                answer = checkIsUnlock(temp, len(lock))
                if answer :
                    return answer
        key = rotate90(key)
    return answer

print(solution([[0, 0, 0], [1, 0, 0], [0, 1, 1]],[[1, 1, 1], [1, 1, 0], [1, 0, 1]] ))
# print(solution([[0,0,0,1], [0,0,0,1], [0,0,0,1],[0,0,0,1]],[[0,1,0,0,0],[0,1,0,0,0],[0,1,0,0,0],[0,1,0,0,0],[0,1,0,0,0] ]  ) )
# print(rotate90([[0, 0, 0], [1, 0, 0], [0, 1, 1]]))
# print(rotate90([[1,2,3], [4,5,6], [7,8,9]]))


from django.shortcuts import render
from eventos.models import Evento
from django.urls import reverse_lazy
from django.views.generic import ListView, CreateView, UpdateView, DeleteView
from eventos.forms import eventoForm
# Create your views here.

def eventos_lista(request):
    evento = Evento.objects.order_by('fecha_inic')
    return render(request, 'eventos/listar.html',{'eventos': evento})

class eventosList(ListView):
    model = Evento
    template_name = 'eventos/listar.html'

class eventoCreate(CreateView):
    model = Evento
    form_class = eventoForm
    template_name = 'eventos/evento_form.html'
    success_url = reverse_lazy('eventos_listar')

class eventoUpdate(UpdateView):
    model = Evento
    form_class = eventoForm
    template_name = 'eventos/evento_form.html'
    success_url = reverse_lazy('eventos_listar')

class eventoDelete(DeleteView):
    model = Evento
    template_name = 'eventos/evento_delete.html'
    success_url = reverse_lazy('eventos_listar')


import cv2
import imutils

img_color = cv2.imread('dogs.jpg', cv2.IMREAD_COLOR)

dst = imutils.translate(img_color, 25, -75)

dst = imutils.rotate(img_color, angle=45, center=(0,0))

dst = imutils.auto_canny(img_color)

cv2.imshow('color', dst)

cv2.waitKey(0)

cv2.destroyAllWindows()


from math import sqrt
# The prime factors of 13195 are 5, 7, 13 and 29.

# What is the largest prime factor of the number 600851475143 ?

num = 600851475143
limit = int(sqrt(num))

def is_prime(n):
    if n <= 3:
        return n > 1
    elif n % 2 == 0 or n % 3 == 0:
        return False

    i = 5

    while i**2 <= n:
        if n % i == 0 or n % (i + 2) == 0:
            return False
        i = i + 6

    return True

result = max(n for n in range(int(sqrt(num))) if is_prime(n) and num % n == 0)

print(f'The result is {result}')


# coding:utf-8
from setuptools import setup,find_packages

PACKAGE = "phone"
NAME = "phone"
DESCRIPTION = "手机号码库"
AUTHOR = "ls0f"
AUTHOR_EMAIL = "admin@lovedboy.com"
URL = "https://github.com/ls0f/phone"
VERSION = '0.4.3'

setup(
    name=NAME,
    version=VERSION,
    description=DESCRIPTION,
    author=AUTHOR,
    author_email=AUTHOR_EMAIL,
    license="BSD",
    url=URL,
    include_package_data = True,
    packages=find_packages(),
    classifiers=[
        'License :: OSI Approved :: MIT License',
        'Programming Language :: Python',
        'Intended Audience :: Developers',
        'Operating System :: OS Independent',
    ],
    zip_safe=False,
)


import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.image as mpimg

cant_ciudades = 24

df_ciudades_distancias = pd.read_excel('TablaCiudades.xlsx')
nombres_ciudades = list(df_ciudades_distancias)
distancias = df_ciudades_distancias.tail(cant_ciudades).to_numpy()
ciudades_posibles = list(range(cant_ciudades))

df_tabla_coordenadas = pd.read_excel('TablaCoordenadas.xlsx', header=None)
lista_coordenadas = df_tabla_coordenadas.values.tolist()

def calcula_distancia_recorrido(cromosoma):  # Devuelve el fitness de un solo cromosoma
    dist_recorrido = 0
    for i in range(cant_ciudades - 1):
        dist_recorrido += distancias[cromosoma[i], cromosoma[i + 1]]

    # Suma tambien la distancia de la ultima ciudad hasta la ciudad de partida
    dist_recorrido += distancias[cromosoma[cant_ciudades - 1], cromosoma[0]]
    return dist_recorrido

def menu():
    for i in range(cant_ciudades):
        print(i, '. ', nombres_ciudades[i])
    recorrido_mvp[0] = int(input("Ingrese la ciudad desde la que quiere empezar: "))

    for i in range(1, 24):
        aux = recorrido_mvp[i - 1]
        recorrido_mvp.append(calc_ciudad_mas_cercana(aux))

def valida_repeticion(ciudad):
    flag = False
    if ciudad in recorrido_mvp:
        flag = True
    return flag

def calc_ciudad_mas_cercana(ciudad):
    distancias_ciudad = distancias[ciudad]
    cont = 1
    flag = True
    distancia_minima = np.argsort(distancias_ciudad)
    while flag:
        ciudad_mas_cercana = distancia_minima[cont]
        valida = valida_repeticion(ciudad_mas_cercana)
        if valida:
            cont += 1
        else:
            flag = False
    return ciudad_mas_cercana

def mostrar_mapa():
    coordenadas_mvp = [0] * 24

    # Guarda las coordenadas del mejor recorrido en orden para mostrar en el mapa
    for i in range(0, cant_ciudades):
        coordenadas_mvp[i] = lista_coordenadas[recorrido_mvp[i]]

    coordenadas_mvp.append(coordenadas_mvp[0])  # Agrega el primer punto al final para cerrar la ruta
    xs, ys = zip(*coordenadas_mvp)  # Crea una lista de los valores mapa,y
    mapa = "mapa_arg.png"
    img = mpimg.imread(mapa)
    imgplot = plt.imshow(img)
    imgplot.axes.get_xaxis().set_visible(False)
    plt.axis('off')
    plt.plot(xs, ys, color="black")
    plt.suptitle("Gráfica del mejor recorrido partiendo de " + nombres_ciudades[recorrido_mvp[0]])
    distancia = calcula_distancia_recorrido(recorrido_mvp)
    plt.title("Se recorrieron " + str(distancia) + " kilómetros", fontsize=10)
    plt.show()

recorrido_mvp = [0]
menu()
print(recorrido_mvp)
mostrar_mapa()


#! /usr/bin/env python3
#-*-coding:utf8;-*-
__author__ = 'Ahmad Abdulnasir <ahmadabdulnasir9@gmail.com>'
__copyright__ = 'Copyright (c) 2018, salafi'
__version__ = "0.1t"

import sys
from math import sqrt

def varInsp():
    try:
        a = float(input("\tPlease enter the coefficients a: "))
        b = float(input("\tPlease enter the coefficients b: "))
        c = float(input("\tPlease enter the constant c: "))
        if a*2 == 0:
            print("Not defined quadratiic equation with a = 0")
            sys.exit(1)
        else:
            pass
        #return a, b , c
        quadratic(a,b,c)
    except ValueError as koo:
        print("Please Check Your Input ", koo)
        varInsp()

def quadratic(a,b,c):
    dis = b*b-4*a*c
    if dis > 0:
        root1 = round((-b + sqrt(dis)) / (2*a),3)
        root2 = round((-b - sqrt(dis)) / (2*a),)
        print("\nThe solutions are: {} and {} ".format(root1, root2))
    elif dis == 0:
        root1 = round((-b + sqrt(dis)) / (2*a),3)
        root2 = round((-b - sqrt(dis)) / (2*a),3)
        print("\nThe solutions are: {} and {} ".format(root1, root2))
    elif dis < 0:
        print("\nThe solutions for this equation are Complex.")
        root1 = round((-b + sqrt(dis*-1)) / (2*a),3)
        root2 = round((-b - sqrt(dis*-1)) / (2*a),3)
        print("\nThe solutions are: {}i and {}i".format(root1 , root2))

def solve():
    print("This program finds the  solutions to a quadratic equation. of the form \n\t ax^2 + bx + c = 0 ")
#    var = varInsp()
#    quadratic(var[0],var[1],var[2])
    varInsp()
if __name__ == "__main__":
    solve()


import os
import cv2
import time
import math
import numpy as np
import torch

'''
    Dual camera.
'''
class Dual:
    def __init__(self):
        self.cam_width, self.cam_height = 640, 480
        self.ratio = 1.0
        self.img_width, self.img_height= int(self.cam_width*self.ratio), int(self.cam_height*self.ratio)

    def load_npz(self, npz_file):
        try:
            npzfile = np.load(npz_file)
        except Exception as e:
            raise ExceptionCommon(message=str(e))
        leftMapX = npzfile['leftMapX']
        leftMapY = npzfile['leftMapY']
        rightMapX = npzfile['rightMapX']
        rightMapY = npzfile['rightMapY']
        Q = npzfile['dispartityToDepthMap']
        return leftMapX, leftMapY, rightMapX, rightMapY, Q

    def get_rectified_dual_images(self, left_frame, right_frame, leftMapX, leftMapY, rightMapX, rightMapY):
        iml_rectified = cv2.remap(left_frame, leftMapX, leftMapY, interpolation=cv2.INTER_LINEAR, borderMode=cv2.BORDER_CONSTANT)
        imr_rectified = cv2.remap(right_frame, rightMapX, rightMapY, interpolation=cv2.INTER_LINEAR, borderMode=cv2.BORDER_CONSTANT)
        return iml_rectified, imr_rectified

    def get_disparity_image(self, iml_rectified, imr_rectified):
        num = 5
        blockSize = 3
        stereo_sgbm = cv2.StereoSGBM_create(
            minDisparity= 0,
            numDisparities=16 * num,
            blockSize=blockSize,
            P1=8 * 3 * blockSize * blockSize,
            P2=32 * 3 * blockSize * blockSize,
            disp12MaxDiff=1,
            preFilterCap=15,
            uniquenessRatio=10,
            speckleWindowSize=100,
            speckleRange=2,
            mode=cv2.STEREO_SGBM_MODE_SGBM_3WAY)

        stereo_sgbm_right_matcher = cv2.ximgproc.createRightMatcher(stereo_sgbm)
        wls_filter = cv2.ximgproc.createDisparityWLSFilter(matcher_left=stereo_sgbm)
        wls_filter.setLambda(8000)
        wls_filter.setSigmaColor(1.2)

        gray_L = cv2.cvtColor(iml_rectified, cv2.COLOR_BGR2GRAY)
        gray_R = cv2.cvtColor(imr_rectified, cv2.COLOR_BGR2GRAY)
        egray_L = cv2.equalizeHist(gray_L)
        egray_R = cv2.equalizeHist(gray_R)

        disparity_left = stereo_sgbm.compute(egray_L, egray_R)
        disparity_right = stereo_sgbm_right_matcher.compute(egray_R,egray_L)
        disparity_left = np.int16(disparity_left)
        disparity_right = np.int16(disparity_right)
        return disparity_left, disparity_right, wls_filter, gray_L, gray_R

    def distance(self, threeD, x, y):
        distance = threeD[y,x,2]
        return distance

    def get_threeD_img(self, l_image, r_image, npz_file):
        leftMapX, leftMapY, rightMapX, rightMapY, Q = self.load_npz(npz_file)
        iml_rectified, imr_rectified = self.get_rectified_dual_images(l_image, r_image, leftMapX, leftMapY, rightMapX, rightMapY)

        disparity_left, disparity_right, wls_filter, gray_L, gray_R = self.get_disparity_image(iml_rectified, imr_rectified)
        os.makedirs('./images/disp/left', exist_ok=True)
        os.makedirs('./images/disp/right', exist_ok=True)
        fname = l_fname.split('/')[-1]
        print(fname)
        print(disparity_left.shape)
        cv2.imwrite(f'./images/disp/left/{fname}', disparity_left)
        cv2.imwrite(f'./images/disp/right/{fname}', disparity_right)

        disparity_filtered = wls_filter.filter(disparity_left, gray_L, None, disparity_right)
        imd = disparity_filtered
        color_image = iml_rectified

        threeD = cv2.reprojectImageTo3D(imd, Q, handleMissingValues=True)
        threeD = threeD * 16
        threeD = threeD.astype(np.float16)

        disp = imd.astype(np.float32) / 16.0
        disp8U = cv2.normalize(disp, disp, alpha=0, beta=255, norm_type=cv2.NORM_MINMAX, dtype=cv2.CV_8U)
        disp8U = cv2.medianBlur(disp8U, 9)
        depth_heatmap = cv2.applyColorMap(disp8U, cv2.COLORMAP_JET)
        os.makedirs('./images/disp/heatmap', exist_ok=True)
        cv2.imwrite(f'./images/disp/heatmap/{fname}', depth_heatmap)

        return color_image, threeD, depth_heatmap

def detect_plate_position(l_fname, model):
    results = model(l_fname)
    bbox = results.pandas().xyxy[0]
    if bbox.shape[0] == 0:
        print(f'no plate be found in {l_fname} thus return x, y as (False, False)')
        return False, False
    else:
        bbox_most_conf = bbox.iloc[bbox.confidence.idxmax()]
        x = (bbox_most_conf.xmin + bbox_most_conf.xmax) / 2
        y = (bbox_most_conf.ymin + bbox_most_conf.ymax) / 2
        return int(x), int(y)

def put_text(image, x, y, depth):
    image = cv2.circle(image, (x,y), 3, (0,0,255), -1)
    image = cv2.putText(image, str(int(depth))+'cm', (x,y+8), cv2.FONT_HERSHEY_SIMPLEX, 1, (255,0,0), 2, cv2.LINE_AA)
    return image

if __name__ == "__main__":
    model = torch.hub.load('ultralytics/yolov5', 'custom', path='weights/best.pt')
    model.conf = 0.6
    dataset_path_left = './images/motor/left'
    dataset_path_right = './images/motor/right'
    npz_file = './calibrate_settings/fishstereocalibrate.npz'
    left_images = sorted([os.path.join(dataset_path_left, img) for img in os.listdir(dataset_path_left)])[:2]
    right_images = sorted([os.path.join(dataset_path_right, img) for img in os.listdir(dataset_path_right)])[:2]
    dual = Dual()
    last_depth = 0
    for i, (l_fname, r_fname) in enumerate(zip(left_images, right_images)):
        print(i)
        l_image, r_image = cv2.imread(l_fname), cv2.imread(r_fname)
        start_time = time.time()
        _, threeD, _ = dual.get_threeD_img(l_image, r_image, npz_file)
        print('time = %.2f' %(time.time() - start_time))
        x,y = detect_plate_position(l_fname, model)
        if not x:
            continue
        depth = threeD[:,:,2]
        point_depth = depth[y, x]/10
        if np.isinf(np.sum(point_depth)) or np.isnan(np.sum(point_depth)):
            point_depth = last_depth
        last_depth = point_depth
        draw_image = put_text(l_image, x, y, point_depth)
        os.makedirs('./images/motor/result', exist_ok=True)
        fname = l_fname.split('/')[-1]
        cv2.imwrite(f'./images/motor/result/{fname}', draw_image)


import numpy as np
import time
from picamera import PiCamera
import RPi.GPIO as GPIO

class LEDctrl(object):
	def __init__(self, cam_res, pins):
		self.cam_res = cam_res

		self.cam = self.cam_setup()       # initialize camera
		self.pwmRed, self.pwmGreen, self.pwmBlue = self.led_setup(pins)
		self.data = np.empty((self.cam_res[0],self.cam_res[1],3),dtype=np.uint8) # x,y and rgb

	def cam_setup(self):
		cam = PiCamera()               # initialize camera

		cam.resolution = (self.cam_res[1],self.cam_res[0])
		cam.framerate = 60
		time.sleep(2) #let the camera settle
		cam.iso = 1#10#100
		cam.shutter_speed = cam.exposure_speed
		cam.exposure_mode = 'off'
		gain_set = cam.awb_gains
		cam.awb_mode = 'off'
		cam.awb_gains = gain_set

		return cam

	def led_setup(self, pins):
		freq = 100

		GPIO.setmode(GPIO.BOARD)       # use PHYSICAL GPIO Numbering
		GPIO.setup(pins, GPIO.OUT)     # set RGBLED pins to OUTPUT mode
		GPIO.output(pins, GPIO.HIGH)   # make RGBLED pins output HIGH level
		pwmRed = GPIO.PWM(pins[0], freq)      # set PWM Frequence to 2kHz
		pwmGreen = GPIO.PWM(pins[1], freq)  # set PWM Frequence to 2kHz
		pwmBlue = GPIO.PWM(pins[2], freq)    # set PWM Frequence to 2kHz
		pwmRed.start(100)      # set initial Duty Cycle to 0
		pwmGreen.start(100)
		pwmBlue.start(100)

		return pwmRed, pwmGreen, pwmBlue

	def setColor(self,r_val,g_val,b_val):      # change duty cycle for three pins to r_val,g_val,b_val
		""" param: rgb values 0 ... 255, find corresponding, duty cycle"""
		r_dc = 100 - (np.mean(self.data[:,:,0])/255)*100
		g_dc = 100 - (np.mean(self.data[:,:,1])/255)*100
		b_dc = 100 - (np.mean(self.data[:,:,2])/255)*100

		self.pwmRed.ChangeDutyCycle(r_dc)     # change pwmRed duty cycle to r_val
		self.pwmGreen.ChangeDutyCycle(g_dc)
		self.pwmBlue.ChangeDutyCycle(b_dc)

	def calibrate(self):
		cycles = 10
		input('calibrate to RED ')
		cal_red = np.zeros(3)
		for i in range(cycles):
			self.cam.capture(self.data, 'rgb')
			cal_red += 1/cycles * np.mean(self.data, axis=(0,1))
		print('RED calibrate %s' % cal_red)

		input('calibrate to GREEN ')
		cal_green = np.zeros(3)
		for i in range(cycles):
			self.cam.capture(self.data, 'rgb')
			cal_green += 1/cycles * np.mean(self.data, axis=(0,1))
		print('GREEN calibrate %s' % cal_green)

		input('calibrate to BLUE ')
		cal_blue = np.zeros(3)
		for i in range(cycles):
			self.cam.capture(self.data, 'rgb')
			cal_blue += 1/cycles * np.mean(self.data, axis=(0,1))
		print('BLUE calibrate %s' % cal_blue)

	def rgb_detect(self):

		while True:
			try:
				self.cam.capture(self.data, 'rgb', use_video_port=True)
				mean_rgb = np.mean(self.data, axis=(0,1))

				self.setColor(*mean_rgb)
			except KeyboardInterrupt:
				self.destroy()
				break

	def destroy(self):
		print('cleanup')
		self.pwmRed.stop()
		self.pwmGreen.stop()
		self.pwmBlue.stop()
		GPIO.cleanup()                     # Release all GPIO

def main():
	h = 128#64#1024                     # pixels in x-dir
	pins = [11, 12, 13]         # define the pins for R:11,G:12,B:13

	cam_res = (int(h),int(0.75*h)) # keeping the natural 3/4 resolution
	# we need to round to the nearest 16th and 32nd (requirement for picamera)
	cam_res = (int(16*np.floor(cam_res[1]/16)),int(32*np.floor(cam_res[0]/32)))

	led = LEDctrl(cam_res, pins)
	led.rgb_detect()
	#led.calibrate()

if __name__ == '__main__':
    main()


#not adding check for whether two movie names are same
#check if both the movies present in dataframe then only proceed
#fetch the name of actors from movie 1 and 2 and display common
#fetch the names of directors from movie 1 and 2 and display common

import pandas as pd

movieDetailDf = pd.read_csv("MovieDetail.csv")

def getDirectors(movie):
    directors = movieDetailDf.loc[movieDetailDf['title'].str.lower() == movie]['directors'].values[0]
    if len(directors) != 0:
        return directors.split(" | ")
    else:
        print("Details of directors for "+ movie +" are not present.")

def getActors(movie):
    actors = movieDetailDf.loc[movieDetailDf['title'].str.lower() == movie]['actors'].values[0]
    if len(actors) != 0:
        return actors.split(" | ")
    else:
        print("Details of actors for "+ movie +" are not present.")

#returns common elements from two lists
def findCommon(l1, l2):
    s1 = set(l1)
    s2 = set(l2)
    return list(s1.intersection(s2))

print("Enter two movie names..")
movie1 = input("1st movie title plz..: ").lower()
movie2 = input("2nd movie title plz..: ").lower()

all_titles = list(movieDetailDf['title'].str.lower().values)

if movie1 in all_titles and movie2 in all_titles:
    #for common actors
    actorsMovie1 = getActors(movie1)
    actorsMovie2 = getActors(movie2)
    commonActors = findCommon(actorsMovie1, actorsMovie2)
    if len(commonActors) != 0:
        print("Common actors in "+movie1+" and "+movie2)
        for actor in commonActors:
            print("  " + actor)
    else:
        print(movie1+" and "+movie2+" dont have common actors.")

    #for common directors
    directorsMovie1 = getDirectors(movie1)
    directorsMovie2 = getDirectors(movie2)
    commonDirectors = findCommon(directorsMovie1, directorsMovie2)
    if len(commonDirectors) != 0:
        print("Common directors in "+movie1.capitalize()+" and "+movie2.capitalize())
        for director in commonDirectors:
            print("  " + director)
    else:
        print(movie1+" and "+movie2+" dont have common directors.")
else:
    print("Seems like i dont have details of these movies.Please enter different movie names..!")


# -*- coding: utf-8 -*-

import pytest

import numpy as np

import pandas.util.testing as tm
from pandas import Categorical, Index, CategoricalIndex, PeriodIndex
from pandas.tests.categorical.common import TestCategorical

class TestCategoricalIndexingWithFactor(TestCategorical):

    def test_getitem(self):
        assert self.factor[0] == 'a'
        assert self.factor[-1] == 'c'

        subf = self.factor[[0, 1, 2]]
        tm.assert_numpy_array_equal(subf._codes,
                                    np.array([0, 1, 1], dtype=np.int8))

        subf = self.factor[np.asarray(self.factor) == 'c']
        tm.assert_numpy_array_equal(subf._codes,
                                    np.array([2, 2, 2], dtype=np.int8))

    def test_setitem(self):

        # int/positional
        c = self.factor.copy()
        c[0] = 'b'
        assert c[0] == 'b'
        c[-1] = 'a'
        assert c[-1] == 'a'

        # boolean
        c = self.factor.copy()
        indexer = np.zeros(len(c), dtype='bool')
        indexer[0] = True
        indexer[-1] = True
        c[indexer] = 'c'
        expected = Categorical(['c', 'b', 'b', 'a', 'a', 'c', 'c', 'c'],
                               ordered=True)

        tm.assert_categorical_equal(c, expected)

class TestCategoricalIndexing(object):

    def test_getitem_listlike(self):

        # GH 9469
        # properly coerce the input indexers
        np.random.seed(1)
        c = Categorical(np.random.randint(0, 5, size=150000).astype(np.int8))
        result = c.codes[np.array([100000]).astype(np.int64)]
        expected = c[np.array([100000]).astype(np.int64)].codes
        tm.assert_numpy_array_equal(result, expected)

    def test_periodindex(self):
        idx1 = PeriodIndex(['2014-01', '2014-01', '2014-02', '2014-02',
                            '2014-03', '2014-03'], freq='M')

        cat1 = Categorical(idx1)
        str(cat1)
        exp_arr = np.array([0, 0, 1, 1, 2, 2], dtype=np.int8)
        exp_idx = PeriodIndex(['2014-01', '2014-02', '2014-03'], freq='M')
        tm.assert_numpy_array_equal(cat1._codes, exp_arr)
        tm.assert_index_equal(cat1.categories, exp_idx)

        idx2 = PeriodIndex(['2014-03', '2014-03', '2014-02', '2014-01',
                            '2014-03', '2014-01'], freq='M')
        cat2 = Categorical(idx2, ordered=True)
        str(cat2)
        exp_arr = np.array([2, 2, 1, 0, 2, 0], dtype=np.int8)
        exp_idx2 = PeriodIndex(['2014-01', '2014-02', '2014-03'], freq='M')
        tm.assert_numpy_array_equal(cat2._codes, exp_arr)
        tm.assert_index_equal(cat2.categories, exp_idx2)

        idx3 = PeriodIndex(['2013-12', '2013-11', '2013-10', '2013-09',
                            '2013-08', '2013-07', '2013-05'], freq='M')
        cat3 = Categorical(idx3, ordered=True)
        exp_arr = np.array([6, 5, 4, 3, 2, 1, 0], dtype=np.int8)
        exp_idx = PeriodIndex(['2013-05', '2013-07', '2013-08', '2013-09',
                               '2013-10', '2013-11', '2013-12'], freq='M')
        tm.assert_numpy_array_equal(cat3._codes, exp_arr)
        tm.assert_index_equal(cat3.categories, exp_idx)

    def test_categories_assigments(self):
        s = Categorical(["a", "b", "c", "a"])
        exp = np.array([1, 2, 3, 1], dtype=np.int64)
        s.categories = [1, 2, 3]
        tm.assert_numpy_array_equal(s.__array__(), exp)
        tm.assert_index_equal(s.categories, Index([1, 2, 3]))

        # lengthen
        def f():
            s.categories = [1, 2, 3, 4]

        pytest.raises(ValueError, f)

        # shorten
        def f():
            s.categories = [1, 2]

        pytest.raises(ValueError, f)

    # Combinations of sorted/unique:
    @pytest.mark.parametrize("idx_values", [[1, 2, 3, 4], [1, 3, 2, 4],
                                            [1, 3, 3, 4], [1, 2, 2, 4]])
    # Combinations of missing/unique
    @pytest.mark.parametrize("key_values", [[1, 2], [1, 5], [1, 1], [5, 5]])
    @pytest.mark.parametrize("key_class", [Categorical, CategoricalIndex])
    def test_get_indexer_non_unique(self, idx_values, key_values, key_class):
        # GH 21448
        key = key_class(key_values, categories=range(1, 5))
        # Test for flat index and CategoricalIndex with same/different cats:
        for dtype in None, 'category', key.dtype:
            idx = Index(idx_values, dtype=dtype)
            expected, exp_miss = idx.get_indexer_non_unique(key_values)
            result, res_miss = idx.get_indexer_non_unique(key)

            tm.assert_numpy_array_equal(expected, result)
            tm.assert_numpy_array_equal(exp_miss, res_miss)


# -*- coding: utf-8 -*-
"""
Plot3d Module
=============

Plotting routines for 3d display of data.

Note
----
This module is using vispy.
"""
__author__ = 'Christoph Kirst <ckirst@rockefeller.edu>'
__license__ = 'MIT License <https://www.opensource.org/licenses/mit-license.php>'
__copyright__ = 'Copyright (c) 2017 by Christoph Kirst, The Rockefeller University, New York City'

import numpy as np

import vispy

#try:
#  vispy.use(app='PyQt5');  #avoid use of ipynb_webgl
#except:
#  print('qt')
#  try:
#    vispy.use(app='PySide')
#  except:
#    print('no')
#    print(vispy.app.backends.BACKENDMAP)

import vispy.app
import vispy.scene
#vispy.app.run();

import ClearMap.Visualization.Vispy.arbitrary_rotation_camera as ttc
import ClearMap.Visualization.Vispy.VolumeVisual as volume_visual

import ClearMap.Visualization.Color as col

import ClearMap.IO.IO as io

###############################################################################
# ## 3d plotting
###############################################################################

def list_line_plot_3d(coordinates, view=None, title=None, center_view=True, **kwargs):
    """
    Plot lines between coordinates in 3d.

    Arguments
    ---------
    coordinates : array
        Coordinate nx3 array.
    title : str or None
        Window title.
    view : view or None
        Add plot to this view. if given.

    Returns
    -------
    view : view
        The view of the plot.
    """
    # visual
    Plot3D = vispy.scene.visuals.create_visual_node(vispy.visuals.LinePlotVisual)

    # view
    title = title if title is not None else 'list_line_plot_3d'
    view = initialize_view(view, title=title)

    # style
    style = dict(width=2.0, color='red', symbol='o',
                 edge_color='w', face_color='blue')
    style.update(**kwargs)

    # plot
    plot = Plot3D(coordinates, parent=view.scene, **style)
    plot.set_gl_state('translucent', blend=True, depth_test=True)

    if center_view:
        _center_view(view)

    return plot

def list_plot_3d(coordinates, view=None, title=None, center_view=True, color=None, **kwargs):
    """
    Scatter plot of points in 3d.

    Arguments
    ---------
    coordinates : array
        Coordinatenx3 array.
    title : str or None
        Window title.
    view : view or None
        Add plot to this view. if given.

    Returns
    -------
    view : view
        The view of the plot.
    """
    # visual
    Scatter3D = vispy.scene.visuals.create_visual_node(vispy.visuals.MarkersVisual)

    # view
    title = title if title is not None else 'list_plot_3d'
    view = initialize_view(view, title=title)

    # style
    if color and 'face_color' not in kwargs.keys():
        kwargs.update(face_color=color)
    if color and 'edge_color' not in kwargs.keys():
        kwargs.update(edge_color=color)
    style = dict(face_color='blue', symbol='o', size=10,
                 edge_width=0.5, edge_color='blue')
    style.update(**kwargs)

    # plot
    scatter_plot = Scatter3D(parent=view.scene)
    scatter_plot.set_gl_state('translucent', blend=True, depth_test=True)
    scatter_plot.set_data(coordinates, **style)

    if center_view:
        _center_view(view)

    return scatter_plot

def plot_3d(source, colormap=None, view=None, title=None, center_view=True, **kwargs):
    """Plot 3d volume.

    Arguments
    ---------
    source : array
      The 3d volume.
    title : str or None
      Window title.
    view : view or None
      Add plot to this view. if given.

    Returns
    -------
    view : view
      The view of the plot.
    """
    # visual
    VolumePlot3D = vispy.scene.visuals.create_visual_node(volume_visual.VolumeVisual)

    # view
    title = title if title is not None else 'plot_3d'
    # center = (np.array(source.shape) // 2)
    view = initialize_view(view, title=title, fov=0, depth_value=10**8)  #, center=center)

    # style
    style = dict(cmap=grays_alpha(), method='translucent', relative_step_size=0.5)
    style.update(**kwargs)

    # source
    source = io.as_source(source)[:]
    if source.dtype == bool:
        source = source.view(dtype='uint8')

    # orient
    source = source.transpose([2, 1, 0])

    # plot
    plot = VolumePlot3D(source, parent=view.scene, **style)

    if center_view:
        _center_view(view)

    return plot

def plot_mesh_3d(coordinates, faces, view=None, shading='smooth', color=None, face_colors=None,
                 vertex_colors=None, mode='triangles', center_view=True,  title=None, **kwargs):
    """Plot a 3d mesh.

    Arguments
    ---------
    coordinates : array
        Coordinate nx3 array.
    faces : array
        Indices of triangular faces, nx3 array.
    title : str or None
        Window title.
    view : view or None
        Add plot to this view. if given.

    Returns
    -------
    view : view
        The view of the plot.
    """

    # build visuals
    MeshVisual = vispy.scene.visuals.create_visual_node(vispy.visuals.mesh.MeshVisual)

    # view
    title = title if title is not None else 'plot_mesh_3d'
    view = initialize_view(view, title=title)

    # print view
    if color is None and face_colors is None and vertex_colors is None:
        color = 'red'

    p = MeshVisual(coordinates, faces, parent=view.scene, shading=shading,
                   color=color, face_colors=face_colors, vertex_colors=vertex_colors,
                   mode=mode, **kwargs)

    if center_view:
        view.camera.center = np.mean(coordinates, axis=0)

    return p

def plot_regular_polygon(center, sides=4, title=None, view=None, color='red',
                         border_color=None, border_width=1, radius=1.0,  **kwargs):
    # build visuals
    PolyVisual = vispy.scene.visuals.create_visual_node(vispy.visuals.RegularPolygonVisual)

    # view
    title = title if title is not None else 'plot_cube'
    view = initialize_view(view, title=title)

    p = PolyVisual(center, color=color, border_color=border_color, border_width=border_width,
                   radius=radius, sides=sides, parent=view.scene, **kwargs)

    if center_view:
        view.camera.center = center

    return p

def plot_box(lower, upper, face_color=(1, 0, 0, 0.5), line_color=None, line_width=1,
             line_padding=0, shading='smooth', mode='triangles',
             title=None, view=None, center_view=True, **kwargs):
    """Plots a box in 3d."""
    # TODO: return compound visual

    # view
    title = title if title is not None else 'plot_box'
    view = initialize_view(view, title=title)

    # corners
    corners_base = [[0, 0, 0], [1, 0, 0], [1, 1, 0], [0, 1, 0],
                    [0, 0, 1], [1, 0, 1], [1, 1, 1], [0, 1, 1]]
    corners = [[lower[d] if c[d] == 0 else upper[d] for d in range(3)] for c in corners_base]
    corners = np.array(corners, dtype=float)

    visuals = []

    if face_color is not None:
        # build visuals
        MeshVisual = vispy.scene.visuals.create_visual_node(vispy.visuals.mesh.MeshVisual)

        faces = [[0, 1, 5], [0, 5, 4],
                 [1, 2, 6], [1, 6, 5],
                 [4, 5, 6], [4, 6, 7],
                 [3, 0, 4], [3, 4, 7],
                 [2, 3, 7], [2, 7, 6],
                 [3, 2, 1], [3, 1, 0]]
        faces = np.array(faces)

        mv = MeshVisual(corners, faces, parent=view.scene, shading=shading, color=face_color, mode=mode, **kwargs)
        visuals.append(mv)

    if line_color is not None:
        # visual
        LineVisual = vispy.scene.visuals.create_visual_node(vispy.visuals.LineVisual)

        lines = np.array([[0, 1], [1, 2], [2, 3], [3, 0], [4, 5], [5, 6], [6, 7], [7, 4], [0, 4], [1, 5], [2, 6], [3, 7]])

        if line_padding != 0:
            corners = [[lower[d] - line_padding if c[d] == 0 else upper[d] + line_padding for d in range(3)] for c in corners_base]
            corners = np.array(corners, dtype=float)

        lv = LineVisual(corners, parent=view.scene, connect=lines, color=line_color, width=line_width)
        visuals.append(lv)

    if center_view:
        view.camera.center = 0.5 * (np.array(lower) + np.array(upper))

    return view

###############################################################################
# ## Helpers
###############################################################################

#TODO: vispy.color.ColorMap([col1,col2,...]) is much easier!

def single_color_colormap(color=(1, 1, 1), alpha=0.075, inverse_alpha=False):
    color = tuple(col.color(color, alpha=alpha))
    if inverse_alpha:
        opacity = lambda t: 1-t
    else:
        opacity = lambda t: t

    class SingleColor(vispy.color.colormap.BaseColormap):
        glsl_map = """
        vec4 grays(float t) {
          return vec4(%g * t, %g * t, %g * t, %g * %s);
        }
        """ % (color + ('(1-t)' if inverse_alpha else 't',))

        def map(self, t):
            if isinstance(t, np.ndarray):
                return np.hstack([color[0] * t, color[1] * t, color[2] * t, color[3] * opacity(t)]).astype(np.float32)
            else:
                return np.array([color[0] * t, color[1] * t, color[2] * t, color[3] * opacity(t)], dtype=np.float32)

    return SingleColor()

def grays_alpha(alpha=0.075, inverse=False):
    return single_color_colormap(color=(1, 1, 1), alpha=alpha, inverse_alpha=inverse)

def get_view(view):
    """
    Return the view of the argument.

    Arguments
    ---------
    view : view
        The vispy window.

    Returns
    -------
    view : view
        The vispy view of the plot.
    """
    while not isinstance(view, vispy.scene.widgets.viewbox.ViewBox) and hasattr(view, 'parent'):
        view = view.parent

    return view

def add_axes(view):
    """
    Add axes to a plot.

    Arguments
    ---------
    view : view
        The vispy window.

    Returns
    -------
    view : view
        The vispy view of the plot.
    """
    view = initialize_view(view)
    axes = vispy.scene.visuals.XYZAxis(parent=view.scene)

    return axes

def set_light_to_camera(mesh):
    """
    Set the light direction to the crrent camera position.

    Arguments
    ---------
    mesh : mesh
        A vispy mesh.
    """
    v = get_view(mesh)
    a = np.deg2rad(v.camera.azimuth)
    e = np.deg2rad(v.camera.elevation)
    direction = (np.cos(a) * np.cos(e), np.sin(a) * np.cos(e), np.sin(e))
    # direction = (np.sin(a) * np.cos(e), np.cos(a) * np.cos(e), np.sin(e))
    direction = tuple(-d for d in direction)
    mesh.light_dir = direction

def set_background(view, color):
    """
    Set the background color of the view.

    Arguments
    ---------
    view : view
        The vispy window.
    color : color specification
        The color for the background.

    Returns
    -------
    view : view
        The vispy view of the plot.
    """
    view = get_view(view)
    view.canvas.bgcolor = col.color(color, alpha=True, as_int=False)
    return view

def center_view(view):
    """
    Center the camera in a plot.

    Arguments
    ---------
    view : view
        The vispy window.

    Returns
    -------
    view : view
        The vispy view of the plot.
    """
    view = get_view(view)
    bounds = view.get_scene_bounds()
    center = [(b[1] - b[0])*0.5 for b in bounds]
    view.camera.center = center

_center_view = center_view  # FIXME: why

def get_view_parameter(view):
    view = get_view(view)
    return view.camera.get_state()

def set_view_parameter(view, parameter):
    view = get_view(view)
    view.camera.set_state(parameter)

def initialize_view(view=None, title=None, show=True, fov=None, distance=None, elevation=None, azimuth=None,
                    center=None, depth_value=None, bg_color='white'):
    """Return a default view."""
    if view is None:
        # build canvas
        canvas = vispy.scene.SceneCanvas(keys='interactive', title=title, show=show, bgcolor=bg_color)

        view = canvas.central_widget.add_view(camera=ttc.ArbitraryRotationCamera())
        # view.camera = 'turntable'  # WARNING: This overwrites the cam defined above
        if fov is not None:
            view.camera.fov = fov
        if distance is not None:
            view.camera.distance = distance
        if elevation is not None:
            view.camera.elevation = elevation
        if azimuth is not None:
            view.camera.azimuth = azimuth
        if center is not None:
            view.camera.center = center
        if depth_value is not None:
            view.camera.depth_value = depth_value
    else:
        view = get_view(view)

    return view

def save(location, view, transparent=None, *args, **kwargs):
    """Save the current view to a file."""
    canvas = get_view(view).canvas
    img = canvas.render(*args, **kwargs)
    if transparent is not None:
        t = np.logical_and(img[:, :, 0] >= transparent, img[:, :, 1] >= transparent)
        t = np.logical_and(img[:, :, 2] >= transparent, t)
        img[:, :, 3][t] = 0
        img = img.transpose([0, 1, 2])
    else:
        img = img[:, :, :3].T
    return io.write(location, img)

###############################################################################
# ## Tests
###############################################################################

def _test():
    import numpy as np
    import ClearMap.Visualization.Vispy.Plot3d as p3d
    # reload(p3d)

    # plot
    coordinates = np.random.rand(40, 3)
    p1 = p3d.list_plot_3d(coordinates, title='test')

    # plot something on top
    coordinates = np.random.rand(30, 3)
    p2 = p3d.list_line_plot_3d(coordinates, color='white', face_color='red', view=p1)  # analysis:ignore

    # volumetric plot
    import numpy as np
    shape = (31, 31, 31)
    binary = np.zeros(shape, dtype=bool)
    grid = np.meshgrid(*[range(s) for s in shape], indexing='ij')
    center = tuple(s/2 for s in shape)
    distance = np.sum([(g-c)**2 for g, c in zip(grid, center)], axis=0)
    binary[distance <= 10**2] = True
    p3 = p3d.plot_3d(binary)  # analysis:ignore

    # reload(p3d)
    v = p3d.plot_box((0, 0, 0), (1, 2, 3), face_color=(1, 0, 0, 0), line_color='white', line_width=2, line_padding=0.015)
    print(v)


from pathlib import Path
from setuptools import setup

from util import parse

def make_relative(fn):
    """
    Make the filename relative to the current file.

    Args:
        fn: The filename to convert.

    Returns:
        The path relative to the current file.
    """
    return Path(__file__).parent / fn

setup(
    name = 'pyconll',
    packages = ['pyconll', 'pyconll.unit', 'pyconll.tree'],
    version = parse.package_version(make_relative('pyconll/_version.py')),
    description = 'Read and manipulate CoNLL files',
    long_description = make_relative('README.rst').read_text(),
    author = 'Matias Grioni',
    author_email = 'matgrioni@gmail.com',
    url = 'https://github.com/pyconll/pyconll',
    license = 'MIT',
    keywords = ['nlp', 'conllu', 'conll', 'universal dependencies'],
    python_requires = '~=3.8',
    package_data = { 'pyconll': ['py.typed'] },
    classifiers = [
        'Development Status :: 5 - Production/Stable',
        'Intended Audience :: Developers',
        'Intended Audience :: Education',
        'Intended Audience :: Science/Research',
        'License :: OSI Approved :: MIT License',
        'Programming Language :: Python :: 3 :: Only',
        'Programming Language :: Python :: Implementation :: CPython',
        'Topic :: Scientific/Engineering',
        'Topic :: Utilities'
    ]
)


import lib

def makeURL(keyECOS, queryYYYYMM, driver):
    ## (통계청KOSIS) 컨테이너 화물수송 현황
    startYYYYMM = 201101
    endYYYYMM = int(queryYYYYMM)
    yyyyMM_list = list(range(startYYYYMM, endYYYYMM, 100))

    def kosisContainerApi(yyyyMM):
        s_yyyyMM = str(yyyyMM)
        e_yyyyMM = str(yyyyMM + 11)
        url = f'https://kosis.kr/openapi/Param/statisticsParameterData.do?method=getList&apiKey=NjgwMjNjNTc0NTBlZWM5Y2JjMmQ0YWEyNTIzMjhhNmM=&itmId=13103114674T.0003+&objL1=13102114674A.01+13102114674A.02+13102114674A.03+13102114674A.04+13102114674A.05+13102114674A.06+13102114674A.07+13102114674A.08+13102114674A.09+13102114674A.10+13102114674A.11+13102114674A.12+13102114674A.13+13102114674A.14+13102114674A.15+13102114674A.16+13102114674A.17+13102114674A.18+13102114674A.19+13102114674A.20+13102114674A.21+13102114674A.22+13102114674A.23+13102114674A.24+13102114674A.25+13102114674A.26+13102114674A.27+13102114674A.28+13102114674A.29+13102114674A.30+&objL2=13102114674B.01+13102114674B.02+&objL3=13102114674C.01+13102114674C.02+13102114674C.03+13102114674C.04+13102114674C.05+&objL4=13102114674D.0006+&objL5=&objL6=&objL7=&objL8=&format=json&jsonVD=Y&prdSe=M&startPrdDe={s_yyyyMM}&endPrdDe={e_yyyyMM}&orgId=146&tblId=DT_MLTM_1312'
        r = lib.requests.get(url)
        jo = r.json()
        df = lib.pd.DataFrame(jo)
        df = df[['PRD_DE', 'C1_NM', 'C2_NM', 'C3_NM', 'DT']]  # C1_NM:항구명, C2_NM:국적구분(국적선/외국선), C3_NM:구분(내항/외항입항/외항출항/입항환적/출항환적, DT:화물수송량(R/T)
        df['DT'] = df['DT'].astype(float) # df['DT'] = pd.to_numeric(df['DT'])
        df.rename(columns = {'PRD_DE':'STD_YM', 'DT':'HAEWOON_CONT'}, inplace = True)
        df = df.set_index('STD_YM')
        return df

    dfCONT = lib.pd.DataFrame()
    for elem in yyyyMM_list:
        if(dfCONT.empty):
            dfCONT = kosisContainerApi(elem)
        else:
            dfCONT = lib.pd.concat([dfCONT, kosisContainerApi(elem)])
        dfCONT = dfCONT.groupby('STD_YM').sum(numeric_only=True)
        #dfCONT = dfCONT.groupby(level = 'STD_YM').transform('sum')
        #dfCONT = dfCONT.groupby('STD_YM').sum(numeric_only=True)

    ## (통계청KOSIS) 수출입 화물수송 현황
    # (수출입 따로 보는 경우) url = f'https://kosis.kr/openapi/Param/statisticsParameterData.do?method=getList&apiKey=NjgwMjNjNTc0NTBlZWM5Y2JjMmQ0YWEyNTIzMjhhNmM=&itmId=13103114675T.0001+&objL1=13102114675A.01+&objL2=13102114675B.01+&objL3=13102114675C.0002+13102114675C.0003+&objL4=&objL5=&objL6=&objL7=&objL8=&format=json&jsonVD=Y&prdSe=M&startPrdDe=201101&endPrdDe={queryYYYYMM}&orgId=146&tblId=DT_MLTM_1316'
    # (수출입 합쳐 보는 경우)
    url = f'https://kosis.kr/openapi/Param/statisticsParameterData.do?method=getList&apiKey=NjgwMjNjNTc0NTBlZWM5Y2JjMmQ0YWEyNTIzMjhhNmM=&itmId=13103114675T.0001+&objL1=13102114675A.01+&objL2=13102114675B.01+&objL3=13102114675C.0001+&objL4=&objL5=&objL6=&objL7=&objL8=&format=json&jsonVD=Y&prdSe=M&startPrdDe=201101&endPrdDe={queryYYYYMM}&orgId=146&tblId=DT_MLTM_1316'
    dfTRANS = lib.pd.DataFrame(lib.apiCall.kosisApiCall(url))
    dfTRANS = dfTRANS[['PRD_DE', 'C3_NM', 'DT']]  # (수출입 따로 보는경우) C3_NM:수출/수입/전체,   (수출입 같이 보는경우)C_NM:전체
    dfTRANS['DT'] = round(lib.pd.to_numeric(dfTRANS['DT']) / 1000, 0) # 천톤단위로 변환
    dfTRANS = dfTRANS[['PRD_DE', 'DT']]
    dfTRANS.rename(columns = {'PRD_DE':'STD_YM', 'DT':'HAEWOON_TRANS'}, inplace = True)
    dfTRANS = dfTRANS.set_index('STD_YM')

    ## 유가(Dubai) 추가 (ECOS)
    # 9.1.6.3. 국제상품가격 : [902Y003][M]   /   Dubai(현물) : [4010102][U$/bbl]
    # (Ex) https://ecos.bok.or.kr/api/StatisticSearch/MTSA07N58C5X8EB4LMJL/json/kr/1/100/902Y003/M/201001/202208/4010102
    dfDUBAI = lib.apiCall.ecosApiCall(keyECOS, f"902Y003/M/201001/{queryYYYYMM}/4010102")
    dfDUBAI.rename(columns = {'DATA_VALUE':'HAEWOON_DUBAI'}, inplace = True)

    ## (통계청KOSIS) 국내화물수송량 : 화물수송실적 - 내항화물입항현황 - 연안화물선(입항) - 화물(단위: R/T)
    url = f'https://kosis.kr/openapi/Param/statisticsParameterData.do?method=getList&apiKey=NjgwMjNjNTc0NTBlZWM5Y2JjMmQ0YWEyNTIzMjhhNmM=&itmId=13103114676T.0003+&objL1=13102114676A.001+&objL2=13102114676B.0002+&objL3=&objL4=&objL5=&objL6=&objL7=&objL8=&format=json&jsonVD=Y&prdSe=M&startPrdDe=201101&endPrdDe={queryYYYYMM}&orgId=146&tblId=DT_MLTM_1314'
    dfDomeTrans =  lib.pd.DataFrame(lib.apiCall.kosisApiCall(url))
    dfDomeTrans = dfDomeTrans[['PRD_DE', 'ITM_NM', 'C1_NM', 'C2_NM', 'DT']]  # ITM_NM:화물, C1_NM:총계, C2_NM:연안화물선(입항)
    dfDomeTrans['DT'] = round(lib.pd.to_numeric(dfDomeTrans['DT']) / 1000, 0) # 천톤단위로 변환
    dfDomeTrans = dfDomeTrans[['PRD_DE', 'DT']]
    dfDomeTrans.rename(columns = {'PRD_DE':'STD_YM', 'DT':'HAEWOON_DOME_TRANS'}, inplace = True)
    dfDomeTrans = dfDomeTrans.set_index('STD_YM')

    ## (TradLinx) 컨테이너 운임지표 : CCFI, SCFI
    # Data reference : Go to TradLinx homepage
    url = "https://www.tradlinx.com/freight-index"
    driver.get(url)

    # Select Month because we need monthly data
    driver.find_element(lib.By.XPATH, '/html/body/application/div/container-freight/div/div[2]/div/div[1]/div[3]/drp-input/div/div/span[2]').click()
    driver.find_element(lib.By.XPATH, '/html/body/application/div/container-freight/div/div[2]/div/div[1]/div[3]/drp-input/div/div[2]/ul/li[2]').click()

    print(driver.find_element(lib.By.XPATH, '/html/body/application/div/container-freight/div/div[2]/div/div[1]/div[3]/drp-input/div/div/span[2]').text)

    driver.find_element(lib.By.XPATH, '/html/body/application/div/container-freight/div/div[2]/div/div[1]/div[4]/div/i').click() # Pick calendar
    driver.implicitly_wait(5)
    lib.time.sleep(5)

    # Set query condition : Select start day as '2020.1.1'
    # Click 'JAN'
    while driver.find_element(lib.By.CLASS_NAME, 'dtp-actual-month').text != 'JAN':
        driver.find_element(lib.By.CLASS_NAME, "dtp-select-month-before").click()
    # Click '2010'
    while driver.find_element(lib.By.CLASS_NAME, 'dtp-actual-year').text != '2010':
        driver.find_element(lib.By.CLASS_NAME, "dtp-select-year-before").click()
    # Click 'day 1'
    driver.find_element(lib.By.XPATH, "/html/body/div[2]/div/div[1]/div[3]/div[1]/table/tbody/tr[2]/td[6]/a").click()

    # Make sure that the selected day is 2010. JAN. 1
    print(driver.find_element(lib.By.CLASS_NAME, 'dtp-actual-year').text)
    print(driver.find_element(lib.By.CLASS_NAME, 'dtp-actual-month').text)
    print(driver.find_element(lib.By.XPATH, "/html/body/div[2]/div/div[1]/div[3]/div[1]/table/tbody/tr[2]/td[6]/a").text)
    print(driver.find_element(lib.By.CLASS_NAME, 'dtp-btn-ok').text)

    driver.find_element(lib.By.CLASS_NAME, 'dtp-btn-ok').click()
    lib.time.sleep(5)
    #print(browser.find_element(By.XPATH, "/html/body").text)
    containerDataFrame = lib.pd.read_html(driver.page_source)[1]

    containerDataFrame = containerDataFrame.transpose()
    containerDataFrame.columns = containerDataFrame.iloc[0]
    containerDataFrame = containerDataFrame[1:]
    containerDataFrame['STDYM'] = containerDataFrame.index.str.replace(" ", "")

    containerDataFrame.columns.name = None  # Delete column name 'Date All'
    containerDataFrame.reset_index(drop=True, inplace=True) # index reset
    containerDataFrame.set_index('STDYM', inplace=True) # Set index as 'STDYM'

    dfSCFI = containerDataFrame[['SCFI']]
    dfSCFI.rename(columns = {'SCFI':'HAEWOON_SCFI'}, inplace = True)
    dfCCFI = containerDataFrame[['CCFI']]
    dfCCFI.rename(columns = {'CCFI':'HAEWOON_CCFI'}, inplace = True)

    # compile the list of dataframes you want to merge
    df_list = [dfSCFI, dfCCFI, dfCONT, dfTRANS, dfDUBAI, dfDomeTrans]
    # grab first dataframe
    haewoonDataFrame = df_list[0]
    # loop through all but first data frame
    for to_merge in df_list[1:]:
        # result of merge replaces first or previously merged data frame w/ all previous fields
        haewoonDataFrame = lib.pd.merge(left = haewoonDataFrame, right = to_merge, left_index = True, right_index = True, how = "outer")

    # 기타 데이터 삽입
    haewoonDataFrame.insert(0, 'HAEWOON_BDI', '')
    haewoonDataFrame.insert(2, 'HAEWOON_WS', '')

    return haewoonDataFrame

CIS eFAS Industry DB Scraping/IT_EFAS_INDU_SPECIAL_DB/SPECIAL_DB/haewoon.py


from fermerce.lib.paystack.verification import schemas
from fermerce.lib.paystack import client, endpoint
from fermerce.lib.errors import error

async def verify_account_number(data_in: schemas.IAccountResolveIn):
    # try:
    response = await client.request.get(
        url=endpoint.get("bank").get("resolve"),
        params={
            "account_number": data_in.account_number,
            "bank_code": data_in.bank_code,
        },
    )
    data = schemas.IAccountResolveResponse(**response.json())
    return data

# except Exception:
#     raise error.BadDataError(detail="Error validating account")

async def validate_account(data_in: schemas.IBankAccountValidateIn):
    # try:
    response = await client.request.post(
        url=endpoint.get("bank").get("validate"),
        json=data_in.dict(),
    )

    data = schemas.IAccountVerificationResponse(**response.json())
    print(response.json())
    return data

# except Exception as e:
#     raise error.BadDataError(detail="Error refunding transaction")


""" linked_list.py

Student: Oliver Näslund
Mail: oliver.naslund@gmail.com
Reviewed by: Joacim Stenlund
Date reviewed: 2 Maj 2023
"""

from re import X

class LinkedList:

    class Node:
        def __init__(self, data, succ):
            self.data = data
            self.succ = succ

        def length(self): #Tillägg
            def _length(f):
                if f is None:
                    return 0
                else:
                    return 1 + _length(f.succ)
            return _length(self.first)

        def insert(self, x):
            if self.succ is None or x <= self.succ.data:
                self.succ = LinkedList.Node(x, self.succ)
            else:
                self.succ.insert(x)

    def __init__(self):
        self.first = None

    def __iter__(self):       # Discussed in the section on iterators and generators
        current = self.first
        while current:
            yield current.data
            current = current.succ

    def __in__(self, x):      # Discussed in the section on operator overloading
        for d in self:
            if d == x:
                return True
            elif x < d:
                return False
        return False

    def insert(self, x): #Metod 2
        self.first = self._insert(x, self.first)

    def _insert(self, x, f): #Metod 2 hjälp
        if f is None or x <= f.data:
            return LinkedList.Node(x, f)
        else:
            f.succ = self._insert(x, f.succ)
        return f

   # def insert(self, x): #Metod 1
   #     if self.first is None or x <= self.first.data:
   #         self.first = LinkedList.Node(x, self.first)
   #     else:
   #         self.first.insert(x)

   # def insert(self, x): #Gammal insert
   #     if self.first is None or x <= self.first.data:
   #         self.first = self.Node(x, self.first)
   #     else:
   #         f = self.first
   #         while f.succ and x > f.succ.data:
   #             f = f.succ
   #         f.succ = self.Node(x, f.succ)

    def print(self):
        print('(', end='')
        f = self.first
        while f:
            print(f.data, end='')
            f = f.succ
            if f:
                print(', ', end='')
        print(')')

    # To be implemented

    def length(self):             # Optional
        len = 0
        f = self.first
        while f:
            len +=1
            f = f.succ
        return len

    def mean(self):               # Optional
        sum = 0
        f = self.first
        while f:
            sum += f.data
            f = f.succ
        return sum / self.length()

    def remove_last(self):        # Optional
        f = self.first
        if not f:
            raise ValueError
        while f.succ:
            fp = f
            f = f.succ
            if not f.succ:
                last = f.data
                fp.succ = None
        return last

    def remove(self, x):          # Compulsory
        f = self.first ; #ff = f.succ

        if f == None:
            return False
            #raise AttributeError("Empty list")
        ff = f.succ

        if f.succ == None:
            if f.data == x:
                self.first = None
                return True
            else:
                return False

        if f.data == x:
                #f = ff
                #f = f.succ
                self.first = ff
                return True

        while f.succ != None:
            if ff.data == x:
                f.succ = ff.succ
                return True
            elif ff.data !=x:
                f = f.succ ; ff = f.succ

        return False

    def count(self, x):           # Optional
        f = self.first
        return self._count(x, f)

    def _count(self, x, f):
            if f == None:
                return 0
            elif f.data == x:
                return 1 + self._count(x, f.succ)
            else:
                return self._count(x, f.succ)

    def to_list(self):            # Compulsory
        f = self.first
        return self._to_list(f)

    def _to_list(self, f):
        if f == None:
            return []
        else:
            return [f.data] + self._to_list(f.succ)

    def remove_all(self, x):      # Compulsory
        f = self.first
        if f == None:
           return 0
        else:
            return self._remove_all(x, f)

    def _remove_all(self, x, f):
        if f == None:
           return 0
        elif f.succ == None: #one node
            if f.data == x:
                self.first = None
                f = None
                return 1
            else:
                return 0
        elif f.data == x:
            self.first = f.succ
            return 1 + self._remove_all(x, f.succ)
        elif f.succ.data == x:
            f.succ = f.succ.succ
            return 1 + self._remove_all(x, f)
        else:
            return self._remove_all(x, f.succ)

    def __str__(self):            # Compulsary
        str = '('
        if self.first == None:
            return '()'

        for i in self:
            str += f'{i}, '
        return str[:-2] + ')'

    def copy2(self):               # Compulsary
        result = LinkedList()
        for x in self:
            result.insert(x)
        return result
    ''' Complexity for this implementation:
        List goes through one at a time and insert using recursion: O(n^2)
    '''

    def copy(self):               # Compulsary  # Should be more efficient
        result = LinkedList()
        f = self.first

        if f == None:
                return result

        def _copy(f):
            if f.succ == None:
                return result.Node(f.data, None)
            else:
                return result.Node(f.data, _copy(f.succ))

        result.first = _copy(f)

        return result
    ''' Complexity for this implementation:
    Data is already sorted we just need to insert into nodes O(n)
    '''

    def __getitem__(self, ind):   # Optional
        count = 0
        for x in self:
            if count == ind:
                return x
            count += 1
        else:
            raise IndexError("index out of range")

class Person:                     # Compulsory
    def __init__(self, name, pnr):
        self.name = name
        self.pnr = pnr

    def __str__(self):
        return f"{self.name}:{self.pnr}"

    def __It__(self, other): # < , >
        return self.name < other.name

    def __le__(self, other): # <= , >=
        return self.name <= other.name

    def __eq__(self, other): # =
        return self.name == other.name

def main():
    lst = LinkedList()
    for x in [1, 1, 1, 2, 3, 3, 2, 1, 9, 7]:
        lst.insert(x)
    lst.print()

    plist = LinkedList()
    p = Person("Oliver", '010830')
    q = Person("Blah", '214212')

    plist.insert(p)
    plist.insert(q)

    plist.print()

    # Test code:
    print('---------')

    print('str rep',str(lst))

if __name__ == '__main__':
    main()