"""Module with multilayer perceptron definition.

"""

import json
import pathlib
import time
from copy import deepcopy
from typing import List, Optional

import numpy as np

from .activations import _ACTIVATION_DICT
from .metrics import _METRICS_DICT
from .utils import chunked, progress_bar, unison_shuffle

class MultilayerPerceptron:
    """Multilayer perceptron estimator.

    Args:
        inputs: Number of inputs to multilayer perceptron.
        units: List of numbers of units in consecutive layers of perceptron.
        activations: List of names of activation functions for consecutive
                     layers. If not given all layers will have sigmoid
                     activation functions.

    Attributes:
        _model: Model data for estimator.

    """

    def __init__(
            self, inputs: int, units: List[int], activations: Optional[List[str]] = None
        ) -> None:
        if activations is None:
            activations = ['sigmoid' for _ in range(len(units))]
        else:
            if len(units) != len(activations):
                raise ValueError('length of units and activations are different')
            for activation in activations:
                if activation not in _ACTIVATION_DICT:
                    raise ValueError(f'{activation} not available')

        layer_shapes = zip((inputs, *units)[1:], (inputs, *units)[:-1])
        self._activations: List[str] = activations
        self._layers: List[np.ndarray] = [
            np.random.rand(units_num, inputs_num + 1) * 2 - 1
            for units_num, inputs_num in layer_shapes]

    def __str__(self) -> str:
        """Creates model summary in form of string.

        Returns:
            Model summary in form of string.

        """
        text = f'{"_"*48}\n{"inputs":<16}{"units(outputs)":<16}{"activation":<16}\n{"="*48}'
        for layer, activation in zip(self._layers, self._activations):
            text += f'\n{layer.shape[1]-1:<16}{layer.shape[0]:<16}{activation:<16}\n{"_"*48}'
        return text

    def predict(self, x: np.ndarray) -> np.ndarray:
        """Predicts outputs for given inputs.

        Args:
            x: Inputs for prediction in form of numpy array of vectors.

        Returns:
            Prediction in form of numpy array of vectors.

        """
        self._validate_x(x)

        y = _bias_extend(np.array(x, ndmin=2))
        for layer, activation in zip(self._layers, self._activations):
            y = _bias_extend(_ACTIVATION_DICT[activation](np.matmul(layer, y.T).T))
        y = _bias_reduce(y)
        return y

    def train(
            self,
            train_x: np.ndarray,
            train_y: np.ndarray,
            val_x: Optional[np.ndarray] = None,
            val_y: Optional[np.ndarray] = None,
            batch_size: int = 32,
            epochs: int = 20,
            learning_rate: float = 0.01,
            momentum: float = 0.9,
            shuffle: bool = True,
            metrics: str = 'mse',
            early_stopping: bool = True,
            verbose: bool = True
        ) -> None:
        """Trains estimator on given data.

        Args:
            train_x: Training input data (2d).
            train_y: Training labels (2d).
            val_x: Validation input data (2d).
            val_y: Validation labels (2d).
            batch_size: Number of vectors in single batch.
            epochs: Number of training epochs.
            learning_rate: Learning rate for model.
            momentum: Momentum or model.
            shuffle: Flag for shuffling input data every epoch.
            metrics: Name of metrics to evaluate model with.
            early_stopping: Flag for early stopping.
            verbose: Flag for training verbosity.

        """
        # pylint: disable=too-many-arguments, too-many-locals, too-many-branches, too-many-statements
        # Check if metrics is available
        if metrics not in _METRICS_DICT:
            raise ValueError(f'{metrics} is not available')
        # Validate data
        self._validate_x(train_x)
        self._validate_y(train_y)
        if val_x is not None and val_y is not None:
            self._validate_x(val_x)
            self._validate_y(val_y)
        # Print training summary
        if verbose:
            print(f'Train on {len(train_x)} samples', end='')
            if val_x is not None and val_y is not None:
                print(f' - Validate on {len(val_x)} samples')
            else:
                print()
        # Calculate base scores
        train_score, compare_score = _METRICS_DICT[metrics](self.predict(train_x), train_y)
        if val_x is not None and val_y is not None:
            val_score, compare_score = _METRICS_DICT[metrics](self.predict(val_x), val_y)
        # Save best model and score
        if early_stopping:
            best_score = compare_score
            best_activations = deepcopy(self._activations)
            best_layers = deepcopy(self._layers)

        deltas = [np.zeros_like(layer) for layer in self._layers]
        for epoch_i in range(epochs):
            if verbose:
                start_time = time.time()
                print(f'Epoch {epoch_i+1}/{epochs}')
            if shuffle:
                train_x, train_y = unison_shuffle(train_x, train_y)

            for batch_x, batch_y in progress_bar(
                    zip(chunked(train_x, batch_size), chunked(train_y, batch_size)),
                    total=len(train_x),
                    step=batch_size,
                    verbose=verbose):
                # Feedforward and save results
                # `inputs` -> layer -> `outputs` -> activation
                inputs, outputs = [_bias_extend(batch_x)], []
                for i, (layer, activation) in enumerate(zip(self._layers, self._activations)):
                    outputs.append(np.matmul(layer, inputs[i].T).T)
                    inputs.append(_bias_extend(_ACTIVATION_DICT[activation](outputs[i])))
                batch_y_pred = _bias_reduce(inputs.pop())
                # Backpropagate
                errors = [
                    (batch_y_pred - batch_y)
                    * _ACTIVATION_DICT[self._activations[-1]](outputs.pop(), derivative=True)]
                for i, (layer, activation) in enumerate(zip(
                        reversed(self._layers), reversed(self._activations[:-1]))):
                    errors.append(
                        np.matmul(_bias_reduce(layer).T, errors[i].T).T
                        * _ACTIVATION_DICT[activation](outputs.pop(), derivative=True))
                errors = list(reversed(errors))
                # Update weigths
                deltas = [
                    -learning_rate * np.matmul(input_.T, error).T + momentum * delta
                    for input_, error, delta in zip(inputs, errors, deltas)]
                for layer, delta in zip(self._layers, deltas):
                    layer += delta

            # Calculate scores
            train_score, compare_score = _METRICS_DICT[metrics](self.predict(train_x), train_y)
            if val_x is not None and val_y is not None:
                val_score, compare_score = _METRICS_DICT[metrics](self.predict(val_x), val_y)
            # Save best model and score
            was_better = False
            if early_stopping and compare_score >= best_score:
                was_better = True
                best_score = compare_score
                best_activations = deepcopy(self._activations)
                best_layers = deepcopy(self._layers)
            # Print epoch summary
            if verbose:
                duration = time.time() - start_time
                # Print results
                if val_x is not None and val_y is not None:
                    print(
                        f'duration: {duration:.2f}s - train_{metrics}: {train_score:.4f} '
                        f'- val_{metrics}: {val_score:.4f}',
                        end='')
                else:
                    print(f'duration: {duration:.2f}s - train_{metrics}: {train_score:.4f}', end='')
                if early_stopping and was_better:
                    print(' <<')
                else:
                    print()

        # Restore best model
        if early_stopping:
            self._activations = best_activations
            self._layers = best_layers

    def save(self, file_path: pathlib.Path) -> None:
        """Saves model to file.

        Args:
            file_path: Path to file to which model will be saved.

        """
        model = {
            'activations': self._activations,
            'layers': [layer.tolist() for layer in self._layers]}
        with open(pathlib.Path(file_path), 'w', encoding='utf-8') as model_file:
            json.dump(model, model_file, indent=4, sort_keys=True)

    @staticmethod
    def load(file_path: pathlib.Path) -> 'MultilayerPerceptron':
        """Loads model from file.

        Args:
            file_path: Path to model file.

        """
        with open(pathlib.Path(file_path), 'r', encoding='utf-8') as model_file:
            model = json.loads(model_file.read())
            multilayer_perceptron = MultilayerPerceptron(inputs=1, units=[1,])
            multilayer_perceptron._activations = model['activations']
            multilayer_perceptron._layers = [np.array(layer, ndmin=2) for layer in model['layers']]
            return multilayer_perceptron

    def _validate_x(self, x: np.ndarray) -> None:
        """Validates x data regarding model.

        Args:
            x: Data to validate.

        Raises:
            ValueError: In case of failed validation.

        """
        if x.ndim != 2:
            raise ValueError('x should have 2 dims')
        if x.shape[1] != self._layers[0].shape[1] - 1:
            raise ValueError(
                f'invalid x shape (None, {x.shape[1]}), '
                f'should be (None, {self._layers[0].shape[1] - 1})')

    def _validate_y(self, y: np.ndarray) -> None:
        """Validates y data regarding model.

        Args:
            y: Data to validate.

        Raises:
            ValueError: In case of failed validation.

        """
        if y.ndim != 2:
            raise ValueError('y should have 2 dims')
        if y.shape[1] != self._layers[-1].shape[0]:
            raise ValueError(
                f'invalid y shape (None, {y.shape[1]}), '
                f'should be (None, {self._layers[-1].shape[0]})')

def _bias_extend(array: np.ndarray) -> np.ndarray:
    """Extends data with ones.

    Method extends each vector in array with additional one at the end.

    Args:
        array: Array to extend.

    Returns:
        Array extended with ones.

    """
    return np.hstack((array, np.ones((array.shape[0], 1))))

def _bias_reduce(array: np.ndarray) -> np.ndarray:
    """Reduces data.

    Method removes last element from each vector in array.

    Args:
        array: Array to reduce.

    Returns:
        Reduced array.

    """
    return array[:, :-1]


import json
from datetime import datetime
from db import Trade
from fetcher import WebsocketFetcher

BASE_URI = 'wss://stream.binance.com:9443/stream?streams='

class Fetcher(WebsocketFetcher):
    NAME = 'Binance'

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.symbols = {
            (base + quote).upper(): pair_id
            for base, quote, pair_id in self.pairs
        }

    def uri(self):
        return BASE_URI + '/'.join([
            (base + quote).lower() + '@aggTrade'
            for base, quote, _ in self.pairs
        ])

    async def parse_message(self, message, callback):
        msg = json.loads(message)
        data = msg['data']
        if (
            data['e'] == 'aggTrade'
            and data['s'] in self.symbols
        ):
            await callback(Trade(
                self.symbols[data['s']],
                int(data['T']),
                float(data['q']) * (-1 if data['m'] else 1),
                float(data['p'])
            ))


#! /usr/bin/env python3

import argparse

parser=argparse.ArgumentParser()
parser.add_argument("--parallel", type=str, nargs='+', help="Get the alignment quality of the parallel corpus", required=True)
args = parser.parse_args()

def isnumber(s):
	try:
		float(s)
		return True
	except ValueError:
		pass

	try:
		import unicodedata
		unicodedata.numeric(s)
		return True
	except (TypeError, ValueError):
		pass
	return False

if args.parallel:
	for z in args.parallel:
		with open(z, "r") as infile:
			contents = infile.readlines()
			total = 0
			loss = 0
			for line in contents:
				check = False
				numbers = []
				source, target = line.strip("\n").split("\t")
				for i in source:
					if i != "౦" and isnumber(i):
						numbers.append(i)
						check = True
				if check == True:
					total += 1

				check = False
				for i in target:
					if i != "౦" and isnumber(i):
						if i in numbers:
							numbers.remove(i)
						else:
							check = True
				if len(numbers) !=0 or check == True:
					loss += 1

			print(z + ":\t" + str(round(loss*100/total, 3)))


# Autor Leonardo Dourado
# É proibida a utilização do programa ou cópia de parte do código sem a autorização do autor.

import requests
import time

