import copy
import git
import os
import re
import sys
import typing

import pandas as pd
import numpy as np

from collections import defaultdict, OrderedDict
from common_primitives import utils

try:
    from dsbox_corex.corextext.corex_topic import Corex
except:
    from corextext.corex_topic import Corex

#from corextext.corex_topic import Corex
from scipy import sparse as sp

from sklearn import preprocessing
from sklearn.feature_extraction.text import CountVectorizer, TfidfVectorizer

import d3m.container as container
from d3m.metadata.base import ALL_ELEMENTS
import d3m.metadata.hyperparams as hyperparams
import d3m.metadata.params as params

from d3m.container import DataFrame as d3m_DataFrame
from d3m.metadata.base import PrimitiveMetadata, DataMetadata
from d3m.metadata.hyperparams import Uniform, UniformBool, UniformInt, Union, Enumeration
from d3m.primitive_interfaces.base import CallResult
from d3m.primitive_interfaces.unsupervised_learning import UnsupervisedLearnerPrimitiveBase

import dsbox_corex._config as cfg_

os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3'

import string

Input = container.DataFrame
Output = container.DataFrame #typing.Union[container.DataFrame, None]

class CorexText_Params(params.Params):
    fitted_: typing.Union[bool, None]
    model_: typing.Union[Corex, None]
    bow_: typing.Union[TfidfVectorizer, None]
    do_nothing_: typing.Union[bool, None]
    text_columns_: typing.Union[typing.List[int], None]
    latent_factors_: typing.Union[pd.DataFrame, None]
    max_iter_: typing.Union[int, None]

# Set hyperparameters according to https://gitlab.com/datadrivendiscovery/d3m#hyper-parameters
class CorexText_Hyperparams(hyperparams.Hyperparams):
    # number of Corex latent factors
    n_hidden = UniformInt(
        lower = 1,
        upper = 301,
        default = 30,
        description = 'number of topics',
        semantic_types=["http://schema.org/Integer", 'https://metadata.datadrivendiscovery.org/types/TuningParameter']
    )

    #
    threshold = Uniform(
        lower = 0,
        upper = 10000,
        default = 0,
        q = 1,
        description = 'threshold for number of columns in the tfidf matrix below which we don`t call CorEx',
        semantic_types=["http://schema.org/Integer", 'https://metadata.datadrivendiscovery.org/types/TuningParameter']
    )

    #
    n_grams = UniformInt(
        lower = 1,
        upper = 10,
        default = 1,
        description = 'n_grams parameter to use before feeding in text to TfidfVectorizer',
        semantic_types=["http://schema.org/Integer", 'https://metadata.datadrivendiscovery.org/types/TuningParameter']
    )

    # max_df @ http://scikit-learn.org/stable/modules/generated/sklearn.feature_extraction.text.TfidfVectorizer.html
    max_df = Uniform(
        lower = 0.0,
        upper = 1.00,
        default = .9,
        q = .05,
        description = 'max percent document frequency of analysed terms',
        semantic_types=["http://schema.org/Float", 'https://metadata.datadrivendiscovery.org/types/TuningParameter']
    )

    # min_df @ http://scikit-learn.org/stable/modules/generated/sklearn.feature_extraction.text.TfidfVectorizer.html
    min_df = Uniform(
        lower = 0.0,
        upper = 1.00,
        default = .02,
        q = .01,
        description = 'min percent document frequency of analysed terms',
        semantic_types=["http://schema.org/Float", 'https://metadata.datadrivendiscovery.org/types/TuningParameter']
    )

class CorexText(UnsupervisedLearnerPrimitiveBase[Input, Output, CorexText_Params, CorexText_Hyperparams]):  #(Primitive):
    """
    Learns latent factors / topics which explain the most multivariate information in bag of words representations of documents. Returns learned topic scores for each document. Also supports hierarchical models and 'anchoring' to encourage topics to concentrate around desired words.
    """
    metadata = PrimitiveMetadata({
        "schema": "v0",
        "id": "0c64ffd6-cb9e-49f0-b7cb-abd70a5a8261",
        "version": "1.0.0",
        "name": "CorexText",
        "description": "Learns latent factors / topics which explain the most multivariate information in bag of words representations of documents. Returns learned topic scores for each document. Also supports hierarchical models and 'anchoring' to encourage topics to concentrate around desired words.",
        #"python_path": "d3m.primitives.dsbox.corex_text.CorexText",
        "python_path": "d3m.primitives.feature_construction.corex_text.DSBOX",
        "original_python_path": "corextext.corex_text.CorexText",
        "source": {
            "name": "ISI",
            "contact": "mailto:sstan@usc.edu",
            "uris": [ "https://github.com/brekelma/dsbox_corex" ]
        },
        "installation": [ cfg_.INSTALLATION ],
        "algorithm_types": ["EXPECTATION_MAXIMIZATION_ALGORITHM", "LATENT_DIRICHLET_ALLOCATION"],
        "primitive_family": "FEATURE_CONSTRUCTION",
        "hyperparams_to_tune": ["n_hidden", "threshold", "n_grams", "max_df", "min_df"]
    })

    def __init__(self, *, hyperparams : CorexText_Hyperparams) -> None:
        super(CorexText, self).__init__(hyperparams = hyperparams)

    # instantiate data and create model and bag of words
    def set_training_data(self, *, inputs : Input) -> None:
        self.training_data = inputs
        self.fitted = False

    # assumes input as data-frame and do prediction on the 'text' labeled columns
    def fit(self, *, timeout : float = None, iterations : int = None) -> None:
        # if already fitted, do nothing
        if self.fitted:
            return CallResult(None, True, 1)

        self.training_data = self._process_files(self.training_data)

        text_attributes = DataMetadata.list_columns_with_semantic_types(self=self.training_data.metadata,\
            semantic_types=["http://schema.org/Text"])
        all_attributes = DataMetadata.list_columns_with_semantic_types(self=self.training_data.metadata,\
            semantic_types=["https://metadata.datadrivendiscovery.org/types/Attribute"])
        categorical_attributes = DataMetadata.list_columns_with_semantic_types(self=self.training_data.metadata,\
            semantic_types=["https://metadata.datadrivendiscovery.org/types/CategoricalData"])

        # want text columns that are attributes
        self.text_columns = set(all_attributes).intersection(text_attributes)

        # but, don't want to edit categorical columns
        self.text_columns = set(self.text_columns) - set(categorical_attributes)

        # and, we want the text columns as a list
        self.text_columns = list(self.text_columns)

        # if no text columns are present don't do anything
        self.do_nothing = False
        if len(self.text_columns) == 0:
            self.fitted = True

            self.model = None
            self.bow = None
            self.do_nothing = True
            self.text_columns = None
            self.latent_factors = None
            self.max_iter = None

            return CallResult(None, True, 1)

        # instantiate a corex model and a bag of words model
        self.model = Corex(n_hidden = self.hyperparams['n_hidden'], max_iter = iterations, seed = self.random_seed)
        self.bow = TfidfVectorizer(decode_error='ignore', max_df = self.hyperparams['max_df'], min_df = self.hyperparams['min_df'])

        # set the number of iterations (for wrapper and underlying Corex model)
        if iterations is not None:
            self.max_iter = iterations
        else:
            self.max_iter = 250
        self.model.max_iter = self.max_iter

        # concatenate the columns row-wise
        concat_cols = None
        for column_index in self.text_columns:
            if concat_cols is not None:
                concat_cols = concat_cols.str.cat(self.training_data.iloc[:,column_index], sep = " ")
            else:
                concat_cols = copy.deepcopy(self.training_data.iloc[:,column_index])

        try:
            bow = self.bow.fit_transform(map(self._get_ngrams, concat_cols.ravel()))
        except ValueError:
            self.bow = TfidfVectorizer(decode_error='ignore', max_df = self.hyperparams['max_df'], min_df = 0)
            bow = self.bow.fit_transform(map(self._get_ngrams, concat_cols.ravel()))

            print("[WARNING] Setting min_df to 0 to avoid ValueError")

        # choose between CorEx and the TfIdf matrix
        if bow.shape[1] > self.hyperparams['threshold']:
            # use CorEx
            self.latent_factors = self.model.fit_transform(bow)
        else:
            # just use the bag of words representation
            self.latent_factors = pd.DataFrame(bow.todense())

        self.fitted = True

        return CallResult(None, True, 1)

    def produce(self, *, inputs : Input, timeout : float = None, iterations : int = None) -> CallResult[Output]:
        # if corex didn't run for any reason, just return the given dataset
        if self.do_nothing:
            return CallResult(inputs, True, 1)

        inputs = self._process_files(inputs)

        if iterations is not None:
            self.max_iter = iterations
        else:
            self.max_iter = 250
        self.model.max_iter = self.max_iter

        # concatenate the columns row-wise
        concat_cols = None
        for column_index in self.text_columns:
            if concat_cols is not None:
                concat_cols = concat_cols.str.cat(inputs.iloc[:,column_index], sep = " ")
            else:
                concat_cols = copy.deepcopy(inputs.iloc[:,column_index])
        bow = self.bow.transform(map(self._get_ngrams, concat_cols.ravel()))

        # choose between CorEx and the TfIdf matrix
        if bow.shape[1] > self.hyperparams['threshold']:
            # use CorEx
            self.latent_factors = self.model.transform(bow).astype(float)
        else:
            # just use the bag of words representation
            self.latent_factors = pd.DataFrame(bow.todense())
        # make the columns corex adds distinguishable from other columns

        # remove the selected columns from input and add the latent factors given by corex
        out_df = d3m_DataFrame(inputs, generate_metadata = True)

        self.latent_factors.columns = [str(out_df.shape[-1] + i) for i in range(self.latent_factors.shape[-1])]

        # create metadata for the corex columns
        corex_df = d3m_DataFrame(self.latent_factors, generate_metadata = True)
        for column_index in range(corex_df.shape[1]):
            col_dict = dict(corex_df.metadata.query((ALL_ELEMENTS, column_index)))
            col_dict['structural_type'] = type(1.0)
            # FIXME: assume we apply corex only once per template, otherwise column names might duplicate
            col_dict['name'] = 'corex_' + str(out_df.shape[1] + column_index)
            col_dict['semantic_types'] = ('http://schema.org/Float', 'https://metadata.datadrivendiscovery.org/types/Attribute')

            corex_df.metadata = corex_df.metadata.update((ALL_ELEMENTS, column_index), col_dict)

        # concatenate is --VERY-- slow without this next line
        corex_df.index = out_df.index.copy()

        out_df = utils.append_columns(out_df, corex_df)

        # remove the initial text columns from the df, if we do this before CorEx we can get an empty dataset error
        out_df = utils.remove_columns(out_df, self.text_columns)

        # TO DO : Incorporate timeout, max_iter
        # return CallResult(d3m_DataFrame(self.latent_factors))
        return CallResult(out_df, True, 1)

    #def fit_multi_produce(self, ):

    def _get_ngrams(self, text : str = None) -> str:
        punctuation_table = str.maketrans(dict.fromkeys(string.punctuation))
        try:
            words = text.translate(punctuation_table).lower().rsplit(" ")
        except:
            words = text.str.translate(punctuation_table).lower().rsplit(" ")

        new_text = ""
        for i in range(len(words)):
            new_text += "".join(words[i : i+int(self.hyperparams['n_grams'])]) + " "

        return new_text

    # remove the FileName columns from the data frame and replace them with text
    def _process_files(self, inputs: Input):
        fn_attributes = DataMetadata.list_columns_with_semantic_types(self=inputs.metadata, \
            semantic_types=["https://metadata.datadrivendiscovery.org/types/FileName"])
        all_attributes = DataMetadata.list_columns_with_semantic_types(self=inputs.metadata, \
            semantic_types=["https://metadata.datadrivendiscovery.org/types/Attribute"])
        fn_columns = list(set(all_attributes).intersection(fn_attributes))

        # if no file name columns are detected, default to regular behavior
        if len(fn_columns) == 0:
            return inputs

        # create an empty DataFrame of the required size
        processed_cols = pd.DataFrame("", index = copy.deepcopy(inputs.index), \
            columns = ['text_files_' + str(i) for i in range(len(fn_columns))])

        # for column_index in range(len(fn_columns)):
        for column_index in fn_columns:
            curr_column = copy.deepcopy(inputs.iloc[:, column_index])

            file_loc = inputs.metadata.query((ALL_ELEMENTS, column_index))['location_base_uris']
            file_loc = file_loc[0]  # take the first elem of the tuple
            file_loc = file_loc[7:] # get rid of 'file://' prefix

            for row_index in range(curr_column.shape[0]):
                text_file = curr_column.iloc[row_index]
                file_path = file_loc + text_file

                with open(file_path, 'rb') as file:
                    doc = file.read()
                doc = "".join(map(chr, doc))
                doc_tokens = re.compile(r"(?u)\b\w\w+\b").findall(doc) # list of strings

                processed_cols.iloc[row_index, fn_columns.index(column_index)] = " ".join(doc_tokens)

        # construct metadata for the newly generated columns
        processed_cols = d3m_DataFrame(processed_cols, generate_metadata = True)

        for column_index in range(processed_cols.shape[1]):
            col_dict = dict(processed_cols.metadata.query((ALL_ELEMENTS, column_index)))
            col_dict['structural_type'] = type("text")
            # FIXME: assume we apply corex only once per template, otherwise column names might duplicate
            col_dict['name'] = 'processed_file_' + str(inputs.shape[1] + column_index)
            col_dict['semantic_types'] = ('http://schema.org/Text', 'https://metadata.datadrivendiscovery.org/types/Attribute')

            processed_cols.metadata = processed_cols.metadata.update((ALL_ELEMENTS, column_index), col_dict)

        # concatenate the input with the newly created columns
        updated_inputs = utils.append_columns(inputs, processed_cols)

        # remove the initial FileName columns from the df, if we do this before concatenating we might get an empty dataset error
        updated_inputs = utils.remove_columns(updated_inputs, fn_columns)

        return updated_inputs

    def get_params(self) -> CorexText_Params:
        return CorexText_Params(
            fitted_ = self.fitted,
            model_ = self.model,
            bow_ = self.bow,
            do_nothing_ = self.do_nothing,
            text_columns_ = self.text_columns,
            latent_factors_ = self.latent_factors,
            max_iter_ = self.max_iter
            )

    def set_params(self, *, params: CorexText_Params) -> None:
        self.fitted = params['fitted_']
        self.model = params['model_']
        self.bow = params['bow_']
        self.do_nothing = params['do_nothing_']
        self.text_columns = params['text_columns_']
        self.latent_factors = params['latent_factors_']
        self.max_iter = params['max_iter_']

    def _annotation(self):
        if self._annotation is not None:
            return self._annotation
        self._annotation = Primitive()
        self._annotation.name = 'CorexText'
        self._annotation.task = 'FeatureExtraction'
        self._annotation.learning_type = 'UnsupervisedLearning'
        self._annotation.ml_algorithm = ['Dimension Reduction']
        self._annotation.tags = ['feature_extraction', 'text']
        return self._annotation


