""" WORKER MODULE

    - This module contains our inbuilt Workers and the base Worker.

    All Workers inherit the Worker base class.

    Users wanting to create their own custom Worker, should inherit from Worker.

    For detailed information on Workers, please see our Readme on our Github.
    https://github.com/RTMAAI/CO600-Musical-Analysis
"""
import threading
import os
import logging
from rtmaii.workqueue import WorkQueue
from scipy.signal import resample
from rtmaii.analysis import frequency, pitch, key, spectral, bpm
from pydispatch import dispatcher
from numpy import reshape, array
from tensorflow.contrib import predictor

LOGGER = logging.getLogger()
class Worker(threading.Thread):
    """ Base worker class, responsible for initializing shared attributes.

        Attributes:
            - queue: queue of data to be processed by a worker.
            - channel_id: id of channel being analysed.

        Args:
            - queue_length: length of queue structure. [Default = 1]
                Workers are greedy and will only consider the latest item.
    """
    def __init__(self, config: dict = None, channel_id: int = None, queue_length: int = 1):
        threading.Thread.__init__(self, args=(), kwargs=None)
        self.queue = WorkQueue(queue_length)
        self.config = config
        self.channel_id = channel_id
        self.setDaemon(True)
        self.reset_attributes()
        self.start()

    def run(self):
        raise NotImplementedError("Run should be implemented")

    def reset_attributes(self):
        """ Inherited method, used for resetting any attributes on configuration changes. """
        pass

class GenrePredictorWorker(Worker):
    """ Worker responsible for analysing Spectrogram intensities for a genre.

        Kwargs:
            - config (Config): Configuration options to use.
            - channel_id: id of channel being analysed.

        Attributes:
            - exporter: Exports spectrograms to an external file for use future training set
            - predict_fn: Loads the 'predict' function of trained tensorflow model
            - genredict: The dictionary from converting the number labels of predicted genre
    """
    def __init__(self, exporter: object, **kwargs: dict):
        Worker.__init__(self, kwargs['config'], kwargs['channel_id'])
        self.exporter = exporter

        self.predict_fn = predictor.from_saved_model(os.path.join(os.path.dirname(__file__), 'model'))
        self.accuracyChecker = []
        self.genredict = {}
        self.genredict[0] = 'Rock'
        self.genredict[1] = 'Folk'
        self.genredict[2] = 'Hip-Hop'
        self.genredict[3] = 'Electric'
        self.prediction = 'N/A'

    def run(self):

        while True:
            spectrogram = self.queue.get()
            spectrodata = spectrogram[2]
            testphoto = array(spectrodata)
            testphoto = testphoto.astype('float32')

            try:
                testphoto = reshape(testphoto, (1,128,128,1))
                predictions = self.predict_fn({'x': testphoto})
                predictionclass = predictions['classes'][0]
                self.prediction = self.genredict[predictionclass]
                self.accuracyChecker.append(self.prediction)

                if(len(self.accuracyChecker) > 3):
                    self.accuracyChecker.pop(0)
                    print(self.accuracyChecker)
                    self.prediction = max(set(self.accuracyChecker), key=self.accuracyChecker.count)

                export_data = [spectrodata,self.prediction]
                self.exporter.queue.put(export_data)
            except:
                pass

            spectrogram = []

            dispatcher.send(signal='genre', sender=self.channel_id, data=self.prediction)

class BandsWorker(Worker):
    """ Worker responsible for analysing interesting frequency bands.

        Kwargs:
            - config (Config): Configuration options to use.
            - channel_id: id of channel being analysed.

        Attributes:
            - bands_of_interest: dictionary of frequency bands to analyse.
            - sampling_rate: sampling_rate of source being analysed.
    """
    def __init__(self, **kwargs: dict):
        Worker.__init__(self, kwargs['config'], kwargs['channel_id'])

    def reset_attributes(self):
        self.bands_of_interest = self.config.get_config('bands')
        self.sampling_rate = self.config.get_config('sampling_rate')

    def run(self):
        while True:
            spectrum = self.queue.get()
            frequency_bands = frequency.frequency_bands(spectrum,
                                                        self.bands_of_interest,
                                                        self.sampling_rate)
            dispatcher.send(signal='bands', sender=self.channel_id, data=frequency_bands)

class Key(object):
    """ Abstract class that has methods to analyse the key/note given a pitch. """
    @staticmethod
    def analyse_note(freq: float, channel_id: int):
        """ Extract the note of a given frequency..

            Args
                - freq: estimated frequency to analyse.
                - channel_id: channel the frequency was analysed from.
        """
        estimated_note = key.note_from_pitch(freq)
        dispatcher.send(signal='note', sender=channel_id, data=estimated_note)

    @staticmethod
    def analyse_key(freq: float, channel_id: int):
        """ Extract the key of a given frequency.

            Args
                - freq: estimated frequency to analyse.
                - channel_id: channel the frequency was analysed from.
        """
        pass

class ZeroCrossingWorker(Worker, Key):
    """ Worker responsible for analysing the fundamental pitch using the zero-crossings method.

        Kwargs:
            - config (Config): Configuration options to use.
            - channel_id: id of channel being analysed.

        Attributes:
            - sampling_rate: sampling_rate of source being analysed.
    """
    def __init__(self, **kwargs: dict):
        Worker.__init__(self, kwargs['config'], kwargs['channel_id'])

    def reset_attributes(self):
        self.sampling_rate = self.config.get_config('sampling_rate')

    def run(self):
        while True:
            signal = self.queue.get()
            estimated_pitch = pitch.pitch_from_zero_crossings(signal, self.sampling_rate)
            dispatcher.send(signal='pitch', sender=self.channel_id, data=estimated_pitch)
            self.analyse_note(estimated_pitch, self.channel_id)

class AutoCorrelationWorker(Worker, Key):
    """ Worker responsible for analysing the fundamental pitch using the auto-corellation method.

        Kwargs:
            - config (Config): Configuration options to use.
            - channel_id: id of channel being analysed.

        Attributes:
            - sampling_rate: sampling_rate of source being analysed.
    """
    def __init__(self, **kwargs: dict):
        Worker.__init__(self, kwargs['config'], kwargs['channel_id'])

    def reset_attributes(self):
        self.sampling_rate = self.config.get_config('sampling_rate')

    def run(self):
        while True:
            signal = self.queue.get()
            convolved_signal = spectral.convolve_signal(signal)
            estimated_pitch = pitch.pitch_from_auto_correlation(convolved_signal,
                                                                self.sampling_rate)
            dispatcher.send(signal='pitch', sender=self.channel_id, data=estimated_pitch)
            self.analyse_note(estimated_pitch, self.channel_id)

class HPSWorker(Worker, Key):
    """ Worker responsible for analysing pitch using the harmonic-product-spectrum method.

        Kwargs:
            - config (Config): Configuration options to use.
            - channel_id: id of channel being analysed.

        Attributes:
            - sampling_rate: sampling_rate of source being analysed.
    """
    def __init__(self, **kwargs: dict):
        Worker.__init__(self, kwargs['config'], kwargs['channel_id'])

    def reset_attributes(self):
        self.sampling_rate = self.config.get_config('sampling_rate')

    def run(self):
        while True:
            spectrum = self.queue.get()
            estimated_pitch = pitch.pitch_from_hps(spectrum, self.sampling_rate, 7)
            dispatcher.send(signal='pitch', sender=self.channel_id, data=estimated_pitch)
            self.analyse_note(estimated_pitch, self.channel_id)

class FFTWorker(Worker, Key):
    """ Worker responsible for analysing the fundamental pitch using the FFT method.

        Kwargs:
            - config (Config): Configuration options to use.
            - channel_id: id of channel being analysed.

        Attributes:
            - sampling_rate: sampling_rate of source being analysed.
    """
    def __init__(self, **kwargs: dict):
        Worker.__init__(self, kwargs['config'], kwargs['channel_id'])

    def reset_attributes(self):
        self.sampling_rate = self.config.get_config('sampling_rate')

    def run(self):
        while True:
            spectrum = self.queue.get()
            estimated_pitch = pitch.pitch_from_fft(spectrum, self.sampling_rate)
            dispatcher.send(signal='pitch', sender=self.channel_id, data=estimated_pitch)
            self.analyse_note(estimated_pitch, self.channel_id)

#class BeatsWorker(Worker):
#    """ Worker responsible for determining beats happening.

#    """
#    def __init__(self, channel_id: int):
#        Worker.__init__(self, channel_id)
#
#    def run(self):
#        while True:
#            data = self.queue.get()
#            beat = bpm.beatdetection(data)
#            timedif = bpm.gettimedif()
#            dispatcher.send(signal='beat', sender=self.channel_id, data=beat)
#            self.analyse_bpm(timedif, self.channel_id)

class BPMWorker(Worker):
    """ Worker responsible for determining beats happening.

    """
    def __init__(self, **kwargs: dict):
        Worker.__init__(self, kwargs['config'], kwargs['channel_id'])

    def run(self):
        while True:
            data = self.queue.get()
            beats = data[0]
            if(len(data)>1):
                hbeats = data[1]
            beats = bpm.cleanbeatarray(beats)
            bpmestimate = bpm.bpmsimple(beats)

            dispatcher.send(signal='bpm', sender=self.channel_id, data=bpmestimate)
            #self.analyse_bpm(timedif, self.channel_id)

#class BPMWorker(Worker):
    #""" Analyse bpm based on beat times """
    #def __init__(self, channel_id: int):
    #    Worker.__init__(self, args=(), kwargs=None)

    #def analyse_bpm(self, timedif):
    #    estimated_bpm = bpm.bpmsimple()
        #dispatcher.send(signal='key', sender=self.channel_id, data=estimated_key)


import pygame
import pymunk as physics

class WaterParticle(object):
    def __init__(self, world, x, y, vx, vy):
        self.radius = 4

        self.max_force = 8

        self.force = self.max_force

        speed = 2000

        self.world = world

        self._mark_for_death = 0
        self.x, self.y = x, y
        self.vx = vx * speed
        self.vy = vy * speed
        self.shape = None
        self.body = None

        self.physics_object_created = False
        self._create_physics_object()

    def _create_physics_object(self):
        mass = self.force*100
        inertia = physics.moment_for_circle(mass, 0, self.radius, (0,0))
        self.body = physics.Body(mass, inertia)
        self.body.position = self.x, self.y
        self.shape = physics.Circle(self.body, self.radius, (0,0))
        self.shape.elasticity = 0
        self.shape.friction = 2
        self.shape.group = 1
        self.shape.collision_type = 2
        self.shape.wp = self
        self.world.space.add(self.body, self.shape)

    def mark_for_death(self):
        self._mark_for_death = .5

    def remove(self):
        self.world.space.remove(self.body, self.shape)

    def _read_from_physics(self):
        self.x = self.body.position.x
        self.y = self.body.position.y

    def update(self, dt):
        def force_for_velocity(vi, vf, dt, mass):
            fx = mass*((vf[0] - vi[0])/dt)
            fy = mass*((vf[1] - vi[1])/dt)
            return fx, fy
        if not self.physics_object_created:
            self.x += self.vx * dt
            self.y += self.vy * dt
            self.body.apply_impulse((self.vx*150, self.vy*150))
            #self.body.apply_impulse(force_for_velocity(self.body.velocity, (self.vx*self.speed, self.vy*self.speed), 1, self.body.mass))
            self.physics_object_created = True

        #self.radius += dt * 6

        self.force -= dt * (4.5 + self._mark_for_death)
        self.body.mass = self.force
        self.shape.radius += dt * 6

        #self.x += self.vx * dt
        #self.y += self.vy * dt

        #self.body.update_velocity((self.vx, self.vy), 1, dt)
        self._read_from_physics()

    #def draw(self, target):
    #    pygame.draw.circle(target, (255,0,0, 255), (int(self.x), int(self.y)), int(self.radius + .5), 1)

    def draw(self, target):
        x, y = int(self.x-self.world.camera_x), int(self.y-self.world.camera_y)
        alpha = int((self.force / self.max_force) * 255)
        pygame.draw.circle(target, (100,100,200, alpha), (x, y), int(self.shape.radius + .5))