def get_count_cryptocurrencies(category):
    '''Essa função retorna a quantidade de
     moedas disponíveis.'''

    if category == "spot":
        URL_query = "https://api.coinmarketcap.com/data-api/v3/cryptocurrency/listing?start=1&category=spot"
        r = requests.get(url = URL_query)
        data_count_crypto = r.json()
    elif category == "futures":
        URL_query = "https://api.coinmarketcap.com/data-api/v3/cryptocurrency/listing?start=1&category=futures"
        r = requests.get(url = URL_query)
        data_count_crypto = r.json()

    return int(data_count_crypto['data']['totalCount'])

def get_all_cryptocurrencies_spot(limit=get_count_cryptocurrencies("spot")):
    '''Essa função retorna as estatísticas das moedas no mercado spot.'''
    limit = get_count_cryptocurrencies("spot")
    URL_query = "https://api.coinmarketcap.com/data-api/v3/cryptocurrency/listing?start=1&limit={0}&sortBy=market_cap&category=spot&sortType=desc&convert=USD,BTC,ETH&cryptoType=all&tagType=all&audited=false&aux=ath,atl,high24h,low24h,num_market_pairs,cmc_rank,date_added,tags,platform,max_supply,circulating_supply,total_supply,volume_7d,volume_30d".format(limit)
    r = requests.get(url = URL_query)
    data_all_cryptocurrencies = r.json()

    return data_all_cryptocurrencies

def get_all_cryptocurrencies_future(limit=get_count_cryptocurrencies("futures")):
    '''Essa função retorna as estatísticas das moedas no mercado future.'''
    limit = get_count_cryptocurrencies("futures")
    URL_query = "https://api.coinmarketcap.com/data-api/v3/cryptocurrency/listing?start=1&limit={0}&sortBy=market_cap&category=futures&sortType=desc&convert=USD,BTC,ETH&cryptoType=all&tagType=all&audited=false&aux=ath,atl,high24h,low24h,num_market_pairs,cmc_rank,date_added,tags,platform,max_supply,circulating_supply,total_supply,volume_7d,volume_30d".format(limit)
    r = requests.get(url = URL_query)
    data_all_cryptocurrencies = r.json()

    return data_all_cryptocurrencies

def get_coins_by_exchange(exchange_slug):
    '''Essa função retorna todas as moedas de uma exchange específica e salva em arquivo.'''
    coins_set = set()
    for page in range(0,100):
        URL_query = "https://api.coingecko.com/api/v3/exchanges/{0}/tickers?page={1}".format(exchange_slug, page)
        r = requests.get(url = URL_query)
        data_exchange = r.json()

        if len(data_exchange['tickers']) > 0:
            for i in range(0,len(data_exchange['tickers'])):
                coins_set.add(data_exchange['tickers'][i]['base'])
        else:
            break

    try:
        file = open("coins_by_exchange.bin","w")
        for line in coins_set:
            file.write("{0}\n".format(line))
        file.close()
    except Exception as ex:
        print(ex)

    return list(coins_set)

def get_coins_list():
    '''Essa função retorna de um arquivo uma lista com as moedas armazenadas.'''
    coins_list = list()
    try:
        file = open("coins_by_exchange.bin","r")

        for line in file:
            coins_list.append(line.replace("\n",""))

        file.close()
    except Exception as ex:
        print(ex)

    return coins_list

#def get_exchanges_by_cryptocurrency(coin_slug):
#    '''Essa função retorna em quais exchanges uma determinada moeda está listada.'''
#    exchanges_set = set()
#    URL_query = "https://api.coinmarketcap.com/data-api/v3/cryptocurrency/market-pairs/latest?slug={0}".format(coin_slug)
#    r = requests.get(url = URL_query)
#    data_exchanges = r.json()
#    exchanges_array_size = len(data_exchanges['data']['marketPairs'])

#    for i in range(1,exchanges_array_size):
#        exchanges_set.add(data_exchanges['data']['marketPairs'][i]['exchangeSlug'])

#    return exchanges_set

def check_crypto_in_exchange(coin_symbol, exchange_coins_list):
    '''Essa função retorna True se uma moeda está listada em uma exchange específica e False se não está listada.'''
    if coin_symbol in exchange_coins_list:
        return True
    else:
        return False

def get_top_gain(top_n, marketcap_greater, volume24h, exchanges, window):
    '''Essa função atualiza os campos da janela com o top n de altas de moedas listada em ordem decrescente.'''
    cryptocurrencies = list()
    data = get_all_cryptocurrencies_spot()
    top_return = list()

    exchanges_coin_list = get_coins_list()

    for i in range(0, int(get_count_cryptocurrencies("spot"))):
        if float(data['data']['cryptoCurrencyList'][int(i)]['quotes'][2]['marketCap']) < marketcap_greater and volume24h > float(data['data']['cryptoCurrencyList'][int(i)]['quotes'][2]['volume24h']):
            continue
        cryptocurrencies.append({'name': data['data']['cryptoCurrencyList'][int(i)]['name'], 'slug': data['data']['cryptoCurrencyList'][int(i)]['slug'], 'symbol': data['data']['cryptoCurrencyList'][int(i)]['symbol'], 'Variação 1h': data['data']['cryptoCurrencyList'][int(i)]['quotes'][2]['percentChange1h'], 'Variação 24h': data['data']['cryptoCurrencyList'][int(i)]['quotes'][2]['percentChange24h']})

    cryptocurrencies_sorted = sorted(cryptocurrencies, key=lambda k: k['Variação 1h'], reverse=True)

    counter = 0

    for cryptocurrency in cryptocurrencies_sorted:
        if check_crypto_in_exchange(cryptocurrency['symbol'], exchanges_coin_list):
            index = str(counter+1)
            #print(".{0}.".format(cryptocurrency['symbol']))
            window.Element("top_gain_{0}_1".format(index)).Update(cryptocurrency['name'])
            window.Element("top_gain_{0}_2".format(index)).Update(cryptocurrency['slug'])
            window.Element("top_gain_{0}_3".format(index)).Update(cryptocurrency['symbol'])
            window.Element("top_gain_{0}_4".format(index)).Update("{0:.2f}".format(cryptocurrency['Variação 1h']))
            counter += 1

        if counter == top_n:
                break

def get_top_loss(top_n, marketcap_greater, volume24h, exchanges, window):
    '''Essa função atualiza os campos da janela com o top n de baixas de moedas listada em ordem crescente.'''
    cryptocurrencies = list()
    data = get_all_cryptocurrencies_future()
    top_return = list()

    exchange_coin_list = get_coins_list()

    for i in range(0, int(get_count_cryptocurrencies("futures"))):
        if float(data['data']['cryptoCurrencyList'][int(i)]['quotes'][2]['marketCap']) < marketcap_greater and volume24h > float(data['data']['cryptoCurrencyList'][int(i)]['quotes'][2]['volume24h']):
            continue
        cryptocurrencies.append({'name': data['data']['cryptoCurrencyList'][int(i)]['name'], 'slug': data['data']['cryptoCurrencyList'][int(i)]['slug'], 'symbol': data['data']['cryptoCurrencyList'][int(i)]['symbol'], 'Variação 1h': data['data']['cryptoCurrencyList'][int(i)]['quotes'][2]['percentChange1h'], 'Variação 24h': data['data']['cryptoCurrencyList'][int(i)]['quotes'][2]['percentChange24h']})

    cryptocurrencies_sorted = sorted(cryptocurrencies, key=lambda k: k['Variação 1h'])

    counter = 0

    for cryptocurrency in cryptocurrencies_sorted:
        if check_crypto_in_exchange(cryptocurrency['symbol'], exchange_coin_list):
            index = str(counter+1)
            #print(".{0}.".format(cryptocurrency['symbol']))
            window.Element("top_loss_{0}_1".format(index)).Update(cryptocurrency['name'])
            window.Element("top_loss_{0}_2".format(index)).Update(cryptocurrency['slug'])
            window.Element("top_loss_{0}_3".format(index)).Update(cryptocurrency['symbol'])
            window.Element("top_loss_{0}_4".format(index)).Update("{0:.2f}".format(cryptocurrency['Variação 1h']))
            counter += 1

        if counter == top_n:
            break

def repeat_by_time_top_gain(top_n, marketcap_greater, volume24h, exchanges, window):
    '''Essa função executa em loop temporal a função get_top_gain.'''
    while True:
        get_top_gain(top_n, marketcap_greater, volume24h, exchanges, window)
        time.sleep(int(returnConfigFile()[3]))

def repeat_by_time_top_loss(top_n, marketcap_greater, volume24h, exchanges, window):
    '''Essa função executa em loop temporal a função get_top_loss.'''
    while True:
        get_top_loss(top_n, marketcap_greater, volume24h, exchanges, window)
        time.sleep(int(returnConfigFile()[3]))

def clear_gain_fields(top_n, window):
    '''Essa função limpa os campos de ganho das moedas na janela.'''
    for index in range(1,top_n+1):
        window.Element("top_gain_{0}_1".format(index)).Update(" ")
        window.Element("top_gain_{0}_2".format(index)).Update(" ")
        window.Element("top_gain_{0}_3".format(index)).Update(" ")
        window.Element("top_gain_{0}_4".format(index)).Update(" ")

def clear_loss_fields(top_n, window):
    '''Essa função limpa os campos de perda das moedas na janela.'''
    for index in range(1,top_n+1):
        window.Element("top_loss_{0}_1".format(index)).Update(" ")
        window.Element("top_loss_{0}_2".format(index)).Update(" ")
        window.Element("top_loss_{0}_3".format(index)).Update(" ")
        window.Element("top_loss_{0}_4".format(index)).Update(" ")

def getValue(config_line):
    '''Essa função separa o parâmetro do valor atribuído, retornando apenas o valor atribuído.'''
    value = config_line.split("=")
    return value[1]

def loadConfigFile(window):
    '''Essa função carrega nos campos da interface GUI os parâmetros salvos no arquivo.'''
    try:
        file = open("config.bin","r")
        counter = 1
        for line in file:
            window.Element(counter).Update(getValue(line))
            counter += 1
        file.close()
    except FileNotFoundError:
        return False

def saveParametersInFile(top_currencies,marketcap_greater,volume24h,time_refresh_seconds):
    '''Essa função salva os parâmetros no arquivo de configuração.'''
    try:
        file = open("config.bin","w")
        file.write("top_currencies={0}\n".format(top_currencies.replace("\n","")))
        file.write("marketcap_greater={0}\n".format(marketcap_greater.replace("\n","")))
        file.write("volume24h={0}\n".format(volume24h.replace("\n","")))
        file.write("time_refresh_seconds={0}\n".format(time_refresh_seconds.replace("\n","")))
        file.close()
    except Exception as ex:
        print(ex)

def returnConfigFile():
    ''' Essa função retorna os parâmetros definidos e salvos no arquivo de configuração.'''
    try:
        file = open("config.bin","r")
        config_parameters = list()
        counter = 1
        for line in file:
            line_return = getValue(line)
            line_return = line_return.replace("\n","")
            config_parameters.append(line_return)
            counter += 1
        file.close()
        return config_parameters
    except FileNotFoundError:
        return [None,None,None,None]

#get_coins_by_exchange("binance")


from base.sql_base import Session
from models.roleModel import Role

def get_roles():
    session = Session()
    roles = session.query(Role).all()
    return roles

def create_role(value:str):
    session = Session()
    role = Role(value)

    try:
        session.add(role)
        session.commit()
    except Exception as exc:
        print(f"Failed to add role - {exc}")
    return role


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# vim:fileencoding=utf-8 fileformat=unix
#
# Author:  Iranoan <iranoan+vim@gmail.com>
# License: GPL Ver.3.

