import nltk
import wikipedia
import prettytable
import matplotlib.pyplot as plt

from nltk import Tree
from nltk.draw.util import CanvasFrame
from nltk.draw import TreeWidget

from typing import List
from nltk.corpus import wordnet
from nltk.stem import WordNetLemmatizer
from nltk.parse.generate import generate
from nltk.tokenize import word_tokenize, sent_tokenize

what = lambda x: print(nltk.help.upenn_tagset(x))

"""
Exercise 1:
Choose a wikipedia article. You will download and acces the article using this python module: wikipedia.
Use the content property to extract the text.
Print the title of the article and the first N=200 words from the article to verify that all works well.
Print the POS-tagging for the first N=20 sentences.
"""

wikipedia.set_lang('en')
wikipedia_page = wikipedia.page("COVID-19 pandemic")
content = wikipedia_page.content

N = 200
print("Wikipedia Page Title: {}".format(wikipedia_page.title))
words = word_tokenize(content)
print(words[: N])

N = 20
sentences = sent_tokenize(content)
pos_taggs = [nltk.pos_tag(word_tokenize(sentence)) for (i, sentence) in enumerate(sentences) if i < N]
print("POS-tagging for the first N sentences")
print(pos_taggs)

"""
Exercise 2:
Create a function that receives a part of speech tag and returns a list with all the words from the text
(can be given as a parameter too) that represent that part of speech.
Create a function that receives a list of POS tags and returns a list with words having any of the given POS tags
(use the first function in implementing the second one).
"""

def get_words_part_of_speech(content: str = None, tag: str = None) -> List[str]:
    sentences = sent_tokenize(content)
    taggs = [nltk.pos_tag(word_tokenize(sentence)) for sentence in sentences]
    return [word for tagg_sentence in taggs for (word, tagg) in tagg_sentence if tagg == tag]

def get_words_parts_of_speech(content: str = None, tags: List[str] = None) -> List[str]:
    result = []
    for pos in tags:
        result.extend(get_words_part_of_speech(content, pos))
    return result

print("Selected words by a single part of speech")
print(get_words_part_of_speech(content, "CD")[:20])
print("Selected words by multiple part of speech")
print(get_words_parts_of_speech(content, ["DT", "CD"])[:50])

"""
Exercise 3:
Use the function above to print all the nouns (there are multiple tags for nouns),
and, respectively all the verbs (corresponding to all verb tags).
Also, print the percentage of content words (noun+verbs) from the entire text
"""

nouns = get_words_parts_of_speech(content, ["NN", "NNP", "NNPS", "NNS"])
verbs = get_words_parts_of_speech(content, ["VB", "VBD", "VBG", "VBN", "VBP", "VBZ"])

print("All nouns from text")
print(nouns[:50])

print("All verbs from text")
print(verbs[:50])

print("The percent of (nouns + verbs) from all text is: {}%".format((len(nouns) + len(verbs)) * 100 / len(word_tokenize(content))))

"""
Exercise 4:
Print a table of four columns. The columns will be separated with the character "|".
The head of the table will be: Original word | POS | Simple lemmatization | Lemmatization with POS that will compare
the results of lemmatization (WordNetLemmatizer) without giving the part of speech and the lemmatization with the given part of speech for each word.
The table must contain only words that give different results for the two lemmatizations (for example, the word "running" - without POS,
the result will always be running, but with pos="v" it is "run").
The table will contain the results for the first N sentences from the text (each row corresponding to a word).
Try to print only distinct results inside the table
(for example, if a word has two occurnces inside the text, and matches the requirments for appearing in the table, it should have only one corresponding row).
"""

def get_wordnet_pos(tag):
    if tag.startswith('J'):
        return wordnet.ADJ
    elif tag.startswith('V'):
        return wordnet.VERB
    elif tag.startswith('N'):
        return wordnet.NOUN
    elif tag.startswith('R'):
        return wordnet.ADV
    else:
        return wordnet.NOUN

N = 5
table = prettytable.PrettyTable(["Original word", "POS", "Simple lemmatization", "Lemmatization with POS"])
lemmatizer = WordNetLemmatizer()
sentences = [sentence for (i, sentence) in enumerate(sent_tokenize(content)) if i < N]
words_and_pos = [(word, get_wordnet_pos(nltk.tag.pos_tag([word])[0][1])) for sentence in sentences for word in word_tokenize(sentence)]

words_and_pos = list(set(words_and_pos))

for word, tag in words_and_pos:
    simple_lemmatize = lemmatizer.lemmatize(word)
    pos_lemmatize = lemmatizer.lemmatize(word, tag)

    if simple_lemmatize != pos_lemmatize:
        table.add_row([word, tag, simple_lemmatize, pos_lemmatize])

print(table)

"""
Exercise 5:
Print a graphic showing the number of words for each part of speech.
If there are too many different parts of speech, you can print only those with a higher number of corresponding words.
"""

sentences = sent_tokenize(content)
pos_taggs = [nltk.pos_tag(word_tokenize(sentence)) for (i, sentence) in enumerate(sentences)]

counter = {tag : 0 for sentence in pos_taggs for word, tag in sentence}
for sentence in pos_taggs:
    for word, tag in sentence:
        counter[tag] += 1

plt.figure(figsize = (24, 9))
plt.bar(range(len(counter)), list(counter.values()), align = 'center')
plt.xticks(range(len(counter)), list(counter.keys()))
plt.xlabel("Part of speech tag")
plt.ylabel("No. of words")
plt.show()

"""
Exercise 6:
Create your own grammar with different terminal symbols.
Apply recursive descent parsing on a sentence with at least 5 different parts of speech and a tree of at least level 4.
"""

grammar_productions = """
S -> SB VB ADV
SB -> PN | SC | SP
PN -> PP | PNP
VB -> CJ VBI | VBP | VBN
ADV -> CJ VBI UDN
UDN -> LA SC
LA -> 'la'
SC -> 'magazin'
VBI -> 'merg'
PP -> 'Eu'
PNP -> 'ma'
VBP -> 'vreau'
CJ -> 'sa'
"""

sentence = "Eu vreau sa merg la magazin"

grammar = nltk.CFG.fromstring(grammar_productions)

# print(grammar)
# for sentence in generate(grammar, n=10):
#     print(' '.join(sentence))

words = word_tokenize(sentence)
#print(words)

# RecursiveDescentParser, ShiftReduceParser
rdp = nltk.RecursiveDescentParser(grammar)
for tree in rdp.parse(words):
    print(tree)

"""
Exercise 7:
Apply shift reduce parsing on the same sentence and check programatically if the two trees are equal.
Find a sentence with equal trees and a sentence with different results
(we consider the tree different even when it has no sollution for one of the parsers, but has for the other).
"""

sentence = "Eu vreau sa merg la magazin"
words = word_tokenize(sentence)

rdp = nltk.RecursiveDescentParser(grammar)
srp = nltk.ShiftReduceParser(grammar)

tree1 = None
for tree in rdp.parse(words):
    tree1 = tree

print(type(tree1))

tree2 = None
for tree in srp.parse(words):
    tree2 = tree

print(type(tree2))

if tree1 == tree2:
    print("Trees are the same")
else:
    print("Trees are different")


def main():
    while True:

        try:
            age = int(input("Enter your age:"))
            print("10/Age is:", 10 / age)

        except (ValueError, ZeroDivisionError) as err:
            print(f"The error occured is: {err}")

        else:
            print("Thank you..")
            break

if __name__ == "__main__":
    main()

4 Python_Programs/Programs to demo python concepts/error_handling2.py


"""add_motd

Revision ID: 19b877061c98
Revises: 1256117ad629
Create Date: 2022-04-05 13:49:44.087517

"""
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import mysql

# revision identifiers, used by Alembic.
revision = "19b877061c98"
down_revision = "1256117ad629"
branch_labels = None
depends_on = None

def upgrade():
    # ### commands auto generated by Alembic - please adjust! ###
    op.create_table(
        "motd",
        sa.Column("id", sa.Integer(), autoincrement=True, nullable=False),
        sa.Column("message", sa.Text(), nullable=False),
        sa.Column("date_created", sa.DateTime(), nullable=False),
        sa.PrimaryKeyConstraint("id"),
    )
    # ### end Alembic commands ###

def downgrade():
    # ### commands auto generated by Alembic - please adjust! ###
    op.drop_table("motd")
    # ### end Alembic commands ###


import sys
from abc import abstractmethod, ABCMeta

from pyspark import since, keyword_only
from pyspark.ml.wrapper import JavaParams
from pyspark.ml.param import Param, Params, TypeConverters
from pyspark.ml.param.shared import HasLabelCol, HasPredictionCol, HasRawPredictionCol, \
    HasFeaturesCol
from pyspark.ml.common import inherit_doc
from pyspark.ml.util import JavaMLReadable, JavaMLWritable

__all__ = ['Evaluator', 'BinaryClassificationEvaluator', 'RegressionEvaluator',
           'MulticlassClassificationEvaluator', 'ClusteringEvaluator']

@inherit_doc
class Evaluator(Params):
    """
    Base class for evaluators that compute metrics from predictions.

    .. versionadded:: 1.4.0
    """

    __metaclass__ = ABCMeta

    @abstractmethod
    def _evaluate(self, dataset):
        """
        Evaluates the output.

        :param dataset: a dataset that contains labels/observations and
               predictions
        :return: metric
        """
        raise NotImplementedError()

    @since("1.4.0")
    def evaluate(self, dataset, params=None):
        """
        Evaluates the output with optional parameters.

        :param dataset: a dataset that contains labels/observations and
                        predictions
        :param params: an optional param map that overrides embedded
                       params
        :return: metric
        """
        if params is None:
            params = dict()
        if isinstance(params, dict):
            if params:
                return self.copy(params)._evaluate(dataset)
            else:
                return self._evaluate(dataset)
        else:
            raise ValueError("Params must be a param map but got %s." % type(params))

    @since("1.5.0")
    def isLargerBetter(self):
        """
        Indicates whether the metric returned by :py:meth:`evaluate` should be maximized
        (True, default) or minimized (False).
        A given evaluator may support multiple metrics which may be maximized or minimized.
        """
        return True

@inherit_doc
class JavaEvaluator(JavaParams, Evaluator):
    """
    Base class for :py:class:`Evaluator`s that wrap Java/Scala
    implementations.
    """

    __metaclass__ = ABCMeta

    def _evaluate(self, dataset):
        """
        Evaluates the output.
        :param dataset: a dataset that contains labels/observations and predictions.
        :return: evaluation metric
        """
        self._transfer_params_to_java()
        return self._java_obj.evaluate(dataset._jdf)

    def isLargerBetter(self):
        self._transfer_params_to_java()
        return self._java_obj.isLargerBetter()