import os
import unittest
from datetime import datetime
from urllib.parse import parse_qs, urlparse

from azure.storage.blob import BlobClient, ContainerClient

from parsons import AzureBlobStorage, Table
from parsons.utilities import files

TEST_ACCOUNT_NAME = os.getenv("PARSONS_AZURE_ACCOUNT_NAME")
TEST_CREDENTIAL = os.getenv("PARSONS_AZURE_CREDENTIAL")
TEST_CONTAINER_NAME = os.getenv("PARSONS_AZURE_CONTAINER_NAME")
TEST_FILE_NAME = "tmp_file_01.txt"
TEST_FILE_CONTENTS = "Test"

@unittest.skipIf(not os.getenv("LIVE_TEST"), "Skipping because not running live test")
class TestAzureBlobStorage(unittest.TestCase):
    def setUp(self):

        self.azure_blob = AzureBlobStorage(
            account_name=TEST_ACCOUNT_NAME, credential=TEST_CREDENTIAL
        )

        # Create the container if it does not exist already
        if not self.azure_blob.container_exists(TEST_CONTAINER_NAME):
            self.azure_blob.create_container(TEST_CONTAINER_NAME)

        # Create blob if it doesn't exist already
        if not self.azure_blob.blob_exists(TEST_CONTAINER_NAME, TEST_FILE_NAME):
            tmp_file_path = files.string_to_temp_file(TEST_FILE_CONTENTS, suffix=".txt")
            self.azure_blob.put_blob(TEST_CONTAINER_NAME, TEST_FILE_NAME, tmp_file_path)

    def test_list_containers(self):

        # Make sure container created in setup is in the list
        container_list = self.azure_blob.list_containers()
        self.assertIn(TEST_CONTAINER_NAME, container_list)

    def test_container_exists(self):

        # Assert that setup container exists
        self.assertTrue(self.azure_blob.container_exists(TEST_CONTAINER_NAME))

        # Assert that invalid bucket does not exists
        self.assertFalse(self.azure_blob.container_exists("fakecontainer"))

    def test_get_container(self):

        # Assert that a ContainerClient object is returned
        self.assertIsInstance(
            self.azure_blob.get_container(TEST_CONTAINER_NAME), ContainerClient
        )

    def test_create_container(self):

        # Assert that container created in setup exists
        self.assertTrue(self.azure_blob.container_exists(TEST_CONTAINER_NAME))

        # Add current datetime microseconds for randomness to avoid intermittent failures
        dt_microseconds = datetime.now().isoformat()[-6:]
        create_container_name = f"{TEST_CONTAINER_NAME}create{dt_microseconds}"

        # Create a new container with metadata, assert that it is included
        create_container = self.azure_blob.create_container(
            create_container_name, metadata={"testing": "parsons"}
        )
        create_container_properties = create_container.get_container_properties()
        self.assertIn("testing", create_container_properties.metadata)

        # Delete the container after the assertion
        self.azure_blob.delete_container(create_container_name)

    def test_delete_container(self):

        # Add current datetime microseconds for randomness to avoid intermittent failures
        dt_microseconds = datetime.now().isoformat()[-6:]
        delete_container_name = f"{TEST_CONTAINER_NAME}delete{dt_microseconds}"

        # Create an additional container, assert that it exists
        self.azure_blob.create_container(delete_container_name)
        self.assertTrue(self.azure_blob.container_exists(delete_container_name))

        # Then delete the container and assert it does not exist
        self.azure_blob.delete_container(delete_container_name)
        self.assertFalse(self.azure_blob.container_exists(delete_container_name))

    def test_list_blobs(self):

        blob_name_list = self.azure_blob.list_blobs(TEST_CONTAINER_NAME)

        # Assert that file created in setup is in the list
        self.assertIn(TEST_FILE_NAME, blob_name_list)

    def test_blob_exists(self):

        # Assert that blob created in setup exists
        self.assertTrue(
            self.azure_blob.blob_exists(TEST_CONTAINER_NAME, TEST_FILE_NAME)
        )

        # Assert that invalid blob does not exist
        self.assertFalse(self.azure_blob.blob_exists(TEST_CONTAINER_NAME, "FAKE_BLOB"))

    def test_get_blob(self):

        # Assert that get_blob returns a BlobClient object for blob created in setup
        self.assertIsInstance(
            self.azure_blob.get_blob(TEST_CONTAINER_NAME, TEST_FILE_NAME), BlobClient
        )

    def test_get_blob_url(self):

        # Assert that get_blob_url returns a URL with a shared access signature
        blob_url = self.azure_blob.get_blob_url(
            TEST_CONTAINER_NAME, TEST_FILE_NAME, permission="r"
        )
        parsed_blob_url = urlparse(blob_url)
        parsed_blob_query = parse_qs(parsed_blob_url.query)
        self.assertIn("sas", parsed_blob_query)

    def test_put_blob(self):

        # Assert that put_blob returns a BlobClient object
        put_blob_name = "tmp_file_put.txt"
        tmp_file_path = files.string_to_temp_file("Test", suffix=".txt")

        put_blob_client = self.azure_blob.put_blob(
            TEST_CONTAINER_NAME, put_blob_name, tmp_file_path
        )
        self.assertIsInstance(put_blob_client, BlobClient)

        self.azure_blob.delete_blob(TEST_CONTAINER_NAME, put_blob_name)

    def test_download_blob(self):

        # Download blob and ensure that it has the expected file contents
        download_blob_path = self.azure_blob.download_blob(
            TEST_CONTAINER_NAME, TEST_FILE_NAME
        )
        with open(download_blob_path, "r") as f:
            self.assertEqual(f.read(), TEST_FILE_CONTENTS)

    def test_delete_blob(self):

        delete_blob_name = "delete_blob.txt"

        # Upload a blob, assert that it exists
        tmp_file_path = files.string_to_temp_file(TEST_FILE_CONTENTS, suffix=".txt")
        self.azure_blob.put_blob(TEST_CONTAINER_NAME, delete_blob_name, tmp_file_path)
        self.assertTrue(
            self.azure_blob.blob_exists(TEST_CONTAINER_NAME, delete_blob_name)
        )

        # Delete the blob, assert that it no longer exists
        self.azure_blob.delete_blob(TEST_CONTAINER_NAME, delete_blob_name)
        self.assertFalse(
            self.azure_blob.blob_exists(TEST_CONTAINER_NAME, delete_blob_name)
        )

    def test_upload_table(self):

        test_table = Table([{"first": "Test", "last": "Person"}])
        test_table_blob_name = "table.csv"

        # Upload a test table as CSV, assert that blob is a CSV
        table_blob_client = self.azure_blob.upload_table(
            test_table, TEST_CONTAINER_NAME, test_table_blob_name, data_type="csv"
        )
        table_blob_client_properties = table_blob_client.get_blob_properties()
        self.assertEqual(
            table_blob_client_properties.content_settings.content_type, "text/csv"
        )

        # Remove blob after assertion
        self.azure_blob.delete_blob(TEST_CONTAINER_NAME, test_table_blob_name)


'''
Clase: Menu principal de Ventas
Autor: Martha Soto Luna
Matricula: 181803008
Fecha creación: 25/10/2022
Última fecha de modificación: 27/10/2022
Docente: Rebeca Rodríguez Huesca
Materia: Ingeniería de requisitos
Proyecto: Veterinaria
Versión: 2.0
'''

from ast import Delete
import sys
from PyQt5.QtWidgets import QApplication, QMainWindow
from EliminarProducto import ventanaEliminar
from SalesMain import Ui_MenuVentas
from AgregarVenta import OtraVenta
from ConsultarVenta import ventanaConsultar

class ventanaPrincipalVent(QMainWindow):
    def __init__(self):
        super(ventanaPrincipalVent, self).__init__()
        self.ui = Ui_MenuVentas()
        self.ui.setupUi(self)

        self.ui.pushButton_Back.clicked.connect(self.salir)

        self.ui.pushButton_AddVenta.clicked.connect(self.VentanaAgregarV)
        self.ad = OtraVenta()

        self.ui.pushButton_consultVenta.clicked.connect(self.consultar)
        self.brows = ventanaConsultar()

    #Funciones para que los botones muestren las interfaces de VENTAS

    def VentanaAgregarV(self):
        self.ad.show()

    def consultar(self):
        self.brows.show()

    def salir(self):
        self.hide()

if __name__ == '__main__':
    app = QApplication([])
    main = ventanaPrincipalVent()
    main.show()
    sys.exit(app.exec())


import tensorflow as tf
from sklearn.metrics import r2_score
from sklearn.metrics import mean_squared_error

tf.compat.v1.set_random_seed(337)

x_data = [[1, 2, 3], [1, 2, 3]]
y_data = [[1], [2], [3]]
x_data = x_data + [[1, 2, 3]]
x = tf.compat.v1.placeholder(tf.float32, shape=[None, 3])
y = tf.compat.v1.placeholder(tf.float32, shape=[None, 1])

w = tf.compat.v1.Variable(tf.compat.v1.random_normal([3, 1]), name='weight')
b = tf.compat.v1.Variable(tf.compat.v1.random_normal([1]), name='bias')

# 2. MODEL
hypothesis = tf.compat.v1.matmul(x, w) + b

# 3. COMPILE, Fit
sess = tf.compat.v1.Session()
sess.run(tf.compat.v1.global_variables_initializer())

# Training
sess.run(hypothesis, feed_dict={x: x_data})

# Get predicted values
y_pred = sess.run(hypothesis, feed_dict={x: x_data})

# Calculate R2 score
r2 = r2_score(y_data, y_pred)
print("R2 Score:", r2)
mse = mean_squared_error(y_data, y_pred)
print("MSE Score:", mse)