from subprocess import run, PIPE
from email import utils
from shutil import which
import re

RE_CRLF = re.compile(r'[\r\n]+')
RE_SPACE = re.compile(r'[\u3000\t ]+')

def asyncomplete_address(kw):
    def goobook(kw):
        ret = run(['goobook', 'query', kw], stdout=PIPE, stderr=PIPE)
        matches = []
        for adr in RE_CRLF.split(ret.stdout.decode()):
            adr = adr.split('\t')
            adr_len = len(adr)
            if adr_len == 2 and adr[1] != 'My Contacts (group)':
                matches.append({'word': adr[0], 'dup': 0, 'icase': 1, 'abbr': adr[1]})
            elif adr_len == 3:
                name = RE_SPACE.sub(' ', utils.unquote(adr[1]))
                if ',' in name:
                    if '"' in name and not (r'\"') in name:
                        name = utils.quote(name)
                    matches.append({'word': '"' + name + '" <' + adr[0] + '>',
                                    'dup': 0, 'icase': 1, 'menu': '[goobook]'})
                else:
                    matches.append({'word': name + ' <' + adr[0] + '>',
                                    'dup': 0, 'icase': 1, 'menu': '[goobook]'})
        return matches

    if which('goobook') is not None:
        return goobook(kw)
    elif which('notmuch'):
        ret = run(['notmuch', 'address', '--deduplicate=address',
                   'from:' + kw, 'or', 'to:' + kw, 'or', 'cc:' + kw, 'or', 'bcc:' + kw],
                  stdout=PIPE, stderr=PIPE)
        return [{'word': RE_SPACE.sub(' ', x), 'dup': 0, 'icase': 1, 'menu': '[notmuch]'}
                for x in RE_CRLF.split(ret.stdout.decode())]


from Classes.Receita import Receita
from Classes.Paciente import Paciente
from datetime import date

class Farmaceutico:

    def __init__(self, nome: str):
        self.nome = nome

    def receber_receita(self, receita: Receita, cliente: Paciente):
        self.cliente = cliente
        self.receita = receita

    # Retorna True se a receita for válida:
    def validar_receita(self) -> bool:
        validade = self.receita.validade.split("/")

        # inverte a string de dd-mm-YYYY para YYYY-mm-dd
        if len(validade[0]) == 2:
            print(validade.reverse())
        ano = int(validade[0])
        mes = int(validade[1])
        dia = int(validade[2])

        validacoes = list()
        validacoes.append(self.cliente == self.receita.paciente)    # Verifica se o paciente é o dono da receita
        validacoes.append(date(ano, mes, dia) >= date.today())      # Verifica a validade
        validacoes.append(self.cliente.idade >= 18)                 # Verifica se ele é maior de idade
        return all(validacoes)

    # Verifica se a quantidade do medicamento existe no estoque:
    def verificar_estoque(self) -> bool:
        if not self.validar_receita():
            return False

        nome = ''
        quantidade = 0

        with open("../dados/estoque.txt") as estoque:
            for line in estoque:
                medicamento = line.split(';')
                # Verifica se
                if medicamento[1] == self.receita.medicamento:
                    nome = medicamento[1]
                    quantidade = int(medicamento[3].strip())
                    break

        if len(nome) > 0 and quantidade >= self.receita.quantidade:
            return True
        else:
            return False

    # Retira o medicamento
    def retirar_medicamento(self) -> bool:
        if not self.verificar_estoque():
            return False

        medicamento_entregue = False

        dados_modificados = []
        with open("../dados/estoque.txt") as estoque:
            for line in estoque:
                medicamento = line.split(';')
                # Verifica se o medicamento está na lista
                if medicamento[1] == self.receita.medicamento:
                    quantidade = int(medicamento[3].strip())
                    # Subtrai a quantidade escrita na receita do estoque:
                    medicamento[3] = str(quantidade - self.receita.quantidade) + '\n'
                    medicamento_entregue = True
                    self.receita.definir_como_entregue(self)
                dados_modificados.append(';'.join(medicamento))

        with open("../dados/estoque.txt", "w") as estoque:
            estoque.writelines(dados_modificados)

        return medicamento_entregue

    def entregar_medicamento(self):
        if self.receita.medicamento_entregue():
            print("Medicamento entregue!")
        else:
            print("medicamento não entregue!")


# Load up packages
from jax import grad, jit, random
import jax.numpy as jnp
import numpy as np
from datetime import datetime
import os

# And functions I've written
from NRT_functions import helper_functions
from NRT_functions import losses

##### Set a load of parameters ######

T = 75000                   # How many gradient steps
D = 25                      # How many neurons
K = 5                       # How many repeats to run at once
N_rand = 150                # How many random angles, to use for separation loss
N_shift = 10                # Number of other rooms to measure positivity and norm
Shift_std = 3              # Standard deviation of normal from which to sample shifts
sampling_choice = 1         # 0 for room, 1 for normal distribution
resample_iters = 5          # How often to resample random points

# Set of parameters for the positivity geco
lambda_pos_init = 5      # 15 for euc, 5 for kern, 150 for euc_A (maybe 0.5 after N), 0.1 for kern_A  # Initial positivity loss weighting
k_p = -9                    # Positivity target
alpha_p = 0.9               # Smoothing of positivity dynamics
gamma_p = 0.00025             # Proportionality constant

# Norm GECO parameters
lambda_norm_init = 0.05      # Initial norm loss weighting
k_norm = 2                   # Equivaraince target
alpha_norm = 0.9             # Smoothing of equivariance dynamics
gamma_norm = 0.00025         # Proportionality constant from mismatch to constrant movement

# Parameters for ADAM
epsilon_w = 0.1             # Step size parameter W
epsilon_om = 0.1            # Frequency step size
beta1 = 0.9                 # Exp moving average parameter for first moment
beta2 = 0.9                 # exp moving average parameter for second moment
eta = 1e-8                   # Small regularising, non-exploding thingy, not v important it seems

# Printing and saving
save_iters = 5               # How often to save results
print_iters = 250            # How often to print results
# save_traj = 1              # Do you want to save a history of w and om?

# Create and save parameter dict
parameters = {"D": D, "T": T, "K": K, "N_rand": N_rand, "N_shift": N_shift, "resample_iters": resample_iters, "save_iters": save_iters,
              "lambda_pos_init": lambda_pos_init, "k_p": k_p, "alpha_p": alpha_p, "gamma_p": gamma_p, "sampling_choice":sampling_choice,
              "lambda_norm_init": lambda_norm_init, "k_norm": k_norm, "alpha_norm": alpha_norm, "gamma_norm": gamma_norm,
              "beta1": beta1, "beta2": beta2, "eta": eta, "epsilon_w": epsilon_w, "epsilon_om": epsilon_om, "dim": 1}

# Frequency choices
# 0: random om from a gaussian
# 1: all the harmonics of up to (D-1)/2 of some base freq
# 2: some random set of (D-1)/2 frequencies
# 3: all the harmonics at a base frequency that increases slowly
# 4: a pair of grids of frequencies
# 5: search through pairs of frequencies
om_init_scheme = 0
M = int(np.floor((D - 1) / 2))
if om_init_scheme == 0:
    om_init_scale = 20  # om init scale

    parameters.update({"om_init_scheme": om_init_scheme, "om_init_scale": om_init_scale})
else:
    epsilon_om = 0
    if om_init_scheme == 1:
        base_freq = 1           # Base frequency

        parameters.update({"om_init_scheme": om_init_scheme, "base_freq": base_freq, "epsilon_om": epsilon_om})
        om = np.arange(1, M+1)*base_freq
    elif om_init_scheme == 2:
        max_freq = 30

        parameters.update({"om_init_scheme": om_init_scheme, "max_freq": max_freq, "epsilon_om": epsilon_om})
        om = np.random.randint(1, max_freq, size=M)
    elif om_init_scheme == 3:
        om_harm = 0.1*np.arange(1, M+1)

        K = 55          # How many harmonics to try
        parameters.update({"om_init_scheme": om_init_scheme, "K": K, "epsilon_om": epsilon_om})
    elif om_init_scheme == 4:
        proportion = 0.5
        freq_1 = 0.5
        freq_2 = 1.2

        M_1 = int(M*proportion)
        M_2 = M - M_1

        parameters.update({"om_init_scheme": om_init_scheme, "proportion": proportion, "freq_1":freq_1, "freq_2":freq_2})
        om_1 = freq_1*np.arange(1, M_1 + 1)
        om_2 = freq_2*np.arange(1, M_2 + 1)
        om = np.hstack([om_1, om_2])
    elif om_init_scheme == 5:
        N_prop = 3
        N_base = 6
        N_harm = 4
        proportions = np.linspace(0.2, 1 - 0.2, N_prop)
        freqs_base = np.linspace(0.75, 2, N_base)
        freqs_harm = freqs_base[:, None] * np.linspace(1.1, 1.4, N_harm)[None, :]

        freq_spec = np.zeros([N_prop * N_base * N_harm, 3])
        spec_counter = 0
        for proportion in proportions:
            for base in freqs_base:
                base_counter = 0
                for harm in freqs_harm[base_counter, :]:
                    freq_spec[spec_counter, :] = [proportion, base, harm]

                    base_counter += 1
                    spec_counter += 1
        parameters.update({"om_init_scheme": om_init_scheme, "proportion": proportion, "freq_1":freq_1, "freq_2":freq_2, "K": spec_counter})

# Separation loss choices
# 0: Simple euclidean loss
# 1: Chi weighted euclidean
# 2: Kernel loss
# 3: chi weighted kernel
sep_loss_choice = 3
chi_choice = 0
if sep_loss_choice == 0:
    loss_sep = jit(losses.sep_line_Euc)
    grad_sep_W = jit(grad(losses.sep_line_Euc, argnums=0))
    grad_sep_om = jit(grad(losses.sep_line_Euc, argnums=1))
elif sep_loss_choice == 1:
    sigma_theta = 0.1
    f = 1

    parameters.update({"sigma_theta": sigma_theta, "f": f, "chi_choice": chi_choice})
    loss_sep = jit(losses.sep_line_EucChi)
    grad_sep_W = jit(grad(losses.sep_line_EucChi, argnums=0))
    grad_sep_om = jit(grad(losses.sep_line_EucChi, argnums=1))
    if chi_choice == 0:
        calc_chi = jit(helper_functions.calc_chi_line)
    elif chi_choice == 1:
        calc_chi = jit(helper_functions.calc_chi_line_euc)
elif sep_loss_choice == 2:
    sigma_sq = 0.1

    parameters.update({"sigma_sq": sigma_sq})
    loss_sep = jit(losses.sep_line_Kern)
    grad_sep_W = jit(grad(losses.sep_line_Kern, argnums=0))
    grad_sep_om = jit(grad(losses.sep_line_Kern, argnums=1))
elif sep_loss_choice == 3:
    sigma_sq = 1
    sigma_theta = 0.1
    f = 1

    parameters.update({"sigma_sq": sigma_sq, "sigma_theta": sigma_theta, "f": f, "chi_choice": chi_choice})
    loss_sep = jit(losses.sep_line_KernChi)
    grad_sep_W = jit(grad(losses.sep_line_KernChi, argnums=0))
    grad_sep_om = jit(grad(losses.sep_line_KernChi, argnums=1))
    if chi_choice == 0:
        calc_chi = jit(helper_functions.calc_chi_line)
    elif chi_choice == 1:
        calc_chi = jit(helper_functions.calc_chi_line_euc)

