import pandas as pd
import numpy as np
import tensorflow as tf
import scipy as sp
import scipy.stats

#from sklearn.preprocessing import StandardScaler
from data_preprocess import Preprocessor
from tools import Tools
from model import Model
from random import random, randint
import time

import shutil

PATH = "unpro"
CUT_OFF_Classes = 50
leaky_relu = lambda x: tf.maximum(0.2*x, x)

# PREPROCESS DATA
if PATH is "cf" or PATH is "concat":
    prepro = Preprocessor("cf_data.csv")
elif PATH is "unpro":
    prepro = Preprocessor("unprocessed_data.csv")
    print("unpro eingelesen")
else:
    prepro = Preprocessor("sv_data.csv")

# ONE PLAYER
#players, _ = prepro.get_list_with_most("Pitcher")
#prepro.select_movement("Windup")

# prepro.cut_file_to_pitcher(players[player])  # change_restore

prepro.remove_small_classes(CUT_OFF_Classes)

if PATH is not "concat":
    # data_raw = prepro.get_coord_arr(PATH+"_all_coord.npy")
    data_raw = np.load("interpolated.npy")
    print("data loaded")
else:
    data_raw = prepro.concat_with_second("sv_data.csv", PATH+"_all_coord.npy")

data_without_head = data_raw[:, :, :12, :]
data_new = Tools.normalize(data_without_head)

labels = prepro.get_labels()

def runscript(data_in, labels_string, BATCH_SZ=40, EPOCHS = 3, batch_nr_in_epoch = 100, align = False, act = tf.nn.relu, rate_dropout = 0,
        learning_rate = 0.0005, nr_layers = 4, n_hidden = 128, optimizer_type="adam", regularization=0, first_conv_filters=128, first_conv_kernel=9, second_conv_filter=128,
        second_conv_kernel=5, first_hidden_dense=128, second_hidden_dense=0, network = "adjustable conv1d"):

    #tic = time.time()

    tf.reset_default_graph()
    sess = tf.InteractiveSession()

    if align:
        data = Tools.align_frames(data_in, prepro.get_release_frame(60, 120), 60, 40)
    else:
        data= data_in

    # ONE PITCH TYPE
    # pitchi, _ = prepro.get_list_with_most("Pitch Type")
    # print("classe trained on:", pitchi[0])
    # prepro.set_labels(pitchi[0])  # change_restore

    # CONCAT
    # prepro.remove_small_classes(CUT_OFF_Classes)
    # data_raw = prepro.concat_with_second(SECOND) #prepro.get_coord_arr()  #np.load("coord_sv.npy")
    # data = Tools.normalize(data_raw)
    #data = np.load("coord_concat.npy")

    M,N,nr_joints,nr_coordinates = data.shape
    SEP = int(M*0.9)

    labels, unique = Tools.onehot_encoding(labels_string)

    nr_classes = len(np.unique(labels_string)) # hier
    ex_per_class = BATCH_SZ//nr_classes
    BATCHSIZE = nr_classes*ex_per_class
    # print("nr classes", nr_classes, "Batchsize", BATCHSIZE)
    # print("classes: ", unique)
    # print("data shape:", data.shape, "label_shape", labels.shape, labels_string.shape)

    # NET

    ind = np.random.permutation(len(data))
    train_ind = ind[:SEP]
    test_ind = ind[SEP:]

    train_x = data[train_ind]
    test_x = data[test_ind]
    train_t= labels[train_ind]
    test_t = labels[test_ind]
    labels_string_train = labels_string[train_ind]
    labels_string_test = labels_string[test_ind]

    index_liste = []
    for pitches in unique:
        index_liste.append(np.where(labels_string_train==pitches))

    len_test = len(test_x)
    len_train = len(train_x)
    # print("Test set size: ", len_test, " train set size: ", len_train)
    # print("Shapes of train_x", train_x.shape, "shape of test_x", test_x.shape)

    #toc = time.time()
    #print("Time before training", toc-tic)

    model = Model()

    x = tf.placeholder(tf.float32, (None, N, nr_joints, nr_coordinates), name = "input")

    y = tf.placeholder(tf.float32, (None, nr_classes))

    training = tf.placeholder_with_default(False, None)

    if network == "conv1d (256, 5) - conv1d(128, 3) - dense(nr_classes) - softmax":
        out, logits = model.best_in_cluster_concat53(x, nr_classes, training, rate_dropout, act)
    elif network == "adjustable conv1d":
        out, logits = model.conv1d_with_parameters(x, nr_classes, training, rate_dropout, act, first_conv_filters, first_conv_kernel, second_conv_filter,
        second_conv_kernel, first_hidden_dense, second_hidden_dense)
    elif network == "rnn with lstm_units and lstm_hidden_layers + 1 dense(nr_classes)":
        out, logits = model.RNN(x, nr_classes, n_hidden, nr_layers)
    elif network=="conv1d(256,5,2)-conv1d(256,3)-conv1d(128,3)-conv1d(1,1)-dense(1024)-dense(128),dense(nr_classes)":
        out, logits = model.conv1dnet(x, nr_classes, training, rate_dropout, act)
    elif network=="conv2d(256,5,2)-conv2d(256,3)-conv2d(128,3)-conv2d(1,1)-dense(1024)-dense(128),dense(nr_classes)":
        out, logits = model.conv2dnet(x, nr_classes, training, rate_dropout, act)
    else:
        print("ERROR, WRONG NETWORK INPUT")

    tv = tf.trainable_variables()

    loss_entropy = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=y, logits=logits))
    loss_regularization = regularization * tf.reduce_sum([ tf.nn.l2_loss(v) for v in tv ])
    # loss_maximum = tf.reduce_mean(tf.reduce_max(tf.nn.relu(y-out), axis = 1))
    loss = loss_entropy + loss_regularization #+  loss_maximum #0.001  loss_entropy +
    # loss = tf.reduce_mean(tf.pow(out-y, 2))
    # loss = tf.reduce_sum(tf.pow(out - y, 2)) + 0.5*regularization_cost
    if optimizer_type=="sgd":
        optimizer = tf.train.GradientDescentOptimizer(learning_rate).minimize(loss)
    elif optimizer_type=="adam":
        optimizer = tf.train.AdamOptimizer(learning_rate).minimize(loss)
    else:
        print("WRONG OPTIMIZER")

    sess.run(tf.global_variables_initializer())

    def balanced_batches(x, y, nr_classes):
        #print("balanced function: ", nr_classes)

        for j in range(batch_nr_in_epoch):
            # tic = time.time()
            liste=np.zeros((nr_classes, ex_per_class))
            for i in range(nr_classes):
                # print(j, i, np.random.choice(index_liste[i][0], ex_per_class))
                liste[i] = np.random.choice(index_liste[i][0], ex_per_class, replace=True)
            liste = liste.flatten().astype(int)
            #toc = time.time()
            #print("time to get batch ", toc-tic)
            yield j, x[liste], y[liste]

    acc_test  = []
    acc_balanced = []
    losses = []
    # Run session for EPOCH epochs
    for epoch in range(EPOCHS + 1):
        # tic2 = time.time()
        for i, batch_x, batch_t in balanced_batches(train_x, train_t, nr_classes):
            opt = sess.run(optimizer, {x: batch_x, y: batch_t, training: True})
        # toc2 = time.time()
        #print("one epoch train", toc2-tic2)

        # tic = time.time()

        loss_test, out_test = sess.run([loss,out], {x: test_x, y: test_t, training: False})
        #print("Loss test", loss_test)
        pitches_test = Tools.decode_one_hot(out_test, unique)
        #print("Accuracy test: ", Tools.accuracy(pitches_test, labels_string_test))
        acc_test.append(Tools.accuracy(pitches_test, labels_string_test))
        losses.append(loss_test)
        acc_balanced.append(Tools.balanced_accuracy(pitches_test, labels_string_test))

        # toc = time.time()
        # print("Time for test accuracy ", toc-tic)
        #Train Accuracy
        # out_train = sess.run(out, {x: train_x, y: train_t, training: False})
        # pitches_train = Tools.decode_one_hot(out_train, unique)
        # acc_train.append(Tools.accuracy(pitches_train, labels_string_train))
        # print(loss_test, acc_test[-1], acc_balanced[-1])

    # AUSGABE AM ENDE
    # losses = np.around(np.array(losses).astype(float), 2)
    # acc_test = np.around(acc_test, 2)
    # acc_train = np.around(acc_train, 2)
    # print("\n\n\n---------------------------------------------------------------------")
    # print("\n\nNEW PARAMETERS: ", BATCHSIZE, CUT_OFF_Classes , EPOCHS, act, align, batch_nr_in_epoch, rate_dropout
    #                      , PATH, learning_rate, len_train, n_hidden, nr_layers, network, nr_classes, nr_joints, optimizer_type, regularization, first_conv_filters, first_conv_kernel, second_conv_filter,
    #                      second_conv_kernel, first_hidden_dense, second_hidden_dense)
    # #Test Accuracy
    # print("Losses", losses)
    # print("Accuracys test: ", acc_test)
    # print("Accuracys train: ", acc_train)
    # print("\n\nMAXIMUM ACCURACY TEST: ", max(acc_test))
    # print("MAXIMUM ACCURACY TRAIN: ", max(acc_train))
    # print("Balanced test accuracy: ", Tools.balanced_accuracy(pitches_test, labels_string_test))
    # print("Balanced train accuracy: ", Tools.balanced_accuracy(pitches_train, labels_string_train))
    #
    # #print("Accuracy test by class: ", Tools.accuracy_per_class(pitches_test, labels_string_test))
    # print("True                Test                 ", unique)
    # # print(np.swapaxes(np.append([labels_string_test], [pitches_test], axis=0), 0,1))
    # for i in range(20):
    #     print('{:20}'.format(labels_string_test[i]), '{:20}'.format(pitches_test[i]), ['%.2f        ' % elem for elem in out_test[i]])

    # new = pd.read_csv("test_parameters.csv")
    #
    # #new.drop(new.columns[[0]], axis=1, inplace=True)
    # columns = new.columns.values.tolist()
    # #print(columns)
    # # print(len(columns))
    # # print("0, BATCHSIZE, CUT_OFF_Classes , EPOCHS, act, align, batch_nr_in_epoch, rate_dropout, PATH, max(acc_test), learning_rate, len_train, losses, n_hidden, nr_layers, network, nr_classes,                         nr_joints, acc_train, acc_test, optimizer_type, regularization, first_conv_filters, first_conv_kernel, second_conv_filter, second_conv_kernel, first_hidden_dense, second_hidden_dense")
    # # print(len(columns))
    # # print("Written to csv: ", BATCHSIZE, CUT_OFF_Classes , EPOCHS, act, align, batch_nr_in_epoch, rate_dropout
    # #                      , PATH, max(acc_test), learning_rate, len_train, losses, n_hidden, nr_layers, network, nr_classes,
    # #                      nr_joints, acc_train, acc_test)
    #
    # add = pd.DataFrame([[0, BATCHSIZE, CUT_OFF_Classes , EPOCHS, act, align, batch_nr_in_epoch, rate_dropout
    #                      , PATH, max(acc_test), learning_rate, len_train, losses, n_hidden, nr_layers, network, nr_classes,
    #                      nr_joints, acc_train, acc_test, optimizer_type, regularization, first_conv_filters, first_conv_kernel, second_conv_filter,
    #                      second_conv_kernel, first_hidden_dense, second_hidden_dense]], columns=columns)
    # concat = new.append(add, ignore_index = True)
    # concat.drop(concat.columns[[0]], axis=1, inplace=True)
    # concat.to_csv("test_parameters.csv")
    print(max(acc_test), max(acc_balanced))
    return max(acc_test), max(acc_balanced)

def individual():
    'Create a member of the population.'
    f = lambda x: np.random.choice(x)
    kernel_sizes = [3,5,7,9,11]
    filter_sizes = [0, 128, 256, 512, 1024]
    rates = [0.0001, 0.00025, 0.0005, 0.001]
    alignd = [True, False]
    dropout = [0, 0.6]
    act = [tf.nn.relu, leaky_relu]
    regularize = [0, 0.0005, 0.001, 0.005]
    return [f(act), f(dropout), f(alignd), f(rates), f(regularize), f(filter_sizes), f(kernel_sizes), f(filter_sizes), f(kernel_sizes), f(filter_sizes), f(filter_sizes)]

def population(count):
    """
    Create a number of individuals (i.e. a population).

    count: the number of individuals in the population
    length: the number of values per individual
    min: the minimum possible value in an individual's list of values
    max: the maximum possible value in an individual's list of values

    """
    return [ individual() for x in range(count) ]