@inherit_doc
class BinaryClassificationEvaluator(JavaEvaluator, HasLabelCol, HasRawPredictionCol,
                                    JavaMLReadable, JavaMLWritable):
    """
    .. note:: Experimental

    Evaluator for binary classification, which expects two input columns: rawPrediction and label.
    The rawPrediction column can be of type double (binary 0/1 prediction, or probability of label
    1) or of type vector (length-2 vector of raw predictions, scores, or label probabilities).

    >>> from pyspark.ml.linalg import Vectors
    >>> scoreAndLabels = map(lambda x: (Vectors.dense([1.0 - x[0], x[0]]), x[1]),
    ...    [(0.1, 0.0), (0.1, 1.0), (0.4, 0.0), (0.6, 0.0), (0.6, 1.0), (0.6, 1.0), (0.8, 1.0)])
    >>> dataset = spark.createDataFrame(scoreAndLabels, ["raw", "label"])
    ...
    >>> evaluator = BinaryClassificationEvaluator(rawPredictionCol="raw")
    >>> evaluator.evaluate(dataset)
    0.70...
    >>> evaluator.evaluate(dataset, {evaluator.metricName: "areaUnderPR"})
    0.83...
    >>> bce_path = temp_path + "/bce"
    >>> evaluator.save(bce_path)
    >>> evaluator2 = BinaryClassificationEvaluator.load(bce_path)
    >>> str(evaluator2.getRawPredictionCol())
    'raw'

    .. versionadded:: 1.4.0
    """

    metricName = Param(Params._dummy(), "metricName",
                       "metric name in evaluation (areaUnderROC|areaUnderPR)",
                       typeConverter=TypeConverters.toString)

    @keyword_only
    def __init__(self, rawPredictionCol="rawPrediction", labelCol="label",
                 metricName="areaUnderROC"):
        """
        __init__(self, rawPredictionCol="rawPrediction", labelCol="label", \
                 metricName="areaUnderROC")
        """
        super(BinaryClassificationEvaluator, self).__init__()
        self._java_obj = self._new_java_obj(
            "org.apache.spark.ml.evaluation.BinaryClassificationEvaluator", self.uid)
        self._setDefault(metricName="areaUnderROC")
        kwargs = self._input_kwargs
        self._set(**kwargs)

    @since("1.4.0")
    def setMetricName(self, value):
        """
        Sets the value of :py:attr:`metricName`.
        """
        return self._set(metricName=value)

    @since("1.4.0")
    def getMetricName(self):
        """
        Gets the value of metricName or its default value.
        """
        return self.getOrDefault(self.metricName)

    @keyword_only
    @since("1.4.0")
    def setParams(self, rawPredictionCol="rawPrediction", labelCol="label",
                  metricName="areaUnderROC"):
        """
        setParams(self, rawPredictionCol="rawPrediction", labelCol="label", \
                  metricName="areaUnderROC")
        Sets params for binary classification evaluator.
        """
        kwargs = self._input_kwargs
        return self._set(**kwargs)

@inherit_doc
class RegressionEvaluator(JavaEvaluator, HasLabelCol, HasPredictionCol,
                          JavaMLReadable, JavaMLWritable):
    """
    .. note:: Experimental

    Evaluator for Regression, which expects two input
    columns: prediction and label.

    >>> scoreAndLabels = [(-28.98343821, -27.0), (20.21491975, 21.5),
    ...   (-25.98418959, -22.0), (30.69731842, 33.0), (74.69283752, 71.0)]
    >>> dataset = spark.createDataFrame(scoreAndLabels, ["raw", "label"])
    ...
    >>> evaluator = RegressionEvaluator(predictionCol="raw")
    >>> evaluator.evaluate(dataset)
    2.842...
    >>> evaluator.evaluate(dataset, {evaluator.metricName: "r2"})
    0.993...
    >>> evaluator.evaluate(dataset, {evaluator.metricName: "mae"})
    2.649...
    >>> re_path = temp_path + "/re"
    >>> evaluator.save(re_path)
    >>> evaluator2 = RegressionEvaluator.load(re_path)
    >>> str(evaluator2.getPredictionCol())
    'raw'

    .. versionadded:: 1.4.0
    """
    metricName = Param(Params._dummy(), "metricName",
                       """metric name in evaluation - one of:
                       rmse - root mean squared error (default)
                       mse - mean squared error
                       r2 - r^2 metric
                       mae - mean absolute error.""",
                       typeConverter=TypeConverters.toString)

    @keyword_only
    def __init__(self, predictionCol="prediction", labelCol="label",
                 metricName="rmse"):
        """
        __init__(self, predictionCol="prediction", labelCol="label", \
                 metricName="rmse")
        """
        super(RegressionEvaluator, self).__init__()
        self._java_obj = self._new_java_obj(
            "org.apache.spark.ml.evaluation.RegressionEvaluator", self.uid)
        self._setDefault(metricName="rmse")
        kwargs = self._input_kwargs
        self._set(**kwargs)

    @since("1.4.0")
    def setMetricName(self, value):
        """
        Sets the value of :py:attr:`metricName`.
        """
        return self._set(metricName=value)

    @since("1.4.0")
    def getMetricName(self):
        """
        Gets the value of metricName or its default value.
        """
        return self.getOrDefault(self.metricName)

    @keyword_only
    @since("1.4.0")
    def setParams(self, predictionCol="prediction", labelCol="label",
                  metricName="rmse"):
        """
        setParams(self, predictionCol="prediction", labelCol="label", \
                  metricName="rmse")
        Sets params for regression evaluator.
        """
        kwargs = self._input_kwargs
        return self._set(**kwargs)

@inherit_doc
class MulticlassClassificationEvaluator(JavaEvaluator, HasLabelCol, HasPredictionCol,
                                        JavaMLReadable, JavaMLWritable):
    """
    .. note:: Experimental

    Evaluator for Multiclass Classification, which expects two input
    columns: prediction and label.

    >>> scoreAndLabels = [(0.0, 0.0), (0.0, 1.0), (0.0, 0.0),
    ...     (1.0, 0.0), (1.0, 1.0), (1.0, 1.0), (1.0, 1.0), (2.0, 2.0), (2.0, 0.0)]
    >>> dataset = spark.createDataFrame(scoreAndLabels, ["prediction", "label"])
    ...
    >>> evaluator = MulticlassClassificationEvaluator(predictionCol="prediction")
    >>> evaluator.evaluate(dataset)
    0.66...
    >>> evaluator.evaluate(dataset, {evaluator.metricName: "accuracy"})
    0.66...
    >>> mce_path = temp_path + "/mce"
    >>> evaluator.save(mce_path)
    >>> evaluator2 = MulticlassClassificationEvaluator.load(mce_path)
    >>> str(evaluator2.getPredictionCol())
    'prediction'

    .. versionadded:: 1.5.0
    """
    metricName = Param(Params._dummy(), "metricName",
                       "metric name in evaluation "
                       "(f1|weightedPrecision|weightedRecall|accuracy)",
                       typeConverter=TypeConverters.toString)

    @keyword_only
    def __init__(self, predictionCol="prediction", labelCol="label",
                 metricName="f1"):
        """
        __init__(self, predictionCol="prediction", labelCol="label", \
                 metricName="f1")
        """
        super(MulticlassClassificationEvaluator, self).__init__()
        self._java_obj = self._new_java_obj(
            "org.apache.spark.ml.evaluation.MulticlassClassificationEvaluator", self.uid)
        self._setDefault(metricName="f1")
        kwargs = self._input_kwargs
        self._set(**kwargs)

    @since("1.5.0")
    def setMetricName(self, value):
        """
        Sets the value of :py:attr:`metricName`.
        """
        return self._set(metricName=value)

    @since("1.5.0")
    def getMetricName(self):
        """
        Gets the value of metricName or its default value.
        """
        return self.getOrDefault(self.metricName)

    @keyword_only
    @since("1.5.0")
    def setParams(self, predictionCol="prediction", labelCol="label",
                  metricName="f1"):
        """
        setParams(self, predictionCol="prediction", labelCol="label", \
                  metricName="f1")
        Sets params for multiclass classification evaluator.
        """
        kwargs = self._input_kwargs
        return self._set(**kwargs)

@inherit_doc
class ClusteringEvaluator(JavaEvaluator, HasPredictionCol, HasFeaturesCol,
                          JavaMLReadable, JavaMLWritable):
    """
    .. note:: Experimental

    Evaluator for Clustering results, which expects two input
    columns: prediction and features. The metric computes the Silhouette
    measure using the squared Euclidean distance.

    The Silhouette is a measure for the validation of the consistency
    within clusters. It ranges between 1 and -1, where a value close to
    1 means that the points in a cluster are close to the other points
    in the same cluster and far from the points of the other clusters.

    >>> from pyspark.ml.linalg import Vectors
    >>> featureAndPredictions = map(lambda x: (Vectors.dense(x[0]), x[1]),
    ...     [([0.0, 0.5], 0.0), ([0.5, 0.0], 0.0), ([10.0, 11.0], 1.0),
    ...     ([10.5, 11.5], 1.0), ([1.0, 1.0], 0.0), ([8.0, 6.0], 1.0)])
    >>> dataset = spark.createDataFrame(featureAndPredictions, ["features", "prediction"])
    ...
    >>> evaluator = ClusteringEvaluator(predictionCol="prediction")
    >>> evaluator.evaluate(dataset)
    0.9079...
    >>> ce_path = temp_path + "/ce"
    >>> evaluator.save(ce_path)
    >>> evaluator2 = ClusteringEvaluator.load(ce_path)
    >>> str(evaluator2.getPredictionCol())
    'prediction'

    .. versionadded:: 2.3.0
    """
    metricName = Param(Params._dummy(), "metricName",
                       "metric name in evaluation (silhouette)",
                       typeConverter=TypeConverters.toString)
    distanceMeasure = Param(Params._dummy(), "distanceMeasure", "The distance measure. " +
                            "Supported options: 'squaredEuclidean' and 'cosine'.",
                            typeConverter=TypeConverters.toString)

    @keyword_only
    def __init__(self, predictionCol="prediction", featuresCol="features",
                 metricName="silhouette", distanceMeasure="squaredEuclidean"):
        """
        __init__(self, predictionCol="prediction", featuresCol="features", \
                 metricName="silhouette", distanceMeasure="squaredEuclidean")
        """
        super(ClusteringEvaluator, self).__init__()
        self._java_obj = self._new_java_obj(
            "org.apache.spark.ml.evaluation.ClusteringEvaluator", self.uid)
        self._setDefault(metricName="silhouette", distanceMeasure="squaredEuclidean")
        kwargs = self._input_kwargs
        self._set(**kwargs)

    @since("2.3.0")
    def setMetricName(self, value):
        """
        Sets the value of :py:attr:`metricName`.
        """
        return self._set(metricName=value)

    @since("2.3.0")
    def getMetricName(self):
        """
        Gets the value of metricName or its default value.
        """
        return self.getOrDefault(self.metricName)

    @keyword_only
    @since("2.3.0")
    def setParams(self, predictionCol="prediction", featuresCol="features",
                  metricName="silhouette", distanceMeasure="squaredEuclidean"):
        """
        setParams(self, predictionCol="prediction", featuresCol="features", \
                  metricName="silhouette", distanceMeasure="squaredEuclidean")
        Sets params for clustering evaluator.
        """
        kwargs = self._input_kwargs
        return self._set(**kwargs)

    @since("2.4.0")
    def setDistanceMeasure(self, value):
        """
        Sets the value of :py:attr:`distanceMeasure`.
        """
        return self._set(distanceMeasure=value)

    @since("2.4.0")
    def getDistanceMeasure(self):
        """
        Gets the value of `distanceMeasure`
        """
        return self.getOrDefault(self.distanceMeasure)

if __name__ == "__main__":
    import doctest
    import tempfile
    import pyspark.ml.evaluation
    from pyspark.sql import SparkSession
    globs = pyspark.ml.evaluation.__dict__.copy()
    # The small batch size here ensures that we see multiple batches,
    # even in these small test examples:
    spark = SparkSession.builder\
        .master("local[2]")\
        .appName("ml.evaluation tests")\
        .getOrCreate()
    globs['spark'] = spark
    temp_path = tempfile.mkdtemp()
    globs['temp_path'] = temp_path
    try:
        (failure_count, test_count) = doctest.testmod(globs=globs, optionflags=doctest.ELLIPSIS)
        spark.stop()
    finally:
        from shutil import rmtree
        try:
            rmtree(temp_path)
        except OSError:
            pass
    if failure_count:
        sys.exit(-1)


import requests
import logging
from tornado.httpclient import HTTPRequest, AsyncHTTPClient
from tornado import gen
try:
    import ujson as json
except:
    import json as json

__author__ = 'grigory51'

logger = logging.getLogger('bot')

def get_updates(bot):
    client = AsyncHTTPClient()
    requests.post(bot.get_method_url('setWebhook'))
    update_id = [None]

    @gen.coroutine
    def wrapper():
        data = {}
        if update_id[0] is not None:
            data['offset'] = update_id[0]

        req = HTTPRequest(bot.get_method_url('getUpdates', data))
        res = yield client.fetch(req)

        data = json.loads(res.body)
        if data.get('ok'):
            flag = False
            for item in data.get('result', []):
                flag = True
                if update_id[0] is None or item.get('update_id') + 1 > update_id[0]:
                    update_id[0] = item.get('update_id') + 1
                    bot._on_hook(item)
            if flag:
                logger.debug('Processing updates for %s' % (bot.name,))

    return wrapper


