#===============================================================================
# acdumo.py
#===============================================================================

# Imports ======================================================================

import matplotlib; matplotlib.use('agg')
import misaka as m
import os
import pandas as pd
import statistics
import seaborn as sns

from argparse import ArgumentParser
from datetime import datetime, timedelta
from operator import itemgetter
from yahoofinancials import YahooFinancials

# Constants ====================================================================

TICKERS = ['SPY', 'TLT', 'VSS', 'SCZ']
BONDS = 'TLT'
REPORT = """Date
====
{date}

Prices
======
![prices plot](prices.svg)

One Month Returns
=================
| Ticker | Return |
| ------ | ------ |
{returns}

Signals
=======
| Ticker | Signal |
| ------ | ------ |
{signals}

Strategy
========
{strategy}
"""

# Functions ====================================================================

def download_historical_price_data(date, *tickers, freq: str = 'monthly'):
    yahoo_financials = YahooFinancials(tickers)
    if freq == 'monthly':
        days = 217
    elif freq == 'weekly':
        days = 186

    def download_into_dfs(buffer=0):
        historical_price_data = yahoo_financials.get_historical_price_data(
            (date - timedelta(days=days)).strftime('%Y-%m-%d'),
            (date + timedelta(days=buffer)).strftime('%Y-%m-%d'),
            freq
        )
        return [
            pd.DataFrame(historical_price_data[ticker]['prices'][::-1])
            for ticker in tickers
        ]

    dfs = download_into_dfs()
    if freq == 'monthly':
        buffer = 0
        while date.strftime('%Y-%m-01') not in set(dfs[0].formatted_date):
            buffer += 1
            dfs = download_into_dfs(buffer=buffer)
    elif freq == 'weekly':
        dfs = [df.drop(0) for df in dfs]
    return {
        ticker: (
            df[
                [
                    d.endswith('-01') if freq == 'monthly' else True
                    for d in df.formatted_date
                ]
            ]
            .reset_index().dropna()
        )
        for ticker, df in zip(tickers, dfs)
    }

def plot_prices(historical_price_data: dict, file_name: str):
    hpd = pd.concat(
        df.assign(
            normalized_adjclose=df.adjclose / df.adjclose.iloc[-1],
            ticker=[ticker] * len(df.index)
        )[['formatted_date', 'normalized_adjclose', 'ticker']]
        for ticker, df in reversed(tuple(historical_price_data.items()))
    )
    ax = sns.lineplot(
        x='formatted_date',
        y='normalized_adjclose',
        hue='ticker',
        data=hpd[::-1]
    )
    ax.set_xlabel('')
    ax.set_ylabel(f'adjclose relative to {hpd.formatted_date.iloc[-1]}')
    ax.set_xticklabels(labels=hpd.formatted_date[::-1], rotation=30, ha='right')
    if len(ax.get_xticklabels()) > 8:
        for ind, label in enumerate(ax.get_xticklabels()):
            if ind % 4 == 0:
                label.set_visible(True)
            else:
                label.set_visible(False)
    fig = ax.get_figure()
    fig.tight_layout()
    fig.savefig(file_name, format='svg')
    fig.clf()

def compute_one_month_return(df, freq: str = 'monthly'):
    if freq == 'monthly':
        return df.adjclose[0] / df.adjclose[1] - 1
    elif freq == 'weekly':
        return (
            df.adjclose[0] / df.adjclose[4] - 1
        )

def compute_one_month_returns(
    historical_price_data: dict,
    freq: str = 'monthly'
):
    return {
        ticker: compute_one_month_return(df, freq=freq)
        for ticker, df in historical_price_data.items()
    }

def compute_signal(df, freq: str = 'monthly'):
    if freq == 'monthly':
        return sum(df.adjclose[0] / df.adjclose[x] - 1 for x in (1, 3, 6))
    elif freq == 'weekly':
        current_month_price = df.adjclose[0]
        return sum(
            current_month_price / df.adjclose[x] - 1
            for x in (4, 12, 24)
        )

def compute_signals(historical_price_data: dict, freq: str = 'monthly'):
    return {
        ticker: compute_signal(df, freq=freq)
        for ticker, df in historical_price_data.items()
    }

def decide_strategy(signals: dict, bonds: str = BONDS):
    signals_sans_bonds = dict((t, s) for t, s in signals.items() if t != bonds)
    if any(s > 0 for s in signals_sans_bonds.values()):
        choice = max(signals_sans_bonds.items(), key=itemgetter(1))[0]
    else:
        choice = bonds
    return f'Buy/Hold {choice}'

def generate_report(date, returns: dict, signals: dict, strategy: str):
    return REPORT.format(
        date=date.strftime('%Y-%m-%d'),
        returns='\n'.join(
            f'|    {t} | {s*100:.3}% |' for t, s in returns.items()
        ),
        signals='\n'.join(
            f'|    {t} | {s*100:.4}% |' for t, s in signals.items()
        ),
        strategy=strategy
    )

def parse_arguments():
    parser = ArgumentParser(description='Accelerated Dual Momentum')
    parser.add_argument(
        'report_dir',
        metavar='<path/to/report/dir/>',
        nargs='?',
        help='write a HTML report'
    )
    parser.add_argument(
        '--date',
        metavar='<yyyy-mm-dd>',
        default=datetime.today().strftime('%Y-%m-%d'),
        help=f'date of interest (default: today)'
    )
    parser.add_argument(
        '--tickers',
        metavar='<TIC>',
        nargs='+',
        default=TICKERS,
        help=f"tickers to use (default: {' '.join(TICKERS)})"
    )
    parser.add_argument(
        '--bonds',
        metavar='<TIC>',
        default=BONDS,
        help=f"ticker representing bonds (default: {BONDS})"
    )
    parser.add_argument(
        '--frequency',
        choices=('monthly', 'weekly'),
        default='monthly',
        help='frequency of data to fetch (default: monthly)'
    )
    return parser.parse_args()

def main():
    args = parse_arguments()
    date = datetime.strptime(args.date, '%Y-%m-%d')
    if date > datetime.today():
        raise RuntimeError(
            "I can't predict the future! Choose an earlier date."
        )
    historical_price_data = download_historical_price_data(
        date, *args.tickers, freq=args.frequency
    )
    returns = compute_one_month_returns(
        historical_price_data, freq=args.frequency
    )
    signals = compute_signals(historical_price_data, freq=args.frequency)
    strategy = decide_strategy(signals, bonds=args.bonds)
    report_text = generate_report(date, returns, signals, strategy)
    print(report_text, end='')
    if args.report_dir:
        if not os.path.isdir(args.report_dir):
            os.mkdir(args.report_dir)
        for ticker, df in historical_price_data.items():
            df.to_csv(
                os.path.join(args.report_dir, f'{ticker}.csv'),
                index=False
            )
        plot_prices(
            historical_price_data,
            os.path.join(args.report_dir, 'prices.svg')
        )
        with open(os.path.join(args.report_dir, 'acdumo.html'), 'w') as f:
            f.write(m.html(report_text, extensions=['tables']))

# Execute ======================================================================

if __name__ == '__main__':
    main()


import asyncio
import serial
from serial.tools.list_ports import comports
from serial.serialutil import SerialException
from signal import SIGINT, SIGTERM

def initialize_port():
    """
    Initialize the serial port.
    :return:
    """
    plist = comports()
    selected = []
    print("Checking for serial ports....")
    print("Found:")
    for i, p in enumerate(plist):
        print("{}. {}".format(i, p))
        if 'usbserial' in p.device:
            selected.append(p)
    print(selected)
    if len(selected) == 1:
        print("Selecting {}".format(selected[0]))
        return serial.Serial(selected[0].device, 500000)
    else:
        print("Could not find appropriate port.")
        return None

async def serial_task():
    """
    Async task for serial port monitoring.
    :return:
    """
    port = initialize_port()
    max_reconnects = 10
    reconnect_count = 0

    if port:
        while True:
            try:
                sdata = port.read(1024)
                print("Got {} chars of data".format(len(sdata)))
                await asyncio.sleep(0.01)
            except asyncio.CancelledError:
                port.close()
                break
            except:
                print("Serial port disconnected.")
                print("Trying to reconnect...")
                port = initialize_port()

                if port is None:
                    print("Failed to read.")
    else:
        pass

if __name__ == '__main__':
    loop = asyncio.get_event_loop()
    stask = loop.create_task(serial_task())
    try:
        loop.run_until_complete(stask)
    except KeyboardInterrupt as e:
        print("Caught keyboard interrupt. Canceling tasks...")
        stask.cancel()
    finally:
        loop.close()


from random import choice
def rockpaperScissors():
    choices = ["R","P","S"]
    player = input("choose an option: R, S, P\n").upper()
    money=True
    while money :
        if player in choices :
            computer = choice(choices)
            RPSdict ={"R":"Rock", "P":"Paper", "S":"Scissors"}
            print ("You chose: ", player, "computer chose: ", computer)
            print ("User(" + RPSdict[player]+ ") : CPU("+ RPSdict[computer]+")")
            if player == computer:
                print("It's a tie. we go again")
                player = input("choose an option: R, S, P\n").upper()
            else :
                if player == "R" and computer== "S":
                    print("player WINS! ")
                    money= False
                if player == "S" and computer== "R":
                    print("computer WINS! ")
                    money= False
                if player == "P" and computer== "R":
                    print ("player WINS! ")
                    money= False
                if player == "R" and computer== "P":
                    print ("computer WINS! ")
                    money= False
                if player == "S" and computer== "P":
                    print ("player WINS! ")
                    money= False
                if player == "P" and computer== "S":
                    print ("computer WINS! ")
                    money= False
        else :
          print("invalid option")
          player= input("choose an option: R, S, P\n").upper()
          continue

rockpaperScissors()


"""
Faça um programa que leia nome e peso de várias pessoas, guarde tudo em uma lista no fim mostre
quantos foram cadstrados
uma lista com os mais pesados
uma lista com os mais leves
"""
pessoas = list()
dados = list()
cont = 0
while True:
    dados.append(input('Diga o nome: '))
    dados.append(int(input('Diga o peso: ')))
    pessoas.append(dados[:])
    if cont == 0:
        pesado = leve = dados[1]
    else:
        if pesado < dados[1]:
            pesado = dados[1]
        elif leve > dados[1]:
            leve = dados[1]
    dados.clear()
    cont += 1
    continua = input('Deseja continuar: ').upper()
    if continua == 'N':
        break
for c in pessoas:
    if pesado == c[1]:
        print(c)
print(pessoas, pesado)