def fitness(ind, target):
    acc, bala = runscript(data_new, labels, EPOCHS = 30, act = ind[0], rate_dropout=ind[1], align= ind[2], learning_rate=ind[3],
    regularization=ind[4], first_conv_filters=ind[5], first_conv_kernel=int(ind[6]), second_conv_filter=ind[7],
    second_conv_kernel=int(ind[8]), first_hidden_dense=ind[9], second_hidden_dense=ind[10], network = "adjustable conv1d") # np.sum(ind[6:10])
    return 2*target- acc - bala

def grade(pop):
    'Find average fitness for a population.'
    return np.array([fitness(x, target) for x in pop])

def evolve(pop, grades, target, retain=0.3, random_select=0.2, mutate=0.1): # 0.2, 0.05, 0.01
    #grades = np.array([fitness(x, target) for x in pop])
    print("\n unsorted")
    for g in grades:
        print(g)
    graded = [ (grades[i], pop[i]) for i in range(len(pop))]
    #print("\n fitness", graded)
    #grade_mean = np.mean(grades)
    sort = sorted(graded, key=lambda x: x[0])
    print("\n sorted")
    for i in sort:
        print(i)
    graded = [ x[1] for x in sorted(graded, key=lambda x: x[0])]
    retain_length = int(len(graded)*retain)
    parents = graded[:retain_length]
    # randomly add other individuals to
    # promote genetic diversity
    for ind in graded[retain_length:]:
        if random_select > random():
            parents.append(ind)
    # mutate some individuals
    for indi in parents:
        if mutate > random():
            pos_to_mutate = randint(0, len(indi)-1)
            lender = individual()
            # this mutation is not ideal, because it
            # restricts the range of possible values,
            # but the function is unaware of the min/max
            # values used to create the individuals,
            indi[pos_to_mutate] = lender[pos_to_mutate]
    # crossover parents to create children
    parents_length = len(parents)
    desired_length = len(pop) - parents_length
    children = []
    while len(children) < desired_length:
        male = randint(0, parents_length-1)
        female = randint(0, parents_length-1)
        if male != female:
            child = parents[male]
            #female = parents[female]
            half = int(len(parents[male]) / 2)
            indize = np.random.permutation(len(parents[male]))[:half]
            for i in indize:
                child[int(i)] = parents[female][int(i)]
            children.append(child)
    parents.extend(children)
    return parents

# from genetic import *
target = 1.0
p_count = 30
# i_length = 6

p = population(p_count)
for i in range(p_count):
    print(p[i])
grades = grade(p)
fitness_history = [np.mean(grades)]

for i in range(20):
    p = evolve(p, grades, target)
    print("\n new population \n ")
    for i in range(p_count):
        print(p[i])
    grades = grade(p)
    print("\n mean of grades", np.mean(grades), "Grades", grades)
    fitness_history.append(np.mean(grades))

print(fitness_history)
#runscript(data_raw, labels, network="adjustable conv1d", act=tf.nn.relu, rate_dropout=0)


# uncompyle6 version 3.7.4
# Python bytecode 3.5 (3350)
# Decompiled from: Python 3.6.9 (default, Apr 18 2020, 01:56:04)
# [GCC 8.4.0]
# Embedded file name: build/bdist.linux-x86_64/egg/noval/plugins/fileview.py
# Compiled at: 2019-08-16 02:55:35
# Size of source mod 2**32: 16000 bytes
from noval import GetApp, _
import os, tkinter as tk
from tkinter.messagebox import showerror
import noval.iface as iface, noval.plugin as plugin, noval.consts as consts, noval.constants as constants
from noval.ttkwidgets.treeviewframe import TreeViewFrame
from tkinter import ttk
import noval.util.utils as utils, noval.util.fileutils as fileutils, noval.util.strutils as strutils, noval.syntax.syntax as syntax, noval.menu as tkmenu
try:
    import tkSimpleDialog
except ImportError:
    import tkinter.simpledialog as tkSimpleDialog

_dummy_node_text = '...'
if utils.is_windows():
    from win32com.shell import shell, shellcon

    def GetDriveDisplayName(path):
        return shell.SHGetFileInfo(path, 0, shellcon.SHGFI_DISPLAYNAME)[1][3]

    def GetRoots():
        roots = []
        import ctypes, os
        for i in range(65, 91):
            vol = chr(i) + ':'
            if os.path.isdir(vol):
                roots.append([GetDriveDisplayName(vol), vol])

        return roots

else:

    def GetRoots():
        roots = []
        home_dir = wx.GetHomeDir()
        roots.append([_('Home directory'), home_dir])
        desktop_dir = home_dir + '/Desktop'
        roots.append([_('Desktop'), desktop_dir])
        roots.append(['/', '/'])
        return roots

def get_win_drives():
    roots = []
    import ctypes, os
    for i in range(65, 91):
        vol = chr(i) + ':'
        if os.path.isdir(vol):
            roots.append(vol)

    return roots

SAVE_OPEN_FOLDER_KEY = 'FileViewSaveFolder'
OPEN_FOLDER_KEY = 'FileViewLastFolder'

class BaseFileBrowser(TreeViewFrame):

    def __init__(self, master, show_hidden_files=False):
        TreeViewFrame.__init__(self, master, ['#0', 'kind', 'path'], displaycolumns=(0, ))
        self.default_extentsion = '.' + syntax.SyntaxThemeManager().GetLexer(GetApp().GetDefaultLangId()).GetDefaultExt()
        self.show_hidden_files = show_hidden_files
        self.tree['show'] = ('tree', )
        wb = GetApp()
        self.folder_icon = wb.GetImage('files/folder.gif')
        self.python_file_icon = wb.GetImage('files/python-file.gif')
        self.text_file_icon = wb.GetImage('files/text-file.gif')
        self.generic_file_icon = wb.GetImage('files/generic-file.gif')
        self.hard_drive_icon = wb.GetImage('files/hard-drive.gif')
        self.tree.column('#0', width=500, anchor=tk.W)
        self.tree.set('', 'kind', 'root')
        self.tree.set('', 'path', '')
        self.refresh_tree()
        self.tree.bind('<<TreeviewOpen>>', self.on_open_node)
        self.open_initial_folder()

    def open_initial_folder(self):
        if utils.profile_get_int(SAVE_OPEN_FOLDER_KEY, True):
            path = utils.profile_get(OPEN_FOLDER_KEY)
            if path:
                self.open_path_in_browser(path, True)

    def save_current_folder(self):
        path = self.get_selected_path()
        if not path:
            return
        if os.path.isfile(path):
            path = os.path.dirname(path)
        utils.profile_set(OPEN_FOLDER_KEY, path)

    def on_open_node(self, event):
        node_id = self.get_selected_node()
        if node_id:
            self.refresh_tree(node_id, True)

    def get_selected_node(self):
        nodes = self.tree.selection()
        assert len(nodes) <= 1
        if len(nodes) == 1:
            return nodes[0]
        else:
            return

    def get_selected_path(self):
        node_id = self.get_selected_node()
        if node_id:
            return self.tree.set(node_id, 'path')
        else:
            return

    def open_path_in_browser(self, path, see=True):

        def split(path):
            head, tail = os.path.split(path)
            if head == '' and tail == '':
                return []
            else:
                if head == path or tail == path:
                    return [path]
                if head == '':
                    return [tail]
                if tail == '':
                    return split(head)
                return split(head) + [tail]

        parts = split(path)
        current_node_id = ''
        current_path = ''
        while parts != []:
            current_path = os.path.join(current_path, parts.pop(0))
            for child_id in self.tree.get_children(current_node_id):
                child_path = self.tree.set(child_id, 'path')
                if child_path == current_path:
                    self.tree.item(child_id, open=True)
                    self.refresh_tree(child_id)
                    current_node_id = child_id
                    break

        if see and current_node_id:
            self.tree.selection_set(current_node_id)
            self.tree.focus(current_node_id)
            if self.tree.set(current_node_id, 'kind') == 'file':
                self.tree.see(self.tree.parent(current_node_id))
        else:
            self.tree.see(current_node_id)

    def refresh_tree(self, node_id='', opening=None):
        path = self.tree.set(node_id, 'path')
        if os.path.isfile(path):
            self.tree.set_children(node_id)
            self.tree.item(node_id, open=False)
        else:
            if node_id == '' or self.tree.item(node_id, 'open') or opening == True:
                if path != '' and not path.endswith(os.sep):
                    path += os.sep
                fs_children_names = self.listdir(path, self.show_hidden_files)
                tree_children_ids = self.tree.get_children(node_id)
                children = {}
                for child_id in tree_children_ids:
                    name = self.tree.item(child_id, 'text')
                    if name in fs_children_names:
                        children[name] = child_id

                for name in fs_children_names:
                    if name not in children:
                        children[name] = self.tree.insert(node_id, 'end')
                        self.tree.set(children[name], 'path', os.path.join(path, name))

                def file_order(name):
                    return (
                     os.path.isfile(os.path.join(path, name)), name.upper())

                ids_sorted_by_name = list(map(lambda key: children[key], sorted(children.keys(), key=file_order)))
                self.tree.set_children(node_id, *ids_sorted_by_name)
                for child_id in ids_sorted_by_name:
                    self.update_node_format(child_id)
                    self.refresh_tree(child_id)

            else:
                children_ids = self.tree.get_children(node_id)
        if len(children_ids) == 0:
            self.tree.insert(node_id, 'end', text=_dummy_node_text)

    def update_node_format(self, node_id):
        assert node_id != ''
        path = self.tree.set(node_id, 'path')
        if os.path.isdir(path) or path.endswith(':') or path.endswith(':\\'):
            self.tree.set(node_id, 'kind', 'dir')
            if path.endswith(':') or path.endswith(':\\'):
                img = self.hard_drive_icon
            else:
                img = self.folder_icon
        else:
            self.tree.set(node_id, 'kind', 'file')
            if path.lower().endswith('.py'):
                img = self.python_file_icon
            else:
                if path.lower().endswith('.txt') or path.lower().endswith('.csv'):
                    img = self.text_file_icon
                else:
                    img = self.generic_file_icon
                text = os.path.basename(path)
                if text == '':
                    if utils.is_windows():
                        if utils.is_py2():
                            name = GetDriveDisplayName(path).decode(utils.get_default_encoding())
                        elif utils.is_py3_plus():
                            name = GetDriveDisplayName(path)
                        text = name
                    else:
                        text = path.strip(os.sep)
        self.tree.item(node_id, text=' ' + text, image=img)
        self.tree.set(node_id, 'path', path)

    def listdir(self, path='', include_hidden_files=False):
        key = str.upper
        if path == '' and utils.is_windows():
            drives = get_win_drives()
            result = [drive + '\\' for drive in drives]
        else:
            if path == '':
                first_level = True
                path = '/'
            else:
                first_level = False
            result = [x for x in self.ListDir(path) if include_hidden_files or not fileutils.is_file_path_hidden(os.path.join(path, x))]
        if first_level:
            result = ['/' + x for x in result]
        if utils.is_py2():
            key = unicode.upper
        return sorted(result, key=key)

    def ListDir(self, path):
        for x in os.listdir(path):
            if utils.is_py2():
                try:
                    yield x.decode(utils.get_default_encoding())
                except:
                    yield x.decode('utf-8')

            else:
                yield x

