'''

   Python Programming of Blockchain

   was a series of three lectures given within the Graduate Course

   'Blockchain and Future Society'

   Offered in the Fall Semester 2018 at

   GIST, Rep. of Korea. The instructor was Prof. Heung-No Lee.

   The blockchain developed in the course was not meant to be complete.

   Instead, aim was to understand

   what a blockchain, and a cryptocurrency based on it, is by

   doing a little bit of programming work.

   To this end, Prof. Lee utilized the blog work

   "Learn Blockchain by Building One" of Daniel Flymen [1],[2].

   Flymen's blog and his Python code offerred good introductory materials.

   His code was also given to learn blockchain and thus was not meant to be complete.

   In my course, I have given a homework assignment to improve on his work.

   The code presented below was a result of homework assignment which

   a group of students have worked together and made improvements.

   There were several upgrades made to [2]. Just to name a few notable ones, they are

   1) mined blocks now have "correct" block hashes with the designated leading

   number of zeros. 2) A auto mining routine was included in which

   the mining operation is continued at a node which listens

   to a new block announcement and switches if a new longest chain is found.

   Overall the list of functions this code can demonstrate includes:

    1. Announcing transactions,

    2. Including transactions into blocks,

    3. Chaining blocks using Proof-of-Work(PoW),

    4. Chainging the level of PoW difficulty

        by varying the number of leading zeros in hash values,

    5. Following the consensus rule of the longest-chain-win, and

    6. Interworking of peer-to-peer nodes using APIs.

  The source code and the relevant lecture note are available to download here in [3],[4].

References      :   [1] Daniel van Flymen, "Learn Blockchain by Building One,"

                        Sept. 25th, 2017, https://hackernoon.com/learn-blockchains-by-building-one-117428612f46.

                    [2] Daniel van Flymen, Source code at https://github.com/dvf/blockchain/blob/master/blockchain.py.

                    [3] Heung-No Lee, "Lecture Note on Python Programming of Blockchain," https://infonet.gist.ac.kr.

                    [4] Heung-No Lee, Source Code of Python Programming of Blockchain," https://github.com/infonetGIST/Blockchain_lecture.

'''

from threading import Thread, Event

import time
from flask import Flask, jsonify, request
import requests
import hashlib
import json
from urllib.parse import urlparse
from uuid import uuid4

import random

STOP_EVENT = Event()
INTERRUPT_EVENT1 = Event()
INTERRUPT_EVENT2 = Event()

class Blockchain:
    def __init__(self):
        self.current_transactions = []
        self.awaiting_transactions =[]
        self.chain = []
        self.nodes = set()
        self.published_transactions_ID = []
        self.mining_reward_address='0'
        self.MY_NODE_ADDRESS='0'
        # Generate a globally unique address for this node
        self.node_identifier = str(uuid4()).replace('-', '')
        # node_identifier = hex(random.randrange(1, 9999999))
        self.interrupt_flag=False
        self.max_blocks = 30

        dummy_block = {
            'index': 0,
            'timestamp': 0,
            'transactions': [],
            'proof': 0,
            'previous_hash': 0,
        }
        Ini_proof = self.proof_of_work(mining_time=0, last_block=dummy_block)
        self.new_block(previous_hash='0', mining_time=0, proof=Ini_proof)

    def register_node(self, address):
        """
        Add a new node to the list of nodes

        :param address: Address of node. Eg. 'http://192.168.0.5:5000'
        """

        parsed_url = urlparse(address)
        if parsed_url.netloc:
            self.nodes.add(parsed_url.netloc)
        elif parsed_url.path:
            # Accepts an URL without scheme like '192.168.0.5:5000'.
            self.nodes.add(parsed_url.path)
        else:
            raise ValueError('Invalid URL')

    def valid_chain(self, chain):
        """
        Determine if a given blockchain is valid

        :param chain: A blockchain
        :return: True if valid, False if not
        """

        current_index = 1

        while current_index < len(chain):
            block = chain[current_index]
            prev_block=chain[current_index-1]
            #print(f'{last_block}')
            #print(f'{block}')
            #print("\n-----------\n")
            # Check that the hash of the block is correct
            prev_block_hash = self.hash(prev_block)
            if block['previous_hash'] != prev_block_hash:
                return False

            # Check that the Proof of Work is correct
            if not self.valid_proof(block):
                return False

            current_index += 1

        return True

    def resolve_conflicts(self):
        """
        This is our consensus algorithm, it resolves conflicts
        by replacing our chain with the longest one in the network.

        :return: True if our chain was replaced, False if not
        """

        neighbours = self.nodes
        new_chain = None

        # We're only looking for chains longer than ours
        max_length = len(self.chain)

        # Grab and verify the chains from all the nodes in our network
        for node in neighbours:
            response = requests.get(f'http://{node}/chain')

            if response.status_code == 200:
                length = response.json()['length']
                chain = response.json()['chain']

                # Check if the length is longer and the chain is valid
                if length > max_length and self.valid_chain(chain):
                    max_length = length
                    new_chain = chain
                    best_node = node

        # Replace our chain if we discovered a new, valid chain longer than ours
            if new_chain is not None:
                self.chain = new_chain
                self.make_published_TXID_list()
                #response2 = requests.get(f'http://{best_node}/get_transactions')
                #self.current_transactions = response2.json()['transactions']
                print("Chain replaced")
                return True

        return False

    def new_block(self, mining_time, proof, previous_hash):
        """
        Create a new Block in the Blockchain

        :param proof: The proof given by the Proof of Work algorithm
        :param previous_hash: Hash of previous Block
        :return: New Block
        """

        block = {
            'index': len(self.chain) + 1,
            'timestamp': mining_time,
            'transactions': self.current_transactions,
            'proof': proof,
            'previous_hash': previous_hash or self.hash(self.chain[-1]),
        }

        # Reset the current list of transactions
        self.current_transactions = []

        self.chain.append(block)
        self.make_published_TXID_list()
        return block

    def new_transaction(self, sender, recipient, amount):
        """
        Creates a new transaction to go into the next mined Block

        :param sender: Address of the Sender
        :param recipient: Address of the Recipient
        :param amount: Amount
        :return: The index of the Block that will hold this transaction
        """
        TX_time=time.time()
        transaction_dummy = {
            'sender': sender,
            'recipient': recipient,
            'amount': amount,
            'transaction time': TX_time
        }
        TXID = self.hash(transaction_dummy)
        new_TX_content = {
            'TXID': TXID,
            'sender': sender,
            'recipient': recipient,
            'amount': amount,
            'transaction time': TX_time
        }
        if self.is_valid_TX(new_TX_content):
            self.current_transactions.append(new_TX_content)
            self.node_identifier = str(uuid4()).replace('-', '')
            return self.last_block['index'] + 1
        else:
            return None

    def update_transactions(self):

        #neighbours = self.nodes

        my_transactions = self.current_transactions
        my_TX_length = len(self.current_transactions)
        flag = 2
        #for node in neighbours:
        her_response = requests.get(f'http://127.0.0.24:2000/get_awaiting_transactions')
        if her_response.status_code == 200 and her_response.json()['length']:
            her_TX_length = her_response.json()['length']
            her_awaiting_transactions = her_response.json()['awaiting_transactions']
            for j in range(her_TX_length):
                her_TXID = her_awaiting_transactions[j]['TXID']
                flag = 1
                for i in range(my_TX_length):
                    my_TXID = my_transactions[i]['TXID']
                    if my_TXID == her_TXID:
                        flag = 0
                if flag == 1 and self.is_valid_TX(her_awaiting_transactions[j]):
                    self.current_transactions.append(her_awaiting_transactions[j])
        return flag

    def is_valid_TX(self, transaction):
        flag = 1
        for i in range(len(self.published_transactions_ID)):
            if self.published_transactions_ID[i] == transaction['TXID']:
                flag = 0
        if flag == 1:
            return True
        else:
            return False

    def check_current_TXs_validity(self):
        flag = 1
        k = 1
        TX_length = len(self.current_transactions)
        while k <= TX_length:
            if self.is_valid_TX(self.current_transactions[k]):
                k += 1
            else:
                del self.current_transactions[k]
                TX_length -= 1
                flag = 0
        if flag == 1:
            return True
        else:
            return False

    def update_awaiting_TX(self):
        latest_published_TXID = self.published_transactions_ID
        length_LPTXID = len(latest_published_TXID)
        awaiting_transactions = self.awaiting_transactions
        length_ATX = len(awaiting_transactions)
        updated_awaiting_transactions = []

        for i in range(length_ATX):
            flag = 1
            for j in range(length_LPTXID):
                if awaiting_transactions[i]['TXID'] == latest_published_TXID[j]:
                    flag = 0
            if flag == 1:
                updated_awaiting_transactions.append(awaiting_transactions[i])
        self.awaiting_transactions = updated_awaiting_transactions
        return self.awaiting_transactions

    def make_published_TXID_list(self):
        self.published_transactions_ID = []
        chain_length = len(self.chain)
        for i in range(chain_length):
            i_published_transactions = self.chain[i]['transactions']
            i_TX_length = len(i_published_transactions)
            for j in range(i_TX_length):
                i_j_TXID = i_published_transactions[j]['TXID']
                self.published_transactions_ID.append(i_j_TXID)
        return self.published_transactions_ID

    def announcement(self):
        neighbours = self.nodes
        for node in neighbours:
            response = requests.get(f'http://{node}/get_updates')
    def mine(self):
        # We run the proof of work algorithm to get the next proof...
        last_block = self.last_block
        mining_time = time.time(),
        randomSTR = str(uuid4()).replace('-', '')
        self.new_transaction(
            sender="Coinbase transaction",
            recipient=self.mining_reward_address + '  #' + randomSTR,
            amount=1,
        )
        proof = self.proof_of_work(mining_time, last_block)

        # We must receive a reward for finding the proof.
        # The sender is "0" to signify that this node has mined a new coin.

        # Forge the new Block by adding it to the chain
        if proof==0:
            del self.current_transactions[-1]
        else:
            previous_hash = self.hash(last_block)
            block = self.new_block(mining_time, proof, previous_hash)
            print("Mining success!")
            self.announcement()

    @property
    def last_block(self):
        return self.chain[-1]

    @staticmethod
    def hash(block):
        """
        Creates a SHA-256 hash of a Block

        :param block: Block
        """

        # We must make sure that the Dictionary is Ordered, or we'll have inconsistent hashes
        block_string = json.dumps(block, sort_keys=True).encode()
        return hashlib.sha256(block_string).hexdigest()

    def proof_of_work(self, mining_time, last_block):
        """
        Simple Proof of Work Algorithm:

         - Find a number p' such that hash(pp') contains leading 4 zeroes
         - Where p is the previous proof, and p' is the new proof

        :param last_block: <dict> last Block
        :return: <int>
        """

        last_proof = last_block['proof']
        if len(self.chain) == 0:
            last_hash = '0'
        else:
            last_hash = self.hash(last_block)

        proof = 0
        test_block = {
            'index': len(self.chain) + 1,
            'timestamp': mining_time,
            'transactions': self.current_transactions,
            'proof': proof,
            'previous_hash': last_hash or self.hash(self.chain[-1]),
        }
        while self.valid_proof(test_block) is False:
            if self.interrupt_flag:
                blockchain.interrupt_flag = False
                return 0

            proof += 1
            test_block = {
                'index': len(self.chain) + 1,
                'timestamp': mining_time,
                'transactions': self.current_transactions,
                'proof': proof,
                'previous_hash': last_hash or self.hash(self.chain[-1]),
            }

        return proof

    @staticmethod
    def valid_proof(test_block):
        """
        Validates the Proof

        :param last_proof: <int> Previous Proof
        :param proof: <int> Current Proof
        :param last_hash: <str> The hash of the Previous Block
        :return: <bool> True if correct, False if not.

        """
        block_string = json.dumps(test_block, sort_keys=True).encode()
        guess_hash = hashlib.sha256(block_string).hexdigest()
        # guess = f'{last_proof}{proof}{last_hash}'.encode()
        # guess_hash = hashlib.sha256(guess).hexdigest()
        # Difficulty Level is adjusted here!  The number of leading zeros shall be
        # changed together with the :4 number in the parenthesis.
        return guess_hash[:5] == "00000"

