import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestRegressor
from sklearn import metrics

# Data collection and processing
# Loading csv file into a pandas dataframe

gold_data = pd.read_csv('D:\Programing\pythonProject\gold price prediction\gld_price_data.csv')

print(gold_data.head(), gold_data.tail())

# find correlation

correlation = gold_data.corr()
# print(correlation)

x = gold_data.drop(['Date', 'GLD'], axis=1)
y = gold_data['GLD']

# splitting testing and training data

x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.2, random_state=2)

# model training: random forest algorithm

regressor = RandomForestRegressor(n_estimators=100)

# model training

regressor.fit(x_train, y_train)

# model evaluation: prediction on test data

test_data_prediction = regressor.predict(x_test)
print(test_data_prediction)

error_score = metrics.r2_score(y_test, test_data_prediction)
print(error_score)

# compare actual value and predict value

y_test = list(y_test)
plt.plot(y_test, color='blue', label='Actual value')
plt.plot(test_data_prediction, color='orange', label='Predicted value')
plt.title("Actual Price vs Predict Value")
plt.xlabel('Number value')
plt.ylabel("Gold price")
plt.legend()
plt.show()


import pytrec_eval
import json
import read_ap
import lsi_lda
from tf_idf import TfIdfRetrieval
from tqdm import tqdm
import scipy.stats
import pickle
import csv
import analysis

qrels, queries = read_ap.read_qrels()
val_keys = [key for key in qrels.keys() if int(key) >= 76 and int(key) <= 100]
test_keys = [key for key in qrels.keys() if key not in val_keys]
test_queries = {key : queries[key] for key in test_keys}
test_qrels = {key : qrels[key] for key in test_keys}
val_queries = {key : queries[key] for key in val_keys}
val_qrels = {key : qrels[key] for key in val_keys}

def evaluate(model, queries, qrels):
	run = {}

	print("Collecting results.")
	for key in tqdm(queries.keys()):
		results = model.search(queries[key])
		run[key] = {ref : score for ref, score in results}

	evaluator = pytrec_eval.RelevanceEvaluator(qrels, {'map', 'ndcg'})
	# data = json.dumps(, indent=1)

	return evaluator.evaluate(run)

def get_averages(data):
	mapp = 0
	ndcg = 0

	n = len(data)

	for i in data:
		mapp += data[i]['map']
		ndcg += data[i]['ndcg']

	return mapp/n, ndcg/n

def get_model(idx):
	# TF-IDF MODEL
	if idx == 1:
		docs_by_id = read_ap.get_processed_docs()
		model = TfIdfRetrieval(docs_by_id)
		return model

	# LSI BINARY MODEL
	elif idx == 2:
		return lsi_lda.LSIRetrieval('binary')

	# LSI TF-IDF MODEL
	elif idx == 3:
		return lsi_lda.LSIRetrieval('tfidf')

	# LDA MODEL
	elif idx == 4:
		return lsi_lda.LDARetrieval()

	elif idx == 5:
		return analysis.Word2Vec()

	# LSI BINARY 5 TOPICS
	elif idx == 12:
		return lsi_lda.LSIRetrieval('binary', path="lsi/5topics", num_topics=5)

def make_results_file(model, run_name, folder='result_files/'):
	file_lines = []
	for query_id in test_keys:
		results = model.search(test_queries[query_id])

		for i, content in enumerate(results):
			doc_id, score = content
			line = query_id + ' Q0 ' + doc_id + ' ' + str(i+1) + ' ' + "{:.6f}".format(score) + ' ' + run_name
			file_lines.append(line)

	path = folder + run_name + '.txt'

	with open(path, 'w') as f:
	    for item in file_lines:
	        f.write("%s\n" % item)

def analysis3_1(model):
	topics = model.get_top_topcis(5, 10)

	for i,terms in enumerate(topics):
		s = ', '.join(terms)
		print('Topic ' + str(i+1) + ': ' + s)

def analysis4_2(model1, model2):
	res1 = evaluate(model2, queries, qrels)
	res2 = evaluate(model2, queries, qrels)

	query_ids = list(set(res1.keys()) & set(res2.keys()))

	first_scores = [res1[query_id]['map'] for query_id in query_ids]
	second_scores = [res2[query_id]['map'] for query_id in query_ids]

	print(scipy.stats.ttest_rel(first_scores, second_scores))

def analysis4_1(model):
	res_all = evaluate(model, queries, qrels)
	res_test = evaluate(model, val_queries, val_qrels)

	print('Results for val set:')
	print("Map : % .2f, nDCG : % .2f" %(get_averages(res_test)))

	print('Results for all queries:')
	print("Map : % .2f, nDCG : % .2f" %(get_averages(res_all)))

##
# print('ANALISIS 4.1\n')

# print('TF-IDF MODEL:')
# analysis4_1(get_model(1))

# print('BINARY LSI MODEL')
# analysis4_1(get_model(2)
# 	)
# print('TFIDF LSI MODEL')
# analysis4_1(get_model(3))

# print('LDA MODEL')
# analysis4_1(get_model(4))

# analysis4_2(get_model(2), get_model(4))

# analysis4_1(get_model(12))

# make_results_file(get_model(5), 'word2vec')

# analysis4_1(get_model(5))


'''This module contains auxiliary types that are not TeXElements but are
used internally in their implementation.'''

import copy as _copy
import sys as _sys

#===============================================================================
# Linked elements
#===============================================================================
class Element:
    '''An element that have an prev/next relationship with other Elements.

    Note on implementation: the information about the prev/next relationships
    is stored into a MasterList object external to the Element. This object
    guarantees a consistent relation among a group of Elements and also offer
    a list-like interface to access those elements.

    Master lists can be created separately or implicitly as in the example usage
    bellow:

    >>> class pnstr(str, Element): pass
    >>> a = pnstr('a')
    >>> a.insert_next(pnstr('b'))
    >>> a.get_siblings()
    ['a', 'b']

    >>> a.get_siblings_next()
    ['b']
    >>> a.get_siblings_prev()
    []

    Deepcopy operations return unlinked objects

    >>> import copy
    >>> A = copy.deepcopy(a); A.get_siblings()
    ['a']

    Elements do not define a __init__() method, hence it does not need to be
    called expliclty by subclasses.
    '''
    # TODO: reimplement the reference system to remove the _masterlist attribute
    # so we can define __slots__ on subtypes
    #
    # If we had defined __slots__ = ('masterlist') here, it would be impossible
    # to have multiple inheritance with C-types such as str, list, etc.

    _masterlist = None

    def _set_masterlist(self, mlist):
        mlist_old = self._masterlist
        if mlist_old is not None and mlist_old is not mlist:
            raise ValueError('%r already in a Masterlist' % self)
        else:
            self._masterlist = mlist

    def __getstate__(self):
        state = dict(self.__dict__)
        state.pop('_masterlist', None)
        return state

    def unlink(self):
        '''Remove itself from list.'''

        if self._masterlist is not None:
            self._masterlist.pop(self.idx)

    def unlinked(self):
        '''Remove iteself from list and return'''

        self.unlink()
        return self

    def copy_unlinked(self, deepcopy=True):
        '''Return a copy of itself'''

        try:
            ml = self.__dict__.pop('_masterlist', None)
            if deepcopy:
                cp = _copy.deepcopy(self)
            else:
                cp = _copy.copy(self)
        finally:
            self._masterlist = ml
        return cp

    def replace_by(self, other):
        '''Replace itself by the other object.

        The object will be unlinked from the list.'''

        if self._masterlist is not None:
            self._masterlist[self.idx] = other
        else:
            raise ValueError('object is not linked')

    def insert_next(self, obj):
        '''Insert obj in the lists of objects just after itself'''

        if self._masterlist is not None:
            self._masterlist.insert(self.idx + 1, obj)
        else:
            self._masterlist = Masterlist([obj])
            self._masterlist.insert(0, self)

    def insert_prev(self, obj):
        '''Insert the given object prior to itself'''

        if self._masterlist is not None:
            self._masterlist.insert(self.idx, obj)
        else:
            self._masterlist = Masterlist([obj])
            self._masterlist.append(self)

    def get_masterlist(self):
        '''Return the master list that controls the prev/next relationships for
        the object'''

        return self._masterlist or Masterlist([self])

    #===========================================================================
    # Properties
    #===========================================================================
    @property
    def idx(self):
        try:
            return self._masterlist.index(self)
        except AttributeError:
            return None

    @property
    def next(self):
        try:
            L = self._masterlist
            return L[L.index(self) + 1]
        except (IndexError, AttributeError):
            return None

    @property
    def prev(self):
        try:
            L = self._masterlist
            idx = L.index(self)
            return L[idx - 1] if idx else None
        except (IndexError, AttributeError):
            return None

    @property
    def has_siblings(self):
        try:
            return len(self._masterlist or []) > 1
        except AttributeError:
            return False

    def get_siblings(self):
        return list(self._masterlist or [self])

    def get_siblings_next(self):
        '''A list of all siblings after itself'''

        try:
            return self._masterlist[self.idx + 1:]
        except AttributeError:
            return []

    def get_siblings_prev(self):
        '''Return a list of all siblings before itself'''

        try:
            return self._masterlist[:self.idx]
        except AttributeError:
            return []

    @property
    def parent(self):
        try:
            masterlist = self._masterlist
        except AttributeError:
            return None
        else:
            return getattr(masterlist, 'parent', None)

    @property
    def has_children(self):
        return False

class Container(Element):
    '''An element that have children'''

    def __init__(self):
        self._children = Masterlist([], self)

    @property
    def children(self):
        return self._children

    @property
    def has_children(self):
        return True

    def __setstate__(self, state):
        self.__dict__.update(state)
        self.children.parent = self