parameters.update({"sep_loss_choice": sep_loss_choice})
loss_pos = jit(losses.pos_line)
grad_pos_W = jit(grad(losses.pos_line, argnums=0))
grad_pos_om = jit(grad(losses.pos_line, argnums=1))
loss_norm = jit(losses.norm_line)
grad_norm_W = jit(grad(losses.norm_line, argnums=0))
grad_norm_om = jit(grad(losses.norm_line, argnums=1))
init_irreps = jit(helper_functions.init_irreps_1D)
key = random.PRNGKey(0)

# Setup save file locations
today = datetime.strftime(datetime.now(), '%y%m%d')
now = datetime.strftime(datetime.now(), '%H%M%S')
filepath = f"./data/{today}/{now}/"
# Make sure folder is there
if not os.path.isdir(f"./data/"):
    os.mkdir(f"./data/")
if not os.path.isdir(f"data/{today}/"):
    os.mkdir(f"data/{today}/")
# Now make a folder in there for this run
savepath = f"data/{today}/{now}/"
if not os.path.isdir(f"data/{today}/{now}"):
    os.mkdir(f"data/{today}/{now}")

helper_functions.save_obj(parameters, "parameters", savepath)
print("\nOPTIMISATION BEGINNING\n")

for counter in range(K):
    # Randomly initialise the weights, losses, moments, and best W and loss
    key, subkey1 = random.split(key)     # How to do random things in jax
    W = random.normal(subkey1, [D, 2*M+1])    # The random init weights
    if om_init_scheme == 0:
        key, subkey2 = random.split(key)
        om = random.uniform(subkey2, [M]) * om_init_scale
    elif om_init_scheme == 3:
        om = (counter + 1)*om_harm
    elif om_init_scheme == 5:
        [proportion, freq_1, freq_2] = freq_spec[counter, :]
        M_1 = int(M*proportion)
        M_2 = M - M_1

        om_1 = freq_1*np.arange(1, M_1 + 1)
        om_2 = freq_2*np.arange(1, M_2 + 1)
        om = np.hstack([om_1, om_2])

    W_init = W
    means_W = jnp.zeros(jnp.shape(W))     # Moments for ADAM
    sec_moms_W = jnp.zeros(jnp.shape(W))
    W_best = W                          # Initialise best W somewhere

    om_init = om
    means_om = jnp.zeros(jnp.shape(om))  # Moments for ADAM
    sec_moms_om = jnp.zeros(jnp.shape(om))
    om_best = om

    Losses = np.zeros([4, int(T / save_iters)])   # Holder for losses, total, sep, and equi
    min_L = np.zeros([5])  # Step, Loss, Loss_Sep, and Loss_Equi at min Loss
    min_L[1] = np.infty                 # Set min Loss = infty
    L2 = 0                              # So that the positivity moving average has somewhere to start
    L3 = 0                              # Starting norm average
    lambda_norm = lambda_norm_init      # Starting lambda norm
    lambda_pos = lambda_pos_init        # And the positivity
    save_counter = 0

    #if save_traj:
    #    W_hist = np.zeros([W.shape[:], int(T / save_iters)])
    #    om_hist = np.zeros([om.shape[:], int(T / save_iters)])

    for step in range(T):
        if step % resample_iters == 0:
            # Create the angles, shifts, irreps, and transforms
            if sampling_choice == 0:
                phi = (np.random.sample(N_rand) - 0.5) * np.pi * 2
            elif sampling_choice == 1:
                phi = np.random.normal(0, 1, N_rand)
            phi_shift = np.random.normal(0, Shift_std, N_shift)
            #phi_shift = (np.random.randint(1 + 2*Shift_std, size=N_shift) - Shift_std)*2 * np.pi
            phi_norm = np.ndarray.flatten(phi[:, None] + phi_shift[None, :])
            phi_pos = np.hstack([phi, phi_norm])

            if sep_loss_choice == 1 or sep_loss_choice == 3:
                chi = calc_chi(phi, sigma_theta, f)

        # Separation Term
        if sep_loss_choice == 0:
            L1 = loss_sep(W, om, phi)
            W_grad1 = grad_sep_W(W, om, phi)
            if om_init_scheme == 0:
                om_grad1 = grad_sep_om(W, om, phi)
        elif sep_loss_choice == 1:
            L1 = loss_sep(W, om, phi, chi)
            W_grad1 = grad_sep_W(W, om, phi, chi)
            if om_init_scheme == 0:
                om_grad1 = grad_sep_om(W, om, phi, chi)
        elif sep_loss_choice == 2:
            L1 = loss_sep(W, om, phi, sigma_sq)
            W_grad1 = grad_sep_W(W, om, phi, sigma_sq)
            if om_init_scheme == 0:
                om_grad1 = grad_sep_om(W, om, phi, sigma_sq)
        elif sep_loss_choice == 3:
            L1 = loss_sep(W, om, phi, sigma_sq, chi)
            W_grad1 = grad_sep_W(W, om, phi, sigma_sq, chi)
            if om_init_scheme == 0:
                om_grad1 = grad_sep_om(W, om, phi, sigma_sq, chi)

        # Positivity Term
        pos = loss_pos(W, om, phi_pos, N_shift)
        W_grad2 = grad_pos_W(W, om, phi_pos, N_shift)
        if om_init_scheme == 0:
            om_grad2 = grad_pos_om(W, om, phi_pos, N_shift)
        if pos > 0:
            L2_Here = np.log(pos) - k_p
            if L2_Here > 0:
                L2_Here = np.log(L2_Here)
        else:
            L2_Here = -5
        L2 = L2*alpha_p + (1 - alpha_p)*L2_Here
        lambda_pos = lambda_pos*np.exp(L2*gamma_p)

        L3_Here = np.log(loss_norm(W, om, phi, phi_norm)) - k_norm
        L3 = L3 * alpha_norm + (1 - alpha_norm) * L3_Here
        lambda_norm = lambda_norm * np.exp(L3 * gamma_norm)
        W_grad3 = grad_norm_W(W, om, phi, phi_norm)
        if om_init_scheme == 0:
            om_grad3 = grad_norm_om(W, om, phi, phi_norm)

        # Update the moment averages, then bias correct them
        W_grad = W_grad1 + lambda_pos*W_grad2 + lambda_norm*W_grad3
        means_W = beta1*means_W + (1 - beta1)*W_grad
        sec_moms_W = beta2*sec_moms_W + (1 - beta2)*np.power(W_grad, 2)
        means_debiased_W = means_W/(1 - np.power(beta1, step+1))
        sec_moms_debiased_W = sec_moms_W/(1 - np.power(beta2, step + 1))

        if om_init_scheme == 0:
            om_grad = om_grad1 + lambda_pos * om_grad2 + lambda_norm * om_grad3
            means_om = beta1 * means_om + (1 - beta1) * om_grad
            sec_moms_om = beta2 * sec_moms_om + (1 - beta2) * np.power(om_grad, 2)
            means_debiased_om = means_om / (1 - np.power(beta1, step + 1))
            sec_moms_debiased_om = sec_moms_om / (1 - np.power(beta2, step + 1))

        if step % save_iters == 0:        # Save and print the appropriate losses
            if L2 > 0:
                Losses[0, save_counter] = L1 + L2 * lambda_pos
            else:
                Losses[0, save_counter] = L1
            if L3 > 0:
                Losses[0, save_counter] += L3 * lambda_norm
            Losses[1, save_counter] = L1
            Losses[2, save_counter] = L2_Here
            Losses[3, save_counter] = L3_Here

        if step % print_iters == 0:
            print(f'Iteration: {step}, Loss: {Losses[1, save_counter]:.5f}\t Sep: {L1:.5f}\t Pos: {L2_Here:.5f}\t {L2:.5f}\t L P: {lambda_pos:.5f}\t Norm: {L3_Here:.5f}\t {L3:.5f}\t L N: {lambda_norm:.5f}')

        # Potentially save the best results
        if Losses[1, save_counter] < min_L[1] and L2 <= 0 and L3 < 0:
            min_L = [save_counter, Losses[0, save_counter], Losses[1, save_counter], Losses[2, save_counter]]
            W_best = W
            om_best = om

        # Take parameter step
        W = W - epsilon_w*means_debiased_W/(np.sqrt(sec_moms_debiased_W + eta))
        if om_init_scheme == 0:
            om = om - epsilon_om * means_debiased_om / (np.sqrt(sec_moms_debiased_om + eta))

    # Now save the weights and the losses
    helper_functions.save_obj(W_best, f"W_{counter}", savepath)
    helper_functions.save_obj(W_init, f"W_init_{counter}", savepath)
    helper_functions.save_obj(Losses, f"L_{counter}", savepath)
    helper_functions.save_obj(min_L, f"min_L_{counter}", savepath)
    helper_functions.save_obj(om, f"om_{counter}", savepath)
    helper_functions.save_obj(om_best, f"om_{counter}", savepath)
    helper_functions.save_obj(W, f"W_final_{counter}", savepath)
    helper_functions.save_obj(om, f"om_final_{counter}", savepath)

    # And print to say iteration done
    print(f"\nDONE ITERATION {counter}: Min_Loss = {min_L[1]:.5f}\n")


#!/usr/bin/env python3
"""Specify the parameters for all the commands in gridgen
"""
from pathlib import Path
from json import load
from collections.abc import Iterable

PKG_PATH = Path(__file__).parents[2]

DIMENSIONS = 'x', 'y', 'rotation'

REQUIRED = {
    'grid2d': [
        'grid2d',
        ],
    'ecog': [
        'ecog',
        ],
    'grid3d': [
        'grid3d',
        'mri',
        'initial',
        ],
    'fit': [
        'grid3d',
        'mri',
        'initial',
        'fit',
        ],
    'matlab': [
        'mri',
        'matlab',
        ]
    }

