# -*- coding: utf-8 -*-
"""
Created on Sat Aug  3 23:26:12 2019

@author: pawan
"""

"""Air QualityUCI data"""

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd

#importing and visualizing data
air_data = pd.read_excel('AirQualityUCI.xlsx')

air_data.head()
air_data.shape

#dropping ueless information from the data

air_data.dropna(axis=0, how='all')

features=air_data
features = features.drop('Date', axis=1)
features = features.drop('Time', axis=1)
features = features.drop('C6H6(GT)', axis=1)
features = features.drop('PT08.S4(NO2)', axis=1)
features

labels = air_data['C6H6(GT)']
#features=features.values

#training and testing

from sklearn.model_selection import train_test_split

X_train,X_test,Y_train,Y_test = train_test_split(features,labels,test_size=.2)

#applying differebt regression models

#1. Linear

from sklearn.linear_model import LinearRegression
regressor=LinearRegression()
regressor.fit(X_train,Y_train)

Y_pred=regressor.predict(X_test)

#2. Polynomial

from sklearn.preprocessing import PolynomialFeatures
Poly=PolynomialFeatures(degree=4)
X_train_poly=Poly.fit_transform(X_train)
X_test_poly=Poly.fit_transform(X_test)
regressor.fit(X_train_poly,Y_train)
Y_pred_poly=regressor.predict(X_test_poly)

#3. Support Vector Regression

     #feature scaling

from sklearn.preprocessing import StandardScaler
X_sc=StandardScaler()
Y_sc=StandardScaler()
Y_train=Y_train.values.reshape(-1,1) #<did this to resshape 1D to 2D>
X_train_sc=X_sc.fit_transform(X_train)
Y_train_sc=Y_sc.fit_transform(Y_train)
#Y_test=Y_test.values.reshape(-1,1)
X_test_sc=X_sc.fit_transform(X_test)
Y_test_sc=Y_sc.fit_transform(Y_test)

   #building the svr
from sklearn.svm import SVR
svmregressor=SVR(kernel='rbf',C=1000)
svmregressor.fit(X_train_sc,Y_train_sc)

Y_pred_svr=svmregressor.predict(X_test_sc)

Y_pred_svr=Y_sc.inverse_transform(Y_pred_svr)

#4. Decision tree regression

from sklearn.tree import DecisionTreeRegressor

DT=DecisionTreeRegressor()
DT.fit(X_train,Y_train)
  #feature importances in DTR
print(DT.feature_importances_)
featureimpDT=np.argsort(DT.feature_importances_)[::-1]
Y_pred_DT=DT.predict(X_test)

#5. Lasso Regression

from sklearn.linear_model import Lasso

classifier=Lasso(alpha=1)
classifier.fit(X_train,Y_train)

Y_pred_L=classifier.predict(X_test)

#6. ExtraTreeRegressor

from sklearn.ensemble import ExtraTreesRegressor
etr=ExtraTreesRegressor(n_estimators=300)
etr.fit(X_train,Y_train)

#Feature Importances on ETR
print(etr.feature_importances_)
indecis = np.argsort(etr.feature_importances_)[::-1]
plt.figure(num=None, figsize=(14, 10), dpi=80, facecolor='w')
plt.title("Feature importances")
plt.bar(range(X_train.shape[1]), etr.feature_importances_[indecis],
       color="r", align="center")
plt.xticks(range(X_train.shape[1]), indecis)
plt.show()

AirQualityUCI Benzene prediction project/AirQualityUCI prediction with LR,PR,DTR,Lasso,ETR.py


# CTI-110
# M3HW1 - Age Classifier
# Lisa Cannon
# 24SEP17

def main():
    # Program to determine a person's stage in life based off age

    infant = 1
    child = 13
    teenager = 20
    adult = 21

    age = int(input('Enter age: '))

    if age <= infant:
        print ('You are an Infant')
##
    if age <= child:
        print ('You are a Child.')

    elif age <= teenager:
        print ('You are a Teenager.')

    elif age >= adult:
        print ('You are an Adult.')

# program start
main ()


"""
Data Structures
===============

Defines various data structures classes:

-   :class:`colour.utilities.Structure`: An object similar to C/C++ structured
    type.
-   :class:`colour.utilities.Lookup`: A :class:`dict` sub-class acting as a
    lookup to retrieve keys by values.
-   :class:`CaseInsensitiveMapping`: A case insensitive
    :class:`dict`-like object allowing values retrieving from keys while
    ignoring the key case.
-   :class:`colour.utilities.LazyCaseInsensitiveMapping`: Another case
    insensitive mapping allowing lazy values retrieving from keys while
    ignoring the key case.
-   :class:`colour.utilities.Node`: A basic node object supporting creation of
    basic node trees.

References
----------
-   :cite:`Mansencalc` : Mansencal, T. (n.d.). Lookup.
    https://github.com/KelSolaar/Foundations/blob/develop/foundations/\
data_structures.py
-   :cite:`Rakotoarison2017` : Rakotoarison, H. (2017). Bunch. Retrieved
    December 4, 2021, from https://github.com/scikit-learn/scikit-learn/blob/\
0d378913b/sklearn/utils/__init__.py#L83
-   :cite:`Reitza` : Reitz, K. (n.d.). CaseInsensitiveDict.
    https://github.com/kennethreitz/requests/blob/v1.2.3/requests/\
structures.py#L37
"""

from __future__ import annotations

from collections.abc import MutableMapping

from colour.hints import (
    Any,
    Boolean,
    Dict,
    Generator,
    Integer,
    Iterable,
    List,
    Mapping,
    Optional,
    Union,
)
from colour.utilities.documentation import is_documentation_building

__author__ = "Colour Developers"
__copyright__ = "Copyright 2013 Colour Developers"
__license__ = "New BSD License - https://opensource.org/licenses/BSD-3-Clause"
__maintainer__ = "Colour Developers"
__email__ = "colour-developers@colour-science.org"
__status__ = "Production"

__all__ = [
    "attest",
    "Structure",
    "Lookup",
    "CaseInsensitiveMapping",
    "LazyCaseInsensitiveMapping",
    "Node",
]

def attest(condition: Boolean, message: str = ""):
    """
    Provide the `assert` statement functionality without being disabled by
    optimised Python execution.

    See :func:`colour.utilities.assert` for more information.

    Notes
    -----
    -   This definition is duplicated to avoid import circular dependency.
    """

    # Avoiding circular dependency.
    import colour.utilities

    colour.utilities.attest(condition, message)

class Structure(dict):
    """
    Define a :class:`dict`-like object allowing to access key values using dot
    syntax.

    Other Parameters
    ----------------
    args
        Arguments.
    kwargs
        Key / value pairs.

    Methods
    -------
    -   :meth:`~colour.utilities.Structure.__init__`
    -   :meth:`~colour.utilities.Structure.__setattr__`
    -   :meth:`~colour.utilities.Structure.__delattr__`
    -   :meth:`~colour.utilities.Structure.__dir__`
    -   :meth:`~colour.utilities.Structure.__getattr__`
    -   :meth:`~colour.utilities.Structure.__setstate__`

    References
    ----------
    :cite:`Rakotoarison2017`

    Examples
    --------
    >>> person = Structure(first_name='John', last_name='Doe', gender='male')
    >>> person.first_name
    'John'
    >>> sorted(person.keys())
    ['first_name', 'gender', 'last_name']
    >>> person['gender']
    'male'
    """

    def __init__(self, *args: Any, **kwargs: Any):
        super().__init__(*args, **kwargs)

    def __setattr__(self, name: str, value: Any):
        """
        Assign given value to the attribute with given name.

        Parameters
        ----------
        name
            Name of the attribute to assign the ``value`` to.
        value
            Value to assign to the attribute.
        """

        self[name] = value

    def __delattr__(self, name: str):
        """
        Delete the attribute with given name.

        Parameters
        ----------
        name
            Name of the attribute to delete.
        """

        del self[name]

    def __dir__(self) -> Iterable:
        """
        Return a list of valid attributes for the :class:`dict`-like object.

        Returns
        -------
        :class:`list`
            List of valid attributes for the :class:`dict`-like object.
        """

        return self.keys()

    def __getattr__(self, name: str) -> Any:
        """
        Return the value from the attribute with given name.

        Parameters
        ----------
        name
            Name of the attribute to get the value from.

        Returns
        -------
        :class:`object`

        Raises
        ------
        AttributeError
            If the attribute is not defined.
        """

        try:
            return self[name]
        except KeyError:
            raise AttributeError(name)

    def __setstate__(self, state):
        """Set the object state when unpickling."""
        # See https://github.com/scikit-learn/scikit-learn/issues/6196 for more
        # information.

        pass

class Lookup(dict):
    """
    Extend :class:`dict` type to provide a lookup by value(s).

    Methods
    -------
    -   :meth:`~colour.utilities.Lookup.keys_from_value`
    -   :meth:`~colour.utilities.Lookup.first_key_from_value`

    References
    ----------
    :cite:`Mansencalc`

    Examples
    --------
    >>> person = Lookup(first_name='John', last_name='Doe', gender='male')
    >>> person.first_key_from_value('John')
    'first_name'
    >>> persons = Lookup(John='Doe', Jane='Doe', Luke='Skywalker')
    >>> sorted(persons.keys_from_value('Doe'))
    ['Jane', 'John']
    """

    def keys_from_value(self, value: Any) -> List:
        """
        Get the keys associated with given value.

        Parameters
        ----------
        value
            Value to find the associated keys.

        Returns
        -------
        :class:`list`
            Keys associated with given value.
        """

        keys = []
        for key, data in self.items():
            matching = data == value
            try:
                matching = all(matching)

            except TypeError:
                matching = all((matching,))

            if matching:
                keys.append(key)

        return keys

    def first_key_from_value(self, value: Any) -> Any:
        """
        Get the first key associated with given value.

        Parameters
        ----------
        value
            Value to find the associated first key.

        Returns
        -------
        :class:`object`
            First key associated with given value.
        """

        return self.keys_from_value(value)[0]