class Masterlist(list):
    '''Organizes a group of objects with next/prev/parent interface into a
    consistent list.

    There are few notable diferences between PrevNextLists and regular lists.
    First, duplicated elements are not allowed. The list represents a
    sequence of prev/next associations and duplicated elements would become
    circular references. For the same reason, mathematical operations are not
    allowed, since the list that shall represent these associations would become
    ambiguous.

    Usage
    -----

    Let us define a class that accept the prev/next interface in order to create
    a list of those objects

    >>> class pnstr(str, Element): pass
    >>> R, E, S, P, e, C, T = L = Masterlist(map(pnstr, 'RESPECT')); L
    ['R', 'E', 'S', 'P', 'E', 'C', 'T']

    Items know their siblings using the prev/next methods

    >>> print(R, R.next, P.prev, C.next)
    R E S T

    Items can be removed and insert in a Masterlist either using the regular
    list interface or calling the proper functions from its elements

    >>> P.unlink(); C.unlink(); L
    ['R', 'E', 'S', 'E', 'T']

    Insertions are also allowed

    >>> R.insert_prev(pnstr('P')); L
    ['P', 'R', 'E', 'S', 'E', 'T']

    Or even replace objects

    >>> deleted = L.pop()
    >>> e.replace_by(pnstr('LEY')); L
    ['P', 'R', 'E', 'S', 'LEY']

    Deleted items loose their siblings

    >>> deleted.has_siblings
    False

    Deepcopies preserve next/prev relationships

    >>> import copy
    >>> L2 = copy.deepcopy(L); L2
    ['P', 'R', 'E', 'S', 'LEY']

    We can clear a list to unlink all its elements

    >>> L.clear()
    ['P', 'R', 'E', 'S', 'LEY']
    >>> R.has_siblings
    False
    '''
    __slots__ = ['parent', '_cache']

    def __init__(self, data=None, parent=None):
        # Only accept parents of the correct type
        if not isinstance(parent, Element) and parent is not None:
            raise TypeError('invalid type for parent: %s' % type(parent).__name__)

        # Save variables and initialize
        super(Masterlist, self).__init__([])
        self.parent = parent
        self._cache = {}
        self.extend(data or [])

    # This is only a debug feature, probably not needed anymore
    if _sys.flags.debug:
        def _has_consistent_idx(self):
            correct = list(range(len(self)))
            return correct == sorted(self._cache.values()) == [ x.idx for x in self ]
    else:
        def _has_consistent_idx(self):
            return True

    def __contains__(self, obj):
        return id(obj) in self._cache

    def __delitem__(self, idx):
        if isinstance(idx, int):
            self.pop(idx)
        else:
            delidx = sorted((obj.idx for obj in self[idx]), reverse=True)
            for idx in delidx:
                del self[idx]

        # invariant checks
        assert self._has_consistent_idx()

    def __setitem__(self, idx, value):
        cache = self._cache
        current = self[idx]

        if value is current:
            return
        if id(value) in cache:
            raise ValueError('object already present in the list')
        if not isinstance(value, Element):
            raise TypeError('only Elements are accepted, got %s' % (type(value).__name__))

        value._set_masterlist(self)
        cache[id(value)] = idx = current.idx
        super(Masterlist, self).__setitem__(idx, value)
        del cache[id(current)]

        # invariant checks
        assert self._has_consistent_idx()

    def __copy__(self):
        L_copies = []
        for x in self:
            try:
                del x._masterlist
                cp = _copy.copy(x)
                if cp is x:
                    raise RuntimeError('improper __copy__ implementation: '
                                       'object and its copy cannot share identity')
                L_copies.append(cp)
            finally:
                x._masterlist = self

        L = Masterlist.__new__(type(self))
        L._cache = {}
        L._parent = self._parent
        L.extend(L_copies)
        return L

    def __deepcopy__(self, memo):
        L = Masterlist.__new__(type(self))
        L._cache = {}
        memo[id(self)] = L

        for x in self:
            try:
                del x._masterlist
                cp = _copy.deepcopy(x, memo)
                assert cp is not x, ('improper __deepcopy__ implementation: '
                                     'object and its copy cannot share identity')
                L.append(cp)
            finally:
                x._masterlist = self
        L.parent = None
        return L

    def __imul__(self, n):
        raise TypeError('arithmetical operations are not allowed')

    def __iadd__(self, n):
        raise TypeError('arithmetical operations are not allowed')

    def __add__(self):
        raise TypeError('arithmetical operations are not allowed')

    def append(self, value):
        '''L.append(value) -- append value to end'''

        cache = self._cache
        if id(value) in cache:
            raise ValueError('object already present in the list')
        if not isinstance(value, Element):
            raise TypeError('only Elements are accepted, got %s' % (type(value).__name__))

        value._set_masterlist(self)
        super(Masterlist, self).append(value)
        cache[id(value)] = len(self) - 1

        # invariant checks
        assert self._has_consistent_idx()

    def extend(self, seq):
        '''L.extend(iterable) -- extend list by appending elements from the iterable'''

        for obj in seq:
            self.append(obj)

        # invariant checks
        assert self._has_consistent_idx()

    def index(self, obj, start=None, stop=None):
        '''L.index(value) -> integer -- return first index of value.
        Raises ValueError if the value is not present.'''

        try:
            idx = self._cache[id(obj)]
        except KeyError:
            raise ValueError('not in list: %r' % obj)
        if start is not None and idx > start:
            raise ValueError(obj)
        elif stop is not None and idx < stop:
            raise ValueError(obj)
        else:
            return idx

    def insert(self, idx, value):
        '''L.insert(index, value) -- insert object before index'''

        cache = self._cache
        if id(value) in cache:
            raise ValueError('object already present in the list')
        if not isinstance(value, Element):
            raise TypeError('only Elements are accepted, got %s' % (type(value).__name__))

        value._set_masterlist(self)
        super(Masterlist, self).insert(idx, value)
        cache[id(value)] = idx
        for i in range(idx + 1, len(self)):
            cache[id(self[i])] += 1

        # invariant checks
        assert self._has_consistent_idx()

    def pop(self, idx=None):
        '''L.pop(index) -> item -- remove and return item at index (default last).
        Raises IndexError if list is empty or index is out of range.'''

        cache = self._cache

        if idx is None:
            obj = super(Masterlist, self).pop()
            del cache[id(obj)]
        else:
            N = len(self)
            obj = super(Masterlist, self).pop(idx)
            idx = (idx if idx >= 0 else (N + idx))
            for i in range(idx, N - 1):
                cache[id(self[i])] -= 1
            del cache[id(obj)]

        del obj._masterlist

        # invariant checks
        assert self._has_consistent_idx()
        return obj

    def remove(self, value):
        '''L.remove(value) -- remove first occurrence of value.
        Raises ValueError if the value is not present.'''

        del self[self._cache[id(value)]]

        # invariant checks
        assert self._has_consistent_idx()

    def reverse(self):
        '''L.reverse() -- reverse *IN PLACE*'''

        cache = self._cache
        super(Masterlist, self).reverse()
        for i, obj in enumerate(self):
            cache[id(obj)] = i

        # invariant checks
        assert self._has_consistent_idx()

    def sort(self, key=None, reverse=False):
        '''L.sort(key=None, reverse=False) -- stable sort *IN PLACE*;'''

        cache = self._cache
        super(Masterlist, self).sort(key=key, reverse=reverse)
        for i, obj in enumerate(self):
            cache[id(obj)] = i

        # invariant checks
        assert self._has_consistent_idx()

    def clear(self):
        '''L.clear() -> list -- clear all objects in the list and return a list
        of the cleared objects. This clear the next/prev association between
        these objects.'''

        objects = list(self)
        del self[:]

        # invariant checks
        assert self._has_consistent_idx()
        return objects

if __name__ == '__main__':
    import doctest
    doctest.testmod()


import pytest

import numpy as np
from pyspark.sql import SparkSession
from pyspark.sql.types import IntegerType

from petastorm import make_reader
from petastorm.codecs import ScalarCodec
from petastorm.etl.dataset_metadata import materialize_dataset
from petastorm.predicates import in_set, in_intersection, \
    in_negate, in_reduce, in_pseudorandom_split, in_lambda
from petastorm.tests.test_common import TestSchema
from petastorm.unischema import dict_to_spark_row, Unischema, UnischemaField

@pytest.fixture(scope="session")
def all_values(request, tmpdir_factory):
    all_values = set()
    for i in range(10000):
        all_values.add('guid_' + str(i))
    return all_values

def test_inclusion(all_values):
    for values in [{'guid_2', 'guid_1'}, {'guid_5', 'guid_XXX'}, {'guid_2'}]:
        test_predicate = in_set(values, 'volume_guid')
        included_values = set()
        for val in all_values:
            if test_predicate.do_include({'volume_guid': val}):
                included_values.add(val)
        assert included_values == all_values.intersection(values)

def test_list_inclusion(all_values):
    for values in [{'guid_2', 'guid_1'}, {'guid_5', 'guid_XXX'}, {'guid_XX'}]:
        test_predicate = in_intersection(values, 'volume_guid')
        included = test_predicate.do_include({'volume_guid': list(all_values)})
        assert included != all_values.intersection(values)

def test_custom_function(all_values):
    for value in ['guid_2', 'guid_1', 'guid_5', 'guid_XXX', 'guid_XX']:
        test_predicate = in_lambda(['volume_guids'], lambda volume_guids, val=value: val in volume_guids)
        included = test_predicate.do_include({'volume_guids': all_values})
        assert included == (value in all_values)

def test_custom_function_with_state(all_values):
    counter = [0]

    def pred_func(volume_guids, cntr):
        cntr[0] += 1
        return volume_guids in all_values

    test_predicate = in_lambda(['volume_guids'], pred_func, counter)
    for value in ['guid_2', 'guid_1', 'guid_5', 'guid_XXX', 'guid_XX']:
        included = test_predicate.do_include({'volume_guids': value})
        assert included == (value in all_values)
    assert counter[0] == 5

def test_negation(all_values):
    for values in [{'guid_2', 'guid_1'}, {'guid_5', 'guid_9'}, {'guid_2'}]:
        test_predicate = in_negate(in_set(values, 'volume_guid'))
        included_values = set()
        for val in all_values:
            if test_predicate.do_include({'volume_guid': val}):
                included_values.add(val)
        assert included_values == all_values.difference(values)

def test_and_argegarion(all_values):
    for values1 in [{'guid_0', 'guid_1'}, {'guid_3', 'guid_6', 'guid_20'}, {'guid_2'}]:
        for values2 in [{'guid_2', 'guid_1'}, {'guid_5', 'guid_9'}, {'guid_2'}]:
            test_predicate = in_reduce(
                [in_set(values1, 'volume_guid'), in_set(values2, 'volume_guid')], all)
            included_values = set()
            for val in all_values:
                if test_predicate.do_include({'volume_guid': val}):
                    included_values.add(val)
            assert included_values == values1.intersection(values2)

def test_or_argegarion(all_values):
    for values1 in [{'guid_0', 'guid_1'}, {'guid_3', 'guid_6', 'guid_20'}, {'guid_2'}]:
        for values2 in [{'guid_2', 'guid_1'}, {'guid_5', 'guid_9'}, {'guid_2'}]:
            test_predicate = in_reduce(
                [in_set(values1, 'volume_guid'), in_set(values2, 'volume_guid')], any)
            included_values = set()
            for val in all_values:
                if test_predicate.do_include({'volume_guid': val}):
                    included_values.add(val)
            assert included_values == values1.union(values2)

def test_pseudorandom_split_on_string_field(all_values):
    split_list = [0.3, 0.4, 0.1, 0.0, 0.2]
    values_num = len(all_values)
    for idx in range(len(split_list)):
        test_predicate = in_pseudorandom_split(split_list, idx, 'string_partition_field')
        included_values = set()
        for val in all_values:
            if test_predicate.do_include({'string_partition_field': val}):
                included_values.add(val)
        expected_num = values_num * split_list[idx]
        assert pytest.approx(len(included_values), expected_num * 0.1) == expected_num

def test_pseudorandom_split_on_integer_field():
    split_list = [0.3, 0.4, 0.1, 0.0, 0.2]
    int_values = list(range(1000))
    values_num = len(int_values)
    for idx, _ in enumerate(split_list):
        test_predicate = in_pseudorandom_split(split_list, idx, 'int_partitioning_field')
        included_values = set()
        for val in int_values:
            if test_predicate.do_include({'int_partitioning_field': val}):
                included_values.add(val)
        expected_num = values_num * split_list[idx]
        assert pytest.approx(len(included_values), expected_num * 0.1) == expected_num

def test_predicate_on_single_column(synthetic_dataset):
    reader = make_reader(synthetic_dataset.url,
                         schema_fields=[TestSchema.id2],
                         predicate=in_lambda(['id2'], lambda id2: True),
                         reader_pool_type='dummy')
    counter = 0
    for row in reader:
        counter += 1
        actual = dict(row._asdict())
        assert actual['id2'] < 2
    assert counter == len(synthetic_dataset.data)

def test_predicate_on_partitioned_dataset(tmpdir):
    """
    Generates a partitioned dataset and ensures that readers evaluate the type of the partition
    column according to the type given in the Unischema.
    """
    TestSchema = Unischema('TestSchema', [
        UnischemaField('id', np.int32, (), ScalarCodec(IntegerType()), False),
        UnischemaField('test_field', np.int32, (), ScalarCodec(IntegerType()), False),
    ])

    def test_row_generator(x):
        """Returns a single entry in the generated dataset."""
        return {'id': x,
                'test_field': x*x}

    rowgroup_size_mb = 256
    dataset_url = "file://{0}/partitioned_test_dataset".format(tmpdir)

    spark = SparkSession.builder.config('spark.driver.memory', '2g').master('local[2]').getOrCreate()
    sc = spark.sparkContext

    rows_count = 10
    with materialize_dataset(spark, dataset_url, TestSchema, rowgroup_size_mb):

        rows_rdd = sc.parallelize(range(rows_count))\
            .map(test_row_generator)\
            .map(lambda x: dict_to_spark_row(TestSchema, x))

        spark.createDataFrame(rows_rdd, TestSchema.as_spark_schema()) \
            .write \
            .partitionBy('id') \
            .parquet(dataset_url)

    with make_reader(dataset_url, predicate=in_lambda(['id'], lambda x: x == 3)) as reader:
        assert next(reader).id == 3
    with make_reader(dataset_url, predicate=in_lambda(['id'], lambda x: x == '3')) as reader:
        with pytest.raises(StopIteration):
            # Predicate should have selected none, so a StopIteration should be raised.
            next(reader)


"""
코딩테스트 연습 > 2021 KAKAO BLIND RECRUITMENT > 메뉴 리뉴얼
"""

from itertools import combinations

def make_comb(order, size):
    order_list = list(order)
    result = list(map(list, (combinations(order_list, size))))
    for i in range(len(result)):
        result[i].sort()
        result[i] = ''.join(result[i])
    result = list(set(result))
    return result

def solution(orders, course):
    menu = [{} for i in range(len(course))]
    for order in orders:
        for size in course:
            comb = make_comb(order, size)
            for c in comb:
                ind = course.index(size)
                if c in menu[ind].keys():
                    menu[ind][c] += 1
                else:
                    menu[ind][c] = 1
    answer = []
    for i in range(len(menu)):
        if len(menu[i]) == 0:
            continue
        target_ref = max(menu[i].values())
        if target_ref < 2:
            continue
        for m in menu[i].keys():
            if menu[i][m] == target_ref:
                answer.append(m)
    answer.sort()

    return answer