class MainFileBrowser(BaseFileBrowser):

    def __init__(self, master, show_hidden_files=False):
        BaseFileBrowser.__init__(self, master, show_hidden_files)
        self.menu = tkmenu.PopupMenu(tk._default_root)
        self.menu.Append(constants.ID_REFRESH_PATH, _('&Refresh'), handler=self.RefreshPath)
        self.menu.Append(constants.ID_OPEN_CMD_PATH, _('Open Command Prompt here...'), handler=self.OpenPathInterminal)
        self.menu.Append(constants.ID_COPY_FULLPATH, _('Open Path in Explorer'), handler=self.OpenPathInexplower)
        self.menu.Append(constants.ID_ADD_FOLDER, _('&Create new folder'), handler=self.create_new_folder)
        self.menu.Append(constants.ID_CREATE_NEW_FILE, _('&Create new file'), handler=self.create_new_file)
        self.tree.bind('<3>', self.on_secondary_click, True)
        self.tree.bind('<Double-Button-1>', self.on_double_click, '+')

    def RefreshPath(self, node_id=None):
        selected_path = self.get_selected_path()
        node_id = self.get_selected_node()
        if not os.path.exists(selected_path):
            node_id = self.tree.parent(node_id)
        for child_id in self.tree.get_children(node_id):
            self.tree.delete(child_id)

        try:
            self.refresh_tree(node_id, True)
        except Exception as e:
            showerror(_('Error'), e)

    def OpenPathInexplower(self):
        selected_path = self.get_selected_path()
        fileutils.safe_open_file_directory(selected_path)

    def OpenPathInterminal(self):
        selected_path = self.get_selected_path()
        if os.path.isfile(selected_path):
            selected_path = os.path.dirname(selected_path)
        try:
            fileutils.open_path_in_terminator(selected_path)
        except RuntimeError as e:
            showerror(_('Error'), e)

    def create_new_file(self):
        selected_path = self.get_selected_path()
        if not selected_path:
            return
        if os.path.isdir(selected_path):
            parent_path = selected_path
        else:
            parent_path = os.path.dirname(selected_path)
        initial_name = self.get_proposed_new_file_name(parent_path, self.default_extentsion)
        name = tkSimpleDialog.askstring('File name', 'Provide filename', initialvalue=initial_name)
        if not name:
            return
        path = os.path.join(parent_path, name)
        if os.path.exists(path):
            showerror('Error', "The file '" + path + "' already exists", parent=GetApp())
            return
        open(path, 'w').close()
        self.open_path_in_browser(path, True)
        GetApp().GotoView(path)

    def create_new_folder(self):
        selected_path = self.get_selected_path()
        if not selected_path:
            return
        if os.path.isdir(selected_path):
            parent_path = selected_path
        else:
            parent_path = os.path.dirname(selected_path)
        initial_name = self.get_proposed_new_file_name(parent_path, '', 'newfoler')
        name = tkSimpleDialog.askstring(_('New folder'), 'Provide folder name', initialvalue=initial_name)
        if not name:
            return
        path = os.path.join(parent_path, name)
        try:
            os.mkdir(path)
        except Exception as e:
            showerror(_('Error'), str(e))
            return

        self.open_path_in_browser(path, True)

    def get_proposed_new_file_name(self, folder, extension, base='new_file'):
        if os.path.exists(os.path.join(folder, base + extension)):
            i = 2
            while True:
                name = base + '_' + str(i) + extension
                path = os.path.join(folder, name)
                if os.path.exists(path):
                    i += 1
                else:
                    return name

        else:
            return base + extension

    def on_secondary_click(self, event):
        node_id = self.tree.identify_row(event.y)
        if node_id:
            self.tree.selection_set(node_id)
            self.tree.focus(node_id)
            self.menu.tk_popup(event.x_root, event.y_root)

    def on_double_click(self, event):
        path = self.get_selected_path()
        if os.path.isfile(path):
            ext = strutils.get_file_extension(path)
            if utils.is_ext_supportable(ext):
                if utils.is_windows():
                    GetApp().GotoView(path, 0)
                else:
                    GetApp().GotoView(path, 0)
            else:
                try:
                    fileutils.start_file(path)
                except:
                    pass

            self.save_current_folder()
        elif os.path.isdir(path):
            self.refresh_tree(self.get_selected_node(), True)

class FileViewLoader(plugin.Plugin):
    plugin.Implements(iface.CommonPluginI)

    def Load(self):
        GetApp().MainFrame.AddView(consts.FILE_VIEW_NAME, MainFileBrowser, _('File View'), 'nw', default_position_key='B')


from flask import render_template
from app import app

@app.route("/")
@app.route("/index")
def index():
    user = {'username':'Vahab'}
    posts = [
        {
            'author':{'username':'John'},
            'body':'Weather is sunny!'
        },
        {
            'author':{'username':'Michael'},
            'body':'What a nice view!'
        },
        {
            'author':{'username':'Lisa'},
            'body':'Can we stay here longer?'
        }
    ]
    return render_template('index.html',title = 'Home',user = user,posts = posts)


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

import logging
from logging import handlers       #需要单独导入handlers函数
import time
logger = logging.getLogger(__name__)

size_log_file = 'size.log'
time_log_file = "timelog.log"

dh = handlers.RotatingFileHandler(filename=size_log_file,maxBytes=10,backupCount=3,encoding='utf-8')
#设定日志切割的方式，maxBytes为最大只保存10字节的内容0为不限制，超过10字节就切割备份，backupCount为只保存最新的3个10字节内容

th = handlers.TimedRotatingFileHandler(filename=time_log_file,when="S",interval=3,backupCount=3,encoding='utf-8')
#设定按时间来生成新的日志文件，when为按秒计算，interval为when的参数，按5秒分割，备份只留下3个
'''when参数是一个字符串。表示时间间隔的单位，不区分大小写。它有以下取值：
S 秒
M 分
H 小时
D 天
W 每星期（interval==0时代表星期一）
midnight 每天凌晨'''

formatter = logging.Formatter('%(asctime)s %(module)s:%(lineno)d %(message)s')

dh.setFormatter(formatter)     #设置格式
th.setFormatter(formatter)

#logger.addHandler(dh)     #启用按大小切割
logger.addHandler(th)      #启用按时间切割

logger.warning("test1")
time.sleep(2)
logger.warning("test12")
time.sleep(2)
logger.warning("test13")
time.sleep(2)
logger.warning("test14")
time.sleep(2)
logger.warning("test15")
time.sleep(2)
logger.warning("test16")
time.sleep(2)
logger.warning("test17")
time.sleep(2)
logger.warning("test18")


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

# In[1]:

def decorator_2(func):                             # Using Decorators to show the running time

    from time import perf_counter
    import inspect
    import contextlib
    import io
    counter = 0

    def inner_func(*args,**kwargs):

        nonlocal counter
        counter += 1
        with contextlib.redirect_stdout(io.StringIO()) as fun:
            start = perf_counter()
            func(*args,**kwargs)
            end = perf_counter()
        out = fun.getvalue()

        print(f'{func.__name__} has been called {counter} times and the execution time was {end-start} \nDESCRIPTION:\nName :{func.__name__} \nType:{type(func)} \nSign:{inspect.signature(func)} \nArgs: positional {args} \nkey=worded {kwargs} \nDoc :{func.__doc__} \nSource:{inspect.getsource(func)} \nOutput:{out}')

    return inner_func


"""ROSARIO VALERO MIRANDA - 1º DAW - PRACTICA7 - EJERCICIO 9
Escribe un programa que pida dos palabras las pase como parámetro a un
procedimiento y diga si riman o no. Si coinciden las tres últimas letras
tiene que decir que riman.
Si coinciden sólo las dos últimas tiene que decir que riman un poco y si no,
que no riman. """

def pide_palabras():
    print("Dime una palabra")
    palabra1=input()
    return palabra1

def pide_segunda_pal():
    print("Dime otra palabra")
    palabra2=input()
    return palabra2

def palabras_mastres(palabra1,palabra2):
    aux=False
    if len(palabra1) < 4 or len(palabra2) < 4:
        aux=True
    return aux

def palabras_riman(palabra1,palabra2):
    auz=False
    if palabra1[-3:] == palabra2[-3:]:
        aux=True
    return aux

def riman_poco(palabra1,palabra2):
    aux=False
    if palabra1[-2:] == palabra2[-2:]:
        aux=True
    return aux

def imprimir():
    if palabras_mastres(texto, texto1):
        print("Tu palabra tiene menos de 4 letras")
    elif palabras_riman(texto,texto1):
        print("Las palabras riman")
    elif riman_poco(texto, texto1):
        print("Las palabras riman poco")
    else:
        print("Las palabras no riman")

texto=pide_palabras()
texto1=pide_segunda_pal()
texto2=palabras_mastres(texto, texto1)
texto3=palabras_riman(texto, texto1)
texto4=riman_poco(texto, texto1)
print(imprimir())


from portmgr import command_list, bcolors, runCompose

def func(action):
    directory = action['directory']
    relative = action['relative']

    res = runCompose(["logs", "--follow", "--tail=200"])

    if res != 0:
        print("Error showing logs for " + relative + "!\n")

    return 0

command_list['l'] = {
    'hlp': 'Show logs',
    'ord': 'nrm',
    'fnc': func
}


"""
Apply CNMF to sima datasets
Adopted from
https://github.com/agiovann/Constrained_NMF/blob/master/demoCNMF.ipynb
by Andrea Giovannucci

(c) 2016 C. Schmidt-Hieber
GPLv3
"""

from __future__ import print_function

import sys
import os
import time
import subprocess
import multiprocessing as mp
import tempfile

import ipyparallel
from ipyparallel import Client

import numpy as np
from scipy.io import savemat, loadmat

from matplotlib import _cntr

import sima
from sima.misc import tifffile
from sima.ROI import ROIList

try:
    from . import utils
except ValueError:
    import utils

sys.path.append('../SPGL1_python_port')
try:
    import ca_source_extraction as cse
except ImportError:
    sys.stderr.write("Could not find cse module")

NCPUS = int(mp.cpu_count()/2)
NCPUS_PATCHES = 8

def tiffs_to_cnmf(haussio_data, mask=None, force=False):
    if not os.path.exists(haussio_data.dirname_comp + '_Y.npy') or force:
        sys.stdout.write('Converting to {0}... '.format(
            haussio_data.dirname_comp + '_Y*.npy'))
        sys.stdout.flush()
        t0 = time.time()
        if haussio_data.rawfile is None or not os.path.exists(
                haussio_data.rawfile):
            if mask is None:
                filenames = haussio_data.filenames
            else:
                if len(haussio_data.filenames) > mask.shape[0]:
                    mask_full = np.concatenate([
                        mask, np.ones((
                            len(haussio_data.filenames)-mask.shape[0])).astype(
                                np.bool)])
                else:
                    mask_full = mask
                filenames = [fn for fn, masked in zip(
                    haussio_data.filenames, mask_full) if not masked]
            tiff_sequence = tifffile.TiffSequence(filenames, pattern=None)
            tiff_data = tiff_sequence.asarray(memmap=True).astype(
                dtype=np.float32)
        else:
            if mask is not None:
                tiff_data = haussio_data.read_raw().squeeze().astype(
                    np.float32)[np.invert(mask), :, :]
            else:
                tiff_data = haussio_data.read_raw().squeeze().astype(
                    np.float32)

        tiff_data = np.transpose(tiff_data, (1, 2, 0))
        d1, d2, T = tiff_data.shape
        tiff_data_r = np.reshape(tiff_data, (d1*d2, T), order='F')
        np.save(haussio_data.dirname_comp + '_Y', tiff_data)
        np.save(haussio_data.dirname_comp + '_Yr', tiff_data_r)

        del tiff_data
        del tiff_data_r

        sys.stdout.write('took {0:.2f} s\n'.format(time.time()-t0))
        # 888s