from utils.node import Model, Node
from utils.io import Input, InputType

class SaveModel(Node):

    def function(self, data:Input, folder, prefix):

        if data.type != InputType.MODEL:
            raise TypeError(f"Input needs to be a model coming from a model node but got '{data.type.name.lower()}'")

        model:Model
        model, just_loaded = data.get()

        if not just_loaded:
            model.save(folder, prefix)
            self.done()
        else:
            self.clear_status()


#!/usr/bin/python

import sys
import timeit as tm
import subprocess as subpc
import numpy as np
import matplotlib.pyplot as plt

if __name__ != "__main__" or len(sys.argv) != 3:
    print("USAGE: ", sys.argv[0], " BINDIR FILENAME")

bindir = sys.argv[1]
filename = sys.argv[2]

def bench(name, grid, steps):
    start = tm.default_timer()
    subpc.run([bindir + "/" + name, str(grid), str(steps)])
    end = tm.default_timer()
    return end - start

ncells = 2 ** 29;
# grids = np.array([
#     16, 32, 48, 64, 80, 96, 112, 128, 144, 160, 176, 192, 208, 224, 240, 256
#     ], dtype=np.uint)

grids = np.array([16, 32, 64, 80, 96, 112, 128, 144, 160], dtype=np.uint)

# static_cfg = [
#         ("linear", 0), ("linear", 1), ("linear", 2), ("linear", 3),
#         ("linear", 4), ("vector", 0), ("vector", 1), ("vector", 2),
#         ("zcube2", 0), ("zcube2", 1), ("zcube2", 2), ("zcube2", 3)
#         ]

static_cfg = [("vector", 0), ("vector", 2), ("zcube2", 0), ("zcube2", 3), ("linear", 0), ("linear", 4)]
# static_cfg = [("linear", 4), ("vector", 2), ("zcube2", 3)]
# static_cfg = [("vector", 2),]

fig, ax = plt.subplots()
ax.set_title("time benchmark, " + str(ncells) + " cells")

for (tile, rank) in static_cfg:
    name = tile + "_" + str(rank)
    times = np.array(
            [bench(name, grid, ncells / (grid ** 3)) for grid in grids])
    ax.plot(grids, times, label=name)

ax.set_xlabel("grid, nodes")
ax.set_ylabel("time, sec")
ax.set_ylim([0, None])

ax.legend()
plt.savefig(filename)


import numpy as np
import cv2

'''
Modifica la cantidad de fps y tamano del video.
Seteado ahora en dividir a 1/3 los fps
'''

video = '../data/videos/large1.mp4'
out = 'large1-10fps.mp4'
x,y,h,w = 0,0,720,1280

# Open the video
cap = cv2.VideoCapture(video)

# Initialize frame counter
cnt = 0

# Some characteristics from the original video
w_frame, h_frame = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)), int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
fps, frames = cap.get(cv2.CAP_PROP_FPS), cap.get(cv2.CAP_PROP_FRAME_COUNT)

# Here you can define your croping values
# x,y,h,w = 350,200,720,1280
# output
fourcc = cv2.VideoWriter_fourcc(*'MP4V')
#out = cv2.VideoWriter('720x1280-x350-y200_originalfps.mp4', fourcc, fps, (w, h))
out = cv2.VideoWriter(out, fourcc, fps/3, (w, h))

frames_mid_eliminate=0

# Now we start
while(cap.isOpened()):
    ret, frame = cap.read()
    cnt += 1 # Counting frames

    # Avoid problems when video finish
    if ret==True:
        if frames_mid_eliminate != 0:
            frames_mid_eliminate+=1
            if frames_mid_eliminate == 3:
                frames_mid_eliminate=0
            continue

        frames_mid_eliminate+=1
        # Croping the frame
        crop_frame = frame[y:y+h, x:x+w]

        # Percentage

        # Saving from the desired frames
        #if 15 <= cnt <= 90:
        #    out.write(crop_frame)

        # I see the answer now. Here you save all the video
        out.write(crop_frame)

        # Just to see the video in real time
        cv2.imshow('frame',frame)
        cv2.imshow('croped',crop_frame)

        if cv2.waitKey(1) & 0xFF == ord('q'):
            break
    else:
        break

cap.release()
out.release()
cv2.destroyAllWindows()


P = []

def union(a,b):
    global P
    A,B = find(a),find(b)
    P[A] = B

def find(a):
    global P
    if P[a] == a:
        return a
    else:
        P[a] = find(P[a])
    return P[a]

def check(s,stones,k):
    cnt = 0
    for i in range(len(stones)):
        cnt = cnt + 1 if stones[i] <= s else 0
        if cnt == k:
            return False
    return True

def solution(stones,k):
    l,r = 0,2000001
    while l<=r:
        m = (l+r)//2
        if check(m,stones,k):
            l = m+1
        else:
            r = m-1
    return l

# def solution(stones, k):
#     global P
#     n = len(stones)
#     v = [0]*n
#     if n == 1:return stones[0]
#     answer = 0
#     P = [i for i in range(n)]
#     enum_stones = sorted(list(enumerate(stones)),key=lambda x:-x[1])
#     while enum_stones:
#         idx,val = enum_stones.pop()
#         v[idx] = 1

#         if idx == 0:
#             if v[P[idx+1]]:
#                 v[P[idx+1]] += v[idx]
#                 union(idx,idx+1)
#         elif idx == n-1:
#             if v[P[idx-1]]:
#                 v[P[idx-1]] += v[idx]
#                 union(idx,idx-1)

#         else:
#             if v[P[idx+1]] and v[P[idx-1]]:
#                 v[P[idx+1]] += v[idx]
#                 v[P[idx+1]] += v[P[idx-1]]
#                 union(idx,idx+1)
#                 union(idx-1,idx+1)
#             elif v[P[idx+1]]:
#                 v[P[idx+1]] += v[idx]
#                 union(idx,idx+1)
#             elif v[P[idx-1]]:
#                 v[P[idx-1]] += v[idx]
#                 union(idx,idx-1)

#         if v[P[idx]] >= k:

#             answer = val
#             break
#     return answer

solution([2, 4, 5, 3, 2, 1, 4, 2, 5, 1]	,4)


from pyramid.traversal import find_interface

from substanced.util import get_dotted_name
from substanced.objectmap import find_objectmap

from substanced.catalog.indexes import AllowedIndex
from substanced.catalog import Catalog

import logging

_marker = object()

logger = logging.getLogger('evolution')

def evolve(root, registry):
    logger.info(
        'Running substanced evolve step 9: reindex all allowed indices '
        'due to change in discriminator principal repr'
        )

    site = root

    objectmap = find_objectmap(site)

    index_oids = objectmap.get_extent(get_dotted_name(AllowedIndex))

    for oid in index_oids:
        index = objectmap.object_for(oid)
        catalog = find_interface(index, Catalog)
        catalog.reindex(indexes=(index.__name__,))


#In the 5 by 5 matrix below, the minimal path sum from the top left to the bottom right, by only moving to the right and down, is indicated in red and is equal to 2427.
#
#
#131    673    234    103    18
#201    96    342    965    150
#630    803    746    422    111
#537    699    497    121    956
#805    732    524    37    331
#
#
#Find the minimal path sum, in matrix.txt (right click and 'Save Link/Target As...'), a 31K text file containing a 80 by 80 matrix, from the top left to the bottom right by only moving right and down.

import logging
from util import parse_matrix

def main(args):
    matrix = parse_matrix("data/p081_matrix.txt")
    n = len(matrix)

    for i in range(n):
        for j in range(n):
            if (i == 0 and j == 0): continue
            if (i == 0):
                matrix[i][j] += matrix[i][j-1]
                continue
            if (j == 0):
                matrix[i][j] += matrix[i-1][j]
                continue
            if (matrix[i-1][j] < matrix[i][j-1]):
                matrix[i][j] += matrix[i-1][j]
            else:
                matrix[i][j] += matrix[i][j-1]

    logging.info("answer: {}".format(matrix[n-1][n-1]))


# FIXME: Make a system that is announcing the user that it has to call the super methods when it is overriding them.
from apps.common.choices import DRFActions
from apps.common.choices import RESTMethods
from apps.common.services import BaseService

class CreateServiceMixin:
    service_class = None

    def perform_create(self, serializer):
        assert self.service_class is not None

        super().perform_create(serializer)

        if self.should_perform_on_create():
            instance = serializer.instance
            service_instance = BaseService.get_service(self)
            service_instance.on_create(instance)

    def should_perform_on_create(self):
        return BaseService.should_perform(self, DRFActions.CREATE, RESTMethods.POST)

class ListServiceMixin:
    service_class = None

    def get_queryset(self):
        assert self.service_class is not None

        queryset = super().get_queryset()

        if self.should_perform_on_list():
            service_instance = BaseService.get_service(self)
            queryset = service_instance.on_list(queryset)

        assert queryset is not None

        return queryset

    def should_perform_on_list(self):
        return BaseService.should_perform(self, DRFActions.LIST, RESTMethods.GET)

class RetrieveServiceMixin:
    service_class = None

    def get_object(self):
        assert self.service_class is not None

        instance = super().get_object()

        if self.should_perform_on_retrieve():
            service_instance = BaseService.get_service(self)
            instance = service_instance.on_retrieve(instance)

        assert instance is not None

        return instance

    def should_perform_on_retrieve(self):
        return BaseService.should_perform(self, DRFActions.RETRIEVE, RESTMethods.GET)

class UpdateServiceMixin:
    service_class = None

    def perform_update(self, serializer):
        assert self.service_class is not None

        super().perform_update(serializer)

        if self.should_perform_on_update():
            instance = serializer.instance
            new_validated_data = serializer.validated_data

            service_instance = BaseService.get_service(self)
            service_instance.on_update(instance, new_validated_data)

    def should_perform_on_update(self):
        return BaseService.should_perform(self, [DRFActions.UPDATE, DRFActions.PARTIAL_UPDATE], RESTMethods.PATCH)

class DestroyServiceMixin:
    service_class = None

    def perform_destroy(self, instance):
        assert self.service_class is not None

        if self.should_perform_on_destroy():
            service_instance = BaseService.get_service(self)
            service_instance.on_destroy(instance)

        super().perform_destroy(instance)

    def should_perform_on_destroy(self):
        return BaseService.should_perform(self, DRFActions.DESTROY, RESTMethods.DELETE)

class ServiceMixin(
    CreateServiceMixin,
    ListServiceMixin,
    RetrieveServiceMixin,
    UpdateServiceMixin,
    DestroyServiceMixin,
):
    def get_service(self):
        return self.service_class.get_service(self)


# coding=utf-8

import os
import glob
import cv2
import math
import numpy as np
from DoG import DoG
from scipy import stats
from file_manager import File_manager

#Radian
radi = 180/np.pi

def create_diff_images(path):
    #List of dances directories
    folders = os.listdir(path)
    diff_img = {}
    #Bluring matrix
    smothing = np.matrix([[1,1,1],[1,1,1],[1,1,1]]) / 9
    #Iterates through all the dances
    for folder in folders:
        #Sets the path to the current dance
        tmp_path = path + folder
        #List of waggle runs
        wd_runs = os.listdir(tmp_path)
        #Iterates through the waggle runs
        for run in wd_runs:
            #Array with the images path
            listing = glob.glob(tmp_path + '/' +  run + '/' + 'image*.png')
            #Initializes the variables
            frame_counter = 0
            last_frame   = None
            image_array = []
            #Iterates through the images
            for frame_path in listing:
                frame = cv2.imread(frame_path)
                #The png file is a 50x50x3 array, we only need one layer
                frame = frame[:,:,1]
                #Sets as key a string with the path to the WRun
                key = str(tmp_path[-15:] + '/' +  run)
                #If it is the first frame
                if last_frame is None:
                    last_frame  = frame
                    continue
                #Any other frame
                else:
                    #Difference between consecutive frames
                    frame_diff = last_frame.astype(float) - frame.astype(float)
                    frame_diff = cv2.filter2D(frame_diff, -1, smothing)
                    #If it is the first diff in the WRun
                    if (key not in diff_img):
                        diff_img[key] = [frame_diff]
                    #If not, it add it
                    else:
                        diff_img[key].append(frame_diff)

                last_frame = frame

    return diff_img