class CaseInsensitiveMapping(MutableMapping):
    """
    Implement a case-insensitive :class:`dict`-like object.

    Allows values retrieving from keys while ignoring the key case.
    The keys are expected to be str or :class:`str`-like objects supporting the
    :meth:`str.lower` method.

    Parameters
    ----------
    data
        Data to store into the case-insensitive :class:`dict`-like object at
        initialisation.

    Other Parameters
    ----------------
    kwargs
        Key / value pairs to store into the mapping at initialisation.

    Attributes
    ----------
    -   :attr:`~colour.utilities.CaseInsensitiveMapping.data`

    Methods
    -------
    -   :meth:`~colour.utilities.CaseInsensitiveMapping.__init__`
    -   :meth:`~colour.utilities.CaseInsensitiveMapping.__repr__`
    -   :meth:`~colour.utilities.CaseInsensitiveMapping.__setitem__`
    -   :meth:`~colour.utilities.CaseInsensitiveMapping.__getitem__`
    -   :meth:`~colour.utilities.CaseInsensitiveMapping.__delitem__`
    -   :meth:`~colour.utilities.CaseInsensitiveMapping.__contains__`
    -   :meth:`~colour.utilities.CaseInsensitiveMapping.__iter__`
    -   :meth:`~colour.utilities.CaseInsensitiveMapping.__len__`
    -   :meth:`~colour.utilities.CaseInsensitiveMapping.__eq__`
    -   :meth:`~colour.utilities.CaseInsensitiveMapping.__ne__`
    -   :meth:`~colour.utilities.CaseInsensitiveMapping.copy`
    -   :meth:`~colour.utilities.CaseInsensitiveMapping.lower_items`

    References
    ----------
    :cite:`Reitza`

    Examples
    --------
    >>> methods = CaseInsensitiveMapping({'McCamy': 1, 'Hernandez': 2})
    >>> methods['mccamy']
    1
    """

    def __init__(
        self, data: Optional[Union[Generator, Mapping]] = None, **kwargs: Any
    ):
        self._data: Dict = dict()

        self.update({} if data is None else data, **kwargs)

    @property
    def data(self) -> Dict:
        """
        Getter property for the case-insensitive :class:`dict`-like object
        data.

        Returns
        -------
        :class:`dict`
            Data.
        """

        return self._data

    def __repr__(self) -> str:
        """
        Return an evaluable string representation of the case-insensitive
        :class:`dict`-like object.

        Returns
        -------
        :class:`str`
            Evaluable string representation.
        """

        if is_documentation_building():  # pragma: no cover
            representation = repr(
                dict(zip(self.keys(), ["..."] * len(self)))
            ).replace("'...'", "...")
            return f"{self.__class__.__name__}({representation})"
        else:
            return f"{self.__class__.__name__}({dict(self.items())})"

    def __setitem__(self, item: Union[str, Any], value: Any):
        """
        Set given item with given value in the case-insensitive
        :class:`dict`-like object.

        Parameters
        ----------
        item
            Item to set in the case-insensitive :class:`dict`-like object.
        value
            Value to store in the case-insensitive :class:`dict`-like object.

        Notes
        -----
        -   The item is stored as lower-case while the original name and its
            value are stored together as the value in a *tuple*::

            {"item.lower()": ("item", value)}
        """

        self._data[self._lower_key(item)] = (item, value)

    def __getitem__(self, item: Union[str, Any]) -> Any:
        """
        Return the value of given item from the case-insensitive
        :class:`dict`-like object.

        Parameters
        ----------
        item
            Item to retrieve the value of from the case-insensitive
            :class:`dict`-like object.

        Returns
        -------
        :class:`object`
            Item value.

        Notes
        -----
        -   The item value is retrieved by using its lower-case variant.
        """

        return self._data[self._lower_key(item)][1]

    def __delitem__(self, item: Union[str, Any]):
        """
        Delete given item from the case-insensitive :class:`dict`-like object.

        Parameters
        ----------
        item
            Item to delete from the case-insensitive :class:`dict`-like object.

        Notes
        -----
        -   The item is deleted by using its lower-case variant.
        """

        del self._data[self._lower_key(item)]

    def __contains__(self, item: Union[str, Any]) -> bool:
        """
        Return whether the case-insensitive :class:`dict`-like object contains
        given item.

        Parameters
        ----------
        item
            Item to find whether it is in the case-insensitive
            :class:`dict`-like object.

        Returns
        -------
        :class:`bool`
            Whether given item is in the case-insensitive :class:`dict`-like
            object.
        """

        return self._lower_key(item) in self._data

    def __iter__(self) -> Generator:
        """
        Iterate over the items of the case-insensitive :class:`dict`-like
        object.

        Yields
        ------
        Generator
            Item generator.

        Notes
        -----
        -   The iterated items are the original items.
        """

        return (item for item, value in self._data.values())

    def __len__(self) -> Integer:
        """
        Return the items count.

        Returns
        -------
        :class:`numpy.integer`
            Items count.
        """

        return len(self._data)

    def __eq__(self, other: Any) -> bool:
        """
        Return whether the case-insensitive :class:`dict`-like object is equal
        to given other object.

        Parameters
        ----------
        other
            Object to test whether it is equal to the case-insensitive
            :class:`dict`-like object

        Returns
        -------
        :class:`bool`
            Whether given object is equal to the case-insensitive
            :class:`dict`-like object.
        """

        if isinstance(other, Mapping):
            other_mapping = CaseInsensitiveMapping(other)
        else:
            raise ValueError(
                f"Impossible to test equality with "
                f'"{other.__class__.__name__}" class type!'
            )

        return dict(self.lower_items()) == dict(other_mapping.lower_items())

    def __ne__(self, other: Any) -> bool:
        """
        Return whether the case-insensitive :class:`dict`-like object is not
        equal to given other object.

        Parameters
        ----------
        other
            Object to test whether it is not equal to the case-insensitive
            :class:`dict`-like object

        Returns
        -------
        :class:`bool`
            Whether given object is not equal to the case-insensitive
            :class:`dict`-like object.
        """

        return not (self == other)

    @staticmethod
    def _lower_key(key: Union[str, Any]) -> Union[str, Any]:
        """
        Return the lower-case variant of given key, if the key cannot be
        lower-cased, it is passed unmodified.

        Parameters
        ----------
        key
            Key to return the lower-case variant.

        Returns
        -------
        :class:`str` or :class:`object`
            Key lower-case variant.
        """

        try:
            return key.lower()
        except AttributeError:
            return key

    def copy(self) -> CaseInsensitiveMapping:
        """
        Return a copy of the case-insensitive :class:`dict`-like object.

        Returns
        -------
        :class:`CaseInsensitiveMapping`
            Case-insensitive :class:`dict`-like object copy.

        Warnings
        --------
        -   The :class:`CaseInsensitiveMapping` class copy returned is a
            *copy* of the object not a *deepcopy*!
        """

        return CaseInsensitiveMapping(dict(self._data.values()))

    def lower_items(self) -> Generator:
        """
        Iterate over the lower-case items of the case-insensitive
        :class:`dict`-like object.

        Yields
        ------
        Generator
            Item generator.

        Notes
        -----
        -   The iterated items are the lower-case items.
        """

        return ((item, value[1]) for (item, value) in self._data.items())

class LazyCaseInsensitiveMapping(CaseInsensitiveMapping):
    """
    Implement a lazy case-insensitive :class:`dict`-like object inheriting
    from :class:`CaseInsensitiveMapping` class.

    Allows lay values retrieving from keys while ignoring the key case.
    The keys are expected to be str or :class:`str`-like objects supporting the
    :meth:`str.lower` method.

    The lazy retrieval is performed as follows: If the value is a callable,
    then it is evaluated and its return value is stored in place of the current
    value.

    Parameters
    ----------
    data
        Data to store into the lazy case-insensitive :class:`dict`-like object
        at initialisation.

    Other Parameters
    ----------------
    kwargs
        Key / value pairs to store into the mapping at initialisation.

    Methods
    -------
    -   :meth:`~colour.utilities.LazyCaseInsensitiveMapping.__getitem__`

    Examples
    --------
    >>> def callable_a():
    ...     print(2)
    ...     return 2
    >>> methods = LazyCaseInsensitiveMapping(
    ...     {'McCamy': 1, 'Hernandez': callable_a})
    >>> methods['mccamy']
    1
    >>> methods['hernandez']
    2
    2
    """

    def __getitem__(self, item: Union[str, Any]) -> Any:
        """
        Return the value of given item from the case-insensitive
        :class:`dict`-like object.

        Parameters
        ----------
        item
            Item to retrieve the value of from the case-insensitive
            :class:`dict`-like object.

        Returns
        -------
        :class:`object`
            Item value.

        Notes
        -----
        -   The item value is retrieved by using its lower-case variant.
        """

        import colour

        value = super().__getitem__(item)

        if callable(value) and hasattr(colour, "__disable_lazy_load__"):
            value = value()
            super().__setitem__(item, value)

        return value