def process_data(haussio_data, mask=None, p=2, nrois_init=400):
    fn_cnmf = haussio_data.dirname_comp + '_cnmf.mat'

    tiffs_to_cnmf(haussio_data, mask)
    sys.stdout.write('Loading from {0}... '.format(
        haussio_data.dirname_comp + '_Y*.npy'))
    Y = np.load(haussio_data.dirname_comp + '_Y.npy', mmap_mode='r')
    d1, d2, T = Y.shape

    if not os.path.exists(fn_cnmf):

        cse.utilities.stop_server()

        sys.stdout.flush()
        t0 = time.time()
        Yr = np.load(haussio_data.dirname_comp + '_Yr.npy', mmap_mode='r')
        sys.stdout.write('took {0:.2f} s\n'.format(time.time()-t0))

        # how to subdivide the work among processes
        n_pixels_per_process = d1*d2/NCPUS

        options = cse.utilities.CNMFSetParms(
            Y, NCPUS, K=nrois_init, p=p, gSig=[9, 9], ssub=2, tsub=2)
        options['preprocess_params']['n_processes'] = NCPUS
        options['preprocess_params'][
            'n_pixels_per_process'] =  n_pixels_per_process
        options['init_params']['nIter'] = 10
        options['init_params']['maxIter'] = 10
        options['init_params']['use_hals'] = True
        options['spatial_params']['n_processes'] = NCPUS
        options['spatial_params'][
            'n_pixels_per_process'] = n_pixels_per_process
        options['temporal_params']['n_processes'] = NCPUS
        options['temporal_params'][
            'n_pixels_per_process'] = n_pixels_per_process

        cse.utilities.start_server()

        t0 = time.time()
        sys.stdout.write("Preprocessing... ")
        sys.stdout.flush()
        Yr, sn, g, psx = cse.preprocess_data(Yr, **options['preprocess_params'])
        sys.stdout.write(' took {0:.2f} s\n'.format(time.time()-t0))
        # 224.94s
        # 2016-05-24: 146.30s

        t0 = time.time()
        sys.stdout.write("Initializing components... ")
        sys.stdout.flush()
        Ain, Cin, b_in, f_in, center = cse.initialize_components(
            Y, **options['init_params'])
        sys.stdout.write(' took {0:.2f} s\n'.format(time.time()-t0))
        # 2281.37s
        # 2016-05-24: 1054.72s

        t0 = time.time()
        sys.stdout.write("Updating spatial components... ")
        sys.stdout.flush()
        A, b, Cin = cse.update_spatial_components(
            Yr, Cin, f_in, Ain, sn=sn, **options['spatial_params'])
        sys.stdout.write(' took {0:.2f} s\n'.format(time.time()-t0))
        # 252.57s
        # 2016-05-24: 445.95s

        t0 = time.time()
        sys.stdout.write("Updating temporal components... ")
        sys.stdout.flush()
        C, f, S, bl, c1, neurons_sn, g, YrA = \
            cse.update_temporal_components(
                Yr, A, b, Cin, f_in, bl=None, c1=None, sn=None, g=None,
                **options['temporal_params'])
        sys.stdout.write(' took {0:.2f} s\n'.format(time.time()-t0))
        # 455.14s
        # 2016-05-24: 86.10s

        t0 = time.time()
        sys.stdout.write("Merging ROIs... ")
        sys.stdout.flush()
        A_m, C_m, nr_m, merged_ROIs, S_m, bl_m, c1_m, sn_m, g_m = \
            cse.merge_components(
                Yr, A, b, C, f, S, sn, options['temporal_params'],
                options['spatial_params'], bl=bl, c1=c1, sn=neurons_sn, g=g,
                thr=0.7, mx=100, fast_merge=True)
        sys.stdout.write(' took {0:.2f} s\n'.format(time.time()-t0))
        # 702.55s
        # 2016-05-24: 11.75s

        t0 = time.time()
        sys.stdout.write("Updating spatial components... ")
        sys.stdout.flush()
        A2, b2, C2 = cse.update_spatial_components(
            Yr, C_m, f, A_m, sn=sn, **options['spatial_params'])
        sys.stdout.write(' took {0:.2f} s\n'.format(time.time()-t0))
        # 77.16s
        # 2016-05-24: 99.22s

        t0 = time.time()
        sys.stdout.write("Updating temporal components... ")
        sys.stdout.flush()
        C2, f2, S2, bl2, c12, neurons_sn2, g21, YrA = \
            cse.update_temporal_components(
                Yr, A2, b2, C2, f, bl=None, c1=None, sn=None, g=None,
                **options['temporal_params'])
        sys.stdout.write(' took {0:.2f} s\n'.format(time.time()-t0))
        # 483.41s
        # 2016-05-24: 74.81s

        # A: spatial components (ROIs)
        # C: denoised [Ca2+]
        # YrA: residuals ("noise")
        # S: Spikes
        savemat(fn_cnmf, {"A": A2, "C": C2, "YrA": YrA, "S": S2, "bl": bl2})
    else:
        resdict = loadmat(fn_cnmf)
        A2 = resdict["A"]
        C2 = resdict["C"]
        YrA = resdict["YrA"]
        S2 = resdict["S"]
        bl2 = resdict["bl"]

    proj_fn = haussio_data.dirname_comp + "_proj.npy"
    if not os.path.exists(proj_fn):
        zproj = utils.zproject(np.transpose(Y, (2, 0, 1)))
        np.save(proj_fn, zproj)
    else:
        zproj = np.load(proj_fn)

    # DF_F, DF = cse.extract_DF_F(Y.reshape(d1*d2, T), A2, C2)

    t0 = time.time()
    sys.stdout.write("Ordering components... ")
    sys.stdout.flush()
    A_or, C_or, srt = cse.order_components(A2, C2)
    sys.stdout.write(' took {0:.2f} s\n'.format(time.time()-t0))

    cse.utilities.stop_server()

    polygons = contour(A2, d1, d2, thr=0.9)
    rois = ROIList([sima.ROI.ROI(polygons=poly) for poly in polygons])

    return rois, C2, zproj, S2, Y, YrA

def process_data_patches(
        haussio_data, mask=None, p=2, nrois_init=400, roi_iceberg=0.9):
    fn_cnmf = haussio_data.dirname_comp + '_cnmf.mat'

    tiffs_to_cnmf(haussio_data, mask)
    sys.stdout.write('Loading from {0}... '.format(
        haussio_data.dirname_comp + '_Y*.npy'))
    Y = np.load(haussio_data.dirname_comp + '_Y.npy', mmap_mode='r')
    d1, d2, T = Y.shape

    if not os.path.exists(fn_cnmf):

        cse.utilities.stop_server()

        sys.stdout.flush()
        t0 = time.time()
        fname_new = haussio_data.dirname_comp + '_Yr.npy'
        Yr = np.load(fname_new, mmap_mode='r')
        sys.stdout.write('took {0:.2f} s\n'.format(time.time()-t0))

        # how to subdivide the work among processes
        n_pixels_per_process = d1*d2/NCPUS_PATCHES

        options = cse.utilities.CNMFSetParms(
            Y, NCPUS, K=np.max((int(nrois_init/NCPUS), 1)), p=p, gSig=[9, 9],
            ssub=1, tsub=1)
        options['preprocess_params']['n_processes'] = NCPUS
        options['preprocess_params'][
            'n_pixels_per_process'] =  n_pixels_per_process
        options['init_params']['nIter'] = 10
        options['init_params']['maxIter'] = 10
        options['init_params']['use_hals'] = True
        options['spatial_params']['n_processes'] = NCPUS
        options['spatial_params'][
            'n_pixels_per_process'] = n_pixels_per_process
        options['temporal_params']['n_processes'] = NCPUS
        options['temporal_params'][
            'n_pixels_per_process'] = n_pixels_per_process
        options['temporal_params']['backend'] = 'ipyparallel'
        rf = 16  # half-size of the patches in pixels. rf=25, patches are 50x50
        stride = 2  # amounpl of overlap between the patches in pixels
        cse.utilities.start_server()
        cl = Client()
        dview = cl[:len(cl)]

        t0 = time.time()
        sys.stdout.write("CNMF patches... ")
        sys.stdout.flush()
        A_tot, C_tot, b, f, sn_tot, opt_out = cse.map_reduce.run_CNMF_patches(
            fname_new, (d1, d2, T), options, rf=rf, stride=stride,
            n_processes=NCPUS_PATCHES, dview=dview, memory_fact=4.0)
        sys.stdout.write(' took {0:.2f} s\n'.format(time.time()-t0))

        options = cse.utilities.CNMFSetParms(
            Y, NCPUS, K=A_tot.shape[-1], p=p, gSig=[9, 9], ssub=1, tsub=1)
        pix_proc = np.minimum(
            np.int((d1*d2)/NCPUS/(T/2000.)),
            np.int((d1*d2)/NCPUS))  # regulates the amount of memory used
        options['preprocess_params']['n_processes'] = NCPUS
        options['preprocess_params'][
            'n_pixels_per_process'] =  n_pixels_per_process
        options['init_params']['nIter'] = 10
        options['init_params']['maxIter'] = 10
        options['init_params']['use_hals'] = True
        options['spatial_params']['n_processes'] = NCPUS
        options['temporal_params']['n_processes'] = NCPUS
        options['spatial_params']['n_pixels_per_process'] = pix_proc
        options['temporal_params']['n_pixels_per_process'] = pix_proc

        t0 = time.time()
        sys.stdout.write("Merging ROIs... ")
        sys.stdout.flush()
        A_m, C_m, nr_m, merged_ROIs, S_m, bl_m, c1_m, sn_m, g_m = \
            cse.merge_components(
                Yr, A_tot, [], np.array(C_tot), [], np.array(C_tot), [],
                options['temporal_params'],
                options['spatial_params'], thr=options['merging']['thr'],
                mx=np.Inf)
        sys.stdout.write(' took {0:.2f} s\n'.format(time.time()-t0))

        t0 = time.time()
        sys.stdout.write("Updating spatial components... ")
        sys.stdout.flush()
        A2, b2, C2 = cse.spatial.update_spatial_components(
            Yr, C_m, f, A_m, sn=sn_tot, **options['spatial_params'])
        sys.stdout.write(' took {0:.2f} s\n'.format(time.time()-t0))
        # 77.16s
        # 2016-05-24: 99.22s

        t0 = time.time()
        sys.stdout.write("Updating temporal components... ")
        sys.stdout.flush()
        C2, f2, S2, bl2, c12, neurons_sn2, g21, YrA = \
            cse.temporal.update_temporal_components(
                Yr, A2, b2, C2, f, bl=None, c1=None, sn=None, g=None,
                **options['temporal_params'])
        sys.stdout.write(' took {0:.2f} s\n'.format(time.time()-t0))
        # 483.41s
        # 2016-05-24: 74.81s

        # A: spatial components (ROIs)
        # C: denoised [Ca2+]
        # YrA: residuals ("noise")
        # S: Spikes
        savemat(fn_cnmf, {"A": A2, "C": C2, "YrA": YrA, "S": S2, "bl": bl2})
    else:
        resdict = loadmat(fn_cnmf)
        A2 = resdict["A"]
        C2 = resdict["C"]
        YrA = resdict["YrA"]
        S2 = resdict["S"]
        bl2 = resdict["bl"]

    proj_fn = haussio_data.dirname_comp + "_proj.npy"
    if not os.path.exists(proj_fn):
        zproj = utils.zproject(np.transpose(Y, (2, 0, 1)))
        np.save(proj_fn, zproj)
    else:
        zproj = np.load(proj_fn)

    # DF_F, DF = cse.extract_DF_F(Y.reshape(d1*d2, T), A2, C2)

    # t0 = time.time()
    # sys.stdout.write("Ordering components... ")
    # sys.stdout.flush()
    # A_or, C_or, srt = cse.order_components(A2, C2)
    # sys.stdout.write(' took {0:.2f} s\n'.format(time.time()-t0))

    cse.utilities.stop_server()

    polygons = contour(A2, d1, d2, thr=roi_iceberg)
    rois = ROIList([sima.ROI.ROI(polygons=poly) for poly in polygons])

    return rois, C2, zproj, S2, Y, YrA

def contour(A, d1, d2, thr=None):
    # Adopted from https://github.com/agiovann/Constrained_NMF
    from scipy.sparse import issparse
    if issparse(A):
        A = np.array(A.todense())
    else:
        A = np.array(A)

    d, nr = np.shape(A)

    x, y = np.mgrid[:d1, :d2]

    coordinates = []
    for i in range(nr):
        indx = np.argsort(A[:, i], axis=None)[::-1]
        cumEn = np.cumsum(A[:, i].flatten()[indx]**2)
        cumEn /= cumEn[-1]
        Bvec = np.zeros(d)
        Bvec[indx] = cumEn
        Bmat = np.reshape(Bvec, (d1, d2), order='F')
        cntr = _cntr.Cntr(y, x, Bmat)
        cs = cntr.trace(thr)
        if len(cs) > 0:
            coordinates.append(cs[0])
        else:
            coordinates.append([[0, 0, 0], [0, 0, 0], [0, 0, 0]])

    return coordinates


import torch
import torch.nn as nn
import torch.nn.parallel
import torch.utils.data
import torch.nn.functional as F

from source.base import utils
import numpy as np
input_dims_per_point = 3

class STN(nn.Module):
    def __init__(self, net_size_max=1024, num_scales=1, num_points=500, dim=3, sym_op='max'):
        super(STN, self).__init__()

        self.net_size_max = net_size_max
        self.dim = dim
        self.sym_op = sym_op
        self.num_scales = num_scales
        self.num_points = num_points

        self.conv1 = torch.nn.Conv1d(self.dim, 64, 1)
        self.conv2 = torch.nn.Conv1d(64, 128, 1)
        self.conv3 = torch.nn.Conv1d(128, self.net_size_max, 1)
        self.mp1 = torch.nn.MaxPool1d(num_points)

        self.fc1 = nn.Linear(self.net_size_max, int(self.net_size_max / 2))
        self.fc2 = nn.Linear(int(self.net_size_max / 2), int(self.net_size_max / 4))
        self.fc3 = nn.Linear(int(self.net_size_max / 4), self.dim*self.dim)

        self.bn1 = nn.BatchNorm1d(64)
        self.bn2 = nn.BatchNorm1d(128)
        self.bn3 = nn.BatchNorm1d(self.net_size_max)
        self.bn4 = nn.BatchNorm1d(int(self.net_size_max / 2))
        self.bn5 = nn.BatchNorm1d(int(self.net_size_max / 4))

        if self.num_scales > 1:
            self.fc0 = nn.Linear(self.net_size_max * self.num_scales, self.net_size_max)
            self.bn0 = nn.BatchNorm1d(self.net_size_max)

    def forward(self, x):
        batch_size = x.size()[0]
        x = F.relu(self.bn1(self.conv1(x)))
        x = F.relu(self.bn2(self.conv2(x)))
        x = F.relu(self.bn3(self.conv3(x)))

        # symmetric operation over all points
        if self.num_scales == 1:
            x = self.mp1(x)
        else:
            x_scales = x.new_empty(x.size(0), self.net_size_max * self.num_scales, 1)
            for s in range(self.num_scales):
                x_scales[:, s*self.net_size_max:(s+1)*self.net_size_max, :] = \
                    self.mp1(x[:, :, s*self.num_points:(s+1)*self.num_points])
            x = x_scales

        x = x.view(-1, self.net_size_max*self.num_scales)

        if self.num_scales > 1:
            x = F.relu(self.bn0(self.fc0(x)))

        x = F.relu(self.bn4(self.fc1(x)))
        x = F.relu(self.bn5(self.fc2(x)))
        x = self.fc3(x)

        iden = torch.eye(self.dim, dtype=x.dtype, device=x.device).view(1, self.dim*self.dim).repeat(batch_size, 1)
        x = x + iden
        x = x.view(-1, self.dim, self.dim)
        return x