TEMPLATE = {
    "output_dir": {
        'type': 'str',
        'necessary': False,
        'help': 'path to output directory',
        },
    "grid2d": {
        "n_rows": {
            'type': 'int',
            'necessary': True,
            'help': 'number of rows',
            },
        "n_columns": {
            'type': 'int',
            'necessary': True,
            'help': 'number of columns',
            },
        "direction": {
            'type': 'str',
            'necessary': True,
            'values': ['TBLR', 'TBRL', 'BTLR', 'BTRL', 'LRTB', 'LRBT', 'RLTB', 'RLBT'],
            'help': 'direction of the grid (wires are by definition at the bottom)',
            'default': 'TBLR'
            },
        "chan_pattern": {
            'type': 'str',
            'necessary': False,
            'help': 'pattern to name the channels (it should match the naming pattern of the data). Examples are "chan{}" or "chan{03d}',
            },
        },
    "ecog": {
        "ecog_file": {
            'type': 'str',
            'necessary': True,
            'help': 'path to ECoG file',
            },
        "freq_range": {
            'type': 'list',
            'necessary': True,
            'help': 'low and high threshold of the frequency range of interest',
            'default': [65, 95],
            },
        "begtime": {
            'type': 'float',
            'necessary': False,
            'help': 'start time in seconds from the beginning of the file',
            },
        "endtime": {
            'type': 'float',
            'necessary': False,
            'help': 'end time in seconds from the beginning of the file',
            },
        "bad_channels": {
            'type': 'list',
            'necessary': False,
            'help': 'list of str, name of the channels to exclude',
            },
        },
    "grid3d": {
        "interelec_distance": {
            "type": "float",
            "necessary": False,
            "help": "distance between the electrode centers (pitch), in mm",
            "default": 3,
            },
        "maximum_angle": {
            "type": "float",
            "necessary": False,
            "help": "maximum angle, in degrees, that the grid can flex, between two neighboring electrodes (elasticity of the grid)",
            "default": 5,
            },
        "step_angle": {
            "type": "float",
            "necessary": False,
            "help": "step size, in degrees, when computing range between -`maximum_angle` and +`maximum_angle`. The smaller the step size, the faster the generation of the grid",
            "default": 0.25,
            },
        },
    "mri": {
        "T1_file": {
            'type': 'str',
            'necessary': True,
            'help': 'path to T1 image (in particular, the T1.mgz from freesurfer). Only used to compute the mapping between T1 RAS space and surface RAS space',
            },
        "dura_file": {
            'type': 'str',
            'necessary': True,
            'help': 'path to dura surface (for example, the smoothed pial surface). This surface will be used to generate the 3D grid',
            },
        "pial_file": {
            'type': 'str',
            'necessary': False,
            'help': 'path to pial surface (in particular, the lh.pial or rh.pial from freesurfer). You need to specify key `morphology` in `parameters.json`',
            'default': None,
            },
        "func_file": {
            'type': 'str',
            'necessary': False,
            'help': 'path to angiogram or fMRI (in NIfTI format). You need to specify key `functional` in `parameters.json`',
            'default': None,
            },
        },
    "initial": {
        "label": {
            'type': 'str',
            'necessary': True,
            'help': 'label for the reference electrode',
            },
        "RAS": {
            'type': 'list',
            'necessary': True,
            'help': 'initial location for the reference electrode (coordinates in MRI space)',
            },
        "rotation": {
            'type': 'float',
            'necessary': True,
            'help': 'degree of rotation of the grid (in degrees, 0° is roughly pointing up)',
            },
        },
    "morphology": {
        "distance": {
            "type": "str",
            "necessary": False,
            "values": ['ray', 'minimum', 'view', 'cylinder', 'pdf'],
            "help": "how to compute the distance of the morphology",
            "default": "ray",
            },
        "maximum_distance": {
            'type': 'float',
            'necessary': False,
            'help': 'maximum distance between electrode and pial surface. Exact interpretation depends on the type of `morphology`',
            'default': 10,
            },
        "penalty": {
            "type": "float",
            "necessary": False,
            "help": "exponent when computing the penalty from the distance. Morphology = 1 / distancepenalty. More simply, 1 = activity decreases linearly with distance; 2 = activity decreases with the square of the distance",
            "default": 1,
            },
        },
    "functional": {
        "threshold": {
            'type': 'float',
            'necessary': True,
            'help': 'value to threshold the func_file and binarize it. If None, func_file won\'t be binarized',
            'default': None,
            },
        "metric": {
            "type": "str",
            "necessary": False,
            "values": ['gaussian', 'sphere', 'inverse'],
            "help": "method to compute the value at each electrode. `sphere` is the sum of the voxels around the electrodes, within `kernel` distance. `gaussian` is the weighted average of the voxels around an electrode, weighted by a 3d gaussian kernel. With `inverse`, the weights are based on the inverse of the distance.",
            "default": "inverse",
            },
        "kernel": {
            "type": "float",
            "necessary": False,
            "help": "With method `sphere`, this is the size of the sphere. With method `gaussian`, this is the size of the sigma of the 3D weighting kernel. With method `inverse`, this is the exponent (1 -> linear, 2 -> quadratic).",
            "default": 2,
            },
        },
    "fit": {
        "method": {
            "type": "str",
            "necessary": True,
            "values": ['brute', 'simplex'],
            "help": "method to use (brute includes simplex as a second step)",
            "default": "brute",
            },
        "metric": {
            "type": "str",
            "necessary": False,
            "values": ['parametric', 'nonparametric', 'sum'],
            "help": "'parametric' correlation (Pearson, default), 'nonparametric' correlation (rank) or 'sum' (grid position where the sum of the electrode values is highest)",
            "default": "parametric",
            },
        "morphology_weight": {
            "type": "float",
            "necessary": False,
            "help": "whether morphology is positively (+1) or negatively (-1) correlated to ECoG (or whether morphology contributes positively or negatively to the highest sum). You can also adjust this value to adjust the scale of the morphology values.",
            "default": 1,
            },
        "functional_weight": {
            "type": "float",
            "necessary": False,
            "help": "whether functional is positively (+1) or negatively (-1) correlated to ECoG (or whether functional contributes positively or negatively to the highest sum). You can also adjust this value to adjust the scale of the functional values.",
            "default": 1,
            },
        "functional_contribution": {
            "type": "list",
            "necessary": False,
            "help": "If both present, it's possible to combine morphology and functional models with varying weights. This parameter indicates which weights will be tested (10 = 10% of functional contribution and 90% of morphology contribution)",
            "default": [0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100],
            },
        "steps": {
            "x": {
                "type": "float",
                "necessary": False,
                "help": "Step size in mm for x-direction, for method simplex",
            },
            "y": {
                "type": "float",
                "necessary": False,
                "help": "Step size in mm for y-direction, for method simplex",
            },
            "rotation": {
                "type": "float",
                "necessary": False,
                "help": "Step size in degrees for rotation, for method simplex",
            },
        },
        "ranges": {
            "x": {
                "type": "list",
                "necessary": False,
                "help": "Range in mm for x-direction, in format [low, step, high], for method brute",
            },
            "y": {
                "type": "list",
                "necessary": False,
                "help": "Range in mm for y-direction, in format [low, step, high], for method brute",
            },
            "rotation": {
                "type": "list",
                "necessary": False,
                "help": "Range in degrees for rotation, in format [low, step, high], for method brute",
            },
        },
    },
    "matlab": {
        "input": {
            "subjectInfo_file": {
                'type': 'str',
                'necessary': True,
                'help': 'path to subjectInfo.mat (can also be subj_info.json if subjectInfo.mat is not available)'
                },
            "gridInfo_file": {
                'type': 'str',
                'necessary': True,
                'help': 'path to gridInfo.mat',
                },
            },
        "comparison": {
            "angiomap_file": {
                'type': 'str',
                'necessary': False,
                'help': 'path to _angiomap.mat',
                },
            "model_file": {
                'type': 'str',
                'necessary': False,
                'help': 'path to full models ("ROI")',
                },
            "prediction_file": {
                'type': 'str',
                'necessary': False,
                'help': 'path to coordinates with the best fit',
                },
            }
        }
    }

def convert_to_path(d, parent):
    """Convert strings to paths. If the path is relative, then this script makes
    it absolute in reference to "parent"

    Parameters
    ----------
    d : dict
        if a key ends in _file or _dir, it gets converted to path
    parent : path
        absolute path to use to make relative paths absolute

    Returns
    -------
    dict
        where keys ending in _file and _dir are all absolute paths
    """
    for k, v in d.items():
        if v is None:
            continue
        elif isinstance(v, dict):
            v = convert_to_path(v, parent)
        elif k.endswith('_file') or k.endswith('_dir'):
            v = Path(v)
            if not v.is_absolute():
                v = (parent / v).resolve()
            d[k] = v
    return d

def prepare_template(temp):
    """Prepare template by reading the TEMPLATE and converting it to markdown

    Parameters
    ----------
    temp : dict
        TEMPLATE (or its subfields)

    Returns
    -------
    dict
        with default values and necessary
    """
    out = {}
    for k, v in temp.items():
        if 'type' in v:
            if not v['necessary']:
                out[k] = None

            elif v['type'] == 'int':
                out[k] = v.get('default', 0)

            elif v['type'] == 'float':
                out[k] = v.get('default', 0.0)

            elif v['type'] == 'str':
                out[k] = v.get('default', '')

            elif v['type'] == 'list':
                out[k] = v.get('default', [])

        else:
            out[k] = prepare_template(v)
    return out

def help_template(temp):
    """Prepare template by reading the TEMPLATE and converting it to markdown

    Parameters
    ----------
    temp : dict
        TEMPLATE (or its subfields)

    Returns
    -------
    list of str
        dict converted to list, so that it can be exported to markdown
    """
    modules = _invert_dict(REQUIRED)

    out = []
    for k, v in temp.items():
        if 'type' in v:
            out_ = f'- **{k}**: '

            if v['type'] == 'int':
                out_ += '(int'

            elif v['type'] == 'float':
                out_ += '(float'

            elif v['type'] == 'str':
                out_ += '(str'

            elif v['type'] == 'list':
                out_ += '(list'

            if v['necessary']:
                out_ += ') '
            else:
                out_ += ', optional) '

            out_ += v['help']

            if 'values' in v:
                out_ += '. Values: [' + ', '.join(v['values']) + ']'

            if 'default' in v:
                out_ += f'. Default: {v["default"]}'

            out.append(out_)

        else:
            out_ = help_template(v)
            if k in modules:
                extra = ' (required by command ' + ', '.join(f'`{x}`' for x in modules[k]) + ')'
            else:
                extra = ''
            out.append(f'- **{k}**' + extra)
            out.extend([f'  {x}' for x in out_])

    return out

def validate_template(temp, d):
    """Check whether the parameters passed in json file are in accordance with
    the template

    Parameters
    ----------
    temp : dict
        TEMPLATE of parameters
    d : dict
        actual parameters

    Returns
    -------
    dict
        input dictionary, with checked values and added defaults if necessary
    """
    out = {}
    for k, v in temp.items():

        if 'method' in d:
            if d['method'] == 'brute':
                for dim in DIMENSIONS:
                    if d.get('ranges', {}).get(dim, None) is None:
                        raise ValueError(f'{dim} should be defined in "ranges" with method "brute"')

                d.pop('steps', None)

            if d['method'] == 'simplex':
                for dim in DIMENSIONS:
                    if d.get('steps', {}).get(dim, None) is None:
                        raise ValueError(f'{dim} should be defined in "steps" with method "simplex"')

                d.pop('ranges', None)

        if k not in d or d[k] is None:
            if v.get('default', False):
                out[k] = v['default']

        elif 'type' in v:
            if v['necessary']:
                if k not in d:
                    raise ValueError(f'{k} should be defined')
                if isinstance(d[k], Iterable) and len(d[k]) == 0:
                    raise ValueError(f'{k} should be defined')

            if 'values' in v and d[k] not in v['values']:
                values = ', '.join(f'{x}' for x in v['values'])
                raise ValueError(f'{k} should be one of these values: {values}')

            out[k] = d[k]

        elif k in d:
            out[k] = validate_template(v, d[k])

    return out

def _invert_dict(d):
    new_dict = {}
    for k, v in d.items():
        for x in v:
            new_dict.setdefault(x, []).append(k)
    return new_dict

def parse_parameters(parameters, function, output_dir=None):
    """Read the parameters file, for a specific command

    Parameters
    ----------
    parameters : str
        path to json file
    function : str
        one of the commands (grid2d, ecog, grid3d etc)
    output_dir : path
        path to use as output, if not specified in parameters

    Returns
    -------
    dict
        complete parameters
    """
    p_json = Path(parameters).resolve()
    with p_json.open() as f:
        parameters = load(f)

    required = REQUIRED[function].copy()
    if 'mri' in parameters:
        if parameters['mri'].get('func_file', None) is not None:
            required.append('functional')
        if parameters['mri'].get('pial_file', None) is not None:
            required.append('morphology')

    for k in required:
        if k not in parameters:
            raise ValueError(f'You need to specify "{k}" when running {function}')
        else:
            parameters[k] = validate_template(TEMPLATE[k], parameters[k])

    if output_dir is not None:
        output = output_dir
    elif 'output_dir' in parameters:
        output = parameters['output_dir']
    else:
        output = 'gridgen_output'

    parameters['output_dir'] = output
    parameters = convert_to_path(parameters, p_json.parent)
    parameters['output_dir'].mkdir(exist_ok=True, parents=True)

    # move one parameter to mri because it's more straightforward
    if parameters.get('mri', {}).get('func_file', None) is not None:
        parameters['mri']['func_threshold'] = parameters['functional'].pop('threshold', None)

    return parameters