# Instantiate the Blockchain
blockchain = Blockchain()

# Instantiate the Node
app = Flask(__name__)

@app.route('/mine', methods=['GET'])
def mine():
    blockchain.mine()
    block=blockchain.last_block
    response = {
        'message': "New Block Forged",
        'index': block['index'],
        'transactions': block['transactions'],
        'proof': block['proof'],
        'previous_hash': block['previous_hash'],
    }
    return jsonify(response), 200

@app.route('/transactions/new', methods=['POST'])
def new_transaction():
    values = request.get_json()
    # Check that the required fields are in the POST'ed data
    required = ['sender', 'recipient', 'amount']
    if not all(k in values for k in required):
        return 'Missing values', 400

    # Create a new Transaction
    index = blockchain.new_transaction(values['sender'], values['recipient'], values['amount'])

    response = {'message': f'Transaction will be added to Block {index}'}
    return jsonify(response), 201

@app.route('/chain', methods=['GET'])
def full_chain():
    # INTERRUPT_EVENT1.set()
    response = {
        'chain': blockchain.chain,
        'length': len(blockchain.chain),
    }
    return jsonify(response), 200

@app.route('/get_transactions', methods=['GET'])
def full_transactions():
    # INTERRUPT_EVENT2.set()
    response = {
        'transactions': blockchain.current_transactions,
        'length': len(blockchain.current_transactions),
    }
    return jsonify(response), 200

@app.route('/get_awaiting_transactions')
def awaiting_transactions():
    response = {
        'awaiting_transactions': blockchain.awaiting_transactions,
        'length': len(blockchain.awaiting_transactions),
    }
    return jsonify(response), 200

@app.route('/get_updates')
def receiving_longest_chain_and_update_TX_list():
    INTERRUPT_EVENT1.set()
    blockchain.interrupt_flag=True
    return "ask received", 200

@app.route('/nodes/register', methods=['POST'])
def register_nodes():
    values = request.get_json()

    nodes = values.get('nodes')
    if nodes is None:
        return "Error: Please supply a valid list of nodes", 400

    for node in nodes:
        blockchain.register_node(node)

    response = {
        'message': 'New nodes have been added',
        'total_nodes': list(blockchain.nodes),
    }
    return jsonify(response), 201

@app.route('/nodes/resolve', methods=['GET'])
def consensus():
    replaced = blockchain.resolve_conflicts()

    if replaced:
        response = {
            'message': 'Our chain was replaced',
            'new_chain': blockchain.chain
        }
    else:
        response = {
            'message': 'Our chain is authoritative',
            'chain': blockchain.chain
        }

    return jsonify(response), 200

# http://flask.pocoo.org/snippets/67/
def shutdown_server():
    func = request.environ.get('werkzeug.server.shutdown')
    if func is None:
        raise RuntimeError('Not running with the Werkzeug Server')
    func()

@app.route("/shutdown")
def shutdown():
    STOP_EVENT.set()
    thread.join()
    shutdown_server()
    return "OK", 200

if __name__ == '__main__':
    from argparse import ArgumentParser

    parser = ArgumentParser()
    parser.add_argument('-p', '--port', default=5000, type=int, help='port to listen on')
    args = parser.parse_args()
    port = args.port

    app.run(host='127.0.0.1', port=2000)


# -*- coding: utf-8 -*-
from odoo import http
from odoo.http import request
import json
import culqipy
import datetime

class PagoCulqi(http.Controller):

    @http.route('/pago/<token>', auth='public',website=True)
    def pago(self, token, **kw):
        pago=request.env["fs_payment.pagoculqi"].sudo().search([["token","=",token]])
        if pago.exists():
            if pago.state!="Pagado":
                if pago.cuentaculqi_id.public_key:
                    d = {"pago":pago,
                        "public_key":pago.cuentaculqi_id.public_key,
                        "token":token,
                        "email":""}
                    if pago.partner_id:
                        if pago.partner_id.email:
                            d.update({"email":pago.partner_id.email})
                    elif pago.sale_order_id:
                        if pago.sale_order_id.partner_id:
                            if pago.sale_order_id.partner_id.email:
                                d.update({"email":pago.sale_order_id.partner_id.email})
                    return http.request.render('fs_payment.formulario_pago_culqi',d)
                else:
                    return http.request.render('website.404')
            else:
                return http.request.render('fs_payment.pagado_1')
        else:
            return http.request.render('website.404')

    @http.route(["/pagar"],type="http",csrf=False, auth='public',methods=["POST"],website=True)
    def pagoculqui(self,**post):
        pago = request.env["fs_payment.pagoculqi"].sudo().search([["token","=",post.get("token_pago")]])
        culqipy.public_key=pago.cuentaculqi_id.public_key
        culqipy.secret_key=pago.cuentaculqi_id.secret_key

        if pago.partner_id:
            partner = pago.partner_id
        else:
            partner_obj = request.env["res.partner"].sudo().search(['|',("name","=",post.get("email")),("email","=",post.get("email"))])
            if partner_obj:
                partner = partner_obj[0]
            else:
                partner = request.env["res.partner"].sudo().create({"name":post.get("email"),"email":post.get("email")})
            pago.partner_id = partner.id
            pago.email_from = partner.email

            if pago.sale_order_id:
                if pago.sale_order_id.partner_id.id == request.website.user_id.sudo().partner_id.id:
                    pago.sale_order_id.partner_id = partner.id
                    pago.sale_order_id.partner_invoice_id = partner.id

        if pago.state!="Pagado":
            charge = culqipy.Charge.create({
                            "amount":int(pago.monto*100),
                            "country_code":"PE",
                            "currency_code":pago.moneda,
                            "email":partner.email,
                            "first_name":partner.name,
                            "description":pago.name,
                            "phone_number":partner.mobile if partner.mobile else "-",
                            "source_id":post.get("token_id")
                        })
            if charge["object"]=="charge":
                if charge["outcome"]["type"]=="venta_exitosa":
                    pago.state="Pagado"
                    pago.fecha_pago = datetime.datetime.now()
                    pago.log_response_success=pago.log_response_success if pago.log_response_success else ""+"\n"+str(datetime.datetime.now())+"\n"+json.dumps(charge)
                    pago.sale_order_id.action_confirm()
                    return http.request.render("fs_payment.pago_exitoso",{})
            print(charge)
            if charge["object"]=="error":
                return http.request.render("fs_payment.pago_error",{"msg":charge["merchant_message"]})

            pago.log_response_error=pago.log_response_error if pago.log_response_error else "" +"\n"+str(datetime.datetime.now())+"\n"+json.dumps(charge)
        else:
            return http.request.render("fs_payment.pagado",{})

# class FsPayment(http.Controller):

#     @http.route('/fs_payment/fs_payment/', auth='public')
#     def index(self, **kw):
#         return "Hello, world"

#     @http.route('/fs_payment/fs_payment/objects/', auth='public')
#     def list(self, **kw):
#         return http.request.render('fs_payment.listing', {
#             'root': '/fs_payment/fs_payment',
#             'objects': http.request.env['fs_payment.fs_payment'].search([]),
#         })

#     @http.route('/fs_payment/fs_payment/objects/<model("fs_payment.fs_payment"):obj>/', auth='public')
#     def object(self, obj, **kw):
#         return http.request.render('fs_payment.object', {
#             'object': obj
#         })


#!/usr/bin/env python3

from enum import Enum
from functools import wraps
import os
from queue import Queue
import serial
from struct import pack, unpack, calcsize
from threading import Thread, Event
from time import sleep
import board

from cellaserv.proxy import CellaservProxy
from cellaserv.service import Service, ConfigVariable
from cellaserv.settings import make_setting

make_setting('TRAJMAN_PORT', '/dev/serial0', 'trajman', 'port', 'TRAJMAN_PORT')
make_setting('TRAJMAN_BAUDRATE', 38400, 'trajman', 'baudrate',
             'TRAJMAN_BAUDRATE', int)
from cellaserv.settings import TRAJMAN_PORT, TRAJMAN_BAUDRATE

from evolutek.lib.gpio import Gpio, Edge as GpioEdge
from evolutek.lib.mdb import Mdb
from evolutek.lib.settings import ROBOT

#######################
# All the commands ID #
#######################
class Commands(Enum):
    DEBUG_MESSAGE      = 127
    TELEMETRY_MESSAGE  = 202
    DEBUG              = 126
    ACKNOWLEDGE        = 200
    MOVE_BEGIN         = 128
    MOVE_END           = 129

    GET_PID_TRSL       = 10
    GET_PID_ROT        = 11
    GET_POSITION       = 12
    GET_SPEEDS         = 13
    GET_WHEELS         = 14
    GET_DELTA_MAX      = 15
    GET_VECTOR_TRSL    = 16
    GET_VECTOR_ROT     = 17
    GOTO_XY            = 100
    GOTO_THETA         = 101
    MOVE_TRSL          = 102
    MOVE_ROT           = 103
    CURVE              = 104
    FREE               = 109
    RECALAGE           = 110
    SET_PWM            = 111
    STOP_ASAP          = 112
    SET_TELEMETRY      = 201
    SET_PID_TRSL       = 150
    SET_PID_ROT        = 151
    SET_TRSL_ACC       = 152
    SET_TRSL_DEC       = 153
    SET_TRSL_MAXSPEED  = 154
    SET_ROT_ACC        = 155
    SET_ROT_DEC        = 156
    SET_ROT_MAXSPEED   = 157
    SET_X              = 158
    SET_Y              = 159
    SET_THETA          = 160
    SET_WHEELS_DIAM    = 161
    SET_WHEELS_SPACING = 162
    SET_DELTA_MAX_ROT  = 163
    SET_DELTA_MAX_TRSL = 164
    SET_ROBOT_SIZE_X   = 165
    SET_ROBOT_SIZE_Y   = 166
    SET_DEBUG          = 200
    ERROR              = 255