class Node:
    """
    Represent a basic node supporting the creation of basic node trees.

    Parameters
    ----------
    name
        Node name.
    parent
        Parent of the node.
    children
        Children of the node.
    data
        The data belonging to this node.

    Attributes
    ----------
    -   :attr:`~colour.utilities.Node.name`
    -   :attr:`~colour.utilities.Node.parent`
    -   :attr:`~colour.utilities.Node.children`
    -   :attr:`~colour.utilities.Node.id`
    -   :attr:`~colour.utilities.Node.root`
    -   :attr:`~colour.utilities.Node.leaves`
    -   :attr:`~colour.utilities.Node.siblings`
    -   :attr:`~colour.utilities.Node.data`

    Methods
    -------
    -   :meth:`~colour.utilities.Node.__new__`
    -   :meth:`~colour.utilities.Node.__init__`
    -   :meth:`~colour.utilities.Node.__str__`
    -   :meth:`~colour.utilities.Node.__len__`
    -   :meth:`~colour.utilities.Node.is_root`
    -   :meth:`~colour.utilities.Node.is_inner`
    -   :meth:`~colour.utilities.Node.is_leaf`
    -   :meth:`~colour.utilities.Node.walk`
    -   :meth:`~colour.utilities.Node.render`

    Examples
    --------
    >>> node_a = Node('Node A')
    >>> node_b = Node('Node B', node_a)
    >>> node_c = Node('Node C', node_a)
    >>> node_d = Node('Node D', node_b)
    >>> node_e = Node('Node E', node_b)
    >>> node_f = Node('Node F', node_d)
    >>> node_g = Node('Node G', node_f)
    >>> node_h = Node('Node H', node_g)
    >>> [node.name for node in node_a.leaves]
    ['Node H', 'Node E', 'Node C']
    >>> print(node_h.root.name)
    Node A
    >>> len(node_a)
    7
    """

    _INSTANCE_ID: Integer = 1
    """
    Node id counter.

    _INSTANCE_ID
    """

    def __new__(cls, *args: Any, **kwargs: Any) -> Node:
        """
        Return a new instance of the :class:`colour.utilities.Node` class.

        Other Parameters
        ----------------
        args
            Arguments.
        kwargs
            Keywords arguments.
        """

        instance = super().__new__(cls)

        instance._id = Node._INSTANCE_ID  # type: ignore[attr-defined]
        Node._INSTANCE_ID += 1

        return instance

    def __init__(
        self,
        name: Optional[str] = None,
        parent: Optional[Node] = None,
        children: Optional[List[Node]] = None,
        data: Optional[Any] = None,
    ):
        self._name: str = f"{self.__class__.__name__}#{self.id}"
        self.name = self._name if name is None else name
        self._parent: Optional[Node] = None
        self.parent = parent
        self._children: List[Node] = []
        self.children = self._children if children is None else children
        self._data: Optional[Any] = data

    @property
    def name(self) -> str:
        """
        Getter and setter property for the name.

        Parameters
        ----------
        value
            Value to set the name with.

        Returns
        -------
        :class:`str`
            Node name.
        """

        return self._name

    @name.setter
    def name(self, value: str):
        """Setter for the **self.name** property."""

        attest(
            isinstance(value, str),
            f'"name" property: "{value}" type is not "str"!',
        )

        self._name = value

    @property
    def parent(self) -> Optional[Node]:
        """
        Getter and setter property for the node parent.

        Parameters
        ----------
        value
            Parent to set the node with.

        Returns
        -------
        :class:`Node` or :py:data:`None`
            Node parent.
        """

        return self._parent

    @parent.setter
    def parent(self, value: Optional[Node]):
        """Setter for the **self.parent** property."""

        if value is not None:
            attest(
                issubclass(value.__class__, Node),
                f'"parent" property: "{value}" is not a '
                f'"{Node.__class__.__name__}" subclass!',
            )

            value.children.append(self)

        self._parent = value

    @property
    def children(self) -> List[Node]:
        """
        Getter and setter property for the node children.

        Parameters
        ----------
        value
            Children to set the node with.

        Returns
        -------
        :class:`list`
            Node children.
        """

        return self._children

    @children.setter
    def children(self, value: List[Node]):
        """Setter for the **self.children** property."""

        attest(
            isinstance(value, list),
            f'"children" property: "{value}" type is not a "list" instance!',
        )

        for element in value:
            attest(
                issubclass(element.__class__, Node),
                f'"children" property: A "{element}" element is not a '
                f'"{Node.__class__.__name__}" subclass!',
            )

        for node in value:
            node.parent = self

        self._children = value

    @property
    def id(self) -> Integer:
        """
        Getter property for the node id.

        Returns
        -------
        :class:`numpy.integer`
            Node id.
        """

        return self._id  # type: ignore[attr-defined]

    @property
    def root(self) -> Node:
        """
        Getter property for the node tree.

        Returns
        -------
        :class:`Node`
            Node root.
        """

        if self.is_root():
            return self
        else:
            return list(self.walk(ascendants=True))[-1]

    @property
    def leaves(self) -> Generator:
        """
        Getter property for the node leaves.

        Yields
        ------
        Generator
            Node leaves.
        """

        if self.is_leaf():
            return (node for node in (self,))
        else:
            return (node for node in self.walk() if node.is_leaf())

    @property
    def siblings(self) -> Generator:
        """
        Getter property for the node siblings.

        Returns
        -------
        Generator
            Node siblings.
        """

        if self.parent is None:
            return (sibling for sibling in ())  # type: ignore[var-annotated]
        else:
            return (
                sibling
                for sibling in self.parent.children
                if sibling is not self
            )

    @property
    def data(self) -> Any:
        """
        Getter property for the node data.

        Returns
        -------
        :class:`object`
            Node data.
        """

        return self._data

    @data.setter
    def data(self, value: Any):
        """Setter for the **self.data** property."""

        self._data = value

    def __str__(self) -> str:
        """
        Return a formatted string representation of the node.

        Returns
        -------
        :class`str`
            Formatted string representation.
        """

        return f"{self.__class__.__name__}#{self.id}({self._data})"

    def __len__(self) -> Integer:
        """
        Return the number of children of the node.

        Returns
        -------
        :class:`numpy.integer`
            Number of children of the node.
        """

        return len(list(self.walk()))

    def is_root(self) -> Boolean:
        """
        Return whether the node is a root node.

        Returns
        -------
        :class:`bool`
            Whether the node is a root node.

        Examples
        --------
        >>> node_a = Node('Node A')
        >>> node_b = Node('Node B', node_a)
        >>> node_c = Node('Node C', node_b)
        >>> node_a.is_root()
        True
        >>> node_b.is_root()
        False
        """

        return self.parent is None

    def is_inner(self) -> Boolean:
        """
        Return whether the node is an inner node.

        Returns
        -------
        :class:`bool`
            Whether the node is an inner node.

        Examples
        --------
        >>> node_a = Node('Node A')
        >>> node_b = Node('Node B', node_a)
        >>> node_c = Node('Node C', node_b)
        >>> node_a.is_inner()
        False
        >>> node_b.is_inner()
        True
        """

        return all([not self.is_root(), not self.is_leaf()])

    def is_leaf(self) -> Boolean:
        """
        Return whether the node is a leaf node.

        Returns
        -------
        :class:`bool`
            Whether the node is a leaf node.

        Examples
        --------
        >>> node_a = Node('Node A')
        >>> node_b = Node('Node B', node_a)
        >>> node_c = Node('Node C', node_b)
        >>> node_a.is_leaf()
        False
        >>> node_c.is_leaf()
        True
        """

        return len(self._children) == 0

    def walk(self, ascendants: Boolean = False) -> Generator:
        """
        Return a generator used to walk into :class:`colour.utilities.Node`
        trees.

        Parameters
        ----------
        ascendants
            Whether to walk up the node tree.

        Yields
        ------
        Generator
            Node tree walker.

        Examples
        --------
        >>> node_a = Node('Node A')
        >>> node_b = Node('Node B', node_a)
        >>> node_c = Node('Node C', node_a)
        >>> node_d = Node('Node D', node_b)
        >>> node_e = Node('Node E', node_b)
        >>> node_f = Node('Node F', node_d)
        >>> node_g = Node('Node G', node_f)
        >>> node_h = Node('Node H', node_g)
        >>> for node in node_a.walk():
        ...     print(node.name)
        Node B
        Node D
        Node F
        Node G
        Node H
        Node E
        Node C
        """

        attribute = "children" if not ascendants else "parent"

        nodes = getattr(self, attribute)
        nodes = nodes if isinstance(nodes, list) else [nodes]

        for node in nodes:
            yield node

            if not getattr(node, attribute):
                continue

            yield from node.walk(ascendants=ascendants)

    def render(self, tab_level: Integer = 0):
        """
        Render the current node and its children as a string.

        Parameters
        ----------
        tab_level
            Initial indentation level

        Returns
        -------
        :class:`str`
            Rendered node tree.

        Examples
        --------
        >>> node_a = Node('Node A')
        >>> node_b = Node('Node B', node_a)
        >>> node_c = Node('Node C', node_a)
        >>> print(node_a.render())
        |----"Node A"
            |----"Node B"
            |----"Node C"
        <BLANKLINE>
        """

        output = ""

        for _i in range(tab_level):
            output += "    "

        tab_level += 1

        output += f'|----"{self.name}"\n'

        for child in self._children:
            output += child.render(tab_level)

        tab_level -= 1

        return output


from abc import ABCMeta, abstractmethod
from typing import List

from tensorflow import Tensor
from tensorflow.keras.layers import MaxPooling2D, AveragePooling2D

from spivak.models.assembly.convolution_stacks import StridedBlockInterface, \
    ConvolutionStackInterface

POOLING_MAX = "max"
POOLING_AVERAGE = "average"

class BottomUpStackInterface(metaclass=ABCMeta):

    @abstractmethod
    def downsample_and_convolve(
            self, bottom_up: Tensor, num_filters_in: int, num_filters_out: int,
            layer_index: int) -> Tensor:
        pass

    @abstractmethod
    def convolve(
            self, bottom_up: Tensor, num_filters: int,
            layer_index: int) -> Tensor:
        pass

class BottomUpLayer:

    def __init__(self, tensor: Tensor, num_channels: int) -> None:
        self.tensor = tensor
        self.num_channels = num_channels

class PoolingBottomUpStack(BottomUpStackInterface):

    def __init__(
            self, pooling: str,
            convolution_stack: ConvolutionStackInterface) -> None:
        self._pooling = pooling
        self._convolution_stack = convolution_stack
        self._name = "bu"

    def convolve(
            self, bottom_up: Tensor, num_filters: int,
            layer_index: int) -> Tensor:
        return self._convolution_stack.convolve(
            bottom_up, num_filters, layer_index, self._name)

    def downsample_and_convolve(
            self, bottom_up: Tensor, num_filters_in: int, num_filters_out: int,
            layer_index: int) -> Tensor:
        if self._pooling == POOLING_MAX:
            pooling = MaxPooling2D(
                (2, 1), name=f"{self._name}_layer{layer_index}_max_pooling")
        elif self._pooling == POOLING_AVERAGE:
            pooling = AveragePooling2D(
                (2, 1), name=f"{self._name}_layer{layer_index}_average_pooling")
        else:
            raise ValueError(f"Unrecognized pooling: {self._pooling}")
        pooled = pooling(bottom_up)
        return self._convolution_stack.convolve(
            pooled, num_filters_out, layer_index, self._name)

class StridedBottomUpStack(BottomUpStackInterface):

    def __init__(
            self, strided_block: StridedBlockInterface,
            layer_num_blocks: List[int], strided_reduction: bool) -> None:
        self._strided_block = strided_block
        self._layer_num_blocks = layer_num_blocks
        self._strided_reduction = strided_reduction
        self._name = "bu"

    def convolve(
            self, bottom_up: Tensor, num_filters: int,
            layer_index: int) -> Tensor:
        for block_index in range(self._layer_num_blocks[layer_index]):
            bottom_up = self._strided_block.convolve(
                bottom_up, num_filters,
                name=f"{self._name}_layer{layer_index}_block{block_index}")
        return bottom_up

    def downsample_and_convolve(
            self, bottom_up: Tensor, num_filters_in: int, num_filters_out: int,
            layer_index: int) -> Tensor:
        num_blocks_in_layer = self._layer_num_blocks[layer_index]
        if self._strided_reduction or num_blocks_in_layer < 2:
            stride_filters = num_filters_out
        else:
            stride_filters = num_filters_in
        bottom_up = self._strided_block.strided_convolve(
            bottom_up, stride_filters,
            name=f"{self._name}_layer{layer_index}_block0")
        for block_index in range(1, num_blocks_in_layer):
            bottom_up = self._strided_block.convolve(
                bottom_up, num_filters_out,
                name=f"{self._name}_layer{layer_index}_block{block_index}")
        return bottom_up