def main():
    """Simple function to create parameters.md"""
    md = [
        '## Parameters',
        '',
        'Parameters should be saved as a `json` file.',
        'You can pass the parameters with the command `gridgen parameters.json func` where `func` is one of the possible functions (`grid2d`, `ecog`, `fit` etc).',
        'You can also use the command `gridgen parameters.json parameters` to generate a template `parameters.json` file.',
        '',
        ]
    md = md + help_template(TEMPLATE)
    parameters_file = PKG_PATH / 'docs' / 'parameters.md'

    with parameters_file.open('w') as f:
        f.write('\n'.join(md))

if __name__ == '__main__':
    main()


#Basics
for x in range(4): #Creating a range from 0 to 4 while excluding 4
  for y in range(3): #Creating a range from 0 to 3 while excluding 3
    print(f"({x}, {y})") #Will continue until inner loop completes

#Practice
numbers = [1, 1, 1, 1, 4] #Create an array called numbers

for x_count in numbers: #Iterate through every element of numbers and assign that value to x_count
  output = '' #Create a variable called output that refers to an empty string
  for count in range(x_count): #Iterate through the loop however much the value of an element in numbers is, assign that element value as count
    output += "x" #Add the string x to variable output every loop
  print(output) #Print the string assigned to output after the initial for loop is completed


from flask import g

from backend.db import query_db

def build_conditions(params={}, date_column="datetime", column_param=None):
    conditions = []

    column = None
    if column_param is not None:
        column = params.get(column_param)
    if column:
        column_conditions = []
        for item in column.split(","):
            column_conditions.append("{}='{}'".format(column_param, item))

        conditions.append("(" + " OR ".join(column_conditions) + ")")

    from_date = params.get("from")
    if from_date:
        conditions.append(date_column + ">='{}'".format(from_date))

    to_date = params.get("to")
    if to_date:
        conditions.append(date_column + "<='{}'".format(to_date))

    conditions = " AND ".join(conditions)
    return conditions

def get_cbs_columns():
    columns = getattr(g, '_cbs_columns', None)
    if columns is None:
        db_response = query_db(
            """
            PRAGMA table_info(cbs)
            """,
            json_response=False
        )
        columns = [r[1] for r in db_response][1:]
        g._cbs_columns = columns

    return columns


import numpy as np
import yuntu.core.audio.utils as auUtils

def audioLoadBasicInfo(au):
    au.originalSr = au.config["samplerate"]
    au.nchannels = au.config["nchannels"]
    au.sampwidth = au.config["sampwidth"]
    au.length = au.config["length"]
    au.md5 = au.config["md5"]
    au.duration = au.config["duration"]
    au.filesize = au.config["filesize"]
    au.sr = au.originalSr
    au.mask = None
    au.signal = None

    return True

def audioReadBasicInfo(au):
    au.originalSr, au.nchannels, au.sampwidth, au.length, \
        au.filesize = auUtils.readInfo(au.path)
    au.duration = (float(au.length) / float(au.originalSr)) / au.timeexp
    au.sr = au.originalSr
    au.mask = None
    au.signal = None

    return True

def audioListen(au):
    from IPython.display import Audio
    return Audio(data=au.getSignal(), rate=au.sr)

def audioReadMedia(au):
    offset = 0.0
    duration = None

    if au.mask is not None:
        offset = au.mask[0]
        duration = au.mask[1] - au.mask[0]

    au.signal, au.sr = auUtils.read(au.path, au.readSr, offset, duration)

    return True

def audioClearMedia(au):
    au.signal = None
    au.sr = au.originalSr

    return True

def audioSetReadSr(au, sr):
    au.readSr = sr
    au.clearMedia()

    return True

def audioSetMetadata(au,
                     metadata):
    au.metadata = metadata

    return True

def audioSetMask(au,
                 startTime,
                 endTime):
    au.mask = [startTime / au.timeexp, endTime / au.timeexp]
    au.readMedia()

    return True

def audioUnsetMask(au):
    au.mask = None
    au.clearMedia()

    return True

def audioGetMediaInfo(au):
    info = {}
    info["path"] = au.path
    info["filesize"] = au.filesize
    info["timeexp"] = au.timeexp
    info["samplerate"] = au.originalSr
    info["sampwidth"] = au.sampwidth
    info["length"] = au.length
    info["nchannels"] = au.nchannels
    info["duration"] = au.duration

    return info

def audioGetSignal(au,
                   preProcess=None):
    if au.signal is None:
        au.readMedia()
        if preProcess is not None:
            if isinstance(preProcess, dict):
                au.signal = preProcess["transform"](
                    au.signal, **preProcess["kwargs"])
            else:
                au.signal = preProcess(au.signal)

    return au.signal

def audioGetZcr(au,
                channel=0,
                frame_length=1024,
                hop_length=512,
                preProcess=None):
    if channel > au.nchannels - 1:
        raise ValueError("Channel outside range.")

    sig = au.getSignal(preProcess)

    sig = auUtils.sigChannel(sig,
                             channel,
                             au.nchannels)

    return auUtils.zeroCrossingRate(sig,
                                    frame_length,
                                    hop_length)

def audioGetSpec(au,
                 channel=None,
                 n_fft=1024,
                 hop_length=512,
                 preProcess=None):
    if channel is None:
        sig = auUtils.channelMean(au.getSignal(preProcess))
    else:
        if channel > au.nchannels - 1:
            raise ValueError("Channel outside range.")

        sig = au.getSignal(preProcess)
        sig = auUtils.sigChannel(au.getSignal(
            preProcess), channel, au.nchannels)

    return auUtils.spectrogram(sig,
                               n_fft=n_fft,
                               hop_length=hop_length),\
        auUtils.specFrequencies(au.sr, n_fft)

def audioGetMfcc(au,
                 channel=0,
                 sr=22050,
                 S=None,
                 n_mfcc=20,
                 dct_type=2,
                 norm='ortho',
                 preProcess=None):
    if channel > au.nchannels - 1:
        raise ValueError("Channel outside range.")

    sig = au.getSignal(preProcess)
    sig = auUtils.sigChannel(sig,
                             channel,
                             au.nchannels)

    return auUtils.mfcc(sig,
                        sr=au.sr,
                        S=None,
                        n_mfcc=n_mfcc,
                        dct_type=dct_type,
                        norm=norm)

def audioWriteMedia(au,
                    path,
                    media_format="wav",
                    sr=None):
    if media_format in ["wav", "flac", "ogg"]:
        sig = au.getSignal()
        out_sr = au.sr

        if sr is not None:
            out_sr = sr

        auUtils.write(path, sig, out_sr, au.nchannels, media_format)

        return path
    else:
        raise ValueError("Writing to '" + media_format +
                         "' is not supported yet.")

def audioWriteChunks(au,
                     basePath,
                     chop,
                     thresh=1,
                     media_format="wav",
                     sr=None):
    duration = au.duration
    if sr is not None:
        audioSetReadSr(au, sr)

    results = []
    if chop is None:
        out = {"tlimits": [0, duration], "number": 0}
        out["path"] = audioWriteMedia(
            au, basePath + "." + media_format, media_format)
        results = [out]
    elif duration < chop:
        out = {"tlimits": [0, duration], "number": 0}
        out["path"] = audioWriteMedia(
            au, basePath + "." + media_format, media_format)
        results = [out]
    else:
        fchunks = duration / chop
        if fchunks <= thresh:
            out = {"tlimits": [0, duration], "number": 0}
            out["path"] = audioWriteMedia(
                au, basePath + "." + media_format, media_format)
            results = [out]
        else:
            nchunks = int(fchunks)
            residual = fchunks - nchunks

            if residual >= 0.5:
                nchunks += 1

            tlimits = [(float(chop * x), float(min(chop * (x + 1), duration)))
                       for x in range(nchunks)]
            for i in range(len(tlimits)):
                au.setMask(tlimits[i][0], tlimits[i][1])
                out = {"tlimits": tlimits[i], "number": i}
                out["path"] = audioWriteMedia(
                    au, basePath + "_chunk_" + str(i) + "." +
                    media_format, media_format)
                results.append(out)
                au.unsetMask()

    return results

def audioSetAnn(ann_au,
                annotations):
    for ann in annotations:
        if ann["atype"] == "single":
            ann_au.annotations[ann["id"]] = ann
        else:
            nann = {"atype": "group", "members": []}
            for sann in ann["data"]:
                ann_au.annotations[sann["id"]] = sann
                nann["members"].append(sann["id"])
            group_keys = []
            for key in ann:
                if key.split("_")[0] == "gkey":
                    group_keys.append(key)
                    nann[key] = ann[key]
            group_keys.sort()
            nann["group_code"] = tuple(group_keys)
            gcode = [nann[x] for x in group_keys]
            ann_au.groups[tuple(gcode)] = nann

def audioGetAnn(ann_au,
                noteids=None,
                groups=None):
    if noteids is not None:
        return [ann_au.annotations[nid] for nid in noteids]
    if groups is not None:
        result = []
        for gkey in groups:
            group = dict(ann_au.groups[gkey])
            group["data"] = [ann_au.annotations[nid]
                             for nid in group["members"]]
            result.append(group)
        return result
    return [ann_au.annotations[x] for x in ann_au.annotations]

def audioGetAnnLimits(ann_au,
                      noteids=None,
                      groups=None):
    if noteids is not None or (noteids is None and groups is None):
        return [{
            "noteid": x["id"],
            "limits": (x["start_time"],
                       x["end_time"],
                       x["min_freq"],
                       x["max_freq"])
        }
            for x in ann_au.getAnn(noteids)]
    group_results = []
    for gkey in groups:
        group = ann_au.groups[gkey]
        member_limits = ann_au.getAnnLimits(noteids=group["members"])
        start_time = min([x["limits"][0] for x in member_limits])
        end_time = max([x["limits"][1] for x in member_limits])
        min_freq = min([x["limits"][2] for x in member_limits])
        max_freq = max([x["limits"][3] for x in member_limits])
        glimits = {
            "group": gkey,
            "limits": (start_time, end_time, min_freq, max_freq),
            "members": group["members"]
        }
        group_results.append(glimits)
    return group_results

def audioGetAnnGeoms(ann_au,
                     noteids=None,
                     groups=None):
    if noteids is not None or (noteids is None and groups is None):
        return [{
            "noteid": x["id"],
            "verts": x["verts"]
        }
            for x in ann_au.getAnn(noteids)]
    group_results = []
    for gkey in groups:
        group = ann_au.groups[gkey]
        member_geoms = ann_au.getAnnGeoms(noteids=group["members"])
        mgeoms = {
            "group": gkey,
            "member_geoms": member_geoms
        }
        group_results.append(mgeoms)
    return group_results