# Emergency stop button
BAU_GPIO = 21

#################
# The errors ID #
#################
class Errors(Enum):
    COULD_NOT_READ          = 1
    DESTINATION_UNREACHABLE = 2
    BAD_ORDER               = 3

class AckTimeout(Exception):
    """Raised when a ACK message is not received in time."""
    def __init__(self):
        super().__init__("AckTimeout")

def if_enabled(method):
    """
    A method can be disabled so that it cannot be used in any circumstances.
    """
    @wraps(method)
    def wrapped(self, *args, **kwargs):
        if self.disabled:
            self.log(what='disabled',
                     msg="Usage of {} is disabled".format(method))
            return
        return method(self, *args, **kwargs)

    return wrapped

# TODO: check if we collided

@Service.require("config")
class TrajMan(Service):
    """
    The trajman service is the interface between cellaserv and the motors of
    the robot.

    It uses two threads: one for the service and one to read on the serial
    asynchronously.

    It can be disabled in order to stop processing commands and make sure that
    the robot will not move.
    """

    w1 = ConfigVariable(section=ROBOT, option="wheel_diam1", coerc=float)
    w2 = ConfigVariable(section=ROBOT, option="wheel_diam2", coerc=float)
    spacing = ConfigVariable(section=ROBOT, option="wheels_spacing", coerc=float)
    pidtp = ConfigVariable(section=ROBOT, option="pidtrsl_p", coerc=float)
    pidti = ConfigVariable(section=ROBOT, option="pidtrsl_i", coerc=float)
    pidtd = ConfigVariable(section=ROBOT, option="pidtrsl_d", coerc=float)
    pidrp = ConfigVariable(section=ROBOT, option="pidrot_p", coerc=float)
    pidri = ConfigVariable(section=ROBOT, option="pidrot_i", coerc=float)
    pidrd = ConfigVariable(section=ROBOT, option="pidrot_d", coerc=float)
    trslacc = ConfigVariable(section=ROBOT, option="trsl_acc", coerc=float)
    trsldec = ConfigVariable(section=ROBOT, option="trsl_dec", coerc=float)
    trslmax = ConfigVariable(section=ROBOT, option="trsl_max", coerc=float)
    rotacc = ConfigVariable(section=ROBOT, option="rot_acc", coerc=float)
    rotdec = ConfigVariable(section=ROBOT, option="rot_dec", coerc=float)
    rotmax = ConfigVariable(section=ROBOT, option="rot_max", coerc=float)
    deltatrsl = ConfigVariable(section=ROBOT, option="delta_trsl", coerc=float)
    deltarot = ConfigVariable(section=ROBOT, option="delta_rot", coerc=float)
    robot_size_x = ConfigVariable(section=ROBOT, option="robot_size_x", coerc=float)
    robot_size_y = ConfigVariable(section=ROBOT, option="robot_size_y", coerc=float)
    telemetry_refresh = ConfigVariable(section=ROBOT, option="telemetry_refresh", coerc=float)
    stoptrsldec = ConfigVariable(section=ROBOT, option="stop_trsl_dec", coerc=float)
    stoptrslrot = ConfigVariable(section=ROBOT, option="stop_trsl_rot", coerc=float)

    def __init__(self):
        super().__init__(ROBOT)

        self.cs = CellaservProxy()

        # Messages comming from the motor card
        self.queue = Queue()
        self.ack_recieved = Event()

        self.has_stopped = Event()
        self.has_avoid = Event()

        # Used to generate debug
        self.debug_file = None
        self.disabled = False

        self.serial = serial.Serial(TRAJMAN_PORT, TRAJMAN_BAUDRATE)

        self.thread = Thread(target=self.async_read)
        self.thread.start()

        """ AVOID """
        self.telemetry = None
        self.avoid_disabled = Event()
        self.front = False
        self.back = False
        self.is_robot = False
        self.side = ''

        # MDB
        self.mdb = Mdb()

        # Set config of the robot
        self.trsl_max_speed = self.trslmax()
        self.rot_max_speed = self.rotmax()
        self.stop_trsl_dec = self.stoptrsldec()
        self.stop_trsl_rot = self.stoptrslrot()

        self.init_sequence()
        self.set_telemetry(0)

        self.set_wheels_diameter(w1=self.w1(), w2=self.w2())
        self.set_wheels_spacing(spacing=self.spacing())

        self.set_pid_trsl(self.pidtp(), self.pidti(), self.pidtd())
        self.set_pid_rot(self.pidrp(), self.pidri(), self.pidrd())

        self.set_trsl_acc(self.trslacc())
        self.set_trsl_dec(self.trsldec())
        self.trsl_max_speed = self.trslmax()
        self.set_trsl_max_speed(self.trsl_max_speed)

        self.set_rot_acc(self.rotacc())
        self.set_rot_dec(self.rotdec())
        self.set_rot_max_speed(self.rotmax())

        self.set_delta_max_rot(self.deltarot())
        self.set_delta_max_trsl(self.deltatrsl())

        self.set_robot_size_x(self.robot_size_x())
        self.set_robot_size_y(self.robot_size_y())

        self.set_telemetry(self.telemetry_refresh())
        self.set_telemetry(500)

        # Get and set MDB config
        self.avoid_refresh = float(self.cs.config.get('avoid', 'refresh'))
        near = self.cs.config.get('avoid', 'near')
        far = self.cs.config.get('avoid', 'far')
        brightness = self.cs.config.get('avoid', 'mdb_brightness')
        self.set_mdb_config(near=near, far=far, brightness=brightness)

        # BAU (emergency stop)
        bau_gpio = Gpio(BAU_GPIO, 'bau', dir=False, edge=GpioEdge.BOTH)
        self.bau_status = bau_gpio.read()
        # If the BAU is set at init, free the robot
        if not self.bau_status:
            self.free()

        bau_gpio.auto_refresh(callback=self.handle_bau)

    # Threading sending the telemetry
    #@Service.thread
    def send_telemetry(self):
        while True:
            if self.telemetry is not None:
                self.publish(ROBOT + '_telemetry', status='successful', telemetry = self.telemetry, robot = ROBOT)
            print('Sending telemetry')
            sleep(0.5)

    """ BAU """
    # BAU handler
    @Service.action
    def handle_bau(self, value, event='', name='', id=0):
        self.bau_status = value
        if value == 0:
            self.free()
            self.disable()
        else:
            self.enable()
            self.unfree()

    @Service.action
    def get_bau_status(self):
        return self.bau_status

    """ AVOID """

    # Thread for avoidance
    @Service.thread
    def loop_avoid(self):
        while True:
            if self.telemetry is None:
                continue
            if self.avoid_disabled.isSet():
                continue
            self.check_avoid()
            sleep(self.avoid_refresh)

    # Check and stop the robot if it need to avoid
    @Service.action
    def check_avoid(self):

        # Read MDB
        zones = self.mdb.get_zones()
        front = zones['front']
        back = zones['back']
        is_robot = zones['is_robot']

        # End detection
        if (self.side == 'front' and not front) or (self.side == 'back' and not back):
            self.side = None
            self.publish(ROBOT + '_end_avoid')

        if(self.is_robot != is_robot):
            self.set_speeds(not self.is_robot)

        # Change the values after the read to avoid race conflict
        self.front = front
        self.back = back
        self.is_robot = is_robot

        if self.has_avoid.isSet() or self.has_stopped.isSet():
            return

        # Check if the robot need to stop
        if self.telemetry['speed'] > 0.0 and self.front:
            self.stop_robot('front')
            print("[AVOID] Front detection")
        elif self.telemetry['speed'] < 0.0 and self.back:
            self.stop_robot('back')
            print("[AVOID] Back detection")

    # Get the avoidance status
    @Service.action
    def avoid_status(self):
        status = {
            'front' : self.front,
            'back' : self.back,
            'side': self.side,
            'is_robot' : self.is_robot,
            'avoid' : self.has_avoid.isSet(),
            'enabled' : not self.avoid_disabled.isSet(),
        }

        return status

    # Set moving speeds of the robot
    @Service.action
    def set_speeds(self, state):
        trsl_speed = self.trsl_max_speed
        rot_speed = self.rot_max_speed
        self.set_trsl_max_speed(trsl_speed)
        self.set_rot_max_speed(rot_speed)

    # Stop the robot
    @Service.action
    def stop_robot(self, side=None):
        stopped = False
        self.side = side
        self.has_avoid.set()
        try:
            self.stop_asap(self.stop_trsl_dec, self.stop_trsl_rot)
            stopped = True
        except Exception as e:
            print('[AVOID] Failed to abort ai of %s: %s' % (ROBOT, str(e)))
        print('[AVOID] Stopping robot, %s detection triggered' % side)
        sleep(0.5)

    # Enable avoidance
    @Service.action
    def enable_avoid(self):
        print('[AVOID] Enable')
        self.avoid_disabled.clear()
        self.enable_mdb()

    # Disable avoidance
    @Service.action
    def disable_avoid(self):
        print('[AVOID] Disable')
        self.avoid_disabled.set()
        self.front = False
        self.back = False
        self.is_robot = False
        # Get speeds back to normal
        self.set_speeds(True)
        self.has_avoid.clear()
        self.disable_mdb()

    # Enable MDB
    @Service.action
    def enable_mdb(self):
        print('[AVOID] Enabling mdb')
        self.mdb.enable()

    # Disable MDB
    @Service.action
    def disable_mdb(self):
        print('[AVOID] Disabling mdb')
        self.mdb.disable()

    # Put MDB in error mode
    @Service.action
    def error_mdb(self, enable=True):
        enable = enable in ['True', 'true', 't', 'T', True, '1', 1]
        if(enable): print('[AVOID] Putting mdb in error mode')
        else: print('[AVOID] Disabling error mode on MDB')
        self.mdb.error_mode(enable)

    def write(self, data):
        """Write data to serial and flush."""

        self.serial.write(data)
        self.serial.flush()

    def command(self, data):
        """Handle commands sent to the card and wait for ack."""

        self.ack_recieved.clear()
        self.write(data)
        if not self.ack_recieved.wait(timeout=1):
            # If no ACK is received within 1s
            raise AckTimeout

    def get_command(self, data):
        """Handle commands that waits for an answer from the motors."""

        self.write(data)
        # If no data is received within 1s, raises the Empty exception
        return self.queue.get(timeout=1)

    ########
    # Meta #
    ########

    @Service.action
    def status(self):
        return {'disabled': self.disabled,
                'moving': self.is_moving()}

    ###########
    # Actions #
    ###########

    @Service.action
    @if_enabled
    def goto_xy(self, x, y):
        tab = pack('B', 2 + calcsize('ff'))
        tab += pack('B', Commands.GOTO_XY.value)
        tab += pack('ff', float(x), float(y))
        self.command(bytes(tab))

    @Service.action
    @if_enabled
    def goto_theta(self, theta):
        tab = pack('B', 6)
        tab += pack('B', Commands.GOTO_THETA.value)
        tab += pack('f', float(theta))
        self.command(bytes(tab))

    @Service.action
    @if_enabled
    def move_trsl(self, dest, acc, dec, maxspeed, sens):
        tab = pack('B', 19)
        tab += pack('B', Commands.MOVE_TRSL.value)
        tab += pack('ffffb', float(dest), float(acc), float(dec),
                    float(maxspeed), int(sens))
        self.command(bytes(tab))

    @Service.action
    @if_enabled
    def move_rot(self, dest, acc, dec, maxspeed, sens):
        tab = pack('B', 19)
        tab += pack('B', Commands.MOVE_ROT.value)
        tab += pack('ffffb', float(dest), float(acc), float(dec),
                    float(maxspeed), int(sens))
        self.command(bytes(tab))

    @Service.action
    @if_enabled
    def curve(self, dt, at, det, mt, st, dr, ar, der, mr, sr, delayed):
        tab = pack('B', 35)
        tab += pack('B', Commands.CURVE.value)
        tab += pack('ffffffff', float(dt), float(at), float(det), float(mt),
                    float(dr), float(ar), float(der), float(mt))

        s = 0
        s += 1 if int(st) == 1 else 0
        s += 2 if int(sr) == 1 else 0
        s += 4 if int(delayed) == 1 else 0

        self.log_serial(s)
        tab += pack('B', s)
        self.write(bytes(tab))

    @Service.action
    def free(self):
        print('[TRAJMAN] Freed robot')
        tab = pack('B', 2)
        tab += pack('B', Commands.FREE.value)
        self.command(bytes(tab))

    @Service.action
    @if_enabled
    def unfree(self):
        self.move_trsl(0, 1, 1, 1, 1)

    @Service.action
    def disable(self):
        self.disabled = True

    @Service.action
    def enable(self):
        self.disabled = False

    #######
    # Set #
    #######

    @Service.action
    def set_telemetry(self, inter):
        tab = pack('B', 4)
        tab += pack('B', Commands.SET_TELEMETRY.value)
        tab += pack('H', int(inter))
        self.command(bytes(tab))

    @Service.action
    def set_pid_trsl(self, P, I, D):
        tab = pack('B', 14)
        tab += pack('B', Commands.SET_PID_TRSL.value)
        tab += pack('fff', float(P), float(I), float(D))
        self.command(bytes(tab))

    @Service.action
    def set_pid_rot(self, P, I, D):
        tab = pack('B', 14)
        tab += pack('B', Commands.SET_PID_ROT.value)
        tab += pack('fff', float(P), float(I), float(D))
        self.command(bytes(tab))

    @Service.action
    def set_debug(self, state: "on or off"):
        tab = pack('B', 3)
        tab += pack('B', Commands.SET_DEBUG.value)
        if state == "on":
            self.debug_file = open("debug.data", "w")
            tab += pack('B', 1)

            data = self.get_pid_trsl()
            with open("trslpid.data", "w") as f:
                f.write("P = {kp} I = {ki} D = {kd}\n".format(**data))

            data = self.get_pid_rot()

            with open("rotpid.data", "w") as f:
                f.write("P = {kp} I = {ki} D = {kd}\n".format(**data))
        else:
            tab += pack('B', 0)
            if self.debug_file:
                self.debug_file.close()

        self.command(bytes(tab))

    @Service.action
    def set_trsl_acc(self, acc):
        tab = pack('B', 6)
        tab += pack('B', Commands.SET_TRSL_ACC.value)
        tab += pack('f', float(acc))
        self.command(bytes(tab))

    @Service.action
    def set_trsl_max_speed(self, maxspeed):
        if maxspeed is None:
            maxspeed = self.trsl_max_speed
        tab = pack('B', 6)
        tab += pack('B', Commands.SET_TRSL_MAXSPEED.value)
        tab += pack('f', float(maxspeed))
        self.command(bytes(tab))

    @Service.action
    def set_trsl_dec(self, dec):
        tab = pack('B', 6)
        tab += pack('B', Commands.SET_TRSL_DEC.value)
        tab += pack('f', float(dec))
        self.command(bytes(tab))

    @Service.action
    def set_rot_acc(self, acc):
        tab = pack('B', 6)
        tab += pack('B', Commands.SET_ROT_ACC.value)
        tab += pack('f', float(acc))
        self.command(bytes(tab))

    @Service.action
    def set_rot_max_speed(self, maxspeed):
        tab = pack('B', 6)
        tab += pack('B', Commands.SET_ROT_MAXSPEED.value)
        tab += pack('f', float(maxspeed))
        self.command(bytes(tab))

    @Service.action
    def set_rot_dec(self, dec):
        tab = pack('B', 6)
        tab += pack('B', Commands.SET_ROT_DEC.value)
        tab += pack('f', float(dec))
        self.command(bytes(tab))

    @Service.action
    def set_x(self, x):
        tab = pack('B', 6)
        tab += pack('B', Commands.SET_X.value)
        tab += pack('f', float(x))
        self.command(bytes(tab))

    @Service.action
    def set_y(self, y):
        tab = pack('B', 6)
        tab += pack('B', Commands.SET_Y.value)
        tab += pack('f', float(y))
        self.command(bytes(tab))

    @Service.action
    def set_theta(self, theta):
        tab = pack('B', 6)
        tab += pack('B', Commands.SET_THETA.value)
        tab += pack('f', float(theta))
        self.command(bytes(tab))

    @Service.action
    def set_wheels_diameter(self, w1, w2):
        tab = pack('B', 10)
        tab += pack('B', Commands.SET_WHEELS_DIAM.value)
        tab += pack('ff', float(w1), float(w2))
        self.command(bytes(tab))

    @Service.action
    def set_delta_max_rot(self, delta):
        tab = pack('B', 6)
        tab += pack('B', Commands.SET_DELTA_MAX_ROT.value)
        tab += pack('f', float(delta))
        self.command(bytes(tab))

    @Service.action
    def set_delta_max_trsl(self, delta):
        tab = pack('B', 6)
        tab += pack('B', Commands.SET_DELTA_MAX_TRSL.value)
        tab += pack('f', float(delta))
        self.command(bytes(tab))

    @Service.action
    def set_wheels_spacing(self, spacing):
        tab = pack('B', 6)
        tab += pack('B', Commands.SET_WHEELS_SPACING.value)
        tab += pack('f', float(spacing))
        self.command(bytes(tab))

    @Service.action
    def set_pwm(self, left, right):
        tab = pack('B', 10)
        tab += pack('B', Commands.SET_PWM.value)
        tab += pack('ff', float(left), float(right))
        self.command(bytes(tab))

    @Service.action
    def set_robot_size_x(self, size):
        tab = pack('B', 6)
        tab += pack('B', Commands.SET_ROBOT_SIZE_X.value)
        tab += pack('f', float(size))
        self.command(bytes(tab))

    @Service.action
    def set_robot_size_y(self, size):
        tab = pack('B', 6)
        tab += pack('B', Commands.SET_ROBOT_SIZE_Y.value)
        tab += pack('f', float(size))
        self.command(bytes(tab))

    @Service.action
    def stop_asap(self, trsldec, rotdec):
        tab = pack('B', 10)
        tab += pack('B', Commands.STOP_ASAP.value)
        tab += pack('ff', float(trsldec), float(rotdec))
        self.command(bytes(tab))

    # mode: sets the MDB debug mode. 0: Distances, 1: Zones, 2: Loading, 3: Disabled
    # yellow: sets the color of the loading animation. True: yellow, False: blue
    # near: sets the distance the robot considers as too close (stops)
    # far: sets the distance the robot considers as dangerous (slows down)
    # brightness: sets the brightness of the leds in the mdb
    @Service.action
    def set_mdb_config(self, mode=None, yellow=None, near=None, far=None, brightness=None):
        if mode is not None:
            self.mdb.set_debug_mode(int(mode))
        if yellow is not None:
            self.mdb.set_color(yellow in [True, 'True', 'true', 1, '1'])
        if near is not None:
            self.mdb.set_near(int(near))
        if far is not None:
            self.mdb.set_far(int(far))
        if brightness is not None:
            self.mdb.set_brightness(int(brightness))

    #######
    # Get #
    #######

    @Service.action
    def get_pid_trsl(self):
        tab = pack('B', 2)
        tab += pack('B', Commands.GET_PID_TRSL.value)
        return self.get_command(bytes(tab))

    @Service.action
    def get_pid_rot(self):
        tab = pack('B', 2)
        tab += pack('B', Commands.GET_PID_ROT.value)
        return self.get_command(bytes(tab))

    @Service.action
    def get_position(self):
        self.log_serial("get_position")
        tab = pack('B', 2)
        tab += pack('B', Commands.GET_POSITION.value)
        return self.get_command(bytes(tab))

    @Service.action
    def get_speeds(self):
        tab = pack('B', 2)
        tab += pack('B', Commands.GET_SPEEDS.value)
        return self.get_command(bytes(tab))

    @Service.action
    def get_wheels(self):
        tab = pack('B', 2)
        tab += pack('B', Commands.GET_WHEELS.value)
        return self.get_command(bytes(tab))

    @Service.action
    def get_delta_max(self):
        tab = pack('B', 2)
        tab += pack('B', Commands.GET_DELTA_MAX.value)
        return self.get_command(bytes(tab))

    @Service.action
    def get_vector_trsl(self):
        tab = pack('B', 2)
        tab += pack('B', Commands.GET_VECTOR_TRSL.value)
        return self.get_command(bytes(tab))

    @Service.action
    def get_vector_rot(self):
        tab = pack('B', 2)
        tab += pack('B', Commands.GET_VECTOR_ROT.value)
        return self.get_command(bytes(tab))

    @Service.action
    def flush_serial(self):
        self.log_serial("Clearing CM buffer")
        self.write(bytes(128))

    @Service.action
    def init_sequence(self):
        self.log_serial("Sending init sequence")
        self.write(bytes([5]))
        self.write(bytes([254]))
        self.write(bytes([0xAA]))
        self.write(bytes([0xAA]))
        self.write(bytes([0xAA]))

    @Service.action
    def flush_queue(self):
        """
        If the serial spits out more messages than expected it will be
        necessary to clean the message buffer.
        """
        self.log_serial("Clearing queue")
        ret = []
        while not self.queue.empty():
            ret.append(self.queue.get())
        return ret

    @Service.action
    def is_moving(self):
        return not self.has_stopped.is_set()

    @Service.action
    def get_zones(self):
        return self.mdb.get_zones()

    @Service.action
    def get_scan(self):
        return self.mdb.get_scan()

    # Calibrate

    @Service.action
    @if_enabled
    def recalibration(self, sens, decal=0, set=1):
        tab = pack('B', 7)
        tab += pack('B', Commands.RECALAGE.value)
        tab += pack('B', int(sens))
        tab += pack('f', float(decal))
        tab += pack('B', int(set))
        return self.command(bytes(tab))

    # Thread 2

    def log_serial(self, *args):
        print(*args)

    def async_read(self):
        """Read events from serial and add them to the queue."""
        while True:
            length = unpack('b', self.serial.read())[0]
            tab = [length]
            # self.log_debug("Message length expected:", length)
            for i in range(length - 1):  # FIXME: use read(lenght)
                tab += self.serial.read()
            # self.log_debug("Received message with length:", len(tab))

            if len(tab) > 1:
                if tab[1] == Commands.ACKNOWLEDGE.value:
                    self.log_serial("Robot acknowledged!")
                    self.ack_recieved.set()

                elif tab[1] == Commands.GET_PID_TRSL.value:
                    self.log_serial("Received the robot's translation pid!")

                    _, _, kp, ki, kd = unpack("=bbfff", bytes(tab))
                    self.log("P =", kp, "I =", ki, "D =", kd)

                    self.queue.put({'kp': kp, 'ki': ki, 'kd': kd})

                elif tab[1] == Commands.GET_PID_ROT.value:
                    self.log_serial("Received the robot's rotation pid!")

                    _, _, kp, ki, kd = unpack("=bbfff", bytes(tab))
                    self.log("P =", kp, "I =", ki, "D =", kd)

                    self.queue.put({'kp': kp, 'ki': ki, 'kd': kd})

                elif tab[1] == Commands.GET_POSITION.value:
                    self.log_serial("Received the robot's position!")

                    _, _, x, y, theta = unpack('=bbfff', bytes(tab))
                    self.log_serial("Position is x:", x, "y:", y, "th:", theta)

                    self.queue.put({
                        'x': x,
                        'y': y,
                        'theta': theta,
                    })

                elif tab[1] == Commands.MOVE_BEGIN.value:
                    self.log_serial("Robot started to move!")
                    self.publish(ROBOT + '_started')
                    self.has_stopped.clear()

                elif tab[1] == Commands.MOVE_END.value:
                    self.log_serial("Robot stopped moving!")
                    self.has_stopped.set()
                    self.publish(ROBOT + '_stopped', has_avoid=self.has_avoid.is_set())
                    self.has_avoid.clear()

                elif tab[1] == Commands.GET_SPEEDS.value:
                    a, b, tracc, trdec, trmax, rtacc, rtdec, rtmax = unpack('=bbffffff', bytes(tab))

                    self.queue.put({
                        'tracc': tracc,
                        'trdec': trdec,
                        'trmax': trmax,
                        'rtacc': rtacc,
                        'rtdec': rtdec,
                        'rtmax': rtmax,
                    })

                    self.log_serial("Translation: Acc:", tracc, "\tDec:", trdec, "\tMax :", trmax, " (mm/(s*s) mm/(s*s) mm/s)")
                    self.log_serial("Rotation:    Acc: {0:.3f}\tDec: {1:.3f}\tMax: {2:.3f} (rad/(s*s) rad/(s*s) rad/s)".format(rtacc, rtdec, rtmax))

                elif tab[1] == Commands.GET_WHEELS.value:
                    a, b, spacing, left_diameter, right_diameter = unpack('=bbfff', bytes(tab))

                    self.queue.put({
                        'spacing': spacing,
                        'left_diameter': left_diameter,
                        'right_diameter': right_diameter,
                    })

                    self.log_serial("Spacing: ", spacing, " Left: ", left_diameter, " Right: ", right_diameter)

                elif tab[1] == Commands.GET_DELTA_MAX.value:
                    a, b, translation, rotation = unpack('=bbff', bytes(tab))

                    self.queue.put({
                        'delta_rot_max': rotation,
                        'delta_trsl_max': translation,
                    })

                    self.log_serial("delta_rot_max : ", rotation, "delta_trsl_max", translation)

                elif tab[1] == Commands.GET_VECTOR_TRSL.value:
                    a, b, speed = unpack('=bbf', bytes(tab))

                    self.queue.put({
                        'trsl_vector': speed,
                    })

                    self.log_serial("Translation vector: ", speed)

                elif tab[1] == Commands.GET_VECTOR_ROT.value:
                    a, b, speed = unpack('=bbf', bytes(tab))

                    self.queue.put({
                        'rot_vector': speed,
                    })

                    self.log_serial("Rotation vector: ", speed)

                elif tab[1] == Commands.RECALAGE.value:
                    a, b, recal_xpos, recal_ypos, recal_theta = unpack('=bbfff', bytes(tab))

                    self.queue.put({
                        'recal_xpos': recal_xpos,
                        'recal_ypos': recal_ypos,
                        'recal_theta': recal_theta,
                    })

                elif tab[1] == Commands.DEBUG_MESSAGE.value:
                    counter, commandid, time, xpos, wpx, ypos, wpy, theta, wpth, trspeed, rotspeed, trp, tri, trd, rtp, rti, rtd = unpack("=bbfffffffffffffff", bytes(tab))
                    try:
                        if self.debug_file and not self.debug_file.closed:
                            self.debug_file.write(str(time) + " ")
                            self.debug_file.write(str(xpos) + " " + str(ypos) + " " + str(theta) + " ")
                            self.debug_file.write(str(wpx) + " " + str(wpy) + " " + str(wpth) + " ")
                            self.debug_file.write(str(trspeed) + " " + str(rotspeed) + " ")
                            self.debug_file.write(str(trp) + " " + str(tri) + " " + str(trd) + " ")
                            self.debug_file.write(str(rtp) + " ")
                            self.debug_file.write(str(rti) + " ")
                            self.debug_file.write(str(rtd) + " ")
                            self.debug_file.write("\n")
                    except:
                        pass

                elif tab[1] == Commands.TELEMETRY_MESSAGE.value:
                    counter, commandid, xpos, ypos, theta, speed =unpack('=bbffff', bytes(tab))
                    self.telemetry = { 'x': xpos, 'y' : ypos, 'theta' : theta, 'speed' : speed}
                    """try:
                        self.publish(ROBOT + '_telemetry', status='successful', telemetry = self.telemetry, robot = ROBOT)
                    except:
                        self.publish(ROBOT + '_telemetry', status='failed', telemetry = None, robot = ROBOT)"""
                elif tab[1] == Commands.ERROR.value:
                    self.log("CM returned an error")
                    if tab[2] == Errors.COULD_NOT_READ.value:
                        self.log("Error was: COULD_NOT_READ")
                    elif tab[2] == Errors.DESTINATION_UNREACHABLE.value:
                        self.log("Error was: DESTINATION_UNREACHABLE")
                    elif tab[2] == Erros.BAD_ORDER.value:
                        self.log("Error was: BAD_ORDER")

                elif tab[1] == Commands.DEBUG.value:
                    message = bytes(tab)[2:]
                    print(message)

                else:
                    self.log("Message not recognised")