class LMIModel(nn.Module):  # basing on P2S and PointNet
    def __init__(self, net_size_max=1024, num_points=200,
                 sub_sample_size=1000, k=10):
        super(LMIModel, self).__init__()

        self.net_size_max = net_size_max
        self.num_points = num_points
        self.use_point_stn = False
        self.sub_sample_size = sub_sample_size
        self.k = k
        self.point_stn = STN(net_size_max=net_size_max, num_scales=1,
                        num_points=self.num_points + self.sub_sample_size, dim=3, sym_op='max')
        self.conv0a_patch = torch.nn.Conv1d(3, 64, 1)
        self.bn0a_patch = nn.BatchNorm1d(64)
        self.conv0b_patch = torch.nn.Conv1d(64, 64, 1)
        self.bn0b_patch = nn.BatchNorm1d(64)

        self.conv0c_patch = torch.nn.Conv1d(64, 128, 1)
        self.bn0c_patch = nn.BatchNorm1d(128)
        self.conv0d_patch = torch.nn.Conv1d(128, 256, 1)
        self.bn0d_patch = nn.BatchNorm1d(256)

        self.conv0a_shape = torch.nn.Conv1d(3, 64, 1)
        self.conv0b_shape = torch.nn.Conv1d(64, 64, 1)
        self.bn0a_shape = nn.BatchNorm1d(64)
        self.bn0b_shape = nn.BatchNorm1d(64)

        self.k_neighbour_mp_patch = torch.nn.MaxPool1d(kernel_size=self.k + 1, stride=self.k + 1)
        self.conv1b_patch = torch.nn.Conv1d(256, 128, 1)
        self.bn1b_patch = nn.BatchNorm1d(128)

        self.conv1c_patch = torch.nn.Conv1d(128, 64, 1)
        self.bn1c_patch = nn.BatchNorm1d(64)

        self.conv1_local = torch.nn.Conv1d(128, 128, 1)
        self.conv2_local = torch.nn.Conv1d(128, 128, 1)
        self.conv3_local = torch.nn.Conv1d(128, 1024, 1)
        self.bn1_pn_local = nn.BatchNorm1d(128)
        self.bn2_pn_local = nn.BatchNorm1d(128)
        self.bn3_pn_local = nn.BatchNorm1d(1024)

        self.conv1_global = torch.nn.Conv1d(64, 64, 1)
        self.conv2_global = torch.nn.Conv1d(64, 128, 1)
        self.conv3_global = torch.nn.Conv1d(128, 1024, 1)
        self.bn1_pn_global = nn.BatchNorm1d(64)
        self.bn2_pn_global = nn.BatchNorm1d(128)
        self.bn3_pn_global = nn.BatchNorm1d(1024)

        self.mp1_local = torch.nn.MaxPool1d(self.num_points)
        self.mp1_global = torch.nn.MaxPool1d(self.sub_sample_size)

        self.fc1_local = nn.Linear(2048, 1024)
        self.bn1_local = nn.BatchNorm1d(1024)
        self.fc2_local = nn.Linear(1024, 1024)
        self.bn2_local = nn.BatchNorm1d(1024)
        self.fc1_global = nn.Linear(2048, 1024)
        self.bn1_global = nn.BatchNorm1d(1024)
        self.fc2_global = nn.Linear(1024, 1024)
        self.bn2_global = nn.BatchNorm1d(1024)

        self.conb_local_conv1 = torch.nn.Conv1d(1152, 512, 1)
        self.conb_local_conv2 = torch.nn.Conv1d(512, 256, 1)
        self.conb_local_bn1 = nn.BatchNorm1d(512)
        self.conb_local_bn2 = nn.BatchNorm1d(256)

        self.conb_global_conv1 = torch.nn.Conv1d(1088, 512, 1)
        self.conb_global_conv2 = torch.nn.Conv1d(512, 256, 1)
        self.conb_global_bn1 = nn.BatchNorm1d(512)
        self.conb_global_bn2 = nn.BatchNorm1d(256)

        self.fc_last_1 = nn.Linear(512, 256)
        self.bn_last_1 = nn.BatchNorm1d(256)

        self.fc_last_2 = nn.Linear(256, 128)
        self.bn_last_2 = nn.BatchNorm1d(128)

        self.fc_last_3 = nn.Linear(128, 1)

    def forward(self, x):
        patch_points_knn = x['patch_points_knn'].transpose(1, 2)
        shape_points = x['shape_points'].transpose(1, 2)
        shape_query_point = x['imp_surf_query_point_ms'].unsqueeze(2)

        patch_points_knn -= shape_query_point.expand(patch_points_knn.shape)
        shape_points -= shape_query_point.expand(shape_points.shape)

        #point and local feature module
        patch_point_self = patch_points_knn[:, :, 0::(self.k + 1)]
        all_point = torch.cat((patch_point_self, shape_points), axis=2)
        trans_pt = self.point_stn(all_point)
        patch_points_knn = torch.bmm(trans_pt, patch_points_knn)
        shape_points = torch.bmm(trans_pt, shape_points)

        patch_points_knn = F.relu(self.bn0a_patch(self.conv0a_patch(patch_points_knn)))
        patch_points_knn = F.relu(self.bn0b_patch(self.conv0b_patch(patch_points_knn)))
        patch_point_feature_self = patch_points_knn[:, :, 0::(self.k + 1)]
        patch_points_knn = F.relu(self.bn0c_patch(self.conv0c_patch(patch_points_knn)))
        patch_points_knn = F.relu(self.bn0d_patch(self.conv0d_patch(patch_points_knn)))
        patch_point_feature = self.k_neighbour_mp_patch(patch_points_knn)
        patch_point_feature = F.relu(self.bn1b_patch(self.conv1b_patch(patch_point_feature)))
        patch_point_feature = F.relu(self.bn1c_patch(self.conv1c_patch(patch_point_feature)))

        shape_point_feature = F.relu(self.bn0a_shape(self.conv0a_shape(shape_points)))
        shape_point_feature = F.relu(self.bn0b_shape(self.conv0b_shape(shape_point_feature)))
        patch_point_feature = torch.cat((patch_point_feature, patch_point_feature_self), axis=1)
        patch_local_feature = patch_point_feature
        shape_local_feature = shape_point_feature

        #global feature module
        patch_point_feature = F.relu(self.bn1_pn_local(self.conv1_local(patch_point_feature)))
        patch_point_feature = F.relu(self.bn2_pn_local(self.conv2_local(patch_point_feature)))
        patch_point_feature = self.bn3_pn_local(self.conv3_local(patch_point_feature))

        shape_point_feature = F.relu(self.bn1_pn_global(self.conv1_global(shape_point_feature)))
        shape_point_feature = F.relu(self.bn2_pn_global(self.conv2_global(shape_point_feature)))
        shape_point_feature = self.bn3_pn_global(self.conv3_global(shape_point_feature))

        patch_features = self.mp1_local(patch_point_feature).squeeze()
        shape_features = self.mp1_global(shape_point_feature).squeeze()

        global_feature = torch.cat((patch_features, shape_features), dim=1)
        patch_features = F.relu(self.bn1_local(self.fc1_local(global_feature)))
        patch_features = F.relu(self.bn2_local(self.fc2_local(patch_features)))

        shape_features = F.relu(self.bn1_global(self.fc1_global(global_feature)))
        shape_features = F.relu(self.bn2_global(self.fc2_global(shape_features)))

        #indicator prediction module
        patch_features = patch_features.view(-1, 1024, 1).repeat(1, 1, self.num_points)
        patch_features = torch.cat((patch_features, patch_local_feature), axis=1)
        shape_features = shape_features.view(-1, 1024, 1).repeat(1, 1, self.sub_sample_size)
        shape_features = torch.cat((shape_features, shape_local_feature), axis=1)
        patch_features = F.relu(self.conb_local_bn1(self.conb_local_conv1(patch_features)))
        patch_features = F.relu(self.conb_local_bn2(self.conb_local_conv2(patch_features)))
        patch_features = patch_features.sum(axis=2) ##[50, 256]

        shape_features = F.relu(self.conb_global_bn1(self.conb_global_conv1(shape_features)))
        shape_features = F.relu(self.conb_global_bn2(self.conb_global_conv2(shape_features))) ##[50, 256, 1000]
        shape_features = shape_features.sum(axis=2)  ##[50, 256]

        total_feature = torch.cat((patch_features,  shape_features), dim=1).squeeze() ##[50, 512]
        indicator = F.relu(self.bn_last_1(self.fc_last_1(total_feature)))
        indicator = F.relu(self.bn_last_2(self.fc_last_2(indicator)))
        indicator = self.fc_last_3(indicator)

        return indicator


from django.http import request
from django.urls  import reverse
from django.http.request import HttpRequest
from django.shortcuts import render, redirect
from django.http import HttpResponse, HttpResponseRedirect
from django.contrib.auth.decorators import login_required
from .models import Benificial,User
from datetime import datetime, timedelta
from functools import wraps
from adminportal.models import Addvaccines
from django.db.models import Q
from adminportal.views import slot_dict
from django.core.mail import send_mail
from django.core.mail import EmailMessage
# Create your views here.

def is_verified(function):
    @wraps(function)
    def wrap(request, *args, **kwargs):
        #not a first time user
        if Benificial.objects.filter(user=request.user).exists():
            benificial = Benificial.objects.get(user=request.user)
            #have registered for the vaccine
            if benificial.is_registered:
                if benificial.is_delivered and benificial.slot_timing<=datetime.now():

                    # got vaccinated , for second dose after 60 days
                    if benificial.slot_timing + timedelta(60)<=datetime.now():
                        benificial.slot_timing = None
                        benificial.is_delivered = False
                        benificial.is_registered = False
                        benificial.registration_timing = None
                        benificial.save()

                    else:
                        expiry = benificial.slot_timing.date() + timedelta(60)
                        message = 'wait till '+ expiry.strftime("%d-%b-%Y ") + ' to register again'
                        return render(request,'error.html',{'message':message})
                #slot is not provided or upcoming
                else:
                    return render(request,'error.html',{'message':'You Are already registered. You will get a mail when you are allotted a slot'})
        return function(request, *args, **kwargs)
    return wrap

@login_required
@is_verified
def register(request):
    roll_number = request.user.last_name
    contact_1 = None
    contact_2 = None
    benificial = None
    try:
        benificial = Benificial.objects.get(user=request.user)
        roll_number = benificial.roll_number
        contact_1 = benificial.contact_1
        contact_2 = benificial.contact_2
    except:
        print("first time")
    if request.method=='POST':
        if benificial is not None:
            benificial.roll_number=request.POST['rollNumber']
            benificial.is_registered=True
            benificial.registration_timing=datetime.now()
            benificial.contact_1=request.POST['contact_1']
            benificial.contact_2=request.POST['contact_2']
            benificial.save()
        else:
            benificial=Benificial.objects.create(
                user=request.user,
                roll_number=request.POST['rollNumber'],
                is_registered=True,
                registration_timing=datetime.now(),
                contact_1=request.POST['contact_1'],
                contact_2=request.POST['contact_2']
            )
        try:
            available_slot = Addvaccines.objects.filter(
                Q(date__gt=datetime.now()) & Q(extra_vaccine__gte=1)
            ).order_by('date').order_by('slot')[0]
            benificial.is_delivered=True
            benificial.slot_timing=datetime.combine(available_slot.date,slot_dict[str(available_slot.slot)])
            benificial.save()
            available_slot.extra_vaccine=available_slot.extra_vaccine-1
            available_slot.save()
            s=["9 to 12", "12 to 3", "3 to 5"]
            email = EmailMessage(
                subject='vaccine lag gyi?',
                body="your vaccine slot is "+s[int(available_slot.slot)]+" "+str(available_slot.date),
                from_email='swc@iitg.ac.in',
                to=[benificial.user.username],
            )
            email.content_subtype = 'html'
            try:
                email.send(fail_silently=False)
                return HttpResponseRedirect(reverse('apply:success'))
            except Exception:
                print('errorr')

        except:
            print("none")
        return render(request,'error.html',{'message':'You Have successfully registered. You will get a mail when you are allotted a slot'})
    return render(request,'register.html',{'roll_number':roll_number,'contact_1':contact_1,'contact_2':contact_2})