"""The base class for deriving types that require schema support.

.. image:: images/ontic_property.jpg

.. contents::

======
Usage
======

The **meta_type** module contains three classes that are used in the
definition and instantiation of object instances.  The root class is
:class:`CoreType`, which is derived from the Python :class:`dict`. The
primary feature of the :class:`CoreType` is provide the means to access
properties of an object as a *dict* key or as object attribute.

Derived from :class:`CoreType` is :class:`MetaType`, which provides the
interface for retrieving a schema from an object schema definition via the
:meth:`MetaType.get_schema()`.

The :class:`PropertySchema` is utilized to define a schema for a single
property. This includes setting data type, required, and other such common
schema definition conventions. See :ref:`property-schema-settings-table` for
details on the :class:`PropertySchema` settings available.

It would be a rare case that requires the use of :class:`CoreType` or
:class:`MetaType`. For the majority of cases, the use of
:class:`PropertySchema` is sufficient. With that in mind, the remainder of
this section will focus on the use of :class:`PropertySchema`

Creating Property Schema
-------------------------

For general purposes, consider utilizing :class:`ontic.schema_type.SchemaType`,
for defining complete models. However, if you need validators for individual
properties, then direct use of :class:`PropertySchema` is a solution.

There are a number of ways to create a :class:`PropertySchema`. Take a look
at :class:`PropertySchema` class documentation for a complete exposition on
the means of instantiating an instance.

The most straight forward way to create an instance of a
:class:`PropertySchema`:

>>> prop_schema = OnticProperty(name='x', type='str', required=True, min=3)
>>> assert prop_schema == {'regex': None, 'enum': None, 'min': 3, 'default': None, 'max': None,
...     'required': True, 'member_type': None, 'member_min': None,
...     'type': str, 'member_max': None, 'name': 'x'}

Demonstrated above is the creation of a property schema of type string. In
addition the property schema forces the value of the property to required and
of minimum length of 3.

Along with the schema settings explicitly set in the constructor, there are a
number of other property schema settings that may be utilized. These
additional settings can be viewed in the output of the *prop_schema* object.
For the details on the property schema settings, see
:ref:`property-schema-settings-table`.

A :class:`PropertySchema` can be created or modified dynamically. If done so,
then the final schema instance should be validated with the use of the method
:meth:`validate_property_schema`.

Utilizing Property Schema
--------------------------

Validation of a value utilizing the *prop_schema* created, is done with the
:meth:`validate_value` method.

>>> prop_schema = OnticProperty(name='some_prop', type='str', required=True)
>>> some_value = 'The cat is on the roof.'
>>> prop_schema.validate_value(value=some_value)
[]

:class:`validate_value` returns an empty list if there are no errors.

The *name* parameter of the :meth:`validate_value`, is used to construct
friendly error messages. For example:

>>> meta.validate_value(prop_schema, None)
['The value for "some_prop" is required.']

The following example demonstrates how a :class:`PropertySchema` being
instantiated with a dictionary. Subsequently a bad value is passed with
multiple validation errors.

>>> other_schema = OnticProperty({
...     'name': 'other_prop',
...     'type': 'str',
...     'max': 3,
...     'enum': {'fish', 'dog', 'cat'}
... })
>>> ret = other_schema.validate_value('frog')
>>> assert len(ret) == 2
>>> assert ret[0] == '''The value "frog" for "other_prop" not in enumeration ['cat', 'dog', 'fish'].'''
>>> assert ret[1] == '''The value of "frog" for "other_prop" fails max of 3.'''

.. _property-schema-settings-table:

Available Property Schema Settings
-----------------------------------

The following table gives a listing of the property schema settings that can
be used to define properties. Details on the schema settings are provided
after the table.

.. table:: Property Schema Settings

    ============ ========= ======== ========  =================================
    Name         Type      Default  Required  Enumeration
    ============ ========= ======== ========  =================================
    type         str       None     False     bool, complex, date,
                 type                         datetime, dict, float, int, list,
                                              None, set, str, time
    default      None      None     False
    required     bool      False    False
    enum         set       None     False
    min          complex   None     False
                 date
                 datetime
                 float
                 int
                 time
    max          complex   None     False
                 date
                 datetime
                 float
                 int
                 time
    regex        str       None     False
    member_type  str       None     False     bool, complex, date,
                 type                         datetime, dict, float, int, list,
                                              None, set, str, time
    member_min   complex   None     False
                 date
                 datetime
                 float
                 int
                 time
    member_max   complex   None     False
                 date
                 datetime
                 float
                 int
                 time
    ============ ========= ======== ========  =================================

*type*
    The *type* settings restricts a property to a known type. If no type is
    defined, then any value type may be assigned to the property.

    The type definition can be by type or by string name. Both ``{type=int}``
    and ``{type='int'}`` are valid examples of type declaration.
*default*
    If no default is applied, then the default value will be ``None``. If a
    default value is supplied, it will only be applied under two conditions.
    A default value is applied during instantiation of an object of type
    :class:`PropertySchema`, :class:`~ontic.schema_type.SchemaType`,
    or :class:`~ontic.ontic_type.OnticType`. The other case is when an
    instance of on of the given types is perfected via the methods
    :func:`perfect_property_schema`, :func:`~ontic.schema_type.perfect_schema`,
    or :func:`~ontic.ontic_type.perfect_object`.

    The default is not applied during validation.

    For the collection types (dict, list, and set), the default value is deep
    copied. This is done to ensure that there is no sharing of collection
    instances or values.
*required*
    A *PropertySchema* with a required setting of *True*, will fail
    validation if the property value is *None*.
*enum*
    An *enum* setting is a set of values that the property value must adhere
    to. If the *type* setting is provided, then the choices provided by
    *enum* must be of that type. If no *type* is provided, then the choices
    in the *enum* set may be of any type, even mixed type.
*min*
    The *min* setting has differing behavior, based on the *type* setting. If
    no *type* setting is provided, then *min* test will not occur. For the
    boundable types (strings and collections) the *min* setting will test that
    the value length is not less than the minimum. For the comparable types
    (numeric and chronological) the *min* setting will test that the
    value is not less than the minimum.
*max*
    The *max setting has differing behavior, based on the *type* setting. If
    no *type* setting is provided, the *max* test will not occur. For the
    boundable types (strings and collections) the *max* setting will test that
    the value length is not more than the maximum. For the comparable types
    (numeric and chronological) the *max* setting will test that the
    value is not more than the maximum.
*regex*
    The *regex* setting is only tested if the *type* or *member_type* setting
    is 'str' and the *regex* setting is not None. When active, the *regex*
    setting will be used to test the given string value.  If the property
    value is 'None', then no regex testing will be done.
*member_type*
    The *member_type* setting is used to restrict the value type for property
    *type* 'list' or 'set'. It does so ensuring that each member of the
    collection is of the type designated by *member_type*.

    The type definition can be by type or by string name. Both
    ``{member_type=int}`` and ``{member_type='int'}`` are valid examples of
    type declaration.
*member_min*
    The *member_min* setting has differing behavior, based on the
    *member_type* setting. If no *member_type* setting is provided, then
    *member_min* test will not occur. For the boundable types
    (strings and collections), the *member_min* setting will test that the
    value length is not less than the minimum. For the comparable types
    (numeric and chronological) the *member_minimum* setting will test
    that the value is not less than the minimum.
*member_max*
    The *member_max* setting has differing behavior, based on the
    *member_max* setting. If no *member_type* setting is provided,
    then *member_max* test will not occur. For the boundable types
    (strings and collections), the *member_max* setting will test that the
    value length is not more than the maximum. For the comparable types
    (numeric and chronological) the *member_max* setting will test
    that the value is not more than the maximum.

"""
from typing import NoReturn, Any

from ontic import meta
from ontic import validation_exception

class OnticProperty(meta.Meta):
    """A class to define a schema for a property."""

    ONTIC_SCHEMA = meta.Meta({
        'name': meta.Meta({
            'name': 'name',
            'type': str,
            'default': None,
            'required': True,
            'enum': None,
            'min': 1,
            'max': None,
            'regex': None,
            'member_type': None,
            'member_min': None,
            'member_max': None,
        }),
        'type': meta.Meta({
            'name': 'type',
            'type': (str, type),  # todo: raul - this could be restricted list
            'default': None,
            'required': False,
            'enum': meta.TYPE_SET + (None,),
            'min': None,
            'max': None,
            'regex': None,
            'member_type': None,
            'member_min': None,
            'member_max': None,
        }),
        'default': meta.Meta({
            'name': 'default',
            'type': None,
            'default': None,
            'required': False,
            'enum': None,
            'min': None,
            'max': None,
            'regex': None,
            'member_type': None,
            'member_min': None,
            'member_max': None,
        }),
        'required': meta.Meta({
            'name': 'required',
            'type': bool,
            'default': False,
            'required': False,
            'enum': None,
            'min': None,
            'max': None,
            'regex': None,
            'member_type': None,
            'member_min': None,
            'member_max': None,
        }),
        'enum': meta.Meta({
            'name': 'enum',
            'type': set,
            'default': None,
            'required': False,
            'enum': None,
            'min': None,
            'max': None,
            'regex': None,
            'member_type': None,
            'member_min': None,
            'member_max': None,
        }),
        'min': meta.Meta({
            'name': 'min',
            'type': tuple(meta.COMPARABLE_TYPES),
            'default': None,
            'required': False,
            'enum': None,
            'min': None,
            'max': None,
            'regex': None,
            'member_type': None,
            'member_min': None,
            'member_max': None,
        }),
        'max': meta.Meta({
            'name': 'max',
            'type': tuple(meta.COMPARABLE_TYPES),
            'default': None,
            'required': False,
            'enum': None,
            'min': None,
            'max': None,
            'regex': None,
            'member_type': None,
            'member_min': None,
            'member_max': None,
        }),
        'regex': meta.Meta({
            'name': 'regex',
            'type': str,
            'default': None,
            'required': False,
            'enum': None,
            'min': 1,
            'max': None,
            'regex': None,
            'member_type': None,
            'member_min': None,
            'member_max': None,
        }),
        'member_type': meta.Meta({
            'name': 'member_type',
            'type': (str, type),  # todo: raul - this could be restricted list
            #  subclass testing.
            'default': None,
            'required': False,
            'enum': meta.TYPE_SET + (None,),
            'min': None,
            'max': None,
            'regex': None,
            'member_type': None,
            'member_min': None,
            'member_max': None,
        }),
        'member_min': meta.Meta({
            'name': 'member_min',
            'type': tuple(meta.COMPARABLE_TYPES),
            'default': None,
            'required': False,
            'enum': None,
            'min': None,
            'max': None,
            'regex': None,
            'member_type': None,
            'member_min': None,
            'member_max': None,
        }),
        'member_max': meta.Meta({
            'name': 'member_max',
            'type': tuple(meta.COMPARABLE_TYPES),
            'default': None,
            'required': False,
            'enum': None,
            'min': None,
            'max': None,
            'regex': None,
            'member_type': None,
            'member_min': None,
            'member_max': None,
        }),
    })

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

        self.perfect()
        self.validate()

    def perfect(self) -> NoReturn:
        """Method to ensure the completeness of a given schema property.

        :rtype: None
        :raises ValueError: If the candidate_property_type is None, or not
            of type *OnticProperty*.
        """
        perfect_property(self)

    def validate(
            self,
            raise_validation_exception: bool = True) -> (None, list[str]):
        """Method to validate a property schema definition.

        :param raise_validation_exception: If True, then
            *validate_property_type* will throw a *ValueException* upon
            validation failure. If False, then a list of validation errors is
            returned. Defaults to True.
        :return: If no validation errors are found, then *None* is returned.
            If validation fails, then a list of the errors is returned if the
            *raise_validation_exception* is set to True.
        :raises ValueError: *the_candidate_schema_property* is not an
            :class:`OnticProperty`.
        :raises ValidationException: A property of *candidate_property_type*
            does not meet schema requirements.
        """
        return validate_property(self, raise_validation_exception)

    def validate_value(self,
                       value: Any,
                       raise_validation_exception: bool = False) -> NoReturn:
        """Method that validates a value against the current schema."""
        value_errors = meta.validate_value(self, value)

        if value_errors and raise_validation_exception:
            raise validation_exception.ValidationException(value_errors)

        return value_errors