def main():
    trajman = TrajMan()
    trajman.run()

if __name__ == '__main__':
    main()


def ingreso_de_datos():
    precio_total_cuotas = cuotas * precio_cuota
    diferencia = precio_total_cuotas - precio_de_contado
    print("Si la compra en un unico pago ahorra ${} ".format(diferencia))

try:
    cuotas = int(input("Ingrese cantidad de cuotas: "))
    precio_cuota = int(input("Ingrese el precio por cuota: "))
    precio_de_contado = int(input("Ingrese el precio de contado: "))
    ingreso_de_datos()
except:
    print("Solo se aceptan numeros enteros")


#!/usr/bin/python3
# -*- coding: utf-8 -*-
"""
date
"""
import sys
from PyQt5.QtWidgets import QApplication , QWidget ,QCalendarWidget , QLabel ,QVBoxLayout
from PyQt5.QtCore import QDate

class Example(QWidget):
    def __init__(self):
        super(Example,self).__init__()
        self.initUI()

    def initUI(self):
        vbox=QVBoxLayout()
        vbox.setSpacing(10)

        cal=QCalendarWidget(self)
        cal.setGridVisible(True)
        cal.clicked[QDate].connect(self.setDate)

        self.lbl=QLabel(self)
        self.lbl.setText(cal.selectedDate().toString())
        vbox.addWidget(cal)
        vbox.addWidget(self.lbl)

        self.setLayout(vbox)

        self.setGeometry(300,300,300,300)
        self.setWindowTitle("Calendar")
        self.show()

    def setDate(self,value):
        self.lbl.setText(value.toString())