print(solution(["ABCFG", "AC", "CDE", "ACDE", "BCFG", "ACDEH"], [2,3,4]))
print(solution(["ABCDE", "AB", "CD", "ADE", "XYZ", "XYZ", "ACD"], [2,3,5]))
print(solution(["XYZ", "XWY", "WXA"], [2,3,4]))


from controlador import *
from markups import *

import telebot
from telebot import types
import numpy as np
from random import randint
from dotenv import load_dotenv
import os
import re

# Telegram Bot Token from BotFather
# Obtener información de .env
load_dotenv(dotenv_path = '.env')
# Obtener host y puerto
TOKEN = os.getenv('TOKEN')

# Telebot Bot
bot = telebot.TeleBot(TOKEN)

# Controlador juego
controlador = Controlador()

# Bienvenida al bot
@bot.message_handler(commands=['start'])
def bienvenida(message):
	bot.send_photo(message.chat.id, photo="https://github.com/Carlosma7/TFM-GrandQuiz/blob/main/doc/img/game/saludo.jpg?raw=true", caption=f"¡Bienvenido {message.from_user.first_name} a GrandQuiz, el concurso donde todas las generaciones son bienvenidas! \n\nMi nombre es Tercetto y seré tu guía en el concurso.", parse_mode = 'Markdown')
	bot.send_message(message.chat.id, f"Para empezar vamos a registrarnos en el concurso, por favor dime tu edad de la forma: \n*/registro <edad>* \n\nPor ejemplo: \n*/registro 24*", parse_mode = 'Markdown')

# Registro en el sistema de GrandQuiz
@bot.message_handler(commands=['registro'])
def registro(message):
	# Crear un jugador con nombre de usuario, nombre y edad
	j = Jugador(message.from_user.username, message.from_user.first_name, int(message.text[10:]))
	try:
		# Crear jugador en controlador
		controlador.crear_jugador(j)
		# Se guarda mensaje de éxito
		respuesta = f"¡Enhorabuena! Ya eres un jugador oficial de GrandQuiz, es hora de la diversión."
	except Exception as error:
		# Se produce un error
		respuesta = str(error)

	# Informar al usuario
	bot.send_message(message.chat.id, respuesta)

# Obtener estadisticas de un jugador
@bot.message_handler(commands=['estadisticas'])
def estadisticas(message):
	try:
		# Obtener estadisticas
		est = controlador.obtener_estadisticas(message.from_user.username)
		# Se guarda mensaje de éxito
		respuesta = f"Las estadísticas de {message.from_user.first_name} son:\n\n\U0001f3c6 {est.get_num_victorias()} victorias.\n\n\U0001f3ae {est.get_num_partidas()} partidas."
	except Exception as error:
		# Se produce un error
		respuesta = str(error)

	# Informar al usuario
	bot.send_message(message.chat.id, respuesta)

# Crear partida de GrandQuiz
@bot.message_handler(commands=['nueva_partida'])
def nueva_partida(message):
	# Comprobar que la conversación es en un grupo
	if message.chat.type == 'group':
		# Crear una partida con el id del chat del grupo
		p = Partida(message.chat.id)
		try:
			# Crear partida en controlador
			controlador.crear_partida(p, message.from_user.username)
			# Se guarda mensaje de éxito
			respuesta = f"¡Allá vamos! {message.from_user.first_name} ha creado una partida. Para unirte indícamelo con */unirme*."
		except Exception as error:
			# Se produce un error
			respuesta = str(error)
	else:
		# No es un grupo
		respuesta = f"Para crear una partida tienes que estar en un grupo."

	# Informar al usuario
	bot.send_message(message.chat.id, respuesta, parse_mode = 'Markdown')

# Unirse a partida
@bot.message_handler(commands=['unirme'])
def unirse_partida(message):
	# Comprobar que la conversación es en un grupo
	if message.chat.type == 'group':
		try:
			# Unirse a partida
			controlador.add_jugador(message.chat.id, message.from_user.username)
			respuesta = f"¡Bien! {message.from_user.first_name} se ha unido a la partida."
		except Exception as error:
			# Se produce un error
			respuesta = str(error)
	else:
		# No es un grupo
		respuesta = f"Para unirte a una partida tienes que estar en un grupo."

	# Informar al usuario
	bot.send_message(message.chat.id, respuesta, parse_mode = 'Markdown')

# Listar jugadores de una partida
@bot.message_handler(commands=['lista'])
def listar_jugadores(message):
	# Comprobar que la conversación es en un grupo
	if message.chat.type == 'group':
		try:
			# Obtener lista de jugadores
			lista = controlador.listar_jugadores(message.chat.id)
			if len(lista) == 0:
				respuesta = f"Aún no hay jugadores en la partida. ¡Anímate en ser el primero!"
			else:
				respuesta = f"Jugadores en la partida:\n\n"
				for jug in lista:
					respuesta += f"\U0001f466\U0001f3fb  {jug.get_nombre()}\n"
				if len(lista) == 2:
					respuesta += f"\nYa hay suficientes jugadores. ¡Así que pon /jugar para que comience el juego!"
		except Exception as error:
			# Se produce un error
			respuesta = str(error)
	else:
		# No es un grupo
		respuesta = f"Para ver una partida tienes que estar en un grupo."

	# Informar al usuario
	bot.send_message(message.chat.id, respuesta, parse_mode = 'Markdown')

# Iniciar una partida
@bot.message_handler(commands=['jugar'])
def iniciar_partida(message):
	# Comprobar que la conversación es en un grupo
	if message.chat.type == 'group':
		try:
			# Iniciar partida
			jug_turno, pregunta = controlador.iniciar_partida(message.chat.id)
			# Informar al usuario
			bot.send_photo(message.chat.id, photo="https://github.com/Carlosma7/TFM-GrandQuiz/blob/main/doc/img/game/nueva_partida.jpg?raw=true", caption=f"¡Por fin es la hora de jugar a GrandQuiz!\n\nY el afortunado en responder primero es \U0001f389 {jug_turno} \U0001f389", parse_mode = 'Markdown')
			# Definir markup
			markup = markup_respuestas(pregunta)
			enunciado = f"Turno de: {jug_turno}.\n\n{pregunta.get_enunciado()}"
			bot.send_message(message.chat.id, enunciado, reply_markup=markup)
		except Exception as error:
			# Se produce un error
			respuesta = str(error)
			# Informar al usuario
			bot.send_message(message.chat.id, respuesta, parse_mode = 'Markdown')
	else:
		# No es un grupo
		respuesta = f"Para iniciar una partida tienes que estar en un grupo."
		# Informar al usuario
		bot.send_message(message.chat.id, respuesta, parse_mode = 'Markdown')

# Responder pregunta
@bot.callback_query_handler(func=lambda call: True)
def responder_pregunta(call):
	if bool(re.match("[1-4]", call.data)):
		try:
			# Responder pregunta
			resultado = controlador.responder_pregunta(call.message.chat.id, call.from_user.username, int(call.data))
			# Pregunta acertada
			if resultado:
				respuesta = f"\u2705 ¡SÍ, HAS ACERTADO! Efectivamente era:\n\n*{controlador.obtener_respuesta(call.message.chat.id)}*"
			# Pregunta fallada
			else:
				respuesta = f"\u274C Noooooo, esa no era la respuesta correcta, la respuesta correcta era:\n\n*{controlador.obtener_respuesta(call.message.chat.id)}*"

			# Editar texto con respuesta
			respuesta = f"{call.message.text}\n\n{respuesta}"
			bot.edit_message_text(respuesta, call.message.chat.id, call.message.id, parse_mode = 'Markdown')

			# Comprobar si ha ganado un jugador
			if not controlador.comprobar_victoria(call.message.chat.id):
				# Cambiar turno
				jug_turno, pregunta = controlador.cambiar_turno(call.message.chat.id)
				# Definir markup
				markup = markup_respuestas(pregunta)
				enunciado = f"Turno de: {jug_turno}.\n\n{pregunta.get_enunciado()}"
				bot.send_message(call.message.chat.id, enunciado, reply_markup=markup)
			else:
				# Si ha ganado un jugador
				ganador = controlador.terminar_partida(call.message.chat.id)
				# Informar al usuario
				bot.send_photo(call.message.chat.id, photo="https://github.com/Carlosma7/TFM-GrandQuiz/blob/main/doc/img/game/ganador.jpg?raw=true", caption=f"\u2B50\U0001f3c6 ¡ENHORABUENA! {ganador.upper()} ES EL CAMPEÓN DE GRANDQUIZ. \U0001f3c6\u2B50", parse_mode = 'Markdown')
		except Exception as error:
			# Se produce un error
			respuesta = f"{call.from_user.first_name}: {str(error)}"
			# Informar al usuario
			bot.send_message(call.message.chat.id, respuesta, parse_mode = 'Markdown')

# Launch bot
bot.polling()


from django.shortcuts import render
from .models import Lesson, Pupil, Teacher
# Create your views here.
from django.http import HttpResponse

def index(request):
    teachers = Teacher.objects.all()
    return render(request, 'main/index.html', {'teachers': teachers, 'list': 'Учителя'} )

def profile(request, teacher_name='Альбус'):
    teacher = Teacher.objects.filter(firstName=teacher_name)
    pupils = teacher[0].pupil_set.all()
    return render(request, 'main/profile.html', {'teacher': teacher[0], 'pupils': pupils, 'list': 'Ученики'} )


import os
import requests
import time

from dotenv import load_dotenv

load_dotenv()

class spotify_user:
    def __init__(self, code: str) -> None:
        r = requests.post("https://accounts.spotify.com/api/token",
                          data={"grant_type": "authorization_code",
                                "code": code,
                                "redirect_uri": "http://localhost:8888/callback",
                                "client_id": os.getenv("client_id"),
                                "client_secret": os.getenv("client_secret")})

        self.token_expiry = time.time() + r.json()["expires_in"]
        self.access_token = r.json()["access_token"]
        self.refresh_token = r.json()["refresh_token"]

        r = requests.get("https://api.spotify.com/v1/me",
                         headers={"Authorization": f"Bearer {self.access_token}"})

        self.id = r.json()["id"]

    def refresh(self) -> None:
        r = requests.post("https://accounts.spotify.com/api/token",
                          data={"grant_type": "refresh_token",
                                "refresh_token": self.refresh_token,
                                "client_id": os.getenv("client_id"),
                                "client_secret": os.getenv("client_secret")})

        self.token_expiry = time.time() + r.json()["expires_in"]
        self.access_token = r.json()["access_token"]

    def check_token(self) -> None:
        if time.time() >= self.token_expiry + 10:  # If token is expired or expires within 10 seconds, for network and processing delays.
            self.refresh()

    def get_playlists(self) -> list:
        self.check_token()
        playlists = []
        r = requests.get("https://api.spotify.com/v1/me/playlists",
                         headers={"Authorization": f"Bearer {self.access_token}"})
        playlists += r.json()["items"]
        while r.json()["next"] is not None:
            r = requests.get(r.json()["next"],
                             headers={"Authorization": f"Bearer {self.access_token}"})
            playlists += r.json()["items"]
        return playlists

    def get_playlist_songs(self, playlist_id: str) -> list:
        self.check_token()
        songs = []
        r = requests.get(f"https://api.spotify.com/v1/playlists/{playlist_id}/tracks",
                         headers={"Authorization": f"Bearer {self.access_token}"})
        songs += r.json()["items"]
        while r.json()["next"] is not None:
            r = requests.get(r.json()["next"],
                             headers={"Authorization": f"Bearer {self.access_token}"})
            songs += r.json()["items"]
        return songs


from aiogram import types, Dispatcher
from aiogram.dispatcher import FSMContext
from aiogram.dispatcher.filters.state import State, StatesGroup
from couch_bot1.create_bot import bot, db
from .keyboards import language_choice, main_menu_rus, change_invitation_rus

class FSMStart(StatesGroup):
    pass

class FSMUsage(StatesGroup):
    language = State()
    vk_link = State()
    is_host = State()
    menu = State()
    searched_city = State()
    choosing_host = State()
    write_text = State()
    send_request = State()
    already_host = State()
    host_city = State()
    write_inv_text = State()
    end_inv = State()
    leave_review = State()
    write_review_text = State()
    leave_mark = State()