from django.contrib import admin
from tasks.models import Task, TaskSet, Stalker, Active

from easy_select2 import select2_modelform

class TaskAdmin(admin.ModelAdmin):
    list_display = ['id', 'title', 'task_set', 'public', 'type']
    search_fields = ['id', 'title', 'text', 'example_solution']
    list_filter = ['type', 'public', 'task_set']

    form = select2_modelform(Task)

admin.site.register(Task, TaskAdmin)

class TaskSetAdmin(admin.ModelAdmin):
    list_display = ['id', 'title', 'public']
    search_fields = ['id', 'title']
    list_filter = ['public']

admin.site.register(TaskSet, TaskSetAdmin)

class ActiveAdmin(admin.ModelAdmin):
    list_display = ['user', 'task', 'task_set']
    search_fields = ['user__username', 'task__id', 'task_set__id']
    list_filter = ['task_set']

    form = select2_modelform(Active)

admin.site.register(Active, ActiveAdmin)

class StalkerAdmin(admin.ModelAdmin):
    list_display = ['task', 'user', 'seen']
    search_fields = ['task__id', 'task__task_set__id', 'user__username']
    list_filter = ['task__task_set']

    form = select2_modelform(Active)

admin.site.register(Stalker, StalkerAdmin)


from enum import Enum, auto

import numpy as np

from qibolab.instruments.qblox.q1asm import (
    Block,
    Program,
    Register,
    convert_frequency,
    convert_gain,
    convert_offset,
    convert_phase,
)
from qibolab.sweeper import Parameter, Sweeper

class QbloxSweeperType(Enum):
    """An enumeration for the different types of sweepers supported by qblox.

    - frequency: sweeps pulse frequency by adjusting the sequencer `nco_freq` with q1asm command `set_freq`.
    - gain: sweeps sequencer gain by adjusting the sequencer `gain_awg_path0` and `gain_awg_path1` with q1asm command
      `set_awg_gain`. Since the gain is a parameter between -1 and 1 that multiplies the samples of the waveforms
      before they are fed to the DACs, it can be used to sweep the pulse amplitude.
    - offset: sweeps sequencer offset by adjusting the sequencer `offset_awg_path0` and `offset_awg_path1` with q1asm
      command `set_awg_offs`
    - start: sweeps pulse start.
    - duration: sweeps pulse duration.
    """

    frequency = auto()
    gain = auto()
    offset = auto()
    start = auto()
    duration = auto()

    number = auto()  # internal
    relative_phase = auto()  # not implemented yet
    time = auto()  # not implemented yet

class QbloxSweeper:
    """A custom sweeper object with the data and functionality required by qblox instruments.

    It is responsible for generating the q1asm code required to execute sweeps in a sequencer. The object can be
    initialised with either:

    - a :class:`qibolab.sweepers.Sweeper` using the :func:`qibolab.instruments.qblox.QbloxSweeper.from_sweeper`, or
    - a range of values and a sweeper type (:class:`qibolab.instruments.qblox.QbloxSweeperType`)

    Like most FPGAs, qblox FPGAs do not support floating point arithmetics. All parameters that can be manipulated in
    real time within the FPGA are represented as two's complement integers.

    Attributes:
        type (:class:`qibolab.instruments.qblox.QbloxSweeperType`): the type of sweeper
        name (str): a name given for the sweep that is later used within the q1asm code to identify the loops.
        register (:class:`qibolab.instruments.qblox_q1asm.Register`): the main Register (q1asm variable) used in the loop.
        aux_register (:class:`qibolab.instruments.qblox_q1asm.Register`): an auxialiry Register requried in duration
            sweeps.
        update_parameters (Bool): a flag to instruct the sweeper to update the paramters or not depending on whether
            a parameter of the sequencer needs to be swept or not.

    Methods:
        block(inner_block: :class:`qibolab.instruments.qblox_q1asm.Block`): generates the block of q1asm code that implements
            the sweep.
    """

    FREQUENCY_LIMIT = 500e6

    def __init__(
        self,
        program: Program,
        rel_values: list,
        type: QbloxSweeperType = QbloxSweeperType.number,
        add_to: float = 0,
        multiply_to: float = 1,
        name: str = "",
    ):
        """Creates an instance from a range of values and a sweeper type (:class:`qibolab.instruments.qblox.QbloxSweeperType`).

        Args:
            program (:class:`qibolab.instruments.qblox_q1asm.Program`): a program object representing the q1asm program
                of a sequencer.
            rel_values (list): a list of values to iterate over. Currently qblox only supports a list of equally spaced
                values, like those created with `np.arange(start, stop, step)`. These values are considered relative
                values. They will later be added to the `add_to` parameter and multiplied to the `multiply_to`
                parameter.
            type (:class:`qibolab.instruments.qblox.QbloxSweeperType`): the type of sweeper.
            add_to (float): a value to be added to each value of the range of values defined in `sweeper.values` or
                `rel_values`.
            multiply_to (float): a value to be multiplied by each value of the range of values defined in
            `sweeper.values` or `rel_values`.
            name (str): a name given for the sweep that is later used within the q1as m code to identify the loops.
        """

        self.type: QbloxSweeperType = type
        self.name: str = None
        self.register: Register = None
        self.aux_register: Register = None
        self.update_parameters: bool = False

        # Number of iterations in the loop
        self._n: int = None

        # Absolute values
        self._abs_start = None
        self._abs_step = None
        self._abs_stop = None
        self._abs_values: np.ndarray = None

        # Converted values (converted to q1asm values, two's complement)
        self._con_start: int = None
        self._con_step: int = None
        self._con_stop: int = None
        self._con_values: np.ndarray = None

        # Validate input parameters
        if not len(rel_values) > 1:
            raise ValueError("values must contain at least 2 elements.")
        elif rel_values[1] == rel_values[0]:
            raise ValueError("values must contain different elements.")

        self._n = len(rel_values) - 1
        rel_start = rel_values[0]
        rel_step = rel_values[1] - rel_values[0]

        if name != "":
            self.name = name
        else:
            self.name = self.type.name

        # create the registers (variables) to be used in the loop
        self.register: Register = Register(program, self.name)
        if type == QbloxSweeperType.duration:
            self.aux_register: Register = Register(program, self.name + "_aux")

        # Calculate absolute values
        self._abs_start = (rel_start + add_to) * multiply_to
        self._abs_step = rel_step * multiply_to
        self._abs_stop = self._abs_start + self._abs_step * (self._n)
        self._abs_values = np.arange(self._abs_start, self._abs_stop, self._abs_step)

        # Verify that all values are within acceptable ranges
        check_values = {
            QbloxSweeperType.frequency: (
                lambda v: all((-self.FREQUENCY_LIMIT <= x and x <= self.FREQUENCY_LIMIT) for x in v)
            ),
            QbloxSweeperType.gain: (lambda v: all((-1 <= x and x <= 1) for x in v)),
            QbloxSweeperType.offset: (lambda v: all((-1.25 * np.sqrt(2) <= x and x <= 1.25 * np.sqrt(2)) for x in v)),
            QbloxSweeperType.relative_phase: (lambda v: True),
            QbloxSweeperType.start: (lambda v: all((4 <= x and x < 2**16) for x in v)),
            QbloxSweeperType.duration: (lambda v: all((0 <= x and x < 2**16) for x in v)),
            QbloxSweeperType.number: (lambda v: all((-(2**16) < x and x < 2**16) for x in v)),
        }

        if not check_values[type](np.append(self._abs_values, [self._abs_stop])):
            raise ValueError(f"Sweeper {self.name} values are not within the allowed range")

        # Convert absolute values to q1asm values
        convert = {
            QbloxSweeperType.frequency: convert_frequency,
            QbloxSweeperType.gain: convert_gain,
            QbloxSweeperType.offset: convert_offset,
            QbloxSweeperType.relative_phase: convert_phase,
            QbloxSweeperType.start: (lambda x: int(x) % 2**16),
            QbloxSweeperType.duration: (lambda x: int(x) % 2**16),
            QbloxSweeperType.number: (lambda x: int(x) % 2**32),
        }

        self._con_start = convert[type](self._abs_start)
        self._con_step = convert[type](self._abs_step)
        self._con_stop = (self._con_start + self._con_step * (self._n) + 1) % 2**32
        self._con_values = np.array([(self._con_start + self._con_step * m) % 2**32 for m in range(self._n + 1)])

        # log.info(f"Qblox sweeper converted values: {self._con_values}")

        if not (
            isinstance(self._con_start, int) and isinstance(self._con_stop, int) and isinstance(self._con_step, int)
        ):
            raise ValueError("start, stop and step must be int")

    @classmethod
    def from_sweeper(
        cls, program: Program, sweeper: Sweeper, add_to: float = 0, multiply_to: float = 1, name: str = ""
    ):
        """Creates an instance form a :class:`qibolab.sweepers.Sweeper` object.

        Args:
            program (:class:`qibolab.instruments.qblox_q1asm.Program`): a program object representing the q1asm program of a
                sequencer.
            sweeper (:class:`qibolab.sweepers.Sweeper`): the original qibolab sweeper.
                associated with the sweep. If no name is provided it uses the sweeper type as name.
            add_to (float): a value to be added to each value of the range of values defined in `sweeper.values`,
                `rel_values`.
            multiply_to (float): a value to be multiplied by each value of the range of values defined in `sweeper.values`,
                `rel_values`.
            name (str): a name given for the sweep that is later used within the q1asm code to identify the loops.
        """
        type_c = {
            Parameter.frequency: QbloxSweeperType.frequency,
            Parameter.gain: QbloxSweeperType.gain,
            Parameter.amplitude: QbloxSweeperType.gain,
            Parameter.bias: QbloxSweeperType.offset,
            Parameter.start: QbloxSweeperType.start,
            Parameter.duration: QbloxSweeperType.duration,
            Parameter.relative_phase: QbloxSweeperType.relative_phase,
        }
        if sweeper.parameter in type_c:
            type = type_c[sweeper.parameter]
            rel_values = sweeper.values
        else:
            raise ValueError(f"Sweeper parameter {sweeper.parameter} is not supported by qblox driver yet.")
        return cls(program=program, rel_values=rel_values, type=type, add_to=add_to, multiply_to=multiply_to, name=name)

    def block(self, inner_block: Block):
        """Generates the block of q1asm code that implements the sweep.

        The q1asm code for a sweeper has the following structure:

        .. code-block:: text

            # header_block
            # initialise register with start value
            move    0, R0           # 0 = start value, R0 = register name
            nop                     # wait an instruction cycle (4ns) for the register to be updated with its value
            loop_R0:                # loop label

                # update_parameter_block
                # update parameters, in this case pulse frequency
                set_freq    R0      # sets the frequency of the sequencer nco to the value stored in R0
                upd_param   100     # makes the change effective and wait 100ns

                # inner block
                play 0,1,4          # play waveforms with index 0 and 1 (i and q) and wait 4ns

            # footer_block
            # increment or decrement register with step value
            add R0, 2500, R0        # R0 = R0 + 2500
            nop                     # wait an instruction cycle (4ns) for the register to be updated with its value
            # check condition and loop
            jlt R0, 10001, @loop_R0 # while R0 is less than the stop value loop to loop_R0
                                    # in this example it would loop 5 times
                                    # with R0 values of 0, 2500, 5000, 7500 and 10000

        Args:
            inner_block (:class:`qibolab.instruments.qblox_q1asm.Block`): the block of q1asm code to be repeated within
                the loop.

        """
        # Initialisation
        header_block = Block()
        header_block.append(
            f"move {self._con_start}, {self.register}",
            comment=f"{self.register.name} loop, start: {round(self._abs_start, 6):_}",
        )
        header_block.append("nop")
        header_block.append(f"loop_{self.register}:")

        # Parameter update
        if self.update_parameters:
            update_parameter_block = Block()
            update_time = 1000
            if self.type == QbloxSweeperType.frequency:
                update_parameter_block.append(f"set_freq {self.register}")  # TODO: move to pulse
                update_parameter_block.append(f"upd_param {update_time}")
            if self.type == QbloxSweeperType.gain:
                update_parameter_block.append(f"set_awg_gain {self.register}, {self.register}")  # TODO: move to pulse
                update_parameter_block.append(f"upd_param {update_time}")
            if self.type == QbloxSweeperType.offset:
                update_parameter_block.append(f"set_awg_offs {self.register}, {self.register}")
                update_parameter_block.append(f"upd_param {update_time}")

            if self.type == QbloxSweeperType.start:
                pass
            if self.type == QbloxSweeperType.duration:
                update_parameter_block.append(f"add {self.register}, 1, {self.aux_register}")
            if self.type == QbloxSweeperType.time:
                pass
            if self.type == QbloxSweeperType.number:
                pass
            if self.type == QbloxSweeperType.relative_phase:
                pass
            header_block += update_parameter_block
        header_block.append_spacer()

        # Main code
        body_block = Block()
        body_block.indentation = 1
        body_block += inner_block

        # Loop instructions
        footer_block = Block()
        footer_block.append_spacer()

        footer_block.append(
            f"add {self.register}, {self._con_step}, {self.register}",
            comment=f"{self.register.name} loop, step: {round(self._abs_step, 6):_}",
        )
        footer_block.append("nop")

        # Qblox fpgas implement negative numbers using two's complement however their conditional jump instructions
        # (jlt and jge) only work with unsigned integers. Negative numbers (from 2**31 to 2**32) are greater than
        # possitive numbers (0 to 2**31). There is therefore a discontinuity between negative and possitive numbers.
        # Depending on whether the sweep increases or decreases the register, and on whether it crosses the
        # discontinuity or not, there are 4 scenarios:

        if self._abs_step > 0:  # increasing
            if (self._abs_start < 0 and self._abs_stop < 0) or (
                self._abs_stop > 0 and self._abs_start >= 0
            ):  # no crossing 0
                footer_block.append(
                    f"jlt {self.register}, {self._con_stop}, @loop_{self.register}",
                    comment=f"{self.register.name} loop, stop: {round(self._abs_stop, 6):_}",
                )
            elif self._abs_start < 0 and self._abs_stop >= 0:  # crossing 0
                # wait until the register crosses 0 to possitive values
                footer_block.append(
                    f"jge {self.register}, {2**31}, @loop_{self.register}",
                )
                # loop if the register is less than the stop value
                footer_block.append(
                    f"jlt {self.register}, {self._con_stop}, @loop_{self.register}",
                    comment=f"{self.register.name} loop, stop: {round(self._abs_stop, 6):_}",
                )
            else:
                raise ValueError(
                    f"incorrect values for abs_start: {self._abs_start}, abs_stop: {self._abs_stop}, abs_step: {self._abs_step}"
                )
        elif self._abs_step < 0:  # decreasing
            if (self._abs_start < 0 and self._abs_stop < 0) or (
                self._abs_stop >= 0 and self._abs_start > 0
            ):  # no crossing 0
                footer_block.append(
                    f"jge {self.register}, {self._con_stop + 1}, @loop_{self.register}",
                    comment=f"{self.register.name} loop, stop: {round(self._abs_stop, 6):_}",
                )
            elif self._abs_start >= 0 and self._abs_stop < 0:  # crossing 0
                if self._con_stop + 1 != 2**32:
                    # wait until the register crosses 0 to negative values
                    footer_block.append(
                        f"jlt {self.register}, {2**31}, @loop_{self.register}",
                    )
                    # loop if the register is greater than the stop value
                    footer_block.append(
                        f"jge {self.register}, {self._con_stop + 1}, @loop_{self.register}",
                        comment=f"{self.register.name} loop, stop: {round(self._abs_stop, 6):_}",
                    )
                else:  # special case when stopping at -1
                    footer_block.append(
                        f"jlt {self.register}, {2**31}, @loop_{self.register}",
                        comment=f"{self.register.name} loop, stop: {round(self._abs_stop, 6):_}",
                    )
            else:
                raise ValueError(
                    f"incorrect values for abs_start: {self._abs_start}, abs_stop: {self._abs_stop}, abs_step: {self._abs_step}"
                )

        return header_block + body_block + footer_block