if __name__=="__main__":
    app=QApplication(sys.argv)
    w=Example()
    sys.exit(app.exec())


import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.utils.data as utils

import e2cnn
from e2cnn import gspaces, group
from e2cnn import nn as gnn

def eigenvalue_covariance_estimate_rep(gspace):
    """
    Input:
        gspace - instance of e2cnn.gspaces.r2.rot2d_on_r2.Rot2dOnR2 - underlying group

    Output:
        psd_rep - instance of e2cnn.group.Representation - group representation of the group representation before the covariance
    """
    # Change of basis matrix:
    change_of_basis = np.array([[1, 1.0, 0.0], [0.0, 0.0, 1.0], [1, -1.0, 0.0]])

    # Get group order and control:
    N = gspace.fibergroup.order()
    if N <= 3 and N != -1:
        sys.exit("Group order is not valid.")

    if isinstance(gspace, gspaces.FlipRot2dOnR2):
        irreps = (
            ["irrep_0,0", "irrep_1,2"]
            if N > 4
            else ["irrep_0,0", "irrep_1,2", "irrep_1,2"]
        )
    elif isinstance(gspace, gspaces.Rot2dOnR2):
        irreps = ["irrep_0", "irrep_2"] if N > 4 else ["irrep_0", "irrep_2", "irrep_2"]
    else:
        sys.exit("Error: Unknown group.")

    psd_rep = e2cnn.group.Representation(
        group=gspace.fibergroup,
        name="eig_val_rep",
        irreps=irreps,
        change_of_basis=change_of_basis,
        supported_nonlinearities=["n_relu"],
    )

    return psd_rep

def get_pre_covariance_field_type(
    gspace, mean_field_type, covariance_activation="quadratic"
):
    if covariance_activation == "quadratic":
        # stack dimension copies of the mean prediction field type
        return sum(
            (mean_field_type.size - 1) * [mean_field_type], start=mean_field_type
        )
    elif covariance_activation in [
        "diagonal_softplus_quadratic",
        "diagonal_softplus",
        "diagonal_quadratic",
    ]:
        # Should ONLY be used with scale fields
        return mean_field_type
    elif covariance_activation == "eigenvalue":
        return gnn.FieldType(gspace, eigenvalue_covariance_estimate_rep(gspace))
    else:
        raise ValueError(
            f"{covariance_activation} is not a recognised covariance activation type"
        )

def get_pre_covariance_dim(mean_dim, covariance_activation="quadratic"):
    if covariance_activation == "quadratic":
        return mean_dim ** 2
    elif covariance_activation == "eigenvalue":
        return 6
    elif covariance_activation in [
        "diagonal_softplus_quadratic",
        "diagonal_softplus",
        "diagonal_quadratic",
    ]:
        return mean_dim
    else:
        raise ValueError(
            f"{covariance_activation} is not a recognised covariance activation type"
        )


