#!/usr/bin/python
"""
Created on Thu Dec  1 15:41:13 2016

@author: pavla kratochvilova
"""
# Imports----------------------------------------------------------------------
from argparse import ArgumentParser
from time import sleep
import threading
import logging
import pika
# Custom imports --------------------------------------------------------------
import serverlib
import common
from common import send_message
from game import Game
# Setup Python logging --------------------------------------------------------
FORMAT = '%(asctime)-15s %(levelname)s %(message)s'
logging.basicConfig(level=logging.INFO, format=FORMAT)
LOG = logging.getLogger(__name__)
LOG.setLevel(logging.DEBUG)
# Constants -------------------------------------------------------------------
___NAME = 'Battleship Game Client'
___VER = '0.1.0.0'
___DESC = 'Battleship Game Client'
___BUILT = '2016-11-10'
# Classes ---------------------------------------------------------------------
class GameList(object):
    '''List of game sessions.
    '''
    def __init__(self, channel, server_args, clients):
        # Dict of running games
        self.games = {}

        # Communication
        self.server_args = server_args
        self.server_name = server_args.name
        self.clients = clients
        self.channel = channel
        self.games_queue = channel.queue_declare(exclusive=True).method.queue
        self.channel.queue_bind(exchange='direct_logs',
                                queue=self.games_queue,
                                routing_key=common.make_key_games(
                                    self.server_name))
        self.channel.basic_consume(self.reply_request,
                                   queue=self.games_queue,
                                   no_ack=True)

    def add_game(self, name, owner, width, height):
        '''Add game to the dict of games.
        @param name: name of game
        @param owner: owner of game
        @param width: width of field of game
        @param height: height of field of game
        '''
        # Create game in new thread
        game = Game(self, self.server_args, name, owner, width, height)
        self.games[name] = game
        game.start()

        # Send event about added game
        msg = serverlib.make_e_game_open(name)
        send_message(self.channel, msg,
                     common.make_key_game_advert(self.server_name))

        return game

    def remove_game(self, name):
        '''Remove game from the dict of games.
        @param name: name of game
        '''
        try:
            del self.games[name]
            # Send event about removed game
            msg = serverlib.make_e_game_end(name)
            send_message(self.channel, msg,
                         common.make_key_game_advert(self.server_name))
        except KeyError:
            pass

    def get_games(self, state=None):
        '''Get list of games, optionally filtering by state.
        @param state: state of game
        @return list: list of games
        '''
        if state is None:
            return self.games
        return [game for game in self.games.values() if game.state == state]

    def process_request(self, msg_parts, properties):
        '''Process request about list of games.
        @param msg_parts: parsed message
        @param properties: pika.spec.BasicProperties
        @return String, response
        '''
        # Get list of games request
        if msg_parts[0] == common.REQ_LIST_OPENED:
            game_names = [game.name for game in self.get_games('opened')]
            return serverlib.make_rsp_list_opened(game_names)
        if msg_parts[0] == common.REQ_LIST_CLOSED:
            game_names = [game.name for game in self.get_games('closed')]
            return serverlib.make_rsp_list_closed(game_names)

        # Create game request
        if msg_parts[0] == common.REQ_CREATE_GAME:
            if len(msg_parts) != 5 or msg_parts[1].strip() == '' or\
                msg_parts[3].strip() == '' or msg_parts[4].strip() == '':
                return serverlib.make_rsp_invalid_request()

            game_name = msg_parts[1]
            client_name = msg_parts[2]
            width = msg_parts[3]
            height = msg_parts[4]

            if game_name in self.games:
                return serverlib.make_rsp_name_exists()
            if client_name not in self.clients.client_set:
                return serverlib.make_rsp_permission_denied()

            game = self.add_game(game_name, client_name, width, height)
            game.wait_for_ready()
            game.client_queues[client_name] = properties.reply_to
            return serverlib.make_rsp_game_entered(game_name, 1)

        # Join game request
        if msg_parts[0] == common.REQ_JOIN_GAME:
            if len(msg_parts) != 3:
                return serverlib.make_rsp_invalid_request()

            game_name = msg_parts[1]
            client_name = msg_parts[2]

            if game_name not in self.games:
                return serverlib.make_rsp_name_doesnt_exist()
            if client_name not in self.clients.client_set:
                return serverlib.make_rsp_permission_denied()
            if client_name not in self.games[game_name].players and\
                self.games[game_name].state == 'closed':
                return serverlib.make_rsp_permission_denied()

            self.games[game_name].client_queues[client_name] =\
                properties.reply_to
            if client_name not in self.games[game_name].players:
                self.games[game_name].players.add(client_name)
                # Send event that new player was added
                msg = serverlib.make_e_new_player(client_name)
                send_message(self.channel, msg,
                             common.make_key_game_events(self.server_name,
                                                         game_name))

            return serverlib.make_rsp_game_entered(game_name, 0)

        # Spectating game request
        if msg_parts[0] == common.REQ_SPECTATE_GAME:
            if len(msg_parts) != 3:
                return serverlib.make_rsp_invalid_request()

            game_name = msg_parts[1]
            client_name = msg_parts[2]

            if game_name not in self.games:
                return serverlib.make_rsp_name_doesnt_exist()
            if client_name not in self.clients.client_set:
                return serverlib.make_rsp_permission_denied()
            if client_name in self.games[game_name].players:
                return serverlib.make_rsp_permission_denied()

            game = self.games[game_name]
            game.spectators.add(client_name)
            return serverlib.make_rsp_game_spectate(game_name, 0,
                                                    game.spectator_queue)

    def reply_request(self, ch, method, properties, body):
        '''Reply to request about list of games.
        @param ch: pika.BlockingChannel
        @param method: pika.spec.Basic.Deliver
        @param properties: pika.spec.BasicProperties
        @param body: str or unicode
        '''
        LOG.debug('Processing game list request.')
        LOG.debug('Received message: %s', body)
        msg_parts = body.split(common.SEP)
        response = self.process_request(msg_parts, properties)

        # Sending response
        ch.basic_publish(exchange='direct_logs',
                         routing_key=properties.reply_to,
                         body=response)
        LOG.debug('Sent response to client: %s', response)

class Clients(object):
    '''Process client connections.
    '''
    def __init__(self, channel, server_name):
        '''Set a set of client usernames, communication channel, and consuming.
        @param channel: pika connection channel
        @param server_name: name of server
        '''
        # Set of client usernames
        self.client_set = set()

        self.server_name = server_name

        # Communication
        self.channel = channel
        self.connect_queue = channel.queue_declare(exclusive=True).method.queue
        self.channel.queue_bind(exchange='direct_logs',
                                queue=self.connect_queue,
                                routing_key=self.server_name)
        self.channel.basic_consume(self.process_client,
                                   queue=self.connect_queue,
                                   no_ack=True)

    def process_client(self, ch, method, properties, body):
        '''Process client's connection request.
        @param ch: pika.BlockingChannel
        @param method: pika.spec.Basic.Deliver
        @param properties: pika.spec.BasicProperties
        @param body: str or unicode
        '''
        LOG.debug('Processing connection request.')
        LOG.debug('Received message: %s', body)
        msg_parts = body.split(common.SEP)
        response = None

        # Connect request
        if msg_parts[0] == common.REQ_CONNECT:
            if len(msg_parts) != 2:
                response = serverlib.make_rsp_invalid_request()
            else:
                client_name = msg_parts[1].strip()
                if client_name in self.client_set:
                    response = serverlib.make_rsp_username_taken()
                else:
                    self.client_set.add(msg_parts[1].strip())
                    response = serverlib.make_rsp_connected(self.server_name,
                                                            client_name)

        # Disconnect request
        elif msg_parts[0] == common.REQ_DISCONNECT:
            try:
                self.client_set.remove(msg_parts[1])
            except KeyError:
                pass
            response = serverlib.make_rsp_disconnected()

        # Sending response
        ch.basic_publish(exchange='direct_logs',
                         routing_key=properties.reply_to,
                         body=response)
        LOG.debug('Sent response to client: %s', response)

# Functions -------------------------------------------------------------------
def __info():
    return '%s version %s (%s)' % (___NAME, ___VER, ___BUILT)

def publish_server_advertisements(server_on, channel, server_name, interval=2):
    '''Publishes server adverts periodically.
    @param server_on: indicate server running
    @param channel: pika.BlockingChannel
    @param server_name: name of server
    @param interval: interval for publishing
    '''
    while server_on[0]:
        channel.basic_publish(exchange='direct_logs',
                              routing_key=common.make_key_server_advert(),
                              body=server_name)
        sleep(interval)

def stop_server(channel, server_name):
    '''Publishes server advert about stopping server.
    @param channel: pika.BlockingChannel
    @param server_name: name of server
    '''
    channel.basic_publish(exchange='direct_logs',
                          routing_key=common.make_key_server_stop(),
                          body=server_name)

# Main function ---------------------------------------------------------------
if __name__ == '__main__':
    # Parsing arguments
    parser = ArgumentParser()
    parser.add_argument(
        '-H', '--host',
        help='Address of the RabbitMQ server, defaults to %s' %
        common.DEFAULT_SERVER_INET_ADDR,
        default=common.DEFAULT_SERVER_INET_ADDR
    )
    parser.add_argument(
        '-p', '--port',
        help='Port of the RabbitMQ server, defaults to %d' %
        common.DEFAULT_SERVER_PORT,
        default=common.DEFAULT_SERVER_PORT
    )
    parser.add_argument('-n', '--name',
                        help='Server name.',
                        required=True)
    args = parser.parse_args()

    # Connection
    connection = pika.BlockingConnection(
        pika.ConnectionParameters(host=args.host, port=args.port)
    )
    channel = connection.channel()
    channel.exchange_declare(exchange='direct_logs', type='direct')

    # Client connections
    clients = Clients(channel, args.name)

    # Server advertisements
    server_on = [True]
    t = threading.Thread(target=publish_server_advertisements,
                         args=(server_on, channel, args.name))
    t.setDaemon(True)
    t.start()
    LOG.debug('Started server advertising.')

    # Dict of games
    game_list = GameList(channel, args, clients)

    try:
        while True:
            channel.start_consuming()
    except KeyboardInterrupt as e:
        LOG.debug('Crtrl+C issued ...')
        LOG.info('Terminating server ...')

    server_on[0] = False
    stop_server(channel, args.name)
    LOG.debug('Stopped advertising.')

    # Send message to all games control queues to stop consuming.
    for game in game_list.games.values():
        channel.basic_publish(exchange='direct_logs',
                              routing_key=game.control_queue,
                              body='')


import time
import datetime

now = datetime.datetime.now()
if now.month <= 6:
    before_date = "%s-%s-%s" % (now.year - 1, 6 + now.month, now.day)
else:
    before_date = "%s-%s-%s" % (now.year, now.month - 6)
print(before_date)

# 上面已经可以算出6个月前的今天，是字符串格式。如果想转回时间类型，则加上以下两句
#atime = datetime.datetime.strptime(before_date, "%Y-%m-%d")
#print(atime)


from IPython.display import display, HTML, clear_output
import matplotlib.pyplot as plt
import numpy as np

from utils import generic_dataloader

encoder_classifier_evaluations = None
generator_discriminator_evaluations = None

def display_table(tabldict):
    content = "

"+"".join([f"{key}	" for key in tabldict])+"
"
    for i in range(len(tabldict[next(iter(tabldict))])):
        content += "
"
        for key in tabldict:
            form = f"{tabldict[key][i]:.4f}" if type(tabldict[key][i]) == float else str(tabldict[key][i])
            content = content + ""+form+"	"
        content += "
"
    content += "
"

    display(HTML(content))

def encoder_classifier_notebook_evaluator_evaluate_and_print(self):
    svhn_train_loss, svhn_train_accuracy, *_ = self.evaluate(self.svhn_trainsplit_loader)
    _, svhn_test_accuracy, *_ = self.evaluate(self.svhn_testsplit_loader)

    _, mnist_train_accuracy, _, mnist_train_above_threshold_accuracy = self.evaluate(self.mnist_trainsplit_loader)

    results = {"Epoch": self.epoch,
               "SVHN Train Split Loss": svhn_train_loss,
               "SVHN Train Split Classification Acc. (%)": svhn_train_accuracy,
               "SVHN Test Split Classification Acc. (%)": svhn_test_accuracy,
               "MNIST Train Split Above Threshold (%)": mnist_train_above_threshold_accuracy}

    for key in results:
        encoder_classifier_evaluations[key].append(results[key])

    # clear output before printing same table with more rows
    clear_output(wait=True)
    display_table(encoder_classifier_evaluations)