def calc_image_sum_for_angle(angles, key, img_arrays, kernels):
    sums = []

    for idx, angle in enumerate(angles):
        img_sum = 0
        kernel = kernels[idx]

        for index, img in enumerate(img_arrays):
            if (index < len(img_arrays) - 10):
                filtered_img = np.amax(cv2.filter2D(img, -1, -kernel))

                img_sum += filtered_img
            else:
                break

        sums.append(img_sum)

    return sums, key

def calc_image_sum_for_frame(_angles, key, img_arrays, kernels):
    mat = np.zeros((len(img_arrays), math.ceil(len(_angles) / 2)))

    for index, img in enumerate(img_arrays):
        for idx in range(int(len(_angles) / 2)):
            kernel = kernels[idx]

            mat[index][idx] = np.amax(abs(cv2.filter2D(img, -1, -kernel)))

    return mat, key

def calc_accumulator(diff_img):
    #Output array
    FDI = {}
    #Iterates through the waggle runs
    for key, img_arrays in list(diff_img.items()):
        image = None
        #Iterates through the diff_images
        for img in img_arrays:
            #fast fourier transformation + shift to center
            tmp = np.fft.fftshift(abs(np.fft.fft2(img)))
            #If it is the first
            if image is None:
                image = tmp
            #From the second on
            else:
                image += tmp
        #Resulting image is stored under key = path to WRun
        FDI[key]=(image)
    return FDI

def filter_with_kernel(FDI):
    #Kernel definition
    dog = DoG().mexican_head_kernel
    cov1 = 30 * np.eye(2)
    cov2 = 4 * np.eye(2)
    Kern = abs(np.fft.fftshift(np.fft.fft2(dog(50, [25,25], cov1, [25,25], cov2))))
    #Restuls array
    FDI_filt = {}
    #Iterates through the FDI
    for key, FDI_img in list(FDI.items()):
        FDI_filt[key] = np.power(np.multiply(FDI_img, Kern), 5)
    return FDI_filt

def calc_angles(FDI_filt):
    #Results vector
    angles = {}
    #Iterates through the FDI_filt
    for key, FDI_img in list(FDI_filt.items()):
        moment = cv2.moments(FDI_img)
        #Image covariance
        img_cov = np.array([[moment['nu20'], moment['nu11']], [moment['nu11'], moment['nu02']]])
        #Eigenvalues
        w, v = np.linalg.eig(img_cov)
        #According to image convention
        angles[key] = -np.arctan2(v[1][np.argmin(w)], v[0][np.argmin(w)])*radi
    return angles

def read_GT(path):
    fm_csv = File_manager(path).read_csv
    #list of Groung Truth angles
    gt_angles = {}
    folders = os.listdir(path)
    #Iterates through all the dances
    for folder in folders:
        #Sets the path to the current dance
        tmp_path = path + folder
        #List of waggle runs
        wd_runs = os.listdir(tmp_path)
        #Iterates through the waggle runs
        for run in wd_runs:
            key = str(tmp_path[-15:] + '/' +  run)
            gt_angles[key] = float(fm_csv(tmp_path + '/' +  run + '/' + "result.csv")["Angle"])
    return gt_angles

#Returns a dictionary with angles in radians based on the dot detector coordinates
def read_DD(path):
    fm_csv = File_manager(path).read_csv
    #list of Groung Truth angles
    dd_angles = {}
    folders = os.listdir(path)
    #Iterates through all the dances
    for folder in folders:
        #Sets the path to the current dance
        tmp_path = path + folder
        #List of waggle runs
        wd_runs = os.listdir(tmp_path)
        #Iterates through the waggle runs
        for run in wd_runs:
            WRPath = str(tmp_path + '/' +  run + '/')
            #path to the waggle run
            split_WR = WRPath.split("/")
            #reads the csv file containing coordinates of dancing bee
            detections = fm_csv(WRPath + split_WR[-3] + "_" + split_WR[-2] + '.csv')
            #Parses last row from csv to vector
            dd_float = np.array(list(detections.values())[0].split(" "))[:-1].astype(float)
            #Filters all -1, no detection
            dd_float = [val for val in dd_float if val != -1]

            #Reshape to an [n,2] array
            #dd_float[:,0] = Xcoordinates
            #dd_float[:,1] = Ycoordinates
            DD = np.reshape(dd_float, (int(len(dd_float)/2),2), order = 'C')
            #LOOKING FOR THE SWEET SPOT!!!
            #Half the size of the vector
            Nhalf = int(np.floor(len(DD)/2))
            #Average coordinates of the first five detections
            m1 = DD[:5,:].mean(axis=0)
            #Average coordinates of the second half of detections
            m2 = DD[Nhalf+1:,:].mean(axis=0)

            #Delta vectors
            dDD = [[i[0]- m1[0],i[1]- m1[1]] for i in DD[Nhalf+1:,:]]
            dDD = np.reshape(dDD,(len(dDD),2), order = 'C')
            #Feature 2: angles of the delta vectors
            feat2 = [np.arctan2(i[1],i[0]) for i in dDD]
            #Histogram of delta vectors where:
            #n = number of occurrencies and c = angle values
            [n, c] = np.histogram(feat2, bins = 100)
            #average orientation of peaks in histogram
            avgHist = stats.circmean(c[np.argwhere(n == np.amax(n))])
            #Feature 4:
            feat4 = (m2-m1) + [math.cos(avgHist), math.sin(avgHist)]

            #returned angle correspond to the vector pointing from m1 towards m2
            dd_angles[tmp_path[-15:] + '/' +  run] = -np.arctan2(feat4[1],feat4[0])*radi
    return dd_angles

#Returns DDvector generated by DotDetector
def read_DDvector(WRPath):
    fm_csv = File_manager(path).read_csv
    WRPath = str(WRPath + '/')
    #path to the waggle run
    split_WR = WRPath.split("/")
    #reads the csv file containing coordinates of dancing bee
    detections = fm_csv(WRPath + split_WR[-3] + "_" + split_WR[-2] + '.csv')
    #Parses last row from csv to vector
    dd_float = np.array(list(detections.values())[0].split(" "))[:-1].astype(float)
    #Filters all -1, no detection
    dd_float = [val for val in dd_float if val != -1]
    return dd_float

#Returns an angles with adjusted orientation
#arguments:
#fft_angles: A dictionary containing the angles computed using the fft method.
#dd_angles: A dictionary containing the vectors defined using the dot detector coordinates.
#returns:
#adj_angles: A dictionary containing the corrected angles.
def def_orientation(fft_angles, dd_angles):
    adj_angles = {}
    #Iterates through all the dances
    for key in list(fft_angles):
        #Angles are converted to vectors
        v1 = [math.cos(fft_angles[key]/radi),math.sin(fft_angles[key]/radi)]
        v2 = [math.cos(dd_angles[key]/radi),math.sin(dd_angles[key]/radi)]
        #If the dot product is negative, the angles differ in more than 90°
        if np.dot(v1,v2) < 0:
            adj_angles[key] = (fft_angles[key] - 180) % 360
        else :
            adj_angles[key] = (fft_angles[key]) % 360
    return adj_angles

# It returns the substraction of two angles, angle1-angle2 in an image convention 0° at 3, +/- 180° at 9.
# arguments: angle1, angle2 in grads
# returns: diffAngle = angle1-angle2
def subst_angles(angle1, angle2):
    #Angles are converted to vectors
    v1 = [math.cos(angle1/radi),math.sin(angle1/radi)]
    v2 = [math.cos(angle2/radi),math.sin(angle2/radi)]
    #The magnitude is calculated using dot product
    diffAngle = math.acos(np.dot(v1,v2))*radi
    #The direction is defined using cross product
    if np.cross(v1,v2) < 0:
        diffAngle = -diffAngle
    return diffAngle


import sys
sys.path.insert(0, '../')
from mv3dpose.data.openpose import OpenPoseKeypoints, MultiOpenPoseKeypoints
from mv3dpose.tracking import tracking, Track
import mv3dpose.geometry.camera as camera
from os.path import isdir, join, isfile
from os import makedirs, listdir
from tqdm import tqdm
from time import time
import json
import numpy as np
import shutil

dataset_dir = '/home/user/dataset'
output_dir = join(dataset_dir, 'tracks3d')
dataset_json = join(dataset_dir, 'dataset.json')

vid_dir = join(dataset_dir, 'videos')
cam_dir = join(dataset_dir, 'cameras')
kyp_dir = join(dataset_dir, 'poses')

assert isdir(vid_dir)
assert isdir(cam_dir)

if isdir(output_dir):
    print('\n[deleting existing output directory...]')
    shutil.rmtree(output_dir)

makedirs(output_dir)

# ~~~~~~~~~~~~~~~~~~~~~~

Settings = json.load(open(dataset_json))

scale_to_mm = Settings['scale_to_mm']
n_cameras = Settings['n_cameras']

def get_optional(key, default_value):
    if key in Settings:
        return Settings[key]
    else:
        return default_value

epi_threshold = get_optional(
    'epi_threshold', 80)
max_distance_between_tracks = get_optional(
    'max_distance_between_tracks', 80)
min_track_length = get_optional(
    'min_track_length', 10)
merge_distance = get_optional(
    'merge_distance', 80)
last_seen_delay = get_optional(
    'last_seen_delay', 15)
smoothing_sigma = get_optional(
    'smoothing_sigma', 2)
smoothing_interpolation_range = get_optional(
    'smoothing_interpolation_range', 50)
do_smoothing = get_optional(
    'do_smoothing', True
)

if 'valid_frames' in Settings:
    valid_frames = Settings['valid_frames']
else:
    # take all frames in the setup
    files = listdir(join(vid_dir, 'camera00'))
    valid_frames = list(range(len(files)))

print("\n#frames", len(valid_frames))

# ~~~~~~~~~~~~~~~~~
# K E Y P O I N T S
# ~~~~~~~~~~~~~~~~~
print('\n[load keypoints]')
keypoints = []
for cid in tqdm(range(n_cameras)):
    loc = join(kyp_dir, 'camera%02d' % cid)
    assert isdir(loc), loc
    pe = OpenPoseKeypoints('frame%09d', loc)
    keypoints.append(pe)
pe = MultiOpenPoseKeypoints(keypoints)

# ~~~~~~~~~~~~~
# C A M E R A S
# ~~~~~~~~~~~~~
print('\n[load cameras]')
Calib = []  # { n_frames x n_cameras }
try:
    for t in tqdm(valid_frames):
        calib = []
        Calib.append(calib)
        for cid in range(n_cameras):
            local_camdir = join(cam_dir, 'camera%02d' % cid)
            assert isdir(local_camdir)
            cam_fname = join(local_camdir, 'frame%09d.json' % t)
            assert isfile(cam_fname), cam_fname
            cam = camera.Camera.load_from_file(cam_fname)
            calib.append(cam)
except AssertionError:
    print('\tnew version of cameras is used...')

    class CamerasPerFrame:

        def __init__(self, cam_dir, n_cameras, valid_frames):
            self.n_cameras = n_cameras
            self.n_frames = len(valid_frames)
            self.first_frame = valid_frames[0]
            self.cameras = []
            for cid in range(n_cameras):
                camfile = join(cam_dir, 'camera%02d.json' % cid)
                with open(camfile, 'r') as f:
                    cam_as_dict_list = json.load(f)

                cam_as_object_list = []
                for cam in cam_as_dict_list:
                    start_frame = cam['start_frame']
                    end_frame = cam['end_frame']
                    K = np.array(cam['K'])
                    rvec = np.array(cam['rvec'])
                    tvec = np.array(cam['tvec'])
                    distCoef = np.array(cam['distCoef'])
                    w = int(cam['w'])
                    h = int(cam['h'])
                    cam = camera.ProjectiveCamera(K, rvec, tvec, distCoef, w, h)

                    cam_as_object_list.append({
                        "start_frame": start_frame,
                        "end_frame": end_frame,
                        "cam": cam
                    })

                self.cameras.append(cam_as_object_list)

        def __getitem__(self, frame):
            """
            :param frame: frame, starting at 0!
            """
            frame += self.first_frame

            cameras = [1] * self.n_cameras
            for cid, cam_as_object_list in enumerate(self.cameras):
                for cam in cam_as_object_list:
                    start_frame = cam['start_frame']
                    end_frame = cam['end_frame']
                    if start_frame <= frame <= end_frame:
                        cameras[cid] = cam['cam']
                        break
            for cam in cameras:
                assert cam != 1
            return cameras

        def __len__(self):
            return self.n_frames

    Calib = CamerasPerFrame(cam_dir, n_cameras, valid_frames)