class Response(Exception):
    """
    Superclass exception for representing HTTP responses. This exception (and
    its subclasses) can be raised to return a specific HTTP response to the
    browser.

    It expects to receive as a parameter at least a status code and the headers
    to be sent.

    ::

        >>> r = Response('404 Not Found')
        >>> r.status_code
        '404 Not Found'

    It can also receive a list containing the headers::

        >>> r = Response(
        ...     '302 Found', headers=[('Location', 'http://pudim.com.br')]
        ... )
        >>> r.status_code
        '302 Found'
        >>> r.headers
        [('Location', 'http://pudim.com.br')]

    For commodity, the list can be given as a dictionary (obviously, only if
    there is no repeated header)::

        >>> r = Response(
        ...     '302 Found', headers={'Location': 'http://pudim.com.br'}
        ... )
        >>> r.status_code
        '302 Found'
        >>> r.headers
        [('Location', 'http://pudim.com.br')]
    """

    def __init__(self, status_code, message=None, headers=None, *args):
        Exception.__init__(self, message, *args)

        self.status_code = status_code

        try:
            self.headers = headers.items()
        except AttributeError:
            self.headers = [] if headers is None else headers

class OK(Response):
    """
    This response reports that the request was successful::

        >>> r = OK(message='Just fine')
        >>> r.status_code
        '200 OK'
        >>> r.message
        'Just fine'
    """

    def __init__(self, message='', headers=None, *args):
        headers = [] if not headers else headers
        Response.__init__(self, '200 OK', message, headers, *args)

class MovedPermanently(Response):
    """
    This response redirects the client to a new URL, to which the sought
    content was supposedly moved::

        >>> r = MovedPermanently(location='http://pudim.com.br')
        >>> r.status_code
        '301 Moved Permanently'
        >>> r.headers
        [('Location', 'http://pudim.com.br')]
    """

    def __init__(self, location=None, message=None, headers=None, *args):
        headers = [] if not headers else headers
        headers.append(('Location', location))
        Response.__init__(
            self, '301 Moved Permanently', message, headers, *args)
        self.location = location

class SeeOther(Response):
    """
    This response redirects the client to a new URL, where a representation of
    the requested URL can be found::

        >>> r = SeeOther(location='http://pudim.com.br')
        >>> r.status_code
        '303 See Other'
        >>> r.headers
        [('Location', 'http://pudim.com.br')]
    """

    def __init__(self, location=None, message=None, headers=None, *args):
        headers = [] if not headers else headers
        headers.append(('Location', location))
        Response.__init__(self, '303 See Other', message, headers, *args)
        self.location = location

class NotFound(Response):
    """
    This response indicates the requested resource could not be found::

        >>> r = NotFound()
        >>> r.status_code
        '404 Not Found'
    """

    def __init__(self, message=None, headers=None, *args):
        Response.__init__(self, '404 Not Found', message, headers, *args)

class MethodNotAllowed(Response):
    """
    This response indicates the requested resource is available but does not
    handle the requested HTTP method::

        >>> r = MethodNotAllowed()
        >>> r.status_code
        '405 Method Not Allowed'
    """

    def __init__(self, message=None, headers=None, *args):
        Response.__init__(
            self, '405 Method Not Allowed', message, headers, *args)


#%%
import pandas as pd
import datetime
import pandas_datareader as web
from pandas import Series, DataFrame

start = datetime.datetime(2017, 10, 30)
end = datetime.datetime(2019, 9, 6)

df = web.DataReader("CGC", 'yahoo', start, end)
df.tail()

#%% Rolling Mean and Plotting
close_px = df['Adj Close']
mavg = close_px.rolling(window=100).mean()

import matplotlib.pyplot as plt
from matplotlib import style

import matplotlib as mpl
mpl.rc('figure', figsize=(8, 7))
mpl.__version__

style.use('ggplot')

close_px.plot(label='GCG')
mavg.plot(label='mavg')
plt.legend()

#%% Return Deviation
rets = close_px / close_px.shift(1) - 1
rets.plot(label='return')

#%% Competitor Analysis
dfcomp = web.DataReader(["CGC", "TLRY"], 'yahoo', start=start, end=end) ['Adj Close']
dfcomp.tail()

#%% Correlation Analysis
retscomp = dfcomp.pct_change()
corr = retscomp.corr()
corr

#%% ScatterPlot to view return distribution
plt.scatter(retscomp.CGC, retscomp.TLRY)
plt.xlabel('Returns CGC')
plt.ylabel('Returns TLRY')

#%% Heat map to visualize correlation ranges between Stocks
plt.imshow(corr, cmap='hot', interpolation='none')
plt.colorbar()
plt.xticks(range(len(corr)), corr.columns)
plt.yticks(range(len(corr)), corr.columns)

#%%
plt.scatter(retscomp.mean(), retscomp.std())
plt.xlabel('Expected returns')
plt.ylabel('Risk')
for label, x, y in zip(retscomp.columns, retscomp.mean(), retscomp.std()):
    plt.annotate(
        label,
        xy = (x, y), xytext = (20, -20),
        textcoords = 'offset points', ha = 'right', va = 'bottom',
        bbox = dict(boxstyle = 'round,pad=0.5', fc = 'yellow', alpha = 0.5),
        arrowprops = dict(arrowstyle = '->', connectionstyle = 'arc3,rad=0')
    )

#%% High-Low Pct and PCT change
dfreg = df.loc[:, ['Adj Close', 'Volume']]
dfreg['HL_PCT'] = (df['High'] - df['Low']) / df['Close'] * 100.0
dfreg['PCT_change'] = (df['Close'] - df['Open']) / df['Open'] * 100.0

#%% Pre-processing and Cross Validation
import math
import numpy as np
from sklearn import preprocessing

# Drop missing value
dfreg.fillna(value=-99999, inplace=True)
# We want to separate 1 percent of the data to forecast
forecast_out = int(math.ceil(0.01 * len(dfreg)))
# Separating the label here, we want to predict the AdjClose
forecast_col = 'Adj Close'
dfreg['label'] = dfreg[forecast_col].shift(-forecast_out)
X = np.array(dfreg.drop(['label'], 1))
# Scale the X so that everyone can have the same distribution for linear regression
X = preprocessing.scale(X)
# Finally We want to find Data Series of late X and early X (train) for model generation and evaluation
X_lately = X[-forecast_out:]
X = X[:-forecast_out]
# Separate label and identify it as y
y = np.array(dfreg['label'])
y = y[:-forecast_out]

#%% Model Generation
from sklearn.linear_model import LinearRegression
from sklearn.neighbors import KNeighborsRegressor
from sklearn.linear_model import Ridge
from sklearn.preprocessing import PolynomialFeatures
from sklearn.pipeline import make_pipeline

X_train = X
X_test = X
y_train = y
y_test = y

# Linear Regression
clfreg = LinearRegression(n_jobs=-1)
clfreg.fit(X_train, y_train)

# Quadratic Regression 2
clfpoly2 = make_pipeline(PolynomialFeatures(2), Ridge())
clfpoly2.fit(X_train, y_train)

#Quadratic Regression 3
clfpoly3 = make_pipeline(PolynomialFeatures(3), Ridge())
clfpoly3.fit(X_train, y_train)

# KNN Regression
clfknn = KNeighborsRegressor(n_neighbors=2)
clfknn.fit(X_train, y_train)

#%% Evaluation
confidencereg = clfreg.score(X_test, y_test)
confidencepoly2 = clfpoly2.score(X_test, y_test)
confidencepoly3 = clfpoly3.score(X_test, y_test)
confidenceknn = clfknn.score(X_test, y_test)

#%%
print('The linear regression confidence is:', confidencereg)
print('The quadratic regression 2 confidence is:', confidencepoly2)
print('The quadratic regression 3 confidence is:',  confidencepoly3)
print('The knn regression confidence is:', confidenceknn)

#%%
forecast_set_knn = clfknn.predict(X_lately)
dfreg['Forecast'] = np.nan

#%%
last_date = dfreg.iloc[-1].name
last_unix = last_date
next_unix = last_unix + datetime.timedelta(days=1)

for i in forecast_set_knn:
    next_date = next_unix
    next_unix += datetime.timedelta(days=1)
    dfreg.loc[next_date] = [np.nan for _ in range(len(dfreg.columns)-1)] +[i]

dfreg['Adj Close'].tail(500).plot()
dfreg['Forecast'].tail(500).plot()
plt.legend(loc=4)
plt.xlabel('Date')
plt.ylabel('Price')
plt.show()

#%%


from django.contrib import admin

from core.admin.utils import get_final_display_list
from core.models.substance import Substance, SubstanceAltName
from admin_auto_filters.filters import AutocompleteFilterFactory

@admin.register(SubstanceAltName)
class SubstanceAltNameAdmin(admin.ModelAdmin):
    search_fields = [
        "name",
        "substance__name",
    ]
    autocomplete_fields = ["substance"]

    def get_queryset(self, request):
        queryset = super().get_queryset(request)
        return queryset.select_related("substance")

    def get_list_display(self, request):
        return get_final_display_list(SubstanceAltName, [])

@admin.register(Substance)
class SubstanceAdmin(admin.ModelAdmin):
    search_fields = [
        "name",
        "formula",
    ]
    list_filter = [AutocompleteFilterFactory("group", "group")]

    def get_queryset(self, request):
        queryset = super().get_queryset(request)
        return queryset.select_related("group")

    def get_list_display(self, request):
        exclude = [
            "blendcomponents",
            "cpprices",
            "cprecord",
            "substancealtname",
            "excludedusage",
            "excluded_usages",
            "admrecord",
            "project_ods",
            "bprecord",
        ]
        return get_final_display_list(Substance, exclude)


import pandas as pd
from sqlalchemy import create_engine

# Define engine and connect

def createsqlengine(_databasepath):
    # Create a SQL engine and return the object
    engine = create_engine('sqlite://' + _databasepath)
    print(engine.table_names())
    return engine

def createdbconnection(_engine):
    # Create a connection to use for interacting with the database
    con = _engine.connect()
    return con

def querydb(_querystring, _con):
    # send a query to an open connection
    rs = _con.execute(_querystring)
    return rs

def insertintotable(_con, _table, _values):
    # insert values into a specific table in a defined connection
    rows = len(_values)
    cols = len(_values[0])

    for row in range(rows):
        query = 'INSERT INTO ' + _table + ' VALUES ('
        rowdata = _values[row]
        for col in range(cols):
            query = query + rowdata[col]
        print(query)
        query = query + ')'
        print(query)
    _ = _con.execute(query)

    print('inserted ' + rows + ' rows of data')
    return True


from PipeConverter import PipeConverter
from typing import List, Dict, Union, Tuple
import numpy as np
from ParsedPipe import ParsedPipe
from ModificationStrategy import ModificationStrategy, Strategy
import argparse