def encoder_classifier_notebook_evaluator_reset():
    global encoder_classifier_evaluations
    encoder_classifier_evaluations = {"Epoch": [],
                                      "SVHN Train Split Loss": [],
                                      "SVHN Train Split Classification Acc. (%)": [],
                                      "SVHN Test Split Classification Acc. (%)": [],
                                      "MNIST Train Split Above Threshold (%)": []}

def generator_discriminator_notebook_evaluator_reset():
    global generator_discriminator_evaluations
    generator_discriminator_evaluations = {"Epoch": [],
                                           "Discriminator Loss": [],
                                           "Generator Deception Loss": [],
                                           "Generator Reconstruction Loss": [],
                                           "Generator Loss": [],
                                           "MNIST High Conf. Sample Count": []}

def generator_discriminator_notebook_evaluator_evaluate_and_print(self, mnist_hc_loader, pseudolabels):

    svhn_train_result_dict, svhn_train_total = self.evaluate(self.svhn_trainsplit_loader, 0)
    mnist_hc_result_dict, mnist_hc_total = self.evaluate(mnist_hc_loader, 1, pseudolabels=pseudolabels)
    training_result_dict = {key: (svhn_train_result_dict[key] * svhn_train_total +
                                  mnist_hc_result_dict[key] * mnist_hc_total) / (svhn_train_total + mnist_hc_total)
                            for (key, _) in svhn_train_result_dict.items()}
    results = {"Epoch": self.epoch,
               "Discriminator Loss": training_result_dict["discriminator_mnist_loss"].item() +
                                     training_result_dict["discriminator_svhn_loss"].item(),
               "Generator Deception Loss": training_result_dict["generator_deception_loss"].item(),
               "Generator Reconstruction Loss": training_result_dict["generator_reconstruction_loss"].item(),
               "Generator Loss": training_result_dict["generator_loss"].item(),
               "MNIST High Conf. Sample Count": mnist_hc_total}

    for key in results:
        generator_discriminator_evaluations[key].append(results[key])

    clear_output(wait=True)
    img = self.reconstruct_images_from_dataset(self.svhn_trainsplit_loader_notshuffled, 1)
    npimg = img.cpu().numpy()
    plt.imshow(np.transpose(npimg, (1, 2, 0)))
    plt.axis('off')
    plt.show()

    display_table(generator_discriminator_evaluations)

def generator_discriminator_notebook_evaluator_evaluate_goals_and_print(self):
    mnist_hc_dataset, pseudolabels = self.get_high_confidence_mnist_dataset_with_pseudolabels()
    mnist_hc_loader = generic_dataloader(self.device, mnist_hc_dataset, shuffle=True, batch_size=self.batch_size)
    generator_discriminator_notebook_evaluator_reset()
    generator_discriminator_notebook_evaluator_evaluate_and_print(self, mnist_hc_loader, pseudolabels)
    mnist_test_result_dict, _ = self.evaluate(self.mnist_testsplit_loader, 1)
    results = {"MNIST Test Split Final Classification Accuracy":
                   [mnist_test_result_dict['encoder_classifier_accuracy']]}
    display_table(results)

def generator_discriminator_notebook_load_and_print_params(self, ckpt_file):
    self.load(ckpt_file)
    self.load(ckpt_file)
    print("Discriminator ADAM learning rate:", self.discriminator_mnist_optimizer.param_groups[0]['lr'])
    print("Discriminator ADAM betas:", self.discriminator_mnist_optimizer.param_groups[0]['betas'])
    print("Generator ADAM learning rate:", self.generator_optimizer.param_groups[0]['lr'])
    print("Generator ADAM betas:", self.generator_optimizer.param_groups[0]['betas'])
    print("Encoder-Classifier ADAM learning rate:", self.encoder_classifier_optimizer.param_groups[0]['lr'])
    print("Encoder-Classifier ADAM betas:", self.encoder_classifier_optimizer.param_groups[0]['betas'])
    print("DUPGAN Alpha:", self.dupgan_alpha)
    print("DUPGAN Beta:", self.dupgan_beta)
    print("epoch:", self.epoch)
    print("experiment_name:", self.experiment_name)

def encoder_classifier_notebook_load_and_print_params(self, ckpt_file):
    self.load(ckpt_file)
    print("ADAM learning rate:", self.optimizer.param_groups[0]['lr'])
    print("ADAM betas:", self.optimizer.param_groups[0]['betas'])
    print("epoch:", self.epoch)
    print("experiment_name:", self.experiment_name)


import os
from flask import Flask, render_template, url_for, redirect
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
from forms import AddForm, DelForm
app = Flask(__name__)

app.config['SECRET_KEY'] = 'mysecretkey'
###########################
### SQL DATABASE BÖLÜMÜ ###
###########################
basedir = os.path.abspath(os.path.dirname(__file__))
app.config['SQLALCHEMY_DATABASE_URI'] = "sqlite:///" + \
    os.path.join(basedir+"data.sqlite")
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)
Migrate(app, db)
###########################
###    MODELS    BÖLÜMÜ ###
###########################

class Ponny(db.Model):
    __tablename__ = 'ponnies'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.Text)

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

    def __repr__(self):
        return f"Ponny name is {self.name}"
###########################
###    VİEWS     BÖLÜMÜ ###
###########################
@app.route('/')
def index():
    return render_template('index.html')

@app.route('/add',methods=['GET','POST'])
def add():
    form = AddForm()
    if form.validate_on_submit():
        name = form.name.data
        new_ponny = Ponny(name)
        db.session.add(new_ponny)
        db.session.commit()
        return redirect(url_for('liste'))
    return render_template('add.html', form=form)

@app.route('/list')
def liste():
    ponnies = Ponny.query.all()
    return render_template('list.html', ponnies=ponnies)

@app.route('/delete', methods=['GET', 'POST'])
def delete():
    form = DelForm()
    if form.validate_on_submit():
        id = form.id.data
        ponny = Ponny.query.get(id)
        db.session.delete(ponny)
        db.session.commit()
        return redirect(url_for('liste'))
    return render_template('delete.html', form=form)

if __name__ == "__main__":
    app.run(debug=True)


#!/usr/bin/env python

from lucky.lang.build_ast import ASTBuilder
from lucky.lang.parser import Parser

class Runtime:
    def __init__(self, file: str, mode: int = 0):
        self.parser = Parser('grammar/main.lark')
        self.ast_builder = ASTBuilder()

        tree = self.parser.parse(file)
        import rich

        rich.print(tree)

        transformed = ASTBuilder().transform(tree)
        rich.print(transformed)


import cv2 as cv

img = cv.imread('photos/nature.jpg')
cv.imshow('Original', img)

# blur is using average bluring method by average surrounding pixel.
avg = cv.blur(img, (7,7))
cv.imshow('Avg', avg)

# Gaussian blur is bluring using kernel weight, 0 is sigmaX is standard deviation in x direction value.
gauss = cv.GaussianBlur(img, (7,7), 0)
cv.imshow('Gaussian', gauss)

# Median blur is using median value in kernel size.
median = cv.medianBlur(img, 3)
cv.imshow('Median', median)

# Bilateral blur is bluring using d-> kernel size, sigmaColor-> number of pixel that consider when blur and sigmaSpace-> space that will random choose pixel to consider.
bilateral = cv.bilateralFilter(img, 9, 50, 40)
cv.imshow('Bilateral', bilateral)

cv.waitKey(0)


"""
Implementation of torch modules for generative flows. Most of the codebase was adapted
from Ilya Kostrikov's implementation at github.com/ikostrikov/pytorch-flows
"""

import math
import torch
import torch.nn as nn

class BatchNormFlow(nn.Module):
    """ An implementation of a batch normalization layer from
    Density estimation using Real NVP
    (https://arxiv.org/abs/1605.08803).
    """

    def __init__(self, num_inputs, momentum=0.0, eps=1e-5):
        super(BatchNormFlow, self).__init__()

        self.log_gamma = nn.Parameter(torch.zeros(num_inputs))
        self.beta = nn.Parameter(torch.zeros(num_inputs))
        self.momentum = momentum
        self.eps = eps

        self.register_buffer('running_mean', torch.zeros(num_inputs))
        self.register_buffer('running_var', torch.ones(num_inputs))

    def forward(self, inputs, cond_inputs=None, mode='direct'):
        if mode == 'direct':
            if self.training:
                self.batch_mean = inputs.mean(0)
                self.batch_var = (
                    inputs - self.batch_mean).pow(2).mean(0) + self.eps

                self.running_mean.mul_(self.momentum)
                self.running_var.mul_(self.momentum)

                self.running_mean.add_(self.batch_mean.data *
                                       (1 - self.momentum))
                self.running_var.add_(self.batch_var.data *
                                      (1 - self.momentum))

                mean = self.batch_mean
                var = self.batch_var
            else:
                mean = self.running_mean
                var = self.running_var

            x_hat = (inputs - mean) / var.sqrt()
            y = torch.exp(self.log_gamma) * x_hat + self.beta
            return y, (self.log_gamma - 0.5 * torch.log(var)).sum(
                -1, keepdim=True)
        else:
            if self.training:
                mean = self.batch_mean
                var = self.batch_var
            else:
                mean = self.running_mean
                var = self.running_var

            x_hat = (inputs - self.beta) / torch.exp(self.log_gamma)

            y = x_hat * var.sqrt() + mean

            return y, (-self.log_gamma + 0.5 * torch.log(var)).sum(
                -1, keepdim=True)

class CouplingLayer(nn.Module):
    """ An implementation of a coupling layer
    from RealNVP (https://arxiv.org/abs/1605.08803).
    """

    def __init__(self,
                 num_inputs,
                 num_hidden,
                 mask,
                 num_cond_inputs=None,
                 s_act='tanh',
                 t_act='relu',
                 shared=False,
                 pre_mlp=False,
                 pre_mlp_units=64):
        super(CouplingLayer, self).__init__()

        self.num_inputs = num_inputs
        self.mask = mask
        self.shared = shared
        self.pre_mlp = pre_mlp
        self.pre_mlp_units = pre_mlp_units

        activations = {'relu': nn.ReLU, 'sigmoid': nn.Sigmoid, 'tanh': nn.Tanh}
        s_act_func = activations[s_act]
        t_act_func = activations[t_act]

        if num_cond_inputs is not None:
            total_inputs = num_inputs + (num_cond_inputs if not self.pre_mlp else self.pre_mlp_units)
            if self.pre_mlp:
                self.mlp = nn.Sequential(
                    nn.Linear(num_cond_inputs, self.pre_mlp_units), t_act_func(),
                    nn.Linear(self.pre_mlp_units, self.pre_mlp_units), t_act_func(),
                    nn.Linear(self.pre_mlp_units, self.pre_mlp_units)
                    )
        else:
            total_inputs = num_inputs

        if self.shared:
            self.shared_net = nn.Sequential(
                nn.Linear(total_inputs, num_hidden), t_act_func(),
                nn.Linear(num_hidden, num_hidden), t_act_func())
            self.scale_net = nn.Sequential(nn.Linear(num_hidden, num_inputs))
            self.translate_net = nn.Sequential(nn.Linear(num_hidden, num_inputs))
        else:
            self.scale_net = nn.Sequential(
                nn.Linear(total_inputs, num_hidden), s_act_func(),
                nn.Linear(num_hidden, num_hidden), s_act_func(),
                nn.Linear(num_hidden, num_inputs))
            self.translate_net = nn.Sequential(
                nn.Linear(total_inputs, num_hidden), t_act_func(),
                nn.Linear(num_hidden, num_hidden), t_act_func(),
                nn.Linear(num_hidden, num_inputs))

    def forward(self, inputs, cond_inputs=None, mode='direct'):
        mask = self.mask
        masked_inputs = inputs * mask
        if cond_inputs is not None:
            cond_inputs = cond_inputs if not self.pre_mlp else self.mlp(cond_inputs)
            masked_inputs = torch.cat([masked_inputs, cond_inputs], -1)

        if mode == 'direct':
            if self.shared:
                masked_inputs = self.shared_net(masked_inputs)
            log_s = self.scale_net(masked_inputs) * (1 - mask)
            t = self.translate_net(masked_inputs) * (1 - mask)
            s = torch.exp(log_s)
            return inputs * s + t, log_s.sum(-1, keepdim=True)
        else:
            if self.shared:
                masked_inputs = self.shared_net(masked_inputs)
            log_s = self.scale_net(masked_inputs) * (1 - mask)
            t = self.translate_net(masked_inputs) * (1 - mask)
            s = torch.exp(-log_s)
            return (inputs - t) * s, -log_s.sum(-1, keepdim=True)