# ~~~~~~~~~~~~~~~~~~~~~~~
# L O A D  2 D  P O S E S
# ~~~~~~~~~~~~~~~~~~~~~~~
print('\n[load 2d poses]')
poses_per_frame = []
for frame in tqdm(valid_frames):
    predictions = pe.predict(frame)
    poses_per_frame.append(predictions)

# ~~~~~~~~~~~~~~~
# T R A C K I N G
# ~~~~~~~~~~~~~~~
print('\n[tracking]')
_start = time()
tracks = tracking(Calib, poses_per_frame,
                  epi_threshold=epi_threshold,
                  scale_to_mm=scale_to_mm,
                  max_distance_between_tracks=max_distance_between_tracks,
                  actual_frames=valid_frames,
                  min_track_length=min_track_length,
                  merge_distance=merge_distance,
                  last_seen_delay=last_seen_delay)
_end = time()
print('\telapsed', _end - _start)
print("\n\t# detected tracks:", len(tracks))

# ~~~~~~~~~~~~~~~
# S M O T H I N G
# ~~~~~~~~~~~~~~~
if do_smoothing:
    print('\n[smoothing]')
    tracks_ = []
    for track in tqdm(tracks):
        track = Track.smoothing(track,
                                sigma=smoothing_sigma,
                                interpolation_range=smoothing_interpolation_range)
        tracks_.append(track)
    tracks = tracks_

# ~~~~~~~~~~~~~~~~~
# S E R I A L I Z E
# ~~~~~~~~~~~~~~~~~
print('\n[serialize 3d tracks]')
for tid, track in tqdm(enumerate(tracks)):
    fname = join(output_dir, 'track' + str(tid) + '.json')
    track.to_file(fname)


import matplotlib
from matplotlib import colormaps
from matplotlib.colors import Colormap
import matplotlib.pyplot as plt
import numpy as np
from scipy.interpolate import griddata
from scipy.interpolate import RegularGridInterpolator
from scipy.ndimage import gaussian_filter
from scipy.special import erf
from typing import Tuple

def cornerplot(
    data: np.ndarray,
    cmap="Blues",
    correlation_textcolor=None,
    dpi=100.,
    hex_gridsize=30,
    highlight=None,
    highlight_linecolor=None,
    highlight_markercolor=None,
    hist_backgroundcolor=None,
    hist_bins=20,
    hist_edgecolor=None,
    hist_facecolor=None,
    labels=None,
    limits=None,
    scatter_alpha=0.5,
    scatter_markercolor=None,
    scatter_outside_sigma=None,
    show_correlations=False,
    sigma_levels=None,
    sigma_linecolor=None,
    sigma_smooth=3.,
    title_quantiles=None,
    width=3.
) -> Tuple[matplotlib.figure.Figure, matplotlib.axes.Axes]:
    """
    Function creates hexbin corner plot matrix to visualize multidimensional data.

    Parameters:
    -----------
    data : (N_sample, N_dims) array-like
        Two-dimensional data array to be visualized. First dimension are the samples,
        second dimension the features.
    cmap : str or matplotlib.colors.Colormap, optional, default: "Blues"
        Either a string of a valid matplotlib colormap or a custom Colormap object
        to be used in the plot.
    correlation_textcolor : str, optional, default: None
        Color of correlation text.
        Defaults to a value from the chosen colormap.
    dpi : float, optional, default: 100.
        Dots per inch of the figure
    hex_gridsize : int, optional, default: 30
        Number of hexagons ins x-direction
    highlight : (N_dims) array-like, optional, default: None
        If not None, array of values to be highlighted in the plot. Typically
        the truth values.
    highlight_linecolor : str or tuple, optional, default: None
        If not None linecolor of the highlighted values.
        Defaults to a value from the chosen colormap.
    highlight_markercolor : str or tuple, optional, default: None
        If not None markercolor of the highlighted values.
        Defaults to a value from the chosen colormap.
    hist_backgroundcolor : str or tuple, optional, default: None
        If not None background color of the axes object.
        Defaults to a value from the chosen colormap.
    hist_bins : int, optinal, default: 20
        Number of bins in histograms.
    hist_edgecolor : str or tuple, optional, default: None
        If not None edgecolor of the histgram bars.
        Defaults to a value from the chosen colormap.
    hist_facecolor : str or tuple, optional, default: None
        If not None face of the histgram bars.
        Defaults to a value from the chosen colormap.
    labels : (N_dims) list, optional, default: None
        If not None list of strings with the feature names
        to be used as axis labels or in the axis titles.
    limits : (2,) or (N_dims, 2) array-like, optional, default: None
        If not None limits is the axis limits of the
        features giving the minimum and maximum values
        of each feature
    scatter_alpha : float, optional, default: 0.5
        Alpha transparency value of scatter plot
    scatter_markercolor : str, optional, default: None
        If not None markercolor of scatter plot markers.
        Defaults to a value from the chosen colormap.
    scatter_outside_sigma : float, optional, default: None
        If not None displays scatter plot of individual data
        points outside of given sigma contour.
    show_correlations : boolean, optional, default: False
        If True show Pearson's correlation coeffiction in each tile.
    sigma_levels : array_like, optional, default: None
        If not None contour levels to be plotted in
        units of the standard deviation.
    sigma_linecolor : str or tuple, optional, default: None
        If not None linecolor of the sigma contour lines.
        Defaults to a value from the chosen colormap.
    sigma_smooth : float, optional, default: 3.
        Smoothing factor for hexbin plot to smooth
        out contour lines.
    title_quantiles : (1,) or (3,) array-like, optional, default: None
        One-dimensional array of either size one or size three with
        the feature quantiles to be plotted as histogram titles.
    width : float, optional, default: 3.
        Width of a single tile of the corner plot.

    Returns:
    --------
    (fig, ax) : tuple
        Tuple containing the figure and axes objects.
    """

    # Number of dimensions
    _, Nd = data.shape

    # Validate colormap
    if isinstance(cmap, str):
        cm = colormaps[cmap]
    elif isinstance(cmap, Colormap):
        cm = cmap
    else:
        raise ValueError(
            "'cmap' has to be either type str or LinearSegmentedColormap.")

    # Setting colors
    hl_lc = highlight_linecolor if highlight_linecolor is not None else cm(1.)
    hl_mc = highlight_markercolor if highlight_markercolor is not None \
        else cm(0.)
    sig_lc = sigma_linecolor if sigma_linecolor is not None else cm(1.)
    hist_bc = hist_backgroundcolor if hist_backgroundcolor is not None \
        else cm(0.)
    hist_ec = hist_edgecolor if hist_edgecolor is not None else cm(1.)
    hist_fc = hist_facecolor if hist_facecolor is not None else cm(0.5)
    scat_mc = scatter_markercolor if scatter_markercolor is not None else cm(
        0.5)

    # Validate labels
    set_labels = False if labels is None else True
    if set_labels:
        if len(labels) != Nd:
            raise ValueError(
                "Size of 'labels' does not match number of dimensions.")

    # Validate highlights
    set_highlights = False if highlight is None else True
    if set_highlights:
        if len(highlight) != Nd:
            raise ValueError(
                "Size of 'highlight' does not match number of dimensions.")

    # Produce levels
    if sigma_levels is not None:
        # Converting to 1d quantiles
        quants = []
        for s in sigma_levels:
            q = sigma_to_quantile(s)
            quants.extend([50.-q, 50.+q])
        quants = np.array(quants)
        quants.sort()
        # Converting to 2d sigma levels
        levels2d = 1. - np.exp(-0.5*np.array(sigma_levels)**2)

    # Threshold for scatter plot
    if scatter_outside_sigma is not None:
        scatter_thr = 1. - np.exp(-0.5*np.array(scatter_outside_sigma)**2)

    # Validate title quantiles
    if title_quantiles is not None:
        if len(title_quantiles) not in [1, 3]:
            raise ValueError(
                "'title_quantiles' has to have either size 1 or size 3.")
        title_quantiles = np.array(title_quantiles)
        title_quantiles.sort()

    # Compute correlation coefficients
    if show_correlations:
        rho = np.corrcoef(data.T)
        cor_tc = correlation_textcolor if correlation_textcolor is not None else cm(
            1.)

    # Setting limits
    lim = np.empty((Nd, 2))
    if limits is not None:
        l = np.array(limits)
        if l.shape not in [(2,), (Nd, 2)]:
            raise ValueError("'limits' does not have the correct shape.")
        lim[...] = l[None, :] if len(l.shape) == 1 else l
    else:
        lim[:, 0] = data.min(axis=0)
        lim[:, 1] = data.max(axis=0)

    fig, ax = plt.subplots(nrows=Nd, ncols=Nd, figsize=(
        Nd*width, Nd*width), dpi=dpi)

    for i in range(Nd**2):
        # x and y coordinates of subplots
        ix, iy = np.divmod(i, Nd)

        if iy > ix:
            # Remove axes outside of corner plot
            fig.delaxes(ax[ix, iy])
        elif ix == iy:
            # Histograms
            ax[ix, iy].set_facecolor(hist_bc)
            ax[ix, iy].hist(data[:, ix], bins=hist_bins, color=cm(1.),
                            facecolor=hist_fc, edgecolor=hist_ec)
            if sigma_levels is not None:
                perc = np.percentile(data[:, ix], quants)
                for p in perc:
                    ax[ix, iy].axvline(p, ls="--", lw=1, c=sig_lc)
            if set_highlights:
                ax[ix, iy].axvline(highlight[iy], ls="-", color=hl_lc)
            if title_quantiles is not None:
                perc = np.percentile(data[:, ix], title_quantiles)
                if len(title_quantiles) == 1:
                    if labels is not None:
                        prefix = "{} $= ".format(labels[iy])
                    else:
                        prefix = "$"
                    msg = "{}{{{:.2f}}}$".format(
                        prefix, perc[0])
                else:
                    diff = np.diff(perc)
                    if labels is not None:
                        prefix = "{} $= ".format(labels[iy])
                    else:
                        prefix = "$"
                    msg = "{}{{{:.2f}}}^{{+{:.2f}}}_{{-{:.2f}}}$".format(
                        prefix, perc[1], diff[1], diff[0])
                ax[ix, iy].set_title(msg, fontsize="x-large")
        else:
            # Hexbin plots
            h = ax[ix, iy].hexbin(
                data[:, iy], data[:, ix],
                cmap=cm,
                gridsize=hex_gridsize,
                linewidths=0.5,
                edgecolor=cm(0),
                extent=(lim[iy, 0], lim[iy, 1], lim[ix, 0], lim[ix, 1])
            )

            # Data gridding if sigma_levels given or scatter plot required
            if sigma_levels is not None or scatter_outside_sigma is not None:

                # Get positions and values from hexbin plots
                xy = h.get_offsets()
                z = h.get_array()

                # Compute gridded data for contour plot
                grid_x, grid_y = np.mgrid[
                    xy[:, 0].min():xy[:, 0].max():3*hex_gridsize*1j,
                    xy[:, 1].min():xy[:, 1].max():3*hex_gridsize*1j
                ]
                zi = griddata(xy, z, (grid_x, grid_y), method="linear")
                # Smooth data to forget about hexplot grid
                zi = gaussian_filter(zi, sigma_smooth)

                # Convert sigma levels to data levels
                z_flattened = zi.flatten()
                z_ordered = z_flattened[z_flattened.argsort()[::-1]]
                cumsum = z_ordered.cumsum()
                cumsum /= cumsum[-1]

            # Contourplot
            if sigma_levels is not None:
                # Compute levels
                levels = np.empty(len(levels2d))
                for i, s in enumerate(levels2d):
                    levels[i] = z_ordered[np.abs(cumsum-s).argmin()]
                levels.sort()
                # Draw plot
                ax[ix, iy].contour(
                    grid_x, grid_y, zi,
                    levels=levels,
                    colors=[sig_lc],
                    linewidths=1.,
                    linestyles="--"
                )

            # Scatter plot
            if scatter_outside_sigma is not None:
                # Compute threshold value
                scat_thr = z_ordered[np.abs(cumsum-scatter_thr).argmin()]
                # Nearest neighbor search
                NNDI = RegularGridInterpolator(
                    (grid_x[:, 0], grid_y[0, :]),
                    zi,
                    method="linear",
                    bounds_error=False,
                    fill_value=0.
                )
                mask = NNDI((data[:, iy], data[:, ix])) < scat_thr
                ax[ix, iy].scatter(
                    data[mask, iy], data[mask, ix],
                    marker=".",
                    s=0.5,
                    alpha=scatter_alpha,
                    c=[scat_mc])

            # Correlation coefficient
            if show_correlations:
                msg = r"$\rho = {{{:.2f}}}$".format(rho[ix, iy])
                ax[ix, iy].text(
                    0.02, 0.98, msg,
                    va="top", ha="left",
                    transform=ax[ix, iy].transAxes,
                    c=cor_tc
                )

            # Set the highlights
            if set_highlights:
                ax[ix, iy].axvline(highlight[iy], ls="-", color=hl_lc)
                ax[ix, iy].axhline(highlight[ix], ls="-", color=hl_lc)
                ax[ix, iy].plot(
                    highlight[iy], highlight[ix],
                    marker=(6, 0, 0),
                    markersize=8,
                    c=hl_mc,
                    markeredgecolor=hl_lc
                )

        # Setting limits
        if ix == Nd-1:
            #ax[ix, iy].set_xlim(data[:, iy].min(), data[:, iy].max())
            #ax[ix, iy].set_ylim(data[:, ix].min(), data[:, ix].max())
            ax[ix, iy].set_xlim(lim[iy, 0], lim[iy, 1])
        if ix > 0 and iy == 0:
            ax[ix, iy].set_ylim(lim[ix, 0], lim[ix, 1])

        # Set y-labels
        if ix > 0 and iy == 0:
            if set_labels:
                ax[ix, iy].set_ylabel(labels[ix], fontsize="x-large")
        elif iy < ix:
            ax[ix, iy].sharey(ax[ix, 0])
            plt.setp(ax[ix, iy].get_yticklabels(), visible=False)
        else:
            plt.setp(ax[ix, iy].get_yticklabels(), visible=False)

        # Set x-labels
        if ix == Nd-1:
            if set_labels:
                ax[ix, iy].set_xlabel(labels[iy], fontsize="x-large")
        else:
            ax[ix, iy].sharex(ax[Nd-1, iy])
            plt.setp(ax[ix, iy].get_xticklabels(), visible=False)

    fig.tight_layout()

    plt.show()

    return fig, ax