def audioGetAnnMatrices(ann_au,
                        noteids=None,
                        groups=None,
                        slices=True,
                        slice_dim=1,
                        window=None,
                        mask_window=None,
                        channel=0,
                        n_fft=1024,
                        hop_length=512,
                        preProcess=None):
    limits = ann_au.getAnnLimits(noteids,
                                 groups)
    ntargets = len(limits)
    if ntargets == 0:
        return []
    spec, freqs = ann_au.getSpec(channel,
                                 n_fft,
                                 hop_length,
                                 preProcess)
    mask_exp = np.zeros_like(spec)
    geoms = ann_au.getAnnGeoms(noteids,
                               groups)
    freqs = freqs / 1000
    mask_exp = auUtils.drawGeoms(geoms, mask_exp, ann_au.duration, freqs)
    actual_pieces = auUtils.getWindowPieces(mask_window,
                                            spec,
                                            freqs,
                                            ann_au.duration,
                                            limits,
                                            slice_dim,
                                            False)
    mask_2d = np.zeros_like(spec)
    for i in range(len(actual_pieces)):
        tbin0, tbin1, fbin0, fbin1 = actual_pieces[i]
        mask_2d[fbin0:fbin1, tbin0:tbin1] = np.ones_like(mask_2d[fbin0:fbin1,
                                                                 tbin0:tbin1])
    mask_1d = np.amax(mask_2d, axis=0)
    if slices:
        print("slices", slices)
        window_pieces = auUtils.getWindowPieces(window,
                                                spec,
                                                freqs,
                                                ann_au.duration,
                                                limits,
                                                slice_dim)
        for i in range(len(window_pieces)):
            tbin0, tbin1, fbin0, fbin1 = window_pieces[i]
            limits[i]["spec"] = spec[fbin0:fbin1, tbin0:tbin1]
            limits[i]["mask2d"] = mask_2d[fbin0:fbin1, tbin0:tbin1]
            limits[i]["mask1d"] = mask_1d[tbin0:tbin1]
            limits[i]["mask_exp"] = mask_exp[fbin0:fbin1, tbin0:tbin1]
            limits[i]["freqs"] = freqs[fbin0:fbin1]
        return limits
    return {"spec": spec,
            "mask1d": mask_1d,
            "mask2d": mask_2d,
            "limits": limits,
            "freqs": freqs,
            "mask_exp": mask_exp}


from django import forms
from lk.models import *

class SelectStock(forms.Form):
	all_stock = []
	stock = forms.ChoiceField(widget=forms.Select, choices=all_stock)
	stock.widget.attrs.update({'class': 'custom-select custom-select-sm', 'id': 'all_stock'})

class StockForm(forms.ModelForm):
	class Meta:
		model = Stock
		fields = ['title', 'country', 'region', 'city', 'street', 'house']

		widgets = {
			'title': forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'По умолчанию: Склад № ... '}),
			'country': forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'Например: Российская Федерация'}),
			'region': forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'Например: Удмуртская Республика'}),
			'city': forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'Например: Ижевск'}),
			'street': forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'Например: Воткинское шоссе'}),
			'house': forms.TextInput(attrs={'class': 'form-control', 'placeholder': '13'})
		}
	def save(self):
		new_stock = Stock.objects.create(
			title=self.cleaned_data['title'],
			value=self.cleaned_data['value'],
			country=self.cleaned_data['country'],
			region=self.cleaned_data['region'],
			city=self.cleaned_data['city'],
			street=self.cleaned_data['street'],
			house=self.cleaned_data['house'],
			account=self.cleaned_data['account'],
		)

		return new_stock


import requests

class CMCTools:

    def __init__(self):
        self.TICKER_URL = "https://api.coinmarketcap.com/v1/ticker/"
        self.GLOBAL_URL = "https://api.coinmarketcap.com/v1/global/"
        self.coin_name_info_list = []

        self.headers = { "User-agent": "cmcools - A lightweight coinmarketcap wrapper. https://github.com/DustinStuff/cmctools" }
        self.session = requests.Session()
        self.session.headers.update(self.headers)

    def ticker(self, coin_id="", limit="", start="", convert=""):
        """
        Gets information from the coinmarketcap API's ticker endpoint. Only valid coinmarketcap coin IDs can
        be used, however you can use a symbol or name if you pass it through name_info([symbol or name])['id'].

        Example return JSON:
        [
            {
                "id": "bitcoin",
                "name": "Bitcoin",
                "symbol": "BTC",
                "rank": "1",
                "price_usd": "8026.4",
                "price_btc": "1.0",
                "24h_volume_usd": "8925990000.0",
                "market_cap_usd": "135277547580",
                "available_supply": "16854075.0",
                "total_supply": "16854075.0",
                "max_supply": "21000000.0",
                "percent_change_1h": "-0.53",
                "percent_change_24h": "-0.73",
                "percent_change_7d": "-7.88",
                "last_updated": "1518151167"
        If convert is used, it also has these entries (using ETH as an example):
                "price_eth": "10.0965816895",
                "24h_volume_eth": "11228195.3546",
                "market_cap_eth": "170168545.0"
            },
            { ... }
        ]
        :param coin_id: A valid coinmarketcap coin id.
        :param limit: Returns a maximum of [limit] results. Defaults to 100, use 0 to return all results.
        :param start: Returns results from rank [start].
        :param convert: Returns price, 24h volume, and market cap in another specified currency.
        :return: /ticker/endpoint JSON data.
        """
        url = "{}{}/".format(self.TICKER_URL, coin_id) if coin_id else self.TICKER_URL
        params = {"limit": limit, "start": start, "convert": convert}
        return self.session.get(url, params=params).json()

    def global_data(self, convert=""):
        """
        Gets information from the coinmarketcap API's global endpoint.

        Example JSON output:
        {
            "total_market_cap_usd": 383330297293.0,
            "total_24h_volume_usd": 24300271821.0,
            "bitcoin_percentage_of_market_cap": 35.07,
            "active_currencies": 888,
            "active_assets": 593,
            "active_markets": 8641,
            "last_updated": 1518152066
        }
        :param convert: Returns price, 24h volume, and market cap in another specified currency
        :return: /global/ endpoint JSON data
        """
        params = {}
        if convert:
            params["convert"] = self.name_info(convert)["symbol"]
        url = self.GLOBAL_URL
        r = self.session.get(url, params=params)
        return r.json()

    def name_info(self, coin_input):
        """
        Takes a coinmarketcap ID, name, or symbol, and returns a dict containing all of that information.

        Example output:
        {
            "id": "bitcoin-cash",
            "name": "Bitcoin Cash",
            "symbol": "BCH"
        }
        :param coin_input: A valid ID, name, or symbol
        :return: Dict
        """
        if not self.coin_name_info_list:
            self._create_name_info_cache()
        coin_input = str(coin_input).lower()
        for coin in self.coin_name_info_list:
            if coin['id'].lower() == coin_input \
                    or coin['name'].lower() == coin_input \
                    or coin['symbol'].lower() == coin_input:
                return coin
        return {"error": "id not found for input \"{}\"".format(coin_input)}

    def _create_name_info_cache(self):
        """
        Creates a cache of all coinmarketcap IDs, names, and symbols so we don't have to keep hitting the API.
        :return: N/A
        """
        params = {"limit": 0} # Get all listings
        coin_list = self.session.get(self.TICKER_URL, params=params).json()
        for coin in coin_list:
            self.coin_name_info_list.append({
               "id": coin["id"],
               "name": coin["name"],
               "symbol": coin["symbol"]
            })