"""Threading Executor
=====================
"""

from typing import Tuple, AsyncGenerator, Union, Callable, Optional, Dict, \
    List, Iterable, Any, AsyncContextManager
import threading
import math
import queue as stdlib_queue
import importlib
from asyncio import iscoroutinefunction
from queue import Empty
import contextlib
from async_generator import aclosing
import trio
from trio import TASK_STATUS_IGNORED
import outcome
import time
import logging
from tree_config import read_config_from_object, apply_config

from pymoa_remote.executor import NO_CALLBACK
from pymoa_remote.client import Executor
from pymoa_remote.utils import asynccontextmanager

__all__ = (
    'ThreadExecutor', 'SyncThreadExecutor', 'AsyncThreadExecutor',
    'TrioPortal')

class ThreadExecutor(Executor):

    # todo: check that methods cannot be canceled in a weird state

    is_remote = False

    _obj_executor: Dict[
        int,
        List[Union[None, 'SyncThreadExecutor', 'AsyncThreadExecutor']]] = {}

    _sync_executor: Optional['SyncThreadExecutor'] = None

    _async_executor: Optional['AsyncThreadExecutor'] = None

    def __init__(self, **kwargs):
        super(ThreadExecutor, self).__init__(**kwargs)
        self._obj_executor = {}

    async def start_executor(self):
        if self._sync_executor is not None:
            raise TypeError('Executor already started')

        self._sync_executor = SyncThreadExecutor()
        self._async_executor = AsyncThreadExecutor()
        await self._sync_executor.start()
        await self._async_executor.start()

    async def stop_executor(self):
        items = list(self._obj_executor.values())
        self._obj_executor.clear()

        with trio.CancelScope(shield=True):
            for sync_exec, async_exec in items:
                if sync_exec is not None:
                    await sync_exec.stop()
                if async_exec is not None:
                    await async_exec.stop()

            if self._sync_executor is not None:
                await self._sync_executor.stop()
                self._sync_executor = None

            if self._async_executor is not None:
                await self._async_executor.stop()
                self._async_executor = None

    async def execute(
            self, obj, fn: Union[Callable, str], args=(), kwargs=None,
            callback: Union[Callable, str] = None):
        if callback is not None and not isinstance(callback, str):
            callback = callback.__name__

        executors = self._obj_executor[id(obj)]
        if iscoroutinefunction(fn):
            executor = executors[1]
            if executor is None:
                executor = executors[1] = AsyncThreadExecutor()
                await executor.start()
        else:
            executor = executors[0]
            if executor is None:
                executor = executors[0] = SyncThreadExecutor()
                await executor.start()

        return await executor.execute(obj, fn, args, kwargs, callback)

    async def execute_generator(
            self, obj, gen: Union[Callable, str], args=(), kwargs=None,
            callback: Union[Callable, str] = None,
            task_status=TASK_STATUS_IGNORED) -> AsyncGenerator:
        task_status.started()

        if callback is not None and not isinstance(callback, str):
            callback = callback.__name__

        executors = self._obj_executor[id(obj)]
        if iscoroutinefunction(gen):
            executor = executors[1]
            if executor is None:
                executor = executors[1] = AsyncThreadExecutor()
                await executor.start()
        else:
            executor = executors[0]
            if executor is None:
                executor = executors[0] = SyncThreadExecutor()
                await executor.start()

        async with aclosing(
                executor.execute_generator(obj, gen, args, kwargs, callback)
        ) as aiter:
            async for value in aiter:
                yield value

    async def get_echo_clock(self) -> Tuple[int, int, int]:
        return await self._sync_executor.get_echo_clock()

    async def sleep(self, duration=None, deadline=None) -> int:
        return await self._sync_executor.sleep(duration, deadline)

    async def _get_async_echo_clock(self) -> Tuple[int, int, int]:
        return await self._async_executor.get_echo_clock()

    async def remote_import(self, module):
        if not isinstance(module, str):
            module = module.__name__
        importlib.import_module(module)

    async def register_remote_class(self, cls):
        mod = importlib.import_module(cls.__module__)
        if cls.__name__ != cls.__qualname__:
            raise TypeError(f'Cannot register {cls}. Can only register module '
                            f'level classes')
        self.registry.register_class(getattr(mod, cls.__name__))

    async def ensure_remote_instance(
            self, obj, hash_name, *args, auto_register_class=True, **kwargs
    ) -> bool:
        # todo: except parameter whether it uses a lock for execute
        if id(obj) in self._obj_executor:
            return False

        cls = obj.__class__
        if auto_register_class and not self.registry.is_class_registered(
                class_to_register=cls):
            self.registry.register_class(cls)

        self._obj_executor[id(obj)] = [None, None]
        self.registry.add_instance(obj, hash_name)
        return True

    async def delete_remote_instance(self, obj):
        if id(obj) not in self._obj_executor:
            return

        self.registry.delete_instance(obj)
        sync_executor, async_executor = self._obj_executor.pop(id(obj))
        if sync_executor is not None:
            await sync_executor.stop()
        if async_executor is not None:
            await async_executor.stop()

    async def get_remote_objects(self):
        return list(self.registry.hashed_instances.keys())

    async def get_remote_object_config(self, obj: Optional[Any]):
        if obj is not None:
            return read_config_from_object(obj)
        return {h: read_config_from_object(o)
                for h, o in self.registry.hashed_instances.items()}

    async def apply_config_from_remote(self, obj):
        raise NotImplementedError

    async def get_remote_object_property_data(
            self, obj: Any, properties: List[str]) -> dict:
        return {k: getattr(obj, k) for k in properties}

    async def apply_property_data_from_remote(
            self, obj: Any, properties: List[str]):
        raise NotImplementedError

    @asynccontextmanager
    async def get_data_from_remote(
            self, obj, trigger_names: Iterable[str] = (),
            triggered_logged_names: Iterable[str] = (),
            logged_names: Iterable[str] = (),
            initial_properties: Iterable[str] = (),
            task_status=TASK_STATUS_IGNORED
    ) -> AsyncContextManager[AsyncGenerator]:
        raise NotImplementedError

    async def apply_data_from_remote(
            self, obj, trigger_names: Iterable[str] = (),
            triggered_logged_names: Iterable[str] = (),
            logged_names: Iterable[str] = (),
            initial_properties: Iterable[str] = (),
            task_status=TASK_STATUS_IGNORED):
        raise NotImplementedError

    @asynccontextmanager
    async def get_channel_from_remote(
            self, hash_name: str, channel: str,
            task_status=TASK_STATUS_IGNORED
    ) -> AsyncContextManager[AsyncGenerator]:
        raise NotImplementedError

    async def apply_execute_from_remote(
            self, obj, exclude_self=True, task_status=TASK_STATUS_IGNORED):
        raise NotImplementedError

class SyncThreadExecutor:
    """Executor that executes functions in a secondary thread.
    """

    _thread: Optional[threading.Thread] = None

    _exec_queue: Optional[stdlib_queue.Queue] = None

    eof = object()

    _limiter: Optional[trio.Lock] = None

    max_queue_size = 10

    _thread_done_event: Optional[trio.Event] = None

    def __del__(self):
        if self._thread is not None:
            logging.warning(f'stop_executor was not called for "{self}"')

    async def start(self, name='ThreadExecutor'):
        queue = self._exec_queue = stdlib_queue.Queue()
        event = self._thread_done_event = trio.Event()
        self._limiter = trio.Lock()

        thread = self._thread = threading.Thread(
            target=self._worker_thread_fn, name=name,
            args=(queue, event, trio.lowlevel.current_trio_token()))
        thread.start()

    async def stop(self):
        if self._thread is None:
            return

        await self.execute(self.eof, None, callback=NO_CALLBACK)
        await self._thread_done_event.wait()

        self._thread = self._exec_queue = self._limiter = None
        self._thread_done_event = None

    def _worker_thread_fn(self, queue, event, start_token):
        eof = self.eof
        try:
            while True:
                obj, sync_fn, args, kwargs, task, token, gen_queue, \
                    gen_do_eof = queue.get(block=True)

                if obj is eof:
                    try:
                        token.run_sync_soon(trio.lowlevel.reschedule, task)
                    except trio.RunFinishedError:
                        pass
                    return

                if gen_queue is None:
                    # not a generator
                    result = outcome.capture(sync_fn, obj, *args, **kwargs)
                    try:
                        token.run_sync_soon(
                            trio.lowlevel.reschedule, task, result)
                    except trio.RunFinishedError:
                        # The entire run finished, so our particular tasks are
                        # certainly long gone - it must have cancelled.
                        # Continue eating the queue. Currently we cannot cancel
                        pass
                else:
                    # generator
                    send_channel, std_queue = gen_queue

                    def send_nowait():
                        try:
                            send_channel.send_nowait(None)
                        except trio.WouldBlock:
                            pass

                    put = std_queue.put
                    # we send to queue followed by ping on memory channel. We
                    # cannot deadlock, because the ping will result in removing
                    # at least one item, ensuring there will always be at least
                    # one item space free eventually, so put will only block
                    # for a short time until then. And then put will ping again
                    result = outcome.capture(sync_fn, obj, *args, **kwargs)
                    try:
                        # did the gen instantiation fail?
                        if isinstance(result, outcome.Error):
                            put(result, block=True)
                            token.run_sync_soon(send_nowait)
                            continue

                        gen = result.unwrap()  # get the actual gen
                        caught_error = False
                        while gen_do_eof[0] is not eof:
                            result = outcome.capture(next, gen)
                            if isinstance(result, outcome.Error):
                                caught_error = True
                                # stop iteration is signaled with None
                                if isinstance(result.error, StopIteration):
                                    result = None

                                put(result, block=True)
                                token.run_sync_soon(send_nowait)
                                break

                            put(result, block=True)
                            token.run_sync_soon(send_nowait)

                        # we exited because of eof not exception/StopIteration
                        # send either None, or closing error
                        if not caught_error:
                            result = outcome.capture(gen.close)
                            if not isinstance(result, outcome.Error):
                                result = None

                            put(result, block=True)
                            token.run_sync_soon(send_nowait)
                    except trio.RunFinishedError:
                        pass
        finally:
            try:
                start_token.run_sync_soon(event.set)
            except trio.RunFinishedError:
                pass

    @trio.lowlevel.enable_ki_protection
    async def execute(self, obj, sync_fn, args=(), kwargs=None, callback=None):
        """It's guaranteed sequential.
        TODO: if called after stop or thread exited it may block forever.
        """
        async with self._limiter:
            await trio.lowlevel.checkpoint_if_cancelled()
            self._exec_queue.put(
                (obj, sync_fn, args, kwargs or {}, trio.lowlevel.current_task(),
                 trio.lowlevel.current_trio_token(), None, None))

            def abort(raise_cancel):
                # cannot be canceled
                return trio.lowlevel.Abort.FAILED
            res = await trio.lowlevel.wait_task_rescheduled(abort)

            # we must execute under the lock to ensure ordered callbacks by
            # order of thread execution when execute is called from multiple
            # tasks
            if callback is not NO_CALLBACK:
                ThreadExecutor.call_execute_callback(obj, res, callback)
        return res

    async def execute_generator(
            self, obj, sync_gen, args=(), kwargs=None, callback=None
    ) -> AsyncGenerator:
        """Last items may be dropped after getting them.
        TODO: if called after stop is called it may block forever.
        """
        send_channel, receive_channel = trio.open_memory_channel(1)
        # we use this queue for back-pressure
        queue = stdlib_queue.Queue(maxsize=max(self.max_queue_size, 2))
        callback = ThreadExecutor.get_execute_callback_func(obj, callback)
        call_callback = ThreadExecutor.call_execute_callback_func
        do_eof = [None]
        token = trio.lowlevel.current_trio_token()

        async with self._limiter:
            await trio.lowlevel.checkpoint_if_cancelled()

            self._exec_queue.put(
                (obj, sync_gen, args, kwargs or {}, None, token,
                 (send_channel, queue), do_eof))

            result = None
            try:
                # wait until signalled
                async for _ in receive_channel:
                    # get all items from the queue
                    while True:
                        try:
                            result = queue.get(block=False)
                        except Empty:
                            # wait for the next signal
                            break

                        # None means generator is done
                        if result is None:
                            return

                        ret = result.unwrap()

                        call_callback(ret, callback)
                        yield ret
            finally:
                # if we are canceled, notify thread
                do_eof[0] = self.eof

                if result is not None and not isinstance(
                        result, outcome.Error):
                    # we need to wait for last result in case closing returned
                    # an error
                    done = False
                    with trio.CancelScope(shield=True):
                        async for _ in receive_channel:
                            while True:
                                try:
                                    result = queue.get(block=False)
                                except Empty:
                                    break

                                # None means generator is done
                                if result is None:
                                    done = True
                                    break
                                # if not None, unwrap to raise any exception
                                result.unwrap()

                            if done:
                                break

    async def get_echo_clock(self) -> Tuple[int, int, int]:
        def get_time(*args):
            return time.perf_counter_ns()

        ts = time.perf_counter_ns()
        t = await self.execute(None, get_time, callback=NO_CALLBACK)
        return ts, t, time.perf_counter_ns()

    async def sleep(self, duration=None, deadline=None) -> int:
        if duration is not None:
            await trio.sleep(duration)
        elif deadline is not None:
            await trio.sleep(max(0, deadline - time.perf_counter_ns()) / 1e9)
        else:
            raise ValueError('Either deadline or duration must be a number')

        return time.perf_counter_ns()