def sigma_to_quantile(sig: float) -> float:
    """
    Function converts standard deviation of
    a normal distribution to quantile.

    Parameters:
    -----------
    sig : float
        Standard deviation

    Returns:
    --------
    q : float
        Quantile
    """
    return _gaussian_primitive(-sig, 0., 1.)*100

def _gaussian_primitive(x: float, mu: float, sig: float) -> float:
    """
    Function returns the primitive of the normal distribution

    Parameters:
    -----------
    x : float, array-like
        Evaluation coordinate
    mu : float
        Mean of normal distribution
    sig : float
        Standard deviation of normal distribution

    Returns:
    --------
    F(x) : float, array-like
        Primitive at x
    """

    return -0.5*erf((x-mu)/(np.sqrt(2.)*sig))


#!/usr/bin/python
#-----------------------------------------------------------------------------
# Name:        scheduler.py
#
# Purpose:     This module is a script use python <schedule> module to scheduler
#              the user's tasks (call different actor module to simulate a normal
#              user's daily action).
#              <schedule> reference link: https://schedule.readthedocs.io/en/stable/
#
# Author:      Yuancheng Liu
#
# Version:     v_0.1
# Created:     2022/12/09
# Copyright:   n.a
# License:     n.a
#-----------------------------------------------------------------------------

# https://schedule.readthedocs.io/en/stable/

import os
import time
import datetime
import threading
import subprocess

import schedule

import actionGlobal as gv
import actorFunctions
import Log

DIR_PATH = os.path.dirname(__file__)
print("Current source code location : %s" % DIR_PATH)

#-----------------------------------------------------------------------------
#-----------------------------------------------------------------------------
class userAction(object):
    def __init__(self, actionName='', timeStr=None, runFunc=None, threadFlg=False) -> None:
        self.name = actionName
        self.timeStr = timeStr
        self.func = runFunc
        self.threadFlg = threadFlg
        self._jobthread = None

#-----------------------------------------------------------------------------
    def runFunc(self):
        Log.info('Start to run job: %s' %str(self.name))
        if self.func:
            try:
                if self.threadFlg:
                    self._jobthread = threading.Thread(target=self.func)
                    self._jobthread.start()
                else:
                    self.func()
            except Exception as err:
                Log.error("Run job %s error :" %str(self.name))
                Log.exception(err)
        else:
            Log.info('No function is added.')

#-----------------------------------------------------------------------------
    def jobThreadJoin(self):
        """ Join the job thread """
        if self._jobthread and self._jobthread.isAlive():
            self._jobthread.join()

#-----------------------------------------------------------------------------
#-----------------------------------------------------------------------------
class actionScheduler(object):

    def __init__(self) -> None:
        # The action dictionary
        self.actionDict = {}
        self.terminate = False

    def addAction(self, actionObj):
        if actionObj:
            #self.actionDict[actionObj.name] = actionObj
            schedule.every().day.at(actionObj.timeStr).do(actionObj.runFunc)

    def startSimulate(self):
        for job in schedule.get_jobs():
            print(job.__str__)

        while not self.terminate:
            schedule.run_pending()
            time.sleep(1)

#-----------------------------------------------------------------------------
def scheduleBobActions():
    # 09:01 ping the config peers
    timeStr = "09:01"
    userAction_0901 = userAction(actionName='09:01_ping', timeStr=timeStr, runFunc=actorFunctions.func_0901, threadFlg=False)
    gv.iScheduler.addAction(userAction_0901)

    # 09:10 ping all the ip in a range
    timeStr = "09:10"
    userAction_0910 = userAction(actionName='09:10_ping', timeStr=timeStr, runFunc=actorFunctions.func_0910, threadFlg=True)
    gv.iScheduler.addAction(userAction_0910)

    # 09:13 run window newtork cmds (this part will take long time)
    timeStr = "09:13"
    userAction_0913 = userAction(actionName='09:13_cmd', timeStr=timeStr, runFunc=actorFunctions.func_0913, threadFlg=True)
    gv.iScheduler.addAction(userAction_0913)

    # 09:20 ssh to the ncl gateway and run commands
    timeStr = "09:20"
    userAction_0920 = userAction(actionName='09:20_ssh', timeStr=timeStr, runFunc=actorFunctions.func_0920, threadFlg=False)
    gv.iScheduler.addAction(userAction_0920)

    # 09:32 do file searchinng system dir-structure check
    timeStr = "09:32"
    userAction_0932 = userAction(actionName='09:32_fileOp', timeStr=timeStr, runFunc=actorFunctions.func_0932, threadFlg=False)
    gv.iScheduler.addAction(userAction_0932)

    # 09:35 do zoom meeting.
    timeStr = "09:35"
    userAction_0935 = userAction(actionName='09:35_zoom', timeStr=timeStr, runFunc=actorFunctions.func_0935, threadFlg=False)
    gv.iScheduler.addAction(userAction_0935)

    # 10:15 download cert, image, css file , js file from a list of webs.
    timeStr = "10:15"
    userAction_1015 = userAction(actionName='10:15_downloadWeb', timeStr=timeStr, runFunc=actorFunctions.func_1015, threadFlg=True)
    gv.iScheduler.addAction(userAction_1015)

    # 10:40 watch some youTube video
    timeStr = "10:40"
    userAction_1040 = userAction(actionName='10:45_Youtube', timeStr=timeStr, runFunc=actorFunctions.func_1040, threadFlg=False)
    gv.iScheduler.addAction(userAction_1040)

    # 10:50 edit word doc
    timeStr = "10:50"
    userAction_1050 = userAction(actionName='10:50_OfficeWord', timeStr=timeStr, runFunc=actorFunctions.func_1050, threadFlg=False)
    gv.iScheduler.addAction(userAction_1050)

    # 11:25 edit word doc
    timeStr = "11:25"
    userAction_1125 = userAction(actionName='11:25_OfficePPT', timeStr=timeStr, runFunc=actorFunctions.func_1125, threadFlg=False)
    gv.iScheduler.addAction(userAction_1125)

    # 11:35 playgame
    timeStr = "11:35"
    userAction_1135 = userAction(actionName='11:35_playgame', timeStr=timeStr, runFunc=actorFunctions.func_1135, threadFlg=False)
    gv.iScheduler.addAction(userAction_1135)

    # 13:10 ping another 100 ip address in subnet2
    timeStr = "13:10"
    userAction_1310 = userAction(actionName='13:10_ping', timeStr=timeStr, runFunc=actorFunctions.func_1310, threadFlg=False)
    gv.iScheduler.addAction(userAction_1310)

    # 13:45 test ssh to different host
    timeStr = "13:45"
    userAction_1345 = userAction(actionName='13:45_ssh', timeStr=timeStr, runFunc=actorFunctions.func_1345, threadFlg=False)
    gv.iScheduler.addAction(userAction_1345)

    # 14:10 turn off the firewall
    timeStr = "14:10"
    userAction_1410 = userAction(actionName='14:10_offFw', timeStr=timeStr, runFunc=actorFunctions.func_1410, threadFlg=False)
    gv.iScheduler.addAction(userAction_1410)

    # 14:10 download some thing from webs
    timeStr = "14:30"
    userAction_1430 = userAction(actionName='14:30_webdownload', timeStr=timeStr, runFunc=actorFunctions.func_1430, threadFlg=False)
    gv.iScheduler.addAction(userAction_1430)

    # 14:50 send message/file by UDP
    timeStr = "14:50"
    userAction_1450 = userAction(actionName='14:50_UDP communication', timeStr=timeStr, runFunc=actorFunctions.func_1450, threadFlg=False)
    gv.iScheduler.addAction(userAction_1450)

    # 15:15 edit ppt
    timeStr = "15:15"
    userAction_1515 = userAction(actionName='15:15_MS-PPT_edit', timeStr=timeStr, runFunc=actorFunctions.func_1515, threadFlg=False)
    gv.iScheduler.addAction(userAction_1515)

    # 15:20 play game
    timeStr = "15:20"
    userAction_1520 = userAction(actionName='playgame', timeStr=timeStr, runFunc=actorFunctions.func_1520, threadFlg=False)
    gv.iScheduler.addAction(userAction_1520)

    # 15:40 run network cmds
    timeStr = "15:40"
    userAction_1540 = userAction(actionName='check network', timeStr=timeStr, runFunc=actorFunctions.func_0913, threadFlg=False)
    gv.iScheduler.addAction(userAction_1540)

    # 15:55 edit ppt
    timeStr = "15:55"
    userAction_1555 = userAction(actionName='15:55_MS-PPT_edit', timeStr=timeStr, runFunc=actorFunctions.func_1555, threadFlg=False)
    gv.iScheduler.addAction(userAction_1555)

    # 16:00 watch video and listen music
    timeStr = "16:00"
    userAction_1600 = userAction(actionName='16:00_watch video', timeStr=timeStr, runFunc=actorFunctions.func_1600, threadFlg=False)
    gv.iScheduler.addAction(userAction_1600)

    # 16:40 check and open pic
    timeStr = "16:35"
    userAction_1635 = userAction(actionName='16:00_check pic', timeStr=timeStr, runFunc=actorFunctions.func_1635, threadFlg=False)
    gv.iScheduler.addAction(userAction_1635)

    # 17:00 check and open pic
    timeStr = "17:00"
    userAction_1700 = userAction(actionName='17:00_UDP communication', timeStr=timeStr, runFunc=actorFunctions.func_1450, threadFlg=False)
    gv.iScheduler.addAction(userAction_1700)

    # 17:25 wite ppt report summary
    timeStr = "17:25"
    userAction_1725 = userAction(actionName='17:25_MS-PPT_edit', timeStr=timeStr, runFunc=actorFunctions.func_1725, threadFlg=False)
    gv.iScheduler.addAction(userAction_1725)

    # 17:35 edit word doc
    timeStr = "17:35"
    userAction_1735 = userAction(actionName='17:35_OfficeWord', timeStr=timeStr, runFunc=actorFunctions.func_1050, threadFlg=False)
    gv.iScheduler.addAction(userAction_1735)

    # 17:35 edit word doc
    timeStr = "17:40"
    userAction_1740 = userAction(actionName='17:40_ReadEmail', timeStr=timeStr, runFunc=actorFunctions.func_1740, threadFlg=False)
    gv.iScheduler.addAction(userAction_1740)

    # 17:35 edit word doc
    timeStr = "18:10"
    userAction_1810 = userAction(actionName='17:35_WriteEmail', timeStr=timeStr, runFunc=actorFunctions.func_1810, threadFlg=False)
    gv.iScheduler.addAction(userAction_1810)