class CNNCouplingLayer(CouplingLayer):
    """ An implementation of a coupling layer
    from RealNVP (https://arxiv.org/abs/1605.08803) conditioned on images.
    """

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        if self.pre_mlp:
            self.mlp = nn.Sequential(
                nn.Conv2d(3, 16, 3, 1), nn.ReLU(), nn.MaxPool2d(2),
                nn.Conv2d(16, 16, 3, 1), nn.ReLU(), nn.MaxPool2d(2),
                nn.Conv2d(16, 16, 3, 1), nn.ReLU(), nn.Flatten(),
                nn.Linear(2304, 1024), nn.ReLU(),
                nn.Linear(1024, 512), nn.ReLU(),
                nn.Linear(512, kwargs['pre_mlp_units']))

class FlowSequential(nn.Sequential):
    """ A sequential container for flows.
    In addition to a forward pass it implements a backward pass and
    computes log jacobians.
    """

    def forward(self, inputs, cond_inputs=None, mode='direct', logdets=None):
        """ Performs a forward or backward pass for flow modules.
        Args:
            inputs: a tuple of inputs and logdets
            mode: to run direct computation or inverse
        """
        self.num_inputs = inputs.size(-1)

        if logdets is None:
            logdets = torch.zeros(inputs.size(0), 1, device=inputs.device)

        assert mode in ['direct', 'inverse']
        if mode == 'direct':
            for module in self._modules.values():
                inputs, logdet = module(inputs, cond_inputs, mode)
                logdets += logdet
        else:
            for module in reversed(self._modules.values()):
                inputs, logdet = module(inputs, cond_inputs, mode)
                logdets += logdet

        return inputs, logdets

    def log_probs(self, inputs, cond_inputs = None):
        u, log_jacob = self(inputs, cond_inputs)
        log_probs = (-0.5 * u.pow(2) - 0.5 * math.log(2 * math.pi)).sum(
            -1, keepdim=True)
        return (log_probs + log_jacob).sum(-1, keepdim=True)

    def sample(self, num_samples=None, noise=None, cond_inputs=None):
        if noise is None:
            noise = torch.Tensor(num_samples, self.num_inputs).normal_()
        device = next(self.parameters()).device
        noise = noise.to(device)
        if cond_inputs is not None:
            cond_inputs = cond_inputs.to(device)
        samples = self.forward(noise, cond_inputs, mode='inverse')[0]
        return samples

class Deterministic(nn.Module):
    """ Simple MLP that learns deterministic mappings instead of conditional distributions. """
    def __init__(self, num_inputs, num_hidden, num_outputs):
        super().__init__()
        self.net = nn.Sequential(
            nn.Linear(num_inputs, num_hidden), nn.ReLU(),
            nn.Linear(num_hidden, num_hidden), nn.ReLU(),
            nn.Linear(num_hidden, num_outputs), nn.Tanh()
        )

    def forward(self, x):
        return self.net(x)

    def sample(self, num_samples=None, noise=None, cond_inputs=None):
        device = next(self.parameters()).device
        cond_inputs = cond_inputs.to(device)
        return self.forward(cond_inputs)

class Gaussian(nn.Module):
    """ Simple MLP that learns deterministic mappings instead of conditional distributions. """
    def __init__(self, num_inputs, num_hidden, num_outputs):
        super().__init__()
        self.net = nn.Sequential(
            nn.Linear(num_inputs, num_hidden), nn.ReLU(),
            nn.Linear(num_hidden, num_hidden), nn.ReLU()
        )
        self.mu_net = nn.Linear(num_hidden, num_outputs)
        self.log_std_net = nn.Linear(num_hidden, num_outputs)

    def forward(self, x):
        feat = self.net(x)
        return self.mu_net(feat), self.log_std_net(feat)

    def sample(self, num_samples=None, noise=None, cond_inputs=None):
        device = next(self.parameters()).device
        cond_inputs = cond_inputs.to(device)
        return self.forward(cond_inputs)


from django.contrib import admin
from django.urls import path,include
from . import views

urlpatterns = [
    path("Home/",views.IndexPage,name="homepage"),
    path("Register-Page/",views.RegisterPage,name="regpage"),
    path("Registration/",views.Register,name="Registerdata"),
    path("Updaate-Page/<int:pk>",views.UpdatePage,name="updatepage"),
    path("Updaate/<int:pk>",views.Update,name="update"),
    path("Delete/<int:pk>",views.Delete,name="delete"),
    path('',views.LoginPage,name='loginpage'),
    path('Login-User/',views.LoginUser,name='loginuser'),
    path('Logout/',views.LogOut,name='logout'),
]


from brownie import PayMeEthereum
from scripts.helper import get_account

def fund():
    pay_me = PayMeEthereum[-1]
    account = get_account()
    entrance_fee = pay_me.getEntranceFee()
    print(entrance_fee)
    print(f"The current entry fee is {entrance_fee}")
    print("Funding")
    pay_me.buyMeACoffee({"from": account, "value": entrance_fee})

def withdraw():
    pay_me = PayMeEthereum[-1]
    account = get_account()
    pay_me.withdraw({"from": account})

def main():
    fund()
    withdraw()


from unittest import TestCase

import networkx

from gtfspy.routing.connection import Connection
from gtfspy.routing.label import LabelTime
from gtfspy.routing.pseudo_connection_scan_profiler import PseudoConnectionScanProfiler

class TestPseudoPseudoConnectionScanProfiler(TestCase):
    # noinspection PyAttributeOutsideInit

    def setUp(self):
        event_list_raw_data = [
            (2, 4, 40, 50, "trip_6", 1),
            (1, 3, 32, 40, "trip_5", 1),
            (3, 4, 32, 35, "trip_4", 1),
            (2, 3, 25, 30, "trip_3", 1),
            (1, 2, 10, 20, "trip_2", 1),
            (0, 1, 0, 10, "trip_1", 1)
        ]
        self.transit_connections = list(map(lambda el: Connection(*el), event_list_raw_data))
        self.walk_network = networkx.Graph()
        self.walk_network.add_edge(1, 2, d_walk=20)
        self.walk_network.add_edge(3, 4, d_walk=15)
        self.walk_speed = 1
        self.source_stop = 1
        self.target_stop = 4
        self.transfer_margin = 0
        self.start_time = 0
        self.end_time = 50

    def test_basics(self):
        csa_profile = PseudoConnectionScanProfiler(self.transit_connections, self.target_stop,
                                                   self.start_time, self.end_time, self.transfer_margin,
                                                   self.walk_network, self.walk_speed)
        csa_profile.run()

        stop_3_labels = csa_profile.stop_profiles[3].get_final_optimal_labels()
        self.assertEqual(len(stop_3_labels), 1)
        self.assertIn(LabelTime(32, 35), stop_3_labels)

        stop_2_labels = csa_profile.stop_profiles[2].get_final_optimal_labels()
        self.assertEqual(len(stop_2_labels), 2)
        self.assertIn(LabelTime(40, 50), stop_2_labels)
        self.assertIn(LabelTime(25, 35), stop_2_labels)

        source_stop_profile = csa_profile.stop_profiles[self.source_stop]
        source_stop_pareto_optimal_tuples = source_stop_profile.get_final_optimal_labels()

        labels = []
        labels.append(LabelTime(departure_time=10, arrival_time_target=35))
        labels.append(LabelTime(departure_time=20, arrival_time_target=50))
        labels.append(LabelTime(departure_time=32, arrival_time_target=55))

        self._assert_pareto_tuple_sets_equal(
            labels,
            source_stop_pareto_optimal_tuples
        )

    def test_simple(self):
        event_list_raw_data = [
            (2, 4, 40, 50, "trip_5", 1),
        ]
        transit_connections = list(map(lambda el: Connection(*el), event_list_raw_data))
        walk_network = networkx.Graph()
        walk_network.add_edge(1, 2, d_walk=20)
        walk_network.add_edge(3, 4, d_walk=15)
        walk_speed = 1
        source_stop = 1
        target_stop = 4
        transfer_margin = 0
        start_time = 0
        end_time = 50

        labels = []
        labels.append(LabelTime(departure_time=20, arrival_time_target=50))

        csa_profile = PseudoConnectionScanProfiler(transit_connections, target_stop,
                                                   start_time, end_time, transfer_margin,
                                                   walk_network, walk_speed)
        csa_profile.run()
        source_stop_profile = csa_profile.stop_profiles[source_stop]
        source_stop_labels = source_stop_profile.get_final_optimal_labels()

        self._assert_pareto_tuple_sets_equal(
            labels,
            source_stop_labels
        )

    def test_last_leg_is_walk(self):
        event_list_raw_data = [
            (0, 1, 0, 10, "trip_1", 1)
        ]
        transit_connections = list(map(lambda el: Connection(*el), event_list_raw_data))
        walk_network = networkx.Graph()
        walk_network.add_edge(1, 2, d_walk=20)

        walk_speed = 1
        source_stop = 0
        target_stop = 2
        transfer_margin = 0
        start_time = 0
        end_time = 50
        labels = []
        labels.append(LabelTime(departure_time=0, arrival_time_target=30))

        csa_profile = PseudoConnectionScanProfiler(transit_connections, target_stop,
                                                   start_time, end_time, transfer_margin,
                                                   walk_network, walk_speed)
        csa_profile.run()
        found_tuples = csa_profile.stop_profiles[source_stop].get_final_optimal_labels()
        self._assert_pareto_tuple_sets_equal(found_tuples, labels)

    def test_walk_is_faster_than_by_trip(self):
        event_list_raw_data = [
            (0, 1, 0, 10, "trip_1", 1)
        ]
        transit_connections = list(map(lambda el: Connection(*el), event_list_raw_data))
        walk_speed = 2
        source_stop = 0
        target_stop = 1
        transfer_margin = 0
        start_time = 0
        end_time = 50

        walk_network = networkx.Graph()
        walk_network.add_edge(0, 1, d_walk=1)
        csa_profile = PseudoConnectionScanProfiler(transit_connections, target_stop,
                                                   start_time, end_time, transfer_margin,
                                                   walk_network, walk_speed)
        csa_profile.run()
        source_profile = csa_profile.stop_profiles[source_stop]
        self.assertEqual(source_profile.evaluate_earliest_arrival_time_at_target(0, 0), 0.5)
        found_tuples = source_profile.get_final_optimal_labels()
        self.assertEqual(len(found_tuples), 0)

    def test_target_node_not_in_walk_network(self):
        event_list_raw_data = [
            (0, 1, 0, 10, "trip_1", 1)
        ]
        transit_connections = list(map(lambda el: Connection(*el), event_list_raw_data))
        walk_speed = 2
        source_stop = 0
        target_stop = 1
        transfer_margin = 0
        start_time = 0
        end_time = 50

        walk_network = networkx.Graph()
        csa_profile = PseudoConnectionScanProfiler(transit_connections, target_stop,
                                                   start_time, end_time, transfer_margin,
                                                   walk_network, walk_speed)
        csa_profile.run()
        source_profile = csa_profile.stop_profiles[source_stop]
        self.assertEqual(source_profile.evaluate_earliest_arrival_time_at_target(0, 0), 10)
        found_tuples = source_profile.get_final_optimal_labels()
        self.assertEqual(len(found_tuples), 1)

    def _assert_pareto_tuple_sets_equal(self, found_tuples, should_be_tuples):
        for found_tuple in found_tuples:
            self.assertIn(found_tuple, should_be_tuples)
        for should_be_tuple in should_be_tuples:
            self.assertIn(should_be_tuple, found_tuples)