def perfect_property(ontic_property: 'OnticProperty') -> NoReturn:
    """Method to ensure the completeness of a given schema property.

    This method ensures completeness by stripping out any properties that
    are not defined by the schema definition. In addition, for any schema
    properties that are not included, the method will add those
    properties to the default value.

    :param ontic_property: The OnticProperty that is to be clean and restricted.
    :type ontic_property: :class:`OnticProperty`
    :rtype: None
    :raises ValueError: If the ontic_property is None, or not of type
        *OnticProperty*.
    """
    if ontic_property is None:
        raise ValueError('"ontic_property" must be provided.')
    if not isinstance(ontic_property, OnticProperty):
        raise ValueError('"ontic_property" must be OnticProperty type.')

    property_schema = ontic_property.get_schema()

    # remove un-necessary properties.
    extra_properties = set(ontic_property.keys()) - set(property_schema.keys())
    for property_name in extra_properties:
        del ontic_property[property_name]

    if 'type' in ontic_property:
        _perfect_type_setting(ontic_property)
    else:
        ontic_property.type = None

    if 'member_type' in ontic_property:
        _perfect_member_type_setting(ontic_property)
    else:
        ontic_property.member_type = None

    # set the default for the given property.
    for property_name, property_schema in property_schema.items():
        if property_name not in ontic_property:
            ontic_property[property_name] = None
        if ontic_property[property_name] is None:
            ontic_property[property_name] = property_schema.default

def validate_property(
        ontic_property: 'OnticProperty',
        raise_validation_exception: bool = True) -> (None, list[str]):
    """Method to validate a property schema definition.

    :param ontic_property: The schema property to be validated.
    :param raise_validation_exception: If True, then *validate_property_type*
        will throw a *ValueException* upon validation failure. If False,
        then a list of validation errors is returned. Defaults to True.
    :return: If no validation errors are found, then *None* is
        returned. If validation fails, then a list of the errors is returned
        if the *raise_validation_exception* is set to True.
    :raises ValueError: *the_candidate_schema_property* is not an
        :class:`~ontic.ontic_type.OnticType`.
    :raises ValidationException: A property of *ontic_property*
        does not meet schema requirements.
    """
    if ontic_property is None:
        raise ValueError('"ontic_property" must be provided.')
    if not isinstance(ontic_property, OnticProperty):
        raise ValueError('"ontic_property" must be OnticProperty type.')

    value_errors = []

    for property_schema in ontic_property.get_schema().values():
        property_value = ontic_property.get(property_schema.name, None)

        # todo: raul - for now skip validating compound schemas.
        if (isinstance(property_value, type) and
                issubclass(property_value, meta.Meta)):
            continue

        value_errors.extend(
            meta.validate_value(
                property_schema, property_value))

    if value_errors and raise_validation_exception:
        raise validation_exception.ValidationException(value_errors)

    return value_errors

def _perfect_type_setting(ontic_property: 'OnticProperty') -> None:
    """Perfect the type setting for a given candidate property schema."""
    if ontic_property.type is None:
        return

    candidate_type = ontic_property.type
    # coerce type declarations as string to base types.
    if isinstance(candidate_type, str):
        try:
            candidate_type = ontic_property.type = meta.TYPE_MAP[
                candidate_type]
        except KeyError:
            raise ValueError('Illegal type declaration: %s' %
                             ontic_property.type)

    # ensure that the type declaration is valid
    is_supported_type = candidate_type in meta.TYPE_SET
    is_meta_schema_type = issubclass(candidate_type, meta.Meta)
    if not (is_supported_type or is_meta_schema_type):
        raise ValueError('Illegal type declaration: %s' % str(candidate_type))

def _perfect_member_type_setting(ontic_property: 'OnticProperty') -> NoReturn:
    """Perfect the member_type setting for a given candidate property schema."""
    if ontic_property.member_type is None:
        return

    candidate_type = ontic_property.member_type
    # coerce type declarations as string to base types.
    if isinstance(candidate_type, str):
        try:
            candidate_type = ontic_property.member_type = meta.TYPE_MAP[
                candidate_type]
        except KeyError:
            raise ValueError('Illegal member_type declaration: %s' %
                             ontic_property.member_type)

    # ensure that the type declaration is valid
    is_supported_type = candidate_type in meta.TYPE_SET
    is_meta_schema_type = issubclass(candidate_type, meta.Meta)
    if not (is_supported_type or is_meta_schema_type):
        raise ValueError('Illegal type declaration: %s' % candidate_type)


#!/usr/bin/python3

## Get an odd number iterator:
## 3 5 7 9 11 13 15 17...
def odd_iter():
    n = 3
    while True:
        yield n
        n = n + 2

## Return those divisible numbers
def not_divisible(n):
    return lambda x:x%n > 0

## Get a prime number iterator
def primes():
    yield 2
    it = odd_iter()
    for i in it:
        yield i
        it = filter(not_divisible(i), it)

## Test to get primes < 100
for i in primes():
    if i < 100:
        print(i)
    else:
        break


def inorder(n=1):
    if n>=N+1:
        return
    inorder(n*2)
    if n<N+1:
        print(arr[n][0],end='')
    inorder(n*2+1)

T = 10
for tc in range(1,1+T):
    N = int(input())
    arr=[[]for _ in range(N+1)]
    for _ in range(N):
        i, node, *args = input().split()
        arr[int(i)].append(node)

    print(f'#{tc}',end=' ')
    inorder()
    print()


from pydantic import BaseModel
from datetime import date

class Metrics(BaseModel):
    date: date
    channel: str
    country: str
    os: str
    impressions: int
    clicks: int
    installs: int
    spend: float
    revenue: float
    cpi: float

    class Config:
        orm_mode = True


# SWDV 610: Data Structures and Algorithms
# Produces a list of random integers, along with a binary heap and search tree
# with the values in that list

from random_int_list import random_int_list
from b_search_tree import BinarySearchTree
from b_heap_tree import BinaryHeapTree

def main():
    int_list = random_int_list()

    # This list is for demonstration
    # int_list = [380, 266, 475, 302, 783, 332, 936, 298, 23, 656]

    print('List:', int_list)
    input('Press <enter> to continue')

    b_heap_tree = BinaryHeapTree(int_list)
    print('\nBinary Heap Tree: ')
    print(b_heap_tree)
    input('Press <enter> to continue')

    b_search_tree = BinarySearchTree(int_list)
    print('\nBinary Search Tree, Preorder Traversal:')
    for node in b_search_tree:
        print(node.key(), end=' -> ')

    print('\n\nBinary Search Tree, Breadth-First Traversal:')
    for node in b_search_tree.breadth_first(b_search_tree.get_root()):
        print(node.key(), end=' -> ')
    print()

if __name__ == '__main__': main()

# Heap Tree output with demonstation list
# [0, 23, 266, 332, 298, 656, 475, 936, 380, 302, 783]

# Search Tree output with demonstration list
# 380 -> 266 -> 23 -> 302 -> 298 -> 332 -> 475 -> 783 -> 656 -> 936 ->
# 380 -> 266 -> 475 -> 23 -> 302 -> 783 -> 298 -> 332 -> 656 -> 936 ->


from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import tensorflow as tf
import numpy as np
from group_ops import query_ball_point, group_point

class GroupPointTest(tf.test.TestCase):

    def _test_grad(self, device):
        with tf.device(device):
            points = tf.constant(
                np.random.random((1, 128, 16)).astype(np.float32))
            xyz1 = tf.constant(np.random.random((1, 128, 3)).astype(np.float32))
            xyz2 = tf.constant(np.random.random((1, 8, 3)).astype(np.float32))
            radius = 0.3
            nsample = 32
            idx, _ = query_ball_point(radius, nsample, xyz1, xyz2)
            grouped_points = group_point(points, idx)

        err = tf.test.compute_gradient_error(points, (1, 128, 16),
                                             grouped_points, (1, 8, 32, 16))
        self.assertLess(err, 1e-4)

    def test_grad_gpu(self):
        self._test_grad('/gpu:0')

    def test_grad_cpu(self):
        self._test_grad('/cpu:0')

if __name__ == '__main__':
    tf.test.main()


from bearer import *
import re

URL = "https://us-4.rightscale.com/api/tags/by_tag"
service = "wfm"
env = "cfn02"
version = "06.07.00"

headers = {'X-API-Version': '1.5',
           'Content-Type': 'application/json',
           'X-Account': '106388',
           'Authorization': 'Bearer ' + token}

data = {"match_all": "true",
        "resource_type": "deployments",
        "tags": ["kronos:environment_name=" + env,
                 "kronos:shared_service_type=" + service,
                 "kronos:service_version=" + version]
        }

r = requests.post(URL, headers=headers, json=data)

# print(json.loads(r.content))

def server_array():
    my_list = []
    for i in (json.loads(r.content)):
        if 'tags' in i:
            array_href = i['links']
            for j in array_href:
                if j['rel'] == 'resource':
                    my_list.append('https://us-4.rightscale.com' + j['href'] + '/server_arrays')
    return my_list

print(server_array())


#!/usr/bin/env python3
import os
from datetime import datetime
import tempfile
from typing import List
import pynvim