async def start(message: types.Message, state: FSMContext):
    if not db.user_exists(message.from_user.id):
        await FSMUsage.language.set()
        await bot.send_message(message.from_user.id, 'Choose your language. Выберите язык', reply_markup=language_choice)
    else:
        await FSMUsage.menu.set()
        async with state.proxy() as data:
            data['lang'] = 0 if db.get_lang(message.from_user.id) == 'Русский' else 1
        await bot.send_message(message.from_user.id, 'Привет! Выбери, что хочешь сделать', reply_markup=main_menu_rus)

async def show_main_menu(message: types.Message, state: FSMContext):
    if message.text == 'Найти хоста':
        await FSMUsage.searched_city.set()
        await bot.send_message(message.from_user.id, 'В каком городе ты ищешь хоста?')
    elif message.text == 'Создать объявление':
        if db.user_invitation_exists(message.from_user.id):
            async with state.proxy() as data:
                data['changing'] = True
            await FSMUsage.already_host.set()
            await bot.send_message(message.from_user.id, 'Вы уже создали приглашение. Хотите его изменить?', reply_markup=change_invitation_rus)
        else:
            async with state.proxy() as data:
                data['changing'] = False
            await FSMUsage.host_city.set()
            await bot.send_message(message.from_user.id, 'В каком городе ты принимаешь гостей?')
    elif message.text == 'Оставить отзыв на хоста':
        await FSMUsage.leave_review.set()
        await bot.send_message(message.from_user.id, 'Отправьте юзернейм хоста в ТГ или ссылку в ВК, на которого вы хотели бы оставить отзыв\n(напр. "@privet или vk.com/privet)')

def register_handlers_start(dp: Dispatcher):
    dp.register_message_handler(start, commands=['start'], state='*')
    dp.register_message_handler(show_main_menu, state=FSMUsage.menu)


'''Implement a stack that has the following methods:

    push(val), which pushes an element onto the stack
    pop(), which pops off and returns the topmost element of the stack.
        If there are no elements in the stack, then it should throw an
        error or return null.
    max(), which returns the maximum value in the stack currently. If
        there are no elements in the stack, then it should throw an
        error or return null.

Each method should run in constant time.'''

class Stack:
    val_stack = []
    max_stack = []

    def push(self, val):
        self.val_stack.append(val)
        m = val
        if len(self.max_stack) > 0:
            m = max(val,self.max_stack[-1])
        self.max_stack.append(m)

    def pop(self):
        self.val_stack.pop()
        self.max_stack.pop()

    def max(self):
        if len(self.max_stack) > 0:
            return self.max_stack[-1]
        return None

s = Stack()
print(s.max())

s.push(2)
print(s.max())

s.push(4)
print(s.max())

s.push(1)
print(s.max())

s.push(3)
print(s.max())

for i in range(4):
    s.pop()
    print(s.max())


import json

class Construct_Lacima_MQTT_Devices(object):

   def __init__(self,bc,cd):
      self.bc = bc
      self.cd = cd

      bc.add_header_node("MQTT_DEVICES")

      cd.construct_package("MQTT_DEVICES_DATA")
      cd.add_redis_stream("MQTT_INPUT_QUEUE",50000)
      cd.add_redis_stream("MQTT_SENSOR_QUEUE",10000)
      cd.add_redis_stream("MQTT_PAST_ACTION_QUEUE",300)
      cd.add_hash("MQTT_SENSOR_STATUS")
      cd.add_hash("MQTT_DEVICES")
      cd.add_hash("MQTT_SUBSCRIPTIONS")
      cd.add_hash("MQTT_CONTACT_LOG")
      cd.add_hash("MQTT_UNKNOWN_DEVICES")
      cd.add_hash("MQTT_UNKNOWN_SUBSCRIPTIONS")
      cd.add_hash("MQTT_REBOOT_LOG")

      cd.add_job_queue("MQTT_PUBLISH_QUEUE",depth= 50,forward = False)
      cd.close_package_contruction()
      properties = {}
      properties["HOST"] = "farm_control.fios-router.home"
      properties["PORT"] = 8883
      properties["BASE_TOPIC"] = "/REMOTES"
      self.bc.add_info_node( "MQTT_SERVER","MQTT_SERVER",properties=properties )
      #self.add_security_monitor("GARAGE_MONITOR_1")
      #self.add_current_monitor("CURRENT_MONITOR_1")
      self.add_well_monitor("WELL_MONITOR_1")
      self.irrigation_hash_fields()
      self.add_minute_average_fields()
      bc.end_header_node("MQTT_DEVICES")

   def add_minute_average_fields(self):
       properties = {}
       properties["data"] = {}
       properties["data"]["WELL_PRESSURE"] = ["WELL_MONITOR_1",'INPUT/AD1/VALUE/RESPONSE', "WELL_PRESSURE"    ]
       #properties["data"]["EQUIPMENT_CURRENT"] =["CURRENT_MONITOR_1",'INPUT/AD1/VALUE/RESPONSE',"EQUIPMENT_CURRENT"]
       #properties["data"]["IRRIGATION_CURRENT"] = [ "CURRENT_MONITOR_1", 'INPUT/AD1/VALUE/RESPONSE', "IRRIGATION_CURRENT"]
       properties["data"]["MAIN_FLOW_METER"] = ["WELL_MONITOR_1",  'INPUT/PULSE_COUNT/VALUE',  "MAIN_FLOW_METER" ]
       properties["data"]["CLEANING_FLOW_METER"] = ["WELL_MONITOR_1",'INPUT/PULSE_COUNT/VALUE' , "CLEANING_OUTLET"   ]
       properties["data"]["INPUT_PUMP_CURRENT"] = ["WELL_MONITOR_1",'INPUT/AD1/VALUE/RESPONSE' ,"INPUT_PUMP_CURRENT"    ]
       properties["data"]["OUTPUT_PUMP_CURRENT"] = ["WELL_MONITOR_1", 'INPUT/AD1/VALUE/RESPONSE', "OUTPUT_PUMP_CURRENT"   ]

       self.bc.add_info_node( "SENSOR_MINUTE_FIELDS","SENSOR_MINUTE_FIELDS",properties=properties )

   def irrigation_hash_fields(self):
       properties = {}
       properties["data"] = {}
       properties["data"]["WELL_PRESSURE"] = ["WELL_MONITOR_1",'INPUT/AD1/VALUE/RESPONSE', "WELL_PRESSURE"    ]
       #properties["data"]["EQUIPMENT_CURRENT"] =["CURRENT_MONITOR_1" ,'INPUT/AD1/VALUE/RESPONSE',"EQUIPMENT_CURRENT"]
       #properties["data"]["IRRIGATION_CURRENT"] = [ "CURRENT_MONITOR_1", 'INPUT/AD1/VALUE/RESPONSE', "IRRIGATION_CURRENT"]
       properties["data"]["MAIN_FLOW_METER"] = ["WELL_MONITOR_1",  'INPUT/PULSE_COUNT/VALUE',  "MAIN_FLOW_METER" ]
       properties["data"]["CLEANING_FLOW_METER"] = ["WELL_MONITOR_1",'INPUT/PULSE_COUNT/VALUE' , "CLEANING_OUTLET"   ]
       properties["data"]["INPUT_PUMP_CURRENT"] = ["WELL_MONITOR_1",'INPUT/AD1/VALUE/RESPONSE' ,"INPUT_PUMP_CURRENT"    ]
       properties["data"]["OUTPUT_PUMP_CURRENT"] = ["WELL_MONITOR_1", 'INPUT/AD1/VALUE/RESPONSE', "OUTPUT_PUMP_CURRENT"   ]

       properties["data"]["SLAVE_RELAY_STATE"] = ["CURRENT_MONITOR_1" ,"OUTPUT/MQTT_CURRENT/RELAY_STATE/RESPONSE",None]
       properties["data"]["SLAVE_MAX_CURRENT"] = ["CURRENT_MONITOR_1" ,"INPUT/MQTT_CURRENT/MAX_CURRENTS/RESPONSE",None]
       properties["data"]["INSTANT_CURRENT"]  = ["CURRENT_MONITOR_1" ,"INPUT/MQTT_CURRENT/CURRENTS/RESPONSE",None]
       self.bc.add_info_node( "IRRIGATION_HASH_FIELDS","IRRIGATION_HASH_FIELDS",properties=properties )

   def add_well_monitor(self,mqtt_tag):
       properties = {}
       properties["type"] = "WELL_MONITOR"
       properties["HEART_BEAT"] = "HEART_BEAT"
       properties["HEART_BEAT_TIME_OUT"] = 120
       properties["REBOOT_FLAG"] = True
       properties["REBOOT_KEY"] = "REBOOT"
       properties["topic"] = mqtt_tag
       properties["null_commands"] = {}
       properties["subscriptions"] = {}
       properties["subscriptions"]["REBOOT"] = True
       properties["subscriptions"]["HEART_BEAT"] = True

       properties["subscriptions"]['INPUT/AD1/VALUE/RESPONSE'] = {"type":"analog_input","main_field":'MEASUREMENTS' ,"fields":
          [  {  "name":"WELL_PRESSURE","type":"pressure_gauge","reduction":2,"range":100,"channel_field":'CHANNEL',"channel_value":0},
             { "name":"INPUT_PUMP_CURRENT","type":"rms_current_transformer","range":50,"channel_field":'CHANNEL',"channel_value":6,"resistor":150},
             { "name":"OUTPUT_PUMP_CURRENT","type":"rms_current_transformer","range":20,"channel_field":'CHANNEL',"channel_value":7,"resistor":150} ]}

       properties["subscriptions"]['INPUT/PULSE_COUNT/VALUE'] = {"type":"pulse_flow","main_field":"DATA",  "fields": [
          {"name":"MAIN_FLOW_METER", "GPIO_PIN":5,"data_field":"COUNTS","conversion":4./2./60./2.0 },
          {"name":"CLEANING_OUTLET", "GPIO_PIN":18,"data_field":"COUNTS","conversion":4./300./3.78541 }
          ]}

       self.bc.add_info_node( "MQTT_DEVICE",mqtt_tag,properties=properties )
   '''
   def add_current_monitor(self,mqtt_tag):
       properties = {}
       properties["type"] = "CURRENT_MONITOR"
       properties["topic"] = mqtt_tag
       properties["HEART_BEAT"] = "HEART_BEAT"
       properties["HEART_BEAT_TIME_OUT"] = 120
       properties["REBOOT_FLAG"] = True
       properties["REBOOT_KEY"] = "REBOOT"
       properties["null_commands"] = {}

       properties["null_commands"]["INPUT/MQTT_CURRENT/GET_LIMIT_CURRENTS"] = True
       properties["null_commands"]["INPUT/MQTT_CURRENT/GET_MAX_CURRENTS"] = True
       properties["null_commands"]["INPUT/MQTT_CURRENT/READ_CURRENT"] = True
       properties["null_commands"]["OUTPUT/MQTT_CURRENT/READ_RELAY_STATES"] = True
       properties["null_commands"]["OUTPUT/MQTT_CURRENT/CLEAR_MAX_CURRENTS"] = True
       properties["null_commands"]["OUTPUT/MQTT_CURRENT/ENABLE_EQUIPMENT_RELAY"] = True
       properties["null_commands"]["OUTPUT/MQTT_CURRENT/ENABLE_IRRIGATION_RELAY"] = True
       properties["null_commands"]["OUTPUT/MQTT_CURRENT/DISABLE_EQUIPMENT_RELAY"] = True
       properties["null_commands"]["OUTPUT/MQTT_CURRENT/DISABLE_IRRIGATION_RELAY"] = True

       properties["subscriptions"] = {}
       properties["subscriptions"]["REBOOT"] = True
       properties["subscriptions"]["HEART_BEAT"] = True
       properties["subscriptions"]['INPUT/AD1/VALUE/RESPONSE'] = {"type":"analog_input","main_field":'MEASUREMENTS' ,"fields":[
         {"name":"EQUIPMENT_CURRENT","type":"analog","channel_field":'CHANNEL',"channel_value":0},
         {"name":"IRRIGATION_CURRENT","type":"analog","channel_field":'CHANNEL',"channel_value":3}]}

       properties["subscriptions"]["OUTPUT/MQTT_CURRENT/EQUIPMENT_RELAY_TRIP/RESPONSE"] = True

       properties["subscriptions"]["OUTPUT/MQTT_CURRENT/IRRIGATION_RELAY_TRIP/RESPONSE"] = True

       properties["subscriptions"]["INPUT/MQTT_CURRENT/GET_LIMIT_CURRENTS/REPONSE"] = True

       properties["subscriptions"]["INPUT/MQTT_CURRENT/MAX_CURRENTS/RESPONSE"] = {"type":"flat","main_field":None ,"fields":[
          {"name":'MAX_EQUIPMENT_CURRENT',"field":'MAX_EQUIPMENT_CURRENT'},
          {"name":'MAX_IRRIGATION_CURRENT',"field":'MAX_IRRIGATION_CURRENT'}]}

       properties["subscriptions"]["INPUT/MQTT_CURRENT/CURRENTS/RESPONSE"] = {"type":"flat","main_field":None ,"fields":[
          {"name":'EQUIPMENT_CURRENT',"field":'EQUIPMENT_CURRENT'},
          {"name":'IRRIGATION_CURRENT',"field":'IRRIGATION_CURRENT'}]}

       properties["subscriptions"]["OUTPUT/MQTT_CURRENT/RELAY_STATE/RESPONSE"] = {"type":"flat","main_field":None ,"fields":[
          {"name":'EQUIPMENT_STATE',"field":'EQUIPMENT_STATE'},
          {"name":'IRRIGATION_STATE',"field":'IRRIGATION_STATE'}]}

       self.bc.add_info_node( "MQTT_DEVICE",mqtt_tag,properties=properties )

   def add_security_monitor(self,mqtt_tag):
       properties = {}
       properties["REBOOT_FLAG"] = True
       properties["REBOOT_KEY"] = "REBOOT"
       properties["type"] = "SECURITY_MONITOR"
       properties["HEART_BEAT"] = "HEART_BEAT"
       properties["HEART_BEAT_TIME_OUT"] = 120
       properties["topic"] = mqtt_tag
       properties["null_commands"] = {}
       properties["subscriptions"] = {}
       properties["subscriptions"]["REBOOT"] = True
       properties["subscriptions"]["HEART_BEAT"] = True
       self.bc.add_info_node( "MQTT_DEVICE",mqtt_tag,properties=properties )
   '''