class FileParser:
    def __init__(self, file_path: str, converter: PipeConverter, strategy: Strategy = Strategy.SINGLE_TANK_CV,
                 tank_height_multiplier: float = 1, cf: float = 1) -> None:
        self.file_path = file_path
        with open(file_path, 'r+') as file:
            self.file = file.read().splitlines()

        self.headers = self.get_headers()
        self.content = self.get_content()

        # check that the file is valid
        if not self.valid_input():
            raise ValueError(
                'Error: Please ensure that you are selecting a valid .inp file with a RULES, TANKS, and PIPES section')

        # should add comment or not
        self.added_pipe = False
        self.added_tank = False
        self.added_rule = False
        self.comment = ";Automated content below - Do not edit!"

        # next available id
        self.rule_count = self.get_rule_count()

        # converter for calculating equivalent lengths
        self.pressure = self.calculate_required_pressure()
        self.converter = converter
        self.converter.update_pressure(self.pressure)

        # initialize modification strategy
        self.modification_strategy = ModificationStrategy(self, strategy, tank_height_multiplier, cf=cf)

    def calculate_required_pressure(self) -> float:
        """
        Determines the range in elevation of the network and then assumes that there is twice that much pressure in
        the system
        :return:
        """
        lowest = highest = 0
        for element in ("JUNCTIONS", "TANKS", "RESERVOIRS"):
            for junction in self.content[element]:
                if self.is_comment(junction):
                    continue
                elevation = float(junction.split("\t")[1].strip())
                lowest = min(lowest, elevation)
                highest = max(highest, elevation)
        return 1 if highest - lowest <= 0 else 2 * (highest - lowest)

    @staticmethod
    def convert_pipe_diameter(diameter: Union[float, int], read: bool = True):
        if read:
            return diameter / 1000
        else:
            return diameter * 1000

    def valid_input(self):
        return "TANKS" in self.headers and "PIPES" in self.headers and "RULES" in self.headers

    @staticmethod
    def is_comment(string: str) -> bool:
        return string.strip()[0] == ";"

    def get_headers(self) -> List[str]:
        headers = []
        for line in self.file:
            stripped_line = line.strip()
            if len(stripped_line) > 0:
                if stripped_line[0] == "[" and stripped_line[-1] == "]":
                    headers.append(line[1: -1])
        return headers

    def get_content(self) -> Dict[str, List[str]]:
        # returns a dict mapping section to content lines
        content_dict = {}
        accum = []
        current = ""
        for line in self.file:
            if len(line) > 0:
                # if this is a header (eliminates whitespace)
                if line.strip()[1: -1] in self.headers:
                    # skip first case
                    if len(current) > 0:
                        content_dict[current] = accum
                        accum = []
                    current = line[1: -1]
                    continue
                accum.append(line)
        return content_dict

    def get_rule_count(self) -> int:
        current = 0
        for line in self.content["RULES"]:
            if "RULE" in line:
                current += 1
        return current + 1

    def reconstruct_file(self) -> str:
        file = ""
        for header, content in self.content.items():
            file += f"[{header}]\n"
            for line in content:
                file += line + "\n"
            file += "\n"
        file += "[END]\n"
        return file

    def add_rule(self, tank_id: str, tank_level, pipe_id: str) -> Union[str, int]:
        # TODO: abstract this to a check comment method that takes in the section name
        if not self.added_rule:
            self.added_rule = True
            self.content["RULES"].append(self.comment)
        # create rule s.t. it's triggered when level is above 99% of tank capacity
        rule = f"RULE\t{self.rule_count}\nIF\tTANK\t{tank_id}\tLEVEL\tABOVE\t{tank_level * 0.99}\nTHEN\tPIPE\t{pipe_id}\tSTATUS\tIS\tOPEN\n\n "
        self.rule_count += 1
        self.content["RULES"].append(rule)
        return self.rule_count - 1

    def add_tank(self, id: str, elevation: int, max_level: int, diameter: Union[float, int], init_level: int = 0,
                 min_level: int = 0, min_vol: int = 0) -> str:
        # init level, min level and min volume should always be zero, max level
        # Diameter and max level are calculated from volume
        if not self.added_tank:
            self.added_tank = True
            self.content["TANKS"].append(self.comment)

        # in the case of flat pipes, we assume a default height of 1
        if max_level == 0:
            max_level = 1

        tank = "\t".join(
            [str(x) for x in [id, elevation, init_level, min_level, max_level, diameter, min_vol, "", ";"]])
        self.content["TANKS"].append(tank)
        return id

    def add_pipe(self, node_a: Union[str, int], node_b: Union[str, int], length: Union[str, int, float],
                 diameter: Union[str, int], status: str = "Open") -> str:
        """
        Used for adding shadow pipes - the id will always be f"{node_a}->{node_b}".
        It might visually look a bit different, but when you upload the model it strips whitespace, so the tabs are important here

        Roughness and Minor loss are both set to be 0
        :param status: Optional status; used for to say if pipe has a check valve or not
        :param node_a:
        :param node_b:
        :param length:
        :param diameter:
        :return:
        """
        if not self.added_pipe:
            self.added_pipe = True
            self.content["PIPES"].append(self.comment)

        # ensure unique node names
        node_a_id = f"({node_a})" if "->" in node_a else node_a
        node_b_id = f"({node_b})" if "->" in node_b else node_b

        # convert from m to mm
        diameter = self.convert_pipe_diameter(diameter, read=False)

        pipe = "\t".join(
            [str(x) for x in [f"{node_a_id}->{node_b_id}", node_a, node_b, length, diameter, 100, 0, status, ";"]])
        self.content["PIPES"].append(pipe)
        return f"{node_a}__{node_b}"

    def add_psv(self, node_origin: Union[str, int], node_dest: Union[str, int]) -> Tuple[
        Union[str, int], Union[str, int]]:
        # create junction to attach PSV
        psv_start, psv_end = f"{node_origin}->{node_dest}" + "_psv", f"{node_origin}->{node_dest}" + "_psv_end"
        psv_elevation = str(self.get_elevation(node_origin))
        # TODO: check what demand should be
        psv_junction = "\t".join([psv_start, psv_elevation, "0", "", ";"])
        psv_junction_end = "\t".join([psv_end, psv_elevation, "0", "", ";"])
        self.content["JUNCTIONS"].append(psv_junction)
        self.content["JUNCTIONS"].append(psv_junction_end)

        # attach PSV
        psv_valve = "\t".join([f"{node_origin}->{node_dest}" + "_psv_pipe",  # pipe id
                               psv_start,  # start
                               psv_end,  # end
                               "100",  # TODO: update diameter [mm]
                               "PSV",  # type of valve
                               str(self.pressure),  # pressure to be sustained
                               "0",  # minor loss
                               ";"])
        self.content["VALVES"].append(psv_valve)
        return psv_start, psv_end

    def close_pipe(self, pipe: str, index: int) -> None:
        if self.is_comment(pipe):
            return
        pipe_split = pipe.split("\t")
        # Status column should always be the 8th
        pipe_split[7] = "Closed"
        self.content["PIPES"][index] = "\t".join(pipe_split)

    def set_initial_pipes_closed(self) -> None:
        # TODO: Don't close math pipes otherwise the networks won't run!
        for index, pipe in enumerate(self.content["PIPES"]):
            self.close_pipe(pipe, index)

    def get_elevation(self, node: str) -> float:
        # need to check [JUNCTIONS] [RESERVOIRS] [TANKS]
        for element in ("JUNCTIONS", "TANKS", "RESERVOIRS"):
            for junction in self.content[element]:
                junction_params = junction.split("\t")
                if junction_params[0].strip() == node:
                    return float(junction_params[1])

        raise Exception(f"Error: There is no tank or junction called: {node}")

    def parse_pipe(self, pipe: str) -> ParsedPipe:
        """
        Returns useful values about the pipe. Note: node_a is always the pipe with the lower elevation
        :param pipe: row from the parsed file
        :return: id, node_a, node_b, length, diameter, d_z, elevation_min, volume, diameter_equivalent
        """
        pipe_split = pipe.split('\t')
        pipe_id, node_a, node_b, length, diameter = pipe_split[:5]

        # need to convert between m and mm
        diameter = self.convert_pipe_diameter(float(diameter), read=True)

        # node_a should always be lower elevation
        elevation_a, elevation_b = self.get_elevation(node_a), self.get_elevation(node_b)
        if elevation_a > elevation_b:
            node_a, node_b = node_b, node_a
            elevation_a, elevation_b = elevation_b, elevation_a

        # d_z is always positive
        d_z, elevation_min = elevation_b - elevation_a, elevation_a

        return ParsedPipe(pipe_id, node_a, node_b, float(length), diameter, d_z, elevation_min)

    def create_intermittent_network(self) -> None:
        # all pipes in the network must be initially closed
        initial_pipes = self.content["PIPES"].copy()

        for index, pipe in enumerate(initial_pipes):
            # skip over comments
            if self.is_comment(pipe):
                continue

            parsed_pipe = self.parse_pipe(pipe)

            # these pipes usually don't exist and are usually used for connecting different components, so we don't
            # want to model them.
            if parsed_pipe.length <= 1:
                continue

            # close pipe if it is long enough
            self.close_pipe(pipe, index)

            self.modification_strategy.evaluate(parsed_pipe)

if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument("--file", type=str)
    parser.add_argument("--output", type=str)
    args = parser.parse_args()
    test_file_path = args.file

    # bad dependency injection lol
    converter = PipeConverter(20, 1)
    parser = FileParser(test_file_path, converter)
    parser.create_intermittent_network()
    reconstructed = parser.reconstruct_file()

    with open(args.output, 'w') as f:
        f.write(reconstructed)


"""Calcular el promedio de las notas que obtiene un alumno al rendir los dos parciales"""

cantidad,suma=0,0
nota=int(input("Ingrese su nota o -1 para finalizar: "))
while nota!=-1:
    cantidad=cantidad+1
    suma=suma+nota
    nota=int(input("Ingrese su nota o -1 para finalizar: "))
promedio=suma/cantidad

print("Su promedio final es de: ",promedio)

TP 2 Estructura Secuencial Ejercicio 3.py


"""example_aws_lambda: An example AWS lambda for the cisagov organization.

Usage:
  eal --region REGION --message MESSAGE [--log-level=LEVEL]
  eal (-h | --help)
  eal --version

Options:
  -h --help                   Show this message.
  --version                   Show version.
  --region REGION             The region this is running in.
  --message MESSAGE           The message to output.
  --log-level=LEVEL           If specified, then the log level will be set to
                              the specified value.  Valid values are "debug",
                              "info", "warning", "error", and "critical".
                              [default: warning]
"""

# Standard Python Libraries
from datetime import datetime, timezone
import logging

# Third-Party Libraries
import docopt

# Local library
from ._version import __version__

def setup_logging(log_level):
    """Set up logging at the provided level."""
    try:
        logging.basicConfig(
            format="%(asctime)-15s %(levelname)s %(message)s", level=log_level.upper()
        )
    except ValueError:
        logging.critical(
            f'"{log_level}" is not a valid logging level.  Possible values '
            "are debug, info, warning, error, and critical."
        )
        return 1

def do_lambda_functionality(region=None, invocation_time=None, message="Hello, World!"):
    """Print out the provided region, invocation time, and the function's time."""
    function_time = datetime.now(timezone.utc)

    logging.debug(__name__)
    print(f"Region: {region}")
    print(f"Invocation Time: {invocation_time}")
    print(f"Function Time (UTC): {function_time}")
    print(f"Provided Message: {message}")

    return True