class BlameLine:
    def __init__(self, commit=None, email=None, timestamp=None, lineno=None, line=None):
        self.commit = commit
        self.email = email
        self.timestamp = timestamp
        self.lineno = lineno
        self.line = line
    def __repr__(self):
        return f'|{self.commit}|{self.email}|{self.timestamp}|{self.lineno}|{self.line}|'
    @staticmethod
    def from_line(line):
        s = line.split(' ', maxsplit=1)
        commit = s[0].strip()
        s = s[1].split('(', maxsplit=1)
        s = s[1].split('>', maxsplit=1)
        email = s[0][1:].strip()
        date_format = "%Y-%m-%d %H:%M:%S %z"
        ts = datetime.strptime(s[1].lstrip()[:10+1+2+2+2+2+1+5], date_format)
        datestr = ts.strftime(date_format)
        s = s[1].split(datestr, maxsplit=1)[1].lstrip()
        s = s.split(')', maxsplit=1)
        lineno, line = s
        lineno, line = int(lineno), line[1:]
        return BlameLine(
            commit=commit,
            email=email,
            timestamp=ts,
            lineno=lineno,
            line=line,
        )

def get_buffer_blame(nvim, bnr, memo={}) -> List[BlameLine]:
    text = '\n'.join(bnr[:])
    if bnr.name not in memo:
        memo[bnr.name] = {}
    if text not in memo.get(bnr.name):
        fullpath = nvim.funcs.expand('%:p')
        d = os.path.dirname(fullpath)
        filename = os.path.basename(fullpath)

        fd, path = tempfile.mkstemp()

        os.write(fd, bytes(text, 'utf-8'))
        os.close(fd)

        with os.popen(f"git -C '{d}' blame '{filename}' --content '{path}' -e") as p:
            blame = p.read()
            lines = [BlameLine.from_line(line) for line in blame.split('\n') if line != ""]

        memo[text] = lines
    return memo[text]

@pynvim.plugin
class TestPlugin(object):

    def __init__(self, nvim):
        self.nvim = nvim
        self.ns_id = nvim.api.create_namespace('demo')
        self.blame_lines = {}
        self.marks = {}

    @pynvim.command("Glame", nargs="*", range="", sync=False)
    def testfunction(self, *args, **kwargs):
        self.update()

    @pynvim.autocmd('BufReadPost')
    def on_bufenter(self, *args, **kwargs):
        self.update()

    @pynvim.autocmd('TextChanged')
    def on_textchanged(self, *args, **kwargs):
        self.update()

    def update(self):
        bnr = self.nvim.current.buffer
        new_blame_lines = get_buffer_blame(self.nvim, bnr)
        if new_blame_lines == self.blame_lines.get(bnr.name):
            return
        self.blame_lines[bnr.name] = new_blame_lines

        for blame in self.blame_lines[bnr.name]:
            hl_id = f"DiffGutter_{blame.commit}"

            background = blame.commit[:6]
            red, green, blue = [int(background[i:i+2], base=16) for i in range(0, len(background), 2)]
            is_light = ( red + green + blue ) / 3 > 128
            text_color = 'black' if is_light else 'white'
            self.nvim.command(f"highlight {hl_id} guibg=#{background} guifg={text_color}")

            sign_id = f"DiffGutterSign_{blame.commit}"
            sign_text = blame.email.split('@')[0][:2]
            self.nvim.command(f"sign define {sign_id} texthl={hl_id} numhl={hl_id} text={sign_text}")
            signref = f'614{blame.lineno}'
            if signref in self.marks:
                self.nvim.command(f'sign unplace {signref}')
            self.marks[signref] = self.nvim.command(f'sign place {signref} line={blame.lineno} name={sign_id}') or True


# -*- coding: utf-8 -*-
"""
Created on Sat Oct 30 12:57:54 2021

@author: Gary

Used to create a full set of data, code and documentation that can be
the source of any use of the Open-FF products.  It is meant to
create an anchor that anyone working on the data can refer to.

Provided in the repo are:
    - data table pickles (for recreating analysis sets)
    - zips of filtered and full sets
    - copies of the translation tables used to created the database
    - a readme file that explains things like when the data were downloaded,
      when the data were compiled, what code version was used to create it,
      etc.
    - maybe a simple script to help user extract their own dataset from the
      pickles.
    - a csv file of hashes for most of the files in the repo.  These can
      be used to verify that the files have not been changed since creation.
"""

import os, shutil
from pathlib import Path
from hashlib import sha256
import pandas as pd
import core.Analysis_set as ana_set
import datetime
#import zipfile
import build_common
outdir = build_common.get_pickle_dir()
sources = build_common.get_data_dir()
trans_dir = build_common.get_transformed_dir()
tempfolder = './tmp/'

data_source = 'bulk'  # 'bulk' for typical processing
repo_name = 'v16_2023_03_18'
inc_zipped = False # should be true for major repositories

# data_source = 'NM_scrape_2022_05'
# repo_name = 'NM_scrape_2022_10_09'

if inc_zipped == False:
    repo_name = repo_name + '_min'

repo_dir = build_common.get_repo_dir() + repo_name
pklsource = 'currentData_pickles'

descriptive_notes = f""" This is an OpenFF data repository for the
bulk download of FracFocus from March 18, 2023

Created {datetime.date.today()}
CodeOcean version: 16
Since the version 16 release, this beta version incorporates:
 - added bgFederalWell and bgNativeAmericanWell that is derived from
    the PADUS-3 data set.

"""

# =============================================================================
# descriptive_notes = f""" This is an OpenFF data repository for the
# **New Mexico state-held** data set as scraped by OpenFF in May 2022.
#
# NOTE THAT THESE DATA ARE OLD AND MAY HAVE BEEN UPDATED BY THE INDUSTRY
# SINCE THE TIME THEY WERE SCRAPED.  USE THESE DATA WITH CARE AND DISCRETION.
#
# Created {datetime.date.today()}
# CodeOcean version: 15
# Since the version 15 release, this beta version incorporates:
#  - The field "rq_lbs" was added from the the ver 15 code.
#  - Cleaned up the bgCAS that were not striped of trailing spaces.
#  - Using new comptox batch cleanup routines. Old EPA names are no longer
#      available.
#  - bgLatitude and bgLongitude are now replaced with state-derived values
#      when errors are detected in the FracFocus versions of those varibales.
#      The field bgLocationSource indictates where the bg values come from.
#  - added bgFederalWell and bgNativeAmericanWell that is derived from
#     the PADUS-3 data set
#
# """
# =============================================================================

boilerplate = """This directory contains a data set generated by the Open-FF
project.
"""
print(descriptive_notes)
print(f'Including big zipped files? {inc_zipped}')
q = input(f'Data source is set to < {data_source} > and repo to {repo_name}. \n\n -- Enter "y" to start building process.  > ')
assert q=='y'

print(f'Starting creation of new Data Repo set: {repo_name}')
# create new directory
try:
    os.mkdir(repo_dir)
except:
    print(f'\nCreation of Directory <{repo_dir}> not allowed;  already created?')

# create and store README
with open(repo_dir+'/README.txt','w') as f:
    f.write(descriptive_notes+'\n')
    f.write(boilerplate)  # see below for the text

# # generate output csv's
# first try to delete any existing big files
try:
    os.remove(repo_dir+'/standard_filtered.zip')
    print('removed old std_filtered')
except:
    pass
try:
    os.remove(repo_dir+'/full_no_filter.zip')
    print('removed old full')
except:
    pass
try:
    os.remove(repo_dir+'/catalog_set.zip')
    print('removed old catalog_set')
except:
    pass

if inc_zipped:
    # now make the zipped sets
    ana_set.Standard_data_set().save_compressed()
    shutil.move(outdir+'standard_filtered.zip',repo_dir+'/standard_filtered.zip')

    ana_set.Full_set().save_compressed()
    shutil.move(outdir+'full_no_filter.zip',repo_dir+'/full_no_filter.zip')

    ana_set.Catalog_set().save_compressed()
    shutil.move(outdir+'catalog_set.zip',repo_dir+'/catalog_set.zip')

# copy pickles
pickledir = repo_dir+'/pickles'
try:
    os.mkdir(pickledir)
except:
    print(f'\nDirectory <{pickledir}> not created;  already created?')
flst = os.listdir(outdir+pklsource)
for fn in flst:
    if fn[-4:]=='.pkl':
        if not (fn[-7:]=='_df.pkl'):  # ignore pickled analysis sets
            shutil.copyfile(outdir+pklsource+'/'+fn, pickledir+'/'+fn)
            print(f'copied {fn}')

# copy curation files

cfiles = ['carrier_list_auto.csv',
          'carrier_list_curated.csv',
          'carrier_list_prob.csv']
files = ['CAS_curated.csv',
         'casing_curated.csv','company_xlate.csv','ST_api_without_pdf.csv',
         'ING_curated.csv','CAS_synonyms.csv',
         'CAS_synonyms_CompTox.csv','CAS_ref_and_names.csv',
         'tripwire_summary.csv','upload_dates.csv',
         'missing_values.csv']

cdir = 'curation_files'
os.mkdir(cdir) # made in the cwd.

for fn in files:
    print(f'  - zipping {fn}')
    shutil.copy(trans_dir+fn,cdir)
for fn in cfiles:
    print(f'  - zipping {fn}')
    shutil.copy(trans_dir+f'{data_source}/{fn}',cdir)
shutil.make_archive(os.path.join(repo_dir,cdir),'zip',cdir)
shutil.rmtree(cdir)

# copy CAS and CompTox reference files

cdir = 'CAS_ref_files'
sdir = r"C:\MyDocs\OpenFF\data\external_refs\CAS_ref_files"

cdir = 'CompTox_ref_files'
sdir = r"C:\MyDocs\OpenFF\data\external_refs\CompTox_ref_files"
shutil.make_archive(os.path.join(repo_dir,cdir),'zip',sdir)

# now create hashfile
#  this is a pandas df with all files (except the hashfile) in the "filename"
#  field and the sha256 hash of the file in the "sha256" field.
#  These hashes can be used to verify that the data is in the original state and
#  has not been modified.

print('\nMaking file hashes for validation')

to_hash = ['pickles/bgCAS.pkl',
           'pickles/cas_ing.pkl',
           'pickles/chemrecs.pkl',
           'pickles/companies.pkl',
           'pickles/disclosures.pkl',
           'curation_files.zip',
           'CAS_ref_files.zip',
           'CompTox_ref_files.zip',
           'README.txt',
           'standard_filtered.zip',
           'full_no_filter.zip',
           'catalog_set.zip']

fnout = []; fnhash = []
for fn in to_hash:
    path = Path(os.path.join(repo_dir,fn))
    if path.is_file():
        print('  -- '+fn)
        fnout.append(fn)
        with open(path,'rb') as f:
            fnhash.append(sha256(f.read()).hexdigest())
    else:
        print(f'  >> file not in repo: {fn} <<')
pd.DataFrame({'filename':fnout,'filehash':fnhash}).to_csv(repo_dir+'/filehash.csv',
                                                          index=False)