class AsyncThreadExecutor:
    """Executor that executes async functions in a trio event loop in a
    secondary thread.
    """

    to_thread_portal: Optional['TrioPortal'] = None

    _thread: Optional[threading.Thread] = None

    _limiter: Optional[trio.Lock] = None

    cancel_nursery: Optional[trio.Nursery] = None

    _thread_done_event: Optional[trio.Event] = None

    def __del__(self):
        if self._thread is not None:
            logging.warning(f'stop_executor was not called for "{self}"')

    async def start(self, name='AsyncThreadExecutor'):
        # daemon=True because it might get left behind if we cancel, and in
        # this case shouldn't block process exit.
        event = trio.Event()
        from_thread_portal = TrioPortal()
        self._limiter = trio.Lock()
        done_event = self._thread_done_event = trio.Event()

        thread = self._thread = threading.Thread(
            target=self._worker_thread_fn, name=name,
            args=(event, from_thread_portal, done_event,
                  trio.lowlevel.current_trio_token()))
        thread.start()
        # wait until class variables are set
        await event.wait()

    async def stop(self):
        if not self._thread:
            return

        async def cancel(*args):
            self.cancel_nursery.cancel_scope.cancel()

        await self.execute(None, cancel, callback=NO_CALLBACK)
        await self._thread_done_event.wait()

        self._thread = self._limiter = self.to_thread_portal = None
        self.cancel_nursery = self._thread_done_event = None

    def _worker_thread_fn(
            self, event, from_thread_portal: 'TrioPortal', done_event,
            start_token):
        # This is the function that runs in the worker thread to do the actual
        # work
        async def runner():
            async with trio.open_nursery() as nursery:
                self.to_thread_portal = TrioPortal()
                self.cancel_nursery = nursery
                await from_thread_portal.run_sync(event.set)

                await trio.sleep(math.inf)

        try:
            trio.run(runner)
        finally:
            try:
                start_token.run_sync_soon(done_event.set)
            except trio.RunFinishedError:
                pass

    async def _execute_function(self, obj, async_fn, args, kwargs):
        return await async_fn(obj, *args, **kwargs)

    async def execute(
            self, obj, async_fn, args=(), kwargs=None, callback=None):
        # TODO: if called after stop or thread exited it may block forever.
        async with self._limiter:
            res = await self.to_thread_portal.run(
                self._execute_function, obj, async_fn, args, kwargs or {})

            if callback is not NO_CALLBACK:
                ThreadExecutor.call_execute_callback(obj, res, callback)
        return res

    async def execute_generator(
            self, obj, sync_gen, args=(), kwargs=None, callback=None
    ) -> AsyncGenerator:
        raise NotImplementedError

    async def get_echo_clock(self) -> Tuple[int, int, int]:
        async def get_time(*args):
            return time.perf_counter_ns()

        ts = time.perf_counter_ns()
        t = await self.execute(None, get_time, callback=NO_CALLBACK)
        return ts, t, time.perf_counter_ns()

class TrioPortal(object):
    """Portal for communicating with trio from a different thread.
    """

    trio_token: trio.lowlevel.TrioToken = None

    def __init__(self, trio_token=None):
        if trio_token is None:
            trio_token = trio.lowlevel.current_trio_token()
        self.trio_token = trio_token

    # This is the part that runs in the trio thread
    def _run_cb_async(self, afn, args, task, token):
        @trio.lowlevel.disable_ki_protection
        async def unprotected_afn():
            return await afn(*args)

        async def await_in_trio_thread_task():
            result = await outcome.acapture(unprotected_afn)
            try:
                token.run_sync_soon(trio.lowlevel.reschedule, task, result)
            except trio.RunFinishedError:
                # The entire run finished, so our particular tasks are certainly
                # long gone - it must have cancelled.
                pass

        trio.lowlevel.spawn_system_task(await_in_trio_thread_task, name=afn)

    def _run_sync_cb_async(self, fn, args, task, token):
        @trio.lowlevel.disable_ki_protection
        def unprotected_fn():
            return fn(*args)

        result = outcome.capture(unprotected_fn)
        try:
            token.run_sync_soon(trio.lowlevel.reschedule, task, result)
        except trio.RunFinishedError:
            # The entire run finished, so our particular tasks are certainly
            # long gone - it must have cancelled.
            pass

    @trio.lowlevel.enable_ki_protection
    async def _do_it_async(self, cb, fn, args):
        await trio.lowlevel.checkpoint_if_cancelled()
        self.trio_token.run_sync_soon(
            cb, fn, args, trio.lowlevel.current_task(),
            trio.lowlevel.current_trio_token())

        def abort(raise_cancel):
            return trio.lowlevel.Abort.FAILED
        return await trio.lowlevel.wait_task_rescheduled(abort)

    async def run(self, afn, *args):
        return await self._do_it_async(self._run_cb_async, afn, args)

    async def run_sync(self, fn, *args):
        return await self._do_it_async(self._run_sync_cb_async, fn, args)


import os
from discord.ext import commands
import discord
import logging
import requests
from WeatherBot import Weather
from ToolsBot import Tools
from COVIDBot import COVID
from ReadBot import Read
from voice_generator import creat_WAV

BOT_PREFIX = ('!!')

class JapaneseHelpCommand(commands.DefaultHelpCommand):
    def __init__(self):
        super().__init__()
        self.commands_heading = "コマンド:"
        self.no_category = "その他"
        self.command_attrs["help"] = "コマンド一覧と簡単な説明を表示"

    def get_ending_note(self):
        return (f"各コマンドの説明: {BOT_PREFIX}help <コマンド名>\n"
                f"各カテゴリの説明: {BOT_PREFIX}help <カテゴリ名>\n")

client = commands.Bot(command_prefix=BOT_PREFIX, help_command=JapaneseHelpCommand())
voice_client = None

activity = discord.Activity(name='メインモード', type=discord.ActivityType.playing)

formatter = '%(asctime)s:%(levelname)s:%(name)s: %(message)s'

logging.basicConfig(filename='/var/log/Maindiscord.log', level=logging.DEBUG, format=formatter)
logger = logging.getLogger('discord')

@client.event
async def on_message(message):
    global channelid

    #Botとメッセージの送信者が同じ場合は何もしない
    if client.user == message.author:
        return
    if message.content.startswith("こんにちは"):
        m = "こんにちは！" + message.author.name + "さん！\n"
        await message.channel.send(m)
    if message.content.startswith("にゃーん"):
        msg = "にゃ～ん" + message.author.name + "🐈\n"
        await message.channel.send(msg)

    if message.content == "!!join":
        channelid = message.channel.id
        print(channelid)

    if message.content.startswith(BOT_PREFIX):
        pass

    else:
        if message.guild.voice_client:
            if message.channel.id == channelid:
                print(message.content)
                creat_WAV(message.content)
                source = discord.FFmpegPCMAudio("output.wav")
                message.guild.voice_client.play(source)
            else:
                pass
    await client.process_commands(message)

@client.event
async def on_command_error(ctx, error):
    if isinstance(error, discord.ext.commands.errors.MissingPermissions):
        embed = discord.Embed(title=":x: 失敗 -MissingPermissions", description=f"実行者の必要な権限が無いため実行出来ません。", timestamp=ctx.message.created_at, color=discord.Colour.red())
        embed.set_footer(text="'!!help'でヘルプコマンドを参照してください")
        await ctx.send(embed=embed)
    elif isinstance(error, discord.ext.commands.errors.BotMissingPermissions):
        embed = discord.Embed(title=":x: 失敗 -BotMissingPermissions", description=f"Botの必要な権限が無いため実行出来ません。", timestamp=ctx.message.created_at, color=discord.Colour.red())
        embed.set_footer(text="'!!help'でヘルプコマンドを参照してください")
        await ctx.send(embed=embed)
    elif isinstance(error, discord.ext.commands.errors.CommandNotFound):
        embed = discord.Embed(title=":x: 失敗 -CommandNotFound", description=f"不明なコマンドもしくは現在使用不可能なコマンドです。", timestamp=ctx.message.created_at, color=discord.Colour.red())
        embed.set_footer(text="'!!help'でヘルプコマンドを参照してください")
        await ctx.send(embed=embed)
    elif isinstance(error, discord.ext.commands.errors.MemberNotFound):
        embed = discord.Embed(title=":x: 失敗 -MemberNotFound", description=f"指定されたメンバーが見つかりません。", timestamp=ctx.message.created_at, color=discord.Colour.red())
        embed.set_footer(text="'!!help'でヘルプコマンドを参照してください")
        await ctx.send(embed=embed)
    elif isinstance(error, discord.ext.commands.errors.BadArgument):
        embed = discord.Embed(title=":x: 失敗 -BadArgument", description=f"指定された引数がエラーを起こしているため実行出来ません。", timestamp=ctx.message.created_at, color=discord.Colour.red())
        embed.set_footer(text="'!!help'でヘルプコマンドを参照してください")
        await ctx.send(embed=embed)
    elif isinstance(error, discord.ext.commands.errors.MissingRequiredArgument):
        embed = discord.Embed(title=":x: 失敗 -BadArgument", description=f"指定された引数が足りないため実行出来ません。", timestamp=ctx.message.created_at, color=discord.Colour.red())
        embed.set_footer(text="'!!help'でヘルプコマンドを参照してください")
        await ctx.send(embed=embed)
    else:
        raise error

    logger.error(error)

@client.event
async def on_ready():
    logger.info('ユーザー名：' + client.user.name)
    logger.info('ユーザーid：' + str(client.user.id))
    await client.change_presence(activity=activity)

client.add_cog(Weather(bot=client))
client.add_cog(Tools(bot=client))
client.add_cog(COVID(bot=client))
client.add_cog(Read(bot=client))
client.run(os.environ.get("DISCORD_TOKEN"))


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

def find_difference(string1, string2):
    """ Find the differing character between strings.
        string2 must be one character longer than string1.
    """
    assert len(string1) + 1 == len(string2)

    char_array = list(string2)

    # Iterates through the first string, popping characters out of the second
    # string until there is only 1 character left
    for char in string1:
        ind = char_array.index(char)
        char_array.pop(ind)

    return char_array[0]


import json

import requests

from common_config import *
from utils.img_util import save_sd_img