#-----------------------------------------------------------------------------
#-----------------------------------------------------------------------------
def main(actorName):
    gv.iScheduler = actionScheduler()

    if actorName == 'Bob':
        scheduleBobActions()
        gv.iScheduler.startSimulate()

def testCase(mode):

    timeData = datetime.datetime.now()
    minDelay = datetime.timedelta(seconds = 60)

    # Task 1: ping

    timeData+= datetime.timedelta(seconds = 10)
    nextMin = timeData.strftime("%H:%M:%S")
    print(nextMin)
    userAction1 = userAction(actionName='action1', timeStr=nextMin, runFunc=func1, threadFlg=False)

    # Task 1_1: run server windows cmds.
    def func1_1():
        appFolder = 'UtilsFunc'
        appName = 'funcActor.py'
        appPath = os.path.join(DIR_PATH, appFolder, appName)
        cmd = "python %s" %str(appPath)
        subprocess.call(cmd, creationflags=subprocess.CREATE_NEW_CONSOLE)
    timeData+= datetime.timedelta(seconds = 10)
    nextMin = timeData.strftime("%H:%M:%S")
    print(nextMin)
    userAction1 = userAction(actionName='action1_1', timeStr=nextMin, runFunc=func1_1, threadFlg=False)
    schedule.every().day.at(userAction1.timeStr).do(userAction1.runFunc)

    # start Zoom meeting
    def func2():
        appFolder = 'UtilsFunc'
        appName = 'zoomActor.py'
        appPath = os.path.join(DIR_PATH, appFolder, appName)
        cmd = "python %s" %str(appPath)
        subprocess.call(cmd, creationflags=subprocess.CREATE_NEW_CONSOLE)
    timeData += minDelay
    nextMin = timeData.strftime("%H:%M:%S")
    userAction2 = userAction(actionName='action2', timeStr=nextMin, runFunc=func2, threadFlg=False)
    schedule.every().day.at(userAction2.timeStr).do(userAction2.runFunc)

    # Draw picture
    def func3():
        os.startfile("C:\\Works\\NCL\\Project\\Windows_User_Simulator\\src\\dist\\actionSimulator.exe")

    timeData += minDelay
    nextMin = timeData.strftime("%H:%M:%S")
    userAction3 = userAction(actionName='action3', timeStr=nextMin, runFunc=func3, threadFlg=True)
    schedule.every().day.at(userAction3.timeStr).do(userAction3.runFunc)

    # playgame
    def func4():
        appFolder = 'UtilsFunc'
        appName = 'dinoActor.py'
        appPath = os.path.join(DIR_PATH, appFolder, appName)
        cmd = "python %s" %str(appPath)
        subprocess.call(cmd, creationflags=subprocess.CREATE_NEW_CONSOLE)
        #subprocess.call('python C:\\Works\\NCL\\Project\\Windows_User_Simulator\\src\\UtilsFunc\\dinoActor.py', creationflags=subprocess.CREATE_NEW_CONSOLE)

    timeData += minDelay
    nextMin = timeData.strftime("%H:%M:%S")
    userAction3 = userAction(actionName='action4', timeStr=nextMin, runFunc=func4, threadFlg=True)
    schedule.every().day.at(userAction3.timeStr).do(userAction3.runFunc)

    print(schedule.get_jobs())

    #while True:
    #    schedule.run_pending()
    #    time.sleep(1)

if __name__ == '__main__':
    #testCase(1)
    main('Bob')


from connection.connection import Connection

class PeriodoRepo:

    def __init__(self,mes,año):
        self.mes = mes
        self.año = año

    def all_periodos(self):
        try:
            conn = Connection('periodo')
            records = conn.select([])

            for record in records:
                print(f'ID: {record[0]}')
                print(f'Mes: {record[1]}')
                print(f'Año: {record[2]}')
                print(f'Estado: {record[3]}')
                print('=====================')
        except Exception as e:
            print(e)

    def one_periodo(self,id):
        try:
            conn = Connection('periodo')
            records = conn.selectOne(id)

            print(f'ID: {records[0]}')
            print(f'Mes: {records[1]}')
            print(f'Año: {records[2]}')
            print(f'Estado: {records[3]}')
            print('=====================')
            return records
        except Exception as ex:
            print(ex)

    def insert_periodo(self, data):

        try:
            conn = Connection('periodo')
            conn.insert(data)

            print(f'se registro correctamente el periodo')

        except Exception as ex:
            print(ex)

    def update_periodo(self, id_object, data):

        conn = Connection('periodo')

        list_where = []
        for field_name, field_value in id_object.items():
            if isinstance(field_value, str):
                field_value = f"'{field_value}'"
            list_where.append(f"{field_name}={field_value}")

        list_update = []
        for field_name, field_value in data.items():
            if isinstance(field_value, str):
                field_value = f"'{field_value}'"
            list_update.append(f"{field_name}={field_value}")

        query = f'''
            UPDATE {conn.table_name} SET {', '.join(list_update)}
            WHERE {' AND '.join(list_where)}
        '''
        conn.execute_query(query)
        return True

    def inhabilitar_periodo(self,parameter, id_object):
        conn = Connection('periodo')
        conn.disable(parameter, id_object)
        return True

    def periodos_habilitados(self):
        conn = Connection('periodo')
        query = f'''
            SELECT * FROM {conn.table_name} WHERE estado = 'true'
        '''
        conn.cursor.execute(query)
        records = conn.cursor.fetchall()

        for record in records:
                print(f'ID: {record[0]}')
                print(f'Mes: {record[1]}')
                print(f'Año: {record[2]}')
                print(f'Estado: {record[3]}')
                print('=====================')


import torch
import numpy as np
import matplotlib.pyplot as plt
from MyDataset import MyDataset
from SNN import SimpleLeakySNN, SimpleSynapticSNN
from SpikeEncoder import rate_encoder, latency_encoder
from torch.utils.data import DataLoader

def print_batch_accuracy(data, targets, train=False):
    output, _ = net(data)
    _, idx = output.sum(dim=0).max(1)
    acc = np.mean((targets == idx).detach().cpu().numpy())

    if train:
        print(f"Train set accuracy for a single minibatch: {acc * 100:.2f}%")
    else:
        print(f"Test set accuracy for a single minibatch: {acc * 100:.2f}%")

def train_printer():
    print(f"Epoch {epoch}, Iteration {iter_counter}")
    print(f"Train Set Loss: {train_loss_hist[counter]:.2f}")
    print(f"Test Set Loss: {test_loss_hist[counter]:.2f}")
    print_batch_accuracy(spk, targets, train=True)
    print_batch_accuracy(test_spk, test_targets, train=False)
    print("\n")

dtype = torch.float
device = torch.device("cuda") if torch.cuda.is_available() else torch.device("cpu")

# Network architecture
num_inputs = 128
num_hidden = 1024
num_outputs = 6
num_steps = 32
net = SimpleLeakySNN(num_inputs, num_hidden, num_outputs, num_steps).to(device)

# Initialize optimizer and loss function
optimizer = torch.optim.Adam(net.parameters(), lr=1e-4, betas=(0.9, 0.999))
loss = torch.nn.CrossEntropyLoss()

# Create dataset and dataLoader
batch_size = 128
train_dataset = MyDataset(train=True)
test_dataset = MyDataset(train=False)
train_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True, drop_last=True)
test_loader = DataLoader(test_dataset, batch_size=batch_size, shuffle=True, drop_last=True)

# Training settings and record
num_epochs = 20
train_loss_hist = []
train_acc_hist = []
test_loss_hist = []
test_acc_hist = []
counter = 0

for epoch in range(num_epochs):
    iter_counter = 0
    train_batch = iter(train_loader)

    for targets, data in train_batch:
        # Spike encoder for data
        spk = rate_encoder(data, num_steps)

        spk = spk.to(device)
        targets = targets.to(device)
        # Forward pass
        net.train()
        spk_rec, mem_rec = net(spk)

        # Initialize the loss and sum over time
        loss_val = torch.zeros(1, dtype=dtype, device=device)
        for step in range(num_steps):
            loss_val += loss(mem_rec[step], targets)

        # Gradient calculation and weight update
        optimizer.zero_grad()
        loss_val.backward()
        optimizer.step()

        # Store train loss history
        train_loss_hist.append(loss_val.item())

        # Test set
        with torch.no_grad():
            net.eval()
            test_targets, test_data = next(iter(test_loader))
            test_spk = rate_encoder(test_data, num_steps)
            test_spk = test_spk.to(device)
            test_targets = test_targets.to(device)

            # Test set forward pass
            test_spk_rec, test_mem_rec = net(test_spk)

            # Test set loss
            test_loss = torch.zeros(1, dtype=dtype, device=device)
            for step in range(num_steps):
                test_loss += loss(test_mem_rec[step], test_targets)
            test_loss_hist.append(test_loss.item())

            if counter % 50 == 0:
                train_printer()
            counter += 1
            iter_counter += 1

# Plot Loss
fig = plt.figure(facecolor="w", figsize=(10, 5))
plt.plot(train_loss_hist)
plt.plot(test_loss_hist)
plt.title("Loss Curves")
plt.legend(["Train Loss", "Test Loss"])
plt.xlabel("Iteration")
plt.ylabel("Loss")
plt.show()


import numpy as np
from math import inf
from modAL.models import BayesianOptimizer
from modAL.acquisition import max_EI
from sklearn.gaussian_process import GaussianProcessRegressor
from sklearn.gaussian_process.kernels import Matern, RBF

from active_learning import ActiveLearner

def max_std(optimizer, X, n_instances=1):
    std_values = optimizer.predict(X, return_std=True)[1]
    # query_idx = np.argmax(std_values)

    max_idx = np.argpartition(-std_values, n_instances - 1, axis=0)[:n_instances]
    return max_idx

    # return query_idx, X[query_idx]

def max_std_repr(optimizer, X, n_instances=1):
    alpha = 0.5
    n_samples = X.shape[0]
    # Get distance pairs
    d_matrix = np.zeros((n_samples, n_samples))
    for i in range(n_samples-1):
        d_matrix[i, i+1:] = np.linalg.norm(X[i] - X[i+1:], axis=1)

    cl = np.zeros(n_samples)
    # Get distance for each sample
    for i in range(n_samples):
        s1 = np.sum(d_matrix[:i, i])
        s2 = np.sum(d_matrix[i, i:])
        cl[i] = 1 / (s1 + s2)

    #Normalize distance
    cl_max = np.max(cl)
    cl_min = np.min(cl)
    cl = (cl - cl_min) / (cl_max - cl_min)

    means, std_values = optimizer.predict(X, return_std=True)

    #normalize std
    std_max = np.max(std_values)
    std_min = np.min(std_values)
    std_values = (std_values - std_min) / (std_max - std_min)

    values = std_values + alpha * cl

    max_idx = np.argpartition(-values, n_instances - 1, axis=0)[:n_instances]
    return max_idx

class AL_GPR(ActiveLearner):

    def __init__(self, x_train, y_train, x_test, y_test):
        # kernel = RBF(length_scale=1e-2)
        kernel = Matern(length_scale=1e-2)
        regressor = GaussianProcessRegressor(kernel=kernel)
        super().__init__(estimator=regressor, x_train=x_train, y_train=y_train, x_test=x_test, y_test=y_test)
        self.optimizer = BayesianOptimizer(estimator=regressor, query_strategy=max_std_repr)

    def teach(self, train_x, train_y):
        self.optimizer.teach(train_x, train_y)

    def query(self, data_x):
        query_idx, _ = self.optimizer.query(data_x)
        return query_idx

    def initialize_model(self, known_idx):
        self.optimizer.teach(self.x_train[known_idx], self.y_train[known_idx])


from mpl_toolkits.mplot3d import axes3d, Axes3D
import matplotlib.pyplot as plt
import numpy as np
from matplotlib import cm

def par_to_dec(u_w):
    u, w = u_w
    x = u * (1 - w)
    y = w
    z = u
    return x, y, z