from random import randint
import sqlite3

class BankingDatabase:
    db_file = '../card.s3db'
    sql_create_card_table = """CREATE TABLE IF NOT EXISTS card (
                        id INTEGER PRIMARY KEY AUTOINCREMENT
                        , number TEXT NOT NULL
                        , pin TEXT
                        , balance INTEGER DEFAULT 0
                                    );"""

    def __init__(self):
        self.db_conn = None
        self.cur = None
        self.db_init()
        self.db_create_tables()

    def db_init(self):
        try:
            self.db_conn = sqlite3.connect(self.db_file)
            self.cur = self.db_conn.cursor()
        except sqlite3.Error as e:
            print(e)

    def db_create_tables(self):
        """ This method includes all the tables that should be created in card.s3db
        """
        self.create_table(self.db_conn, self.sql_create_card_table)

    @staticmethod
    def create_table(db_conn, create_table_sql):
        try:
            c = db_conn.cursor()
            c.execute(create_table_sql)
            db_conn.commit()
        except sqlite3.Error as e:
            print(e)

    def db_insert_account_num(self, acc_num, pin):
        try:
            with self.db_conn:
                self.cur.execute("INSERT INTO card(number, pin) VALUES (:number, :pin)",
                                 {'number': acc_num, 'pin': pin})
        except sqlite3.IntegrityError as e:
            print(e)

    def db_get_card_pin(self, card_num):
        with self.db_conn:
            self.cur.execute("SELECT pin FROM card WHERE number=:number", {'number': card_num})
            return self.cur.fetchone()

    def db_get_card_balance(self, card_num):
        with self.db_conn:
            self.cur.execute("SELECT balance FROM card WHERE number=:number", {'number': card_num})
            return self.cur.fetchone()

    def db_add_income_to_balance(self, card, income):
        with self.db_conn:
            self.cur.execute("UPDATE card SET balance = balance + ? WHERE number = ?", (income, card))

    def db_remove_account(self, card_number):
        with self.db_conn:
            self.cur.execute("DELETE FROM card WHERE number = ?", (card_number,))

class CustomerInfo:
    # POJO
    def __init__(self):
        self.account_number = None
        self.card_number = None
        self.card_pin = None
        self.current_balance = 0

class BankingConsoleInterface:
    start_menu = f'1. Create an account \n2. Log into account \n0. Exit'
    login_menu = f'1. Balance\n2. Add income\n3. Do transfer\n4. Close account\n5. Log out\n0. Exit'
    bank_iin = 400000  # Issuer Identification Number (IIN)

    def __init__(self):
        self.db = BankingDatabase()
        self.customer = CustomerInfo()
        self.show_start_menu()

    def show_start_menu(self):
        print(self.start_menu)
        try:
            global menu_option
            menu_option = int(input())
        except ValueError:
            print('\nPlease, choose one of the existing Menu options\n')
            self.show_start_menu()

        if menu_option == 1:
            self.db.db_insert_account_num(self.generate_account_number(), self.generate_card_pin())
            print(
                f'\nYour card has been created\nYour card number:\n{self.customer.card_number}\nYour card PIN:\n{self.customer.card_pin}\n')
            self.show_start_menu()
        elif menu_option == 2:
            self.log_in()
        elif menu_option == 0:
            self.db.cur.close()
            self.db.db_conn.close()
            print('\nBye!')
        else:
            print('\nPlease, choose one of the existing Menu options\n')
            self.show_start_menu()

    def generate_account_number(self):
        # TODO: move simple generators to class BankingUtils
        self.customer.account_number = self.concatenate_integers(self.bank_iin, randint(100000000, 200000000))
        self.customer.card_number = self.concatenate_integers(self.customer.account_number,
                                                              self.return_checksum(self.customer.account_number))
        return self.customer.card_number

    @staticmethod
    def concatenate_integers(num1, num2):
        num1 = str(num1)
        num2 = str(num2)
        num1 += num2
        return int(num1)

    @staticmethod
    def return_checksum(account_num):
        counter = 0
        for i, value in enumerate(list(str(account_num)), start=1):
            if i % 2 == 0:
                counter += int(value)
            elif int(value) * 2 > 9:
                counter += (int(value) * 2) - 9
            else:
                counter += (int(value) * 2)
        return 10 - (counter % 10) if (counter % 10) > 0 else 0

    def generate_card_pin(self):
        self.customer.card_pin = str(randint(0000, 9999)).zfill(4)
        return self.customer.card_pin

    def log_in(self):
        self.customer.card_number = input('Enter your card number:\n').strip()
        self.customer.card_pin = input('Enter your PIN:\n').strip()
        try:
            if self.db.db_get_card_pin(self.customer.card_number) is None:
                print('\nWrong card number or PIN!\n')
                self.show_start_menu()
            elif self.db.db_get_card_pin(self.customer.card_number)[0] == self.customer.card_pin:
                print('\nYou have successfully logged in!\n')
                self.show_account_menu()
            else:
                print('\nWrong card number or PIN!\n')
                self.show_start_menu()
        except KeyError:
            print('\nWrong card number or PIN!\n')

    def show_account_menu(self):
        print(self.login_menu)
        account_option = int(input())
        if account_option == 1:
            print(f'\nBalance: {self.db.db_get_card_balance(self.customer.card_number)[0]}\n')
            self.show_account_menu()
        elif account_option == 2:
            income = int(input('Enter income:\n').strip())
            self.db.db_add_income_to_balance(self.customer.card_number, income)
            print('\nIncome was added!\n')
            self.show_account_menu()
        elif account_option == 3:
            self.transfer_amount()
        elif account_option == 4:
            self.db.db_remove_account(self.customer.card_number)
            print('\nThe account has been closed!\n')
            self.show_start_menu()
        elif account_option == 5:
            print('\nYou have successfully logged out!\n')
            self.show_start_menu()
        elif account_option == 0:
            self.db.cur.close()
            self.db.db_conn.close()
            print('\nBye!')
        else:
            print('\nPlease, choose one of the existing Login options\n')
            self.show_account_menu()

    def transfer_amount(self):
        transfer_card = input('Transfer\nEnter card number:\n').strip()
        if self.customer.card_number == transfer_card:
            print("\nYou can't transfer money to the same account!\n")
            self.show_account_menu()
        elif transfer_card[-1] != str(self.return_checksum(transfer_card[:-1])):
            print('\nProbably you made a mistake in the card number. Please try again!\n')
            self.show_account_menu()
        elif self.db.db_get_card_balance(transfer_card) is None:
            print('\nSuch a card does not exist.\n')
            self.show_account_menu()
        else:
            transfer_amount = int(input('Enter how much money you want to transfer:\n').strip())
            if transfer_amount > self.db.db_get_card_balance(self.customer.card_number)[0]:
                print('Not enough money!\n')
                self.show_account_menu()
            else:
                # TODO: make transactional on a DB level (ex. open transaction, commit)
                self.db.db_add_income_to_balance(self.customer.card_number, -transfer_amount)
                self.db.db_add_income_to_balance(transfer_card, transfer_amount)
                print('Success!\n')
                self.show_account_menu()

if __name__ == '__main__':
    BankingConsoleInterface()
exit()


import operator
import time
from typing import Dict, List, Optional

from acme import core
from acme.tf import losses
from acme.tf import networks
from acme.tf import savers as tf2_savers
from acme.tf import utils as tf2_utils
from acme.utils import counting
from acme.utils import loggers
import numpy as np
import reverb
import sonnet as snt
import tensorflow as tf
import tree