def main() -> int:
    """Set up logging and call the import_data function."""
    # Parse command line arguments
    args = docopt.docopt(__doc__, version=__version__)

    # Set up logging
    setup_logging(args["--log-level"])

    result = do_lambda_functionality(
        args["--region"], datetime.now(timezone.utc), args["--message"]
    )

    # Stop logging and clean up
    logging.shutdown()

    return 0 if result else -1


# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution(object):

    def kthSmallest(self, root, k):
        """
        :type root: TreeNode
        :type k: int
        :rtype: int
        """

        stack = []
        def travel(cur):
            if cur is None:
                return

            travel(cur.left)
            stack.append(cur.val)
            travel(cur.right)

        travel(root)

        stack.sort()
        return stack[k-1]


# -*- coding: utf-8 -*-

import math
import random
import time
import sys
import matplotlib
import matplotlib.pyplot as plt
from collections import namedtuple
from itertools import count
from PIL import Image
from net import DQN
import data
import torch
import torch.optim as optim
import torch.nn.functional as F
import torchvision.transforms as T

if __name__ == '__main__':
    # set up matplotlib
    is_ipython = 'inline' in matplotlib.get_backend()
    if is_ipython:
        from IPython import display

    plt.ion()

    # if gpu is to be used
    device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")

    Transition = namedtuple('Transition',
                            ('state', 'action', 'next_state', 'reward'))

    class ReplayMemory(object):

        def __init__(self, capacity):
            self.capacity = capacity
            self.memory = []
            self.position = 0

        def push(self, *args):
            """Saves a transition."""
            if len(self.memory) < self.capacity:
                self.memory.append(None)
            self.memory[self.position] = Transition(*args)
            self.position = (self.position + 1) % self.capacity

        def sample(self, batch_size):
            return random.sample(self.memory, batch_size)

        def __len__(self):
            return len(self.memory)

    BATCH_SIZE = 64
    GAMMA = 0.95
    TARGET_UPDATE = 30

    policy_net = DQN().to(device)
    target_net = DQN().to(device)
    target_net.load_state_dict(policy_net.state_dict())
    target_net.eval()

    optimizer = optim.Adam(policy_net.parameters())
    memory = ReplayMemory(10000)

    episode_durations = []

    def plot_durations():
        plt.figure(2)
        plt.clf()
        durations_t = torch.tensor(episode_durations, dtype=torch.float)
        plt.title('Training...')
        plt.xlabel('Episode')
        plt.ylabel('Duration')
        plt.plot(durations_t.numpy())
        # Take 100 episode averages and plot them too
        if len(durations_t) >= 100:
            means = durations_t.unfold(0, 100, 1).mean(1).view(-1)
            means = torch.cat((torch.zeros(99), means))
            plt.plot(means.numpy())

        plt.pause(0.001)  # pause a bit so that plots are updated
        if is_ipython:
            display.clear_output(wait=True)
            display.display(plt.gcf())

    def optimize_model():
        if len(memory) < BATCH_SIZE:
            time.sleep(1)
            return 0
        transitions = memory.sample(BATCH_SIZE)
        # Transpose the batch (see http://stackoverflow.com/a/19343/3343043 for
        # detailed explanation).
        batch = Transition(*zip(*transitions))

        # Compute a mask of non-final states and concatenate the batch elements
        non_final_mask = torch.tensor(tuple(map(lambda s: s is not None,
                                              batch.next_state)), device=device, dtype=torch.uint8)
        non_final_next_states = torch.cat([s for s in batch.next_state
                                                    if s is not None]).to(device)
        state_batch = torch.cat(batch.state).to(device)
        action_batch = torch.cat(batch.action).to(device)
        reward_batch = torch.cat(batch.reward).to(device)

        # Compute Q(s_t, a) - the model computes Q(s_t), then we select the
        # columns of actions taken
        state_action_values = policy_net(state_batch).gather(1, action_batch)

        # Compute V(s_{t+1}) for all next states.
        next_state_values = torch.zeros(BATCH_SIZE, device=device)
        next_state_values[non_final_mask] = target_net(non_final_next_states).max(1)[0].detach()
        # Compute the expected Q values
        expected_state_action_values = (next_state_values * GAMMA) + reward_batch

        # Compute Huber loss
        loss = F.smooth_l1_loss(state_action_values, expected_state_action_values.unsqueeze(1))

        # Optimize the model
        optimizer.zero_grad()
        loss.backward()
        for param in policy_net.parameters():
            param.grad.data.clamp_(-1, 1)
        optimizer.step()
        return 1

    data.start()
    if len(sys.argv) > 2:
        policy_net.load_state_dict(torch.load("models/" + sys.argv[2] + ".pt"))
        target_net.load_state_dict(policy_net.state_dict())
        data.updateNet(policy_net.state_dict())

    num_episodes = int(sys.argv[1])
    i_episode = 0
    data_count = 0
    net_count = 0
    while i_episode < num_episodes:
        for data_point in data.getData():
            data_count += 1
            action_dict = {'l':0, 's':1, 'r':2}
            state = data_point[0].to("cpu")
            action = torch.tensor([[action_dict[data_point[1]]]], device="cpu")
            if data_point[2] is None:
                next_state = None
            else:
                next_state = data_point[2].to("cpu")
            reward = torch.tensor([float(data_point[3])], device="cpu")
            memory.push(state, action, next_state, reward)

        #print("Optimizing, {0}".format(len(memory)))
        i_episode += optimize_model()
        if i_episode % TARGET_UPDATE == TARGET_UPDATE - 1:
            print("UPDATE_NET, Data Count: ", data_count, "Episode Count: ", i_episode)
            target_net.load_state_dict(policy_net.state_dict())
            data.updateNet(policy_net.state_dict())

        if i_episode % 1000 == 999:
            torch.save(policy_net.state_dict(), "models/" + str(net_count) + ".pt")
            net_count += 1

    print('Complete')
    data.stop()
    plt.ioff()
    plt.show()


# Python version 3.7

import json
import math

NDBench_testing_json = "workload_data_json/NDBench-testing.json"
NDBench_training_json = "workload_data_json/NDBench-training.json"
DVD_testing_json = "workload_data_json/DVD-testing.json"
DVD_training_json = "workload_data_json/DVD-training.json"

def file_selector(benchmark_type_val):
    switcher = {
        1: NDBench_testing_json,
        2: NDBench_training_json,
        3: DVD_testing_json,
        4: DVD_training_json
    }
    return switcher.get(benchmark_type_val, "null")

def workloadMetric_selector(workloadMetric_val):
    switcher = {
        1: "CPU",
        2: "NetworkIn",
        3: "NetworkOut",
        4: "Memory"
    }
    return switcher.get(workloadMetric_val, "null")

def generate_batch_data_response(user_request):
    # Client Request data
    rfwId = user_request['rfwId']  # 1. RFWID
    # Benchmark -> \n1 - DVD_Test, \n2 - DVD_Train, \n3 - NDBench_Test, \n4 - NDBench_Train
    benchmarkType = user_request['benchmarkType']
    # Workload Metric -> \n1 - CPU, \n2 - NetworkIn, \n3 - NetworkOut, \n4 - Memory
    workloadMetric = user_request['workloadMetric']  # 3. CPU / NetworkIn
    batchUnit = user_request['batchUnit']  # number of samples
    batchId = user_request['batchId']  # 5th batch or 6th batch etc
    batchSize = user_request['batchSize']  # how many batches to return

    data = -1
    response_start_line = -1
    response_end_line = -1
    response_lines_size = -1

    try:

        with open(file_selector(benchmarkType), 'r') as f:
            data = json.load(f)

            total_number_of_batches = {math.floor(len(data) / batchUnit)}
            length_of_json_data_files = len(data)
            response_start_line = (batchUnit * (batchId - 1))
            response_end_line = (batchUnit * ((batchId - 1) + batchSize) - 1)
            response_lines_size = (batchUnit * batchSize)
            last_batch_id = (batchId - 1) + batchSize

            # calculation_tester(data, batchId, last_batch_id, length_of_json_data_files, response_end_line,
            #                    response_lines_size, response_start_line, total_number_of_batches)

            f.close()

            try:
                with open("response_data/clientID_response.json", 'w') as file:
                    response_data = data[response_start_line:response_end_line + 1]
                    json.dump(response_data, file)

            except:
                print(f"Error writing response to file")

            # building response packet
            response_data = [data[i][workloadMetric_selector(workloadMetric)] for i in
                             range(response_start_line, (response_end_line + 1))]
            # response_data = data[response_start_line:response_end_line + 1]
            response = [rfwId, last_batch_id, response_data]

        # send response packet to client
        return response

    except:
        print(f"Error reading json file")

def calculation_tester(data, batchId, end_batch_id, length_of_json_data_files, response_end_line, response_lines_size,
                       response_start_line, total_number_of_batches):
    print("")
    print(f"Length of json data file: {length_of_json_data_files}")
    print("")
    print(f"Starting batch unit: {batchId}")
    print(f"Ending batch unit: {end_batch_id}")
    print("")
    # Calculations done on the server side from request received client
    print(f"Total number of batches from 1 - {total_number_of_batches}")
    print(f"Starting line from batch unit (start is 0): {response_start_line}")
    print(f"Ending line from batch unit (start is 0): {response_end_line}")
    print(f"Total number of lines: {response_lines_size}")
    print("")

    print(data[response_start_line:response_end_line + 1])

# generate_batch_data()

def test_file(user_request):
    print("File executed")
    print(user_request)
    print(NDBench_testing_json)
    print(NDBench_training_json)
    print(DVD_training_json)
    print(DVD_testing_json)


########################################
# name:
# date:
# description:
########################################
from Tkinter import *

# the main GUI
class Chessboard(Frame, Canvas):
    # the constructor
    def __init__(self, parent):
        Frame.__init__(self, parent, bg="grey")
        parent.attributes("-fullscreen", True)
        self.setupGUI()

    # sets up the GUI
    def setupGUI(self):
        for i in [1, 2, 3, 4, 5, 6, 7, 8]:
            for j in ["A", "B", "C", "D", "E", "F", "G", "H"]:
                self.Tiles(i, j)
        # pack the GUI
        self.pack(fill=BOTH, expand=1)

    def Tiles(self, i, j):
        """ tiles need to be implemented """

##############################
# the main part of the program
##############################
# create the window
window = Tk()
# set the window title
window.title("Chess")
# generate the GUI
p = Chessboard(window)
# display the GUI and wait for user interaction
window.mainloop()


K = int(input())
nums = list(map(int, input().split()))
N = 0
for i in range(K):
    N += 2**i
x = N - len(nums)
y = 2**(K-1) - x
answer = []

while True:
    for i in range(K-1, -1, -1):
        tmp = []
        for j in range(len(nums)):
            a = nums.pop(j)
            tmp.append(a)
            if (i != K-1 and len(tmp) == 2 ** i) or (i == K-1 and len(tmp) == y):
                break
        answer.insert(0, tmp)
    if len(nums) == 0:
        break

for ans in answer:
    print(*ans)

백준/Silver/9934. 완전 이진 트리/완전 이진 트리.py