# coding: utf-8
from __future__ import unicode_literals

import re

from .common import InfoExtractor
from ..utils import (
    determine_ext,
    int_or_none,
    float_or_none,
    js_to_json,
    parse_iso8601,
    remove_end,
)

class TV2IE(InfoExtractor):
    _VALID_URL = r'https?://(?:www\.)?tv2\.no/v/(?P<id>\d+)'
    _TEST = {
        'url': 'http://www.tv2.no/v/916509/',
        'info_dict': {
            'id': '916509',
            'ext': 'mp4',
            'title': 'Se Frode Gryttens hyllest av Steven Gerrard',
            'description': 'TV 2 Sportens huspoet tar avskjed med Liverpools kaptein Steven Gerrard.',
            'timestamp': 1431715610,
            'upload_date': '20150515',
            'duration': 156.967,
            'view_count': int,
            'categories': list,
        },
        'params': {
            # m3u8 download
            'skip_download': True,
        },
    }

    def _real_extract(self, url):
        video_id = self._match_id(url)

        formats = []
        format_urls = []
        for protocol in ('HDS', 'HLS'):
            data = self._download_json(
                'http://sumo.tv2.no/api/web/asset/%s/play.json?protocol=%s&videoFormat=SMIL+ISMUSP' % (video_id, protocol),
                video_id, 'Downloading play JSON')['playback']
            for item in data['items']['item']:
                video_url = item.get('url')
                if not video_url or video_url in format_urls:
                    continue
                format_id = '%s-%s' % (protocol.lower(), item.get('mediaFormat'))
                if not self._is_valid_url(video_url, video_id, format_id):
                    continue
                format_urls.append(video_url)
                ext = determine_ext(video_url)
                if ext == 'f4m':
                    formats.extend(self._extract_f4m_formats(
                        video_url, video_id, f4m_id=format_id, fatal=False))
                elif ext == 'm3u8':
                    formats.extend(self._extract_m3u8_formats(
                        video_url, video_id, 'mp4', entry_protocol='m3u8_native',
                        m3u8_id=format_id, fatal=False))
                elif ext == 'ism' or video_url.endswith('.ism/Manifest'):
                    pass
                else:
                    formats.append({
                        'url': video_url,
                        'format_id': format_id,
                        'tbr': int_or_none(item.get('bitrate')),
                        'filesize': int_or_none(item.get('fileSize')),
                    })
        self._sort_formats(formats)

        asset = self._download_json(
            'http://sumo.tv2.no/api/web/asset/%s.json' % video_id,
            video_id, 'Downloading metadata JSON')['asset']

        title = asset['title']
        description = asset.get('description')
        timestamp = parse_iso8601(asset.get('createTime'))
        duration = float_or_none(asset.get('accurateDuration') or asset.get('duration'))
        view_count = int_or_none(asset.get('views'))
        categories = asset.get('keywords', '').split(',')

        thumbnails = [{
            'id': thumbnail.get('@type'),
            'url': thumbnail.get('url'),
        } for _, thumbnail in asset.get('imageVersions', {}).items()]

        return {
            'id': video_id,
            'url': video_url,
            'title': title,
            'description': description,
            'thumbnails': thumbnails,
            'timestamp': timestamp,
            'duration': duration,
            'view_count': view_count,
            'categories': categories,
            'formats': formats,
        }

class TV2ArticleIE(InfoExtractor):
    _VALID_URL = r'https?://(?:www\.)?tv2\.no/(?:a|\d{4}/\d{2}/\d{2}(/[^/]+)+)/(?P<id>\d+)'
    _TESTS = [{
        'url': 'http://www.tv2.no/2015/05/16/nyheter/alesund/krim/pingvin/6930542',
        'info_dict': {
            'id': '6930542',
            'title': 'Russen hetses etter pingvintyveri - innrømmer å ha åpnet luken på buret',
            'description': 'md5:339573779d3eea3542ffe12006190954',
        },
        'playlist_count': 2,
    }, {
        'url': 'http://www.tv2.no/a/6930542',
        'only_matching': True,
    }]

    def _real_extract(self, url):
        playlist_id = self._match_id(url)

        webpage = self._download_webpage(url, playlist_id)

        # Old embed pattern (looks unused nowadays)
        assets = re.findall(r'data-assetid=["\'](\d+)', webpage)

        if not assets:
            # New embed pattern
            for v in re.findall(r'TV2ContentboxVideo\(({.+?})\)', webpage):
                video = self._parse_json(
                    v, playlist_id, transform_source=js_to_json, fatal=False)
                if not video:
                    continue
                asset = video.get('assetId')
                if asset:
                    assets.append(asset)

        entries = [
            self.url_result('http://www.tv2.no/v/%s' % asset_id, 'TV2')
            for asset_id in assets]

        title = remove_end(self._og_search_title(webpage), ' - TV2.no')
        description = remove_end(self._og_search_description(webpage), ' - TV2.no')

        return self.playlist_result(entries, playlist_id, title, description)


import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
from sklearn.cluster import KMeans
from sklearn.cluster import MeanShift, estimate_bandwidth
from itertools import cycle

data=pd.read_csv("table_jones.csv", delimiter=',', header=None)
x=data[1].values
y=data[4].values
XX=np.array(list(zip(x,y)))

# #############################################################################
# Compute clustering with MeanShift

# The following bandwidth can be automatically detected using
bandwidth = estimate_bandwidth(XX, quantile=0.2, n_samples=500)

ms = MeanShift(bandwidth=bandwidth, bin_seeding=True)
ms.fit(XX)
labels = ms.labels_
cluster_centers = ms.cluster_centers_

labels_unique = np.unique(labels)
n_clusters_ = len(labels_unique)

print("number of estimated clusters : %d" % n_clusters_)

# #############################################################################
colors = cycle('bgrcmykbgrcmykbgrcmykbgrcmyk')
for k, col in zip(range(n_clusters_), colors):
    my_members = labels == k
    cluster_center = cluster_centers[k]
    plt.plot(XX[my_members, 0], XX[my_members, 1], col + '.')
    plt.plot(cluster_center[0], cluster_center[1], 'o', markerfacecolor=col,
             markeredgecolor='k', markersize=14)

plt.xlabel('Absolute magnitude')
plt.ylabel('Median age [Myr]')
plt.title('(3152) Jones')
plt.text(15.2,4.65,'(a)', fontsize=12)
plt.savefig('/home/valerio/PRAVEC/TEXT/ML_JONES/MEAN-SHIFT_JONES/Mean-shift_jones.eps')
plt.show()


import time
from bs4 import BeautifulSoup as soup

MODELS_MAKES_URL = 'https://www.autotrader.com/cars-for-sale'

# page_soup = soup(pull_url(MODELS_MAKES_URL, 'form-control'), features="lxml")

# makes = page_soup.find('select', {'aria-label': 'Select [object Object]'}).find('optgroup', {'label': 'All Makes'}).find_all('option')

# for make in makes:
#     print(make)
    # make.click()
    # print(page_soup.find('select', {'name': 'ModelCode'}).find('optgroup', {'label': 'All Models'}).find_all('option'))

# make_ex = makes[0]

# print(type(make_ex))
import time
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

def pull_url(url):
    chrome_driver_path = '/Users/josepholeynik/Coding/Python/used_cars/chromedriver'
    chrome_options = Options()
    chrome_options.add_argument('--headless')
    user_agent = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.89 Safari/537.36'
    chrome_options.add_argument('user-agent={0}'.format(user_agent))
    webdriverC = webdriver.Chrome(executable_path=chrome_driver_path, options=chrome_options)
    with webdriverC as driver:
        driver.implicitly_wait(10)
        driver.get(url)
        WebDriverWait(driver, 30).until(EC.presence_of_all_elements_located((By.CLASS_NAME, 'form-control')))
        #WebDriverWait(driver, 30).until(EC.element_to_be_clickable((By.CLASS_NAME, 'form-control')))

        #el = driver.find_element_by_id('ModelCode2069')
        #eli = driver.find_elements_by_tag_name('optgroup')
        #el = driver.find_element_by_xpath("html/body/div/div/div/div/div/div/div/div/div/form/div/div[@class='col-xs-6 col-sm-4 padding-left-0 padding-left-sm-2']
        el = driver.find_element_by_xpath("//optgroup[contains(@label,'All Makes')]")
        print(el)
        #print(len(eli.text)
        els = el.find_elements_by_tag_name('option')#.getText()
        print(len(els))
        for i in range(len(els)):
            print(els[i].text)
        # for option in el.find_elements_by_tag_name('option'):
        #     print(option.text)

        #page_source = driver.page_source
        driver.close()
    return

pull_url(MODELS_MAKES_URL)

# .find('select', {'aria-label': 'Select [object Object]'})
# .find('optgroup', {'label': 'All Makes'})
# .find_all('option')


from celery import Celery, Task
from projects import create_app, db
from .models import DataAction
from celery import chain
from .aggregator import aggregate_data
from .writer import write_to_excel
from .uploader import upload_to_S3

app = create_app()

def celery_init_app(app=app):
    class FlaskTask(Task):
        def __call__(self, *args: object, **kwargs: object):
            with app.app_context():
                return self.run(*args, **kwargs)

    celery_app = Celery(app.name, task_cls=FlaskTask)
    celery_app.config_from_object(app.config)
    celery_app.set_default()
    app.extensions["celery"] = celery_app
    return celery_app

App = celery_init_app()

App.conf.beat_schedule = {
    'run_jobs': {
        'task': 'projects.worker.check_for_jobs',
        'schedule': 20
    },
}

@App.task
def check_for_jobs():
    try:
        results = DataAction.query.filter_by(is_main=True,is_being_processed=True).all()
        print('GETTING RESULTS--------------',results)
        for result in results:
            if result.current_state == 'DATA_AGGREGATION':
                aggregate_data.delay(result.func_id)
            elif result.current_state == 'WRITING_DATA':
                write_to_excel.delay(result.func_id)
            elif result.current_state == 'UPLOADING_DATA':
                upload_to_S3.delay(result.func_id)
            else:
                print("unkown state") # use logging here
        return True
    except Exception as e:
        print(e)
        return False


from django.shortcuts import render, get_object_or_404
from django.views.generic import ListView
from .models import Post

class PostListView(ListView):
    model               = Post
    template_name       = 'blog/post/list.html'
    queryset            = Post.published.all()
    context_object_name = 'posts'
    # paginate_by         = 1

def Post_detail_view(request, year, month, day, slug):
    post = get_object_or_404(
        Post,
        publish__year=year,
        publish__month=month,
        publish__day=day,
        slug=slug,
    )
    context = {
        'post':post,
    }
    return render(request, 'blog/post/detail.html', context)


"""Quantile Loss"""
import math
from typing import Callable, Tuple, Optional

import numpy as np
import torch
from torch import nn

MeanStdFun = Callable[[torch.Tensor], Tuple[torch.Tensor, torch.Tensor]]

class LaplaceLoss(nn.Module):
    """Laplace Loss"""

    def __init__(self, get_mean_std: MeanStdFun,
                 clips: Optional[Tuple[float, float]] = None):
        super().__init__()
        self.get_mean_std = get_mean_std
        self.root_2 = math.sqrt(2)
        self.clips = clips

    def forward(self, logits: torch.Tensor,
                targets: torch.Tensor) -> torch.Tensor:
        """Calculate laplacian loss"""
        means, std = self.get_mean_std(logits)
        delta = torch.abs(means - targets)
        if self.clips is not None:
            delta[delta > self.clips[0]] = self.clips[0]
            std[std < self.clips[1]] = self.clips[1]
        laplace = np.sqrt(2) * delta / std + torch.log(np.sqrt(2) * std)
        return torch.mean(laplace)


import numpy as np
from skimage import io
import matplotlib.pyplot as plt

from util import dict_minus_immutable, load_dict, timing
from config import *