class RCRRLearner(core.Learner):
  """Recurrent CRR learner.

  This is the learning component of a RCRR agent. It takes a dataset as
  input and implements update functionality to learn from this dataset.
  """

  def __init__(self,
               policy_network: snt.RNNCore,
               critic_network: networks.CriticDeepRNN,
               target_policy_network: snt.RNNCore,
               target_critic_network: networks.CriticDeepRNN,
               dataset: tf.data.Dataset,
               accelerator_strategy: Optional[tf.distribute.Strategy] = None,
               behavior_network: Optional[snt.Module] = None,
               cwp_network: Optional[snt.Module] = None,
               policy_optimizer: Optional[snt.Optimizer] = None,
               critic_optimizer: Optional[snt.Optimizer] = None,
               discount: float = 0.99,
               target_update_period: int = 100,
               num_action_samples_td_learning: int = 1,
               num_action_samples_policy_weight: int = 4,
               baseline_reduce_function: str = 'mean',
               clipping: bool = True,
               policy_improvement_modes: str = 'exp',
               ratio_upper_bound: float = 20.,
               beta: float = 1.0,
               counter: Optional[counting.Counter] = None,
               logger: Optional[loggers.Logger] = None,
               checkpoint: bool = False):
    """Initializes the learner.

    Args:
      policy_network: the online (optimized) policy.
      critic_network: the online critic.
      target_policy_network: the target policy (which lags behind the online
        policy).
      target_critic_network: the target critic.
      dataset: dataset to learn from, whether fixed or from a replay buffer
        (see `acme.datasets.reverb.make_reverb_dataset` documentation).
      accelerator_strategy: the strategy used to distribute computation,
        whether on a single, or multiple, GPU or TPU; as supported by
        tf.distribute.
      behavior_network: The network to snapshot under `policy` name. If None,
        snapshots `policy_network` instead.
      cwp_network: CWP network to snapshot: samples actions
        from the policy and weighs them with the critic, then returns the action
        by sampling from the softmax distribution using critic values as logits.
        Used only for snapshotting, not training.
      policy_optimizer: the optimizer to be applied to the policy loss.
      critic_optimizer: the optimizer to be applied to the distributional
        Bellman loss.
      discount: discount to use for TD updates.
      target_update_period: number of learner steps to perform before updating
        the target networks.
      num_action_samples_td_learning: number of action samples to use to
        estimate expected value of the critic loss w.r.t. stochastic policy.
      num_action_samples_policy_weight: number of action samples to use to
        estimate the advantage function for the CRR weighting of the policy
        loss.
      baseline_reduce_function: one of 'mean', 'max', 'min'. Way of aggregating
        values from `num_action_samples` estimates of the value function.
      clipping: whether to clip gradients by global norm.
      policy_improvement_modes: one of 'exp', 'binary', 'all'. CRR mode which
        determines how the advantage function is processed before being
        multiplied by the policy loss.
      ratio_upper_bound: if policy_improvement_modes is 'exp', determines
        the upper bound of the weight (i.e. the weight is
          min(exp(advantage / beta), upper_bound)
        ).
      beta: if policy_improvement_modes is 'exp', determines the beta (see
        above).
      counter: counter object used to keep track of steps.
      logger: logger object to be used by learner.
      checkpoint: boolean indicating whether to checkpoint the learner.
    """

    if accelerator_strategy is None:
      accelerator_strategy = snt.distribute.Replicator()
    self._accelerator_strategy = accelerator_strategy
    self._policy_improvement_modes = policy_improvement_modes
    self._ratio_upper_bound = ratio_upper_bound
    self._num_action_samples_td_learning = num_action_samples_td_learning
    self._num_action_samples_policy_weight = num_action_samples_policy_weight
    self._baseline_reduce_function = baseline_reduce_function
    self._beta = beta

    # When running on TPUs we have to know the amount of memory required (and
    # thus the sequence length) at the graph compilation stage. At the moment,
    # the only way to get it is to sample from the dataset, since the dataset
    # does not have any metadata, see b/160672927 to track this upcoming
    # feature.
    sample = next(dataset.as_numpy_iterator())
    self._sequence_length = sample.action.shape[1]

    self._counter = counter or counting.Counter()
    self._logger = logger or loggers.TerminalLogger('learner', time_delta=1.)
    self._discount = discount
    self._clipping = clipping

    self._target_update_period = target_update_period

    with self._accelerator_strategy.scope():
      # Necessary to track when to update target networks.
      self._num_steps = tf.Variable(0, dtype=tf.int32)

      # (Maybe) distributing the dataset across multiple accelerators.
      distributed_dataset = self._accelerator_strategy.experimental_distribute_dataset(
          dataset)
      self._iterator = iter(distributed_dataset)

      # Create the optimizers.
      self._critic_optimizer = critic_optimizer or snt.optimizers.Adam(1e-4)
      self._policy_optimizer = policy_optimizer or snt.optimizers.Adam(1e-4)

    # Store online and target networks.
    self._policy_network = policy_network
    self._critic_network = critic_network
    self._target_policy_network = target_policy_network
    self._target_critic_network = target_critic_network

    # Expose the variables.
    self._variables = {
        'critic': self._target_critic_network.variables,
        'policy': self._target_policy_network.variables,
    }

    # Create a checkpointer object.
    self._checkpointer = None
    self._snapshotter = None
    if checkpoint:
      self._checkpointer = tf2_savers.Checkpointer(
          objects_to_save={
              'counter': self._counter,
              'policy': self._policy_network,
              'critic': self._critic_network,
              'target_policy': self._target_policy_network,
              'target_critic': self._target_critic_network,
              'policy_optimizer': self._policy_optimizer,
              'critic_optimizer': self._critic_optimizer,
              'num_steps': self._num_steps,
          },
          time_delta_minutes=30.)

      raw_policy = snt.DeepRNN(
          [policy_network, networks.StochasticSamplingHead()])
      critic_mean = networks.CriticDeepRNN(
          [critic_network, networks.StochasticMeanHead()])
      objects_to_save = {
          'raw_policy': raw_policy,
          'critic': critic_mean,
      }
      if behavior_network is not None:
        objects_to_save['policy'] = behavior_network
      if cwp_network is not None:
        objects_to_save['cwp_policy'] = cwp_network
      self._snapshotter = tf2_savers.Snapshotter(
          objects_to_save=objects_to_save, time_delta_minutes=30)
    # Timestamp to keep track of the wall time.
    self._walltime_timestamp = time.time()

  def _step(self, sample: reverb.ReplaySample) -> Dict[str, tf.Tensor]:
    # Transpose batch and sequence axes, i.e. [B, T, ...] to [T, B, ...].
    sample = tf2_utils.batch_to_sequence(sample)
    observations = sample.observation
    actions = sample.action
    rewards = sample.reward
    discounts = sample.discount

    dtype = rewards.dtype

    # Cast the additional discount to match the environment discount dtype.
    discount = tf.cast(self._discount, dtype=discounts.dtype)

    # Loss cumulants across time. These cannot be python mutable objects.
    critic_loss = 0.
    policy_loss = 0.

    # Each transition induces a policy loss, which we then weight using
    # the `policy_loss_coef_t`; shape [B], see https://arxiv.org/abs/2006.15134.
    # `policy_loss_coef` is a scalar average of these coefficients across
    # the batch and sequence length dimensions.
    policy_loss_coef = 0.

    per_device_batch_size = actions.shape[1]

    # Initialize recurrent states.
    critic_state = self._critic_network.initial_state(per_device_batch_size)
    target_critic_state = critic_state
    policy_state = self._policy_network.initial_state(per_device_batch_size)
    target_policy_state = policy_state

    with tf.GradientTape(persistent=True) as tape:
      for t in range(1, self._sequence_length):
        o_tm1 = tree.map_structure(operator.itemgetter(t - 1), observations)
        a_tm1 = tree.map_structure(operator.itemgetter(t - 1), actions)
        r_t = tree.map_structure(operator.itemgetter(t - 1), rewards)
        d_t = tree.map_structure(operator.itemgetter(t - 1), discounts)
        o_t = tree.map_structure(operator.itemgetter(t), observations)

        if t != 1:
          # By only updating the target critic state here we are forcing
          # the target critic to ignore observations[0]. Otherwise, the
          # target_critic will be unrolled for one more timestep than critic.
          # The smaller the sequence length, the more problematic this is: if
          # you use RNN on sequences of length 2, you would expect the code to
          # never use recurrent connections. But if you don't skip updating the
          # target_critic_state on observation[0] here, it won't be the case.
          _, target_critic_state = self._target_critic_network(
              o_tm1, a_tm1, target_critic_state)

        # ========================= Critic learning ============================
        q_tm1, next_critic_state = self._critic_network(o_tm1, a_tm1,
                                                        critic_state)
        target_action_distribution, target_policy_state = self._target_policy_network(
            o_t, target_policy_state)

        sampled_actions_t = target_action_distribution.sample(
            self._num_action_samples_td_learning)
        # [N, B, ...]
        tiled_o_t = tf2_utils.tile_nested(
            o_t, self._num_action_samples_td_learning)
        tiled_target_critic_state = tf2_utils.tile_nested(
            target_critic_state, self._num_action_samples_td_learning)

        # Compute the target critic's Q-value of the sampled actions.
        sampled_q_t, _ = snt.BatchApply(self._target_critic_network)(
            tiled_o_t, sampled_actions_t, tiled_target_critic_state)

        # Compute average logits by first reshaping them to [N, B, A] and then
        # normalizing them across atoms.
        new_shape = [self._num_action_samples_td_learning, r_t.shape[0], -1]
        sampled_logits = tf.reshape(sampled_q_t.logits, new_shape)
        sampled_logprobs = tf.math.log_softmax(sampled_logits, axis=-1)
        averaged_logits = tf.reduce_logsumexp(sampled_logprobs, axis=0)

        # Construct the expected distributional value for bootstrapping.
        q_t = networks.DiscreteValuedDistribution(
            values=sampled_q_t.values, logits=averaged_logits)
        critic_loss_t = losses.categorical(q_tm1, r_t, discount * d_t, q_t)
        critic_loss_t = tf.reduce_mean(critic_loss_t)

        # ========================= Actor learning =============================
        action_distribution_tm1, policy_state = self._policy_network(
            o_tm1, policy_state)
        q_tm1_mean = q_tm1.mean()

        # Compute the estimate of the value function based on
        # self._num_action_samples_policy_weight samples from the policy.
        tiled_o_tm1 = tf2_utils.tile_nested(
            o_tm1, self._num_action_samples_policy_weight)
        tiled_critic_state = tf2_utils.tile_nested(
            critic_state, self._num_action_samples_policy_weight)
        action_tm1 = action_distribution_tm1.sample(
            self._num_action_samples_policy_weight)
        tiled_z_tm1, _ = snt.BatchApply(self._critic_network)(
            tiled_o_tm1, action_tm1, tiled_critic_state)
        tiled_v_tm1 = tf.reshape(tiled_z_tm1.mean(),
                                 [self._num_action_samples_policy_weight, -1])

        # Use mean, min, or max to aggregate Q(s, a_i), a_i ~ pi(s) into the
        # final estimate of the value function.
        if self._baseline_reduce_function == 'mean':
          v_tm1_estimate = tf.reduce_mean(tiled_v_tm1, axis=0)
        elif self._baseline_reduce_function == 'max':
          v_tm1_estimate = tf.reduce_max(tiled_v_tm1, axis=0)
        elif self._baseline_reduce_function == 'min':
          v_tm1_estimate = tf.reduce_min(tiled_v_tm1, axis=0)

        # Assert that action_distribution_tm1 is a batch of multivariate
        # distributions (in contrast to e.g. a [batch, action_size] collection
        # of 1d distributions).
        assert len(action_distribution_tm1.batch_shape) == 1
        policy_loss_batch = -action_distribution_tm1.log_prob(a_tm1)

        advantage = q_tm1_mean - v_tm1_estimate
        if self._policy_improvement_modes == 'exp':
          policy_loss_coef_t = tf.math.minimum(
              tf.math.exp(advantage / self._beta), self._ratio_upper_bound)
        elif self._policy_improvement_modes == 'binary':
          policy_loss_coef_t = tf.cast(advantage > 0, dtype=dtype)
        elif self._policy_improvement_modes == 'all':
          # Regress against all actions (effectively pure BC).
          policy_loss_coef_t = 1.
        policy_loss_coef_t = tf.stop_gradient(policy_loss_coef_t)

        policy_loss_batch *= policy_loss_coef_t
        policy_loss_t = tf.reduce_mean(policy_loss_batch)

        critic_state = next_critic_state

        critic_loss += critic_loss_t
        policy_loss += policy_loss_t
        policy_loss_coef += tf.reduce_mean(policy_loss_coef_t)  # For logging.

      # Divide by sequence length to get mean losses.
      critic_loss /= tf.cast(self._sequence_length, dtype=dtype)
      policy_loss /= tf.cast(self._sequence_length, dtype=dtype)
      policy_loss_coef /= tf.cast(self._sequence_length, dtype=dtype)

    # Compute gradients.
    critic_gradients = tape.gradient(critic_loss,
                                     self._critic_network.trainable_variables)
    policy_gradients = tape.gradient(policy_loss,
                                     self._policy_network.trainable_variables)

    # Delete the tape manually because of the persistent=True flag.
    del tape

    # Sync gradients across GPUs or TPUs.
    ctx = tf.distribute.get_replica_context()
    critic_gradients = ctx.all_reduce('mean', critic_gradients)
    policy_gradients = ctx.all_reduce('mean', policy_gradients)

    # Maybe clip gradients.
    if self._clipping:
      policy_gradients = tf.clip_by_global_norm(policy_gradients, 40.)[0]
      critic_gradients = tf.clip_by_global_norm(critic_gradients, 40.)[0]

    # Apply gradients.
    self._critic_optimizer.apply(critic_gradients,
                                 self._critic_network.trainable_variables)
    self._policy_optimizer.apply(policy_gradients,
                                 self._policy_network.trainable_variables)

    source_variables = (
        self._critic_network.variables + self._policy_network.variables)
    target_variables = (
        self._target_critic_network.variables +
        self._target_policy_network.variables)

    # Make online -> target network update ops.
    if tf.math.mod(self._num_steps, self._target_update_period) == 0:
      for src, dest in zip(source_variables, target_variables):
        dest.assign(src)
    self._num_steps.assign_add(1)

    return {
        'critic_loss': critic_loss,
        'policy_loss': policy_loss,
        'policy_loss_coef': policy_loss_coef,
    }

  @tf.function
  def _replicated_step(self) -> Dict[str, tf.Tensor]:
    sample = next(self._iterator)
    fetches = self._accelerator_strategy.run(self._step, args=(sample,))
    mean = tf.distribute.ReduceOp.MEAN
    return {
        k: self._accelerator_strategy.reduce(mean, fetches[k], axis=None)
        for k in fetches
    }

  def step(self):
    # Run the learning step.
    with self._accelerator_strategy.scope():
      fetches = self._replicated_step()

    # Update our counts and record it.
    new_timestamp = time.time()
    time_passed = new_timestamp - self._walltime_timestamp
    self._walltime_timestamp = new_timestamp
    counts = self._counter.increment(steps=1, wall_time=time_passed)
    fetches.update(counts)

    # Checkpoint and attempt to write the logs.
    if self._checkpointer is not None:
      self._checkpointer.save()
      self._snapshotter.save()
    self._logger.write(fetches)

  def get_variables(self, names: List[str]) -> List[List[np.ndarray]]:
    return [tf2_utils.to_numpy(self._variables[name]) for name in names]


from aiogram import Bot,Dispatcher,executor,types
from config import API_TOKEN
import logging
from buttons  import natija,natijaa