def new_pandas_column_GUI(df_info=None, show_text_col = False, **kwargs):
    """
    If passed no parameters this will look for all the dataframes in the user
    namespace and make them available for adding a new column to. Once a
    dataframe is chosen only the numerical columns from that dataframe will
    be available for inclusion in the new column expression.

    If you wish to allow only certain dataframes or have them show up as
    user friendly names in the menus provide that information in the first
    paramater df_info.

    To allow inclusion of text columns pass True for show_text_col.

    :param bool show_text_col: (default = False). When True columns
    containing text will be shown.

    :param list df_info: List of Lists [[object,globalname,
    userfriendly]],..]
      * object -- pandas.DataFrame
      * globalname -- string name of the object in the user global name space.
      * userfriendly -- string name to display for user selection.

    :keyword bool findframes: default = True. If set to false and dataframes
    are passed in dfs_info, will not search for dataframes in the user
    namespace.
    """

    from ipywidgets import Layout, Box, HBox, VBox, GridBox, Tab, \
        Dropdown, Label, Text, Textarea, Button, Checkbox, Output
    from ipywidgets import HTML as richLabel
    from IPython.display import display, HTML
    from IPython import get_ipython
    from JPSLUtils.utils import new_cell_immediately_below,\
        select_cell_immediately_below, move_cursor_in_current_cell, \
        insert_text_into_next_cell, insert_text_at_beginning_of_current_cell, \
        insert_newline_at_end_of_current_cell, select_containing_cell, \
        delete_selected_cell, replace_text_of_next_cell

    from .utils import find_pandas_dataframe_names, build_run_snip_widget
    from IPython import get_ipython
    global_dict = get_ipython().user_ns
    JPSLUtils = global_dict["JPSLUtils"]
    dfs_info = []
    if isinstance(df_info,list):
        for k in df_info:
            dfs_info.append(k)
    findframes = kwargs.pop('findframes',True)
    if findframes:
        for k in find_pandas_dataframe_names():
            dfs_info.append([global_dict[k],k,k])
    friendly_to_globalname = {k[2]:k[1] for k in dfs_info}
    friendly_to_object = {k[2]:k[0] for k in dfs_info}

    #### Define GUI Elements ####

    importstr = '# CODE BLOCK generated using new_pandas_column_GUI().\n' \
                '# See https://jupyterphysscilab.github.io/' \
                'jupyter_Pandas_GUI.\n' \
                '# Imports (no effect if already imported)\n' \
                'import numpy as np\n'
    allbutlastline = importstr
    lastline = ''

    def split_to_all_but_last_and_last(text):
        all_but_last = ''
        last = ''
        lines = text.split('\n')
        for k in range(len(lines)):
            if k < len(lines) - 1:
                all_but_last += lines[k] + '\n'
            else:
                last = lines[k]
        return all_but_last, last

    # DataFrame Choice (Step 1)
    step1instr = Label(value = 'Select the DataFrame to work with.')
    tempopts = []
    tempopts.append('Choose')
    for k in dfs_info:
        tempopts.append(k[2])
    whichframe = Dropdown(options=tempopts,
                                description='DataFrame: ',)

    def update_columns(change):
        df = friendly_to_object[change['new']]
        tempcols = df.columns.values
        tempopt = ['Choose column to insert.']
        for k in tempcols:
            if show_text_col:
                tempopt.append(k)
            else:
                if df[k].dtype != 'O':
                    tempopt.append(k)
        whichcolumn.options = tempopt
        pass
    whichframe.observe(update_columns, names='value')
    step1 = VBox(children=[step1instr, whichframe])

    # Step 2
    newname = Text(placeholder='Type name for new column.')
    step2instr = richLabel(
        value='Pick a name for the new column. The expression will be ' \
              'built in the cell (textbox) below. Click the "Insert" button ' \
              'when you are satisfied with the name.')
    insertname = Button(description="Insert")

    def do_insertname(change):
        framename = friendly_to_globalname[whichframe.value]
        codestr = framename + '[\'' + newname.value + '\'] = '
        if JPSLUtils.notebookenv == 'NBClassic':
            select_containing_cell('newcolGUI')
            select_cell_immediately_below()
            insert_newline_at_end_of_current_cell(codestr)
        else:
            allbutlastline, lastline = split_to_all_but_last_and_last(
                codearea.sniptext.value)
            if lastline == '' or lastline == '\n':
                codearea.sniptext.value = allbutlastline + '\n' + codestr
            else:
                if lastline.endswith('\n'):
                    codearea.sniptext.value = allbutlastline + lastline + codestr
                else:
                    codearea.sniptext.value = allbutlastline + lastline + '\n' + \
                                   codestr
        pass

    insertname.on_click(do_insertname)

    step2 = VBox(children=[step2instr, HBox(children=[newname,
                                           insertname])])

    # Step 3
    whichcolumn = Dropdown(options=['Choose column to insert.'],
                           description='Column: ',
                           )

    def column_insert(change):
        col = change['new']
        if col == 'Choose column to insert.':
            return
        framename = friendly_to_globalname[whichframe.value]
        text = framename + '[\'' + col + '\']'
        if JPSLUtils.notebookenv == 'NBClassic':
            select_containing_cell('newcolGUI')
            insert_text_into_next_cell(text)
        else:
            allbutlastline, lastline = split_to_all_but_last_and_last(
                codearea.sniptext.value)
            if lastline.endswith('()') or lastline.endswith('+)') or \
                lastline.endswith('-)') or lastline.endswith('*)') or \
                lastline.endswith('/)') or lastline.endswith(' )'):
                lastline = lastline[:-1] + text +')'
            else:
                lastline += text
            codearea.sniptext.value = allbutlastline+lastline
        whichcolumn.value = 'Choose column to insert.'
        pass

    whichcolumn.observe(column_insert, names='value')
    step3instr = richLabel(
        value='Add the calculation to the right hand side of the = using the '
              'menus to insert columns, math operations or functions. ' \
              'Your choices will be appended to the end of the last line ' \
              'or inserted within the last set of parentheses. You can also' \
              ' manually edit the expression.')
    oplst = ['Choose an operation to insert.', '+', '-', '*', '/', '**',
             'exp()', 'log10()', 'ln()', 'sqrt()', 'sin()', 'cos()',
             'tan()', 'cot()', 'asin()', 'acos()', 'atan()', 'acot()']
    whichop = Dropdown(options=oplst,
                       description='Operation: ')

    def op_insert(change):
        need_numpy = False
        np_list = ['exp()', 'log10()', 'ln()', 'sqrt()', 'sin()', 'cos()',
                   'tan()', 'cot()', 'asin()', 'acos()', 'atan()',
                   'acot()']
        op = change['new']
        if op == 'Choose an operation to insert.':
            return
        if op in np_list:
            need_numpy = True
            if op == 'ln()':
                op = 'log()'
            op = 'np.' + op
        else:
            op = ' ' + op + ' '
        if JPSLUtils.notebookenv == 'NBClassic':
            select_containing_cell('newcolGUI')
            insert_text_into_next_cell(op)
            if need_numpy:
                move_cursor_in_current_cell(-1)
        else:
            allbutlastline, lastline = split_to_all_but_last_and_last(
                codearea.sniptext.value)
            if lastline.endswith('()') or lastline.endswith('+)') or \
                lastline.endswith('-)') or lastline.endswith('*)') or \
                lastline.endswith('/)') or lastline.endswith(' )') or \
                lastline.endswith('])'):
                lastline = lastline[:-1] + op +')'
            else:
                lastline += op
            codearea.sniptext.value = allbutlastline+lastline
        whichop.value = 'Choose an operation to insert.'
        pass

    whichop.observe(op_insert, names='value')

    step3drops = HBox(children=[whichcolumn, whichop])
    step3 = VBox(children=[step3instr, step3drops])

    # Step 4
    step4instr = richLabel(
        value = 'Carefully check the expression for typos:' \
            '

Check that parentheses, brackets or braces are properly ' \
              'paired.
' \
            '
Check that all double and single quotes are also ' \
              'properly paired.
' \
            '
Check that all function calls are prefaced by ' \
              'an np..

' \
            'Uncheck "Display updated data set", if you do not wish to ' \
                'display a summary of the updated data set. ' \
            'Click \'OK\' to do final code updates. ' \
            'In the classic Jupyter notebook this button will also ' \
            'run the code and clear this GUI from the notebook.'
    )
    show_updated_df_box = Checkbox(description='Show updated data set.',
                                   value=True,
                                   layout=Layout(left='-90px'))
    gen_col_but = Button(description='      OK      ')

    def run_new_col_decl(change):
        from IPython.display import display, HTML
        from IPython.display import Javascript as JS
        # if show updated dataframe is checked append dataframe name as last line.
        if show_updated_df_box.value == True:
            text = '# Display summary of updated data set.\n'
            text += 'display('+friendly_to_globalname[whichframe.value]+')'
            if JPSLUtils.notebookenv == 'NBClassic':
                select_containing_cell('newcolGUI')
                select_cell_immediately_below()
                insert_newline_at_end_of_current_cell(text)
            else:
                allbutlastline, lastline = split_to_all_but_last_and_last(
                    codearea.sniptext.value)
                if lastline == '' or lastline == '\n':
                    codearea.sniptext.value = allbutlastline + '\n' + text
                else:
                    codearea.sniptext.value = allbutlastline + lastline + \
                                              '\n\n' + text

        # run composed operation
        if JPSLUtils.notebookenv == 'NBClassic':
            select_containing_cell('newcolGUI')
            select_cell_immediately_below()
            display(JS('Jupyter.notebook.get_selected_cell().execute()'))
            select_containing_cell('newcolGUI')
            delete_selected_cell()
        pass

    gen_col_but.on_click(run_new_col_decl)
    step4act = VBox(children=[show_updated_df_box, gen_col_but])
    step4 = HBox(children=[step4instr, step4act])

    steps = Tab(children=[step1, step2, step3, step4])
    steps.set_title(0, 'Step 1')
    steps.set_title(1, 'Step 2')
    steps.set_title(2, 'Step 3')
    steps.set_title(3, 'Step 4')

    output = Output()
    codearea = build_run_snip_widget(importstr, output)

    with output:
        display(HTML(
        "
Pandas New Calculated "
        "Column "
        "Composer
"))
        display(steps)
    if JPSLUtils.notebookenv == 'NBClassic':
        display(output)
        select_containing_cell('newcolGUI')
        new_cell_immediately_below()
        select_containing_cell('newcolGUI')
        replace_text_of_next_cell(importstr)
    else:
        with output:
            display(codearea)
        display(output)
    pass


import sys
from pyspark import SparkConf, SparkContext
from pyspark.sql import SparkSession
from pyspark.sql.functions import col, max
from pyspark.sql.window import Window

# command to execute
# spark-submit Recreating.py 2019 01

def main(argv):
    input_basepath = "s3://bnc-datamigration-temp-bucket-dev-20181106/Temp-dataset"
    output_basepath = "s3://bnc-datamigration-temp-bucket-dev-20181106/Results"
    yyyy = argv[0]
    mm = argv[1]
    env = argv[1]
    if 'PROD' == env:
        input_basepath = "s3://market-data-ticker/block-explorer-parquet"
        output_basepath = "s3://market-data-migration/block-explorer-last-reported"

    conf = SparkConf()
    spark = SparkSession \
        .builder \
        .appName("FetchLastReportedSupply") \
        .getOrCreate()
    df = spark.read.csv('/'.join([input_basepath, yyyy, mm, '*/*']))
    result = df.withColumn("ts", col("date").cast('timestamp')).drop("date")
    result.persist()
    w = Window.partitionBy("symbol").orderBy("ts").rowsBetween(Window.unboundedPreceding, Window.unboundedFollowing)
    last_df = result.select('symbol', 'open', 'close', 'low', 'high', 'volume', 'ts',
                           max(col('ts')).over(w).alias('last_reported_ts')).where(
        (col('ts') == col('last_reported_ts')))
    last_df.repartition(1).write.csv('/'.join([output_basepath, yyyy, mm]), header='true')

if __name__ == "__main__":
    main(sys.argv[1:])


import sys

SIM_CYCLES = 1e3

#Numbers from: https://arxiv.org/pdf/2105.03814.pdf#cite.gomezluna2021repo
MRAM_SIZE = 2**26

WRAM_SIZE = 2**16

MRAM_READ_ALPHA = 77
MRAM_WRITE_ALPHA = 61

HOST_TO_DPU_BW = 0.1 * (2**30)

DPU_TO_HOST_BW = 0.5 * (2**30)

DPU_CLOCK_SPEED = 350e6

JobIndex = 0

class Job:
	Priority = 0
	WorkLoadSize = 0
	WorkLoadDispatched = 0
	WorkLoadCompleted = 0

	CyclesPerByte = 0
	ID = 0

	def __init__(self, WorkLoadSize, Priority, BytesPerCycle) -> None:
		global JobIndex
		self.Priority = Priority
		self.WorkLoadSize = WorkLoadSize
		self.CyclesPerByte = BytesPerCycle
		self.ID = JobIndex

		JobIndex += 1

class Task:
	Priority = 0
	PartitionSize = 0
	CyclesPerByte = 0

	ParentJob: Job = None

	Valid = False

	Active = False
	InternalCyclesRemaining = 0

	Transfering = False
	IsToHost = False
	IsToDPU = False
	TransferCyclesRemaining = 0

	TaskID = 0

	def __init__(self, TaskID, WorkLoadSize, Priority, BytesPerCycle) -> None:
		self.TaskID = TaskID
		self.Priority = Priority
		self.WorkLoadSize = WorkLoadSize
		self.CyclesPerByte = BytesPerCycle

def getTaskLabel(task: Task) -> str:
	return str(task.ParentJob.ID) + "-" + str(task.TaskID)

class SimState:
	#	InternalDMAActive = False

	DPUActive = False
	ActiveTask: Task = None

	MemoryBusActive = False
	MemoryBusTask: Task = None

	TaskSize = 0
	TotalCycles = 0

	JobList: list[Job] = None
	TaskArray: list[Task] = None

	OutQueue: list = None
	InQueue: list = None

	Task_RR_Index = 0

	def pruneJobs(self) -> None:
		modified = True

		while modified:
			modified = False
			for job in self.JobList:
				if job.WorkLoadCompleted >= job.WorkLoadSize:
					print("--- Job : ", job.ID, " finished at cycle : ", self.TotalCycles)
					self.JobList.remove(job)
					modified = True

	def SimMemoryBus(self):
		#if outbound task waiting, start its transfer
		self.FindBusOutputJob()

		#if need to read from host
		self.FindBusInputJob()

		#if memory bus is active, continue whatever transfer is happening
		self.SimMemoryBusTransfer()

	def SimMemoryBusTransfer(self):
		#if memory bus is active, continue whatever transfer is happening
		if self.MemoryBusActive:
			self.MemoryBusTask.TransferCyclesRemaining -= SIM_CYCLES

			if self.MemoryBusTask.TransferCyclesRemaining <= 0:
				print("Done transfering", getTaskLabel(self.MemoryBusTask), "...")

				if self.MemoryBusTask.IsToHost:
					self.MemoryBusTask.ParentJob.WorkLoadCompleted += self.TaskSize
					print("Task ", self.MemoryBusTask.ParentJob.ID, " - ", self.MemoryBusTask.TaskID,  " has finished : ",
                                            self.MemoryBusTask.ParentJob.WorkLoadCompleted, '/', self.MemoryBusTask.ParentJob.WorkLoadSize)
					self.MemoryBusTask.Valid = False

					self.pruneJobs()

				self.MemoryBusTask.Transfering = False
				self.MemoryBusTask = None
				self.MemoryBusActive = False

	def FindBusInputJob(self):
		#if need to read from host
		if not self.MemoryBusActive:

			#Is there a spot available on the DPU?
			FreeTask = getFreeTask(self.TaskArray)

			if FreeTask != None and self.InQueue:
				NextJob = self.InQueue.pop(0)

				#Associate Task with Job, and mark as transfering to DPU
				FreeTask.ParentJob = NextJob
				FreeTask.CyclesPerByte = NextJob.CyclesPerByte
				FreeTask.TransferCyclesRemaining = hostToDPUTransfer(self.TaskSize)
				FreeTask.InternalCyclesRemaining = getInternalCycles(
					self.TaskSize, FreeTask.CyclesPerByte)
				FreeTask.Transfering = True
				FreeTask.Valid = True

				print("Starting transfer of job", getTaskLabel(FreeTask))

				#Let global state know memory bus is active
				self.MemoryBusActive = True
				self.MemoryBusTask = FreeTask

	def FindBusOutputJob(self):
		#if outbound task waiting, start its transfer
		if not self.MemoryBusActive and self.OutQueue:
			print("Starting transfer back to host")
			self.MemoryBusTask = self.OutQueue.pop(0)

			self.MemoryBusTask.Transfering = True
			self.MemoryBusActive = True

	def SimDPU(self):
		#if need to start a task
		sim.FindDPUTask()

		#Process currently running task
		sim.RunDPUTask()

	def FindDPUTask(self):
		#if need to start a task
		if not self.DPUActive:

			#Is there a task that needs to be run?
			NextTask: Task = self.selectTask()
			#NextTask: Task = self.selectTask_RR()

			if NextTask != None:
				print("Starting task ", NextTask.TaskID,
				      ", job ID: ", NextTask.ParentJob.ID)
				NextTask.Active = True

				self.ActiveTask = NextTask
				self.DPUActive = True

	def RunDPUTask(self):
		#Process currently running task
		if self.ActiveTask != None:
			self.ActiveTask.InternalCyclesRemaining -= SIM_CYCLES

			#If task has finished, begin transfering it back to Host
			if self.ActiveTask.InternalCyclesRemaining <= 0:
				print("Done")

				self.ActiveTask.Active = False

				self.ActiveTask.TransferCyclesRemaining = DPUToHostTransfer(self.TaskSize)
				self.ActiveTask.IsToHost = True

				#Start transfer
				if not self.MemoryBusActive:
					print("Starting transfer back to host")
					self.ActiveTask.Transfering = True

					self.MemoryBusTask = self.ActiveTask
					self.MemoryBusActive = True

				#Bus is currently busy, put task in outbound queue
				else:
					self.OutQueue.append(self.ActiveTask)

				self.DPUActive = False
				self.ActiveTask = None

	def selectTask(self) -> Task:
		global sim
		for task in self.TaskArray:
			if task.Valid and not task.Active and not task.Transfering and task.InternalCyclesRemaining > 0:
				return task

		return None

	def selectTask_RR(self) -> Task:
		task = self.TaskArray[self.Task_RR_Index]

		self.Task_RR_Index = (self.Task_RR_Index + 1) % len(self.TaskArray)

		if task.Valid and not task.Active and not task.Transfering and task.InternalCyclesRemaining > 0:
			return task

		else:
			return None

	#Fill input job queue in round robin order
	def fillInQueue_RR(self) -> None:
		self.InQueue = []

		tmpList = self.JobList.copy()

		while tmpList:
			for job in tmpList:
				if job.WorkLoadDispatched < job.WorkLoadSize:
					self.InQueue.append(job)
					job.WorkLoadDispatched += sim.TaskSize

			modified = True
			while modified:
				modified = False
				for job in tmpList:
					if job.WorkLoadDispatched >= job.WorkLoadSize:
						print("--- Job : ", job.ID, " fully queued")
						tmpList.remove(job)
						modified = True

	#Fill input job queue in FCFS order
	def fillInQueue_FCFS(self) -> None:
		self.InQueue = []

		tmpList = self.JobList.copy()

		for job in tmpList:

			while job.WorkLoadDispatched < job.WorkLoadSize:
				self.InQueue.append(job)
				job.WorkLoadDispatched += sim.TaskSize

sim = SimState()

def getFreeTask(TaskArray: list[Task]) -> Task:
	for task in TaskArray:
		if not task.Valid:
			return task

	return None

def read_mramLatency(size):
	return MRAM_READ_ALPHA + 0.5 * size

def write_mramLatency(size):
	return MRAM_WRITE_ALPHA + 0.5 * size

def hostToDPUTransfer(size):
	return (size * 1.0 / HOST_TO_DPU_BW) * DPU_CLOCK_SPEED

def DPUToHostTransfer(size):
	return (size * 1.0 / DPU_TO_HOST_BW) * DPU_CLOCK_SPEED

def getInternalCycles(PartitionSize, CyclesPerByte):
	return (PartitionSize * 1.0 / WRAM_SIZE) * (read_mramLatency(WRAM_SIZE) + write_mramLatency(WRAM_SIZE) + WRAM_SIZE*CyclesPerByte)

def getExternalCycles(PartitionSize):
	return hostToDPUTransfer(PartitionSize) + DPUToHostTransfer(PartitionSize)

#def selectJob(JobList: list[Job]) -> Job:
#	global sim
#	for job in JobList:
#		if job.WorkLoadDispatched < job.WorkLoadSize:
#			return job
#
#	return None

def main():
	global sim

	TaskPower = int(sys.argv[1])

	sim.TaskSize = 2**TaskPower

	print("Task Power :", TaskPower)
	scale = 3
	sim.JobList = [Job(2**28, 0, (70.0/8)*scale), Job(2**28, 0, (70.0/8)*scale), Job(2**28, 0, (70.0/8)*scale)]
	sim.OutQueue = []
	sim.InQueue = []

	for job in sim.JobList:
		print("Job :", job.ID)
		print("\tHost -> DPU Cycles : ", hostToDPUTransfer(sim.TaskSize))
		print("\tDPU -> Host Cycles : ", DPUToHostTransfer(sim.TaskSize))
		print("\tTask Time          : ", getInternalCycles(sim.TaskSize, job.CyclesPerByte))

	sim.TaskArray = []
	for i in range(int(MRAM_SIZE/sim.TaskSize)):
		sim.TaskArray.append(Task(i, 0, 0, 0))

	#sim.fillInQueue_RR()
	sim.fillInQueue_FCFS()

	#Simulation loop
	while sim.JobList:
		sim.TotalCycles += SIM_CYCLES

		#Simulate memory bus transfers
		sim.SimMemoryBus()

		#Simulate taks on DPU
		sim.SimDPU()

	print("TotalCycles :", sim.TotalCycles)

if __name__ == "__main__":
	main()


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

#
# Copyright (C) 2012 Alexander Labunets (cahbka@gmail.com).
# All rights reserved.
#

import logging
import M2Crypto
import urllib
import urllib2
import xml.etree.ElementTree as etree

class SPGW:
    ALG = 'SHA1RSA'

    def __init__(self, private_key, public_key, url, aid, tident):
        self.private_key = private_key
        self.public_key = public_key
        self.url = url
        self.aid = aid
        self.tident = tident

    def _sign(self, text):
        key = M2Crypto.EVP.load_key_string(self.private_key)
        key.reset_context(md='sha1')
        key.sign_init()
        key.sign_update(text)
        signature = key.sign_final()[::-1]              # compatibility with Microsoft Cryptographic API (CAPI)
        return signature.encode('base64')

    def _verify_sign(self, text, signature):
        signature = signature.decode('base64')[::-1]    # compatibility with Microsoft Cryptographic API (CAPI)
        bio = M2Crypto.BIO.MemoryBuffer(self.public_key)
        rsa = M2Crypto.RSA.load_pub_key_bio(bio)
        pubkey = M2Crypto.EVP.PKey()
        pubkey.assign_rsa(rsa)
        pubkey.reset_context(md='sha1')
        pubkey.verify_init()
        pubkey.verify_update(text)
        return pubkey.verify_final(signature)

    def _parse(self, response):
        root = etree.fromstring(response)
        self.c = int(root.find('C').text.encode('utf-8'))
        self.r = root.find('R').text.encode('utf-8')
        self.s = root.find('S').text.encode('utf-8')
        if self._verify_sign(self.r, self.s):
            logging.debug('The signature is authentic')
            return dict(x.split('=') for x in self.r.split('&'))
        else:
            logging.debug('The signature is not authentic')
            return None

    def _send(self, command, params):
        query = 'ot=%s' % command
        for k, v in params.items():
            query = '&'.join([query, '='.join([k, v])])
        signature = self._sign(query)
        request = '{0:>s}?alg={1:>s}&query={2:>s}&sign={3:>s}'.format(
            self.url,
            self.ALG,
            urllib2.quote(query.encode('cp1251')),
            urllib2.quote(signature)
        )
        logging.debug("Request: [{0:>s}]".format("".join(request.split())))
        response = urllib2.urlopen(request).read()
        logging.debug("Response: [{0:>s}]".format("".join(response.split())))
        return self._parse(response)

    def request(self, ocode, code_1, code_2, code_3, amount, full_amount):
        command = 'R'
        params = {'TIdent': str(self.tident),
                  'OCode' : str(ocode),
                  'Code1' : str(code_1),
                  'Code2' : str(code_2),
                  'Code3' : str(code_3),
                  'Amount' : str(int(amount * 100)),
                  'FullAmount' : '' if full_amount is None else str(int(full_amount * 100))}
        return self._send(command, params)

    def confirm(self, cid, receiptnum):
        command = 'C'
        params = {'TIdent': str(self.tident),
                  'Cid': str(cid),
                  'ReceiptNum': str(receiptnum)}
        return self._send(command, params)

    def balance(self):
        command = 'GB'
        params = {'AId': str(self.aid)}
        balance = None
        try:
            b = self._send(command, params).get("Balances", None)
            if b:
                root = etree.fromstring(urllib.unquote_plus(b))
                node = root.find('Balance').find('CurrentBalance')
                if node.text:
                    balance = node.text
        except:
            pass
        return balance

if __name__ == "__main__":
    # set logger
    channel = logging.StreamHandler()
    channel.setFormatter(logging.Formatter("[%(asctime)s] [%(process)d] [%(levelname)-8s] %(message)s"))
    logger = logging.getLogger()
    logger.setLevel(logging.DEBUG)
    logger.addHandler(channel)

    url = 'https://test.delta-telecom.ru/dtpayspgw/'

    # agent params
    privkey = open("private.key").read()
    pubkey = open("pubkey.pem").read()
    aid = 5088
    tident = '00000005088.00001558'

    # payment params
    receiptnum = '123456789'
    ocode = 3
    code_1 = '9261234567'
    amount = 97.0
    full_amount = 100.0

    # start test
    spgw = SPGW(privkey, pubkey, url, aid, tident)
    balance = spgw.balance()
    if balance and spgw.c == 0:
        balance = float(balance)
        logging.info("Balance = {0:.2f}".format(balance))
        if balance > amount:
            response = spgw.request(ocode, code_1, '', '', amount, full_amount)
            if spgw.c == 0:
                result = int(response.get("Result", None))
                message = response.get("ResultMessage", None)
                logging.info("Result = {0:>d}, Message = {1:>s}".format(result, message))
                if result == 0 and spgw.c == 0:
                    cid = int(response["Cid"])
                    response = spgw.confirm(cid, receiptnum)
                    if spgw.c == 0:
                        result = int(response.get("Result", None))
                        logging.info("Result = {0:>d}, Cid = {1:>d}".format(result, cid))
                        if result == 0:
                            logging.info("Payment processed successfully")
                else:
                    logging.info("Payment error: {0:>s}".format(message))
            else:
                logging.error("Error: {0:>s}".format(spgw.r))
        else:
            logging.error("Error: balance too low")
    else:
        logging.error("Error: wrong balance ({0:>s})".format(spgw.r))


import numpy as np
import pytest

from cgpm.utils.general import get_prng
from cgpm.utils.test import gen_data_table

from cgpm2.categorical import Categorical
from cgpm2.crp import CRP
from cgpm2.normal import Normal
from cgpm2.poisson import Poisson

from cgpm2.flexible_rowmix import FlexibleRowMixture
from cgpm2.product import Product

from cgpm2.walks import add_cgpm
from cgpm2.walks import remove_cgpm

from cgpm2.transition_views import get_cgpm_view_proposals_existing
from cgpm2.transition_views import get_cgpm_view_proposals_singleton
from cgpm2.transition_views import get_dataset

def get_crosscat(prng):
    view0 = FlexibleRowMixture(
        cgpm_row_divide=CRP([-1], [], rng=prng),
        cgpm_components_base=Product([
            Normal([0], [], rng=prng),
            Normal([1], [], rng=prng),
        ], rng=prng),
        rng=prng)
    view1 = FlexibleRowMixture(
        cgpm_row_divide=CRP([-2], [], rng=prng),
        cgpm_components_base=Product([
            Poisson([2], [], rng=prng),
            Normal([3], [], rng=prng),
            Normal([4], [], rng=prng),
        ], rng=prng),
        rng=prng)
    view2 = FlexibleRowMixture(
        cgpm_row_divide=CRP([-3], [], rng=prng),
        cgpm_components_base=Product([
            Categorical([5], [], distargs={'k':4}, rng=prng),
        ], rng=prng),
        rng=prng)
    return Product([view0, view1, view2], rng=prng)

def populate_crosscat(crosscat, prng):
    X, Zv, Zrv = gen_data_table(
        n_rows=10,
        view_weights=[.4, .6],
        cluster_weights=[[.3,.4,.3],[.5,.5]],
        cctypes=['normal','normal','poisson','normal','normal','categorical'],
        distargs=[None, None, None, None, None, {'k':4}],
        separation=[0.99]*6,
        rng=prng)
    X[0,1] = X[3,1] = float('nan')
    dataset = np.transpose(X)
    for rowid, row in enumerate(dataset):
        observation = {c:v for c,v in enumerate(row)}
        crosscat.observe(rowid, observation)
    return crosscat

def test_crosscat_add_remove():
    prng = get_prng(2)
    crosscat =  get_crosscat(prng)
    infinite_mixture4 = FlexibleRowMixture(
        cgpm_row_divide=CRP([-4], [], rng=prng),
        cgpm_components_base=Product([
            Categorical([6], [], distargs={'k':4}, rng=prng),
        ], rng=prng),
        rng=prng)
    crosscat = add_cgpm(crosscat, infinite_mixture4)
    assert crosscat.outputs == [-1, 0, 1, -2, 2, 3, 4, -3, 5, -4, 6]
    crosscat = remove_cgpm(crosscat, -1)
    assert crosscat.outputs == [-2, 2, 3, 4, -3, 5, -4, 6]
    crosscat = remove_cgpm(crosscat, 5)
    assert crosscat.outputs == [-2, 2, 3, 4, -4, 6]

def test_get_view_proposals():
    prng = get_prng(2)
    crosscat = get_crosscat(prng)
    # Get block proposals of outputs [0,1] into all three views.
    proposals = get_cgpm_view_proposals_existing(crosscat, [0,1])
    assert len(proposals) == 3
    assert proposals[0].outputs == crosscat.cgpms[0].outputs
    assert proposals[1].outputs == crosscat.cgpms[1].outputs + [0, 1]
    assert proposals[2].outputs == crosscat.cgpms[2].outputs + [0, 1]
    # Get proposals of outputs [0,1] into 2 singleton views.
    proposals = get_cgpm_view_proposals_singleton(crosscat, [0,1], 2)
    assert len(proposals) == 2
    assert proposals[0].outputs[1:] == [0,1]
    assert proposals[1].outputs[1:] == [0,1]
    # Fail to get proposals for outputs in different views.
    with pytest.raises(Exception):
        proposals = get_cgpm_view_proposals_existing(crosscat, [0,2])

def test_logpdf_basic():
    prng = get_prng(2)
    crosscat = get_crosscat(prng)
    crosscat = populate_crosscat(crosscat, prng)
    for _rowid, row in get_dataset(crosscat, 0):
        logp = crosscat.logpdf(None, row)
        if np.isnan(row.values()[0]):
            assert np.allclose(logp, 0)
        else:
            assert logp < 0


from robot.libraries.BuiltIn import BuiltIn
import requests

class APIKeywords:
    def get_weather(self, city, base_url, api_key):
        query_params = {
            "q": city,
            "appid": api_key,
            "units": "metric"
        }
        response = requests.get(base_url, params=query_params)
        return response


#! /usr/bin/python3

import numpy as np
from scipy.optimize import curve_fit

"""
Colección de funciones para calcular un vector desde
el modelo de trayectoria
"""

def fun_lineal(x, b, c):
    return x * b + c

def tangente(ti, t, e, n, z):
    """
    Genera un vector en el tiempo ti
    para un modelo de desplazamiento (n, e, z)
    con un tiempo t

    Input:
    ti: ubicación de la recta tangente
    t:  array con tiempo del modelo
    e:  array con desplazamiento este
    n:  array con desplazamiento norte
    z:  array con desplazamiento vertical
    """
    # evalua la velocidad en base a los dos puntos mas cercanos del modelo
    idx = (np.abs(t-ti)).argmin()

    # dependiendo de la posicion de idx, considera el punto mas cercano
    # a la izquierda o a la derecha
    if idx-1 > 0:
        vel_e = (e[idx] - e[idx-1]) / (t[idx]-t[idx-1])
        vel_n = (n[idx] - n[idx-1]) / (t[idx]-t[idx-1])
        vel_z = (z[idx] - z[idx-1]) / (t[idx]-t[idx-1])
        # y = mx + c
        # calculo de c
        c_e = vel_e*(-t[idx-1]) + e[idx-1]
        c_n = vel_n*(-t[idx-1]) + n[idx-1]
        c_z = vel_z*(-t[idx-1]) + z[idx-1]

    else:
        vel_e = (e[idx+1] - e[idx]) / (t[idx+1]-t[idx])
        vel_n = (n[idx+1] - n[idx]) / (t[idx+1]-t[idx])
        vel_z = (z[idx+1] - z[idx]) / (t[idx+1]-t[idx])
        # y = mx + c
        # calculo de c
        c_e = vel_e*(-t[idx]) + e[idx]
        c_n = vel_n*(-t[idx]) + n[idx]
        c_z = vel_z*(-t[idx]) + z[idx]

    return np.array([vel_e, vel_n, vel_z]), np.array([c_e, c_n, c_z])

def fit(intervalo, t, e, n, z):
    """
    Genera un vector realizando un ajuste lineal
    sobre una serie en un intervalo de tiempo
    """
    # obtiene datos de intervalo de tiempo
    id_t = (t >= intervalo[0]) & (t <= intervalo[1])
    t = t[id_t]
    e = e[id_t]
    n = n[id_t]
    z = z[id_t]
    if len(t) < 10:
        print("Estacion sin datos para calcular una vel media")
        return False

    # ajuste de datos
    pva_e, cov_e = curve_fit(fun_lineal, t, e)
    pva_n, cov_n = curve_fit(fun_lineal, t, n)
    pva_z, cov_z = curve_fit(fun_lineal, t, z)

    err_e = np.sqrt(np.diag(cov_e))
    err_n = np.sqrt(np.diag(cov_n))
    err_z = np.sqrt(np.diag(cov_z))

    return (np.array([pva_e[0], pva_n[0], pva_z[0]]),
            np.array([pva_e[1], pva_n[1], pva_z[1]]),
            np.array([err_e[0], err_n[0], err_z[0]]))


B="B-.png"
BB="BB.png"
BBB="BBB.png"
BBK="BBK.png"
BBQ="BBQ.png"
BBR="BBR.png"
BBXX="BBXX.png"
BWB="BWB.png"
BWK="BWK.png"
BWP="BWP.png"
BWQ="BWQ.png"
BWR="BWR.png"
BWXX="BWXX.png"
BBP="BBP.png"
W="W-.png"
WB="WB.png"
WBB="WBB.png"
WBK="WBK.png"
WBQ="WBQ.png"
WBE="WBE.png"
WBXX="WBXX.png"
WWB="WWB.png"
WWK="WWK.png"
WWP="WWP.png"
WWQ="WWQ.png"
WWR="WWR.png"
WWXX="WWXX.png"
WBR="WBR.png"
WBP="WBP.png"


import pyttsx3  # pip install pyttsx3
import speech_recognition as sr  # pip install speechRecognition
import datetime
import wikipedia  # pip install wikipedia
import webbrowser
import os
import smtplib
import pywhatkit
import pyjokes

engine = pyttsx3.init('sapi5')
voices = engine.getProperty('voices')
# print(voices[1].id)
engine.setProperty('voice', voices[0].id)

def speak(audio):
    engine.say(audio)
    engine.runAndWait()

def wishMe():
    hour = int(datetime.datetime.now().hour)
    if hour >= 0 and hour < 12:
        speak("Good Morning!")

    elif hour >= 12 and hour < 18:
        speak("Good Afternoon!")

    else:
        speak("Good Evening!")

    speak("I am your voice assistant how may I help you")

def takeCommand():
    # It takes microphone input from the user and returns string output

    r = sr.Recognizer()
    with sr.Microphone() as source:
        print("Listening...")
        r.pause_threshold = 1
        audio = r.listen(source)

    try:
        print("Recognizing...")
        text = r.recognize_google(audio)
        print(f"User said: {text}\n")

    except Exception as e:
        # print(e)
        speak("please repeat again...")
        return "None"
    return text

if __name__ == "__main__":
    wishMe()
    while True:
        # if 1:
        text = takeCommand().lower()

        # Logic for executing tasks based on query

        if 'open youtube' in text:
            webbrowser.open("youtube.com")

        elif 'open google' in text:
            webbrowser.open("google.com")

        elif 'who is' in text:
            person = text.replace('who is', '')
            info = wikipedia.summary(person, 1)
            print(info)
            speak(info)

        elif 'how are you' in text:
            speak("im good, thanks for asking")

        elif 'play' in text:
            song = text.replace('play', '')
            speak('playing ' + song)
            pywhatkit.playonyt(song)

        elif 'time' in text:
            time = datetime.datetime.now().strftime('%I:%M %p')
            speak('Current time is ' + time)

        elif 'joke' in text:
            speak(pyjokes.get_joke())

        elif 'name' in text:
            speak("prajwal")

        elif 'exit' in text:
            speak("thank you")
            quit()


from random import randint, random

# Napiste funkci, ktera bude provadet hazeni obycejnou sestistennou kostkou
# tak dlouho dokud nepadne liche cislo, pricemz jednotlive hody vypisujte na
#  jeden radek. Pote funkce vrati celkovy soucet vsech hozenych hodu.
def even_turn():
    number = 1
    total = 0
    number_of_throws = 0

    while number % 2 == 1:
        number = randint(1, 6)
        total = total + number
        number_of_throws += 1
        print(number, end=" ")

        print()
        print("Pocet hodu:", number_of_throws)
        print("Prumer hodu:", total / number_of_throws)

        return total

print("\nVysledek =", even_turn())
print("\nVysledek =", even_turn())
print("\nVysledek =", even_turn())

# Ve funkci vypiste pocet hozeni kostkou a prumer hodu
def even_turn2():
    return 0  # TODO

print("\nVysledek =", even_turn2())
print("\nVysledek =", even_turn2())
print("\nVysledek =", even_turn2())

# Prestante hazet, pokud hody prekroci hranici danou novym parametrem limit
# Nastavte, ze prvnich first hodu muze padnout i liche cislo
def even_turn3(limit, first):
    return 0  # TODO

print("\nVysledek =", even_turn3(10, 3))
print("\nVysledek =", even_turn3(15, 4))
print("\nVysledek =", even_turn3(100, 5))

# Napiste funkci divisors_count(n), ktera vrati pocet delitelu cisla n
def divisors_count(n):
    divisors_found = 0

    for i in range(1, n + 1):
        if n % i == 0:
            divisors_found += 1

    return divisors_found

# Napiste funkci is_prime(n), ktera vrati True pokud je cislo n prvocislo,
# jinak False
def is_prime(n):
    return divisors_count(n) == 2

# Napiste funkci kth_prime(k), ktera vrati k-te prvocislo.
def kth_prime(k):
    count = 0
    num = 0

    if count == num:
        while count <= num:
            is_prime(k)
            count += 1

    return num

# Napiste funkci, ktera vygeneruje a vypise count nahodnych cisel v intervalu
# [lower, upper], pricemz jednotlive hody vypisujte na jeden radek. Nasledne
# vypise nejmensi, nejvetsi a prumerne cislo.
def dice_freq(count, lower, upper):
    return 0

dice_freq(10, 1, 16)

# Opilec na ceste domu
# Opilec je na puli cesty mezi domovem a hospodou, kazdy krok udela nahodne
# jednim smerem. Napiste funkci, ktera bude simulovat opilcuv pohyb. Jejimy
# parametry budou vzdalenost mezi domovem a hospodou a pocet kroku do
# opilcova usnuti (tj. maximalni delka simulace). Simulace skonci bud tehdy,
# kdyz opilec dojede domu nebo do hospody, pripadne po vycerpani poctu kroku.

# Ukazka vystupu:
# home . . . . . * . . . . pub
# home . . . . * . . . . . pub
# home . . . * . . . . . . pub
# home . . . . * . . . . . pub
# home . . . * . . . . . . pub
# home . . . . * . . . . . pub
# home . . . * . . . . . . pub
# home . . * . . . . . . . pub
# home . * . . . . . . . . pub
# home * . . . . . . . . . pub
# home . . . . . . . . . . pub
# Got home!

# Upravte funkci z predchozi prikladu tak, aby nevypisovala stav opilce
# (napriklad pridanim volitelneho parametru output a zapodminkovanim vypisu)
# a aby vracela True dojde-li opilec domu a False pokud ne.

def drunkman_simulator(size, steps, output=False):
    pass  # TODO

drunkman_simulator(10, 10)

# Nasledne napiste funkci, ktera provede simulaci opilce count krat a vypise
# procentualni uspesnost dojiti domu.

def drunkman_analysis(size, steps, count):
    pass  # TODO

drunkman_analysis(10, 100, 100)
print()

########################################################################
#               Nasleduje kod testu                                    #
########################################################################

ib113_divisors_in = (1, 5, 42, 127, 1024)
ib113_divisors_out = (1, 2, 8, 2, 11)

def ib113_test_divisors_count():
    print("Testovani funkce divisors_count: ", end="")
    failure = False

    for i in range(len(ib113_divisors_in)):
        res = divisors_count(ib113_divisors_in[i])
        if not isinstance(res, int):
            failure = True
            print("NOK")
            print("Nebyla vracena hodnota typu int, "
                  "ale typu {}".format(type(res)))
            break
        if res != ib113_divisors_out[i]:
            failure = True
            print("NOK")
            print("Pro hodnotu {} nebyl vracen spravny vysledek"
                  .format(ib113_divisors_in[i]))
            print("Byl vracen vysledek: {}".format(res))
            print("Byl ocekavan vysledek: {}".format(ib113_divisors_out[i]))
            break

    if not failure:
        print("OK")

ib113_is_prime_in = (1, 2, 3, 42, 127)
ib113_is_prime_out = (False, True, True, False, True)

def ib113_test_is_prime():
    print("Testovani funkce is_prime_count: ", end="")
    failure = False

    for i in range(len(ib113_is_prime_in)):
        res = is_prime(ib113_is_prime_in[i])
        if not isinstance(res, int):
            failure = True
            print("NOK")
            print("Nebyla vracena hodnota typu int, "
                  "ale typu {}".format(type(res)))
            break
        if res != ib113_is_prime_out[i]:
            failure = True
            print("NOK")
            print("Pro hodnotu {} nebyl vracen spravny vysledek"
                  .format(ib113_is_prime_in[i]))
            print("Byl vracen vysledek: {}".format(res))
            print("Byl ocekavan vysledek: {}".format(ib113_is_prime_out[i]))
            break

    if not failure:
        print("OK")

ib113_kth_prime_in = (1, 2, 10, 100)
ib113_kth_prime_out = (2, 3, 29, 541)

def ib113_test_kth_prime():
    print("Testovani funkce kth_prime_count: ", end="")
    failure = False

    for i in range(len(ib113_kth_prime_in)):
        res = kth_prime(ib113_kth_prime_in[i])
        if not isinstance(res, int):
            failure = True
            print("NOK")
            print("Nebyla vracena hodnota typu int, "
                  "ale typu {}".format(type(res)))
            break
        if res != ib113_kth_prime_out[i]:
            failure = True
            print("NOK")
            print("Pro hodnotu {} nebyl vracen spravny vysledek"
                  .format(ib113_kth_prime_in[i]))
            print("Byl vracen vysledek: {}".format(res))
            print("Byl ocekavan vysledek: {}".format(ib113_kth_prime_out[i]))
            break

    if not failure:
        print("OK")

# Zde muzete vkladat vlastni testy
if __name__ == '__main__':
    ib113_test_divisors_count()
    print()
    ib113_test_is_prime()
    print()
    ib113_test_kth_prime()


import socket, os
from threading import Thread
from dotenv import load_dotenv
from datetime import datetime

load_dotenv() # Carrega as variáveis de ambiente

HOST = ''                                      # Endereco IP do Servidor
PORT = int(os.getenv('PORT', "1234"))            # Porta do Servidor

def writer(msg, file_name, client):
    file = open(file_name, "ab")

    # Verifica se o espaço restante do arquivo atualmente aberto, considerando o tamanho máximo por arquivo, é suficiente para receber o novo dado
    remain_space = int(os.getenv("MAX_FILE_LENGTH", "10")) - os.stat(file_name).st_size

    if remain_space >= len(msg):
        file.write(msg)
    else:
        # Caso não tenha espaço suficiente, então parte do arquivo é gravado no espaço
        # restante do arquivo atual e logo depois novo(s) arquivo(s) é/são gerado(s)
        # para armazenar o restante dos dados
        file.write(msg[:remain_space])

        date_time = datetime.now().strftime("%Y%m%d%H%M%S")
        file_name = f"logs/{client[0]}:{client[1]}_{date_time}"

        file = open(file_name, "ab")

        # Para mensagens que precisam ser armazenadas em mais de um arquivo o count_file
        # é utilizado para diferenciar os vários arquivos que compõem a mesma mensagem
        remain_msg_to_be_stored = len(msg) - remain_space
        head = remain_space
        count_file = 1

        # Esse laço avalia o quanto da mensagem falta ser armazenada e se deve ser em
        # um único arquivo ou em vários.
        while remain_msg_to_be_stored > 0:
            if remain_msg_to_be_stored <= int(os.getenv("MAX_FILE_LENGTH", "10")):
                file.write(msg[head:])
                remain_msg_to_be_stored = 0
            else:
                file.write(msg[head:(head + int(os.getenv("MAX_FILE_LENGTH", "10")))])
                head += int(os.getenv("MAX_FILE_LENGTH", "10"))
                remain_msg_to_be_stored -= int(os.getenv("MAX_FILE_LENGTH", "10"))

                if remain_msg_to_be_stored > 0:
                    file_name = f"logs/{client[0]}:{client[1]}_{count_file}_{date_time}"
                    count_file += 1
                    file = open(file_name, "ab")

        file.close()

    return file_name

def listener(con, client):
    print(f"Recebido a conexão {client[0]}:{client[1]}")
    # Cancela a conexão caso o cliente não envie dados no timeout especificado
    con.settimeout(int(os.getenv("TIMEOUT", "10")))
    print("Conexão estabelecida de ", client)

    try:
        date_time = datetime.now().strftime("%Y%m%d%H%M%S")
        file_name = f"logs/{client[0]}:{client[1]}_{date_time}"

        while True:
            msg = con.recv(1024)

            # Encerra a conexão caso o programa cliente seja encerrado
            if not msg:
                con.close()

            file_name = writer(msg, file_name, client)

    except Exception as e:
        print(f"Cliente {client[0]}:{client[1]} desconectado")

if __name__ == "__main__":
    # Os argumentos indicam que o socket irá operar com IPv4 e utilizando o protocolo TCP
    server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server.bind((HOST, PORT))
    server.listen()

    #O uso de threads permite múltiplas conexões simultaneamente
    while True:
        conn, client = server.accept()
        conn_listener = Thread(target=listener, args=(conn, client,))
        conn_listener.start()
        # Não foi necessário finalizar as threads com o join(), pois o timeout do socket
        # encerra a thread quando o cliente estoura o tempo limite para envio de mensagens
        # levantando uma exceção, já o client.close() encerra a conexão com o cliente
        # quando ele é encerrado antes de estourar o timeout também levantando uma
        # exceção o que encerra a thread para aquele cliente.