@timing
def get_face_matches(known_faces, face):
    return np.linalg.norm(known_faces - face, axis=1)

@timing
def calculate_quality(own_matches, other_matches):
    """
    IDEAS:
        - ? drop the 10% worst images of ourselves
            > or probably not - we want to score high on these too
        - ! drop the 80% worst images of other
            > we are primarily interested in other images that look a bit like us
        - subtract standard deviation
    """
    details = {}
    avg_own = np.average(own_matches)
    avg_oth = np.average(other_matches)
    std_own = np.std(own_matches)
    std_oth = np.std(other_matches)

    details["avg_own"] = avg_own
    details["avg_oth"] = avg_oth
    details["std_own"] = std_own
    details["std_oth"] = std_oth

    others_like_me_n = int(len(other_matches)*0.20) # the 20% that looks most like me
    details["avg_others_like_me"] = np.average(sorted(other_matches)[:others_like_me_n])

    # Number of own images that fails comparison
    details["n_false_negative"] = len(own_matches[own_matches > 0.6])

    # Number of other images that tests positive
    details["n_false_positive"] = len(other_matches[other_matches < 0.6])

    quality = avg_oth - avg_own
    return (quality, details)

def find_other_embeddings(embeddings_per_person, person_id):
    others_embeddings = dict_minus_immutable(embeddings_per_person, person_id).values()
    return [item for sublist in others_embeddings for item in sublist]  # just efficient flatten()

def calculate_qualities(people):
    print("Calculating embedding qualities")
    embeddings_per_person = dict([(k, [f["embedding"] for f in v["faces"]]) for k, v in people.items()])

    for person_id, person in people.items():
        others_embeddings = find_other_embeddings(embeddings_per_person, person_id)
        print("  " + person_id + ": faces: ", len(person["faces"]), ", other faces: ", len(others_embeddings))

        for face in person["faces"]:
            own_embeddings_except_this_face = [f["embedding"] for f in person["faces"] if f["image_id"] != face["image_id"]]
            some_others_embeddings = others_embeddings # For now use all, it runs fast :)

            own_matches = get_face_matches(own_embeddings_except_this_face, face["embedding"])
            other_matches = get_face_matches(some_others_embeddings, face["embedding"])
            quality, quality_details = calculate_quality(own_matches, other_matches)

            face["quality"] = quality
            face["quality_details"] = quality_details

        # print("   - qualities: ", [face["quality"] for face in person["faces"]])

def filter_dataset_errors(people):
    """
    The MS-Celeb dataset have lots of people placed in wrong
    """
    calculate_qualities(people)     # Or use a tailored calculation for filtering???
    print("Filtering dataset for people not belonging")
    for person_id, person in people.items():
        faces = sorted(person["faces"], key=lambda f: -f['quality'])
        n_false_negatives = faces[0]["quality_details"]["n_false_negative"]
        if n_false_negatives > 0:
            print("Removing ",n_false_negatives," false negatives (probably wrong person) from ",person_id)
            person["faces"] = faces[:-n_false_negatives]

def print_best_image(people):
    for person_id, person in people.items():
        faces = sorted(person["faces"], key=lambda f: -f['quality'])
        print("Best image for recognition for "+person_id+" is "+faces[0]["image_id"]+"; having quality:", faces[0]["quality"])

def decorate_image_with_metrics(ax, image, face):
    image_height, image_width, unused = image.shape
    h, w = image_height / 5, image_width / 2   # text should be unaffected by image size (that may be uneven)
    # ax.text(0, 0, "{0:.2f}".format(face["quality"]), fontsize=10, color='red', verticalalignment='bottom')
    ax.text(0, 0,   "{0:.2f}".format(face["quality_details"]["avg_own"]), color='red', verticalalignment='top')
    ax.text(w, 0,   "{0:.2f}".format(face["quality_details"]["avg_oth"]), color='green', verticalalignment='top')
    ax.text(0, h,   "{}/{}".format(face["quality_details"]["n_false_negative"], face["quality_details"]["n_false_positive"]), color='blue', verticalalignment='top')
    ax.text(w, h,   "{0:.2f}".format(face["quality_details"]["avg_others_like_me"]), color='white', verticalalignment='top')

def plot_persons_faces(person):
    faces = sorted(person["faces"], key=lambda f: -f['quality'])    # best quality first
    faces = faces[0:18] + faces[-18:]   # Just some, not all
    num_cols = int(np.sqrt(len(faces))-(1e-7)) + 1
    print("Plotting face for ", person["person_id"])
    plt.figure(person["person_id"], figsize=(num_cols, num_cols))
    for i, face in enumerate(faces):
        image = io.imread(face["path"])
        ax = plt.subplot(num_cols, num_cols, i + 1)
        ax.set_axis_off()
        decorate_image_with_metrics(ax, image, face)
        plt.imshow(image)

    plt.subplots_adjust(wspace=0.1, hspace=0, left=0, right=1, top=1, bottom=0)
    plt.draw()  # plt.show()
    return None

def plot_images(people):
    # for person in people.values():
    #     plot_persons_faces(person)
    people_arr = list(people.values())
    plot_persons_faces(people_arr[1])
    plot_persons_faces(people_arr[5])
    plot_persons_faces(people_arr[11])
    plot_persons_faces(people_arr[12])
    plot_persons_faces(people_arr[13])

people = load_dict(intermediate_file)
#filter_dataset_errors(people)
calculate_qualities(people)

print_best_image(people)

plot_images(people)
plt.show()

# people:
#{
#    'm.03g19n': {
#        'person_id': 'm.03g19n',
#        'best_landmark':, ''
#        'faces': [
#            {
#                'image_id': '82-FaceId-0.jpg',
#                'quality': TBD: 0..1
#                'quality_details': {
#                   avg_own, avg_oth, std_own, std_oth, ...
#                },
#                'path':  '/Users/trygve/data/ms-celeb/MsCelebV1-Faces-Aligned.Samples/samples//m.03g19n/82-FaceId-0.jpg',
#                'bounds': rectangle(21,37,93,109),
#                'landmarks-5': [(80, 52), (66, 54), (31, 52), (44, 54), (56, 84)],
#                'landmarks-68': [(80, 52), (66, 54), (31, 52), (44, 54), (56, 84), ...],
#                'embedding': array([<128-vector embedding>])
#            },
#            {
#                'image_id': '91-FaceId-0.jpg',
#                'quality': TBD: 0..1
#                'quality_details': {
#                   avg_own, avg_oth, std_own, std_oth, ...
#                },
#                'path':  '/Users/trygve/data/ms-celeb/MsCelebV1-Faces-Aligned.Samples/samples//m.03g19n/91-FaceId-0.jpg',
#                'bounds': rectangle(21,37,93,109),
#                'landmarks-5': [(80, 52), (66, 54), (31, 52), (44, 54), (56, 84)],
#                'landmarks-68': [(80, 52), (66, 54), (31, 52), (44, 54), (56, 84), ...],
#                'embedding': array([<128-vector embedding>])
#            },
#            ...
#        ]
#    },
#    'm.044wfaf': {...}
#}


import json, boto3, datetime
from boto3.dynamodb.conditions import Key
from layer import jsonDumpsSetDefault

##### GETSOCIALEVENTS: {apiurl}/socialEvent/getEvents ######
# Created 2023-03-04 | Vegan Lroy
# LastRev 2023-05-20 | Vegan Lroy
#
# Lambda fn fetch social events from the past week (up to 3)
#
############################################################

NUM_SECS_IN_WK = 604800

# ENDPOINT CODE
def lambda_handler(event, context):
    data = event['queryStringParameters']
    if 'univ' in data and 'city' not in data:
        pKey    = 'univAssoc'
        pKeyVal = data['univ']
    elif 'city' in data:
        pKey    = 'city-createTimestamp-index'
        pKeyVal = data['city']
    else:
        return {
            'statusCode': 400,
            'body': json.dumps({
                'Client-Error Description': 'Neither city nor univ query string provided.'
            })
        }

    tableName = "SocialEvents"
    table = boto3.resource("dynamodb").Table(tableName)

    if 'fromTime' in data:
        for i in range(1,4):
            try:
                timeFrom = (int(data['fromTime']) - (NUM_SECS_IN_WK * i)) * 1000
            except:
                return {
                    'statusCode': 404,
                    'body': json.dumps({
                        'Client-Error Description': 'Timestamp given included non-numerical characters: ' + data['fromTime']
                    })
                }

            if pKey == 'univAssoc':
                response = table.query(
                    KeyConditionExpression=Key(pKey).eq(pKeyVal)&Key('createTimestamp').gt(timeFrom)
                    )
            else:
                response = table.query(
                    IndexName=pKey,
                    KeyConditionExpression=Key('city').eq(pKeyVal)&Key('createTimestamp').gt(timeFrom)
                    )

            if 'Items' in response and len(response['Items']) > 0:
                break
    else:
        for i in range(1,4):
            time = (int(datetime.datetime.now().timestamp()) - (NUM_SECS_IN_WK * i)) * 1000

            if pKey == 'univAssoc':
                response = table.query(
                    KeyConditionExpression=Key(pKey).eq(pKeyVal)&Key('createTimestamp').gt(time)
                    )
            else:
                response = table.query(
                    IndexName=pKey,
                    KeyConditionExpression=Key('city').eq(pKeyVal)&Key('createTimestamp').gt(time)
                    )

            if 'Items' in response and len(response['Items']) > 0:
                break

    try:
        rV = json.dumps(response['Items'], default=jsonDumpsSetDefault)

        return {
            'statusCode': 200,
            'body': rV
        }
    except:
        return {'statusCode': 500}


from MapView.CustomSprites.ContainerSprite import ContainerSprite
from MapView.Utils import draw_text_with_wrapping, draw_text, \
    draw_text_with_wrapping_and_centering
from MapView.Consts import YELLOW, BUILDINGS_PANEL_WIDTH, \
    RESOURCES_PANEL_HEIGHT, NAVIGATION_PANEL_HEIGHT
from MapView.Items.Button import Button
from CreatorView.RelativePaths import relative_textures_path
from MapView.Modals.ClosedHintModal import HINT_WIDTH
import pygame

HINT_MODAL_X = 0.2
HINT_MODAL_Y = 0.2
HINT_MODAL_WIDTH = 1 - BUILDINGS_PANEL_WIDTH - HINT_WIDTH - 0.4
HINT_MODAL_HEIGHT = 1 - RESOURCES_PANEL_HEIGHT - NAVIGATION_PANEL_HEIGHT - 0.4

BUTTON_WIDTH = 0.1
BUTTON_HEIGHT = 0.1

ARROW_BUTTON_WIDTH = 0.15
ARROW_BUTTON_HEIGHT = 0.12
LEFT_ARROW_X = 0.25
RIGHT_ARROW_X = 1 - LEFT_ARROW_X - ARROW_BUTTON_WIDTH
ARROW_Y = 0.88

TEXT_FONT_SIZE = 25
MARGIN = 8