def create_bottom_up_layers(
        input_mlp_out: Tensor, num_layers: int, base_num_filters: int,
        max_num_filters: int, bottom_up_stack: BottomUpStackInterface
) -> List[BottomUpLayer]:
    # VGG-16 applied dropout of 0.5 to their last two layers. U-net paper did
    # something similar, only applying dropout at the end of their bottom-up
    # layers.
    # https://arxiv.org/pdf/1409.1556.pdf
    # https://arxiv.org/pdf/1505.04597.pdf
    bottom_up_layers = []
    # Start with just a convolution stack and add that to the layers.
    num_filters_out = min(max_num_filters, base_num_filters)
    x = bottom_up_stack.convolve(input_mlp_out, num_filters_out, 0)
    bottom_up_layers.append(BottomUpLayer(x, num_filters_out))
    # Now, for each layer, add a stack that downsamples then convolves.
    for layer_index in range(1, num_layers):
        num_filters_in = num_filters_out
        num_filters_out = min(
            max_num_filters, 2 ** layer_index * base_num_filters)
        x = bottom_up_stack.downsample_and_convolve(
            x, num_filters_in, num_filters_out, layer_index)
        bottom_up_layers.append(BottomUpLayer(x, num_filters_out))
    return bottom_up_layers


from data_providers.base_data_provider import BaseDataProvider
from data_providers.duke_data_provider import DukeDataProvider

__all_data_providers__ = [
    "BaseDataProvider",
    "DukeDataProvider"
]

def make_data_provider(config):
    name = config["name"] if type(config) is dict else config.name
    if name in __all_data_providers__:
        return globals()[name](config)
    else:
        raise Exception('The data provider name %s does not exist' % name)


import os
from os import environ, write

from app import app

RED   = "\033[1;31m"
CYAN  = "\033[1;36m"
GREEN = "\033[0;32m"
RESET = "\033[0;0m"
BOLD  = "\033[;1m"

if environ.get('ENV') == 'PROD': print(f'{BOLD}{RED}USING PROD{RESET}')
elif environ.get('ENV') == 'LOCAL': print(f'{GREEN}using local{RESET}')
elif environ.get('ENV') == 'TESTING': print(f'{GREEN}Using Testing{RESET}')
else: print(f'{CYAN}using staging{RESET}')

PORT = int(os.getenv('PORT', '5000'))
app.run(host='0.0.0.0', port=PORT, debug=True, threaded=True)


# quick fix to work in gameLogicTests and for environment tests
try:
    from .gameClasses import game
except:
    from gameClasses import game

import numpy as np

class witches(game):
    def __init__(self, options_dict):
        super().__init__(options_dict)

        # Specific for witches:
        self.shifted_cards     = 0 # counts
        self.nu_shift_cards    = options_dict["nu_shift_cards"] # shift 2 cards!  # set to 0 to disable
        self.shifting_phase    = True
        self.shift_option      = 2 # due to gym reset=2 ["left", "right", "opposide"]
        self.correct_moves     = 0 # is not used or?!
        super().setup_game()       # is required here already for gym to work!

    def reset(self):
        self.nu_games_played +=1
        self.shifted_cards  = 0

        if self.shift_option <2:
            self.shift_option += 1
        else:
            self.shift_option  = 0
        if self.nu_shift_cards>0:
            self.shifting_phase    = True
        else:
            self.shifting_phase    = False
        self.players           = []  # stores players object
        self.on_table_cards    = []  # stores card on the table
        self.played_cards      = []  # of one game # see also in players offhand!
        self.gameOver          = 0
        self.rewards           = np.zeros((self.nu_players,))
        self.current_round     = 0
        super().setup_game()
        self.active_player     = self.nextGamePlayer()
        self.correct_moves     = 0

    def play_ai_move(self, ai_card_idx, print_=False):
        'card idx from 0....'
        current_player    =  self.active_player
        card_options__    = self.getValidOptions(current_player)# cards
        card              = self.idx2Card(ai_card_idx)
        player_has_card   = self.players[current_player].hasSpecificCardOnHand(ai_card_idx)
        tmp               = card.idx
        card_options      = self.cards2Idx(card_options__)
        if player_has_card and tmp in card_options and "RL" in self.player_types[current_player]:
            if print_:
                if self.shifting_phase and self.nu_shift_cards>0:
                    print("[{}] {} {}\t shifts {}\tCard {}\tCard Index {}\t len {}".format(self.current_round, current_player, self.player_names[current_player], self.player_types[current_player], card, ai_card_idx, len(self.players[current_player].hand)))
                else:
                    print("[{}] {} {}\t plays {}\tCard {}\tCard Index {}\t len {}  options {} on table".format(self.current_round, current_player, self.player_names[current_player], self.player_types[current_player], card, ai_card_idx, len(self.players[current_player].hand), card_options__), self.on_table_cards)
            self.correct_moves +=1
            rewards, round_finished, gameOver = self.step(self.idx2Hand(tmp, current_player), print_)
            if print_ and round_finished:
                print(rewards, self.correct_moves, gameOver, "\n")
            return rewards, round_finished, gameOver
        else:
            if print_:
                if not player_has_card:
                    print("Caution player does not have card:", card, " choose one of:", self.idxList2Cards(card_options))
                if not tmp in card_options:
                    print("Caution option idx", tmp, "not in (idx)", card_options)
                if not "RL" in self.player_types[current_player]:
                    print("Caution", self.player_types[current_player], self.active_player, "is not of type RL", self.player_types)
            return {"state": "play_or_shift", "ai_reward": None}, False, True # rewards round_finished, game_over

    def playUntilAI(self, print_=False):
        rewards        = {"state": "play_or_shift", "ai_reward": None}
        gameOver       = False
        round_finished = False
        while len(self.players[self.active_player].hand) > 0:
            current_player = self.active_player
            if "RANDOM" in self.player_types[current_player]:
                if  self.shifting_phase and self.nu_shift_cards>0:
                    hand_idx_action = self.getRandomCard()
                    card            = self.players[current_player].hand[hand_idx_action]
                    if print_:
                        print("[{}] {} {}\t shifts {}\tCard {}\tHand Index {}\t len {}".format(self.current_round, current_player, self.player_names[current_player], self.player_types[current_player], card, hand_idx_action, len(self.players[current_player].hand)))
                else:
                    card            = self.getRandomValidOption()
                    hand_idx_action = self.players[self.active_player].hand.index(card)
                    if print_:
                        print("[{}] {} {}\t plays {}\tCard {}\tHand Index {}\t len {}".format(self.current_round, current_player, self.player_names[current_player], self.player_types[current_player], card, hand_idx_action, len(self.players[current_player].hand)))
                rewards, round_finished, gameOver = self.step(hand_idx_action, print_)
                if print_ and round_finished:
                    print("")
            else:
                return rewards, round_finished, gameOver
        # Game is over!
        #CAUTION IF GAME OVER NO REWARDS ARE RETURNED
        #rewards = {'state': 'play_or_shift', 'ai_reward': None}
        return rewards, True, True

    def stepRandomPlay(self, action_ai, print_=False):
        # fängt denn ai überhaupt an???
        # teste ob correct_moves korrekt hochgezählt werden?!
        rewards, round_finished, gameOver = self.play_ai_move(action_ai, print_=print_)
        if rewards["ai_reward"] is None: # illegal move
            return None, self.correct_moves, True
        elif gameOver and "final_rewards" in rewards:
            # case that ai plays last card:
            mean_random = (sum(rewards["final_rewards"])- rewards["final_rewards"][1])/3
            return [rewards["final_rewards"][1], mean_random], self.correct_moves, gameOver
        else:
            #case that random player plays last card:
            if "RL" in self.player_types[self.active_player]:
                return [0, 0], self.correct_moves, gameOver
            else:
                rewards, round_finished, gameOver = self.playUntilAI(print_=print_)
                ai_reward   = 0
                mean_random = 0
                if gameOver and "final_rewards" in rewards:
                    mean_random = (sum(rewards["final_rewards"])- rewards["final_rewards"][1])/3
                    ai_reward = rewards["final_rewards"][1]
                return [ai_reward, mean_random], self.correct_moves, gameOver

    def getInColor(self):
        # returns the leading color of the on_table_cards
        # if only joker are played None is returned
        for i, card in enumerate(self.on_table_cards):
            if card is not None:
                if card.value <15:
                    return card.color
        return None

    def evaluateWinner(self):
        #uses on_table_cards to evaluate the winner of one round
        #returns winning card
        #player_win_idx: player that one this game! (0-3)
        #on_table_win_idx: player in sequence that one!
        highest_value    = 0
        winning_card     = self.on_table_cards[0]
        incolor          = self.getInColor()
        on_table_win_idx = 0
        if  incolor is not None:
            for i, card in enumerate(self.on_table_cards):
                # Note 15 is a Jocker
                if card is not None and ( card.value > highest_value and card.color == incolor and card.value<15):
                    highest_value = card.value
                    winning_card = card
                    on_table_win_idx = i
        player_win_idx = self.player_names.index(winning_card.player)
        return winning_card, on_table_win_idx, player_win_idx

    def getState(self):
        play_options = self.getBinaryOptions(self.active_player, self.nu_players, self.nu_cards)
        #play_options = self.convertAvailableActions(play_options)
        on_table, on_hand, played = self.getmyState(self.active_player, self.nu_players, self.nu_cards)
        add_states = [] #(nu_players-1)*5
        for i in range(len(self.players)):
            if i!=self.active_player:
                add_states.extend(self.getAdditionalState(i))
        return np.asarray([on_table+ on_hand+ played+ play_options+ add_states])

    def getValidOptions(self, player):
        # returns card of valid options
        if self.shifting_phase and self.nu_shift_cards>0:
            options = [x for x in range(len(self.players[player].hand))] # hand index
        else:
            options = self.getOptions(self.getInColor(), player) # hand index
        # return as cards
        return [self.players[player].hand[i] for i in options]

    def convertTakeHand(self, player, take_hand):
        converted_cards = []
        for card in take_hand:
            card.player = player.name
            converted_cards.append(card)
        return converted_cards

    def step(self, card_idx, print_=False):
        #Note that card_idx is a Hand Card IDX!
        # it is not card.idx unique number!
        self.shifting_phase = (self.shifted_cards<=self.nu_players*self.nu_shift_cards)
        if self.shifting_phase and self.nu_shift_cards>0:
            shift_round   = int(self.shifted_cards/self.nu_players)
            self.shiftCard(card_idx, self.active_player, self.getShiftPlayer())
            self.shifted_cards +=1

            round_finished = False
            if self.shifted_cards%self.nu_players == 0:
                round_finished = True
            #if print_: print("Shift Round:", shift_round, "Shifted Cards:", self.shifted_cards, "round_finished", round_finished)
            if shift_round == (self.nu_shift_cards)-1 and round_finished:
                if print_: print("\nShifting PHASE FINISHED!!!!!!\n")
                for player in self.players:
                    # convert cards of take hand card.player to correct player!
                    player.take_hand = self.convertTakeHand(player, player.take_hand)
                    player.hand.extend(player.take_hand)
                    if print_: print(player.name, "takes now", player.take_hand, " all cards", player.hand)
                self.shifted_cards  = 100
                self.shifting_phase = False
            self.active_player = self.getNextPlayer()
            return {"state": "shift", "ai_reward": 0}, round_finished, False # rewards, round_finished, gameOver
        else:
            # in case card_idx is a simple int value
            round_finished = False
            # play the card_idx:
            played_card = self.players[self.active_player].hand.pop(card_idx)
            self.on_table_cards.append(played_card)
            # Case round finished:
            trick_rewards    = [0]*self.nu_players
            on_table_win_idx = -1
            player_win_idx   = -1
            if len(self.on_table_cards) == self.nu_players:
                winning_card, on_table_win_idx, player_win_idx = self.evaluateWinner()
                trick_rewards[player_win_idx] = self.countResult([self.on_table_cards], self.players[player_win_idx].offhand)
                self.current_round +=1
                self.played_cards.extend(self.on_table_cards)
                self.players[player_win_idx].appendCards(self.on_table_cards)
                self.on_table_cards = []
                self.active_player  = player_win_idx
                round_finished = True

            else:
                self.active_player = self.getNextPlayer()

            if round_finished and len(self.played_cards) == self.nu_cards*self.nu_players:
                self.assignRewards()
            if self.isGameFinished():
                self.assignRewards()
                for i in range(len(self.total_rewards)):
                    self.total_rewards[i] +=self.rewards[i]
    		#yes this is the correct ai reward in case all players are ai players.
            return {"state": "play", "ai_reward": trick_rewards[player_win_idx], "on_table_win_idx": on_table_win_idx, "trick_rewards": trick_rewards, "player_win_idx": player_win_idx, "final_rewards": self.rewards}, round_finished, self.isGameFinished()

    def getAdditionalState(self, playeridx):
        # result = [would win, bgry color free]
        result = []
        player = self.players[playeridx]

        #extend if this player would win the current cards
        player_win_idx = playeridx
        if len(self.on_table_cards)>0:
            winning_card, on_table_win_idx, player_win_idx = self.evaluateWinner()
        if player_win_idx == playeridx:
            result.extend([1])
        else:
            result.extend([0])
        result.extend(player.colorFree) # 4 per player -> 12 states
        return result

    def getmyState(self, playeridx, players, cards):
        # should be 60 here in case of error!
        on_table, on_hand, played =[0]*players* cards, [0]*players* cards, [0]*players* cards
        for card in self.on_table_cards:
            on_table[card.idx]= 1

        for card in self.players[playeridx].hand:
            on_hand[card.idx] =1

        for card in self.played_cards:
            played[card.idx] = 1
        return on_table, on_hand, played

    def getOptions(self, incolor, player, orderOptions=False):
        # incolor = None -> Narr was played played before
        # incolor = None -> You can start!
        # Return Hand index

        cards        = self.players[player].hand

        options = []
        hasColor = False
        if incolor is None:
            for i, card in enumerate(cards):
                options.append(i)
        else:
            for i, card in enumerate(cards):
                if card.color == incolor and card.value <15:
                    options.append(i)
                    hasColor = True
                if card.value == 15: # append all joker
                    options.append(i)

        # if has not color and no joker append all cards!
        # wenn man also eine Farbe aus ist!
        if not hasColor:
            options = [] # necessary otherwise joker double!
            for i, card in enumerate(cards):
                options.append(i)
            if incolor is not None: # no do not check for joker here!
                self.players[player].setColorFree(incolor)
        if orderOptions: return sorted(options, key = lambda x: ( x[1].color,  x[1].value))
        return options

    def hasJoker(self, cards):
        for i in ["Y", "R", "G", "B"]:
            if super().hasSpecificCard(15, i, cards):
                return True
        return False

    def hasYellowEleven(self, cards):
        return self.hasSpecificCard(11, "Y", cards)

    def hasRedEleven(self, cards):
        return self.hasSpecificCard(11, "R", cards)

    def hasBlueEleven(self, cards):
        return self.hasSpecificCard(11, "B", cards)

    def countResult(self, input_cards, offhandCards):
        #input_cards = [[card1, card2, card3, card4], [stich2], ...]
        # in class player
        # get the current Reward (Evaluate offhand cards!)
        negative_result = 0
        # input_cards = self.offhand
        for stich in input_cards:
            for card in stich:
                if card is not None:
                    if card.color == "R" and card.value <15 and card.value!=11 and not self.hasRedEleven(offhandCards):
                        negative_result -=1
                    if card.color == "R" and card.value <15 and card.value!=11 and self.hasRedEleven(offhandCards):
                        negative_result -=1*2
                    if not self.hasBlueEleven(offhandCards):
                        if card.color == "G" and card.value == 11:
                            negative_result -= 5
                        if card.color == "G" and card.value == 12:
                            negative_result -= 10
                    if card.color == "Y" and card.value == 11:
                        negative_result+=5
        return negative_result

    def getBinaryOptions(self, player, nu_players, nu_cards):
        #returns 0....1... x1 array BGRY 0...15 sorted
        options_list = [0]*nu_players*nu_cards
        cards        = self.getValidOptions(player)
        unique_idx   = self.cards2Idx(cards)
        for idx in unique_idx:
            options_list[idx] = 1
        return options_list