logging.basicConfig(level=logging.INFO)

bot=Bot(token=API_TOKEN)
dp=Dispatcher(bot)

@dp.message_handler(commands=['start'])
async def start(message: types.Message):
    ism = message.from_user.first_name
    await message.answer(f"Assalomu aleykum {ism}. Botimizga xush kelibsiz.",reply_markup=natija)

@dp.message_handler(text=["Ma'lumot"])
async def start(message: types.Message):
    await message.answer_photo("https://t.me/alisher_sadullaev/3419",
    caption="Ko'proq Ma'lumot:'https://ezguamal.org/taskin'")

@dp.message_handler(text="Xodimlar haqida ma'lumot")
async def start(message: types.Message):
    await message.answer("🤵🏼 Mamayusupov Ilxom Ravshanovich: Vrach reanimatolog, Bo'lim mudiri",reply_markup=natija)
    await message.answer("🧑 Ochilova Zilola Absalom qizi: Psixolog",reply_markup=natija)

if __name__=='__main__':
    executor.start_polling(dp, skip_updates=True)


from scrapy.spider import BaseSpider
from scrapy.selector import HtmlXPathSelector
from scrapy.http.request import Request
from test_scrapy.items import TestScrapyItem

class WoblogSpider(BaseSpider):
    name = "woblog"
    allowed_domains = ["tetsuwo.tumblr.com"]
    start_urls = ["http://tetsuwo.tumblr.com"]

    def parse(self, response):
        hxs = HtmlXPathSelector(request)

        next_page = hxs.select("//div[@class='pagination']/a[@class='next_page']/@href").extract()
        if not not next_page:
            yield Request(next_page[0], self.parse)

        posts = hxs.select("//div[@class='post']")
        items = []
        for post in posts:
            item = TestScrapyItem()
            item["title"] = post.select("//div[@class='bodytext']/h2/a/text()").extract()
            item["link"] = post.select("//div[@class='bodytext']/h2/a/@href").extract()
            item["content"] = post.select("//div[@class='bodytext']/p/text()").extract()
            items.append(item)
        for item in items:
            yield item


## imaging_360.py
# This example demonstrates how to read all 4 csi cameras and display in a single openCV window. If you encounter any errors,
# use the hardware_test_csi_camera_single.py script to find out which camera is giving you trouble.

from pal.utilities.vision import Camera2D
import time
import struct
import numpy as np
import cv2

# -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
## Timing Parameters and methods
startTime = time.time()
def elapsed_time():
    return time.time() - startTime

sampleRate     = 30.0
sampleTime     = 1/sampleRate
simulationTime = 60.0
print('Sample Time: ', sampleTime)

# -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
# Additional parameters
counter = 0
imageWidth = 640
imageHeight = 480
imageBuffer360 = np.zeros((imageHeight + 40, 4*imageWidth + 120, 3), dtype=np.uint8) # 20 px padding between pieces

# -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
## Initialize the CSI cameras
# myCam1 = Camera2D(cameraId="0", frameWidth=imageWidth, frameHeight=imageHeight, frameRate=sampleRate)
# myCam2 = Camera2D(cameraId="1", frameWidth=imageWidth, frameHeight=imageHeight, frameRate=sampleRate)
# myCam3 = Camera2D(cameraId="2", frameWidth=imageWidth, frameHeight=imageHeight, frameRate=sampleRate)
myCam4 = Camera2D(cameraId="3", frameWidth=imageWidth, frameHeight=imageHeight, frameRate=sampleRate)

# -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
## Main Loop
try:
    # while elapsed_time() < simulationTime:
    while True:

        # Start timing this iteration
        start = time.time()

        # Capture RGB Image from CSI
        # myCam1.read()
        # myCam2.read()
        # myCam3.read()
        myCam4.read()

        counter += 1

        # End timing this iteration
        end = time.time()

        # Calculate the computation time, and the time that the thread should pause/sleep for
        computationTime = end - start
        sleepTime = sampleTime - ( computationTime % sampleTime )

        # Stitch images together with black padding
        horizontalBlank     = np.zeros((20, 4*imageWidth+120, 3), dtype=np.uint8)
        verticalBlank       = np.zeros((imageHeight, 20, 3), dtype=np.uint8)

        # imageBuffer360 = np.concatenate(
        #                                    (horizontalBlank,
        #                                     np.concatenate((    verticalBlank,
        #                                                         # myCam2.imageData[:,320:640],
        #                                                         # verticalBlank,
        #                                                         # myCam3.imageData,
        #                                                         # verticalBlank,
        #                                                         myCam4.imageData,
        #                                                         # verticalBlank,
        #                                                         # myCam1.imageData,
        #                                                         # verticalBlank,
        #                                                         # # myCam2.imageData[:,0:320],
        #                                                         # verticalBlank
        #                                                         ),
        #                                                         axis = 1),
        #                                     horizontalBlank
        #                                     ),
        #                                     axis=0
        #                                 )

        # Display the stitched image at half the resolution
        # cv2.imshow('Combined View', cv2.resize(imageBuffer360, (int(2*imageWidth), int(imageHeight/2))))
        # cv2.imshow('Combined View', myCam4.imageData)
        img = cv2.imread('LAneTest.png')
        gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)

        # Apply edge detection method on the image
        edges = cv2.Canny(gray, 200, 250, apertureSize=3)

        # This returns an array of r and theta values
        lines = cv2.HoughLines(edges, 1, np.pi/180, 200)

        cv2.imshow('Combined Viewedge', edges)

        # The below for loop runs till r and theta values
        # are in the range of the 2d array
        if (lines is not None) :
            for r_theta in lines:
                arr = np.array(r_theta[0], dtype=np.float64)
                r, theta = arr
                # Stores the value of cos(theta) in a
                a = np.cos(theta)

                # Stores the value of sin(theta) in b
                b = np.sin(theta)

                # x0 stores the value rcos(theta)
                x0 = a*r

                # y0 stores the value rsin(theta)
                y0 = b*r

                # x1 stores the rounded off value of (rcos(theta)-1000sin(theta))
                x1 = int(x0 + 1500*(-b))

                # y1 stores the rounded off value of (rsin(theta)+1000cos(theta))
                y1 = int(y0 + 1500*(a))

                # x2 stores the rounded off value of (rcos(theta)+1000sin(theta))
                x2 = int(x0 - 1500*(-b))

                # y2 stores the rounded off value of (rsin(theta)-1000cos(theta))
                y2 = int(y0 - 1500*(a))

                # cv2.line draws a line in img from the point(x1,y1) to (x2,y2).
                # (0,0,255) denotes the colour of the line to be
                # drawn. In this case, it is red.
                cv2.line(gray, (x1, y1), (x2, y2), (0, 0, 255), 1)
        cv2.imshow('Combined View', gray)

        # Pause/sleep for sleepTime in milliseconds
        msSleepTime = int(1000*sleepTime)
        if msSleepTime <= 0:
            msSleepTime = 1 # this check prevents an indefinite sleep as cv2.waitKey waits indefinitely if input is 0
        cv2.waitKey(msSleepTime)

except KeyboardInterrupt:
    print("User interrupted!")

finally:
    # Terminate all webcam objects
    # myCam1.terminate()
    # myCam2.terminate()
    # myCam3.terminate()
    myCam4.terminate()
# -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --


import random
import chaos
import rune

weapon_enchantment_dict = {
    '1': 'Additional Damage',
    '2': 'Characteristic Gain',
    '3': 'Characteristic Drain',
    '4': 'Bane Weapon',
    '5': 'Flame Attack',
    '6': 'Poison Attack',
    '7': 'Degeneration Attack',
    '8': 'Freeze Attack',
    '9': 'Warp Attack',
    '10': 'Sleep',
    '11': 'Flight',
    '12': 'Breather Underwater',
    '13': 'Confusion',
    '14': 'Fear ',
    '15': 'Instability',
    '16': 'Protection',
    '17': 'Resist Fire',
    '18': 'Animated',
    '19': 'Invisibility',
    '20': 'Magic Damper',
    '21': 'Berserk',
    '22': 'Repel Undead',
    '23': 'Repel Demons',
    '24': 'Destroy Magical Weapon',
    '25': 'Spell Absorption',
    '26': 'Mighty Strike'
}

melee_weapon_enchantment_list = ['1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1',
                                 '1', '1', '1', '1', '1', '1', '1', '1', '2', '2', '2', '2', '2', '2', '2', '2', '2',
                                 '2', '2', '2', '2', '2', '3', '3', '3', '3', '3', '3', '3', '3', '3', '4', '4', '4',
                                 '4', '4', '4', '4', '4', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14',
                                 '14', '15', '15', '16', '16', '17', '18', '19', '20', '21', '21', '22', '22', '23',
                                 '23', '24', '25', '25', '26', '26']

range_weapon_enchantment_list = ['1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1',
                                 '1', '1', '1', '1', '1', '1', '1', '1', '2', '2', '2', '2', '2', '2', '2', '2', '2',
                                 '2', '2', '2', '2', '2', '3', '3', '3', '3', '3', '3', '3', '3', '3', '4', '4', '4',
                                 '4', '4', '4', '4', '4', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '15',
                                 '15', '16', '16', '17', '19', '20', '22', '22', '23', '23', '25', '25', '26', '26']

melee_weapon_list = ['1', '2', '2', '2', '3', '4', '5', '6', '7', '7', '8', '8', '9', '10', '11', '12', '13', '14',
                     '15', '15', '15', '16', '17', '18', '18', '18', '18', '18', '19', '19', '19', '19', '19', '20',
                     '20', '20', '21', '21']

range_weapon_list = ['1', '2', '2', '3', '4', '5', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', '16',
                     '17']

melee_weapon_dict = {
    '1': ['Buckler', 'Enchanted weapon. See manual for a description of its properties.', 'CORE1', '188'],
    '2': ['Dagger', 'Enchanted weapon. See manual for a description of its properties.', 'CORE1', '188'],
    '3': ['Cavalry Spear', 'Enchanted weapon. See manual for a description of its properties.', 'CORE1', '188'],
    '4': ['Flail', 'Enchanted weapon. See manual for a description of its properties.', 'CORE1', '188'],
    '5': ['Foil', 'Enchanted weapon. See manual for a description of its properties.', 'CORE1', '188'],
    '6': ['Knuckle-duster ', 'Enchanted weapon. See manual for a description of its properties.', 'CORE1', '188'],
    '7': ['Great Sword', 'Enchanted weapon. See manual for a description of its properties.', 'CORE1', '188'],
    '8': ['Great Axe', 'Enchanted weapon. See manual for a description of its properties.', 'CORE1', '188'],
    '9': ['Halberd', 'Enchanted weapon. See manual for a description of its properties.', 'CORE1', '188'],
    '10': ['Lance', 'Enchanted weapon. See manual for a description of its properties.', 'CORE1', '188'],
    '11': ['Main Gauche ', 'Enchanted weapon. See manual for a description of its properties.', 'CORE1', '188'],
    '12': ['Morning Star ', 'Enchanted weapon. See manual for a description of its properties.', 'CORE1', '188'],
    '13': ['Quarterstaff', 'Enchanted weapon. See manual for a description of its properties.', 'CORE1', '188'],
    '14': ['Rapier ', 'Enchanted weapon. See manual for a description of its properties.', 'CORE1', '188'],
    '15': ['Shield ', 'Enchanted weapon. See manual for a description of its properties.', 'CORE1', '188'],
    '16': ['Spear ', 'Enchanted weapon. See manual for a description of its properties.', 'CORE1', '188'],
    '17': ['Sword-breaker ', 'Enchanted weapon. See manual for a description of its properties.', 'CORE1', '188'],
    '18': ['Hand Axe', 'Enchanted weapon. See manual for a description of its properties.', 'CORE1', '188'],
    '19': ['Long Sword', 'Enchanted weapon. See manual for a description of its properties.', 'CORE1', '188'],
    '20': ['One-Handed Hammer', 'Enchanted weapon. See manual for a description of its properties.', 'CORE1', '188'],
    '21': ['Great Hammer', 'Enchanted weapon. See manual for a description of its properties.', 'CORE1', '188'],
}