class ExpandedHintModal(ContainerSprite):
    def __init__(self, pos_x, pos_y, width, height, texture_path, hints,
                 game_board, close_modal, id):
        ContainerSprite.__init__(self, pos_x, pos_y, width, height,
                                 texture_path, "Hints modal",
                                 game_board)
        self.hints = hints
        self.curr_page = 1
        self.pages = {}
        self.buttons_sprites = pygame.sprite.Group()
        self.create_buttons(close_modal)
        self.id = id

        self.parse_message()

    def draw(self):
        self.clean()

        # draw current page
        self.surface.blit(self.pages[self.curr_page], (0, 0))

        # draw buttons
        self.surface.blit(self.right_arrow.image,
                          (self.right_arrow.rect[0] - self.pos_x,
                           self.right_arrow.rect[1] - self.pos_y))
        self.surface.blit(self.left_arrow.image,
                          (self.left_arrow.rect[0] - self.pos_x,
                           self.left_arrow.rect[1] - self.pos_y))
        self.surface.blit(self.close_button.image,
                          (self.close_button.rect[0] - self.pos_x,
                           self.close_button.rect[1] - self.pos_y))

        # draw page number
        draw_text_with_wrapping_and_centering(
            self.left_arrow.pos_x + self.left_arrow.width - self.pos_x,
            ARROW_Y * self.height,
            self.right_arrow.pos_x - self.pos_x,
            "{}/{}".format(self.curr_page, self.last_page),
            self.surface, YELLOW)

        # blit surface
        self.blit_surface.blit(self.surface, self.rect)

    def create_page(self, surface, words, msg_split=False):
        remaining_words = draw_text_with_wrapping(
            MARGIN, BUTTON_HEIGHT * self.height + MARGIN, self.width - MARGIN,
            words, YELLOW, surface, TEXT_FONT_SIZE,
            max_pos_y=self.right_arrow.rect[1] - self.pos_y,
            msg_split=msg_split)[3]
        return remaining_words

    def parse_message(self):
        self.pages[self.curr_page] = pygame.Surface.copy(self.image)
        remaining_words = self.create_page(self.pages[self.curr_page],
                                           self.hints)

        while remaining_words:
            self.curr_page += 1
            self.pages[self.curr_page] = pygame.Surface.copy(self.image)
            remaining_words = self.create_page(self.pages[self.curr_page],
                                               remaining_words,
                                               True)

        self.last_page = self.curr_page
        self.curr_page = 1

    def create_buttons(self, close_modal):
        self.close_button = Button(
            self.pos_x + self.width - BUTTON_WIDTH * self.width, self.pos_y,
            BUTTON_WIDTH * self.width, BUTTON_HEIGHT * self.height,
            relative_textures_path + 'delete.png', close_modal,
            self.blit_surface, "Close")
        self.buttons_sprites.add(self.close_button)

        self.create_scrolling_arrows()

    def create_scrolling_arrows(self):
        self.right_arrow = Button(RIGHT_ARROW_X * self.width + self.pos_x,
                                  ARROW_Y * self.height + self.pos_y,
                                  ARROW_BUTTON_WIDTH * self.width,
                                  ARROW_BUTTON_HEIGHT * self.height,
                                  relative_textures_path + "RightArrow.png",
                                  self.scroll_modal_right,
                                  self,
                                  "Go to the next page")

        self.left_arrow = Button(self.pos_x + LEFT_ARROW_X * self.width,
                                 self.pos_y + ARROW_Y * self.height,
                                 ARROW_BUTTON_WIDTH * self.width,
                                 ARROW_BUTTON_HEIGHT * self.height,
                                 relative_textures_path + "LeftArrow.png",
                                 self.scroll_modal_left,
                                 self,
                                 "Go to the previous page")
        self.buttons_sprites.add(self.right_arrow, self.left_arrow)

    def scroll_modal_left(self):
        if self.curr_page > 1:
            self.curr_page -= 1

    def scroll_modal_right(self):
        if self.curr_page < self.last_page:
            self.curr_page += 1


from typing import Dict, NamedTuple, Tuple, Union
from enum import auto
from enum import Enum
import numpy as np  # type: ignore
import ethosu.vela.api as vapi  # type: ignore

import tvm
from tvm.tir import stmt_functor
from tvm.relay.backend.contrib.ethosu import util
from tvm.relay.backend.contrib.ethosu import vela_api
from tvm.relay.backend.contrib.ethosu.tir import spec

class BufferType(Enum):
    """The type of information that a buffer contains."""

    constant = auto()
    input_or_output = auto()
    scratch = auto()
    input = auto()
    output = auto()
    shram = auto()

_REGION_MAP = {
    BufferType.constant: 0,
    BufferType.scratch: 1,
    BufferType.input: 3,
    BufferType.output: 4,
    BufferType.shram: int((1 << 8) | (3 << 0)),
}

class BufferInfo(NamedTuple):
    """A data structure to hold metadata of the buffer."""

    # If the buffer holds constants, the values will contain that otherwise None
    values: np.ndarray
    shape: tvm.ir.container.Array
    dtype: np.dtype
    btype: BufferType

class AcceleratorArchConfig:
    def __init__(self, total_shram_banks):
        self.shram_bank_size = 1024
        self.total_shram_banks = total_shram_banks
        self.shram_size_bytes = self.shram_bank_size * self.total_shram_banks
        self.lut_size_bytes = 2048
        self.lut_start_address = self.shram_size_bytes - self.lut_size_bytes

def get_accelerator_arch_config(accel_type):
    accel_config_str_map = {
        "ethos-u55-256": AcceleratorArchConfig(48),
        "ethos-u55-128": AcceleratorArchConfig(24),
        "ethos-u55-64": AcceleratorArchConfig(16),
        "ethos-u55-32": AcceleratorArchConfig(16),
    }
    return accel_config_str_map[accel_type]

def translate(tir_module, params):
    """This will take an tir module for the NPU
    and compile to command stream

    Parameters
    ----------
    tir_module : tvm.IRModule
        The TIR module containing ethosu extern calls
    params : dict
        A dictionary containing TIR primfunc argument ordering
        idx to constant NDArray map
    accel_type : ethosu.vela.api.NpuAccelerator
        the accelerator variant the tir module needs to compiled to

    Returns
    -------
    cs : str
        An hex string of the bytes of command stream
    encoded_constants : str
        An hex string of the bytes that includes concat'd
        encoded weights, encoded biases and scales.
    scratch_size : int
        The size of the scratch buffer needed.
    """

    buffer_info = extract_buffer_info(tir_module, params)
    call_extern_list = extract_call_extern_list(tir_module)
    _npu_ops = list()
    for call_extern in call_extern_list:
        _npu_ops.append(translate_ethosu_tir_call_extern(call_extern))
    _npu_ops, constant_data, scratch_size = assign_addresses(buffer_info, _npu_ops)
    target_accel_config = vela_api.get_accelerator_config()
    cmds = vapi.npu_generate_register_command_stream(_npu_ops, target_accel_config)
    payload = vapi.npu_create_driver_payload(cmds, target_accel_config)
    return payload.hex(), constant_data, scratch_size

def extract_call_extern_list(mod):
    """This function will obtain all extern
    calls from a TIR module
    Parameters
    ----------
    mod : tvm.IRModule
        The TIR Module for NPU

    Returns
    -------
    list
        of tvm.tir.Call objects
        that are tir extern calls
    """
    # There should only be a single function
    assert len(mod.functions.items()) == 1
    primfunc = mod.functions.items()[0][1]

    call_extern_list = list()

    def populate_call_extern_list(stmt):
        if isinstance(stmt, tvm.tir.Call) and stmt.op.name == "tir.call_extern":
            call_extern_list.append(stmt)

    stmt_functor.post_order_visit(primfunc.body, populate_call_extern_list)
    return call_extern_list

def extract_buffer_info(
    mod: tvm.IRModule, param_dict: Dict[int, np.ndarray]
) -> Dict[str, BufferInfo]:
    """This function is to read the tvm.IRModule that
    contains Relay to TIR compiled IRModule. Thereafter,
    this will extract the buffer information as the shape
    and constant data (if any).

    Parameters
    ----------
    mod : tvm.IRModule
        The NPU TIR IRModule.
    param_dict : Dict[int, np.ndarray]
        A dictionary containing param idx --> const numpy.NDArray

    Returns
    -------
    dict : Dict[str, BufferInfo]
        A dictionary of buffer names --> BufferInfo

    """
    buffer_info = dict()
    # There should only be a single function
    assert len(mod.functions.items()) == 1
    primfunc = mod.functions.items()[0][1]
    for idx, const_data in param_dict.items():
        param = primfunc.params[idx]
        buffer_info[param] = BufferInfo(
            const_data, const_data.shape, const_data.dtype, BufferType.constant
        )

    for param in primfunc.params:
        if param not in buffer_info.keys():
            buffer_info[param] = BufferInfo(
                None,
                None,
                None,
                BufferType.input_or_output,
            )

    def populate_allocate_buffer_info(stmt):
        if isinstance(stmt, tvm.tir.stmt.Allocate):
            allocate = stmt
            if "placeholder" in allocate.buffer_var.name:
                storage_scope = allocate.buffer_var.name.split(".")[-1]
            else:
                storage_scope = "global"

            if storage_scope == "local":
                buffer_type = BufferType.shram
            else:
                buffer_type = BufferType.scratch
            buffer_info[allocate.buffer_var] = BufferInfo(
                None,
                allocate.extents,
                allocate.dtype,
                buffer_type,
            )

    tvm.tir.stmt_functor.post_order_visit(primfunc.body, populate_allocate_buffer_info)

    return buffer_info