#### custom
#### custom functions very game type specific functions
#### custom
    def shiftCard(self, card_idx, current_player, next_player):
        # shift round = 0, 1, ... (for 2 shifted cards)
        #print("I shift now hand idx", card_idx, "from", self.players[current_player].name, "to", self.players[next_player].name)
        card = self.players[current_player].hand.pop(card_idx) # wenn eine Karte weniger index veringern!
        self.players[next_player].take_hand.append(card)

    def getShiftPlayer(self):
        # works FOR 4 Players only!
        if self.shift_option==0:
            return self.getNextPlayer_()
        elif self.shift_option==1:
            return self.getPreviousPlayer(self.active_player)
        elif self.shift_option==2: # opposide
            return self.getPreviousPlayer(self.getPreviousPlayer(self.active_player))
        else:
            print("ERROR!!!! TO BE IMPLEMENTED!")
            raise

    def getShiftOptions(self):
        # Return all options to shift 2 not unique card idx.
        # returns:  [[0, 1], [0, 2], [0, 3], [0, 4], [0, 5], [0, 6], [0, 7], [0, 8], [0, 9], [0, 10], [0, 11], [0, 12], [0, 13], [0, 14], [1, 2], [1
        n   = len(self.players[self.active_player].hand)
        i   = 0
        options = []
        for j in range(0, n-1):
            tmp = i
            while tmp<n-1:
                options.append([j, tmp+1])
                tmp +=1
            i = i+1
        return options


import os
import time
import requests
from bs4 import BeautifulSoup

page_range = [129, 159]
limit_cache_num = 25

list_collect = []
save_idx = 0
while page_range[0] < page_range[1]:
	try:
		page = page_range[0]
		page_link = 'https://github.com/programthink?page=%d&tab=followers' % page
		print(page_link)
		r = requests.get(page_link)
		soup = BeautifulSoup(r.text, 'html.parser')
		results = soup.find_all("span", "link-gray pl-1")
		for idx, res in enumerate(results):
			if idx < save_idx:
				continue
			save_idx = idx
			user = res.string
			print('page: %s, user: %s' % (page,user))
			user_link = 'https://github.com/' + str(user)
			r = requests.get(user_link)
			so = BeautifulSoup(r.text, 'html.parser')
			links = so.find_all('a', "u-url")
			for l in links:
				link = links[0].string
				list_collect.append(str(link) + '#' + str(user_link))
				print(list_collect)
				print(len(list_collect))
				if len(list_collect) > limit_cache_num:
					raise Exception('overpage')
		page_range[0] += 1
		save_idx = 0
	except (Exception, KeyboardInterrupt):
		print('Ctrl-C interrupt, enter to continue ...')
		inp = input()
		if inp == 'quit':
			quit();
		elif inp == 'open':
			tot = len(list_collect)
			for idx, link in enumerate(list_collect):
				print("[%d / %d]" % (idx, tot))
				os.system('chromium ' + link)
				time.sleep(1)
			list_collect = []
		else:
			print('starting from ' + str(save_idx))
			continue

tot = len(list_collect)
for idx, link in enumerate(list_collect):
	print("[%d / %d]" % (idx, tot))
	os.system('chromium ' + link)
	time.sleep(1)


class Solution:
    def operation(self,arr):
        newArr = arr.copy()
        newArr.append(1)
        for i in range(len(arr)):
            arr[i] = (1-arr[i])

        arr.reverse()
        newArr.extend(arr)
        return newArr

    def find(self,k,arr):
        if k <= len(arr):
            return arr[k-1]

        n = len(arr)
        newArr = self.operation(arr)
        return self.find(k,newArr)

    def findKthBit(self, n: int, k: int) -> str:
        return str(self.find(k,[0]))


from selenium.webdriver.common.by import By
from selenium.webdriver.support.wait import WebDriverWait