def text_to_image(prompt, negative_prompt, out_path, steps=SD_DEFAULT_STEPS, batch_size=SD_DEFAULT_BATCH_SIZE):
    url = SD_TXT_TO_IMG_URL
    headers = {
        "accept": "application/json",
        "Content-Type": "application/json"
    }
    data = {
        "prompt": prompt,
        "batch_size": batch_size,
        "n_iter": SD_DEFAULT_N_ITER,
        "steps": steps,
        "width": SD_DEFAULT_WIDTH,
        "height": SD_DEFAULT_HEIGHT,
        "negative_prompt": negative_prompt,
        "cfg_scale": SD_CFG_SCALE,
        "enable_hr": SD_ENABLE_HR,
        "hr_scale": SD_HR_SCALE,
        "hr_upscaler": SD_HR_UPSCALER,
        "denoising_strength": SD_DENOISING_STRENGTH
    }
    res = requests.post(url, headers=headers, data=json.dumps(data))
    save_sd_img(res.json(), out_path)

# if __name__ == '__main__':
#     text_to_image(
#         "Sun WuKong watched in Heaven for more than half a month.,best quality ,masterpiece, illustration, an extremely delicate and beautiful, extremely detailed ,CG ,unity ,8k wallpaper"
#         , NEGATIVE
#         , r"D:\novelai\ai\out.png"
#         , steps=50)


from sklearn.model_selection import train_test_split
from sklearn.svm import SVC
from sklearn.metrics import classification_report, confusion_matrix
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

# drop nan rows
# alternative is to replace with 0 float
# for now we can drop nan rows
def remove_nan(df):
    # is_nan = team_stats.isnull()
    # row_has_nan = is_nan.any(axis=1)
    # rows_with_nan = team_stats[row_has_nan]
    # print(rows_with_nan)
    team_stats = df.dropna()
    return team_stats

"""
    1. Split the data for training and testing using the sklearn.model_selection (train_test_split) module
    2. Use the 'SVC' model to train the model
        - 'fit' is used to train the data
    3. Predict
    4. Display Accuracy
        - use the metric modules
"""
def svm():
    drop_cols = ['result', 'Unnamed: 0']
    df = pd.read_csv('../data/teams_ml_data/combined_team_stats.csv')
    team_stats = remove_nan(df)

    X = team_stats.drop(drop_cols, axis = 1)
    y = team_stats['result']

    X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.20)
    svc_classifier = SVC(kernel='linear')
    svc_classifier.fit(X_train, y_train)

    y_pred = svc_classifier.predict(X_test)
    print(confusion_matrix(y_test, y_pred))
    print(classification_report(y_test, y_pred))

def main():
    svm()

if __name__ == "__main__":
    main()

"""
FIRST RUN THROUGH
[[487  12]
 [ 15 478]]
              precision    recall  f1-score   support

           0       0.97      0.98      0.97       499
           1       0.98      0.97      0.97       493

    accuracy                           0.97       992
   macro avg       0.97      0.97      0.97       992
weighted avg       0.97      0.97      0.97       992
"""


def _slice_i_n(args):
    if not isinstance(args, (list, tuple)):
        raise ValueError(args)
    if len(args) != 2:
        raise ValueError(f"slice filter should be (i, n), is {args}")
    else:
        i, n = map(int, args)
        if n < 2:
            raise ValueError(f"n must be at least 2, is {n}")
        if i < 1 or i > n:
            raise ValueError(f"i must be between 1 and {n}")
        return i, n

class Slice:
    def __init__(self, spec):
        if spec is None:
            self._i = 1
            self._n = 1
        elif isinstance(spec, str):
            self._i, self._n = _slice_i_n(spec.split("/"))
        else:
            self._i, self._n = _slice_i_n(spec)

    def __call__(self, i):
        return 1 + (i % self._n) == self._i


import argparse
import datetime
import logging
import os
import re
import sys
from subprocess import call

import h5py
import numpy as np
import pandas as pd
import tifffile as tf

from tools import stats
from imagej.imagej_pandas import ImagejPandas