def Q(u, w):
    arr1 = np.array([1 - u, u])
    arr2 = np.array([1 - w, w])

    x = np.matmul(np.matmul(P[:, :, 0], arr1), arr2)
    y = np.matmul(np.matmul(P[:, :, 1], arr1), arr2)
    z = np.matmul(np.matmul(P[:, :, 2], arr1), arr2)
    # x, y, z = par_to_dec(q)
    return np.array([x, y, z])

def find_points(u, w):
    points = []
    for uu in u:
        for ww in w:
            points.append(Q(uu, ww))
    return np.array(points)

def plot_3d_surface(points, points1, points2):
    plot1 = plt.figure(0, figsize=(7, 7))
    ax = plot1.add_subplot(projection='3d')
    ax.scatter(points[:, 0], points[:, 1], points[:, 2], color='#7379ff', alpha=0.2)
    ax.scatter(points1[:, 0], points1[:, 1], points1[:, 2], color='#484167', alpha=0.7)
    ax.scatter(points2[:, 0], points2[:, 1], points2[:, 2], color='#484167', alpha=0.7)
    ax.set_xlabel('X')
    ax.set_ylabel('Y')
    ax.set_zlabel('Z')
    # ax1.scatter(points[:, 0], points[:, 1], points[:, 2], c=points[:, 2],  cmap='viridis', alpha=0.5)

def plot_projections(points):
    plot2, (ax1, ax2, ax3) = plt.subplots(3, figsize=(4, 10))
    ax1.scatter(points[:, 1], points[:, 2], c=points[:, 2], cmap='Purples', zorder=3)
    ax2.scatter(points[:, 0], points[:, 2], c=points[:, 2], cmap='Purples', zorder=3)
    ax3.scatter(points[:, 0], points[:, 1], c=points[:, 2], cmap='Purples', zorder=3)
    ax1.grid(zorder=0)
    ax2.grid(zorder=0)
    ax3.grid(zorder=0)

    ax1.set_xlabel('Y')
    ax1.set_ylabel('Z')
    ax2.set_xlabel('X')
    ax2.set_ylabel('Z')
    ax3.set_xlabel('X')
    ax3.set_ylabel('Y')

if __name__ == "__main__":
    u = np.arange(0.0, 1.0, 1.0/50)
    w = np.arange(0.0, 1.0, 1.0/50)

    p1 = np.array([0, 0])
    p2 = np.array([0, 1])
    p3 = np.array([1, 0])
    p4 = np.array([1, 1])

    P = np.array([[par_to_dec(p1), par_to_dec(p2)],
                  [par_to_dec(p3), par_to_dec(p4)]])

    points = find_points(u, w)
    points1 = find_points(np.array([0, 1]), w)
    points2 = find_points(u, np.array([0, 1]))

    plot_3d_surface(points, points1, points2)
    plot_projections(points)
    plt.show()


import matplotlib.pyplot as plt
import numpy as  np

import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim

from eloss import losstest, SoftDiceLoss
from DataLoader import test
from torch.utils.data import DataLoader
import os
os.environ['CUDA_VISIBLE_DEVICES'] = '2'
color = ['r', 'g', 'b', 'c', 'm', 'y', 'k', 'w']
line_style = ['-', '--', '-.']

'''

'''
def train(model, dataset, lr, epochs, batch_size, loss_func, SaveEach:bool = False):
    print("Begin trainning...")
    optimizer = optim.Adam(model.parameters(), lr = lr)
    if torch.cuda.is_available():
        device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
        model = model.to(device)
    print("Loading model to GPU...")
    history_t = []
    history_v = []
    tloss = 0
    #dataset = DataLoader(dataset=Full_dataset, batch_size=batch_size, shuffle=False)
    (train, test) = dataset
    train = DataLoader(dataset=train, batch_size=batch_size, shuffle=False)
    #print("Begin trainning...")
    test = DataLoader(dataset=test, batch_size=batch_size, shuffle=False)
    #print("Begin trainning...")
    for epoch in range(epochs):
        print("Epoch: {}".format(epoch))
        train_step = 0
        for i, data in enumerate(train):
            (input, target) = data
            '''
            # 如果GPU可用，将模型和张量加载到GPU上
            if torch.cuda.is_available():
                input = input.cuda()
                target = target.cuda()
            '''
            output = model(input)
            #print(output)
            target = torch.sigmoid(target)
            loss = loss_func(output, target)
            optimizer.zero_grad()
            loss.backward()
            optimizer.step()
            train_step = train_step + 1
            if train_step % 10 == 0:
                print("Train_step: {}, loss: {}".format(train_step, loss.item()))
        print("Epoch:{}, Loss:".format(epoch))
        history_t.append(tloss)
        # Testing Step start.
        total_test_loss = 0

        with torch.no_grad():
            for i, data in enumerate(test):
                (input, targets) = data
                targets = torch.sigmoid(targets)
                outputs = model(input)
                loss = loss_func(outputs, targets)
                if i % 10 == 0:
                    print("Validation Step {} : {}" .format(i, loss.item()))
                total_test_loss = total_test_loss + loss.item()
        print("Total Test Loss: {}".format(total_test_loss))
        try:
            if total_test_loss > history_v[-1]:
                lr *= 0.1
                optimizer = optim.Adam(model.parameters(), lr = lr)
        except:
            pass
        history_v.append(total_test_loss)

        '''
        Consider the model is too big to save so much version.
        '''
        if SaveEach:
            torch.save(test, "test_{}.pth".format(i))
            print("The model has been saved.")

    return 1

def validation(model, val):
    loss_func = SoftDiceLoss(1)
    total_loss = 0
    val = DataLoader(val, batch_size=16, shuffle=False)
    with torch.no_grad():
        for i, data in enumerate(val):
            (input, target) = data
            output = model(input)
            loss = loss_func(output, target)
            total_loss = total_loss + loss.item()
        print("Validation Loss: {}".format(total_loss))

'''
Name: draw_chart
Function: Using the data and its name(type) to draw a chart.

para:
    data(list):
        include [(x1, y1) , (x2, y2), ...]
        the x1 y1 are list too.

    type(list):
        include the name of (x1, y1)...
        [name1, name2, ...]

    savefig(bool):
        default = True. Decide whether to save the chart as file.
'''
def draw_chart(data:list, type:list, savefig:bool=True, save_dir:str = './result.png'):
    lend = len(data)
    lent = len(type)
    try:
        assert lend == lent
    except:
        print("Draw chart Failure. The size of data{}, bu the size of type{}".format(lend, lent))
        exit(1)

    plt.figure(figsize=(20, 10), dpi=100)
    for i in range(lend):
        (x, y) = data[i]
        name = type[i]
        plt.plot(x, y, color[i], marker='*', markersize=2)

    plt.legend(type)
    plt.show()
    if savefig:
        plt.savefig(save_dir)
    else:
        pass

    return;

'''
Name: normalization
Function: Use the formule x = (x - Min)/(Max - Min), to get the data to [0, 1]

para:
    input(list):
        the input

return:
    the result(input(list))
'''
def normalization(input:list):
    maxVal = max(input)
    minVal = min(input)
    input = (input - minVal)/(maxVal - minVal)
    return input
'''
Name: chart_two
Function: To draw two data in the same chart. (Will normalize)

para:
    data1(tuple):
        input data1, the tuple include (x1:list, y1:list)
    data2(tuple):
        same as data1
    name(tuple):
        include the name of data1 and data2. like (name1, name2)
    savefig(bool): default = True
        To determine whether you want to save the chart as a png image.

'''
def chart_two(data1:tuple, data2:tuple, name:tuple, savefig:bool = True):
    (x1, y1) = data1
    (x2, y2) = data2
    (name1, name2) = name
    x1 = normalization(x1)
    y1 = normalization(y1)
    x2 = normalization(x2)
    y2 = normalization(y2)
    plt.figure(figsize=(20, 10))
    plt.plot(x1, y1, 'r', '*')
    plt.plot(x2, y2, 'y', '*')
    plt.show()

if __name__ == "__main__":
    losstest()
    test()


from django.urls import path
from .views import IndexView, DetailItemView, CreateItemView, UpdateItemView, DeleteItemView

urlpatterns = [
    path('', IndexView.as_view(), name='index'),
    path('<int:pk>/', DetailItemView.as_view(), name='detail_view'),
    path('create/', CreateItemView.as_view(), name='create'),
    path('<int:pk>/update/', UpdateItemView.as_view(), name='update'),
    path('<int:pk>/delete/', DeleteItemView.as_view(), name='delete'),
]


import sys, math

def main():
    '''
    Given file data about cubes we will find the smallest number of cubes it takes to fill cube A
    '''
    cubeInfo = parseInput() # parse input
    for info in range(0, len(cubeInfo)): # loop through the lines of the list
        cubeA, nCubes = volumeofCubeA(cubeInfo[info]) # extract volume and cube list data
        fillCubeCount = calculateCubes(cubeA, nCubes) # whats the smallest number of cubes it takes to fill cube A
        print(fillCubeCount)
        print()
        fillCubeCount = 0 # reset for next line

def calculateCubes( cubeA, nCubes):
    '''
    params:
        cubeA: the volume of the cube we are filling
        nCubes: the list of cubes we are filling cube A with
        fillCubeCount:  starts as zero and as we subtract cube volumnes from cube A we add to This
    return:
        -1 if we cant fill cube A
        fillCubeCount if we did fill cube A
    '''
    if cubeA == 0: # the cube is not fillable because it dosent take up space
        return -1

    fillCubeCount = 0
    for cube in range(len(nCubes)-1, -1, -1):
        # go backwards through the list to subtract the maximum cube sizes first
        # this will minimize the number of cubes it takes to fill cube A
        volumeOfCubeN = pow(pow(2,cube),3)

        # continue subtracting values when we still have space left in Cube A and we still have cubes in to subtract with
        # and the volume of cube N is not zero and the volume of cube N is less than the volume of cube A
        while(cubeA >= 0  and nCubes[cube] > 0 and nCubes[cube] != 0 and volumeOfCubeN <= cubeA):
            # print("cubeA: " + str(cubeA) + " - volume of cube at " +str(cube)+ " where the volume is " + str(pow(pow(2,cube),3)))
            cubeA = cubeA - volumeOfCubeN
            nCubes[cube] = nCubes[cube] - 1
            fillCubeCount = fillCubeCount + 1

    if cubeA > 0: # we did not fill the cube all the way
        return -1

    return fillCubeCount

def volumeofCubeA( listOfCubes ):
    '''
    this calculates the volume of cube A, or the cube we are trying to fill
    returns the volume of cube A and the list of cubes N without cube A's dimensions
    ex:

    '''
    #      length           * width            * height          , [x, y, ... z]
    return listOfCubes[0] * listOfCubes[1] * listOfCubes[2], listOfCubes[3:]

def parseInput():
    '''
    This function checks for command line input or standard in for file information
    and converts it into a line by line list,
    I am going to assume for now that only valid files will be used.
    returns a list of all cube data
    '''
    lines = ""

    # command line input
    if len(sys.argv) > 1:
        with open(sys.argv[1], encoding="utf-8") as file:
            lines = [l.strip() for l in file]

    # sdandard in
    else:
        lines = sys.stdin.readlines()
        lines = [l.strip() for l in lines]

    # make it a list of integers and strip spaces
    actual = []
    for item in range(0, len(lines)):
        temp = lines[item].split(" ")
        temp = list(map(int, temp))
        actual.append(temp)

    return actual
if __name__ == "__main__": main()


from main import ud_to_um, morph_translation
import argparse

parser = argparse.ArgumentParser(description='Cross-inflect a UD treebank using a seq2seq model trained on UM data')
parser.add_argument('--treebank_folder', help='Directory where the UD treebank files are located', required=True)
parser.add_argument('--post_lang', help='Language dependent postprocessing to improve the feature conversion', required=False, default='')

parser.add_argument('--model_folder', help='Directory where the inflection model is located', required=True)
parser.add_argument('--output', help='Output location of the cross-inflected treebank', required=True)
parser.add_argument('--pos_types', help='POS tags that are cross-inflected', required=False, default=['ADJ','NOUN','VERB'])
args = parser.parse_args()

if __name__ == '__main__':
    ud_to_um(args.post_lang, args.treebank_folder)
    morph_translation(args.treebank_folder, args.model_folder, args.pos_types, args.output, args.post_lang)