range_weapon_dict = {
    '1': ['Blunderbuss', 'Enchanted weapon. See manual for a description of its properties.', 'CORE1', '188'],
    '2': ['Pistol', 'Enchanted weapon. See manual for a description of its properties.', 'CORE1', '188'],
    '3': ['Repeater Pistol', 'Enchanted weapon. See manual for a description of its properties.', 'CORE1', '188'],
    '4': ['Bola', 'Enchanted weapon. See manual for a description of its properties.', 'CORE1', '188'],
    '5': ['Crossbow', 'Enchanted weapon. See manual for a description of its properties.', 'CORE1', '188'],
    '6': ['Crossbow Pistol ', 'Enchanted weapon. See manual for a description of its properties.', 'CORE1', '188'],
    '7': ['Javelin ', 'Enchanted weapon. See manual for a description of its properties.', 'CORE1', '188'],
    '8': ['Lasso', 'Enchanted weapon. See manual for a description of its properties.', 'CORE1', '188'],
    '9': ['Net', 'Enchanted weapon. See manual for a description of its properties.', 'CORE1', '188'],
    '10': ['Repeater Crossbow', 'Enchanted weapon. See manual for a description of its properties.', 'CORE1', '188'],
    '11': ['Sling ', 'Enchanted weapon. See manual for a description of its properties.', 'CORE1', '188'],
    '12': ['Staff Sling', 'Enchanted weapon. See manual for a description of its properties.', 'CORE1', '188'],
    '13': ['Throwing Axe', 'Enchanted weapon. See manual for a description of its properties.', 'CORE1', '188'],
    '14': ['Throwing Hammer ', 'Enchanted weapon. See manual for a description of its properties.', 'CORE1', '188'],
    '15': ['Throwing Dagger', 'Enchanted weapon. See manual for a description of its properties.', 'CORE1', '188'],
    '16': ['Throwing Star', 'Enchanted weapon. See manual for a description of its properties.', 'CORE1', '188'],
    '17': ['Whip', 'Enchanted weapon. See manual for a description of its properties.', 'CORE1', '188']
}

# this function picks a random object
# from the list, then takes the information from
# the corresponding dictionary
# entry.

def pick_weapon():
    type_of_magic_weapon = random.randint(1, 100)
    if type_of_magic_weapon > 84 and type_of_magic_weapon < 96:
        return rune.pick_weapon()
    if type_of_magic_weapon > 95:
        weapon = chaos.pick_weapon_chaos()
        return weapon

    amount_properties_roll = random.randint(1, 100)
    if amount_properties_roll <= 20:
        amount_properties = 0
    elif amount_properties_roll <= 70:
        amount_properties = 1
    elif amount_properties_roll <= 90:
        amount_properties = 2
    elif amount_properties_roll <= 95:
        amount_properties = 3
    elif amount_properties_roll <= 99:
        amount_properties = 4
    elif amount_properties_roll == 100:
        amount_properties = 5
    weapon_type_roll = random.randint(1, 100)
    if weapon_type_roll <= 70:
        choice = str(random.choice(melee_weapon_list))
        chosen_object = melee_weapon_dict[choice]
        enchantment_list = melee_weapon_enchantment_list
    elif weapon_type_roll <= 100:
        choice = str(random.choice(range_weapon_list))
        chosen_object = range_weapon_dict[choice]
        enchantment_list = range_weapon_enchantment_list
    object_id = choice
    name = chosen_object[0]

    if amount_properties == 0:
        name += ' (Magical, '
    elif amount_properties != 0:
        name += ' ('
    description = chosen_object[1]
    source = chosen_object[2]
    page = chosen_object[3]

    object_enchantments = []
    while len(object_enchantments) < amount_properties:
        pick = random.choice(enchantment_list)
        if pick not in object_enchantments:
            object_enchantments.append(pick)
    for enchantment in object_enchantments:
        if enchantment == '1':
            damage_roll = random.randint(1, 100)
            name += 'Additional Damage ('
            if damage_roll <= 50:
                name += '+1), '
            elif damage_roll <= 75:
                name += '+2), '
            elif damage_roll <= 90:
                name += '+3), '
            elif damage_roll <= 95:
                name += '+4), '
            elif damage_roll <= 98:
                name += 'double normal damage), '
            elif damage_roll <= 100:
                name += 'double normal damage, +4), '
        elif enchantment == '2':
            char_gain_roll = random.randint(1, 89)
            name += 'Characteristic Gain ('
            if char_gain_roll <= 9:
                name += 'WS +10), '
            elif char_gain_roll <= 18:
                name += 'S +10), '
            elif char_gain_roll <= 27:
                name += 'T +10), '
            elif char_gain_roll <= 36:
                name += 'Agi +10), '
            elif char_gain_roll <= 45:
                name += 'A +1), '
            elif char_gain_roll <= 54:
                name += 'Fel +10), '
            elif char_gain_roll <= 63:
                name += 'Int +10), '
            elif char_gain_roll <= 72:
                name += 'WP +10), '
            elif char_gain_roll <= 75:
                name += 'WS +'+str(random.randint(1, 3)*10)+'), '
            elif char_gain_roll <= 77:
                name += 'S +'+str(random.randint(1, 3)*10)+'), '
            elif char_gain_roll <= 79:
                name += 'T +'+str(random.randint(1, 3)*10)+'), '
            elif char_gain_roll <= 81:
                name += 'Agi +'+str(random.randint(1, 3)*10)+'), '
            elif char_gain_roll <= 83:
                name += 'A +'+str(random.randint(1, 3))+'), '
            elif char_gain_roll <= 85:
                name += 'Fel +'+str(random.randint(1, 3)*10)+'), '
            elif char_gain_roll <= 87:
                name += 'Int +'+str(random.randint(1, 3)*10)+'), '
            elif char_gain_roll <= 89:
                name += 'WP +'+str(random.randint(1, 3)*10)+'), '
        elif enchantment == '3':
            char_drain_roll = random.randint(1, 80)
            name += 'Characteristic Drain ('
            if char_drain_roll <= 15:
                name += 'WS -10), '
            elif char_drain_roll <= 30:
                name += 'S -10), '
            elif char_drain_roll <= 40:
                name += 'T -10), '
            elif char_drain_roll <= 50:
                name += 'Agi -10), '
            elif char_drain_roll <= 60:
                name += 'Fel -10), '
            elif char_drain_roll <= 70:
                name += 'Int -10), '
            elif char_drain_roll <= 80:
                name += 'WP -10), '
        elif enchantment == '4':
            name += 'Bane ('
            bane_roll = random.randint(1, 100)
            if bane_roll <= 5:
                name += 'Goblins and Snotlings'
            elif bane_roll <= 10:
                name += 'Hobgoblins'
            elif bane_roll <= 20:
                name += 'Orcs'
            elif bane_roll <= 25:
                name += 'All Goblinoids'
            elif bane_roll <= 27:
                name += 'Elementals'
            elif bane_roll <= 30:
                name += 'Daemons'
            elif bane_roll <= 35:
                name += 'Undead'
            elif bane_roll <= 45:
                name += 'Non-Daemonic creatures and followers of Chaos'
            elif bane_roll <= 50:
                name += 'Dragons'
            elif bane_roll <= 55:
                name += 'All reptiles'
            elif bane_roll <= 60:
                name += 'Dwarfs, Gnomes and Halflings'
            elif bane_roll <= 65:
                name += 'Elves'
            elif bane_roll <= 70:
                name += 'Fimir'
            elif bane_roll <= 75:
                name += 'Giant Animals'
            elif bane_roll <= 80:
                name += 'Skaven'
            elif bane_roll <= 85:
                name += 'Giants'
            elif bane_roll <= 90:
                name += 'Ogres and Trolls'
            elif bane_roll <= 95:
                name += 'Werecreatures'
            elif bane_roll <= 100:
                name += 'Vampires'
            name += '), '
        elif enchantment == '16':
            name += 'Protection ('
            protection_roll = random.randint(1, 100)
            if protection_roll <= 75:
                name += '+1 AP in all areas'
            elif protection_roll <= 90:
                name += '+2 AP in all areas'
            elif protection_roll <= 95:
                name += '+3 AP in all areas'
            elif protection_roll <= 98:
                name += '1 Attack per round automatically parried'
            elif protection_roll <= 100:
                name += '2 Attacks per round automatically parried'
            name += '), '
        else:
            name += weapon_enchantment_dict[enchantment]+', '
    name = name[:-2]
    name += ')'
    final_object = [object_id, name, description, source, page]
    return final_object


from astropy.nddata import support_nddata

from astropy import log
import numpy as np
from astropy.wcs import wcs
import craspy.axes as axes

from .index import _slab
from .homogen import synthesize_bubbles
import matplotlib.pyplot as plt

def _draw_spectra(data, wcs=None, unit=None,velocities=False):
    try:
        freq_axis = axes._get_axis(wcs, "FREQ")
    except ValueError:
        log.warning("Data does not have a spectral dimension")
        return
    ll = list(range(wcs.naxis))
    ll.remove(freq_axis)
    yvals = np.nansum(data, axis=tuple(ll))
    plt.ylabel(unit)
    if velocities == True:
        xvals = axes.spectral_velocities(data, wcs=wcs)
        plt.xlabel("VEL [Km/s]")
    else:
        dim = wcs.wcs.spec
        fqis = np.arange(data.shape[data.ndim - dim - 1])
        idx = np.zeros((fqis.size, data.ndim))
        idx[:, dim] = fqis
        vals = wcs.all_pix2world(idx, 0)
        xvals = vals[:, dim]
        plt.xlabel("FREQ [Hz]")
    plt.plot(xvals, yvals)

@support_nddata
def visualize_spectra(data, wcs=None, unit=None,velocities=False):
    if wcs is None:
        if data.ndim != 1:
            log.info("Only 1D data can be shown without WCS")
            return
        else:
            visualize_plot(data,wcs,unit)
            return
    _draw_spectra(data,wcs,unit,velocities)
    plt.show()

@support_nddata
def visualize(data,wcs=None,unit=None):
    """
    Generic function to visualize data, line-plot for 1D and image for 2D.

    Parameters
    ----------
    data : numpy.ndarray or astropy.nddata.NDData or astropy.nddata.NDDataRef
        Astronomical image

    wcs : astropy.wcs.WCS
        World Coordinate System from the image (not needed if contained in NDData)

    unit : astropy.unit
        Image units (not needed if contained in NDData)
    """

    if data.ndim == 1:
        return visualize_plot(data,wcs,unit)
    elif data.ndim == 2:
        return visualize_image(data,wcs,unit)
    elif data.ndim == 3:
        if axes._is_spectra(data,wcs):
            visualize_spectra(data,wcs,unit)
        else:
            #TODO: Moment 0
            visualize_image(data,wcs,unit)
    else:
        log.error("Data dimensions must be between 1 and 3")

@support_nddata
def visualize_plot(data,wcs=None,unit=None):
    """
    Plot 1D data for astronomical data.

    Parameters
    ----------
    data : numpy.ndarray or astropy.nddata.NDData
        Astronomical image

    wcs : astropy.wcs.WCS
        World Coordinate System from the image (not needed if contained in NDData)

    unit : astropy.unit
        Image units (not needed if contained in NDData)
    """
    if wcs is None:
        plt.plot(data)
        plt.ylabel(unit)
    else:
        #TODO: Implement x vector, but check why the wcs cannot be onedimensional!
        plt.plot(data)
        plt.ylabel(unit)
        plt.xlabel(wcs.axis_type_names[0])
    plt.show()