class LabHDF5NeXusFile():
    def __init__(self, filename='fabio_data_hochegger_lab.nexus.hdf5', imagesfile=None, fileflag='r'):
        self.filename = filename
        self.imagefile = imagesfile

        # open the HDF5 NeXus file
        if fileflag == 'w':
            with h5py.File(self.filename, fileflag) as f:
                # point to the default data to be plotted
                f.attrs['default'] = 'entry'
                # give the HDF5 root some more attributes
                f.attrs['file_name'] = self.filename
                timestamp = datetime.datetime.now().isoformat()
                f.attrs['file_time'] = timestamp
                f.attrs['creator'] = 'fabio@hochegger.lab'
                f.attrs['NeXus_version'] = '4.3.0'
                f.attrs['HDF5_Version'] = h5py.version.hdf5_version
                f.attrs['h5py_version'] = h5py.version.version

    def add_experiment(self, group, experiment_tag, timestamp=None):
        gr = '%s/%s' % (group, experiment_tag)
        timestamp = timestamp if timestamp is not None else datetime.datetime.now().isoformat()

        with h5py.File(self.filename, 'a') as f:
            if gr in f: del f[gr]

            # create the NXentry experiment group
            nxentry = f.create_group(gr)
            nxentry.attrs['NX_class'] = 'NXentry'
            nxentry.attrs['datetime'] = timestamp
            nxentry.attrs['default'] = 'processed'

            nxentry_raw = nxentry.create_group('raw')
            nxentry_raw.attrs['NX_class'] = 'NXgroup'
            nxentry_meas = nxentry.create_group('measurements')
            nxentry_meas.attrs['NX_class'] = 'NXgroup'
            nxentry_sel = nxentry.create_group('selection')
            nxentry_sel.attrs['NX_class'] = 'NXgroup'
            nxentry_proc = nxentry.create_group('processed')
            nxentry_proc.attrs['NX_class'] = 'NXgroup'

        with h5py.File(self.imagefile, 'a') as i:
            rawgr = '%s/%s/raw' % (group, experiment_tag)
            # create the NXentry experiment group
            nxentry = i.require_group(rawgr)
            nxentry.attrs['NX_class'] = 'NXentry'
            nxentry.attrs['datetime'] = timestamp
            i[rawgr].attrs['NX_class'] = 'NXgroup'

    def add_tiff_sequence(self, tiffpath, experiment_tag, run):
        _grp = '%s/%s/raw' % (experiment_tag, run)
        # open the HDF5 NeXus file
        if self.imagefile is None:
            f = h5py.File(self.filename, 'a')
        else:
            f = h5py.File(self.imagefile, 'a')

        # update the NXentry group
        nxdata = f[_grp]
        nxdata.attrs['NX_class'] = 'NXdata'
        nxdata.attrs['signal'] = 'Y'  # Y axis of default plot
        nxdata.attrs['axes'] = 'X'  # X axis of default plot
        nxdata.attrs['units'] = 'um'  # default units

        nframes = len(nxdata.items())
        if nframes == 0:
            with tf.TiffFile(tiffpath, fastij=True) as tif:
                if tif.is_imagej is not None:
                    sizeT, channels = tif.pages[0].imagej_tags.frames, tif.pages[0].imagej_tags.channels
                    sizeZ, sizeX, sizeY = 1, tif.pages[0].image_width, tif.pages[0].image_length
                    logging.info('N of frames=%d channels=%d, sizeZ=%d, sizeX=%d, sizeY=%d' % \
                                 (sizeT, channels, sizeZ, sizeX, sizeY))

                    res = 'n/a'
                    if tif.pages[0].resolution_unit == 'centimeter':
                        # asuming square pixels
                        xr = tif.pages[0].x_resolution
                        res = float(xr[0]) / float(xr[1])  # pixels per cm
                        res = res / 1e4  # pixels per um
                    elif tif.pages[0].imagej_tags.unit == 'micron':
                        # asuming square pixels
                        xr = tif.pages[0].x_resolution
                        res = float(xr[0]) / float(xr[1])  # pixels per um

                    if sizeT > 1:
                        p1a = tif.pages[0].asarray().reshape([sizeT, channels, sizeX, sizeY])
                        for i in range(sizeT):
                            # create a NXentry frame group
                            nxframe = nxdata.create_group('%03d' % i)
                            nxframe.attrs['units'] = 'um'
                            nxframe.attrs['resolution'] = res
                            nxframe.attrs['long_name'] = 'image um (micrometers)'  # suggested X axis plot label

                            # save XY data
                            ch1 = nxframe.create_dataset('channel-1', data=p1a[i][0], dtype=np.uint16)
                            ch2 = nxframe.create_dataset('channel-2', data=p1a[i][1], dtype=np.uint16)
                            ch3 = nxframe.create_dataset('channel-3', data=p1a[i][2], dtype=np.uint16)
                            for ch in [ch1, ch2, ch3]:
                                ch.attrs['CLASS'] = np.string_('IMAGE')
                                ch.attrs['IMAGE_SUBCLASS'] = np.string_('IMAGE_GRAYSCALE')
                                ch.attrs['IMAGE_VERSION'] = np.string_('1.2')

        f.close()

        if self.imagefile is not None and nframes == 0:
            with h5py.File(self.filename, 'a') as f:
                del f[_grp]
                f[_grp] = h5py.ExternalLink(self.imagefile, _grp)

    def add_measurements(self, csvpath, experiment_tag, run):
        dfc = ImagejPandas(csvpath)
        with h5py.File(self.filename, 'a') as f:
            nxmeas = f['%s/%s/measurements' % (experiment_tag, run)]

            dfnt = dfc.df_nuclei.set_index('Frame').sort_index()
            for (nuc_id), filt_nuc_df in dfnt.groupby('Nuclei'):
                nxnucl = nxmeas.create_group('nuclei/N%02d' % nuc_id)
                nxnucl.attrs['NX_class'] = 'NXdata'
                nxnucl.attrs['Nuclei'] = 'N%02d' % nuc_id
                nx = filt_nuc_df['NuclX']
                ny = filt_nuc_df['NuclY']
                fn = filt_nuc_df.reset_index()
                nxnucl.create_dataset('pos', data=fn[['Frame', 'NuclX', 'NuclY']], dtype=nx.dtype)
                nxnucl.create_dataset('frame', data=fn['Frame'], dtype=nx.dtype)
                nxnucl.create_dataset('sample_x', data=nx, dtype=nx.dtype)
                nxnucl.create_dataset('sample_y', data=ny, dtype=ny.dtype)

            dfct = dfc.df_centrosome.set_index('Frame').sort_index()

            for (centr_id), filt_centr_df in dfct.groupby('Centrosome'):
                nxcid = nxmeas.create_group('centrosomes/C%03d' % centr_id)
                nxcid.attrs['NX_class'] = 'NXdata'
                cx = filt_centr_df['CentX']
                cy = filt_centr_df['CentY']
                cn = filt_centr_df.reset_index()
                nxcid.create_dataset('pos', data=cn[['Frame', 'CentX', 'CentY']], dtype=cx.dtype)
                nxcid.create_dataset('frame', data=cn['Frame'], dtype=cx.dtype)
                nxcid.create_dataset('sample_x', data=cx, dtype=cx.dtype)
                nxcid.create_dataset('sample_y', data=cy, dtype=cy.dtype)

            visitedCentrosomes = []
            for _, filt_centr_df in dfct.groupby('Centrosome'):
                nuc_id = filt_centr_df['Nuclei'].unique()[0]
                centrosomesOfNuclei = dfct[dfct['Nuclei'] == nuc_id].groupby('Centrosome')
                if len(centrosomesOfNuclei.groups) >= 2:
                    for i, ((centr_id), filt_centr_df) in enumerate(centrosomesOfNuclei):
                        if centr_id not in visitedCentrosomes:
                            visitedCentrosomes.append(centr_id)
                            self.associate_centrosome_with_nuclei(centr_id, nuc_id, experiment_tag, run, i % 2)
        dfc.merged_df.to_hdf(self.filename, '%s/%s/measurements/pandas_dataframe' % (experiment_tag, run), mode='r+')
        dfc.df_nuclei.to_hdf(self.filename, '%s/%s/measurements/nuclei_dataframe' % (experiment_tag, run), mode='r+')
        self.process_selection_for_run(experiment_tag, run)

    @property
    def dataframe(self):
        df_out = pd.DataFrame()
        with h5py.File(self.filename, 'r') as f:
            for experiment_tag in f:
                for run in f['%s' % experiment_tag]:
                    if 'pandas_dataframe' in f['%s/%s/processed' % (experiment_tag, run)]:
                        selection_key = '%s/%s/processed/pandas_dataframe' % (experiment_tag, run)
                        df = pd.read_hdf(self.filename, key=selection_key, mode='r')
                        df['condition'] = experiment_tag
                        df['run'] = run
                        df_out = df_out.append(df, sort=True)
        df_out = stats.reconstruct_time(df_out)
        df_out.loc[:, ['Frame', 'Centrosome', 'Nuclei']] = df_out[['Frame', 'Centrosome', 'Nuclei']].astype('int32')
        df_out.loc[:, 'Time'] = df_out['Time'].astype('float64')

        return df_out

    @property
    def mask(self):
        df_msk = pd.DataFrame()
        with h5py.File(self.filename, 'r') as f:
            for experiment_tag in f:
                for run in f['%s' % experiment_tag]:
                    if 'pandas_masks' in f['%s/%s/processed' % (experiment_tag, run)]:
                        selection_key = '%s/%s/processed/pandas_masks' % (experiment_tag, run)
                        msk = pd.read_hdf(self.filename, key=selection_key, mode='r')
                        msk.loc[':,condition'] = experiment_tag
                        msk.loc[:, 'run'] = run
                        df_msk = df_msk.append(msk, sort=True)
        return stats.reconstruct_time(df_msk)

    def process_selection_for_run(self, experiment_tag, run):
        with h5py.File(self.filename, 'r') as f:
            nuclei_list = list(f['%s/%s/selection' % (experiment_tag, run)].keys())
            logging.debug(
                'for %s %s there are %d nuclei: %s' % (experiment_tag, run, len(nuclei_list), str(nuclei_list)))
            # don't keep processing if there's nothing to do
            if len(nuclei_list) == 0: return

        merge_key = '%s/%s/measurements/pandas_dataframe' % (experiment_tag, run)
        nuclei_key = '%s/%s/measurements/nuclei_dataframe' % (experiment_tag, run)
        pdhdf_measured = pd.read_hdf(self.filename, key=merge_key, mode='r')
        pdhdf_nuclei = pd.read_hdf(self.filename, key=nuclei_key, mode='r')

        # update centrosome nuclei from selection
        centrosomes_of_nuclei_a = centrosomes_of_nuclei_b = None
        centrosomes_all = list()
        with h5py.File(self.filename, 'r') as f:
            for nuclei_str in nuclei_list:
                if nuclei_str == 'pandas_dataframe' or nuclei_str == 'pandas_masks': continue
                nuclei_id = int(nuclei_str[1:])
                sel_str = '%s/%s/selection/%s' % (experiment_tag, run, nuclei_str)
                centrosomes_of_nuclei_a = [int(c[1:]) for c in f['%s/A' % (sel_str)].keys()]
                centrosomes_of_nuclei_b = [int(c[1:]) for c in f['%s/B' % (sel_str)].keys()]
                for centr_id in centrosomes_of_nuclei_a + centrosomes_of_nuclei_b:
                    pdhdf_measured.loc[pdhdf_measured['Centrosome'] == centr_id, 'Nuclei'] = nuclei_id
                # tag centrosomes with the label given in the GUI
                for centr_id in centrosomes_of_nuclei_a:
                    pdhdf_measured.loc[pdhdf_measured['Centrosome'] == centr_id, 'CentrLabel'] = 'A'
                for centr_id in centrosomes_of_nuclei_b:
                    pdhdf_measured.loc[pdhdf_measured['Centrosome'] == centr_id, 'CentrLabel'] = 'B'

                centrosomes_all.extend(centrosomes_of_nuclei_a + centrosomes_of_nuclei_b)

        # re-merge with nuclei data
        pdhdf_measured.drop(['NuclX', 'NuclY', 'NuclBound'], axis=1, inplace=True)
        pdhdf_measured = pdhdf_measured[pdhdf_measured['Centrosome'].isin(centrosomes_all)]
        df_merge = pdhdf_measured.merge(pdhdf_nuclei, how='left')

        # merge with cell boundary data
        with h5py.File(self.filename, 'r') as f:
            if 'boundary' in f['%s/%s/processed' % (experiment_tag, run)]:
                df_cell = pd.read_hdf(self.filename, key='%s/%s/processed/boundary' % (experiment_tag, run))
                df_cell = df_cell.loc[~df_cell['CellBound'].isnull(),
                                      set(ImagejPandas.MASK_INDEX + ['CellX', 'CellY', 'CellBound',
                                                                     'DistCell', 'SpdCell', 'AccCell'])]

                if 'CellBound' in df_merge.columns and not df_cell.empty:
                    logging.info('clearing CellBound')
                    df_merge.drop(['CellX', 'CellY', 'CellBound'], axis=1, inplace=True)
                df_merge = df_merge.merge(df_cell, how='left')

        df_merge['condition'] = experiment_tag
        df_merge['run'] = run
        logging.debug('nuclei to process: ' + str(df_merge.groupby(ImagejPandas.NUCLEI_INDIV_INDEX).size()))

        try:
            with h5py.File(self.filename, 'r+') as f:
                fproc = f['%s/%s/processed' % (experiment_tag, run)]
                if 'pandas_dataframe' in fproc: del fproc['pandas_dataframe']
                if 'pandas_masks' in fproc: del fproc['pandas_masks']

            df_merge.dropna(how='all', inplace=True)
            df_merge = df_merge[~df_merge['CentrLabel'].isnull()]
            df_interpolated, imask = ImagejPandas.interpolate_data(df_merge)
            df_interpolated = ImagejPandas.vel_acc_nuclei(df_interpolated)
            proc_df = ImagejPandas.dist_vel_acc_centrosomes(df_interpolated)

            maxframe1 = proc_df.loc[proc_df['CentrLabel'] == 'A', 'Frame'].max()
            maxframedc = proc_df['Frame'].max()
            minframe1 = min(maxframe1, maxframedc)

            idx1 = (proc_df['CentrLabel'] == 'A') & (proc_df['Frame'] <= minframe1)
            proc_df.loc[idx1, 'SpeedCentr'] *= -1
            proc_df.loc[idx1, 'AccCentr'] *= -1

            # process interpolated data mask
            mask_df = imask[imask['Nuclei'] > 0]
            mi = mask_df.set_index(ImagejPandas.MASK_INDEX).sort_index()
            mu = mi.unstack('CentrLabel')
            msk = mu.loc[:, ['CentX', 'CentY']].all(axis=1)
            for key in ['Dist', 'Speed', 'Acc']:
                mu.loc[:, (key, 'A')] = mu.loc[:, ('CentX', 'A')]
                mu.loc[:, (key, 'B')] = mu.loc[:, ('CentX', 'B')]
            for key in ['DistCentr', 'SpeedCentr', 'AccCentr']:
                mu.loc[:, (key, 'A')] = msk
            mask_df = mu.stack().reset_index()

            proc_df.to_hdf(self.filename, key='%s/%s/processed/pandas_dataframe' % (experiment_tag, run), mode='r+')
            mask_df.to_hdf(self.filename, key='%s/%s/processed/pandas_masks' % (experiment_tag, run), mode='r+')
        except Exception as e:
            exc_type, exc_obj, exc_tb = sys.exc_info()
            logging.warning('Problem processing %s-%s in line %d of hdf5_nexus.py:\r\n%s' % (
                experiment_tag, run, exc_tb.tb_lineno, e))

    def associate_centrosome_with_nuclei(self, centr_id, nuc_id, experiment_tag, run, centrosome_group=0):
        with h5py.File(self.filename, 'a') as f:
            # link centrosome to current nuclei selection
            source_cpos_addr = '%s/%s/measurements/centrosomes/C%03d/pos' % (experiment_tag, run, centr_id)
            source_npos_addr = '%s/%s/measurements/nuclei/N%02d/pos' % (experiment_tag, run, nuc_id)
            nxcpos = f[source_cpos_addr]

            target_addr = '%s/%s/selection/N%02d' % (experiment_tag, run, nuc_id)
            if source_npos_addr in f:
                if target_addr not in f:
                    nxnuc_ = f.create_group(target_addr)
                    nxnuc_.create_group('A')
                    nxnuc_.create_group('B')
                    nxnpos = f[source_npos_addr]
                    nxnuc_['pos'] = nxnpos

                cstr = 'A' if centrosome_group == 0 else 'B'
                nxnuc_ = f['%s/%s' % (target_addr, cstr)]
                nxnuc_['C%03d' % centr_id] = nxcpos

    def clear_associations(self, experiment_tag, run):
        with h5py.File(self.filename, 'a') as f:
            fsel = f['%s/%s/selection' % (experiment_tag, run)]
            for o in fsel:
                del fsel[o]

    def delete_association(self, of_centrosome, with_nuclei, experiment_tag, run):
        with h5py.File(self.filename, 'a') as f:
            centosomesA = f['%s/%s/selection/N%02d/A' % (experiment_tag, run, with_nuclei)]
            centosomesB = f['%s/%s/selection/N%02d/B' % (experiment_tag, run, with_nuclei)]
            if 'C%03d' % of_centrosome in centosomesA:
                del centosomesA['C%03d' % of_centrosome]
            if 'C%03d' % of_centrosome in centosomesB:
                del centosomesB['C%03d' % of_centrosome]

            with h5py.File(self.filename, 'a') as f:
                fproc = f['%s/%s/processed' % (experiment_tag, run)]
                df_key = '%s/%s/processed/pandas_dataframe' % (experiment_tag, run)
                msk_key = '%s/%s/processed/pandas_masks' % (experiment_tag, run)
                _newdf = _newmsk = None
                if 'pandas_dataframe' in fproc:
                    _newdf = pd.read_hdf(self.filename, key=df_key, mode='r')
                    del fproc['pandas_dataframe']
                if _newdf is not None:
                    _idx = (_newdf['Centrosome'] == of_centrosome) & \
                           (_newdf['Nuclei'] == with_nuclei)
                    _newdf[~_idx].to_hdf(self.filename, key=df_key, mode='r+')
                if 'pandas_masks' in fproc:
                    _newmsk = pd.read_hdf(self.filename, key=msk_key, mode='r')
                    del fproc['pandas_masks']
                if _newmsk is not None:
                    _idx = (_newmsk['Centrosome'] == of_centrosome) & \
                           (_newmsk['Nuclei'] == with_nuclei)
                    _newmsk[~_idx].to_hdf(self.filename, key=msk_key, mode='r+')

    def move_association(self, of_centrosome, from_nuclei, toNuclei, centrosome_group, experiment_tag, run):
        self.delete_association(of_centrosome, from_nuclei, experiment_tag, run)
        self.associate_centrosome_with_nuclei(of_centrosome, toNuclei, experiment_tag, run)

    def is_centrosome_associated(self, centrosome, experiment_tag, run):
        with h5py.File(self.filename, 'r') as f:
            nuclei_list = f['%s/%s/measurements/nuclei' % (experiment_tag, run)]
            sel = f['%s/%s/selection' % (experiment_tag, run)]
            for nuclei in nuclei_list:
                if nuclei in sel:
                    nuc = sel[nuclei]
                    if centrosome in nuc['A'] or centrosome in nuc['B']:
                        return True
        return False