class BaseAction:

    def __init__(self, driver):
        self.driver = driver

    def click(self, loc):
        self.find_element(loc).click()

    def input_text(self, loc, text):
        self.find_element(loc).send_keys(text)

    def find_element(self, loc, timeout=5.0, poll=1.0):
        by = loc[0]
        value = loc[1]  # "text,0"
        if by == By.XPATH:
            value = self.make_xpath_with_feature(value) # //*
            print(value)
        return WebDriverWait(self.driver, timeout, poll).until(lambda x: x.find_element(by, value))

    def find_elements(self, loc, timeout=5.0, poll=1.0):
        by = loc[0]
        value = loc[1]
        if by == By.XPATH:
            value = self.make_xpath_with_feature(value) # //*
        return WebDriverWait(self.driver, timeout, poll).until(lambda x: x.find_elements(by, value))

    def make_xpath_with_unit_feature(self, loc):
        """
        拼接xpath中间的部分
        :param loc:
        :return:
        """
        key_index = 0
        value_index = 1
        option_index = 2

        args = loc.split(",")
        feature = ""

        if len(args) == 2:
            feature = "contains(@" + args[key_index] + ",'" + args[value_index] + "')" + "and "
        elif len(args) == 3:
            if args[option_index] == "1":
                feature = "@" + args[key_index] + "='" + args[value_index] + "'" + "and "
            elif args[option_index] == "0":
                feature = "contains(@" + args[key_index] + ",'" + args[value_index] + "')" + "and "

        return feature

    def make_xpath_with_feature(self, loc):
        feature_start = "//*["
        feature_end = "]"
        feature = ""

        if isinstance(loc, str):
            # 如果是正常的xpath
            if loc.startswith("//"):
                return loc

            # loc str
            feature = self.make_xpath_with_unit_feature(loc)
        else:
            # loc 列表
            for i in loc:
                feature += self.make_xpath_with_unit_feature(i)

        feature = feature.rstrip("and ")

        loc = feature_start + feature + feature_end

        return loc

    def find_toast(self, message, is_screenshot=False, screenshot_name=None, timeout=3, poll=0.1):
        """
        # message: 预期要获取的toast的部分消息
        """
        message = "//*[contains(@text,'" + message + "')]"  # 使用包含的方式定位
        element = self.find_element((By.XPATH, message), timeout, poll)
        if is_screenshot:
            self.screenshot(screenshot_name)

        return element.text

    def is_toast_exist(self, message, is_screenshot=False, screenshot_name=None, timeout=3, poll=0.1):
        try:
            self.find_toast(message, is_screenshot, screenshot_name, timeout, poll)
            return True
        except Exception:
            return False

    def screenshot(self, file_name):
        self.driver.get_screenshot_as_file("./screen/" + file_name + ".png")


import tensorflow as tf
from io import BytesIO
from PIL import Image
import os
import io
import PIL
import hashlib
import numpy as np
import matplotlib.pyplot as plt
import cv2

def int64_feature(value):
    return tf.train.Feature(int64_list=tf.train.Int64List(value=[value]))

def int64_list_feature( value):
    return tf.train.Feature(int64_list=tf.train.Int64List(value=value))

def bytes_feature(value):
    return tf.train.Feature(bytes_list=tf.train.BytesList(value=[value]))

def bytes_list_feature(value):
    return tf.train.Feature(bytes_list=tf.train.BytesList(value=value))

def float_list_feature( value):
    return tf.train.Feature(float_list=tf.train.FloatList(value=value))

def read_examples_list(path):
    """Read list of training or validation examples.

    The file is assumed to contain a single example per line where the first
    token in the line is an identifier that allows us to find the image and
    annotation xml for that example.

    For example, the line:
    xyz 3
    would allow us to find files xyz.jpg and xyz.xml (the 3 would be ignored).

    Args:
    path: absolute path to examples list file.

    Returns:
    list of example identifiers (strings).
    """
    with tf.io.gfile.GFile(path) as fid:
        lines = fid.readlines()
    return [line.strip().split(' ')[0] for line in lines]

def recursive_parse_xml_to_dict(xml):
    """
    Recursively parses XML contents to python dict.
    We assume that `object` tags are the only ones that can appear
    multiple times at the same level of a tree.
    Args:
    xml: xml tree obtained by parsing XML file contents using lxml.etree
    Returns:
    Python dictionary holding XML contents.
    """
    if not xml:
        return {xml.tag: xml.text}
    result = {}
    for child in xml:
        child_result = recursive_parse_xml_to_dict(child)
        if child.tag != 'object':
            result[child.tag] = child_result[child.tag]
        else:
            if child.tag not in result:
                result[child.tag] = []
            result[child.tag].append(child_result[child.tag])
    return {xml.tag: result}

def _bytes_feature(value):
    return tf.train.Feature(bytes_list=tf.train.BytesList(value=[value]))

class TFConverter(object):
    def __init__(self, object_list, annotation_path, image_path):
        self.object_list = object_list  # 0 is background
        self.annotation_path = annotation_path
        self.image_path = image_path
        self.annotations = [f for f in os.listdir(annotation_path) if f.endswith(".npy")]
        self.images = [i for i in os.listdir(image_path) if (i.endswith("png") or i.endswith("jpg"))]

    def convert(self, gray_scale=False, output_path="."):
        writer = tf.io.TFRecordWriter(output_path + "/tf.record")
        for image in self.images:
            annotation = image.split(".")[0] + ".npy"
            if annotation not in self.annotations:
                print("No annotation file: Ignore "+image)
                continue
            else:
                annotation_file = os.path.join(self.annotation_path, annotation)
                image_file = os.path.join(self.image_path, image)
                masks = np.load(annotation_file)
                if masks.max()  < 1:
                    continue
                else:
                    tf_example = self._getTFExample(annotation_file, image_file, gray_scale)
                    writer.write(tf_example.SerializeToString())
        writer.close()

    def _getTFExample(self, annotation_file_path, image_file_path, gray_scale):
        if not gray_scale:
            fid = tf.io.gfile.GFile(image_file_path, 'rb')  # tensorflow 2.0
            encoded_jpg = fid.read()
            encoded_jpg_io = io.BytesIO(encoded_jpg)
            image = PIL.Image.open(encoded_jpg_io)
        else:
            gray_image = cv2.imread(image_file_path, cv2.IMREAD_GRAYSCALE)
            image = Image.fromarray(gray_image)
            encoded_jpg_io = BytesIO()
            image.save(encoded_jpg_io, 'JPEG')
            encoded_jpg = encoded_jpg_io.getvalue()
            encoded_jpg_io = io.BytesIO(encoded_jpg)
            image = PIL.Image.open(encoded_jpg_io)

        if image.format != 'JPEG':
            raise ValueError('Image format not JPEG')
        key = hashlib.sha256(encoded_jpg).hexdigest()

        width = image.width
        height = image.height
        masks = np.load(annotation_file_path)
        masks = np.swapaxes(masks, axis1=0, axis2=1)
        masks = np.swapaxes(masks, axis1=1, axis2=2)
        masks = (masks > 0.5) * 255
        if len(masks.shape) == 2:
            masks = np.expand_dims(masks, 2)
        obj_nm = masks.shape[-1]
        masks = (masks/255.0).astype(np.uint8)

        xmin = []
        ymin = []
        xmax = []
        ymax = []
        classes = []
        classes_text = []
        masks_PNG = []
        masks_list = []

        for i in range(obj_nm):
            mask = masks[:, :, i]
            if mask.max() < 1:
                continue
            masks_list.append(mask.tostring())
            bbox = self._getBBox(mask)
            xmin.append(float(bbox[0]) / width)
            ymin.append(float(bbox[2]) / height)
            xmax.append(float(bbox[1]) / width)
            ymax.append(float(bbox[3]) / height)
            id = int(mask.max())
            classes.append(id)
            classes_text.append(self.object_list[id-1])
            masks_PNG.append(self._image2PNGString(mask))

        example = tf.train.Example(features=tf.train.Features(feature={
            'image/height': int64_feature(height),
            'image/width': int64_feature(width),
            'image/filename': bytes_feature(image_file_path.encode('utf8')),  #
            'image/source_id': bytes_feature(image_file_path.encode('utf8')),  #
            'image/encoded': bytes_feature(encoded_jpg),
            'image/format': bytes_feature('jpeg'.encode('utf8')),
            'image/object/bbox/xmin': float_list_feature(xmin),
            'image/object/bbox/xmax': float_list_feature(xmax),
            'image/object/bbox/ymin': float_list_feature(ymin),
            'image/object/bbox/ymax': float_list_feature(ymax),
            'image/object/class/text': bytes_list_feature(classes_text),
            'image/object/class/label': int64_list_feature(classes),
            'image/object/mask': bytes_list_feature(masks_PNG)
            }))
        return example

    def _image2PNGString(self, image):
        image = Image.fromarray(image)
        byte_io = BytesIO()
        image.save(byte_io, 'PNG')
        return byte_io.getvalue()

    def _getBBox(self, mask):
        rows = np.any(mask, axis=1)
        cols = np.any(mask, axis=0)
        rmin, rmax = np.where(rows)[0][[0, -1]]
        cmin, cmax = np.where(cols)[0][[0, -1]]

        #xmin, xmax, ymin, ymax = rmin, rmax, cmin, cmax  # the bounding box is transposed
        ymin, ymax, xmin, xmax = rmin, rmax, cmin, cmax

        return xmin, xmax, ymin, ymax

if __name__ == "__main__":
    tfrecorder = TFConverter(['crater'], "./npy", "./moon_images")
    tfrecorder.convert(gray_scale=True)


import datetime
import os
from werkzeug.utils import secure_filename

from flask import Flask, render_template, redirect, request, url_for
import flask_login

from data import db_session
from data.users import User
from data.add_news import AddNews
from forms.loginform import LoginForm
from forms.settingsform import SettingsForm
from flask_login import LoginManager, login_user, login_required, logout_user
from forms.user import RegisterForm
from forms.add_newsform import AddNewsForm
from data.comments import Comment
from forms.add_comment import AddComment
from forms.add_news_random_game import AddNewsRandomGame

# Создать программу
app = Flask(__name__)
app.config['SECRET_KEY'] = 'yandexlyceum_secret_key'

login_manager = LoginManager()
login_manager.init_app(app)

# Создание пути
uploads_dir = os.path.join('', 'static/img')

# Главная страница
@app.route('/')
def main():
    db_sess = db_session.create_session()
    # Получение всех новостей
    news_list = db_sess.query(AddNews).all()
    return render_template('news.html', title='GameWiki', news_list=news_list[::-1])

# Форма входа в пользователя
@app.route('/login', methods=['GET', 'POST'])
def login():
    form = LoginForm()
    if form.validate_on_submit():
        db_sess = db_session.create_session()

        # Получение пользователя из БД по эл почте
        user = db_sess.query(User).filter(User.email == form.email.data).first()
        # Если пользователь найден и пароли совпадают
        if user and user.check_password(form.password.data):
            login_user(user, remember=form.remember_me.data)
            return redirect("/")
        return render_template('login.html',
                               message="Неправильный логин или пароль",
                               form=form)
    return render_template('login.html', title='Авторизация', form=form)