def _draw_image(data,gax,wcs,unit,cmap=plt.cm.gist_heat):
    plt.imshow(data, origin='lower', cmap=cmap)
    g0 = gax.coords[0]
    g1 = gax.coords[1]
    g0.set_axislabel(wcs.axis_type_names[0])
    g1.set_axislabel(wcs.axis_type_names[1])
    cb = plt.colorbar()
    cb.ax.set_ylabel(unit)

@support_nddata
def show_subcube(data,wcs=None,meta=None,mask=None,unit=None,lower=None,upper=None):
    plt.figure(figsize=(10,5))
    mslab=_slab(data, lower, upper)
    #scube=reduction.cut(data,wcs=wcs,meta=meta,mask=mask,unit=unit,lower=lower,upper=upper)
    if data.ndim == 3:
        freq_axis = axes._get_axis(wcs, "FREQ")
        wcs=wcs.slice(mslab, numpy_order=True)
        wcsp=wcs.dropaxis(wcs.wcs.spec)
        im1=121
        #data2d= np.nansum(data, axis=(freq_axis))
        #scube2d=np.nansum(scube.data, axis=(freq_axis))
    else:
        wcs=wcs.slice(mslab, numpy_order=True)
        wcsp=wcs
        im1=111
        #im2=122
        #data2d=data
        #scube2d=scube.data
    gax=plt.subplot(im1,projection=wcsp)
    if data.ndim == 3:
        _draw_image(np.nansum(data[mslab],axis=freq_axis),gax,wcsp,unit,cmap=plt.cm.seismic)
    else:
        _draw_image(data[mslab], gax, wcsp, unit, cmap=plt.cm.seismic)
    #gax=plt.subplot(im2, projection=swcs2d)
    #_draw_image(scube2d, gax, swcs2d, unit, cmap=plt.cm.seismic)
    if (data.ndim == 3):
        #plt.subplot(223)
        #_draw_spectra(data,wcs=wcs,unit=unit)
        plt.subplot(122)
        _draw_spectra(data[mslab], wcs=wcs, unit=unit)
    plt.show()
    #return(scube)

def show_clumps(hrtree,node=0,print_numbers=True):
    fig = plt.figure(figsize=(10, 10))
    shape = hrtree.synth.data.shape
    parent=hrtree.find_parent(node,hrtree.tree)
    n_colors = hrtree.visible_clumps(parent,node)
    gs = gridspec.GridSpec(2, 2,width_ratios=[shape[2] / shape[0], 1], height_ratios=[shape[1] / shape[0], 1])
    tempXY = hrtree.synth.data.sum(axis=(0))
    nax = plt.subplot(gs[0])
    nax.imshow(tempXY, origin='lower', cmap=plt.cm.gray_r)
    nax.get_xaxis().set_visible(False)
    nax.get_yaxis().set_visible(False)

    tempXZ = hrtree.synth.data.sum(axis=(1))
    nax2 = plt.subplot(gs[2])
    nax2.imshow(tempXZ, origin='lower', cmap=plt.cm.gray_r)
    nax2.get_xaxis().set_visible(False)
    nax2.get_yaxis().set_visible(False)

    tempYZ = hrtree.synth.data.sum(axis=(2)).T
    nax3 = plt.subplot(gs[1])
    nax3.imshow(tempYZ, origin='lower', cmap=plt.cm.gray_r)
    nax3.get_xaxis().set_visible(False)
    nax3.get_yaxis().set_visible(False)

    color = plt.cm.rainbow(np.linspace(0, 1, n_colors))

    hrtree.t_n = 0
    def plotme(key):
        newSyn = np.zeros(shape)
        newSyn = synthesize_bubbles(newSyn, hrtree.clumps[key], hrtree.kernel, hrtree.noise, hrtree.delta)
        ct = nax.contour(newSyn.sum(axis=(0)), levels=[0.0], alpha=1.0, colors=[color[hrtree.t_n]])
        if print_numbers:
            plt.clabel(ct, fontsize=10, inline=1, fmt={0.0: str(key)})
        ct = nax2.contour(newSyn.sum(axis=(1)), levels=[0.0], alpha=1.0, colors=[color[hrtree.t_n]])
        if print_numbers:
            plt.clabel(ct, fontsize=10, inline=1, fmt={0.0: str(key)})
        ct = nax3.contour(newSyn.sum(axis=(2)).T, levels=[0.0], alpha=1.0, colors=[color[hrtree.t_n]])
        if print_numbers:
            plt.clabel(ct, fontsize=10, inline=1, fmt={0.0: str(key)})
        hrtree.t_n += 1

    def recu(tree):
        for (key, val) in tree.items():
            if hrtree.enabled[key]:
                if hrtree.display[key]:
                   plotme(key)
                if isinstance(val, dict):
                    recu(val)
    if hrtree.enabled[node]:
        if hrtree.display[node]:
            plotme(node)
    if isinstance(parent[node], dict):
        recu(parent[node])

    #i = 0
    #for b in bco:
    #    imask = (labels == b)
    #    npos = sol[imask]
    #    newSyn = np.zeros(shape)
    #    newSyn = synthesize_bubbles(newSyn, npos, mould, noise, delta)
    #    nax.contour(newSyn.sum(axis=(0)), levels=[0.0], alpha=1.0, colors=[color[i]])
    #    nax2.contour(newSyn.sum(axis=(1)), levels=[0.0], alpha=1.0, colors=[color[i]])
    #    nax3.contour(newSyn.sum(axis=(2)).T, levels=[0.0], alpha=1.0, colors=[color[i]])
    #    i += 1
    #plt.tight_layout()
    plt.show()
    #plt.figure()

    # nax4=fig.add_subplot(1,3,3)
    #nax4 = plt.subplot(111)
    #i = 0
    #for b in bco:
    #    imask = (labels == b)
    #    npos = sol[imask]
    #    newSyn = np.zeros(shape)
    #    newSyn = synthesize_bubbles(newSyn, npos, mould, noise, delta)
    #    nax.contour(newSyn.sum(axis=(0)), levels=[0.0], alpha=1.0, colors=[color[i]])
    #    nax2.contour(newSyn.sum(axis=(1)), levels=[0.0], alpha=1.0, colors=[color[i]])
    #    nax3.contour(newSyn.sum(axis=(2)).T, levels=[0.0], alpha=1.0, colors=[color[i]])
    #    nax4.plot(newSyn.sum(axis=(1, 2)), color=color[i])
    #    i += 1
    #plt.tight_layout()
    #plt.show()
    #return (bco)

@support_nddata
def visualize_image(data,wcs=None,unit=None,contour=False,cmap=None):
    """
    Plot 2D astronomical data.

    Parameters
    ------------
    data : numpy.ndarray or astropy.nddata.NDData or astropy.nddata.NDDataRef
        Astronomical image

    wcs : astropy.wcs.WCS
        World Coordinate System from the image (not needed if contained in NDData)

    unit : astropy.unit
        Image units (not needed if contained in NDData)

    contour : numpy.ndarray
        For plotting Contourns
    """
    if cmap is None:
        cmap=plt.cm.gray_r
    if wcs is None:
        if data.ndim != 2:
            log.info("Cannot visualize image data with no WCS and dimension != 2")
            return
        plt.imshow(data, origin='lower', cmap=cmap)
        cb = plt.colorbar()
        cb.ax.set_ylabel(unit)
    else:
        # Only work for spectral cubes... what else?
        if data.ndim == 3:
            try:
                freq_axis = axes._get_axis(wcs, "FREQ")
            except ValueError:
                log.warning("Data does not have a FREQ dimension to stack, aborting visualization")
                return
            wcs = wcs.dropaxis(wcs.naxis - freq_axis - 1)
            data = np.nansum(data, axis=(freq_axis))
        gax = plt.subplot(111, projection=wcs)
        _draw_image(data, gax, wcs, unit,cmap=cmap)
        g0 = gax.coords[0]
        g1 = gax.coords[1]
        g0.grid(color='yellow', alpha=0.5, linestyle='solid')
        g1.grid(color='yellow', alpha=0.5, linestyle='solid')
        if contour:
            arms=rms(data)
            dmax=data.max()
            crs=np.arange(1,dmax/arms)
            plt.contour(data,levels=arms*crs,alpha=0.5)
    plt.show()

# Specific plotting function
def plot_snr_estimation(target,snr_results):
    fig = plt.figure(figsize=(10,4))
    # Unpack results
    (slimit,rms,x,y,v,n,p)=snr_results
    # Plot
    ax = fig.add_subplot(1,1,1)
    ax.plot(x,y,color='b')
    ax.plot(x,x,color='b',linestyle="--")
    ax.axvline(x=slimit,color='r',label="$"+str(slimit)+" \sigma$")
    ax.legend(loc=7)
    ax.set_title(target)
    ax.set_xlabel("SNR ($ \\tau / \sigma$)")
    ax.set_ylabel('RMS', color='b')
    for tl in ax.get_yticklabels():
        tl.set_color('b')
    axp = ax.twinx()
    axp.plot(x[:-1],v,color='grey')
    axp.set_ylabel('$\Delta$RMS', color='grey')
    for tl in axp.get_yticklabels():
        tl.set_color('grey')

def visualize_rgb(rdata,gdata,bdata):
    wcs=rdata.wcs
    gax = plt.subplot(111, projection=wcs)
    sh = rdata.data.shape
    data = np.zeros((sh[0],sh[1],3))
    #plt.imshow(gdata.data)
    #plt.show()
    (rdata,_,_)=flux.standarize(rdata)
    (gdata,_,_)=flux.standarize(gdata)
    (bdata,_,_)=flux.standarize(bdata)
    data[:,:,0] = rdata.data/np.nanmax(rdata.data)
    data[:,:,1] = gdata.data/np.nanmax(gdata.data)
    data[:,:,2] = bdata.data/np.nanmax(bdata.data)
    plt.imshow(data, origin='lower')
    g0 = gax.coords[0]
    g1 = gax.coords[1]
    g0.set_axislabel(wcs.axis_type_names[0])
    g1.set_axislabel(wcs.axis_type_names[1])
    #cb = plt.colorbar()
    #cb.ax.set_ylabel(unit)
    g0 = gax.coords[0]
    g1 = gax.coords[1]
    g0.grid(color='yellow', alpha=0.5, linestyle='solid')
    g1.grid(color='yellow', alpha=0.5, linestyle='solid')
    plt.show()

from matplotlib import gridspec

# TODO: vmax can be computed by default
def show_image_grid(img_list,side,vmax,cmap=None):
    if cmap == None:
        cmap="gray_r"
    origin="lower"

    plt.figure(figsize=(10,10))
    gs = gridspec.GridSpec(side, side,wspace=0.0, hspace=0.0)
    for i in range(side*side):
        ax  = plt.subplot(gs[i])
        ax.imshow(img_list[i],origin=origin,vmax=vmax,vmin=0,cmap=cmap)
        ax.get_xaxis().set_visible(False)
        ax.get_yaxis().set_visible(False)
    plt.show()


from enum import Enum
from collections import namedtuple
import re