def move_images(filefrom, fileto):
    src = h5py.File(filefrom, 'a')
    dst = h5py.File(fileto, 'a')
    for cond in src.keys():
        for run in src[cond].keys():
            _grp = '%s/%s/raw' % (cond, run)
            if isinstance(src[_grp], h5py.SoftLink):
                logging.debug(_grp, 'group already a soft link')
            if isinstance(src[_grp], h5py.HardLink):
                logging.debug(_grp, 'group already a hard link')
            if isinstance(src[_grp], h5py.Group):
                # Get the name of the parent for the group we want to copy
                group_path = src[_grp].parent.name
                # Check that this group exists in the destination file; if it doesn't, create it
                # This will create the parents too, if they don't exist
                group_id = dst.require_group(group_path)
                # Copy src -> dst
                if _grp not in dst:
                    logging.debug(_grp, 'copying raw images')
                    src.copy(_grp, group_id, name='raw')
                del src[_grp]
                src[_grp] = h5py.ExternalLink(fileto, _grp)
    src.close()
    dst.close()

def process_dir(path, hdf5f):
    condition = os.path.abspath(args.input).split('/')[-1]

    for root, directories, filenames in os.walk(os.path.join(path, 'input')):
        for filename in filenames:
            ext = filename.split('.')[-1]
            if ext == 'tif':
                joinf = os.path.join(root, filename)
                logging.info('--------------------------------------------------------------')
                groups = re.search('^(.+)-(.+).tif$', filename).groups()
                run_id = groups[1]
                run_str = 'run_%s' % run_id
                centdata = os.path.join(path, 'data', 'run-%s-table.csv' % run_id)
                nucldata = os.path.join(path, 'data', 'run-%s-nuclei.csv' % run_id)

                if os.path.isfile(centdata) and os.path.isfile(nucldata) and os.path.isfile(joinf):
                    logging.info('adding raw file: %s' % joinf)
                    hdf5.add_experiment(condition, run_str)
                    logging.info('adding tiff:', joinf)
                    hdf5f.add_tiff_sequence(joinf, condition, run_str)
                    logging.info('adding data file: %s' % centdata)
                    hdf5f.add_measurements(centdata, condition, run_str)

if __name__ == '__main__':
    # process input arguments
    parser = argparse.ArgumentParser(
        description='Creates an HDF5 file for experiments storage.')
    parser.add_argument('input', metavar='I', type=str, help='input directory where the files are')
    args = parser.parse_args()

    # Create hdf5 file if it doesn't exist
    hdf5 = LabHDF5NeXusFile(filename='out/centrosomes.nexus.hdf5',
                            imagesfile='out/centrosomes-images.nexus.hdf5', fileflag='a')
    try:
        process_dir(args.input, hdf5)
        move_images('out/centrosomes.nexus.hdf5', 'out/centrosomes-images.nexus.hdf5')

        logging.info('--------------------------------------------------------------')
        logging.info('shrinking file size...')
        call('h5repack out/centrosomes.nexus.hdf5 out/repack.hdf5', shell=True)
        os.remove('out/centrosomes.nexus.hdf5')
        os.rename('out/repack.hdf5', 'out/centrosomes.nexus.hdf5')
        call('h5repack out/centrosomes-images.nexus.hdf5 out/repack.hdf5', shell=True)
        os.remove('out/centrosomes-images.nexus.hdf5')
        os.rename('out/repack.hdf5', 'out/centrosomes-images.nexus.hdf5')
    finally:
        logging.info('finished.')


"""
What is the value of the first triangle number to have over five hundred divisors?
"""
from utils import pfactors, n_divisors
from collections import defaultdict

def get_factors_quick(num, cache):
    if cache.has_key(num):
        return cache[num]
    else:
        factors = pfactors(num)
        cache[num] = factors
        return factors

def first_triangle_ndivisors_gt(min_divisors):
    tri = lambda x: x*(x+1)/2

    ndivisors = 1
    curr = 1
    factors_cache = {}
    while ndivisors <= min_divisors:
        curr += 1

        if curr % 2 == 0:
            prime_factors = (get_factors_quick(curr/2, factors_cache) +
                             get_factors_quick(curr+1, factors_cache))
        else:
            prime_factors = (get_factors_quick((curr+1)/2, factors_cache) +
                             get_factors_quick(curr, factors_cache))

        factors_cache[tri(curr)] = prime_factors

        ndivisors = n_divisors(prime_factors)

    return tri(curr)

def p12():
    return first_triangle_ndivisors_gt(500)


class Stack :

    def __init__(self) :
        self.value = []

    def push(self,value) :
        self.value.append(value)

    def pop(self) :
        return self.value.pop(-1)

    def size(self) :
        return len(self.value)

    def isEmpty(self) :
        return len(self.value) == 0

    def __str__(self) :
        return "".join(self.value)

class Queue:

    def __init__(self) :
        self.item = []

    def enQueue(self,value) :
        self.item.append(value)

    def deQueue(self) :
        return self.item.pop(0)

    def isEmpty(self) :
        return len(self.item) == 0

    def size(self) :
        return len(self.item)

    def __str__(self) :
        return "".join(self.item)

def checkbomb(s,bomb,item,str):
    bomb1 = s.pop()
    bomb2 = s.pop()
    countbomb = 0
    if bomb == bomb1 and bomb1 == bomb2:
        countbomb += 1
        if str == "M":
            item.enQueue(bomb)
        else:
            if not item.isEmpty():
                temp = item.deQueue()
                if temp == bomb1 and temp == bomb:
                    s.push(bomb2)
                else:
                    s.push(bomb2)
                    s.push(bomb1)
                    s.push(temp)
                    s.push(bomb)
                    countbomb -= 1
    else:
        s.push(bomb2)
        s.push(bomb1)
        s.push(bomb)
    return countbomb

Smirror= Stack()
Qmirror = Queue()
Snormal = Stack()
Qnormal = Queue()
inp = input("Enter Input (Normal, Mirror) : ").split(" ")
mirrorbomb = 0
normalbomb = 0
fail = 0
item = Queue()
for x in inp[1][::-1]:
    if Smirror.size() < 2:
        Smirror.push(x)
    else:
        mirrorbomb += checkbomb(Smirror,x,item,"M")
for x in inp[0]:
    if Snormal.size() < 2:
        Snormal.push(x)
    else:
        temp = normalbomb
        useitem = item.size()
        normalbomb += checkbomb(Snormal,x,item,"N")
        if temp != normalbomb and useitem != 0:
            fail += 1
            normalbomb -= 1

print("NORMAL :")
print(Snormal.size())
if Snormal.isEmpty():
    print("Empty")
else:
    for x in range(Snormal.size()):
        Qnormal.enQueue(Snormal.pop())
    print(Qnormal)
print(str(normalbomb)+" Explosive(s) ! ! ! (NORMAL)")
if fail != 0:
    print("Failed Interrupted "+str(fail)+" Bomb(s)")
print("------------MIRROR------------")
print(": RORRIM")
print(Smirror.size())
if Smirror.isEmpty():
    print("ytpmE")
else:
    for x in range(Smirror.size()):
        Qmirror.enQueue(Smirror.pop())
    print(Qmirror)
print("(RORRIM) ! ! ! (s)evisolpxE "+str(mirrorbomb))
# print(item)


from biosimulators_utils.report.data_model import VariableResults
from biosimulators_utils.sedml.data_model import Variable  # noqa: F401
from biosimulators_utils.utils.core import validate_str_value, parse_value
import cobra  # noqa: F401
import libsbml
import numpy

__all__ = [
    'get_objective_sbml_fbc_ids',
    'set_simulation_method_arg',
    'apply_variables_to_simulation_method_args',
    'validate_variables',
    'get_results_paths_for_variables',
    'get_results_of_variables',
]

def get_objective_sbml_fbc_ids(model_source):
    """ Get the SBML-FBC id of the active objective

    Args:
        model_source (:obj:`str`): path to model

    Returns:
        :obj:`tuple`:

            * :obj:`str`: SBML-FBC id of the active objective
            * :obj:`list` of :obj:`str`: SBML-FBC id of the objectives
    """
    doc = libsbml.readSBMLFromFile(model_source)
    model = doc.getModel()
    model_fbc = model.getPlugin("fbc")
    return (
        model_fbc.getListOfObjectives().getActiveObjective(),
        [objective.getId() for objective in model_fbc.getListOfObjectives()],
    )

def set_simulation_method_arg(method_props, argument_change, model, model_method_kw_args):
    """ Set the value of an argument of a simulation method based on a SED
    algorithm parameter change

    Args:
        method_props (:obj:`dict`): properties of the simulation method
        argument_change (:obj:`AlgorithmParameterChange`): algorithm parameter change
        model (:obj:`cobra.core.model.Model`)
        model_method_kw_args (:obj:`dict`): keyword arguments for the simulation method
            for the model

    Raises:
        :obj:`NotImplementedError`: if the simulation method doesn't support the parameter
        :obj:`ValueError`: if the new value is not a valid value of the parameter
    """
    parameter_kisao_id = argument_change.kisao_id
    parameter = method_props['parameters'].get(parameter_kisao_id, None)
    if parameter is None:
        msg = "".join([
            "{} ({}) does not support parameter `{}`. ".format(
                method_props['name'], method_props['kisao_id'], argument_change.kisao_id),
            "The parameters of {} must have one of the following KiSAO ids:\n  - {}".format(
                method_props['name'],
                '\n  - '.join(
                    '{} ({}): {}'.format(kisao_id, parameter['name'], parameter['description'])
                    for kisao_id, parameter in method_props['parameters'].items())),
        ])
        raise NotImplementedError(msg)

    value = argument_change.new_value
    if not validate_str_value(value, parameter['type']):
        msg = "`{}` is not a valid value for parameter {} ({}) of {} ({})".format(
            value, parameter['name'], parameter_kisao_id,
            method_props['name'], method_props['kisao_id'])
        raise ValueError(msg)
    enum = parameter.get('enum', None)
    if enum:
        if value.lower() not in enum.__members__:
            msg = ("`{}` is not a valid value for parameter {} ({}) of {} ({}). "
                   "The value of {} must be one of the following:\n  - {}").format(
                value, parameter['name'], parameter_kisao_id,
                method_props['name'], method_props['kisao_id'],
                method_props['name'],
                '\n  - '.join(sorted('`' + value + '`' for value in enum.__members__.keys())))
            raise ValueError(msg)

    parsed_value = parse_value(value, parameter['type'])
    if enum:
        parsed_value = enum[value.lower()].value

    if 'alg_arg' in parameter:
        model_method_kw_args[parameter['alg_arg']] = parsed_value
    else:
        setattr(model, parameter['model_arg'], parsed_value)

def apply_variables_to_simulation_method_args(target_x_paths_ids, method_props, variables, model_method_kw_args):
    """ Encode the desired output variables into arguments to simulation methods

    Args:
        target_x_paths_ids (:obj:`dict` of :obj:`str` to :obj:`str`): dictionary that maps each XPath to the
            SBML id of the corresponding model object
        method_props (:obj:`dict`): properties of the simulation method
        variables (:obj:`list` of :obj:`Variable`): variables that should be recorded
        model_method_kw_args (:obj:`dict`): keyword arguments for the simulation method
            for the model
    """
    if method_props['kisao_id'] == 'KISAO_0000526':
        reaction_list = set()
        for variable in variables:
            reaction_id = target_x_paths_ids[variable.target]
            reaction_list.add(reaction_id[2:] if reaction_id.startswith('R_') else reaction_id)
        model_method_kw_args['reaction_list'] = sorted(reaction_list)