# Форма регистрации пользователя
@app.route('/register', methods=['GET', 'POST'])
def reqister():
    form = RegisterForm()
    if form.validate_on_submit():
        # Если пароли не совпадают
        if form.password.data != form.password_again.data:
            return render_template('register.html', title='Регистрация',
                                   form=form,
                                   message="Пароли не совпадают")
        db_sess = db_session.create_session()

        # Если пользователь уже заргеистрирован
        if db_sess.query(User).filter(User.email == form.email.data).first():
            return render_template('register.html', title='Регистрация',
                                   form=form,
                                   message="Такой пользователь уже есть")
        user = User(
            name=form.name.data,
            email=form.email.data,
            about=form.about.data
        )
        user.set_password(form.password.data)
        db_sess.add(user)
        db_sess.commit()
        return redirect('/login')
    return render_template('register.html', title='Регистрация', form=form)

# Функция загрузки пользователя
@login_manager.user_loader
def load_user(user_id):
    db_sess = db_session.create_session()
    return db_sess.query(User).get(user_id)

# Профиль пользователя
@app.route('/user/<int:id>', methods=['GET', 'POST'])
def profile(id):
    db_sess = db_session.create_session()
    user = db_sess.query(User).filter(User.id == id).first()
    return render_template('profile.html', title='Профиль', user=user)

# Настройки пользователя
@app.route('/profile_settings/<int:user_id>', methods=['GET', 'POST'])
def profile_settings(user_id):
    form = SettingsForm()
    db_sess = db_session.create_session()
    user = db_sess.query(User).filter(User.id == user_id).first()

    if request.method == 'POST':
        if request.files['profile']:
            # Загрузка фотографии
            profile = request.files['profile']
            profile.save(os.path.join(uploads_dir, secure_filename(profile.filename)))
            for file in request.files.getlist('charts'):
                file.save(os.path.join(uploads_dir, secure_filename(file.name)))

            # Изменение данных пользователя
        if user and user.check_password(form.password.data):
            login_user(user)
            user.age = form.age.data
            user.address = form.address.data
            user.about = form.about.data

            # Если фотография загружена
            if request.files['profile']:
                user.profile_image = f'../static/img/{profile.filename}'

            db_sess.commit()
            return redirect("/")
        return render_template('profile_settings.html',
                               message="Неправильный логин или пароль",
                               form=form)

    # Автозаполнение формы
    form.age.data = user.age
    form.about.data = user.about
    form.email.data = user.email
    form.address.data = user.address

    return render_template('profile_settings.html', title='Настройки профиля', form=form)

# Страница по новостям доты 2
@app.route('/dota2')
def dota_news():
    db_sess = db_session.create_session()
    # Получение всех новостей по доте 2
    news_list = db_sess.query(AddNews).filter(AddNews.game == 'dota').all()
    return render_template('dota2.html', title='Dota 2', news_list=news_list[::-1])

# Страница для добавления новостей по доте 2
@app.route('/add_news_dota', methods=['GET', 'POST'])
def add_news_dota():
    form = AddNewsForm()
    if request.method == 'POST':
        # Загрузка фотографии
        if request.files['profile']:
            profile = request.files['profile']
            profile.save(os.path.join(uploads_dir, secure_filename(profile.filename)))
            for file in request.files.getlist('charts'):
                file.save(os.path.join(uploads_dir, secure_filename(file.name)))

            # Добавление новости по данным с формы
            db_sess = db_session.create_session()
            add_new = AddNews()
            add_new.header = form.header.data
            add_new.description = form.description.data
            add_new.game = 'dota'
            add_new.date = datetime.datetime.now().strftime('%d %b %Y')
            add_new.image = f'../static/img/{profile.filename}'
            db_sess.add(add_new)
            db_sess.commit()

            return redirect("/dota2")
        else:
            return render_template('add_news.html', title='Добавление новости', form=form,
                                   message='Добавьте картинку!')

    return render_template('add_news.html', title='Добавление новости', form=form)

# Страница по новостям кс го
@app.route('/cs')
def cs_news():
    db_sess = db_session.create_session()
    # Получение всех новостей по кс го
    news_list = db_sess.query(AddNews).filter(AddNews.game == 'cs').all()
    return render_template('cs.html', title='CS:GO', news_list=news_list[::-1])

# Страница для добавления новостей по доте 2
@app.route('/add_news_cs', methods=['GET', 'POST'])
def add_news_cs():
    form = AddNewsForm()
    if request.method == 'POST':
        # Загрузка фотографии
        if request.files['profile']:
            profile = request.files['profile']
            profile.save(os.path.join(uploads_dir, secure_filename(profile.filename)))
            for file in request.files.getlist('charts'):
                file.save(os.path.join(uploads_dir, secure_filename(file.name)))

        # Добавление новости по данным с формы
        db_sess = db_session.create_session()
        add_new = AddNews()
        add_new.header = form.header.data
        add_new.description = form.description.data
        add_new.game = 'cs'
        add_new.date = datetime.datetime.now().strftime('%d %b %Y')
        add_new.image = f'../static/img/{profile.filename}'
        db_sess.add(add_new)
        db_sess.commit()

        return redirect("/cs")
    return render_template('add_news.html', title='Добавление новости', form=form)

# страница выхода из профиля
@app.route('/logout')
@login_required
def logout():
    logout_user()
    return redirect('/')

# Страница по кс
@app.route('/cs_for_new_players')
def cs_for_new_players():
    return render_template('cs_for_new_players.html', title='Кс для новичков')

# Страница по кс
@app.route('/cs_guns')
def cs_guns():
    return render_template('cs_guns.html', title='Оружие в кс')

# Страница по кс
@app.route('/cs_economy')
def cs_economy():
    return render_template('cs_economy.html', title='Экономика в кс')

# Страница по доте
@app.route('/dota_for_new_players')
def dota_for_new_players():
    return render_template('dota_for_new_players.html', title='Дота для новичков')

# Страница по доте
@app.route('/dota_choice')
def dota_choice():
    return render_template('dota_choice.html', title='Дота для новичков')

# Страница по доте
@app.route('/dota_heroes_for_new_players')
def dota_heroes_for_new_players():
    return render_template('dota_heroes_for_new_players.html', title='Дота для новичков')

# Страница по доте
@app.route('/dota_sokrasheniya')
def dota_sokrasheniya():
    return render_template('dota_sokrasheniya.html', title='Сокращения Dota 2')

# Страница по кс
@app.route('/cs_choice')
def cs_choice():
    return render_template('cs_choice.html', title='Кс для новичков')

# Страница для новости по id
@app.route('/news/<int:news_id>', methods=['GET', 'POST'])
def news(news_id):

    # Если пользователь не вошел в систему
    if flask_login.current_user.get_id() is None:
        return redirect('/register_should')

    form = AddComment()
    db_sess = db_session.create_session()
    if request.method == "POST":
        new_comment = Comment()
        new_comment.id_news = news_id
        new_comment.id_user = flask_login.current_user.id
        new_comment.content = form.description.data
        db_sess.add(new_comment)
        db_sess.commit()
        return redirect(f"/news/{news_id}")

    news = db_sess.query(AddNews).filter(AddNews.id == news_id).first()
    comments = db_sess.query(Comment).filter(Comment.id_news == news_id).all()
    all_users = set()

    for x in comments:
        users = db_sess.query(User).filter(User.id == x.id_user).all()
        for el in users:
            all_users.add(el)
    all_users = list(all_users)
    return render_template('one_news.html', title='Новость', news=news, comments=comments[::-1],
                           users=all_users, form=form)

# Страница для оповещения пользователя чтобы тот зарегистрировался
@app.route('/register_should')
def register_should():
    return render_template('register_should.html', title='Зарегистрируйтесь!')

# Добавление новости для любой игры
@app.route('/add_news_random_game',  methods=['GET', 'POST'])
def add_news_random_game():
    form = AddNewsRandomGame()
    if request.method == 'POST':

        # Загрузка фотографии для пользователя
        if request.files['profile']:
            profile = request.files['profile']
            profile.save(os.path.join(uploads_dir, secure_filename(profile.filename)))
            for file in request.files.getlist('charts'):
                file.save(os.path.join(uploads_dir, secure_filename(file.name)))

        db_sess = db_session.create_session()
        add_new = AddNews()
        add_new.header = form.header.data
        add_new.description = form.description.data
        add_new.game = form.game.data
        add_new.date = datetime.datetime.now().strftime('%d %b %Y')
        add_new.image = f'../static/img/{profile.filename}'
        db_sess.add(add_new)
        db_sess.commit()

        return redirect("/")
    return render_template('add_news_random_game.html', title='Добавление новости', form=form)

# Запуск программы
if __name__ == '__main__':
    db_session.global_init("db/GameWiki.db")
    port = int(os.environ.get("PORT", 5000))
    app.run(host='0.0.0.0', port=port)


from datetime import datetime
from fastapi import APIRouter, WebSocket, WebSocketDisconnect

router = APIRouter(prefix="/ws")

@router.websocket("/session")
async def websocket_endpoint(websocket: WebSocket):
    await websocket.accept()
    start = datetime.now()
    while True:
        try:
            data = await websocket.receive_text()
            await websocket.send_text(f"Message text was: {data}")
        except WebSocketDisconnect as e:
            print(f"connection duration {datetime.now()-start}")
            return


import logging
import os

import pandas as pd

from demandprediction.prediction.model import BaseModel
from demandprediction.prediction.postprocessing.error_measures import log_grid_error
from demandprediction.prediction.postprocessing.postprocessing import calculate_grid_error
from demandprediction.prediction.preprocessing.preprocessing import DataPreprocessor
from demandprediction.utils.shared_filenames import get_predictions_filename