class Transação(object):
	"""docstring for Transação"""
	# Estados possíveis em que uma transação pode estar
	(INICIADA, LENDO, COMMITED) = (1, 2, 3)

	def __init__(self, identificador, operações):
		super(Transação, self).__init__()
		self.identificador = identificador
		self.operações = operações
		self.estado = self.INICIADA
		self.conjunto_leitura = set()
		self.conjunto_escrita = set()

		self.timestamp_commit = None
		self.timestamp_leitura = None

		for op in operações:
			if   op.op == "w":
				self.conjunto_escrita.add(op.objeto)
			elif op.op == "r":
				self.conjunto_leitura.add(op.objeto)

	def __repr__(self):
		out = "Transação("+repr(self.identificador)+",[\""
		for op in self.operações:
			out+=op.op+"("+op.objeto+")"
		out += "\"])"
		return out

	def __str__(self):
		out = "T"+str(self.identificador)+":"
		for op in self.operações:
			out+=op.op+"("+op.objeto+")"
		return out

	def nome(self):
		return "T"+str(self.identificador)

	def primeiro_teste(Ti,Tj):
		"""Transação Tj completa sua fase de escrita antes que Ti começou sua
		fase de leitura """
		#print ("Primeiro Teste")
		#print (Tj.nome()+".timestamp_commit < "+Ti.nome()+".timestamp_leitura")
		#print (str(Tj.timestamp_commit)+"<"+str(Ti.timestamp_leitura))
		#print ((Tj.timestamp_commit)<(Ti.timestamp_leitura))
		return Tj.timestamp_commit < Ti.timestamp_leitura

	def segundo_teste(Ti, Tj):
		"""Ti começa a sua fase de escrita depois que Tj completa sua fase de
		escrita e o conjunto de leitura de Ti não tem intersecção com o
		conjunto de escrita de Tj"""
		#print ("\nSegundo Teste")
		#print (Ti.nome()+".conjunto_leitura.isdisjoint("+Tj.nome()+".conjunto_escrita)")
		#print (str(Ti.conjunto_leitura)+".isdisjoint("+str(Tj.conjunto_escrita)+")")
		#print (Ti.conjunto_leitura.isdisjoint(Tj.conjunto_escrita))
		return Ti.conjunto_leitura.isdisjoint(Tj.conjunto_escrita)

	def terceiro_teste(Ti, Tj):
		"""A união do conjunto de leitura e escrita de Ti não tem intersecção
		com o conjunto de escrita de Tj e Tj completa sua fase de leitura antes
		de Ti."""
		x = Ti.conjunto_leitura.isdisjoint(Tj.conjunto_escrita) and \
		    Ti.conjunto_escrita.isdisjoint(Tj.conjunto_escrita)
		#print("\nTerceiro Teste")
		#print(Ti.nome()+".conjunto_leitura.isdisjoint("+Tj.nome()+".conjunto_escrita) and \n"+
		#      Ti.nome()+".conjunto_escrita.isdisjoint("+Tj.nome()+".conjunto_escrita)")
		#print(str(Ti.conjunto_leitura)+".isdisjoint("+str(Tj.conjunto_escrita)+") and \n"+
		#      str(Ti.conjunto_escrita)+".isdisjoint("+str(Tj.conjunto_escrita)+")")
		#print(x)
		return x

	def validar(Ti,timestamp,comitadas):
		teste = lambda Tj: Ti.primeiro_teste(Tj) or \
		                   Ti.segundo_teste(Tj)  or \
		                   Ti.terceiro_teste(Tj)

		validada = all(map(teste,comitadas))
		if (validada):
			Ti.timestamp_commit = timestamp
			Ti.estado = Ti.COMMITED
		return validada

	def ler_do_arquivo(caminho):
		arquivo = open(caminho,"r");
		retorno = []
		for line in arquivo:
			identificador = int(line.split(":")[0][1:])
			operações = re.findall("(\S+?)\((\S+?)\)",line.split(":")[1])
			operações = list(map(Operação._make,operações))
			retorno.append(Transação(identificador,operações))
		return retorno

	def iniciar_leitura(self,timestamp):
		self.estado = self.LENDO
		self.timestamp_leitura = timestamp
		self.numero_operações = 0

	def próxima_operação(self):
		"""Leva a transação par a próxima operação.
		Retorna True se todas as operações daquela transação forem realizadas,
		assinalando a hora de dar commit"""

		self.numero_operações = self.numero_operações + 1
		return self.numero_operações == len(self.operações)

	def reiniciar_transação(self):
		"""Reincia a transação"""
		self.estado = self.INICIADA

Operação = namedtuple("Operação",['op','objeto'])


import vision
import telebot
import os
import time

# Так делать не стоит: токены/пароли и прочее стоит хранить в переменных окружения или конфигурационных файлах.
# Я не буду это исправлять потому что мне лень
# bot = telebot.TeleBot("1918344985:AAFnF5zliY0ULGMLxXE0X4WxXb69aJzDzc8")

# Так наверно можно писать, но на мой взгляд лучше запихнуть все в функцию, чтобы четко было видно где программа начинается и что она делает
# image_path = get_image_from_camera()
# c = count_faces(image_path)

# if c > 0:
#     bot.send_message(
#         240940120,
#         f"{os.getlogin()} на вашем этаже обнаружен инопланетянин",
#     )

#     bot.send_photo(240940120, open(image_path, "rb"))

def start():
    bot = telebot.TeleBot("1918344985:AAFnF5zliY0ULGMLxXE0X4WxXb69aJzDzc8")
    chat_id = 240940120

    while True:
        # Получаем изображение
        image_path = vision.save_image_from_camera()

        # Считаем количество лиц на фото
        faces = vision.count_faces(image_path)

        # Если на фото есть лицо, отправляем сообщение с помощью бота
        if faces > 0:
            bot.send_message(
                chat_id,
                f"на вашем этаже обнаружен инопланетянин",
            )

            bot.send_photo(chat_id, open(image_path, "rb"))
        time.sleep(8)

# Вызываем объявленную выше функцию
start()


from typing import List
import mido

def get_midi_notes(msg_list: List):
    cache = []
    notes = []
    for msg in msg_list:
        if msg.is_meta or (msg.type != 'note_on' and msg.type != 'note_off'):
            continue

        if cache:
            chord = [(MidiNote(cache[0][0], cache[0][1], msg.time))]
            if len(cache) > 1:
                for tone in cache[1:]:
                    chord.append(MidiNote(tone[0], tone[1], msg.time))
            notes.append(MidiChord(tuple(chord)))

        curr_tone = (msg.note, msg.channel)
        if curr_tone in cache:
            cache.remove(curr_tone)
        else:
            cache.append(curr_tone)

    return notes

class MidiNote:

    def __init__(self, note, channel, duration, velocity=64):
        self.note = note
        self.velocity = velocity
        self.channel = channel
        self.duration = duration

    def __eq__(self, other):
        if not isinstance(other, MidiNote):
            return NotImplemented
        return (self.velocity == other.velocity
                and self.note == other.note
                and self.channel == other.channel
                and self.duration == other.duration)

    def __hash__(self):
        return hash((self.velocity, self.channel, self.note, self.duration))

    def as_msgs(self):
        start = mido.Message('note_on', note=self.note,
                             channel=self.channel, velocity=self.velocity,
                             time=0)
        end = mido.Message('note_off', note=self.note,
                           channel=self.channel, velocity=0,
                           time=self.duration)
        return (start, end)

    def __str__(self):
        return 'Note: {} Channel: {} Velocity: {} Duration: {}'.format(
            self.note, self.channel, self.velocity, self.duration)

class MidiChord():

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

    def __eq__(self, other):
        if not isinstance(other, MidiChord):
            return NotImplemented
        return self.tones == other.tones

    def __hash__(self):
        return hash(self.tones)

    def __str__(self):
        s = ""
        for note in self.tones:
            s += str(note)
        return s

    def as_msgs(self):
        starts = []
        stops = []
        for tone in self.tones:
            start, stop = tone.as_msgs()
            starts.append(start)
            stops.append(stop)
        return starts + stops


import argparse
import os
import sys
from importlib import metadata
from typing import Callable, Optional

from jmeslog import core, model
from jmeslog.constants import DEFAULT_RENDER_TEMPLATE
from jmeslog.errors import NoChangesFoundError, ValidationError

SUB_CMD_FUNC = Callable[[argparse.Namespace], int]

def cmd_new_release(args: argparse.Namespace) -> int:
    # Parse the upcoming changes and determine the type of version
    # bump.
    # Apply the version bump to the last known release and figure out
    # the new version.
    # Create a new version file from the existing changes.
    # Delete the next changes folder.
    changes = core.load_next_changes(args.change_dir)
    if args.release_version is not None:
        next_version = args.release_version
    else:
        last_released_version = core.find_last_released_version(
            args.change_dir
        )
        next_version = core.determine_next_version(
            last_released_version, changes.version_bump_type
        )
    release_file = core.consolidate_next_release(
        next_version, args.change_dir, changes
    )
    print(f"New release file written: {release_file}")
    return 0

def cmd_new_change(args: argparse.Namespace) -> int:
    entry = model.JMESLogEntry(
        type=args.type, category=args.category, description=args.description
    )
    recorder = core.create_entry_recorder(entry, args.change_dir)
    try:
        change_file = recorder.write_change_file_entry()
    except ValidationError as e:
        sys.stderr.write(str(e))
        sys.stderr.write("\n")
        return 1
    except Exception:
        sys.stderr.write("Unexpected error raised:\n\n")
        raise
    print(
        f"The change has been written to: {change_file}\n"
        f"You add this to your commit by running:\n\n"
        f"git add {change_file}\n"
    )
    return 0

def cmd_render(args: argparse.Namespace) -> int:
    changes = core.load_all_changes(args.change_dir)
    template_file = None
    if args.template:
        template_file = os.path.join(
            args.change_dir, 'templates', args.template
        )
        with open(template_file) as f:
            template_contents = f.read()
    else:
        template_contents = DEFAULT_RENDER_TEMPLATE
    core.render_changes(changes, sys.stdout, template_contents)
    return 0

def cmd_init(args: argparse.Namespace) -> int:
    if not os.path.isdir(args.change_dir):
        os.mkdir(args.change_dir)
    return 0

def cmd_query(args: argparse.Namespace) -> int:
    runner = core.ChangeQuery(args.change_dir)
    try:
        result = runner.run_query(args.query_for)
    except NoChangesFoundError as e:
        sys.stdout.write(str(e))
        sys.stdout.write("\n")
        return 1
    print(result)
    return 0

def cmd_pending(args: argparse.Namespace) -> int:
    pending_changes = core.load_next_changes(args.change_dir)
    sys.stdout.write('\n')
    core.render_single_release_changes(pending_changes, sys.stdout)
    return 0

def create_parser() -> argparse.ArgumentParser:
    parser = argparse.ArgumentParser()
    parser.add_argument(
        '--version', action='version', version=metadata.version(__package__)
    )
    parser.add_argument(
        '--change-dir',
        default='.changes',
        help='The location of the .changes directory.',
    )
    subparser = parser.add_subparsers()

    init = subparser.add_parser('init')
    init.set_defaults(func=cmd_init)

    new_change = subparser.add_parser('new-change')
    new_change.set_defaults(func=cmd_new_change)
    new_change.add_argument(
        '-t',
        '--type',
        default='',
        choices=('bugfix', 'feature', 'enhancement'),
    )
    new_change.add_argument('-c', '--category', dest='category', default='')
    new_change.add_argument(
        '-d', '--description', dest='description', default=''
    )

    new_release = subparser.add_parser('new-release')
    new_release.set_defaults(func=cmd_new_release)
    new_release.add_argument(
        '-r', '--release-type', default='', choices=('patch', 'minor', 'major')
    )
    new_release.add_argument(
        '--release-version',
        help=(
            'Specify release version.  If not specified '
            'this value will be determined automatically.'
        ),
    )
    new_release.add_argument(
        '-d',
        '--description',
        dest='description',
        help=("Provide additional release notes for this " "release."),
    )

    render = subparser.add_parser('render')
    render.add_argument(
        '-t',
        '--template',
        help=(
            'The name of the template to use from the '
            '.changes/templates/ directory.'
        ),
    )
    render.set_defaults(func=cmd_render)

    query = subparser.add_parser('query')
    query.add_argument(
        'query_for',
        choices=('next-release-type', 'next-version', 'last-release-version'),
    )
    query.set_defaults(func=cmd_query)

    pending = subparser.add_parser('pending')
    pending.set_defaults(func=cmd_pending)

    return parser