import numpy as np
from gym import spaces
from geometry_msgs.msg import Vector3, Point, Quaternion, Pose, Twist, Wrench
from quad_controller_rl.tasks.base_task import BaseTask

class Takeoff(BaseTask):
    def __init__(self):
        # debugger
        # import pdb; pdb.set_trace()

        cube_size = 300.0
        self.observation_space = spaces.Box(
            np.array([- cube_size / 2.0, - cube_size / 2.0, 0.0, -1.0, -1.0, -1.0, -1.0]),
            np.array([ cube_size / 2.0, cube_size / 2.0, cube_size,  1.0,  1.0,  1.0, 1.0]))

        max_force = 25.0

        self.action_space = spaces.Box(
            np.array([-max_force, -max_force, -max_force]),
            np.array([ max_force, max_force, max_force]))

        self.max_duration = 5.0
        self.target_z = 10.0
        self.threshold = 0.2

    def reset(self):
        return Pose(
                position=Point(0.0, 0.0, 0.0),
                orientation=Quaternion(0.0, 0.0, 0.0, 0.0),
            ), Twist(
                linear=Vector3(0.0, 0.0, 0.0),
                angular=Vector3(0.0, 0.0, 0.0)
            )

    def update(self, timestamp, pose, angular_velocity, linear_acceleration):
        # debugger
        # import pdb; pdb.set_trace()

        # linear_acceleration.z = abs(linear_acceleration.z) + 6
        # angular_velocity.z += abs(linear_acceleration.z) + 6
        # pose.position.z += abs(linear_acceleration.z) + 11

        state = np.array([
                pose.position.x, pose.position.y, pose.position.z,
                pose.orientation.x, pose.orientation.y, pose.orientation.z, pose.orientation.w])

        done = False
        reward = -min(abs(self.target_z - pose.position.z), 20.0)
        if pose.position.z >= self.target_z:
            reward += 10.0
            done = True
        if not -self.threshold < pose.position.x < self.threshold:
            reward -= 10.0
            done = True
        if not -self.threshold < pose.position.y < self.threshold:
            reward -= 10.0
            done = True
        if timestamp < self.max_duration and pose.position.z > self.target_z:
            reward -= 10.0
            done = True
        elif timestamp > self.max_duration:
            reward -= 10.0
            done = True

        action = self.agent.step(state, reward, done)

        if action is not None:
            action = np.clip(action.flatten(), self.action_space.low, self.action_space.high)
            # print("Action: {}, {}, {} ".format(action[0], action[1], action[2]))
            # z-position, z-linear acceleration, and a calculated per-timestep z-velocity
            return Wrench(force=Vector3(action[0], action[1], action[2])), done
        else:
            print("Empty Wrench no action...")
            return Wrench(), done


from flask import Blueprint
from project.http.response import ok

from .purchase.views import NewPurchase, StartPurchase, FinishPurchase

bp = Blueprint('api', __name__)

bp.add_url_rule('/purchase', 'create', NewPurchase.view())
bp.add_url_rule('/purchase/start', 'start', StartPurchase.view())
bp.add_url_rule('/purchase/finish', 'finish', FinishPurchase.view())

@bp.route('/ping', methods=('GET', ))
def ping():
    return ok(message='pong')


#K-Means Clustering

#importing libraries
import numpy as np
from matplotlib import pyplot as plt
import pandas as pd

#importing the datasets
data=pd.read_csv("Mall_Customers.csv")
x=data.iloc[:,3:].values

#selecting no.of clusters using elbow method
from sklearn.cluster import KMeans
wcss=[]
for i in range(1,11):
    kmeans=KMeans(n_clusters=i,init="k-means++",random_state=0)
    kmeans.fit(x)
    wcss.append(kmeans.inertia_)
plt.plot(range(1,11),wcss)
plt.title("The Elbow Method")
plt.xlabel("No.of Clusters")
plt.ylabel("WCSS")
plt.show()

#creating K-Means cluster
kmeans=KMeans(n_clusters=5,init="k-means++",random_state=0)
y_means=kmeans.fit_predict(x)

#Visualizing the Clusters
plt.scatter(x[y_means==0,0],x[y_means==0,1],c="red",s=100,label="Cluster 1")
plt.scatter(x[y_means==1,0],x[y_means==1,1],c="blue",s=100,label="Cluster 2")
plt.scatter(x[y_means==2,0],x[y_means==2,1],c="green",s=100,label="Cluster 3")
plt.scatter(x[y_means==3,0],x[y_means==3,1],c="yellow",s=100,label="Cluster 4")
plt.scatter(x[y_means==4,0],x[y_means==4,1],c="black",s=100,label="Cluster 5")
plt.scatter(kmeans.cluster_centers_[:,0],kmeans.cluster_centers_[:,1],c="cyan",s=100,label="centroids")
plt.title("Clusters of Clients")
plt.xlabel("Annual Income")
plt.ylabel("Spending Score")
plt.legend()
plt.show()


from language import Builder

builder = Builder.get_builder()

all_properties = [
	'keyFor', 'getOwnPropertyDescriptors', 'toExponential', 'unscopables', 'bold', 'strike', 'setYear', 'getUTCDay',
	#'for', 'catch', 'delete',
	'big', 'defineProperty', 'getOwnPropertyNames', 'setMinutes', 'entries', 'split', 'isSafeInteger', 'from', 'getSeconds',
	'sub', 'getUint32', 'UTC', 'stackTraceLimit', 'constructor', 'hasOwnProperty', 'species', 'dotAll', 'isView',
	'toString', 'toISOString', 'setSeconds', 'some', 'input', 'getFloat32', 'toLocaleString', 'call', 'setUTCMinutes', 'reduce',
	 'flags', 'isFinite', 'propertyIsEnumerable', 'italics', 'getOwnPropertySymbols', 'set', 'forEach', 'then', 'revocable',
	 'getHours', 'getMinutes', 'ignoreCase', 'setMonth', 'asUintN', 'normalize', 'getUTCHours', 'getUTCMinutes', 'size', 'MAX_VALUE',
	 'name', 'unicode', 'bind', 'hasInstance', 'toDateString', 'BYTES_PER_ELEMENT', 'fontsize', 'fill', 'sticky', 'getUTCDate', 'blink',
	 'defineProperties', 'setInt8', 'values', 'source', 'fromCodePoint', 'isNaN', 'getTime', 'setUint16', 'EPSILON', 'lastMatch', 'setFloat64',
	 'global', 'copyWithin', 'lastParen', 'assign', 'isExtensible', 'asIntN', 'charCodeAt', 'getInt16', 'getDate', 'codePointAt', 'is',
	 'getMilliseconds', 'localeCompare', 'getDay', 'push', 'getUTCMonth', '__proto__', 'getBigInt64', '__defineSetter__', 'small', 'finally',
	 'compile', 'NaN', 'toStringTag', 'setUint32', 'lastIndexOf', 'trimStart', 'indexOf', 'toPrecision', 'trimEnd', 'reject', 'toLocaleDateString',
	 'setFloat32', 'freeze', 'isFrozen', 'replace', 'anchor', 'trimLeft', 'resolve', 'exec', 'setBigUint64', 'shift', 'charAt', 'endsWith', 'filter',
	 'iterator', 'getPrototypeOf', 'setDate', '__lookupGetter__', 'concat', 'includes', 'MIN_VALUE', 'reverse', 'setFullYear', 'substring',
	 'toLocaleTimeString', 'getUTCMilliseconds', 'setUTCSeconds', 'parseInt', 'apply', 'getUint8', 'getInt32', 'substr', 'multiline', 'byteOffset',
	 'trim', 'length', 'getFloat64', 'getUTCSeconds', 'create', 'isSealed', 'keys', 'toGMTString', 'link', 'every', 'match', 'MAX_SAFE_INTEGER',
	 'parse', 'rightContext', 'getBigUint64', 'toJSON', 'callee', 'asyncIterator', 'getYear', 'getUTCFullYear', 'setHours', 'search', 'getFullYear',
	 'MIN_SAFE_INTEGER', 'test', 'isPrototypeOf', 'sort', 'valueOf', 'unshift', 'leftContext', 'toLocaleLowerCase', 'setUint8', 'splice', 'setInt16',
	 'trimRight', 'message', '__defineGetter__', 'toLowerCase', 'setUTCMilliseconds', 'getTimezoneOffset', 'setBigInt64', 'fixed', 'setPrototypeOf',
	 'caller', 'isInteger', 'setUTCHours', 'clear', 'getOwnPropertyDescriptor', 'padStart', 'fromCharCode', 'fontcolor', 'toTimeString', 'setUTCFullYear',
	 'add', 'toPrimitive', 'prototype', 'of', 'repeat', 'isConcatSpreadable', '__lookupSetter__', 'arguments',
	 'NEGATIVE_INFINITY', 'byteLength', 'find', 'padEnd', 'captureStackTrace', 'sup', 'setUTCMonth', 'findIndex', 'setMilliseconds', 'race', 'toFixed',
	 'buffer', 'toLocaleUpperCase', 'has', 'get', 'getUint16', 'getInt8', 'map', 'setInt32', 'seal', 'reduceRight', 'join', 'startsWith', 'preventExtensions',
	 'setTime', 'getMonth', 'isArray', 'toUpperCase', 'now', 'slice', 'toUTCString', 'pop', 'all', 'raw', 'POSITIVE_INFINITY', 'setUTCDate', 'parseFloat',
	 'value', 'writable']