def validate_variables(model, active_objective_sbml_fbc_id, objective_sbml_fbc_ids,
                       method, variables, target_sbml_id_map, target_sbml_fbc_id_map, sbml_fbc_uri):
    """ Validate the desired output variables of a simulation

    Args:
        model (:obj:`cobra.core.model.Model`): model
        active_objective_sbml_fbc_id (:obj:`str`): SBML-FBC id of the active objective
        objective_sbml_fbc_ids (:obj:`list` of :obj:`str`): SBML-FBC id of the objectives
        method (:obj:`dict`): properties of desired simulation method
        variables (:obj:`list` of :obj:`Variable`): variables that should be recorded
        target_sbml_id_map (:obj:`dict` of :obj:`str` to :obj:`str`): dictionary that maps each XPath to the
            SBML id of the corresponding model object
        target_sbml_fbc_id_map (:obj:`dict` of :obj:`str` to :obj:`str`): dictionary that maps each XPath to the
            SBML-FBC id of the corresponding model object
        sbml_fbc_uri (:obj:`str`): URI for SBML FBC package
    """
    possible_target_results_path_map = set()
    for variable_pattern in method['variables']:
        for sbml_id, fbc_id, attr, result_type, result_name in variable_pattern['get_target_results_paths'](
                model, active_objective_sbml_fbc_id, objective_sbml_fbc_ids):
            possible_target_results_path_map.add((sbml_id, fbc_id, attr))

    invalid_symbols = set()
    invalid_targets = set()
    for variable in variables:
        if variable.symbol:
            invalid_symbols.add(variable.symbol)

        else:
            valid = True

            target = variable.target
            variable_target_id = target_sbml_id_map.get(target, None)
            variable_target_fbc_id = target_sbml_fbc_id_map.get(target, None)
            target_attr = target.partition('/@')[2] or None
            if target_attr:
                target_ns, _, target_attr = target_attr.rpartition(':')
                if target_ns and variable.target_namespaces.get(target_ns, None) != sbml_fbc_uri:
                    valid = False

            if not valid or (variable_target_id, variable_target_fbc_id, target_attr) not in possible_target_results_path_map:
                invalid_targets.add(variable.target)

    if invalid_symbols:
        raise NotImplementedError("{} ({}) doesn't support variables with symbols".format(
            method['name'], method['kisao_id']))

    if invalid_targets:
        msg = (
            "{} ({}) doesn't support variables with the following target XPaths:\n  - {}\n\n"
            "The targets of variables should match one of the following patterns of XPaths:\n  - {}"
        ).format(
            method['name'], method['kisao_id'],
            '\n  - '.join(sorted('`' + target + '`' for target in invalid_targets)),
            '\n  - '.join(sorted('{}: `{}`'.format(
                variable_pattern['description'], variable_pattern['target'])
                for variable_pattern in method['variables']))
        )
        raise ValueError(msg)

def get_results_paths_for_variables(model, active_objective_sbml_fbc_id, objective_sbml_fbc_ids,
                                    method, variables, target_sbml_id_map, target_sbml_fbc_id_map):
    """ Get the path to results for the desired variables

    Args:
        model (:obj:`cobra.core.model.Model`): model
        active_objective_sbml_fbc_id (:obj:`str`): SBML-FBC id of the active objective
        objective_sbml_fbc_ids (:obj:`list` of :obj:`str`): SBML-FBC id of the objectives
        method (:obj:`dict`): properties of desired simulation method
        variables (:obj:`list` of :obj:`Variable`): variables that should be recorded
        target_sbml_id_map (:obj:`dict` of :obj:`str` to :obj:`str`): dictionary that maps each XPath to the
            SBML id of the corresponding model object
        target_sbml_fbc_id_map (:obj:`dict` of :obj:`str` to :obj:`str`): dictionary that maps each XPath to the
            SBML-FBC id of the corresponding model object

    Returns:
        :obj:`dict`: path to results of desired variables
    """
    possible_target_results_path_map = {}
    for variable_pattern in method['variables']:
        for sbml_id, fbc_id, attr, result_type, result_name in variable_pattern['get_target_results_paths'](
                model, active_objective_sbml_fbc_id, objective_sbml_fbc_ids):
            possible_target_results_path_map[(sbml_id, fbc_id, attr)] = (result_type, result_name)

    target_results_path_map = {}
    for variable in variables:
        target = variable.target
        variable_target_id = target_sbml_id_map[target]
        variable_target_fbc_id = target_sbml_fbc_id_map[target]
        target_attr = target.partition('/@')[2].rpartition(':')[2] or None
        target_results_path_map[variable.target] = possible_target_results_path_map[(
            variable_target_id, variable_target_fbc_id, target_attr)]

    return target_results_path_map

def get_results_of_variables(target_results_path_map, variables, solution):
    """ Get the results of the desired variables

    Args:
        target_results_path_map (:obj:`dict`): path to results of desired variables
        variables (:obj:`list` of :obj:`Variable`): variables that should be recorded
        solution (:obj:`cobra.core.solution.Solution`): solution of method

    Returns:
        :obj:`VariableResults`: the results of desired variables
    """
    variable_results = VariableResults()
    for variable in variables:
        result_type, result_name = target_results_path_map[variable.target]
        if result_type:
            result = getattr(solution, result_type)
            if result_name:
                if hasattr(result, 'get'):
                    result = result.get(*result_name)
                else:
                    result = result[result_name]
        else:
            result = numpy.nan

        variable_results[variable.id] = numpy.array(result)

    return variable_results


from pandas import HDFStore, DataFrame, read_hdf, read_parquet
from pathlib import Path
import yaml

def load_config(path: Path) -> dict:
    """Load the configuration file"""
    return yaml.load(open(path, "r"), Loader=yaml.Loader)

# def open_hdf(path: Path):
#     return HDFStore(path.absolute(), mode="r")

def get_candle_data(path: Path, symbol: str, period: str, candle: str) -> DataFrame:
    if not path:
        return None

    # ohlc_key = f"/OHLCV/{period}/"
    # print("OHLC_key", ohlc_key)
    ohlc_df = read_parquet(path=path / f"OHLCV/{period}/data.parquet").query(f"symbol == '{symbol}'")
    if candle == "ohlc":
        return ohlc_df.sort_values("Date", ascending=False).reset_index(drop=True)  # .drop("Index", axis=1)

    if candle == "ha":
        # ha_key = f"/Signals/{period}/heikin_ashi/"
        ha_df = read_parquet(path=path / f"signals/{period}/heikin_ashi.parquet").query(f"symbol == '{symbol}'")
        # print("ha_df", ha_df)
        # print("ohlc_df", ohlc_df)

        return (
            ha_df.drop("Volume", axis=1)
            .merge(ohlc_df, how="inner", on=["Date", "symbol"])
            .loc[:, ["Date", "symbol", "HA_Open", "HA_High", "HA_Low", "HA_Close", "Volume"]]
            .rename(
                columns={
                    "HA_Open": "Open",
                    "HA_High": "High",
                    "HA_Low": "Low",
                    "HA_Close": "Close",
                }
            )
            .sort_values("Date", ascending=False)
            .reset_index(drop=True)
        )

def load_screener_data(path: Path, period: str, lookback: list[int] = [0, 1]) -> DataFrame:
    if not path:
        return None

    # screener_key = f"Signals/{period}/merged"
    # print("lookback", lookback)
    return (
        read_parquet(path=path / f"signals/{period}/merged.parquet")
        .sort_values("Date", ascending=True)
        .groupby("symbol")
        .tail(lookback[1])
        .groupby("symbol")
        .head(lookback[1] - lookback[0])
        .drop("index", axis=1)
    )

def get_symbol_info(path: Path, symbol: str) -> str:
    if not path or not symbol:
        return ""

    row = read_parquet(path=path / "info.parquet").query(f'symbol == "{symbol}"').iloc[0]
    return "\n".join([f"{k}: {v}" for k, v in row.to_dict().items()])


from vertices import *

dict_of_roads = {}
road_neighbors = {}
road_direction = {}
count = 0
"""looping through all the keys in dict_of_vertices and storing their xy coordinates"""

for vert1 in dict_of_vertices:
    vert1xy = dict_of_vertices[vert1]
    for vert2 in dict_of_vertices:

        """repeating the same process from before, but instead of storing the xy coordinates right away
        the program first checks if the second vertex is a neighbor to the first vertex"""

        if vert2 in vertice_neighbors[vert1]:
            vert2xy = dict_of_vertices[vert2]

            """calculating the midpoint requires finding the distance between two points dividing by two then adding them
            to the subtrahend which in this case is the vert2xy. The subtrahend is the part that subtracts in the equation"""

            new_x = (vert1xy[0]-vert2xy[0])/2+vert2xy[0]
            new_y = (vert1xy[1]-vert2xy[1])/2+vert2xy[1]
            count += 1
            road = "road%s" % (count)

            """checks to see if the new road has been inputed already"""

            if [new_x,new_y] in dict_of_roads.values():
                continue

            if vert1xy[0]-vert2xy[0] < 0 and vert1xy[1]-vert2xy[1] < 0:
                road_direction[road] = 'UL'
            elif vert1xy[0]-vert2xy[0] > 0 and vert1xy[1]-vert2xy[1] < 0:
                road_direction[road] = 'UR'
            elif vert1xy[0]-vert2xy[0] < 0 and vert1xy[1]-vert2xy[1] > 0:
                road_direction[road] = 'UR'
            elif vert1xy[0]-vert2xy[0] > 0 and vert1xy[1]-vert2xy[1] > 0:
                road_direction[road] = 'UL'
            else:
                road_direction[road] = 'UP'
            """adding a new road to dict_of_roads and vertice_neighbors. Also adding the vertices to road_neighbors"""

            dict_of_roads[road] = [new_x,new_y]
            road_neighbors[road] = [vert1,vert2]
            vertice_neighbors[vert1].append(road)
            vertice_neighbors[vert2].append(road)

#print (dict_of_roads)
#Bprint (road_neighbors)
#print (vertice_neighbors)


import psycopg2
import json
# Leer las credenciales de un archivo JSON
# Recomendado: https://parzibyte.me/blog/2019/06/09/json-python-codificar-decodificar/
with open("credenciales.json") as archivo_credenciales:
    credenciales = json.load(archivo_credenciales)
# Como la conexión devuelve un diccionario podemos convertirlo fácilmente
# a "kwargs" o key arguments ;)
# Recomendado: https://parzibyte.me/blog/2018/12/20/args-kwargs-python/
try:
    conn = psycopg2.connect(**credenciales)
    print('yes')
except psycopg2.Error as e:
    print("Ocurrió un error al conectar a PostgreSQL: ", e)


import unittest
from panda3d.core import Plane, LVector3f, LPoint3f
from utils import triangle_plane_intersection

class test_triangle_intersection(unittest.TestCase):
    def setUp(self):
        self.plane = Plane(LVector3f(0, -1, 0), LPoint3f(0, 0, 0))

    def test_simple_intersection(self):
        """
        In this test case, the plane passes through the origin and faces towards the camera

        (z is up and y is depth)

        The triangle is flat on the xz plane and crosses at -2.5, 0, 0 and 2.5, 0, 0
        """
        triangle = [
            LPoint3f( 5, -5, 0),
            LPoint3f(-5, -5, 0),
            LPoint3f( 0,  5, 0)
        ]

        intersection = triangle_plane_intersection(triangle, self.plane)
        assert(len(intersection) == 2)

    def test_triangle_on_plane(self):
        """In this test case, the entire triangle lies on the plane. So we should get three points back"""
        triangle = [
            LPoint3f( 5, 0, -5),
            LPoint3f(-5, 0, -5),
            LPoint3f( 0, 0,  5)
        ]

        intersection = triangle_plane_intersection(triangle, self.plane)
        assert(len(intersection) == 3)

    def test_triangle_edge_on_plane(self):
        """In this test case, one edge of the triangle lies on the plane, so we should get that edge back"""
        triangle = [
            LPoint3f( 5, 0, 0),
            LPoint3f(-5, 0, 0),
            LPoint3f( 0, -5, 0)
        ]

        intersection = triangle_plane_intersection(triangle, self.plane)
        assert(len(intersection) == 2)


'''
img.shape
img.size
img.dtype
'''

import cv2
import numpy as np

img = cv2.imread('D:/A LEARN/Image Processing/Program Youtube/Gambar/messi.jpg',1)

print(img.shape) #returns a tuple of rows, columns and chanels
print(img.size) #return total number of pixel (row*columns*chanell)
print(img.dtype) #return image datatype is obtained

b,g,r = cv2.split(img)  #ngesplit semua bgr dalam setiap pixel di gambar
img = cv2.merge((b,g,r)) #nyatuin semua bgr perpixel jadi gambar lagi

cv2.imshow('image', img)
cv2.waitKey()
cv2.destroyAllWindows()