def main(argv: Optional[list[str]] = None) -> int:
    parser = create_parser()
    if argv is None:
        argv = sys.argv[1:]
    args = parser.parse_args(argv)
    if not hasattr(args, 'func'):
        parser.print_help()
        return 0
    else:
        handler: SUB_CMD_FUNC = args.func
        return handler(args)

if __name__ == '__main__':
    sys.exit(main())


import os
import sys
import random
import itertools
import numpy as np
import datetime

import tensorflow as tf
os.environ['CUDA_VISIBLE_DEVICES'] = '0'

gpus = tf.config.experimental.list_physical_devices('GPU')
for gpu in gpus:
    tf.config.experimental.set_memory_growth(gpu, True)

def main():
    BASE_MODEL_NAMES = ["SpCas9-NG", "SpCas9", "VRQR variant", "SpCas9-NG", "SpCas9-NRRH", "SpCas9-NRTH", "SpCas9-NRCH", "SpG", "SpRY", "Sc++"]
    base_model_names = ["NG", "SpCas9", "VRQR", "NG", "NRRH", "NRTH", "NRCH", "SpG", "SpRY", "Sc++"]
    EDITOR_NAMES = ["YE1-BE4max", "SsAPOBEC3B", "ABE8e(V106W)", "ABE8.17m+V106W", "CGBE1", "miniCGBE1", "APOBEC-nCas9-Ung"]
    editor_names = ["YE1", "Ss", "8e", "17m", "CGBE1", "mini", "Bi"]
    starts = [7, 6, 6, 6, 7, 7, 7]
    lengths = [5, 7, 8, 8, 5, 5, 5]

    path = sys.argv[1]

    FILE = open(os.path.join(path, "MODEL.txt"), "r")
    MODEL = int(FILE.readlines()[0][0])
    FILE.close()
    if MODEL == 1:
        EDITOR_NAMES = EDITOR_NAMES[2:4]
        editor_names = editor_names[2:4]
        starts = starts[2:4]
        lengths = lengths[2:4]
    elif MODEL == 2:
        EDITOR_NAMES = EDITOR_NAMES[:2]
        editor_names = editor_names[:2]
        starts = starts[:2]
        lengths = lengths[:2]
    else:
        EDITOR_NAMES = EDITOR_NAMES[4:]
        editor_names = editor_names[4:]
        starts = starts[4:]
        lengths = lengths[4:]

    with open(os.path.join(path, "input.txt"), "r") as FILE:
        lines = FILE.readlines()

    TIME = open(os.path.join(path, "TIME.txt"), "w")
    TIME_START = datetime.datetime.now()

    time_start = datetime.datetime.now()
    seq, SEQ_PAM = preprocess_seq_pam(lines[3:])

    SEQS = {}
    for editor_i, (editor_name, start, length) in enumerate(zip(editor_names, starts, lengths)):
        SEQS[editor_name] = preprocess_seq(lines[3:], start, length)
    time_end = datetime.datetime.now()
    TIME.write("\t".join(["%30s" % 'preprocess', "%30s" % 'elapsed time:', str(time_end - time_start)]) + "\n")

    MODELS = {}
    time_start = datetime.datetime.now()
    for base_i, base_model_name in enumerate(base_model_names):
        if base_i != 0:
            MODELS['PAM_variant_%s_model.h5' % base_model_name] = \
                tf.keras.models.load_model('bin/DeepCas9variants/PAM_variant_%s_model.h5' % base_model_name, compile=False)

    for editor_i, (editor_name, start, length) in enumerate(zip(editor_names, starts, lengths)):
        MODELS['DeepNG-BE_%s_model' % editor_name] = \
            tf.keras.models.load_model('bin/DeepBE/DeepNG-BE_%s_model' % editor_name, compile=False)
        MODELS['DeepBE_%s_model' % editor_name] = \
            tf.keras.models.load_model('bin/DeepBE/DeepBE_%s_model' % editor_name, compile=False)
    time_end = datetime.datetime.now()
    TIME.write("\t".join(["%30s" % "model_load", "%30s" % 'elapsed time:', str(time_end - time_start)]) + "\n")

    scores = []
    for base_i, base_model_name in enumerate(base_model_names):
        time_start = datetime.datetime.now()
        if base_i != 0:
            base_score = MODELS['PAM_variant_%s_model.h5' % base_model_name].predict(SEQ_PAM, batch_size=4096)
        time_end = datetime.datetime.now()
        TIME.write("\t".join(["%30s" % (base_model_name+"-pred"), "%30s" % 'elapsed time:', str(time_end - time_start)]) + "\n")

        for editor_i, (editor_name, start, length) in enumerate(zip(editor_names, starts, lengths)):
            time_start = datetime.datetime.now()
            if base_i == 0:
                score = MODELS['DeepNG-BE_%s_model' % editor_name].predict([SEQ_PAM, SEQ_PAM], batch_size=4096)
            else:
                score = MODELS['DeepBE_%s_model' % editor_name].predict([[SEQS[editor_name], base_score], SEQ_PAM], batch_size=4096)
            time_end = datetime.datetime.now()
            TIME.write("\t".join(["%30s" % (editor_name + "-pred"), "%30s" % 'elapsed time:', str(time_end - time_start)]) + "\n")

            time_start = datetime.datetime.now()
            alist = []
            for x in range(length):
                b = []
                for i in range(1, 2**x + 1):
                    for k in range(1, 2**(length-1 - x) + 1):
                        b.append(2**(length - x) * i - k - 1)
                alist.append(b)
            time_end = datetime.datetime.now()
            TIME.write("\t".join(["%30s" % "create-alist", "%30s" % 'elapsed time:', str(time_end - time_start)]) + "\n")

            time_start = datetime.datetime.now()
            for i in range(len(score)):
                eff = score[i].sum()
                motif = seq[i][start:start+length]
                non = []
                for k in range(length):
                    if ((editor_name in ["YE1", "Ss"] and motif[k] in 'Cc') or
                        (editor_name in ["8e", "17m"] and motif[k] in 'Aa') or
                        (editor_name in ["CGBE1", "mini", "Bi"] and motif[k] in 'Cc')):
                        non.append(2**(length-1 - k))
                on = []
                for j in range(len(non)):
                    iter = list(itertools.combinations(non, j+1))
                    for k in iter:
                        on.append(sum(k))
                on = [x - 1 for x in on]
                off = list(set(list(range(2**(length)-1))) - set(on))

                # for m in off:
                #     score[score == score[i, m]] = 0
                score[i, off] = 0

                patt = score[i].sum()
                score[i] = (score[i] / patt) * eff * 100
            time_end = datetime.datetime.now()
            TIME.write("\t".join(["%30s" % "set-score", "%30s" % 'elapsed time:', str(time_end - time_start)]) + "\n")

            time_start = datetime.datetime.now()
            if base_i == 0:
                output = "DeepNG-BE_%s_%s_Results.txt" % (BASE_MODEL_NAMES[base_i], EDITOR_NAMES[editor_i])
            else:
                output = "DeepBE_%s_%s_Results.txt" % (BASE_MODEL_NAMES[base_i], EDITOR_NAMES[editor_i])

            with open(os.path.join(path, output), "w") as OUTPUT:
                OUTPUT.write("\t".join(["Model", "", "", "", "", "", "", "DeepNG-BE" if base_i == 0 else "DeepBE"]) + "\n")
                OUTPUT.write("\t".join(["Nuclease or nickase", "", "", "", "", "", "", BASE_MODEL_NAMES[base_i]]) + "\n")
                OUTPUT.write("\t".join(["ID", "Location", "Input Sequence (30bp)", "Target Sequence (30bp)", "Guide RNA Sequence (20bp)",
                                        "Outcome Sequence (30bp)", "GC Contents (%)", EDITOR_NAMES[editor_i]]) + "\n")

                scores.append([])
                for i in range(len(seq)):
                    strings = []

                    data = lines[i+3].strip().split("\t")
                    score_sum = 0
                    for j in range(2**(length)-1):
                        strings.append(data[:5] + [seq[i], data[5], "%.3f" % score[i, j] if data[6+len(scores)-1] == "." else "0"])
                        if float(strings[-1][-1]) > 0:
                            score_sum += float(strings[-1][-1])
                    scores[-1].append(score_sum)

                    for k in range(len(alist)):
                        for j in alist[k]:
                            if float(strings[j][-1]) > 0:
                                if editor_name in ["YE1", "Ss"]:
                                    strings[j][5] = strings[j][5][:k+start] + "t" + strings[j][5][k+1+start:]
                                elif editor_name in ["8e", "17m"]:
                                    strings[j][5] = strings[j][5][:k+start] + "g" + strings[j][5][k+1+start:]
                                elif editor_name in ["CGBE1", "mini", "Bi"]:
                                    strings[j][5] = strings[j][5][:k+start] + "g" + strings[j][5][k+1+start:]

                    strings_dict = {}
                    for string in strings:
                        if float(string[-1]) > 0:
                            v = float(string[-1]) * -1
                            while 1:
                                if v not in strings_dict:
                                    strings_dict[v] = string
                                    break
                                else:
                                    v += random.random() * 0.0000001

                    for _, string in sorted(strings_dict.items()):
                        OUTPUT.write("\t".join(string) + "\n")

            time_end = datetime.datetime.now()
            TIME.write("\t".join(["%30s" % "print", "%30s" % 'elapsed time:', str(time_end - time_start)]) + "\n")

    time_start = datetime.datetime.now()
    with open(os.path.join(path, "DeepBE_Results.txt"), "w") as OUTPUT:
        for l in range(len(lines)):
            if l < 3:
                OUTPUT.write(lines[l])
            else:
                data = lines[l].strip().split("\t")
                for i in range(len(data[6:])):
                    if data[6+i] == ".":
                        data[6+i] = "%.3f" % scores[i][l-3]# if scores[i][l-3] > 0.1 else "No activity"
                OUTPUT.write("\t".join(data) + "\n")
    time_end = datetime.datetime.now()
    TIME.write("\t".join(["%30s" % 'print-all', "%30s" % 'elapsed time:', str(time_end - time_start)]) + "\n")

    TIME_END = datetime.datetime.now()
    TIME.write("\n" + "\t".join(["%30s" % 'TOTAL:', "%30s" % 'elapsed time:', str(TIME_END - TIME_START)]) + "\n")
    TIME.close()

    return

def preprocess_seq(lines, start, length):
    DATA_X = np.zeros((len(lines), length + 2, 4), dtype=int)
    for l in range(len(lines)):
        seq = lines[l].split("\t")[3]
        for i in range(length + 2):
            if seq[i + start - 1] in "Aa":    DATA_X[l, i, 0] = 1
            elif seq[i + start - 1] in "Cc":  DATA_X[l, i, 1] = 1
            elif seq[i + start - 1] in "Gg":  DATA_X[l, i, 2] = 1
            elif seq[i + start - 1] in "Tt":  DATA_X[l, i, 3] = 1

    return DATA_X

def preprocess_seq_pam(lines, seq_length=30):
    seqs = []
    DATA_X_PAM = np.zeros((len(lines), seq_length, 4), dtype=int)
    for l in range(len(lines)):
        seq = lines[l].split("\t")[3]
        seqs.append(seq)

        for i in range(seq_length):
            if seq[i]in "Aa":    DATA_X_PAM[l, i, 0] = 1
            elif seq[i] in "Cc": DATA_X_PAM[l, i, 1] = 1
            elif seq[i] in "Gg": DATA_X_PAM[l, i, 2] = 1
            elif seq[i] in "Tt": DATA_X_PAM[l, i, 3] = 1

    return seqs, DATA_X_PAM

if __name__ == '__main__':
    main()