print(f'Repo creation completed: {repo_dir}')


class User:
    # declaring class attribute
    bank_name = "Dojo National Bank"
    def __init__(self, name, email_address):
        self.name = name
        self.email = email_address
        self.account_balance = 0
    # adding the deposit method
    def make_deposit(self,amount): #takes an argument that is the amount
    #of the deposit
        self.account_balance += amount
    # making a withdrawal from the account
    def make_withdrawal(self,amount):
        self.account_balance -= amount
    def display_user_balance(self): #print the user's name and account balance to the terminal
        print(f"User: {self.name}, Balance: ${self.account_balance}")
    def transfer_money(self, other_user, amount):
        self.account_balance -= amount
        self = other_user
        self.account_balance += amount
        return self

guido = User("Guido van Rossum","guido@email.com")
monty = User("Monty Python","pythonM@python.com")
tom = User("Tom Woodward","tom@email.com")

# 3 deposits for first user
guido.make_deposit(300)
guido.make_deposit(500)
guido.make_deposit(1000)
# withdrawal for first user
guido.make_withdrawal(400)
# print user balance for first user
guido.display_user_balance()

# second user with two deposits and two withdrawals
monty.make_deposit(400)
monty.make_deposit(500)
monty.make_withdrawal(300)
monty.make_withdrawal(500)
# display second user balance
monty.display_user_balance()

# make 1 deposit and 3 withdrawals for third user
tom.make_deposit(1000)
tom.make_withdrawal(300)
tom.make_withdrawal(300)
tom.make_withdrawal(300)
# display third user balance
tom.display_user_balance()

# transfer funds from first user to third user
guido.transfer_money(tom,200)
# print both users account balances
guido.display_user_balance()
tom.display_user_balance()


from __future__ import print_function
#cat ../phenix_index.htm | grep '
' | grep -v '
 list1.dat