def assign_addresses(buffer_info, npu_ops):
    """This function will assign addresses to tensors
    within two buffers : scratch and constants.
    The scratch is the buffer created to hold all intermediary data
    The constants is the buffer created via unifying all the constant data
    (post-encoding).
    Parameters
    ----------
    buffer_info : dict
        This is the dictionary obtained via calling extract_buffer_info.
        The key is the buffer name to BufferInfo
    npu_ops : list
        A list of Vela NpuOps with tir.Loads for addresses
    Returns
    -------
    npu_ops : list
        A list of Vela NpuOps with addesses within scratch and constant buffers
    constant_tensor : NDArray
        A unified constant data array of uint8 as the constant buffer
    scratch_size : int
        The size of the scratch tensor.
    """

    def replace_npu_fm_with_address(npu_fm):
        assert isinstance(npu_fm.tiles.addresses[0], tvm.tir.Load)
        # We currently does not support tiles
        # Change this when tiles are needed
        # (i.e. when using rolling buffers)
        assert npu_fm.tiles.addresses[1:] == [0, 0, 0]
        npu_fm.tiles.addresses[1:] = [0, 0, 0]
        buffer = npu_fm.tiles.addresses[0].buffer_var
        assert buffer in buffer_addresses.keys()
        address, buffer_type = buffer_addresses[buffer]
        index = npu_fm.tiles.addresses[0].index * (
            np.iinfo(np.dtype(npu_fm.tiles.addresses[0])).bits // 8
        )
        npu_fm.tiles.addresses[0] = address + int(index)
        npu_fm.region = _REGION_MAP[buffer_type]
        return npu_fm

    def replace_npu_address_range_with_address(npu_addr_range):
        assert isinstance(npu_addr_range.address, tvm.tir.Load)
        buffer = npu_addr_range.address.buffer_var
        assert buffer in buffer_addresses.keys(), f"searching for buffer : {buffer}, but not found"
        address, buffer_type = buffer_addresses[buffer]
        return vapi.NpuAddressRange(_REGION_MAP[buffer_type], address, npu_addr_range.length)

    def replace_tir_loads(npu_object):
        if isinstance(npu_object, vapi.NpuFeatureMap):
            return replace_npu_fm_with_address(npu_object)
        if isinstance(npu_object, vapi.NpuAddressRange):
            return replace_npu_address_range_with_address(npu_object)
        return npu_object

    def classify_io(buffer):
        for _npu_op in npu_ops:
            if issubclass(type(_npu_op), vapi.NpuBlockOperation):
                if _npu_op.ifm and _npu_op.ifm.tiles.addresses[0].buffer_var == buffer:
                    return BufferType.input
                if _npu_op.ifm2 and _npu_op.ifm2.tiles.addresses[0].buffer_var == buffer:
                    return BufferType.input
                if _npu_op.ofm and _npu_op.ofm.tiles.addresses[0].buffer_var == buffer:
                    return BufferType.output

        raise ValueError(f"Unused IO : {buffer} in tir module.")

    scratch_size = 0
    constant_hex_data = []
    total_constant_len = 0
    buffer_addresses = dict()
    for _buffer, info in buffer_info.items():
        if info.values is not None:
            assert info.btype == BufferType.constant
            assert len(info.shape) == 1
            buffer_addresses[_buffer] = (
                (total_constant_len, info.btype) if constant_hex_data else (0, info.btype)
            )
            dtype_bytes = np.iinfo(np.dtype(info.dtype)).bits // 8
            size_in_bytes = dtype_bytes * np.prod(list(info.shape))
            # Every memory address the NPU access have to be 16 byte aligned
            size_in_bytes = util.round_up(size_in_bytes, 16)
            constant_tensor = np.resize(info.values, size_in_bytes // dtype_bytes)
            constant_tensor = constant_tensor.tobytes().hex()
            constant_hex_data.append(constant_tensor)
            total_constant_len += len(constant_tensor) // 2
        else:
            if info.btype == BufferType.input_or_output:
                buffer_type = classify_io(_buffer)
                assert buffer_type in (BufferType.input, BufferType.output)
                address = 0
                buffer_addresses[_buffer] = (address, buffer_type)
            elif info.btype == BufferType.shram:
                accl_config = util.get_accelerator_config()
                arch_config = get_accelerator_arch_config(accl_config)
                address = arch_config.lut_start_address
                buffer_addresses[_buffer] = (address, info.btype)
            else:
                dtype_bytes = np.iinfo(np.dtype(info.dtype)).bits // 8
                size_in_bytes = int(dtype_bytes * np.prod(list(info.shape)))
                # Every memory address the NPU access have to be 16 byte aligned
                size_in_bytes = util.round_up(size_in_bytes, 16)
                assert info.btype == BufferType.scratch
                address = scratch_size
                scratch_size += size_in_bytes
                buffer_addresses[_buffer] = (address, info.btype)

    for npu_op in npu_ops:
        for attr_name, attr in npu_op.__dict__.items():
            if isinstance(attr, list):
                new_attr = list()
                for attr_ in attr:
                    new_attr.append(replace_tir_loads(attr_))
                setattr(npu_op, attr_name, new_attr)
            else:
                setattr(npu_op, attr_name, replace_tir_loads(attr))

    constant_data = "".join(constant_hex_data)
    return (
        npu_ops,
        constant_data,
        scratch_size,
    )

def translate_ethosu_tir_call_extern(tir_call_extern):
    """This is a dispatcher function to dispatch
    correct translation call depending on the extern call's
    first argument"""
    supported_call_extern = {
        "ethosu_conv2d": translate_ethosu_conv2d,
        "ethosu_copy": translate_ethosu_copy,
        "ethosu_depthwise_conv2d": translate_ethosu_depthwise_conv2d,
        "ethosu_pooling": translate_ethosu_pooling,
        "ethosu_binary_elementwise": translate_ethosu_binary_elementwise,
        "ethosu_identity": translate_ethosu_pooling,
        "ethosu_unary_elementwise": translate_ethosu_unary_elementwise,
    }
    ext_call_type = tir_call_extern.args[0].value
    assert ext_call_type in supported_call_extern.keys(), f"{ext_call_type} is not yet supported"
    npu_op = supported_call_extern[ext_call_type](tir_call_extern)
    # Some conversions return additional outputs
    # if they are needed, the caller should use the function directly
    if isinstance(npu_op, tuple):
        return npu_op[0]
    return npu_op

def translate_ethosu_copy(tir_call_extern: tvm.tir.Call) -> vapi.NpuDmaOperation:
    """This function will translate a TIR call_extern
    as produced by NPU Relay to TIR compilation.

    Parameters
    ----------
    tir_call_extern : tvm.tir.Call

    Returns
    -------
    ethosu.vela.api.NpuDmaOperation
        The vela object containing the params of ethosu_copy
    """
    # We skip the first element as it is the call_extern function name
    serial_object = spec.create_serial_object(spec.SerialCopy, tir_call_extern.args[1:])
    return _create_npu_dma_op(serial_object)

def _convert_clip_bounds(npu_op: vapi.NpuBlockOperation):
    """This function will convert the min and max value
    of clip activations to non quantized floats as
    expected by the API.

    Parameters
    ----------
    npu_op : vapi.NpuBlockOperation

    """
    clip_min_quant = npu_op.activation.min
    clip_max_quant = npu_op.activation.max
    clip_min_actual = (
        clip_min_quant - npu_op.ofm.quantization.zero_point
    ) * npu_op.ofm.quantization.scale_f32
    clip_max_actual = (
        clip_max_quant - npu_op.ofm.quantization.zero_point
    ) * npu_op.ofm.quantization.scale_f32
    npu_op.activation.min = clip_min_actual
    npu_op.activation.max = clip_max_actual

def translate_ethosu_conv2d(tir_call_extern: tvm.tir.Call) -> Tuple[vapi.NpuConv2DOperation, int]:
    """This function will translate a TIR call_extern
    as produced by NPU Relay to TIR compilation.

    Parameters
    ----------
    tir_call_extern : tvm.tir.Call
        This should be a TIR call_extern that has agreed upon ordering
        for TIR Compiler. See Serial2DConvolution in
        tvm/relay/backend/contrib/ethosu/tir/spec.py for the ordering.

    Returns
    -------
    ethosu.vela.api.NpuConv2DOperation
        The vela object containing the params of ethosu_conv2d
    weights_zero_point : int
        The zero point of the weights
    """
    # We skip the first element as it is the call_extern function name
    serial_object = spec.create_serial_object(spec.Serial2DConvolution, tir_call_extern.args[1:])
    return _create_npu_op_conv2d(serial_object)

def _create_npu_op_conv2d(
    serial_2d_convolution: spec.Serial2DConvolution,
) -> Tuple[vapi.NpuConv2DOperation, int]:
    """This is a helper function to capture a list
    of arguments to create Vela NpuConv2DOperation object.
    """
    npu_conv2d_op = vapi.NpuConv2DOperation()
    npu_conv2d_op.ifm = _create_npu_feature_map(serial_2d_convolution.ifm)
    npu_conv2d_op.ofm = _create_npu_feature_map(serial_2d_convolution.ofm)
    npu_conv2d_op.kernel = _create_npu_kernel(serial_2d_convolution.kernel)
    npu_conv2d_op.weights = [_create_npu_address_range(serial_2d_convolution.weight)]
    weights_zero_point = np.int64(serial_2d_convolution.weight_zero_point.value)
    npu_conv2d_op.biases = [_create_npu_address_range(serial_2d_convolution.scale_bias)]
    npu_conv2d_op.padding = _create_npu_padding(serial_2d_convolution.padding)

    npu_conv2d_op.activation = _create_npu_activation(serial_2d_convolution.activation)
    if (
        npu_conv2d_op.activation
        and npu_conv2d_op.activation.op_type == vapi.NpuActivationOp.NONE_OR_RELU
    ):
        _convert_clip_bounds(npu_conv2d_op)

    npu_conv2d_op.rounding_mode = _create_npu_rounding_mode(serial_2d_convolution.rounding_mode)
    npu_conv2d_op.upscale = _create_npu_resampling_mode(serial_2d_convolution.upscale)
    accel_config = vela_api.get_accelerator_config()
    weights_shape_ohwi = [
        npu_conv2d_op.ofm.shape.depth,
        npu_conv2d_op.kernel.height,
        npu_conv2d_op.kernel.width,
        npu_conv2d_op.ifm.shape.depth,
    ]
    npu_conv2d_op.block_traversal = vela_api.calculate_block_traversal_mode(
        is_depthwise=False,
        weights_shape_ohwi=weights_shape_ohwi,
        ifm_bitdepth=npu_conv2d_op.ifm.data_type.size_in_bits(),
    )
    block_config = vela_api.get_optimal_block_config(npu_conv2d_op, accel_config)
    npu_conv2d_op.block_config = block_config
    return npu_conv2d_op, weights_zero_point

def translate_ethosu_depthwise_conv2d(
    tir_call_extern: tvm.tir.Call,
) -> Tuple[vapi.NpuConvDepthWiseOperation, int]:
    """This function will translate a TIR call_extern
    as produced by NPU Relay to TIR compilation.

    Parameters
    ----------
    tir_call_extern : tvm.tir.Call
        This should be a TIR call_extern that has agreed upon ordering
        for TIR Compiler. See Serial2DDepthwise in
        tvm/relay/backend/contrib/ethosu/tir/spec.py for the ordering.

    Returns
    -------
    ethosu.vela.api.NpuConvDepthWiseOperation
        The vela object containing the params of ethosu_depthwise_conv2d
    weights_zero_point : int
        The zero point of the weights
    """
    serial_object = spec.create_serial_object(spec.Serial2DDepthwise, tir_call_extern.args[1:])
    return _create_npu_op_depthwise_conv2d(serial_object)

def _create_npu_op_depthwise_conv2d(serial_2d_depthwise):
    npu_depthwise_conv2d_op = vapi.NpuConvDepthWiseOperation()

    npu_depthwise_conv2d_op.ifm = _create_npu_feature_map(serial_2d_depthwise.ifm)
    npu_depthwise_conv2d_op.ofm = _create_npu_feature_map(serial_2d_depthwise.ofm)
    npu_depthwise_conv2d_op.kernel = _create_npu_kernel(serial_2d_depthwise.kernel)
    npu_depthwise_conv2d_op.weights = [_create_npu_address_range(serial_2d_depthwise.weight)]
    weights_zero_point = np.int64(serial_2d_depthwise.weight_zero_point.value)
    npu_depthwise_conv2d_op.biases = [_create_npu_address_range(serial_2d_depthwise.scale_bias)]
    npu_depthwise_conv2d_op.padding = _create_npu_padding(serial_2d_depthwise.padding)

    npu_depthwise_conv2d_op.activation = _create_npu_activation(serial_2d_depthwise.activation)
    if (
        npu_depthwise_conv2d_op.activation
        and npu_depthwise_conv2d_op.activation.op_type == vapi.NpuActivationOp.NONE_OR_RELU
    ):
        _convert_clip_bounds(npu_depthwise_conv2d_op)

    npu_depthwise_conv2d_op.rounding_mode = _create_npu_rounding_mode(
        serial_2d_depthwise.rounding_mode
    )
    npu_depthwise_conv2d_op.upscale = _create_npu_resampling_mode(serial_2d_depthwise.upscale)
    target_accel_config = vela_api.get_accelerator_config()
    block_config = vela_api.get_optimal_block_config(npu_depthwise_conv2d_op, target_accel_config)
    npu_depthwise_conv2d_op.block_config = block_config

    return npu_depthwise_conv2d_op, weights_zero_point

def _create_npu_feature_map(serial_feature_map: spec.SerialFeatureMap) -> vapi.NpuFeatureMap:
    """This is a helper function to capture a list
    of arguments to create Vela NpuFeatureMap object.
    """
    layout_map = {"NHWC": vapi.NpuLayout.NHWC, "NHCWB16": vapi.NpuLayout.NHCWB16}
    datatype_map = {
        "uint8": vapi.NpuDataType.UINT8,
        "int8": vapi.NpuDataType.INT8,
        "uint16": vapi.NpuDataType.UINT16,
        "int16": vapi.NpuDataType.INT16,
        "int32": vapi.NpuDataType.INT32,
    }
    layout = str(serial_feature_map.layout.value)
    data_type = str(serial_feature_map.data_type.value)
    date_type_bytes = np.iinfo(np.dtype(data_type)).bits // 8
    assert layout in layout_map.keys()
    assert data_type in datatype_map.keys()
    nfm = vapi.NpuFeatureMap()
    nfm.data_type = datatype_map[data_type]
    nfm.shape = vapi.NpuShape3D(
        int(serial_feature_map.height),
        int(serial_feature_map.width),
        int(serial_feature_map.channels),
    )
    nfm.tiles = vapi.NpuTileBox(
        int(serial_feature_map.tile_height_0),
        int(serial_feature_map.tile_height_1),
        int(serial_feature_map.tile_width_0),
        [
            serial_feature_map.tile_address_0,
            serial_feature_map.tile_address_1,
            serial_feature_map.tile_address_2,
            serial_feature_map.tile_address_3,
        ],
    )
    nfm.quantization = _create_npu_quantization(
        serial_feature_map.scale, serial_feature_map.zero_point
    )
    nfm.layout = layout_map[layout]
    nfm.strides = vapi.NpuShape3D(
        int(serial_feature_map.stride_h.value) * date_type_bytes,
        int(serial_feature_map.stride_w.value) * date_type_bytes,
        int(serial_feature_map.stride_c.value) * date_type_bytes,
    )
    return nfm

def _create_npu_kernel(serial_kernel: spec.SerialKernel) -> vapi.NpuKernel:
    """This is a helper function to capture a list
    of arguments to create Vela NpuKernel object.
    """
    nknl = vapi.NpuKernel(
        w=int(serial_kernel.width),
        h=int(serial_kernel.height),
        stride_x=int(serial_kernel.stride_w),
        stride_y=int(serial_kernel.stride_h),
        dilation_x=int(serial_kernel.dilation_w),
        dilation_y=int(serial_kernel.dilation_h),
    )
    return nknl

def _create_npu_address_range(
    serial_address_range: spec.SerialAddressRange,
) -> vapi.NpuAddressRange:
    """This is a helper function to capture a list
    of arguments to create Vela NpuAddressRange object.
    """
    addr_range = vapi.NpuAddressRange(
        # region will be updated later
        region=0,
        address=serial_address_range.address,
        length=int(serial_address_range.length),
    )
    return addr_range

def _create_npu_quantization(
    scale: Union[tvm.tir.FloatImm, float],
    zero_point: Union[tvm.tir.IntImm, int],
) -> vapi.NpuQuantization:
    """This is a helper function to capture a list
    of arguments to create Vela NpuQuantization object.
    """
    return vapi.NpuQuantization(scale_f32=float(scale), zero_point=int(zero_point))

def _create_npu_weights_zero_point(
    zero_point: Union[int, tvm.tir.IntImm],
) -> int:
    """This is a helper function to capture the weights zero point."""
    return int(zero_point)

def _create_npu_padding(serial_padding: spec.SerialPadding) -> vapi.NpuPadding:
    """This is a helper function to capture a list
    of arguments to create Vela NpuPadding object."""
    padding = vapi.NpuPadding(
        top=int(serial_padding.top),
        left=int(serial_padding.left),
        bottom=int(serial_padding.bottom),
        right=int(serial_padding.right),
    )
    return padding

def _create_npu_activation(serial_activation: spec.SerialActivation) -> vapi.NpuActivation:
    """This is a helper function to capture a list
    of arguments to create Vela NpuActivation object."""
    if serial_activation.op == "NONE":
        return None
    if (
        serial_activation.op == "CLIP"
        and serial_activation.clip_min == 0
        and serial_activation.clip_max == 0
    ):
        return None
    op_map = {
        "CLIP": vapi.NpuActivationOp.NONE_OR_RELU,
        "TANH": vapi.NpuActivationOp.TABLE_LOOKUP,
        "SIGMOID": vapi.NpuActivationOp.TABLE_LOOKUP,
        "LUT": vapi.NpuActivationOp.TABLE_LOOKUP,
    }
    op = str(serial_activation.op.value)
    assert op in op_map.keys()
    act_op = vapi.NpuActivation(op_map[op])
    if serial_activation.op == "CLIP":
        act_op.min = int(serial_activation.clip_min.value)
        act_op.max = int(serial_activation.clip_max.value)
    if op_map[op] == vapi.NpuActivationOp.TABLE_LOOKUP:
        act_op.lookup_table_index = 0
    return act_op

def _create_npu_resampling_mode(
    mode: str,
) -> vapi.NpuResamplingMode:
    """This is a helper function to capture a list
    of arguments to create Vela NpuResamplingMode object."""
    mode_map = {
        "NONE": vapi.NpuResamplingMode.NONE,
        "NEAREST": vapi.NpuResamplingMode.NEAREST,
        "TRANSPOSE": vapi.NpuResamplingMode.TRANSPOSE,
    }
    mode = str(mode.value)
    assert mode in mode_map.keys()
    return mode_map[mode]

def _create_npu_rounding_mode(
    mode: str,
) -> vapi.NpuRoundingMode:
    """This is a helper function to capture a list
    of arguments to create Vela NpuRoundingMode object."""
    mode_map = {
        "TFL": vapi.NpuRoundingMode.TFL,
        "TRUNCATE": vapi.NpuRoundingMode.TRUNCATE,
        "NATURAL": vapi.NpuRoundingMode.NATURAL,
    }
    mode = str(mode.value)
    assert mode in mode_map.keys()
    return mode_map[mode]

def _create_npu_dma_op(serial_copy):
    """This is a helper function to capture the list of arguments
    to create a NpuDmaOperation object"""
    src = vapi.NpuAddressRange(
        # region will be updated later
        region=0,
        address=serial_copy.read_address,
        length=int(serial_copy.length.value),
    )
    dest = vapi.NpuAddressRange(
        # region will be updated later
        region=0,
        address=serial_copy.write_address,
        length=int(serial_copy.length.value),
    )
    return vapi.NpuDmaOperation(src, dest)

def translate_ethosu_pooling(tir_call_extern: tvm.tir.Call) -> vapi.NpuPoolingOperation:
    """This function will translate a TIR call_extern
    as produced by NPU Relay to TIR compilation.

    Parameters
    ----------
    tir_call_extern : tvm.tir.Call
        This should be a TIR call_extern that has agreed upon ordering
        for TIR Compiler. See SerialPooling in
        tvm/relay/backend/contrib/ethosu/tir/spec.py for the ordering.

    Returns
    -------
    ethosu.vela.api.NpuPoolingOperation
        The vela object containing the params of ethosu_pooling
    """
    serial_object = spec.create_serial_object(spec.SerialPooling, tir_call_extern.args[1:])
    return _create_npu_op_pooling(serial_object)

def _create_npu_op_pooling(serial_pooling: spec.SerialPooling):
    pooling_type = serial_pooling.pooling_type
    if pooling_type == "AVG":
        npu_pooling_op = vapi.NpuPoolingOp.AVERAGE
    elif pooling_type == "MAX":
        npu_pooling_op = vapi.NpuPoolingOp.MAX

    npu_pooling_op = vapi.NpuPoolingOperation(npu_pooling_op)
    npu_pooling_op.ifm = _create_npu_feature_map(serial_pooling.ifm)
    npu_pooling_op.ofm = _create_npu_feature_map(serial_pooling.ofm)
    npu_pooling_op.kernel = _create_npu_kernel(serial_pooling.pool_shape)
    npu_pooling_op.padding = _create_npu_padding(serial_pooling.padding)

    npu_pooling_op.activation = _create_npu_activation(serial_pooling.activation)
    if (
        npu_pooling_op.activation
        and npu_pooling_op.activation.op_type == vapi.NpuActivationOp.NONE_OR_RELU
    ):
        _convert_clip_bounds(npu_pooling_op)

    npu_pooling_op.rounding_mode = _create_npu_rounding_mode(serial_pooling.rounding_mode)
    npu_pooling_op.upscale = _create_npu_resampling_mode(serial_pooling.upscale)

    target_accel_config = vela_api.get_accelerator_config()
    block_config = vela_api.get_optimal_block_config(npu_pooling_op, target_accel_config)
    npu_pooling_op.block_config = block_config

    return npu_pooling_op

def translate_ethosu_binary_elementwise(
    tir_call_extern: tvm.tir.Call,
) -> vapi.NpuElementWiseOperation:
    """This function will translate a TIR call_extern
    as produced by NPU Relay to TIR compilation.

    Parameters
    ----------
    tir_call_extern : tvm.tir.Call
        This should be a TIR call_extern that has agreed upon ordering
        for TIR Compiler. See SerialBinaryElementwise in
        tvm/relay/backend/contrib/ethosu/tir/spec.py for the ordering.

    Returns
    -------
    ethosu.vela.api.NpuElementWiseOperation
        The vela object containing the params of ethosu_binary_elementwise
    """
    serial_object = spec.create_serial_object(
        spec.SerialBinaryElementwise, tir_call_extern.args[1:]
    )
    return _create_npu_op_binary_elementwise(serial_object)

def _create_npu_op_binary_elementwise(serial_binary_elementwise: spec.SerialBinaryElementwise):
    operator_type = serial_binary_elementwise.operator_type
    if operator_type == "ADD":
        op = vapi.NpuElementWiseOp.ADD
    elif operator_type == "SUB":
        op = vapi.NpuElementWiseOp.SUB
    elif operator_type == "MUL":
        op = vapi.NpuElementWiseOp.MUL
    elif operator_type == "MIN":
        op = vapi.NpuElementWiseOp.MIN
    elif operator_type == "MAX":
        op = vapi.NpuElementWiseOp.MAX
    elif operator_type == "SHR":
        op = vapi.NpuElementWiseOp.SHR
    elif operator_type == "SHL":
        op = vapi.NpuElementWiseOp.SHL

    npu_binary_elementwise_op = vapi.NpuElementWiseOperation(op)
    npu_binary_elementwise_op.ifm = _create_npu_feature_map(serial_binary_elementwise.ifm)
    npu_binary_elementwise_op.ifm2 = _create_npu_feature_map(serial_binary_elementwise.ifm2)
    npu_binary_elementwise_op.ofm = _create_npu_feature_map(serial_binary_elementwise.ofm)
    npu_binary_elementwise_op.reversed_operands = serial_binary_elementwise.reversed_operands

    npu_binary_elementwise_op.activation = _create_npu_activation(
        serial_binary_elementwise.activation
    )
    if (
        npu_binary_elementwise_op.activation
        and npu_binary_elementwise_op.activation.op_type == vapi.NpuActivationOp.NONE_OR_RELU
    ):
        _convert_clip_bounds(npu_binary_elementwise_op)

    npu_binary_elementwise_op.rounding_mode = _create_npu_rounding_mode(
        serial_binary_elementwise.rounding_mode
    )

    target_accel_config = vela_api.get_accelerator_config()
    block_config = vela_api.get_optimal_block_config(npu_binary_elementwise_op, target_accel_config)
    npu_binary_elementwise_op.block_config = block_config

    return npu_binary_elementwise_op

def translate_ethosu_unary_elementwise(
    tir_extern_call: tvm.tir.Call,
) -> vapi.NpuElementWiseOperation:

    """This function will translate a tir extern_call
    as produced by Relay to TIR compilation.
    Parameters
    ----------
    tir_extern_call : tvm.tir.Call
        This should be a tir external call that has a agreed upon ordering
        for the NPU TIR Compiler. See SerialUnaryElementwise in
        tvm/relay/backend/contrib/ethosu/tir/spec.py for the ordering.

    Returns
    -------
    ethosu.vela.api.NpuElementWiseOperation
        The vela object containing the params of ethosu_unary_elementwise
    """
    serial_object = spec.create_serial_object(spec.SerialUnaryElementwise, tir_extern_call.args[1:])
    return _create_npu_op_unary_elementwise(serial_object)

def _create_npu_op_unary_elementwise(serial_unary_elementwise):
    operator_type = serial_unary_elementwise.operator_type
    if operator_type == "ABS":
        op = vapi.NpuElementWiseOp.ABS
    if operator_type == "CLZ":
        op = vapi.NpuElementWiseOp.CLZ

    npu_unary_elementwise_op = vapi.NpuElementWiseOperation(op)
    npu_unary_elementwise_op.ifm = _create_npu_feature_map(serial_unary_elementwise.ifm)
    npu_unary_elementwise_op.ofm = _create_npu_feature_map(serial_unary_elementwise.ofm)

    npu_unary_elementwise_op.activation = _create_npu_activation(
        serial_unary_elementwise.activation
    )
    if (
        npu_unary_elementwise_op.activation
        and npu_unary_elementwise_op.activation.op_type == vapi.NpuActivationOp.NONE_OR_RELU
    ):
        _convert_clip_bounds(npu_unary_elementwise_op)

    npu_unary_elementwise_op.rounding_mode = _create_npu_rounding_mode(
        serial_unary_elementwise.rounding_mode
    )
    target_accel_type = vela_api.get_accelerator_config()
    block_config = vela_api.get_optimal_block_config(npu_unary_elementwise_op, target_accel_type)
    npu_unary_elementwise_op.block_config = block_config

    return npu_unary_elementwise_op


# ------------------------------------------------------------------------------

# Example SABIO-RK script 10 - returns entry data in SBML format

# ------------------------------------------------------------------------------

import requests

# specify SBML as output format
SBML_URL='http://sabiork.h-its.org/sabioRestWebServices/searchKineticLaws/sbml'

# input: search fields and search terms eg
query_dict = {"Organism":'"Haemophilus influenzae"',"ECNumber":"2.7.7.1"}
query_string = ' AND '.join(['%s:%s' % (k,v) for k,v in query_dict.items()])
query = {'q':query_string}

request = requests.post(SBML_URL, params = query)
request.raise_for_status()

# results

print(request.text)