class ConvLSTMBaseModel(BaseModel):
    def __init__(self, model_name: str, config: dict):
        """
        Initializes the ConvLSTM model.
        Inputs are: Demand and Metainformation
        The Architecture does use a Hadamard layer
        :param config: Configuration for the prediction.
        """
        super().__init__(model_name, config['data_directory'])
        self.start_date = config['start_date']
        self.stop_date = config['stop_date']
        self.number_of_grid_rows = config['number_of_grid_rows']
        self.number_of_grid_columns = config['number_of_grid_columns']
        self.lags = config['lags']
        self.number_of_filters = config['number_of_filters']
        self.kernel_size = config['kernel_size']
        self.batch_size = config['batch_size']
        self.learning_rate = config['learning_rate']
        self.step_size = config['step_size']
        self.epochs = config['epochs']
        self.x_limits = (config['x_min'], config['x_max'])
        self.y_limits = (config['y_min'], config['y_max'])
        prediction_relative_path = get_predictions_filename(self.model_name, self.start_time)
        self.prediction_filepath = os.path.join(self.data_directory, prediction_relative_path)
        self.number_of_prediction_timesteps = 0

        self.logger = logging.getLogger(__name__)

    def prepare_data(self):
        super().prepare_data()
        data_preprocessor = DataPreprocessor(self.data_directory, self.x_limits, self.y_limits)
        self.ground_truth_filepath = data_preprocessor.generate_window_grid(
            stop_date=self.stop_date,
            number_of_rows=self.number_of_grid_rows,
            number_of_columns=self.number_of_grid_columns,
            step_size=self.step_size,
            feature_name='demand'
        )

        self.number_of_prediction_timesteps = len(
            DataPreprocessor.get_date_range_between_dates(
                start_date=self.start_date,
                end_date=self.stop_date,
                freq=f'{self.step_size}min',
                end_inclusive=False
            )
        )
        # set flag
        self.data_prepared = True

    def save_predictions(self):
        super().save_predictions()
        predictions = self.predictions.reshape(self.predictions.shape[0],
                                               self.number_of_grid_rows * self.number_of_grid_columns)
        predictions_df = pd.DataFrame(predictions)

        # load actual data for index
        # noinspection PyTypeChecker
        actual_data_df = pd.read_hdf(self.ground_truth_filepath, key='even_grid')  # type: pd.DataFrame
        predictions_df.index = actual_data_df.index[-len(predictions_df.index):]
        self.logger.debug(predictions_df.index[:10])
        self.logger.debug(predictions_df.index[-10:])

        predictions_df.to_hdf(self.prediction_filepath, key='predictions', complevel=6)
        self.logger.info(f"Predictions saved to file: {self.prediction_filepath}")

    def score_model(self):
        """
        Calculate the evaluation metrics (RMSE, MAPE, etc.).
        Save the metrics and model hyperparams to csv file.
        """
        super().score_model()

        # Calculate error
        model_id = "{}_{date:%Y-%m-%d_%H-%M-%S}.h5".format(
            self.model_name, date=self.start_time)

        errors = calculate_grid_error(
            filepath=self.ground_truth_filepath,
            prediction_filepath=self.prediction_filepath,
            number_of_rows=self.number_of_grid_rows,
            number_of_columns=self.number_of_grid_columns,
            ceiling=1,
            logger=self.logger
        )

        # Write the errors and all hyperparams to a csv file!
        df = pd.DataFrame({
            'model_id': [model_id],
            'model_name': [self.model_name],
            'avg_grid_rmse_above_ceiling': [errors[0]],
            'avg_grid_mae_above_ceiling': [errors[1]],
            'avg_grid_mapec_above_ceiling': [errors[2]],
            'global_rmse': [errors[3]],
            'global_mae': [errors[4]],
            'global_mape': [errors[5]],
            'number_of_rows': [self.number_of_grid_rows],
            'number_of_columns': [self.number_of_grid_columns],
            'lags': [self.lags],
            'nb_filters': [self.number_of_filters],
            'k_size': [self.kernel_size],
            'batch_size': [self.batch_size],
            'lr': [self.learning_rate],
            'step_size': [self.step_size],
        })

        filename = os.path.join(self.data_directory, "evaluation/metrics_and_hyperparams.csv")
        with open(filename, 'a') as f:
            df.to_csv(filename, mode='a', header=not f.tell())

        log_grid_error(self.logger, self.prediction_filepath, errors)

        self.logger.info("Model errors were calculated successfully")


print("="*20)
print("Keterangan:")
print("H = hadir")
print("I = izin")
print("S = sakit")
print("A = alfa/tanpa keterangan")
print("="*20)

def absensi_siswa(students):
  jumlah = {}
  jumlah_hadir = 0
  jumlah_sakit = 0
  jumlah_izin = 0
  jumlah_alfa = 0

  for student in students:

    status = input(student + " (H/S/I/A): ")
    jumlah[student] = status

    if status == "H":
      jumlah_hadir += 1
    elif status == "S":
      jumlah_sakit += 1
    elif status == "I":
      jumlah_izin += 1
    elif status == "A":
      jumlah_alfa += 1

  print("\nAbsensi siswa:")
  for student, status in jumlah.items():
    if status == 'H':
      print(student+": Hadir")
    elif status == "S":
      print(student+": Sakit")
    elif status == "I":
      print(student+": Izin")
    elif status == "A":
      print(student+": Alfa")

  jumlah_siswa = len(students)
  persentase_hadir = jumlah_hadir / jumlah_siswa * 100
  persentase_izin = jumlah_izin / jumlah_siswa * 100
  persentase_sakit = jumlah_sakit / jumlah_siswa * 100
  persentase_alfa = jumlah_alfa / jumlah_siswa * 100
  print("\nJumlah siswa yang hadir: " + str(jumlah_hadir)+ " ("+"{:.2f}%" ")".format(persentase_hadir))
  print("Jumlah siswa yang sakit: " + str(jumlah_sakit)+ " ("+"{:.2f}%" ")".format(persentase_sakit))
  print("Jumlah siswa yang izin: " + str(jumlah_izin)+ " ("+"{:.2f}%" ")".format(persentase_izin))
  print("Jumlah siswa yang Alfa: " + str(jumlah_alfa)+ " ("+"{:.2f}%" ")".format(persentase_alfa))

students = ["Pram", "Dita", "Adit", "Mrap", "Raidan","Pramud","DeDita"]
absensi_siswa(students)


import contextlib
import random

def do_log(msg):
    print(("    " * LOG_INDENT) + msg)

def no_log(msg):
    pass

log = do_log
LOG_INDENT = 0

@contextlib.contextmanager
def indent_log():
    global LOG_INDENT
    LOG_INDENT += 1
    yield
    LOG_INDENT -= 1

@contextlib.contextmanager
def suppress_log():
    global log
    orig_log = log
    log = no_log
    yield
    log = orig_log

def draw(n=30):
    """Draw a sample of 'n' different numbers in the range [1, 60]."""
    return set(random.sample(xrange(1, 61), n))

def str_to_mask(mask_str, hit_symbol="X"):
    """Convert a string representing a card mask to a list of booleans."""
    return [char == hit_symbol for char in mask_str]

def mask_to_str(mask, hit_symbol="X", miss_symbol="-"):
    """Inverse of str_to_mask()."""
    return "".join(hit_symbol if m else miss_symbol for m in mask)

class Card(object):
    def __init__(self, nums):
        self.nums = list(nums)

    def __repr__(self):
        return repr(self.nums)

    def hits(self, draw):
        """List of booleans indicating whether each cell's number is part of the 'draw'."""
        return [hit in draw for hit in self.nums]
        #raise NotImplementedError(">>> your code goes here <<<")

class Prize(object):
    def __init__(self, value, mask):
        self.value = value
        self.mask = mask

    def __repr__(self):
        return "{} (value={})".format(mask_to_str(self.mask), self.value)

    def check(self, card_hits):
        """True iff the given 'card_hits' list contains this prize."""
        if self.mask == card_hits:
            return True
        return False
        #raise NotImplementedError(">>> your code goes here <<<")

class Game(object):
    def __init__(self, prizes=()):
        self.prizes = list(prizes)

class Player(object):
    def __init__(self, game, cards, balance=100):
        self.game = game
        self.cards = cards
        self.balance = balance

    def play(self, bet=1):
        self.place_bet(bet)
        nums = draw()
        log("Draw: {}".format(sorted(nums)))
        prizes_won = list(self.check_cards(nums))
        if len(prizes_won) > 0:
            log("Awarding prizes:")
            with indent_log():
                for prize in prizes_won:
                    self.award_winnings(prize, bet)
        log("Balance after play: {}".format(self.balance))
        return prizes_won

    def check_cards(self, nums):
        """Verify prizes against all cards and return an iterable of all prizes won."""
        for card in self.cards:
            log("Checking card: {}".format(card))
            card_hits = card.hits(nums)
            with indent_log():
                log("Card hits: {}".format(mask_to_str(card_hits)))
                for prize in self.game.prizes:
                    log("Checking prize: {}".format(prize))
                    if prize.check(card_hits):
                        with indent_log():
                            log("Prize won!")
                            yield prize
        #raise NotImplementedError(">>> your code goes here <<<")

    def check_card(self, card, nums):
        """Verify prizes against a given card and return an iterable of all prizes won."""
        log("Checking card: {}".format(card))
        card_hits = card.hits(nums)
        with indent_log():
            log("Card hits: {}".format(mask_to_str(card_hits)))
            for prize in self.game.prizes:
                log("Checking prize: {}".format(prize))
                if prize.check(card_hits):
                    with indent_log():
                        log("Prize won!")
                        yield prize

    def place_bet(self, bet):
        log("Placing bet: {}".format(bet))
        self.balance * bet
        #raise NotImplementedError(">>> your code goes here <<<")

    def award_winnings(self, prize, bet):
        log("Awarding winnings for {} with bet {}.".format(prize, bet))
        self.add_balance(bet)
        #raise NotImplementedError(">>> your code goes here <<<")

    def add_balance(self, delta):
        new_balance = self.balance + delta
        log("Balance change: {} {:+d} => {}".format(self.balance, delta, new_balance))
        if new_balance < 0.0:
            raise ValueError("attempting to set negative balance")
        self.balance = new_balance

# Global list of bingo prizes.
PRIZES = [
    Prize(
        value=2000,
        mask=str_to_mask(
            "XXXXX"
            "XXXXX"
            "XXXXX"
        ),
    ),
    Prize(
        value=200,
        mask=str_to_mask(
            "X---X"
            "XXXXX"
            "X---X"
        ),
    ),
    Prize(
        value=20,
        mask=str_to_mask(
            "X---X"
            "X---X"
            "X---X"
        ),
    ),
    Prize(
        value=10,
        mask=str_to_mask(
            "--X--"
            "-X-X-"
            "X---X"
        ),
    ),
    Prize(
        value=10,
        mask=str_to_mask(
            "-----"
            "XXXXX"
            "-----"
        ),
    ),
    Prize(
        value=5,
        mask=str_to_mask(
            "X---X"
            "-----"
            "X---X"
        ),
    ),
]

def init(seed=None):
    random.seed(seed)
    return Player(
        game=Game(prizes=PRIZES),
        cards=[Card(draw(15)) for _ in xrange(5)],
        balance=1000,
    )

def main(nplays=287657):
    player = init(seed=0)
    with suppress_log():
        for _ in xrange(nplays-1):
            player.play(bet=random.choice([1, 2, 3]))
    player.play(bet=random.choice([1, 2, 3]))
    return player

if __name__ == "__main__":
    main()