count = 0
while True:
  l, p, v = map(int, input().split())
  count += 1
  if l == 0 and p == 0 and v == 0:
    break
  if v % p > l:
    day = ((v // p) * l) + l
  else:
    day = ((v // p) * l) + (v % p)
  print("Case {}: {}".format(count, day))


import time
import os
import threading
import sys

class vGPIO():

    __HIGH = "1"
    __LOW = "0"
    __PIN_PATH = os.path.normpath('./gpio/gpio')
    __TRIG_PULSE_MIN = 1e-5

    def __init__(self, id) :
        # value file of GPIO
        self.__value = vGPIO.__LOW
        self.__id = id
        self.__pulse_trig = False
        self.__pulse_cnt = 0.0
        self.__t_rise = 0.0
        self.__t_fall = 0.0
        self.__t_last = 0.0

    @property
    def id(self):
        return self.__id

    def is_high(self) :
        ret_val = vGPIO.__LOW
        print (self.__pulse_cnt)
        if not self.__pulse_trig:
            ret_val = vGPIO.__LOW
        else:
            if self.__pulse_cnt > 0.0:
                t_cur = time.time()
                dt = self.__t_last - t_cur
                self.__pulse_cnt -= dt
                self.__t_last = t_cur
                ret_val = vGPIO.__HIGH
            else:
                self.__pulse_cnt = 0.0
                self.__pulse_trig = False
                ret_val = vGPIO.__LOW
            if (self.__t_fall-self.__t_rise) > vGPIO.__TRIG_PULSE_MIN:
                print ("Tx")
                self.__t_fall = 0.0
                self.__t_rise = 0.0
                self.__pulse_trig=True
                self.__t_last = time.time()
                self.__pulse_cnt = 2.0*range_sonar/340.0
                ret_val = vGPIO.__HIGH
        return ret_val ==  vGPIO.__HIGH

    def set_high(self) :
        if self.__value!=vGPIO.__HIGH:
            self.__t_rise = time.time()
        self.__value=vGPIO.__HIGH

    def set_low(self) :
        if self.__value==vGPIO.__HIGH:
            self.__t_fall = time.time()
        self.__value=vGPIO.__LOW

class vSonar():
    # Ensure we don't have a zillion fd on the vGPIO pins if the students
    # call this class' __init__ several times
    __PIN_MAP = {"rear": (vGPIO(231),vGPIO(230)),
                 "left": (vGPIO(232),vGPIO(34)),
                 "front": (vGPIO(259),vGPIO(233)),
                 "right": (vGPIO(234),vGPIO(229))}

    __MAX_DIST = 10 # maximum distance
    __SPEED_OF_SOUND = 340.0 # meters/sec

    def __init__(self):
        self.all_pin_in=[]
        self.all_pin_out=[]
        for pin_in, pin_out in vSonar.__PIN_MAP.values():
            pin_out.set_low()
            self.all_pin_in.append(pin_in)
            self.all_pin_out.append(pin_out)
        self.tx=[False,False,False,False]
        t = threading.Thread(target=vSonar.simPropag,args=(self.all_pin_in,self.all_pin_out,))
        t.start()

    def simPropag(all_pin_in,all_pin_out):

        n_pin=len(all_pin_in)
        val=[]
        for i in range (n_pin):
            val.append(all_pin_out[i].is_high())
            print ("val = ",val[i])

        sonarDist = [0.3,0.4,0.5,0.6]
        sonarDelay = [0.0,0.0,0.0,0.0]
        sonarTime = []
        for i in range(n_pin):
            sonarTime.append(sonarDist[i]*2.0/340.)
        dt = 0.00001
        pulse=[False,False,False,False]
        while True:
            for i in range(n_pin):
                valnew = all_pin_out[i].is_high()
                if valnew != val[i]:
                    #print (i,all_pin_out[i].id,valnew,pulse[i])
                    pass
                if valnew > val[i]:
                    all_pin_in[i].set_high()
                    time.sleep(0.05)
                    all_pin_in[i].set_low()
                """
                if pulse[i]:
                    sonarDelay[i] -= dt
                    if sonarDelay[i]<= 0.0:
                        pulse[i] = False
                        all_pin_in[i].set_low()
                        t1=time.time()
                        print ("end ping : ",i,all_pin_in[i].id,t1-t0)
                if (valnew > val[i]) and (not pulse[i]):
                    t0=time.time()
                    print ("start ping : ",i,all_pin_in[i].id)
                    all_pin_in[i].set_high()
                    sonarDelay[i] = sonarTime[i]
                    pulse[i] = True
                """
                val[i]=valnew
            time.sleep(dt)

    def get_distance(self, sonar_key):
        """
        Triggers the sonar referenced by ''sonar_key'' and returns the one-way
        travel time to the nearest obstacle.

        Parameters:
            sonar_key: string, one of ''front'', ''back'', ''left'', ''right''

        Return value:
            travel_time: float, -1 on error, ''math.inf'' if the sonar can't
                detect any obstacle or the one way travel time in seconds to
                the nearest obstacle.
        """
        try:
            pin_in, pin_out = vSonar.__PIN_MAP[sonar_key]
        except KeyError:
            print("There is no such key as: "+sonar_key)
            return -1

        # get the sonar distance from V-REP
        sonarRangeVrep = 0.8
        sonarTimeOfFly = (sonarRangeVrep*2.0)/vSonar.__SPEED_OF_SOUND

        pin_out.set_low()
        pin_out.set_high()
        time.sleep(1e-3)
        pin_out.set_low()

        # Sometimes the answer is too fast so it isn't caught, sometimes the 10us pulse is not caught by the PCDuino (python not much precise with time.sleep())

        start = time.time()
        while not pin_in.is_high():
            if time.time()- start > 1e-3:
                print("No answer from sonar: "+sonar_key)
                return -1

        #print ("rd pin_in",pin_in.id,pin_in.is_high())
        # sometimes there are fake detections faster than the time elapsed
        # between these two loops
        timeOut = 2.0*vSonar.__MAX_DIST/vSonar.__SPEED_OF_SOUND
        timeOut = 1.0
        start = time.time()
        stop = start
        while pin_in.is_high():
            #print ("rd pin_in",pin_in.id,pin_in.is_high())
            #sys.stdout.write(".")
            #sys.stdout.flush()
            stop = time.time()
            if (stop - start) > timeOut:
                print (stop-start,timeOut,sonarTimeOfFly)
                print ("rd pin_in",pin_in.id,pin_in.is_high())
                return 9999.99

        return (stop-start)*vSonar.__SPEED_OF_SOUND/2.0


class Solution:
    def smallerNumbersThanCurrent(self, nums: List[int]) -> List[int]:

        init_nums = nums.copy()
        nums.sort()
        d = {}

        # 1 2 2 3 8

        for i, num in enumerate(nums):
            if num not in d:
                d[num] = i

        res = []
        for num in init_nums:
            res.append(d[num])

        return res


import re

def five_long(sub_str):
    p = re.compile(r'[^a-zA-Z]', re.MULTILINE)
    s = p.sub('', sub_str)
    if s:
        return s
    return None

sample_string ='dsjakf233490gjiewj0c23jic00(#)!@JI)WNDI)!J)#DJ!@JDI)CJ@#290318'
print(five_long(sample_string))


import sys, os, argparse
import json, csv
from time import time
from utils import *
from objects import *
import numpy as np

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description='argparse')
    # parser.add_argument('--expnum', '-n', help='experiment number', required=True)
    # parser.add_argument('--perf', '-p', help='performance output', required=True)
    # parser.add_argument('--result', '-r', help='result output', required=True)
    parser.add_argument('--dbdir', '-b', help='database directory', required=True)
    parser.add_argument('--db', '-d', help='database name', required=True)
    parser.add_argument('--minsup', '-m', type=float, help='minimum support X%', required=True)
    parser.add_argument('--inc_number', '-i', type=int, help='number of increments', required=False, default=3)
    parser.add_argument('--granularity', '-g', type=int, help='size of increment', required=False, default=10000)
    args = parser.parse_args()

    totalDB = get_DB(args.dbdir, args.db)
    db_size = len(totalDB)
    minsup = args.minsup / 100 * db_size

    inc_number = args.inc_number
    granularity = args.granularity
    inc_split = db_size - inc_number * granularity
    assert(inc_split >= 0)

    baseDB = totalDB[:inc_split]
    zigzag = ZigZag(minsup, baseDB)
    zigzag.prep()
    zigzag.run()
    zigzag.updateRetainedFIs()

    for i in range(inc_number):
        incDB = totalDB[inc_split + granularity * i : inc_split + granularity * (i+1)]
        zigzag.update_incDB(incDB, inc_split)
        zigzag.runInc()
        zigzag.updateRetainedFIs()


"""General useful functions"""

import os
from warnings import warn
from random import choice
from string import ascii_lowercase, digits
import subprocess
import numpy as np
from pytraj import load, Trajectory

def renumber_pdb(input, reference, output=None, matching='warn', offset=0):
    """Renumber a PDB file based on a reference structure.

    Parameters
    ----------
    input : str
        PDB input to renumber

    reference : pytraj.Trajectory, str, [str]
        reference system files

    output : str
        output path. If None, no output will be saved

    matching : str
        how to handle when not all atoms in "input" are found in "reference". Allowed values are
        "ignore", "warn", and "error"

    offset : int
        residue difference between the input and reference

    Returns
    -------
    new_pdb : [str]
        renumbered PDB file
    """
    # load reference
    if isinstance(reference, Trajectory):
        return reference
    elif isinstance(reference, str):
        if not reference.endswith('.pdb'):
            raise AssertionError('If only a single file provided for reference, it must be of PDB format')
        else:
            reference = load(reference)
    elif isinstance(reference, list):
        for file in reference:
            if file.endswith('.prm7') or file.endswith('.parm7') or file.endswith('.top'):
                topology = file
            else:
                coordinates = file
        reference = load(coordinates, top=topology)
    else:
        raise TypeError('Unsupported reference files')

    # read pdb
    with open(input, 'r') as file:
        pdb = file.readlines()

    # look for PDB atoms in reference
    new_pdb_unsorted = {}
    unmatched = []
    for line in pdb:
        if line.startswith('ATOM') or line.startswith('HETATM'):
            res_idx = int(line[22:26].strip())
            at_name = line[12:16]
            at_idx = int(line[6:11].strip())
            search = reference.top.select(f':{res_idx+offset}@{at_name}')
            if len(search) == 0:
                unmatched.append(f':{res_idx}@{at_name}')
                new_pdb_unsorted[at_idx] = line
                last_idx = at_idx
            else:
                new_pdb_unsorted[search[0]+1] = line[:6] + '%5s'%(search[0]+1) + line[11:]
                last_idx = search[0]+1
        else:
            new_pdb_unsorted[last_idx] = new_pdb_unsorted[last_idx]+line

    # deal with unmatched atoms
    if len(unmatched) > 0:
        if matching == 'warn':
            print(f'Warning: residues {",".join(unmatched)} in system were not found in reference')
        elif matching == 'error':
            raise ValueError(f'residues {",".join(unmatched)} in system were not found in reference')

    # sort atoms by new index
    new_pdb = [new_pdb_unsorted[idx] for idx in sorted(new_pdb_unsorted)]

    # write output
    if output is not None:
        with open(output, 'w') as file:
            file.writelines(new_pdb)

    return new_pdb

def get_dry_trajectory(topology, trajectory, output):
    """Dry a trajectory using cpptraj

    Parameters
    ----------
    topology : str
        path to topology file

    trajectory : str
        path to trajectory file

    output : str
        where to save the dry output

    Return
    ------
    None
    """
    to_strip = ':WAT,:SOL,:HOH,:NA,:CL,:Na+,:Cl-,:CLA,:POT,:SOD'
    cpptraj_file = f'cpptraj_{"".join(choice(ascii_lowercase + digits) for _ in range(10))}.in'

    with open(cpptraj_file, 'w') as file:
        file.writelines([f'parm {topology}\n',
                        f'trajin {trajectory}\n',
                        f'strip {to_strip}\n',
                        f'trajout {output}\n',
                         'go\nquit\n'])

    subprocess.run(['cpptraj', '-i', cpptraj_file])
    os.remove(cpptraj_file)

    return None

def __parse_seeds(seeds):
    if seeds == 'all':
        seeds = [int(folder.split('_')[1]) for folder in os.listdir() if folder.startswith('snapshot_') and '.pdb' not in folder]
        seeds.sort()
    elif isinstance(seeds, (list, tuple)):
        if not all(isinstance(idx, int) for idx in seeds):
            raise TypeError('Seed indices must all be of type int')
        else:
            return seeds
    elif isinstance(seeds, str):
        if '-' in seeds:
            idx_range = [int(idx) for idx in seeds.split('-')]
            return np.arange(idx_range[0], idx_range[1]+1).tolist()
        elif ',' in seeds:
            return [int(idx) for idx in seeds.split(',')]
        else:
            return [int(seeds)]
    elif isinstance(seeds, int):
        return [seeds]
    else:
        raise TypeError('Seeds must be of type str, int, list or tuple')

def __parse_time(input, output_units, output_digits=3, output_type='string'):
    """Parse time given as a string and return either as string with units or numerical value

    Parameters
    ----------
    input : str
        time in format "value unit", e.g. "10 ps"

    output_units : str
        units to give output in. Allowed values are: "fs", "ps", "ns, "us", "ms", and "s"

    output_digits : int
        place to round output to

    output_type : str
        type of output to give. If "string" it will be "value unit" and if "number" it will be the numerical value
    """
    conversion = {'fs': -15, 'ps': -12, 'ns': -9, 'us': -6, 'ms': -3, 's': 0}

    components = input.split(' ')

    try:
        value = int(components[0]) # get numerical value
        value = value * 10**(conversion[components[1]]) # convert to seconds
    except:
        raise ValueError(f'Time has to be in the format "value unit", e.g. "10 ps". Time provided: {input}')

    output_value = round(value * 10**(-1*conversion[output_units]), output_digits)

    if output_type == 'string':
        return f'{output_value} {output_units.replace("u", "μ")}'
    elif output_type == 'number':
        return output_value
    else:
        raise ValueError(f'"output_type" can be either "string" or "number". Was: {output_type}')


import torch
import os
import numpy as np
import argparse

from tqdm import tqdm
from perf_gpu import save_image_grid

def test_om(args):
    bin_path = args.bin_path
    image_path = args.image_path
    bin_list = os.listdir(bin_path)
    bin_list.sort()
    for i in tqdm(range(len(bin_list))):
        images = np.fromfile(os.path.join(bin_path, bin_list[i]), dtype=np.float32)
        images = torch.Tensor(images)
        images = images.reshape(-1, 3, 512, 512)
        bs = images.shape[0]
        grid_size = (4, 4) if bs == 16 else (1, 1)
        os.makedirs(image_path, exist_ok=True)
        save_image_grid(images, os.path.join(image_path, f'gen_image_{i:04d}') + ".png", drange=[-1, 1],
                        grid_size=grid_size)

if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument('--bin_path', type=str, required=True)
    parser.add_argument('--image_path', type=str, default='./results')
    args = parser.parse_args()

    test_om(args)


from django.conf import settings
from django.views.generic import View
from django.shortcuts import render
from django.http import HttpResponseBadRequest

from .models import Tag
from .forms import TagForm

class Tags(View):
    def get(self, request, *args, **kwargs):
        context = {}
        tags = Tag.get_tags_sorted_by_number_of_resources()
        context['tags_grid'] = Tag.get_tags_grid(tags, settings.TAGS_PER_ROW)
        tag_form = TagForm()
        context['form'] = tag_form
        return render(request, 'tags/tags.html', context)

    def post(self, request, *args, **kwargs):
        if not request.user.is_authenticated():
            return HttpResponseBadRequest()
        context = {}
        tag_form = TagForm(request.POST)
        if tag_form.is_valid():
            tag_form.save()
            tag_form = TagForm()
        context['form'] = tag_form
        tags = Tag.get_tags_sorted_by_number_of_resources()
        context['tags_grid'] = Tag.get_tags_grid(tags, settings.TAGS_PER_ROW)
        return render(request, 'tags/tags.html', context)