BaseClass = [
	'Object', 'Array', 'Function', 'Number', 'Boolean', 'String',
	'Symbol', 'Date', 'Promise', 'RegExp',
	'ArrayBuffer',
	'Uint8Array', 'Int8Array', 'Uint16Array', 'Int16Array',
	'Uint32Array', 'Int32Array', 'Float32Array', 'Float64Array',
	'Uint8ClampedArray', 'SharedArrayBuffer', 'DataView',
	'Map', 'Set', 'WeakMap', 'WeakSet', 'Proxy',
]
"""
IdentifierName
"""
@builder.rule('IdentifierName', w=1)
def _(m):
	""" IdentifierName: """
	return m.ref_Id()

"""
IdentifierName
"""
@builder.rule('StringLiteral', w=1)
def _(m):
	""" StringLiteral: """
	return '"%s"' % m.choice(all_properties)

"""
IdentifierName
"""
@builder.rule('NumericLiteral', w=1)
def _(m):
	""" NumericLiteral: """
	return '%d' % m.randint(-0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF+1)

"""
TemplateLiteral
"""
@builder.rule('TemplateLiteral', w=1)
def _(m):
	""" TemplateLiteral: $empty """
	return '``'

@builder.rule('TemplateLiteral', w=1)
def _(m):
	""" TemplateLiteral: just_properties """
	return '`%s`' % m.choice(all_properties)

@builder.rule('TemplateLiteral', w=1)
def _(m):
	""" TemplateLiteral: `${Expression}` """
	return '`${%s}`' % m.make('Expression')

@builder.rule('BuiltInBaseClass', w=1)
def _(m):
	""" @BuiltInBaseClass: [...]  """
	base = m.choice(BaseClass)
	return base

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

@builder.rule('TestDeepArray', w=1, e=True)
def _(maker):
	""" @ArrayInit: new Array() """
	return '1'

@builder.rule('TestInt', w=1, e=True)
def _(maker):
	""" @ArrayInit: new Array() """
	return '0xFFFFFFFF'

@builder.rule('TestDeepArray', w=5)
def _(maker):
	""" @ArrayInit: new Array() """
	return '%s+%s' % (maker.make('TestDeepArray'), maker.make('TestDeepArray'))

@builder.rule('TestNewTarget', w=1)
def _(maker):
	""" TestNewTarget: Newtarget """
	return '%s' % (maker.make('Newtarget'))

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


import data
import pickle
import os
import argparse
import pyLDAvis.gensim
import pyLDAvis
import gensim
import json

def lda(fileName):
    with open(fileName , 'rb') as f:
        a = pickle.load(f)
        dictionary = gensim.corpora.Dictionary(a)
        dictionary.filter_extremes(no_below = 2 , no_above=0.1)

        corpse = [dictionary.doc2bow(text) for text in a]
        lda = gensim.models.ldamodel.LdaModel(corpse , num_topics = 8 , id2word=dictionary , passes=10)

    name = list(list(fileName.split('/'))[-1].split("."))[-2]
    # print(name)

    with open("../output/"+name+"_lda.json" , 'w') as f:
        f.write(json.dumps(lda.print_topics(-1), indent=4))

    web = pyLDAvis.gensim.prepare(topic_model=lda , corpus=corpse , dictionary=dictionary)
    htmlName = name+".html"
    pyLDAvis.save_html(web , htmlName)

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="Processing data")
    parser.add_argument("-rem" , metavar="R" , nargs="*" , type=str , help="List of POS tags to remove")
    args = parser.parse_args()

    fileName = "../data/94-documents"

    if not os.path.isfile(fileName):
        data.getData(fileName , args.rem)
        # print("\nEntered\n")
    lda(fileName+".txt")


import os

def sellAction(sellOpt, resultList, singleDate):
	curResult = resultList[-1]
	if curResult[4] == 10:
		print("Error: No Hold Stock")
		return None

	partXCode = sellOpt[-1]
	partXPrice = sellOpt[3]
	partXShare = sellOpt[2]
	partXDate = singleDate

	part = [partXCode, partXPrice, partXShare, partXDate]

	sellResult = sell(curResult, part, singleDate)
	if sellResult:
		update(sellResult)

	return sellResult

def sell(curResult, part, singleDate):
	partCodeIndex = (6, 10, 14, 18, 22, 26, 30, 34, 38, 42)
	sellResult =[]
	for n in curResult:
		sellResult.append(n)
	#sellResult = curResult

	for num in partCodeIndex:
		if curResult[num] == part[0]:
			#print(sellResult)
			#print(part)

			sellResult[0] = singleDate
			sellResult[1] = curResult[1] + 1
			sellResult[2] = curResult[2] - curResult[num + 1] * curResult[num + 2] + part[1] * curResult[num + 2]
			sellResult[3] = curResult[3] + part[1] * curResult[num + 2]
			sellResult[4] = curResult[4] + 1
			sellResult[5] = sellResult[3] / sellResult[4]
			sellResult[46] = "sell"
			sellResult[47] = part[0]
			sellResult[48] = part[1]
			sellResult[49] = sellResult[num + 2]
			sellResult[50] = sellResult[num + 3]
			sellResult[num] = 0
			sellResult[num + 1] = 0
			sellResult[num + 2] = 0
			sellResult[num + 3] = 0
			#print(sellResult)
			return sellResult
	return None

def update(sellResult):
	partCodeIndex = (6, 10, 14, 18, 22, 26, 30, 34, 38, 42)
	#print(sellResult)
	holdNum = 10 - sellResult[4]
	if holdNum == 0:
		return sellResult

	for num in xrange(0,holdNum):
		indexNum = partCodeIndex[num]
		if sellResult[indexNum] == 0:
			del sellResult[indexNum: indexNum + 4]
			#print("del")

			sellResult.insert(42, 0)
			sellResult.insert(43, 0)
			sellResult.insert(44, 0)
			sellResult.insert(45, 0)

def buyAction(buyOptList, resultList, singleDate):
	qOptList = []
	qOptList = chooseBuyOpt(buyOptList)
	if qOptList:
		#curResult = []
		curResult = resultList[-1]
		leftPart = curResult[4]
		sortBuyOpt(qOptList, leftPart)
		buyResultList =[]

		for buyOpt in qOptList:
			buyResult = buy(curResult, buyOpt, singleDate)
			resultList.append(buyResult)
			curResult = resultList[-1]

def chooseBuyOpt(buyOptList):
	qOptList = []
	for buyOpt in buyOptList:
		# decide what to choosepy
		if buyOpt[6] > 0 and buyOpt[7] > 0.00:
		# just decide from last op rate
		# if buyOpt[5] > 1:
			qOptList.append(buyOpt)

	return qOptList

#need to complete this function
def sortBuyOpt(qOptList, leftPart):
	lenNum = len(qOptList)
	if lenNum > leftPart:
		del qOptList[leftPart: lenNum]

def buy(curResult, buyOpt, singleDate):
	partCodeIndex = (6, 10, 14, 18, 22, 26, 30, 34, 38, 42)
	buyResult = []
	for n in curResult:
		buyResult.append(n)

	partXCode = buyOpt[-1]
	partXPrice = buyOpt[3]
	partXShare = curResult[5] / buyOpt[3]
	partXDate = singleDate

	part = [partXCode, partXPrice, partXShare, partXDate]

	holdNum = 10 - curResult[4]
	indexNum = partCodeIndex[holdNum]

	buyResult[0] = singleDate
	buyResult[1] = curResult[1] + 1
	buyResult[3] = curResult[3] - part[1] * part[2]
	buyResult[4] = curResult[4] - 1
	if buyResult[4]:
		buyResult[5] = buyResult[3] / buyResult[4]
	else :
		buyResult[5] = 0
	for n in xrange(0,4):
		buyResult[indexNum + n] = part[n]
	buyResult[46] = "buy"
	buyResult[47] = part[0]
	buyResult[48] = part[1]
	buyResult[49] = part[2]
	buyResult[50] = part[3]

	return buyResult

def test(testList):
	del testList[3: 5]

# test ===================
if __name__=='__main__':

	testList = range(1, 10)

	print(testList)
	test(testList)
	print(testList)

	#print(fileDict)
	#for filePath, tbl in fileDict.items():
	#	print(filePath)
	#	print(tbl)


from GC_interface import GarbageCollector

#This is a WAYYYY better garbage collector!  It does not require a garbage
# collector of its own and it functions solely in statically allocated memory.
# It works quite similarly to mark and sweep in that the 'marking' is done in
# the bits left over between how large a word is and how large a pointer is.
# Here, it assumes that pointers will be less than 22 bits long, which I think
# is a pretty fair assumption for this simulator.

#This one takes MUCH less memory and even runs way faster than it's predecessor,
# although, it could still be improved on.

#data should be treated in 4 byte chunks
# data can only have Nodes in it.
# the first and second words are the first node's data
# the third and fourth words are the first node's pointers
# the fifth and sixth words are the second node's data...
# -1 denotes a null pointer

class GC_more_complex(GarbageCollector):
    def __init__(self):
        self.alloc_count=-1
        self.active_mask=(2**26)
        self.checked_mask=(2**27)
        self.toCheck_mask=(2**28)

    def is_marked_active(self,data_copy,i):
        return data_copy[i+2]&self.active_mask
    def is_marked_checked(self,data_copy,i):
        return data_copy[i+2]&self.checked_mask
    def is_marked_toCheck(self,data_copy,i):
        return data_copy[i+2]&self.toCheck_mask
    def mark_active(self,data_copy,i):
        if not self.is_marked_active(data_copy,i):
            data_copy[i+2]=data_copy[i+2]|self.active_mask
    def mark_checked(self,data_copy,i):
        if not self.is_marked_checked(data_copy,i):
            data_copy[i+2]=data_copy[i+2]|self.checked_mask
    def mark_toCheck(self,data_copy,i):
        if not self.is_marked_toCheck(data_copy,i):
            data_copy[i+2]=data_copy[i+2]|self.toCheck_mask
    def unmark_toCheck(self,data_copy,i):
        if self.is_marked_toCheck(data_copy,i):
            data_copy[i+2]=data_copy[i+2]&(~self.toCheck_mask)
    def get_next_node_to_check(self,data_copy):
        i=0
        while i<len(data_copy) and not self.is_marked_toCheck(data_copy,i):
            i+=4
        return i if i<len(data_copy) else -1

    def allocate(self,data,active_roots):
        self.alloc_count+=1
        mask=(2**25)-1
        data_copy=[i if i>=0 else 2**23 for i in data]
        for i in active_roots:
            if not self.is_marked_checked(data_copy,i): #if i has not been checked, make sure it is in active_nodes and add both of its children to the to_check list
                self.mark_active(data_copy,i)
                if not data_copy[i+2]&mask==2**23 and not self.is_marked_checked(data_copy,data_copy[i+2]&mask):
                    self.mark_active(data_copy,data_copy[i+2]&mask)
                    self.mark_toCheck(data_copy,data_copy[i+2]&mask)
                if not data_copy[i+3]&mask==2**23 and not self.is_marked_checked(data_copy,data_copy[i+3]&mask):
                    self.mark_active(data_copy,data_copy[i+3]&mask)
                    self.mark_toCheck(data_copy,data_copy[i+3]&mask)
                self.mark_checked(data_copy,i)
                while not self.get_next_node_to_check(data_copy)==-1:
                    checking_node=self.get_next_node_to_check(data_copy)
                    if not data_copy[checking_node+2]&mask==2**23 and not self.is_marked_checked(data_copy,data_copy[checking_node+2]&mask):
                        self.mark_active(data_copy,data_copy[checking_node+2]&mask)
                        self.mark_toCheck(data_copy,data_copy[checking_node+2]&mask)
                    if not data_copy[checking_node+3]&mask==2**23 and not self.is_marked_checked(data_copy,data_copy[checking_node+3]&mask):
                        self.mark_active(data_copy,data_copy[checking_node+3]&mask)
                        self.mark_toCheck(data_copy,data_copy[checking_node+3]&mask)
                    self.unmark_toCheck(data_copy,checking_node)
                    self.mark_checked(data_copy,checking_node)
        i=0
        while i<len(data_copy):
            if not self.is_marked_active(data_copy,i):
                return i
            i+=4
        return -1 #This would indicate that every node is active and return a null pointer, aka heap overflow