all_lines=[]
txt=open('../../../doc/phenix_index.html').read()
txt=txt.replace("
","\n
")
txt=txt.replace("
","\n
")
txt=txt.replace("
","
")
txt=txt.replace("
<a","
-1 and not line.find("
-1:
    all_lines.append(line.replace("
","").replace("\n",""))

text=open("good_list").read()
good_lines=text.split("\n")
f=open('all_list','w')
for line in all_lines:
  f.write(line+"\n")
  if line and line.replace(" ","") and not line in good_lines:
     print(line)


#  Shop.py was created by Redjumpman for Redbot
#  This will create a data folder with 3 JSON files and 1 logger
#  The logger will contain information for admin use
import uuid
import discord
import os
import logging
import time
from operator import itemgetter
from discord.ext import commands
from .utils.dataIO import fileIO
from __main__ import send_cmd_help
from .utils import checks
from datetime import datetime
try:   # Check if Tabulate is installed
    from tabulate import tabulate
    tabulateAvailable = True
except:
    tabulateAvailable = False

class Shop:
    """Allows you to purchase items created by the Admins with your credits"""
    # We have to define all the different files were going to load and save
    def __init__(self, bot):
        self.bot = bot
        self.players = fileIO("data/shop/players.json", "load")
        self.shopsys = fileIO("data/shop/shop.json", "load")
        self.pending = fileIO("data/shop/pending.json", "load")
        self.config = fileIO("data/shop/config.json", "load")

    @commands.command(pass_context=True, no_pm=True)
    async def inventory(self, ctx):
        """Shows a list of items you have purchased"""
        user = ctx.message.author
        if user.id in self.players:
            if not self.players[user.id]["Inventory"]:
                await self.bot.say("You have not purchased any items for me to display")
            else:
                    column1 = [subdict["Item Name"] for subdict in self.players[user.id]["Inventory"].values()]
                    column2 = [subdict["Item Quantity"] for subdict in self.players[user.id]["Inventory"].values()]
                    m = list(zip(column1, column2))
                    m.sort()
                    t = tabulate(m, headers=["Item Name", "Item Quantity"])
                    header = "```"
                    header += self.bordered("I N V E N T O R Y")
                    header += "```"
                    if self.config["Inventory Output"] == "Whisper":
                        await self.bot.whisper(header + "```\n" + t + "```")
                    elif self.config["Inventory Output"] == "Chat":
                        await self.bot.say(header + "```\n" + t + "```")
                    else:
                        await self.bot.whisper(header + "```\n" + t + "```")
        else:
            await self.bot.say("You need to join the shop. Use the `beemoshop join` command.")

    @commands.group(pass_context=True, no_pm=True)
    async def shop(self, ctx):
        """Shop Commands. Use !help Shop for other command groups"""

        if ctx.invoked_subcommand is None:
            await send_cmd_help(ctx)

    # We want to seperate the store so it doesn't have a shop prefix
    @shop.command(name="list", pass_context=True)
    async def _list_shop(self, ctx):
        """Shows a list of items that can be purchased"""
        shop_name = self.config["Shop Name"]
        column1 = [subdict["Item Name"] for subdict in self.shopsys.values()]
        column2 = [subdict["Item Cost"] for subdict in self.shopsys.values()]
        print(str(column1))
        if not column1:
            await self.bot.say("There are no items for sale in the shop.")
        else:
            m = list(zip(column1, column2))
            if self.config["Sort Method"] == "Alphabet":
                m = sorted(m)
            elif self.config["Sort Method"] == "Lowest":
                m = sorted(m, key=itemgetter(1), reverse=True)
            elif self.config["Sort Method"] == "Highest":
                m = sorted(m, key=itemgetter(1))
            t = tabulate(m, headers=["Item Name", "Item Cost"])
            header = "```"
            header += self.bordered(shop_name + " Store Listings")
            header += "```"
            if len(t) > 2000:
                first_msg1, first_msg2 = column1[::2], column1[1::2]
                second_msg1, second_msg2 = column2[::2], column2[1::2]
                m1 = list(zip(first_msg1, second_msg1))
                m2 = list(zip(first_msg2, second_msg2))
                if self.config["Sort Method"] == "Alphabet":
                    sorted(m1)
                    sorted(m2)
                elif self.config["Sort Method"] == "Lowest":
                    m1 = sorted(m1, key=itemgetter(1))
                    m2 = sorted(m2, key=itemgetter(1))
                elif self.config["Sort Method"] == "Highest":
                    m1 = sorted(m1, key=itemgetter(1), reverse=True)
                    m2 = sorted(m2, key=itemgetter(1), reverse=True)
                t1 = tabulate(m1, headers=["Item Name", "Item Cost"])
                t2 = tabulate(m2, headers=["Item Name", "Item Cost"])
                if self.config["Store Output"] == "Whisper":
                    await self.bot.whisper(header + "```\n" + t1 + "```")
                    await self.bot.whisper("```" + t2 + "```")
                elif self.config["Store Output"] == "Chat":
                    await self.bot.say(header + "```\n" + t1 + "```")
                    await self.bot.say("```" + t2 + "```")
                else:
                    await self.bot.whisper(header + "```\n" + t1 + "```")
                    await self.bot.whisper("```" + t2 + "```")
            else:
                if self.config["Store Output"] == "Whisper":
                    await self.bot.whisper(header + "```\n" + t + "```")
                elif self.config["Store Output"] == "Chat":
                    await self.bot.say(header + "```\n" + t + "```")
                else:
                    await self.bot.whisper(header + "```\n" + t + "```")

    @shop.command(name="add", pass_context=True, no_pm=True)
    @checks.admin_or_permissions(manage_server=True)
    async def _add_shop(self, ctx, cost: int, *, itemname):
        """Adds an item to the shop list. Max 100 items"""
        if self.config["Shop Items"] < 100:
            self.config["Shop Items"] += 1
            fileIO("data/shop/config.json", "save", self.config)
            shop_name = self.config["Shop Name"]
            self.shopsys[itemname] = {"Item Name": itemname, "Item Cost": cost}
            fileIO("data/shop/shop.json", "save", self.shopsys)
            item_count = len(list(self.shopsys.keys()))
            await self.bot.say("```{} has been added to {} shop for purchase.\nThere is now {} items for sale in the store.```".format(itemname, shop_name, str(item_count)))
        else:
            await self.bot.say("You can only have 100 items for sale in the store.\nDelete an item to add more.")

    @shop.command(name="remove", pass_context=True, no_pm=True)
    @checks.admin_or_permissions(manage_server=True)
    async def _remove_shop(self, ctx, *, itemname):
        """Removes an item from the shop list"""
        shop_name = self.config["Shop Name"]
        if itemname in self.shopsys:
            self.config["Shop Items"] -= 1
            fileIO("data/shop/config.json", "save", self.config)
            del self.shopsys[itemname]
            fileIO("data/shop/shop.json", "save", self.shopsys)
            await self.bot.say("```{} has been removed from {} shop.```".format(itemname, shop_name))
        else:
            await self.bot.say("That item is not in {}'s store listings".format(shop_name))

    @shop.command(name="redeem", pass_context=True, no_pm=True)
    async def _redeem_shop(self, ctx, *, itemname):
        """Sends a request to redeem an item"""
        user = ctx.message.author
        time_now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        role = self.config["Shop Role"]
        if self.inventory_item_check(user.id, itemname):
            confirmation_number = str(uuid.uuid4())
            self.pending[confirmation_number] = {"Confirmation Number": confirmation_number,
                                                 "Time Stamp": time_now,
                                                 "Name": user.name,
                                                 "ID": user.id,
                                                 "Item": itemname}
            fileIO("data/shop/pending.json", "save", self.pending)
            self.inventory_remove(user.id, itemname)
            if self.config["Shop Notify"]:
                names = self.role_check(role, ctx)
                destinations = [m for m in ctx.message.server.members if m.name in names]
                for destination in destinations:
                    await self.bot.send_message(destination, "{} was added to the pending list by {}.".format(itemname, user.name))
                await self.bot.say("```{} has been added to pending list. Your confirmation number is {}.```".format(itemname, confirmation_number))
            await self.bot.say("```{} has been added to pending list. Your confirmation number is {}.```".format(itemname, confirmation_number))
        else:
            await self.bot.say("You do not have that item to redeem")

    @shop.command(name="buy", pass_context=True, no_pm=True)
    async def _buy_shop(self, ctx, *, itemname):
        """Buy an item from the store list"""
        shop_name = self.config["Shop Name"]
        user = ctx.message.author
        if self.config["Shop Open"]:
            if self.inventory_check(user.id):
                if itemname in self.shopsys:
                    points = self.shopsys[itemname]["Item Cost"]
                    if self.account_check(user):
                        if self.enough_points(user, points):
                            points = self.shopsys[itemname]["Item Cost"]
                            self.inventory_add(user.id, itemname)
                            bank = self.bot.get_cog("Economy").bank
                            bank.withdraw_credits(user, points)
                            await self.bot.say("```You have purchased a {} for {} credits.\n{} has been added to your inventory.```".format(itemname, str(points), itemname))
                        else:
                            await self.bot.say("You don't have enough credits to purchase this item.")
                    else:
                        await self.bot.say("You do not have a bank account.")
                else:
                    await self.bot.say("This item is not in the shop.")
            else:
                await self.bot.say("You need to join the {} shop to purchase items. Example: beemoshop join".format(shop_name))
        else:
            await self.bot.say("{} shop is currently closed.".format(shop_name))

    @shop.command(name="gift", pass_context=True, no_pm=True)
    async def _gift_shop(self, ctx, user: discord.Member, *, itemname):
        """Send a gift in your inventory to another member"""
        author = ctx.message.author
        if author == user:
            await self.bot.say("You can't give an item to yourself.")
            return
        if len(itemname) < 0:
            await self.bot.say("You need to tell me what you want to transfer.")
            return
        if user.id in self.players:
            if self.inventory_item_check(author.id, itemname):
                if self.inventory_item_amount(author.id, itemname):
                    nametwo = self.shopsys[itemname]["Item Name"]
                    self.inventory_remove(author.id, itemname)
                    self.inventory_add(user.id, itemname)
                    logger.info("{}({}) gifted a {} item to {}({})".format(author.name, author.id, itemname, user.name, user.id))
                    await self.bot.say("```I have gifted {} to {}'s inventory```".format(nametwo, user.name))
                else:
                    await self.bot.say("You currently don't own any of these.")
            else:
                await self.bot.say("You do not own this shop item.")
        else:
            shop_name = self.config["Shop Name"]
            await self.bot.say("I cant find a user with that name." +
                               " Check to see if that user has joined {} shop. They need to type beemoshop join before they can recieve a gift.".format(shop_name))

    @shop.command(name="trade", pass_context=True, no_pm=True)
    async def _trade_shop(self, ctx, user: discord.Member, *, tradeoffer: str):
        """Requests a trade with another shop member"""
        author = ctx.message.author
        if author.id in self.players:
            if user.id in self.players:
                if not self.players[user.id]["Block Trades"]:
                    if await self.check_cooldowns(user.id):
                        if tradeoffer in self.players[author.id]["Inventory"]:
                            await self.bot.say("{} requests a trade with {}. Do you wish to trade for {}?".format(author.mention, user.mention, tradeoffer))
                            answer = await self.bot.wait_for_message(timeout=15, author=user)
                            if not answer:
                                await self.bot.say("No response. Cancelling trade with {}.".format(user.name))
                            elif answer.content.title() == "No":
                                await self.bot.say("{} has rejected your trade.".format(user.name))
                            elif answer.content.title() == "Yes":
                                await self.bot.say("Please say which item you would like to trade.")
                                response = await self.bot.wait_for_message(timeout=15, author=user)
                                if not response:
                                    await self.bot.say("No response. Cancelling trade with {}.".format(user.name))
                                elif response.content.title() in self.players[user.id]["Inventory"]:
                                    await self.bot.say("{} has offered {}, do you wish to accept this trade, {}?".format(user.mention, response.content, author.mention))
                                    reply = await self.bot.wait_for_message(timeout=15, author=author)
                                    if not reply:
                                        await self.bot.say("No response. Cancelling trade with {}.".format(user.name))
                                    elif reply.content.title() == "No" or reply.content.title() == "Cancel":
                                        await self.bot.say("Trade Rejected. Cancelling trade.")
                                    elif reply.content.title() == "Yes" or reply.content.title() == "Accept":
                                        self.inventory_remove(author.id, tradeoffer)
                                        self.inventory_remove(user.id, response.content.title())
                                        self.inventory_add(user.id, tradeoffer)
                                        self.inventory_add(author.id, response.content.title())
                                        await self.bot.say("Trading items... {} recieved {}, and {} recieved {}.".format(author.mention, response.content, user.mention, tradeoffer))
                                        await self.bot.say("Trade complete.")
                                    else:
                                        await self.bot.say("Invalid response. Cancelling trade with {}.".format(user.name))
                                else:
                                    await self.bot.say("You don't have this item. Cancelling trade.")
                            else:
                                await self.bot.say("Invalid response. Cancelling trade with {}.".format(user.name))
                        else:
                            await self.bot.say("You don't have this item. Cancelling trade.")
                else:
                    await self.bot.say("This player is currently blocking trades.")
            else:
                await self.bot.say("This person is not a member of the shop.")
        else:
            await self.bot.say("You need to join the shop before you can trade items.")

    @shop.command(name="join", pass_context=True, no_pm=True)
    async def _join_shop(self, ctx):
        """Adds you to the shop. Only need to do this once."""
        shop_name = self.config["Shop Name"]
        user = ctx.message.author
        if user.id not in self.players:
            self.players[user.id] = {}
            fileIO("data/shop/players.json", "save", self.players)
            self.players[user.id] = {"Inventory": {},
                                     "Block Trades": False,
                                     "Trade Cooldown": 0}
            fileIO("data/shop/players.json", "save", self.players)
            await self.bot.say("```You have joined {} shop. You can now buy items with credits.```".format(shop_name))
        else:
            await self.bot.say("```You have already a member of the {} shop```".format(shop_name))

    @shop.command(name="blocktrades", pass_context=True, no_pm=True)
    async def _blocktrades_shop(self, ctx, cooldown: int):
        """Toggles blocking trade requests on and off."""
        user = ctx.message.author
        if user.id in self.players:
            if self.players[user.id]["Block Trades"] is False:
                self.players[user.id]["Block Trades"] = True
                fileIO("data/shop/config.json", "save", self.config)
                await self.bot.say("Now blocking all trades")
            else:
                self.players[user.id]["Block Trades"] = False
                fileIO("data/shop/config.json", "save", self.config)
                await self.bot.say("Trades are now enabled.")

    @commands.group(pass_context=True, no_pm=True)
    async def setshop(self, ctx):
        """Shop configuration settings"""
        if ctx.invoked_subcommand is None:
            await send_cmd_help(ctx)

    @setshop.command(name="notify", pass_context=True, no_pm=True)
    @checks.admin_or_permissions(manage_server=True)
    async def _notify_setshop(self, ctx):
        """PM's all users with Shopkeeper role. Add this role to be notified.
        This command will toggle notifications on/off"""
        if self.config["Shop Notify"]:
            self.config["Shop Notify"] = not self.config["Shop Notify"]
            fileIO("data/shop/config.json", "save", self.config)
            await self.bot.say("Shop notifications are now OFF!")
        else:
            self.config["Shop Notify"] = True
            fileIO("data/shop/config.json", "save", self.config)
            await self.bot.say("Shop notifications are now ON!")

    @setshop.command(name="output", pass_context=True, no_pm=True)
    @checks.admin_or_permissions(manage_server=True)
    async def _output_setshop(self, ctx, command: str, output: str):
        """Sets the output to chat/whisper for inventory & shop list"""
        command = command.title()
        output = output.title()
        if command == "Shop":
            if output == "Chat":
                self.config["Store Output"] = "Chat"
                fileIO("data/shop/config.json", "save", self.config)
                await self.bot.say("Store listings will now display in chat.")
            elif output == "Whisper" or output == "Pm" or output == "Dm":
                self.config["Store Output"] = "Whisper"
                fileIO("data/shop/config.json", "save", self.config)
                await self.bot.say("Store listings will now display in whisper.")
            else:
                await self.bot.say("Output must be Chat or Whisper/DM/PM.")
        elif command == "Inventory":
            if output == "Chat":
                self.config["Inventory Output"] = "Chat"
                fileIO("data/shop/config.json", "save", self.config)
                await self.bot.say("Inventory will now display in chat.")
            elif output == "Whisper" or output == "Pm" or output == "Dm":
                self.config["Inventory Output"] = "Whisper"
                fileIO("data/shop/config.json", "save", self.config)
                await self.bot.say("Inventory will now display in whisper.")
            else:
                await self.bot.say("Output must be Chat or Whisper/DM/PM.")
        else:
            await self.bot.say("Command must be Shop or Inventory.")

    @setshop.command(name="tradecd", pass_context=True, no_pm=True)
    @checks.admin_or_permissions(manage_server=True)
    async def _tcd_setshop(self, ctx, cooldown: int):
        """Sets the cooldown timer for trading, in seconds."""
        self.config["Trade Cooldown"] = cooldown
        fileIO("data/shop/config.json", "save", self.config)
        await self.bot.say("Trading cooldown set to {}".format(self.time_format(cooldown)))

    @setshop.command(name="role", pass_context=True, no_pm=True)
    @checks.admin_or_permissions(manage_server=True)
    async def _role_sethop(self, ctx, *, rolename: str):
        """Change the name of the notification role"""
        self.config["Shop Role"] = rolename
        fileIO("data/shop/config.json", "save", self.config)
        await self.bot.say("Notify role set to {}. Assign this role to users you want to haven notifed of pending items.".format(rolename))

    @setshop.command(name="toggle", pass_context=True, no_pm=True)
    @checks.admin_or_permissions(manage_server=True)
    async def _toggle_setshop(self, ctx):
        """Opens and closes the shop"""
        shop_name = self.config["Shop Name"]
        if self.config["Shop Open"]:
            self.config["Shop Open"] = not self.config["Shop Open"]
            fileIO("data/shop/config.json", "save", self.config)
            await self.bot.say("The shop is now closed.")
        else:
            self.config["Shop Open"] = True
            fileIO("data/shop/config.json", "save", self.config)
            await self.bot.say("{} shop is now open for business!".format(shop_name))

    @setshop.command(name="sorting", pass_context=True, no_pm=True)
    @checks.admin_or_permissions(manage_server=True)
    async def _sort_setshop(self, ctx, choice: str):
        """Changes the sorting method for shop listings. Alphabet, Lowest, Highest"""
        choice = choice.title()
        if choice == "Alphabet":
            self.config["Sort Method"] = "Alphabet"
            fileIO("data/shop/config.json", "save", self.config)
            await self.bot.say("Changing sorting method to Alphabetical.")
        elif choice == "Lowest":
            self.config["Sort Method"] = "Lowest"
            fileIO("data/shop/config.json", "save", self.config)
            await self.bot.say("Setting sorting method to Lowest.")
        elif choice == "Highest":
            self.config["Sort Method"] = "Highest"
            fileIO("data/shop/config.json", "save", self.config)
            await self.bot.say("Setting sorting method to Highest.")
        else:
            await self.bot.say("Please choose Alphabet, Lowest, or Highest.")

    @setshop.command(name="name", pass_context=True, no_pm=True)
    @checks.admin_or_permissions(manage_server=True)
    async def _name_setshop(self, ctx, *, name):
        """Renames the shop"""
        shop_name = self.config["Shop Name"]
        if len(name) > 0:
            self.config["Shop Name"] = name
            fileIO("data/shop/config.json", "save", self.config)
            shop_name = self.config["Shop Name"]
            await self.bot.say("I have renamed the shop to {}.".format(shop_name))
        else:
            await self.bot.say("You need to enter a name for the shop.")

    @commands.group(name="pending", pass_context=True)
    async def _pending(self, ctx):
        """List of pending commands for redemable items"""
        if ctx.invoked_subcommand is None:
            await send_cmd_help(ctx)

    @_pending.command(pass_context=True, no_pm=True)
    async def check(self, ctx, *, code):
        """Checks if an item is on the pending list with conf #"""
        if code in self.pending:
            item = self.pending[code]["Item"]
            await self.bot.say("{} is still on the pending list.".format(item))
        else:
            await self.bot.say("This code is either not valid, or the item is no longer on the list.")

    @_pending.command(pass_context=True, no_pm=True)
    @checks.admin_or_permissions(manage_server=True)
    async def show(self, ctx):
        """Shows a list of items waiting to be redeemed"""
        if len(self.pending) > 0:
            keys = ["Item", "User Name", "User ID", "Time Stamp", "Confirmation Number"]
            items = []
            user_names = []
            user_ids = []
            time_stamps = []
            conf_nums = []
            for x in self.pending:
                items.append(self.pending[x]["Item"])
                user_names.append(self.pending[x]["Name"])
                time_stamps.append(self.pending[x]["Time Stamp"])
                conf_nums.append(self.pending[x]["Confirmation Number"])
                user_ids.append(self.pending[x]["ID"])
            table = list(zip(items, user_names, user_ids, time_stamps, conf_nums))
            t = tabulate(table, headers=keys, numalign="left")
            await self.bot.say("```" + t + "```")
        else:
            await self.bot.say("The pending list is empty.")

    @_pending.command(pass_context=True, no_pm=True)
    @checks.admin_or_permissions(manage_server=True)
    async def clear(self, ctx, *, number):
        """Allows you to clear one item by confirmation number"""
        if len(self.pending) > 0:
            if number in self.pending:
                name = self.pending[number]["Name"]
                item = self.pending[number]["Item"]
                del self.pending[number]
                fileIO("data/shop/pending.json", "save", self.pending)
                await self.bot.say("{}'s {} has been cleared from the pending list.'.".format(name, item))
            else:
                await self.bot.say("Could not find this code in the pending. It may have been cleared or does not exist.")
        else:
            await self.bot.say("The pending list is empty.")

    @_pending.command(pass_context=True, no_pm=True)
    @checks.admin_or_permissions(manage_server=True)
    async def clearall(self, ctx):
        """Clears all items from the pending list"""
        if len(self.pending) > 0:
            del self.pending
            self.pending = {}
            fileIO("data/shop/pending.json", "save", self.pending)
            await self.bot.say("Pending list now cleared.")
        else:
            await self.bot.say("Nothing in pending list to clear.")

    async def check_cooldowns(self, userid):
        if abs(self.players[userid]["Trade Cooldown"] - int(time.perf_counter())) >= self.config["Trade Cooldown"]:
            self.players[userid]["Trade Cooldown"] = int(time.perf_counter())
            fileIO("data/shop/players.json", "save", self.players)
            return True
        elif self.players[userid]["Trade Cooldown"] == 0:
            self.players[userid]["Trade Cooldown"] = int(time.perf_counter())
            fileIO("data/shop/players.json", "save", self.players)
            return True
        else:
            s = abs(self.players[userid]["Trade Cooldown"] - int(time.perf_counter()))
            seconds = abs(s - self.config["Trade Cooldown"])
            await self.bot.say("You must wait before trading again. You still have: {}".format(self.time_format(seconds)))
            return False

    def bordered(self, text):
        lines = text.splitlines()
        width = max(len(s) for s in lines)
        res = ["┌" + "─" * width + "┐"]
        for s in lines:
            res.append("│" + (s + " " * width)[:width] + "│")
        res.append("└" + "─" * width + "┘")
        return "\n".join(res)

    def time_format(self, seconds):
        m, s = divmod(seconds, 60)
        h, m = divmod(m, 60)
        if h > 0:
            msg = "{} hours, {} minutes, {} seconds".format(h, m, s)
        elif h == 0 and m > 0:
            msg = "{} minutes, {} seconds".format(m, s)
        elif m == 0 and h == 0 and s > 0:
            msg = "{} seconds".format(s)
        elif m == 0 and h == 0 and s == 0:
            msg = "No cooldown"
        return msg

    def account_check(self, uid):
        bank = self.bot.get_cog("Economy").bank
        if bank.account_exists(uid):
            return True
        else:
            return False

    def role_check(self, role, ctx):
        return [m.name for m in ctx.message.server.members if role.lower() in [str(r).lower() for r in m.roles] and str(m.status) != "offline"]

    def enough_points(self, uid, amount):
        bank = self.bot.get_cog("Economy").bank
        if self.account_check(uid):
            if bank.can_spend(uid, amount):
                return True
            else:
                return False

    def inventory_check(self, uid):
        if uid in self.players:
            return True
        else:
            return False

    def inventory_item_check(self, uid, itemname):
        if self.inventory_check(uid):
            if itemname in self.players[uid]["Inventory"]:
                return True
            else:
                return False
        else:
            False

    def inventory_item_amount(self, uid, itemname):
            if self.inventory_check(uid):
                if self.inventory_item_check(uid, itemname):
                    if self.players[uid]["Inventory"][itemname]["Item Quantity"] > 0:
                        return True
                    else:
                        return False
                else:
                    return False
            else:
                return False

    def inventory_add(self, uid, itemname):
        if self.inventory_check(uid):
            if self.inventory_item_check(uid, itemname):
                self.players[uid]["Inventory"][itemname]["Item Quantity"] += 1
                fileIO("data/shop/players.json", "save", self.players)
            else:
                self.players[uid]["Inventory"][itemname] = {"Item Name": itemname,
                                                            "Item Quantity": 1}
                fileIO("data/shop/players.json", "save", self.players)
        else:
            return False

    def inventory_remove(self, uid, itemname):
        if self.inventory_check(uid):
            if self.inventory_item_check(uid, itemname):
                self.players[uid]["Inventory"][itemname]["Item Quantity"] -= 1
                fileIO("data/shop/players.json", "save", self.players)
                if self.players[uid]["Inventory"][itemname]["Item Quantity"] < 1:
                    del self.players[uid]["Inventory"][itemname]
                    fileIO("data/shop/players.json", "save", self.players)
            else:
                return False
        else:
            return False

def check_folders():
    if not os.path.exists("data/shop"):
        print("Creating data/shop folder...")
        os.makedirs("data/shop")

def check_files():
    pconfig = {"Block Trades": False,
               "Trade Cooldown": 0}
    # For people using an old version of shop. Will be removed at a later date NOTE
    try:
        shop_dict = fileIO("data/shop/shop.json", "load")
        shop_item_count = len(list(shop_dict.keys()))
        system = {"Shop Name": "ARDENT",
                  "Shop Open": True,
                  "Shop Notify": False,
                  "Shop Items": shop_item_count,
                  "Shop Role": "Shopkeeper",
                  "Trade Cooldown": 30,
                  "Store Output": "Whisper",
                  "Inventory Output": "Whisper",
                  "Sort Method": "Alphabet"}
    except:
        system = {"Shop Name": "ARDENT",
                  "Shop Open": True,
                  "Shop Notify": False,
                  "Shop Items": 0,
                  "Trade Cooldown": 30,
                  "Store Message": "Whisper",
                  "Inventory Output": "Whisper",
                  "Shop Role": "Shopkeeper",
                  "Sort Method": "Alphabet"}

    f = "data/shop/pending.json"
    if not fileIO(f, "check"):
        print("Creating default shop pending.json...")
        fileIO(f, "save", {})

    f = "data/shop/shop.json"
    if not fileIO(f, "check"):
        print("Creating default shop shop.json...")
        fileIO(f, "save", {})

    f = "data/shop/players.json"
    if not fileIO(f, "check"):
        print("Adding shop player.json...")
        fileIO(f, "save", {})
    else:
        current = fileIO(f, "load")
        if current.keys() is not None:
            for player in current:
                    for key in pconfig.keys():
                        if key not in current[player].keys():
                            current[player][key] = pconfig[key]
                            print("Adding " + str(key) + " field to shop players.json")
                            fileIO(f, "save", current)
    f = "data/shop/config.json"
    if not fileIO(f, "check"):
        print("Adding shop config.json...")
        fileIO(f, "save", system)
    else:  # consistency check
        current = fileIO(f, "load")
        if current.keys() != system.keys():
            for key in system.keys():
                if key not in current.keys():
                    current[key] = system[key]
                    print("Adding " + str(key) +
                          " field to shop config.json")
            fileIO(f, "save", current)

def setup(bot):
    global logger
    check_folders()
    check_files()
    logger = logging.getLogger("shop")
    if logger.level == 0:  # Prevents the logger from being loaded again in case of module reload
        logger.setLevel(logging.INFO)
        handler = logging.FileHandler(filename="data/shop/shop.log", encoding="utf-8", mode="a")
        handler.setFormatter(logging.Formatter("%(asctime)s %(message)s", datefmt="[%d/%m/%Y %H:%M]"))
        logger.addHandler(handler)
    if tabulateAvailable:
        bot.add_cog(Shop(bot))
    else:
        raise RuntimeError("You need to run 'pip3 install tabulate'")


teen_code = {
    "pt": "Phát triển",
    "eny": "Em người yêu",
    "any": "Anh người yêu",
    "stt": "Status",
}
loop = True
while loop:
    k = input("enter Your Words ")
    if k in teen_code:
        print(teen_code[k])
    else:
        print("Not")
        n = input("Có muốn đóng góp k ?? (YES or NO)").upper()
        if n == "YES":
            l = input("nhập value: ")
            teen_code[k] = l
            print(teen_code)
        else:
            print("bạn muốn tiếp tục k ??")
    if k == "exit":
        loop = False


def getMostTask(task_list):
    available_task = 0
    last_end = 0
    for tup in task_list:
        start_time, end_time = tup
        if start_time < last_end:
            continue
        available_task += 1
        last_end = end_time

    return available_task

if __name__ == '__main__':
    TC = int(input())
    for T in range(1, TC + 1):

        N = int(input())
        task_list = []
        for i in range(N):
            a, b = map(int, input().split(' '))
            task_list.append((a,b))

        task_list = sorted(task_list, key=lambda item:item[1])
        res = getMostTask(task_list)
        print("#%d %d" % (T, res))


#!/usr/bin/env python
# -*- coding: utf-8 -*-
#************************************************************
#*                    Data Reduction                        *
#*          Salvador Ventura - Marcial Becerril             *
#************************************************************

import numpy as np
from matplotlib import pyplot as plt
from numpy import fft

import math
import glob
import os
import sys

from astropy.io import fits
from astropy.visualization import astropy_mpl_style
plt.style.use(astropy_mpl_style)
from astropy.utils.data import get_pkg_data_filename
from astropy.io import fits

from scipy import signal
from removeCR import remCosRay

class dataRed():

    # Getting the arrays  from the fits file in the path given
    def get_arrays_fits(self, path):
        data_fits = fits.getdata(path, ext=0)
        return data_fits

    def get_header_time_stream(self, path):
        hdul = fits.open(path)
        hdr = hdul[1].header

        I0 = hdr['IF0']
        Q0 = hdr['QF0']

        dqdf = hdr['DQDF']
        didf = hdr['DIDF']

        Fs = hdr['SAMPLERA']

        actual_temp = hdr['SAMPLETE']
        kid_number = hdr['TONE']
        input_att = hdr['INPUTATT']

        f0 = hdr["SYNTHFRE"]

        return I0,Q0,Fs,actual_temp,kid_number,input_att,didf,dqdf,f0

    def get_params_from_header(self, path):
        hdul = fits.open(path)
        hdr = hdul[1].header

        f0 = hdr["F0FOUND"]
        actual_temp = hdr['SAMPLETE']
        kid_number = hdr['TONE']
        input_att = hdr['INPUTATT']

        return f0,actual_temp,kid_number,input_att

    def get_vna_sweep(self,path):
        data_fits = self.get_arrays_fits(path)

        freqs = data_fits.field(0)
        I = data_fits.field(1)
        Q = data_fits.field(2)
        return freqs,I,Q

    """
    def get_sweep_hr(self,path):
        data_fits = self.get_arrays_fits(path)

        freqs_hr = data_fits.field(0)
        I_hr = data_fits.field(1)
        Q_hr = data_fits.field(2)

        return freqs_hr,I_hr,Q_hr
    """

    def get_full_vna(self,path):
        data_fits = self.get_arrays_fits(path)

        freq = data_fits.field(0)
        I = data_fits.field(1)
        Q = data_fits.field(2)

        mag = np.sqrt(I**2 + Q**2)

        return freq, mag, I, Q

    def smooth_IQ(self,I,Q):
        sI = savgol_filter(I,51,10)
        sQ = savgol_filter(Q,51,10)
       # fs21 = np.sqrt((fI**2)+(fQ**2))
        return sI,sQ

    def get_vna_sweep_parameters(self,freqs,I,Q,f0_fits):

        # FITS frequency
        f0_ind = np.argmin(np.abs(freqs - (f0_fits)))

        f0 = freqs[f0_ind]
        I0 = I[f0_ind]
        Q0 = Q[f0_ind]

        df = freqs[1]-freqs[0]

        try:
            #np.diff::::didf = (I[f0_ind + 1]-I[f0_ind])/(freqs[f0_ind + 1]-freqs[f0_ind])
            #np.gradient:::: (In+1 - In-1)/2df
            #didf = (I[f0_ind + 1]-I[f0_ind])/(freqs[f0_ind + 1]-freqs[f0_ind])
            #dqdf = (Q[f0_ind + 1]-Q[f0_ind])/(freqs[f0_ind + 1]-freqs[f0_ind])

            # Primero un filtro a la señal
            I = savgol_filter(I, 31, 3)
            Q = savgol_filter(Q, 31, 3)

            didf = np.gradient(I,freqs)[f0_ind]
            dqdf = np.gradient(Q,freqs)[f0_ind]

            #didf = (I[f0_ind + 1]-I[f0_ind])/(freqs[f0_ind + 1]-freqs[f0_ind])
            #dqdf = (Q[f0_ind + 1]-Q[f0_ind])/(freqs[f0_ind + 1]-freqs[f0_ind])

            check = True
        except:
            didf = 0
            dqdf = 0
            check = False

        return I0,Q0,didf,dqdf,check

    def df(self, I0,Q0,didf,dqdf,I,Q):
        vel = (didf**2)+(dqdf**2)
        df = [  ((( I0-I[i] ) * didf) + ( ( Q0-Q[i]) * dqdf )) / vel for i in range(len(I))  ]
        return df, vel

    def get_IQ_data_homo(self, path):
        data_fits = self.get_arrays_fits(path)

        I = [data_fits.field(2*i) for i in range(len(data_fits[0])/2)]
        Q = [data_fits.field(2*i+1) for i in range(len(data_fits[0])/2)]

        return I,Q

    def psd(self, df, Fs,isMean):
        psd = [signal.periodogram(df[i], Fs)[1]  for i in range(len(df))]
        freqs = signal.periodogram(df[0],Fs)[0]

        if isMean == True:
            psd_mean = 10*np.log10(np.average(psd,axis=0))
        else:
            psd_mean = 10*np.log10(np.median(psd,axis=0))

        return freqs, psd, psd_mean

    def get_homodyne_psd(self, path, didf, dqdf, check, sigma, cosRayFlag):

        I0,Q0,Fs,actual_temp,kid_number,input_att,didf_p,dqdf_p,f0 = self.get_header_time_stream(path)

        if check == False:
            didf = didf_p
            dqdf = dqdf_p

        step = 1/Fs
        I_old,Q_old = self.get_IQ_data_homo(path)

        time = np.arange(0,step*len(I_old[0]),step)

        I = []
        Q = []

        if cosRayFlag == True:
            # Remove Cosmic Ray
            cos_ray = remCosRay()
            for i in range(len(I_old)):

                time,n_I,flagRm_I = cos_ray.findCosmicRay(time,I_old[i],sigma)

                time,n_Q,flagRm_Q = cos_ray.findCosmicRay(time,Q_old[i],sigma)

                if flagRm_I == False and flagRm_Q == False:
                    I.append(n_I)
                    Q.append(n_Q)

        else:
            I = I_old
            Q = Q_old

        df,vel = self.df(I0,Q0,didf,dqdf,I,Q)

        freqs, psd, psd_mean = self.psd(df,Fs,cosRayFlag)

        df_avg = np.average(df,axis=0)
        I_avg = np.average(I,axis=0)
        Q_avg = np.average(Q,axis=0)

        time = np.linspace(0,step*len(I_avg),len(I_avg))

        return freqs, psd, psd_mean, time, I_avg, Q_avg, df_avg, kid_number, actual_temp, input_att, I,Q

    def validate_folder(self,path):
        if len(os.listdir(path) ) == 0:
            return False
        else:
            return True

    def get_sweep_psd_data(self, path, cosRayFlag):

        sweep_path, _, ONTemp, OFFTemp = self.get_each_path(path)

        content_flags = [sweep_path is not "",[True]*len(ONTemp),[True]*len(OFFTemp)]

        freq, sweep_i,sweep_q = [],[],[]
        freq_hr, sweep_i_hr, sweep_q_hr = [],[],[]
        psd, psd_low = [],[]
        psd_OFF, psd_low_OFF = [],[]
        f0_fits = 0
        params = []

        if content_flags[0]:
            freq, sweep_i, sweep_q = self.get_vna_sweep(os.path.join(path, sweep_path))
            f0_fits,actual_temp,kid_number,input_att = self.get_params_from_header(os.path.join(path, sweep_path))
            I0,Q0,didf,dqdf,check = self.get_vna_sweep_parameters(freq,sweep_i,sweep_q,f0_fits)
            params = [actual_temp,kid_number,input_att]

        if len(content_flags[1]) > 0:
            if len(content_flags[1]) > 1:
                path_on_up, path_on_low = self.split_array(ONTemp)

                #print "PSD LOW ON"
                psd_low = self.get_homodyne_psd(os.path.join(path, path_on_low),didf,dqdf,check,5,cosRayFlag)
            elif len(content_flags[1]) == 1:
                path_on_up = ONTemp[0][0]

            #print "PSD HIGH ON"
            psd = self.get_homodyne_psd(os.path.join(path, path_on_up),didf,dqdf,check,5,cosRayFlag)

        if len(content_flags[2]) > 0:
            if len(content_flags[2]) > 1:
                path_off_up, path_off_low = self.split_array(OFFTemp)

                #print "PSD LOW OFF"
                psd_low_OFF = self.get_homodyne_psd(os.path.join(path, path_off_low),didf,dqdf,check,5,cosRayFlag)
            elif len(content_flags[2]) == 1:
                path_off_up = OFFTemp[0][0]

            #print "PSD HIGH OFF"
            psd_OFF = self.get_homodyne_psd(os.path.join(path, path_off_up),didf,dqdf,check,5,cosRayFlag)

        return freq, sweep_i, sweep_q, psd, psd_low, psd_OFF, psd_low_OFF, f0_fits,params

    def get_sweep_hr(self, path):
        _,sweep_hr_path,_,_ = self.get_each_path(path)

        assert sweep_hr_path != "", "File of sweep at high resolution not founded"
        freq_hr, sweep_i_hr, sweep_q_hr = self.get_vna_sweep(os.path.join(path, sweep_hr_path))

        return freq_hr, sweep_i_hr, sweep_q_hr

    # Choose the newest version of the fits files
    def split_array(self, array):
        low = []
        up = []
        a1 = []
        a2 = []

        ref = array[0][1]

        for m in array:
            if m[1] == ref:
                a1.append(m)
            else:
                a2.append(m)

        if a1[0][1] >= a2[0][1]:
            up = a1
            low = a2
        else:
            up = a2
            low = a1

        aux = 0
        for n in low:
            if n[2] >= aux:
                aux = n[2]
                low_path = n[0]

        aux = 0
        for m in up:
            if m[2] >= aux:
                aux = m[2]
                up_path = m[0]

        return up_path, low_path

    # Get the data of the directory
    def get_each_path(self, diry):

        files = os.listdir(diry)

        sweep_path = ""
        sweep_hr_path = ""
        ONTemp = []
        OFFTemp = []

        for i in files:
            k = i.lower()
            if k == "sweep.fits":
                sweep_path = i
            elif k == "sweep_hr.fits":
                sweep_hr_path = i
            else:
                freq = ''
                mode = ''
                n = ''
                cnt = 0
                for j in k:
                    if j == '_':
                        cnt += 1
                    elif j == '.':
                        cnt = 0
                    elif cnt == 1:
                        freq = freq + j
                    elif cnt == 3:
                        mode = mode + j
                    elif cnt == 6:
                        n = n + j
                if n == '':
                    n = 0
                if mode == "on":
                    ONTemp.append([i,int(freq),int(n)])
                elif mode == "off":
                    OFFTemp.append([i,int(freq),int(n)])

        return sweep_path, sweep_hr_path, ONTemp, OFFTemp