#!/usr/bin/env python3

import numpy as np
import networkx as nx
import logging
import collections
import os
import math

try:
	from PySide2 import QtGui, QtCore
except ImportError:
	from PySide6 import QtGui, QtCore

from functools import lru_cache

from origami.core.predict import PredictorType
from origami.core.neighbors import neighbors
from origami.core.math import partition_path

class Pens:
	def __init__(self, keys, width=10):
		self._pens = dict()

		for i, k in enumerate(keys):
			color = QtGui.QColor.fromHsv(
				20 + 230 * (i / (1 + len(keys))), 200, 250)
			pen = QtGui.QPen()
			pen.setWidth(width)
			pen.setColor(color)
			pen.setCapStyle(QtCore.Qt.RoundCap)
			self._pens[k] = pen

	def get(self, key):
		return self._pens[key]

def get_region_classes(predictors):
	classes = []
	for p in predictors:
		if p.type == PredictorType.REGION.name:
			for c in p.classes:
				if c != "BACKGROUND":
					classes.append((p.name, c))
	return sorted(classes)

def render_separators(pixmap, separators):
	pens = Pens(sorted(p[:2] for p in separators.keys()))

	qp = QtGui.QPainter()
	qp.begin(pixmap)

	try:
		qp.setOpacity(0.75)

		for line_path, separator in separators.items():
			qp.setPen(pens.get(line_path[:2]))

			if separator.geom_type != "LineString":
				logging.error(
					"encountered %s while rendering separator %s" % (
						separator.geom_type, line_path))
				continue

			pts = [QtCore.QPointF(x, y) for x, y in separator.coords]
			qp.drawPolyline(pts)

	finally:
		qp.end()

	return pixmap

def block_hsv(classes):
	for i, c in enumerate(classes):
		yield tuple(c), (255 * (i / (1 + len(classes))), 100, 200)

class LabelBrushes:
	def __init__(self, predictors):
		self._classes = get_region_classes(predictors)

	@lru_cache(maxsize=32)
	def brushes(self, hue=0, saturation=0, value=0, style=QtCore.Qt.SolidPattern):
		brushes = dict()
		for c, (h, s, v) in block_hsv(self._classes):
			brushes[c] = QtGui.QBrush(
				QtGui.QColor.fromHsv(
					(h + hue) % 256, s + saturation, v + value),
				style)
		return brushes

	def get_brush(self, block_path, **kwargs):
		classifier, label, block_id = block_path
		return self.brushes(**kwargs)[(classifier, label)]

def default_pen(color="black", width=5):
	pen = QtGui.QPen()
	pen.setWidth(width)
	pen.setColor(QtGui.QColor(color))
	pen.setCapStyle(QtCore.Qt.RoundCap)
	return pen

def render_blocks(pixmap, blocks, *args, **kwargs):
	contours = dict((k, b.image_space_polygon) for (k, b) in blocks.items())
	return render_contours(pixmap, contours, *args, **kwargs)

_patterns = (
	QtCore.Qt.SolidPattern,
	QtCore.Qt.Dense1Pattern,
	QtCore.Qt.Dense2Pattern,
	QtCore.Qt.Dense3Pattern,
	QtCore.Qt.Dense4Pattern,
	QtCore.Qt.Dense5Pattern
)

def contour_patterns(contours, buffer=-5, threshold=10):
	buffered_contours = dict(
		(k, v.buffer(buffer)) for k, v in contours.items())
	buffered_contours = dict([
		(k, c.convex_hull if c.geom_type != "Polygon" else c)
		for k, c in buffered_contours.items()])
	neighbors_ = neighbors(buffered_contours)
	apart = set()
	for a, b in neighbors_.edges():
		if buffered_contours[a].distance(buffered_contours[b]) > threshold:
			apart.add((a, b))
	for a, b in apart:
		neighbors_.remove_edge(a, b)
	return nx.algorithms.coloring.equitable_color(
		neighbors_, 1 + max(d for _, d in neighbors_.degree()))

def render_contours(
	pixmap, contours, predictors,
	brushes=None, transform=None, scale=1, font_scale=1,
	get_label=None, alternate=False, edges=None):

	if not contours:
		return pixmap

	if brushes is None:
		brushes = LabelBrushes(predictors)

	def points(pts):
		pts = np.array(pts)
		if transform is not None:
			pts = transform(pts)
		return [QtCore.QPointF(*pt) for pt in (pts * scale)]

	if alternate:
		patterns = contour_patterns(contours)
	else:
		patterns = None

	qp = QtGui.QPainter()
	qp.begin(pixmap)

	try:
		qp.setOpacity(0.5)

		label_path = collections.defaultdict(list)
		for i, (block_path, contour) in enumerate(contours.items()):
			path, label = get_label(block_path)
			if label is not None:
				label_path[path[:2]].append((label, block_path))

		sorted_contours = dict()
		for k in label_path.keys():
			sorted_contours[k] = [(x[1], contours[x[1]]) for x in sorted(
				label_path[k], key=lambda x: x[0])]

		def render_contour(coords):
			qp.drawPolygon(points(coords))

		for k in sorted_contours.keys():
			for i, (block_path, contour) in enumerate(sorted_contours[k]):
				if contour.is_empty:
					continue

				if contour.geom_type not in ("Polygon", "MultiPolygon"):
					logging.error(
						"encountered %s while rendering contour %s" % (
							contour.geom_type, block_path))
					continue

				if patterns:
					style = _patterns[patterns[block_path] % len(_patterns)]
				else:
					style = QtCore.Qt.SolidPattern

				qp.setBrush(brushes.get_brush(
					block_path, style=style))

				if contour.geom_type == "Polygon":
					render_contour(contour.exterior.coords)
				elif contour.geom_type == "MultiPolygon":
					for geom in contour.geoms:
						render_contour(geom.exterior.coords)
				else:
					raise ValueError(contour.geom_type)

		qp.setBrush(QtGui.QBrush(QtGui.QColor("white")))

		font = QtGui.QFont("Arial Narrow", 56 * scale * font_scale, QtGui.QFont.Bold)
		qp.setFont(font)

		fm = QtGui.QFontMetrics(font)

		qp.setPen(default_pen(width=5 * scale * font_scale))
		nodes = dict()
		node_r = 50 * scale * font_scale

		for block_path, contour in contours.items():
			if contour.is_empty:
				continue

			p = points([contour.centroid.coords[0]])[0]

			path, label = get_label(block_path)
			qp.setBrush(brushes.get_brush(block_path, value=50))

			qp.setOpacity(0.8)
			qp.drawEllipse(p, node_r, node_r)
			if edges:
				nodes[block_path] = p

			qp.setOpacity(1)
			# flags=QtCore.Qt.AlignHCenter | QtCore.Qt.AlignVCenter does
			# not work. fix it manually.
			label_str = label if isinstance(label, str) else str(label)
			w = fm.horizontalAdvance(label_str)
			qp.drawText(p.x() - w / 2, p.y() + fm.descent(), label_str)

		if edges:
			qp.setOpacity(0.8)
			qp.setPen(default_pen(width=10 * scale))

			for p, q in edges:
				coords = [nodes[p], nodes[q]]
				qp.drawPolyline(coords)

	finally:
		qp.end()

	return pixmap

def render_arrows(qp, path, pos="center", scale=1):
	theta = 45
	d = 25 * scale
	for (x1, y1), (x2, y2) in zip(path, path[1:]):
		dx = x2 - x1
		dy = y2 - y1
		phi = math.atan2(dy, dx)
		phi1 = phi + (90 + theta) * (math.pi / 180)
		phi2 = phi - (90 + theta) * (math.pi / 180)
		if pos == "begin":
			ax, ay = x1, x2
		elif pos == "end":
			ax, ay = x2, y2
		elif pos == "center":
			ax = (x1 + x2) / 2
			ay = (y1 + y2) / 2
		else:
			raise ValueError(pos)
		qp.drawPolyline([
			QtCore.QPointF(ax + d * math.cos(phi1), ay + d * math.sin(phi1)),
			QtCore.QPointF(ax, ay),
			QtCore.QPointF(ax + d * math.cos(phi2), ay + d * math.sin(phi2))
	])

def render_lines(
	pixmap, lines, predictors, scale=1, font_scale=1,
	get_label=None, show_vectors=False):

	if not lines:
		return pixmap

	brushes = LabelBrushes(predictors)

	qp = QtGui.QPainter()
	qp.begin(pixmap)

	try:
		black_pen = default_pen(width=5 * scale)
		red_pen = default_pen("#FFA500", width=7 * scale)

		for i, (line_path, line) in enumerate(lines.items()):
			geom_type = line.image_space_polygon.geom_type
			if geom_type != "Polygon":
				logging.error("encountered %s as line geometry" % geom_type)
				continue

			qp.setBrush(brushes.get_brush(line_path[:3], value=(i % 2) * 50))
			qp.setPen(black_pen)

			qp.setOpacity(0.5)
			poly = QtGui.QPolygonF()
			coords = np.array(line.image_space_polygon.exterior.coords) * scale
			for x, y in coords:
				poly.append(QtCore.QPointF(x, y))
			qp.drawPolygon(poly)

			if show_vectors:
				p1, p2 = line.baseline
				p1 = np.array(p1) * scale
				p2 = np.array(p2) * scale

				line_info = line.info
				tess_data = line_info["tesseract_data"]

				up = np.array(line_info["up"])
				lh = abs(tess_data["height"]) - abs(tess_data["ascent"])
				up = up * (scale * lh / np.linalg.norm(up))

				qp.setOpacity(0.9)
				qp.setPen(red_pen)
				qp.drawPolyline([QtCore.QPointF(*p1), QtCore.QPointF(*p2)])

				m = (np.array(p1) + np.array(p2)) / 2
				qp.drawPolyline([QtCore.QPointF(*m), QtCore.QPointF(*(m + up))])
				render_arrows(qp, [m, m + up], "end", scale=scale)

		if get_label:
			font = QtGui.QFont("Arial Narrow", 24 * scale * font_scale, QtGui.QFont.Bold)
			qp.setFont(font)
			fm = QtGui.QFontMetrics(font)

			qp.setPen(default_pen(width=5 * scale * font_scale))
			node_r = 25 * scale * font_scale

			for i, (line_path, line) in enumerate(lines.items()):
				x, y = line.image_space_polygon.centroid.coords[0]
				p = QtCore.QPointF(x * scale, y * scale)

				path, label = get_label(line_path)
				qp.setBrush(brushes.get_brush(line_path[:3], value=50))

				qp.setOpacity(0.8)
				qp.drawEllipse(p, node_r, node_r)

				qp.setOpacity(1)
				# flags=QtCore.Qt.AlignHCenter | QtCore.Qt.AlignVCenter does
				# not work. fix it manually.
				label_str = label if isinstance(label, str) else str(label)
				w = fm.horizontalAdvance(label_str)
				qp.drawText(p.x() - w / 2, p.y() + fm.descent(), label_str)

	finally:
		qp.end()

	return pixmap

def render_warped_line_paths(pixmap, lines, predictors, resolution=0.1, opacity=0.9):
	classes = get_region_classes(predictors)
	pens = Pens(classes)

	qp = QtGui.QPainter()
	qp.begin(pixmap)

	try:
		qp.setOpacity(opacity)

		for i, (line_path, line) in enumerate(lines.items()):
			#if line.confidence < 0.5:
			#	continue  # ignore

			classifier, label, block_id, line_id = line_path

			path, height = line.warped_path(resolution)
			pen = pens.get((classifier, label))
			pen.setWidth(int(height / 3))
			qp.setPen(pen)

			poly = QtGui.QPolygonF()
			for x, y in path:
				poly.append(QtCore.QPointF(x, y))
			qp.drawPolyline(poly)

	finally:
		qp.end()

	return pixmap

def render_warped_line_confidence(pixmap, lines):
	qp = QtGui.QPainter()
	qp.begin(pixmap)

	try:
		font = QtGui.QFont("Arial Narrow", 48, QtGui.QFont.Bold)
		qp.setFont(font)
		fm = QtGui.QFontMetrics(font)

		for i, (line_path, line) in enumerate(lines.items()):
			#if line.confidence < 0.5:
			#	continue  # ignore

			path, height = line.warped_path(0.1)

			qp.setOpacity(1)
			if line.confidence < 0.75:
				qp.setPen(default_pen("red"))
				label = "%.2f" % line.confidence
				w = fm.horizontalAdvance(label)
				qp.drawText(
					np.mean(path[:, 0]) - w / 2,
					np.mean(path[:, 1]) + fm.descent(), label)

	finally:
		qp.end()

	return pixmap

def render_paths(
	pixmap, columns,
	color="blue", opacity=0.5,
	show_dir=False, scale=1):

	if not columns:
		return pixmap

	qp = QtGui.QPainter()
	qp.begin(pixmap)

	try:
		qp.setOpacity(opacity)
		qp.setPen(default_pen(color, 10))

		for path in columns:
			path = np.array(path) * scale

			poly = QtGui.QPolygonF()
			for x, y in path:
				poly.append(QtCore.QPointF(x, y))
			qp.drawPolyline(poly)

			if show_dir:
				for part in partition_path(path, 200):
					render_arrows(qp, part, "center", scale=scale)

	finally:
		qp.end()

	return pixmap


from typing import Optional

import pytest

from robotoff.insights.ocr.label import LABELS_REGEX

XX_BIO_XX_OCR_REGEX = LABELS_REGEX["xx-bio-xx"][0]
ES_BIO_OCR_REGEX = LABELS_REGEX["xx-bio-xx"][1]

@pytest.mark.parametrize(
    "input_str,is_match,output",
    [
        ("ES-ECO-001-AN", True, "en:es-eco-001-an"),
        ("ES-ECO-001", False, None),
        ("ES-ECO-001-", False, None),
        ("FR-BIO-01", False, None),
    ],
)
def test_es_ocr_regex(input_str: str, is_match: bool, output: Optional[str]):
    regex = ES_BIO_OCR_REGEX.regex
    match = regex.match(input_str)
    assert (match is not None) == is_match

    if is_match:
        assert ES_BIO_OCR_REGEX.processing_func(match) == output  # type: ignore


class ListNode:
    def __init__(self, val):
        self.val = val
        self.next = None

class MyLinkedList:

    def __init__(self):
        self.head = None
        self.tail = None
        self.size = 0

    def getFirst(self):
        return self.head.val

    def getLast(self):
        return self.tail.val

    def getNodeAt(self, index):
        curr = self.head
        while index > 0:
            curr = curr.next
            index -= 1

        return curr

    def get(self, index: int) -> int:
        if index < 0 or index >= self.size:
            return -1

        node = self.getNodeAt(index)
        return node.val

    # addFirst
    def addAtHead(self, val: int) -> None:
        newNode = ListNode(val)
        if self.head is None:
            self.head = newNode
            self.tail = newNode
        else:
            newNode.next = self.head
            self.head = newNode

        self.size += 1

    # addTail
    def addAtTail(self, val: int) -> None:
        newNode = ListNode(val)
        if self.head is None:
            self.head = newNode
            self.tail = newNode
        else:
            self.tail.next = newNode
            self.tail = newNode

        self.size += 1

    # addAt(index)
    def addAtIndex(self, index: int, val: int) -> None:
        if index < 0 or index > self.size:
            return
        elif index == 0:
            self.addAtHead(val)
        elif index == self.size:
            self.addAtTail(val)
        else:
            prevNode = self.getNodeAt(index - 1)
            nextNode = prevNode.next

            newNode = ListNode(val)

            prevNode.next = newNode
            newNode.next = nextNode

            self.size += 1

    def deleteFirst(self):
        deleteNode = self.head
        if self.size == 1:
            self.head = None
            self.tail = None
        else:
            self.head = self.head.next
            deleteNode.next = None

        self.size -= 1

    def deleteLast(self):
        deleteNode = self.tail
        if self.size == 1:
            self.head = None
            self.tail = None
        else:
            prevNode = self.getNodeAt(self.size - 2)
            prevNode.next = None
            self.tail = prevNode

        self.size -= 1

    # DeleteAt(index)
    def deleteAtIndex(self, index: int) -> None:
        if index < 0 or index >= self.size:
            return
        elif index == 0:
            self.deleteFirst()
        elif index == self.size - 1:
            self.deleteLast()
        else:
            prevNode = self.getNodeAt(index - 1)
            deleteNode = prevNode.next

            prevNode.next = deleteNode.next

            deleteNode.next = None

            self.size -= 1


from torch.nn import BCEWithLogitsLoss

from pytorch_toolbelt import losses as L
import numpy as np
import torch
import matplotlib.pyplot as plt

def main():
    losses = {
        "bce": BCEWithLogitsLoss(),
        # "focal": L.BinaryFocalLoss(),
        # "jaccard": L.BinaryJaccardLoss(),
        # "jaccard_log": L.BinaryJaccardLogLoss(),
        # "dice": L.BinaryDiceLoss(),
        # "dice_log": L.BinaryDiceLogLoss(),
        # "sdice": L.BinarySymmetricDiceLoss(),
        # "sdice_log": L.BinarySymmetricDiceLoss(log_loss=True),
        "bce+lovasz": L.JointLoss(BCEWithLogitsLoss(), L.BinaryLovaszLoss()),
        # "lovasz": L.BinaryLovaszLoss(),
        # "bce+jaccard": L.JointLoss(BCEWithLogitsLoss(),
        #                            L.BinaryJaccardLoss(), 1, 0.5),
        # "bce+log_jaccard": L.JointLoss(BCEWithLogitsLoss(),
        #                            L.BinaryJaccardLogLoss(), 1, 0.5),
        # "bce+log_dice": L.JointLoss(BCEWithLogitsLoss(),
        #                                L.BinaryDiceLogLoss(), 1, 0.5)
        # "reduced_focal": L.BinaryFocalLoss(reduced=True)
    }

    dx = 0.01
    x_vec = torch.arange(-5, 5, dx).view(-1, 1).expand((-1, 100))

    f, ax = plt.subplots(3, figsize=(16, 16))

    for name, loss in losses.items():
        x_arr = []
        y_arr = []
        target = torch.tensor(1.0).view(1).expand((100))

        for x in x_vec:
            y = loss(x, target).item()

            x_arr.append(float(x[0]))
            y_arr.append(float(y))

        ax[0].plot(x_arr, y_arr, label=name)
        ax[1].plot(x_arr, np.gradient(y_arr, dx))
        ax[2].plot(x_arr, np.gradient(np.gradient(y_arr, dx), dx))

    f.legend()
    f.show()

if __name__ == "__main__":
    main()


import omdb
import csv
import requests

def search_dictionaries(key, value, list_of_dictionaries):
	return [element for element in list_of_dictionaries if element[key] == value]

API_KEY = 'd76fe527' #premium service OMDB API Key
# Set the default key for all future calls.
omdb.set_default('apikey', API_KEY)

#build list of valid IMDB_IDs
valid_imdbids = []
with open("valid_imdbid.csv") as file:
    for line in file:
        line = line.strip() #preprocess line
        valid_imdbids.append(line)

#print(valid_imdbids)

# Prepare CSV file for output of db
with open('JAMA_Movie_DB.csv', mode='w', encoding='utf8') as dbfile:
	db_writer = csv.writer(dbfile, delimiter=',', quotechar='"', quoting=csv.QUOTE_MINIMAL) #csv formatting
	# File header population
	db_writer.writerow(['imdb_id', 'title', 'year', 'plot', 'poster', 'runtime', 'website', 'genre', 'director', 'actors', 'rating', 'country', 'season', 'episode', 'tomato_score', 'tomato_fresh'])

	#loop from imdbid 0000001 to 0001000   <--- This will likely change to a static valid IMDBID list to iterate through
	for x in reversed(valid_imdbids):

		print(x) #debug to check progress and API call speed.

		imdbid = "tt" + str(x).zfill(7) # create imdbid with padding 0s. Seven int length. i.e. 24 = 0000024

		try:
			res = omdb.get(imdbid=imdbid,tomatoes=True)
		except:
			print("Internal Error - Timeout Detected.")
			continue

		#print(res)

		#if there is a valid API response
		if res:

			# Fields of our schema
			imdb_id = str(res.get("imdb_id"))
			title = str(res.get("title"))
			year = str(res.get("year"))
			plot = str(res.get("plot"))
			poster = str(res.get("poster"))
			runtime = str(res.get("runtime"))
			website = str(res.get("website"))
			genre = str(res.get("genre"))
			director = str(res.get("director"))
			actors = str(res.get("actors"))
			rating = str(res.get("rated"))
			country = str(res.get("country"))
			season = str(res.get("season"))
			episode = str(res.get("episode"))
			tomato_score = search_dictionaries("source", "Rotten Tomatoes",res.get("ratings"))
			if tomato_score:
				tomato_score = tomato_score[0].get("value")
			else:
				tomato_score = "N/A"
			tomato_fresh = str(res.get("tomato_fresh"))
			# write the fields to file
			db_writer.writerow([imdb_id,title,year,plot,poster,runtime,website,genre,director,actors,rating,country,season,episode,tomato_score,tomato_fresh])


def sum(numbers):
    added_value = 0
    for num in numbers:
        num_val = int(num)
        added_value = added_value + num_val
    return added_value

num = []

while True:
    entries = input("Enter a number or 'done' to quit: ")
    if entries.lower() == 'done':
        print('Goodbye')
        break
    elif entries.lower() != 'done':
            num.append(entries)

print(f'Sum: {sum(num)}')


class Solution:
    def sumSubarrayMins(self, A: List[int]) -> int:
        stack = []
        stack.append([A[0], 0, A[0]])
        res = A[0]
        for i in range(1, len(A)):
            while len(stack) > 0 and stack[-1][0] >= A[i]:
                stack.pop()
            if len(stack) == 0:
                temp = A[i] * (i + 1)
            else:
                temp = A[i] * (i - stack[-1][1]) + stack[-1][2]
            stack.append([A[i], i, temp])
            # calculate
            res += temp
        return res % (10 ** 9 + 7)

# 带object的

class Solution:
    def sumSubarrayMins(self, A: List[int]) -> int:
        stack = []
        node = Node(A[0], 0, A[0])
        stack.append(node)
        res = node.total_until_now
        for i in range(1, len(A)):
            while len(stack) > 0 and stack[-1].value >= A[i]:
                stack.pop()
            if len(stack) == 0:
                temp = A[i] * (i + 1)
            else:
                temp = A[i] * (i - stack[-1].index) + stack[-1].total_until_now
            node = Node(A[i], i, temp)
            stack.append(node)
            # calculate
            res += temp
        return res % (10 ** 9 + 7)

class Node:
    def __init__(self, value, index, total_until_now):
        self.value = value
        self.index = index
        self.total_until_now = total_until_now

# 超时的
class Solution:
    def sumSubarrayMins(self, A: List[int]) -> int:
        stack = []
        stack.append([A[0], 0])
        res = A[0]
        for i in range(1, len(A)):
            while len(stack) > 0 and stack[-1][0] >= A[i]:
                stack.pop()
            stack.append([A[i], i])
            # calculate
            res += self.sum_up(A, stack)
        return res % (10**9 + 7)
    def sum_up(self, A, stack):
        res = 0
        for i in range(len(stack) - 1, -1, -1):
            if i == 0:
                res += stack[i][0]*(stack[i][1] + 1)
            else:
                res += stack[i][0]*(stack[i][1] - stack[i - 1][1])
        return res


import requests
import json
import time
from pygame import mixer
#Enter your url here and enjoy your free offer!!
url = 'https://www.cricbuzz.com/match-api/21859/commentary.json'

f = 0
c = time.time()
while True:
	try:
		current_scorecard = requests.get(url).json()['score']['prev_overs']
	except:
		mixer.init()
		mixer.music.load('error.mp3')
		mixer.music.play()
		break
	for score in current_scorecard[-10:-1]:
		if score == '6':
			mixer.init()
			mixer.music.load('six.mp3')
			mixer.music.play()
			f = 1
			break
	if f == 1:
		break
	time.sleep(5*60)


import logging
import re

from streamlink.plugin import Plugin, pluginmatcher
from streamlink.stream import HLSStream

log = logging.getLogger(__name__)

@pluginmatcher(
    re.compile(r"https?://(?:www\.)?auftanken\.tv/livestream/?")
)
class AuftankenTV(Plugin):
    _hls_url_re = re.compile(r"(https://.+?/http_adaptive_streaming/\w+\.m3u8)")

    PLAYER_URL = "https://webplayer.sbctv.ch/auftanken/"

    def get_title(self):
        return "auftanken.TV Livestream"

    def _get_streams(self):
        res = self.session.http.get(self.PLAYER_URL)
        m = self._hls_url_re.search(res.text)
        if m:
            for s in HLSStream.parse_variant_playlist(self.session, m.group(1)).items():
                yield s

__plugin__ = AuftankenTV


from sqlite3 import Error as sqliteError
from sqlite3 import OperationalError as sqliteOperationalError
from loggingSystem import LoggingSystem
import sqlite3,sys,os,time
from typing import Union

class ProcessamentoSqlite:
    def __init__(self,sqlite_db="./initial_db.db",sql_file_pattern="scripts/sqlitePattern.sql", log_file="./processadorSQlite.log",level:int=10,logging_pattern='%(name)s - %(levelname)s - %(message)s',log_name:str="gerenciador sqlite",logstash_data:dict={},thread=False):
        """
        classe para gerenciar arquivos sqlite
        :param loggin_name: nome do log que foi definido para a classe,altere apenas em caso seja necessário criar multiplas insstancias da função
        :param log_file: nome do arquivo de log que foi definido para a classe,altere apenas em caso seja necessário criar multiplas insstancias da função
        """
        self.logging = LoggingSystem(name=log_name, arquivo=log_file,level=level,formato=logging_pattern,logstash_data=logstash_data)
        self.create_temporary_DB(local=sqlite_db,pattern=sql_file_pattern)
        if thread is True:
            self.conn = sqlite3.connect(sqlite_db,check_same_thread=False)
        else:
            self.conn = sqlite3.connect(sqlite_db)
        self.stack_overflow_max=5

    def create_temporary_DB(self,local,pattern):
        """verifica a integridade do db caso ele n exista

        Args:
            local (path): local onde o bd sqlite está salvo
            pattern (path): local onde o arquivo sql está salvo
        """
        try:
            if not os.path.isfile(local):
                f = open(local, "a")
                f.write("")
                f.close()
                conn = sqlite3.connect(local)
                self.execute_sqlfile_sqlite(pattern,conn)
                conn.close()
                self.logging.info("bd gerado com sucesso")
            else:
                self.logging.info("bd já existe")
        except sqliteOperationalError as e:
            #print("erro operacional no sqlite")
            self.logging.error(e)
            quit()
        except sqliteError as e:
            #print("erro desconhecido no sqlite")
            self.logging.error(e)
        except :
            self.logging.error("Unexpected error:", str(sys.exc_info()[0]))

    def insert_data_sqlite(self,data:dict,table:str=""):
        '''
        INSERT INTO "operacoes"(	"tipoOperacao",	"nomeBD","adicionais","dados")
        VALUES(1,"empregado","[(pessoas,pessoas_id,1),(lojas,loja_id)]","{salario:1200,contratado:30/12/20}")
        '''
        self.logging.info("insercao dado sqlite")
        insert_command="INSERT INTO "
        insert_command+="'"+table+"' ("
        self.logging.debug(data)
        for coluna in data.keys():
            insert_command+=str(coluna)
            if coluna !=  list(data.keys())[-1]:
                insert_command+=","
        insert_command+=") VALUES ("
        for coluna in data.keys():
            if type(data[coluna]) == type("") :
                insert_command+='"'+data[coluna].replace("\n","")+'"'
            elif type(data[coluna]) == type({}) or  type(data[coluna]) == type([]):
                for i in list(data[coluna]):
                    i.replace("\n","")
                insert_command+='"'+str(data[coluna])+'"'
            else:
                insert_command+=str(data[coluna])
            if coluna !=  list(data.keys())[-1]:
                insert_command+=","
        insert_command+=");"
        self.logging.debug(insert_command)
        try:
            cursor = self.conn.cursor()
            cursor.execute(insert_command)
            self.conn.commit()
        except sqliteOperationalError as e:
            #print("erro operacional no sqlite")
            self.logging.error(e)
            time.sleep(0.001)
            try:
                chamadas=LoggingSystem.full_inspect_caller()
                if chamadas.count(chamadas[0])>self.stack_overflow_max:
                    return None
            except IndexError as e:
                pass
            except:
                raise
            self.insert_data_sqlite(data=data,table=table)
        except sqliteError as e:
            #print("erro desconhecido no sqlite")
            self.logging.error(e)
        except :
            self.logging.error("Unexpected error:", sys.exc_info()[0])

    def read_data_sqlite(self,table:str,filtro:Union[str,dict]="*",query:Union[str,dict]="*"):
        self.logging.info("lendo sqlite")
        read_command=""
        read_command+="SELECT "
        if filtro != "*":
            read_command+="("
            for key in filtro:
                read_command+=key
                if len(filtro)>1:
                    if key !=  filtro[-1]:
                        read_command+=","
            read_command+=")"
        else:
            read_command+=filtro
        read_command+=" FROM "
        read_command+="'"+table+"'"
        if query != "*":
            read_command+=" WHERE "
            for coluna in query.keys():
                        read_command+=str(coluna) + " IS "
                        if type(query[coluna])==type(""):
                            read_command+="'"+query[coluna]+"'"
                        else:
                            read_command+=str(query[coluna])
                        if coluna !=  list(query.keys())[-1]:
                            read_command+=" AND "
        read_command+=";"
        try:
            cursor = self.conn.cursor()
            self.logging.info(read_command)
            cursor.execute(read_command)
            self.conn.commit()
            saida=cursor.fetchall()
            return saida
        except sqliteOperationalError as e:
            #print("erro operacional no sqlite")
            self.logging.error(e)
            return self.read_data_sqlite(table,filtro,query)
        except sqliteError as e:
            #print("erro desconhecido no sqlite")
            self.logging.error(e)
        except :
            self.logging.error("Unexpected error:", sys.exc_info()[0])

    def execute_sqlfile_sqlite(self,pattern:dict,conn=None):
        self.logging.info("executar arquivo sql em sqlite")
        try:
            if conn != None:
                cursor = conn.cursor()
            else:
                cursor=self.conn.cursor()
            sqlfile=open(pattern).read().split(";\n")
            for sqlstatement in sqlfile:
                if sqlstatement[-1] != ";":
                    sqlstatement+=";"
                self.logging.debug(sqlstatement)
                cursor.execute(sqlstatement)
                conn.commit()
        except sqliteOperationalError as e:
            #print("erro operacional no sqlite")
            self.logging.error(e)
            return self.execute_sqlfile_sqlite(pattern,conn)
        except sqliteError as e:
            #print("erro desconhecido no sqlite")
            self.logging.error(e)
        except :
            self.logging.error("Unexpected error:", sys.exc_info()[0])

    def dict_all_string(self,entrada:dict)-> dict:
        retorno={}
        for i in entrada.keys():
            if type(i)==type(""):
                retorno[i]=entrada[i]
            else:
                retorno[i]=str(entrada[i])


# coding:utf-8
import numpy as np
from chainer import cuda, Function, gradient_check, report, training, utils, Variable
from chainer import datasets, iterators, optimizers, serializers
import chainer.functions as F
import chainer.links as L

import sys
import argparse
import _pickle as pickle
import MeCab
from LSTM import LSTM

BOS_INDEX = 0
EOS_INDEX = 1

# arguments
parser = argparse.ArgumentParser()
parser.add_argument('--unit_size',        type=int,   default=100)
parser.add_argument('--seed',           type=int,   default=1)
parser.add_argument('--gpu',            type=int,   default=-1)

args = parser.parse_args()

xp = cuda.cupy if args.gpu >= 0  else np
xp.random.seed(args.seed)
mecab = MeCab.Tagger ("-Ochasen")

vocab = pickle.load(open('data/vocab.bin','rb'))
train_data = pickle.load(open('data/train_data.bin', 'rb'))

rnn =  LSTM(len(vocab),args.unit_size)
model = L.Classifier(rnn)
if args.gpu >= 0:
    print('use GPU!')
    cuda.get_device(args.gpu).use()
    model.to_gpu()

serializers.load_npz('data/latest.model',model)

# vocabのキーと値を入れ替えたもの
ivocab = {}
for c, i in vocab.items():
    ivocab[i] = c

def get_index_a(_model):
    _model.predictor.reset_state()
    _sentence_index_a = []
    index = BOS_INDEX
    while index != EOS_INDEX:
        y = _model.predictor(xp.array([index], dtype=xp.int32))
        probability = F.softmax(y)
        probability.data[0] /= sum(probability.data[0])
        try:
            #確率によって、ランダムに１つ単語を選択
            #index = np.argmax(probability.data[0])
            index = xp.random.choice(range(len(probability.data[0])), p=probability.data[0])
            if index!=EOS_INDEX:
                #終了<EOS>でなかった場合
                _sentence_index_a.append(index)
        except Exception as e:
            print('probability error')
            break

    return _sentence_index_a

print('\n-=-=-=-=-=-=-=-')
for i in range(10):
    sentence_index_a = get_index_a(model)

    for index in sentence_index_a:
        if index in ivocab:
            sys.stdout.write( ivocab[index].split("::")[0] )
    print('\n-=-=-=-=-=-=-=-')

print('generated!')


class Node:
    def __init__(self,val):
        self.val = val
        self.children = []

class Solution:
    def maxAvg(self,node):
        if node is None:
            return None
        else:
            self.ans = float('-inf')
            def helper(node):
                if node is None:
                    return 0,0
                if len(node.clildren) == 0:
                    self.ans = max(self.ans, node.val)
                    return 1,node.val
                c = 1
                temp_sum = node.valc
                for i in range(len(node.children)):
                    temp_c, temp_sum_1 = helper(node.children[i])
                    c += temp_c
                    temp_sum += temp_sum_1
                self.ans = max(self.ans, temp_sum/c)

                return temp_sum


import torch
import torch.nn.functional as F
from torch.autograd import Variable
import torch.nn as nn

# Credict: https://github.com/kefirski/pytorch_Highway
class Highway(nn.Module):
    def __init__(self, size, num_layers, f):

        super(Highway, self).__init__()

        self.num_layers = num_layers

        self.nonlinear = nn.ModuleList([nn.Linear(size, size) for _ in range(num_layers)])

        self.linear = nn.ModuleList([nn.Linear(size, size) for _ in range(num_layers)])

        self.gate = nn.ModuleList([nn.Linear(size, size) for _ in range(num_layers)])

        self.f = f

    def forward(self, x):
        for layer in range(self.num_layers):
            gate = F.sigmoid(self.gate[layer](x))

            nonlinear = self.f(self.nonlinear[layer](x))
            linear = self.linear[layer](x)

            x = gate * nonlinear + (1 - gate) * linear
        return x

class Model(nn.Module):

    def __init__(self, weeks, time_slots, features, drop_out, device=None):

        super(Model, self).__init__()
        self.device = device
        self.weeks = weeks
        self.time_slots = time_slots

        self.time_slot_GRU_1 = nn.GRU(features, 256, 1, batch_first=True, bidirectional=True)
        self.time_slot_Linear_1 = nn.Linear(256*2, 256)
        self.norm_1 = torch.nn.BatchNorm1d(time_slots)

        self.time_slot_Linear_3 = nn.Linear(256, 256)
        self.time_slot_MaxPool = nn.MaxPool1d(256)

        self.last_two_GRU_1 = nn.GRU(time_slots, 256, 1, batch_first=True, bidirectional=True)
        self.last_two_Linear_1 = nn.Linear(256*2, 256)

        self.week_GRU_1 = nn.GRU(time_slots, 256, 1, batch_first=True, bidirectional=True)
        self.week_linear_1 = nn.Linear(256*2, 256)
        self.norm_3 = torch.nn.BatchNorm1d(weeks)

        self.week_GRU_2 = nn.GRU(256, 256, 1, batch_first=True, bidirectional=True)
        self.MaxPool = nn.MaxPool1d(256*2)
        self.norm_4 = torch.nn.BatchNorm1d(34)

        self.highway_1 = Highway(34, 3, f=torch.nn.functional.relu)
        self.linear_5 = torch.nn.Linear(34, 28)

        self.drop = nn.Dropout(drop_out)

    def forward(self, x):
        x = x.permute(1, 0, 2, 3)
        collect = torch.Tensor().type(torch.FloatTensor).to(self.device)
        for idx in x:
            layer_1, _ = self.time_slot_GRU_1(idx)
            layer_1 = self.time_slot_Linear_1(self.drop(layer_1.contiguous().view(-1, layer_1.size(2))))
            layer_1 = F.selu(self.norm_1(layer_1.view(-1, idx.size(1), 256)))

            layer_2 = self.time_slot_Linear_3(self.drop(layer_1))
            layer_2 = self.time_slot_MaxPool(layer_2).squeeze(2)
            collect = torch.cat((collect, layer_2.unsqueeze(0)), dim=0)

        last_two = collect[collect.size(0)-2:]

        collect = collect.permute(1, 0, 2)

        last_two, _ = self.last_two_GRU_1(last_two)
        last_two = self.last_two_Linear_1(last_two.contiguous().view(-1, last_two.size(2)))
        last_two = last_two.view(-1, 2, 256)

        layer_3, _ = self.week_GRU_1(collect)
        layer_3 = self.week_linear_1(layer_3.contiguous().view(-1, layer_3.size(2)))
        layer_3 = F.selu(self.norm_3(layer_3.view(-1, collect.size(1), 256)))

        layer_4 = (torch.cat((layer_3, last_two), dim=1))
        layer_4 = self.MaxPool(layer_4).squeeze(2)

        x = self.norm_4(layer_4)
        x = self.drop(x)
        x = self.highway_1(x)
        x = self.drop(x)
        x = self.linear_5(x)

        return x


from django.shortcuts import render, redirect
from users.forms import CustomUserCreationForm, CustomUserChangeForm
from django.contrib.auth.decorators import login_required
from users.models import CustomUser

# Create your views here.

@login_required(login_url='/login/')
def home(request):
    """show users view"""
    users = CustomUser.objects.all()
    if request.method == 'POST':
        form = CustomUserCreationForm(request.POST)
        if form.is_valid():
            data = form.cleaned_data
            user = form.save()
            return redirect('/users/home/')
        else:
            return render(request, 'users.html', {'form': form, 'users': users})
    else:
        form = CustomUserCreationForm()
        return render(request, 'users.html', {'form': form, 'users': users})

@login_required(login_url='/login/')
def edit_user(request, id_user):
    """allow edit a user"""
    user = CustomUser.objects.get(pk=id_user)

    if request.method == 'GET':
        # Get se usa para obtener datos y Post para enviar datos
        form = CustomUserChangeForm(instance=user)
    else:
        # Aqui guardamos el cliente
        form = CustomUserChangeForm(request.POST, instance=user)
        if form.is_valid():
            form.save()
            return redirect('/users/home/')
    return render(request, 'edit_user.html', {'form': form})

@login_required(login_url='/login/')
def view_user(request, id_user):
    """can view data user"""
    user = CustomUser.objects.get(pk=id_user)
    return render(request, 'view_user.html', {'user': user})

@login_required(login_url='/login/')
def delete_user(request, id_user):
    """delete a user"""
    user = CustomUser.objects.get(pk=id_user)
    user.delete()
    return redirect('/users/home/')


import csv
from scipy.interpolate import interp1d
from typing import Dict

def app() -> None:
    # Separated govt bonds and c bonds because calculating benchmark yield spread
    # checks 1 corporate bond against all govt bonds
    f_name = input("csv name (with.csv): ")
    g_bonds, c_bonds = load_csv(f_name)

    print_benchmark_yield_spread(c_bonds, g_bonds)
    print("\n")
    print_interpolated_yield_spread(c_bonds, g_bonds)
    assert len(c_bonds) > 0 and len(g_bonds) > 0

def load_csv(file_name: str) -> (Dict, Dict):
    g_bonds = {}
    c_bonds = {}

    with open(file_name, mode='r') as bond_file:
        csv_reader = csv.DictReader(bond_file)

        for row in csv_reader:
            bond_id, term, _yield, bond_type = row['bond'], row['term'], row['yield'], row['type']
            term = float(term.split(' ')[0])
            _yield = float(_yield[:-2])

            bond_info = {'term': term, 'yield': _yield}

            if bond_type == "government":
                g_bonds[bond_id] = bond_info
            else:
                c_bonds[bond_id] = bond_info
    return g_bonds, c_bonds

def print_benchmark_yield_spread(c_bonds, g_bonds) -> None:
    """
       @c_bonds: Dict[str,[Dict[str, float]]
       @g_bonds: Dict[str,[Dict[str, float]]

       Prints the benchmark yield spread of all corporate bonds
       """
    for cb_id, info in c_bonds.items():
        bm_bond_id, yield_spread = calc_benchmark_yield_spread(cb_id, c_bonds, g_bonds)
        print("bond,benchmark,spread_to_benchmark")
        print(f"{cb_id},{bm_bond_id}, {yield_spread:.2f}%")

def print_interpolated_yield_spread(c_bonds, g_bonds) -> None:
    """
    @c_bonds: Dict[str, Dict[str, float]]
    @g_bonds: Dict[str, Dict[str, float]]

    Prints the interpolated yield spread of all corporate bonds
    """
    for cb_id, cb in c_bonds.items():
        yield_spread_to_curve = calc_spread_to_curve(cb_id, c_bonds, g_bonds)
        print("bond,spread_to_curve")
        print(f"{cb_id}, {yield_spread_to_curve:.2f}%")

def calc_benchmark_yield_spread(cb_id, c_bonds, g_bonds) -> (str, float):
    """
    @cb_id: str
    @c_bonds:  Dict[str, Dict[str, float]]
    @g_bonds: Dict[str, Dict[str, float]]
    Returns the yield spread and the corresponding govt benchmark bond for <c_bond>

    """
    min_term_diff = float('inf')
    bm_bond = ""

    for gb in g_bonds:
        term_diff = abs(c_bonds[cb_id]['term'] - g_bonds[gb]['term'])
        if term_diff < min_term_diff:
            min_term_diff = term_diff
            bm_bond = gb

    yield_spread = c_bonds[cb_id]['yield'] - g_bonds[bm_bond]['yield']  # Govt bm yield < corporate bond yield
    return f"{bm_bond}", yield_spread

def calc_spread_to_curve(cb_id, c_bonds, g_bonds) -> float:
    """
    @cb_id: str
    @c_bonds:  Dict[str, Dict[str, float]]
    @g_bonds: Dict[str, Dict[str, float]]
    Returns interpolated spread
    prerequisite:
        interpolation is always possible
    Returns interpolated yield spread
    """

    inter_func = interp1d([b_info['term'] for b_info in g_bonds.values()], [b_info['yield'] for b_info in g_bonds.values()])

    interpolated_yield = inter_func(c_bonds[cb_id]['term'])
    spread_to_curve = c_bonds[cb_id]['yield'] - interpolated_yield
    return spread_to_curve

if __name__ == "__main__":
    app()


#!/usr/bin/env python
# encoding: utf-8
#
# facke-guider.py
#
# Created by José Sánchez-Gallego on 29 Mar 2017.

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

import opscore
from opscore.protocols.parser import CommandParser
from opscore.utility.qstr import qstr
from opscore.utility.tback import tback

from opscore.utility.sdss3logging import setupRootLogger, setConsoleLevel
import logging

import opscore.protocols.keys as keys
import opscore.protocols.validation as validation

import actorcore.CommandLinkManager as cmdLinkManager
import actorcore.Command as actorCmd
import actorcore.CmdrConnection

import ConfigParser
import Queue

from twisted.internet import reactor

import imp
import inspect
import os
import re
import sys
import threading
import traceback

class FakeGuider(object):

    def __init__(self, name, productName='guiderActor', makeCmdrConnection=True):
        self.ii = 1026
        self.name = name
        self.productName = productName if productName else self.name
        product_dir_name = '$%s_DIR' % (self.productName.upper())
        self.product_dir = os.path.expandvars(product_dir_name)

        self.parser = CommandParser()

        self.config = ConfigParser.ConfigParser()
        self.config.read(os.path.join(os.path.dirname(__file__), 'guider.cfg'))

        self.configureLogs()

        # The list of all connected sources.
        tronInterface = ''
        tronPort = 9994
        self.commandSources = cmdLinkManager.listen(self,
                                                    port=tronPort,
                                                    interface=tronInterface)
        # The Command which we send uncommanded output to.
        self.bcast = actorCmd.Command(self.commandSources,
                                      'self.0', 0, 0, None, immortal=True)

        # IDs to send commands to ourself.
        self.selfCID = self.commandSources.fetchCid()
        self.synthMID = 1

        # commandSets are the command handler packages. Each handles
        # a vocabulary, which it registers when loaded.
        # We gather them in one place mainly so that "meta-commands" (init, status)
        # can find the others.
        self.commandSets = {}

        self.handler = validation.CommandHandler()

        self.attachAllCmdSets()

        self.commandQueue = Queue.Queue()
        self.shuttingDown = False

        if makeCmdrConnection:
            self.cmdr = actorcore.CmdrConnection.Cmdr(name, self)
            self.cmdr.connectionMade = self._connectionMade
            self.cmdr.connect()
        else:
            self.cmdr = None

    def configureLogs(self, cmd=None):
        """ (re-)configure our logs. """

        self.logDir = self.config.get('logging', 'logdir')
        assert self.logDir, "logdir must be set!"

        # Make the root logger go to a rotating file. All others derive from this.
        setupRootLogger(self.logDir)

        # The real stderr/console filtering is actually done through the console Handler.
        try:
            consoleLevel = int(self.config.get('logging', 'consoleLevel'))
        except:
            consoleLevel = int(self.config.get('logging', 'baseLevel'))
        setConsoleLevel(consoleLevel)

        # self.console needs to be renamed ore deleted, I think.
        self.console = logging.getLogger('')
        self.console.setLevel(int(self.config.get('logging', 'baseLevel')))

        self.logger = logging.getLogger('actor')
        self.logger.setLevel(int(self.config.get('logging', 'baseLevel')))
        self.logger.propagate = True
        self.logger.info('(re-)configured root and actor logs')

        self.cmdLog = logging.getLogger('cmds')
        self.cmdLog.setLevel(int(self.config.get('logging', 'cmdLevel')))
        self.cmdLog.propagate = True
        self.cmdLog.info('(re-)configured cmds log')

        if cmd:
            cmd.inform('text="reconfigured logs"')

    def versionString(self, cmd):
        """ Return the version key value.

        If you simply want to generate the keyword, call .sendVersionKey().
        """

        cmd.warn("text='pathetic version string: unknown'")
        return 'unknown'

    def sendVersionKey(self, cmd):
        """ Generate the version keyword in response to cmd. """

        version = self.versionString(cmd)
        cmd.inform('version=%s' % (qstr(version)))

    def triggerHubConnection(self):
        """ Send the hub a command to connect back to us. """

        if not self.cmdr:
            self.bcast.warn('text="CANNOT ask hub to connect to us, '
                            'since we do not have a connection to it yet!"')
            return

        self.bcast.warn('%s is asking the hub to connect back to us' % (self.name))
        self.cmdr.dispatcher.executeCmd(opscore.actor.keyvar.CmdVar
                                        (actor='hub', cmdStr='startNubs %s' % (self.name),
                                         timeLim=5.0))

    def _connectionMade(self):
        """ twisted arranges to call this when self.cmdr has been established. """

        self.bcast.warn('%s is connected to the hub.' % (self.name))

        #
        # Request that tron connect to us.
        #
        self.triggerHubConnection()
        self.connectionMade()

    def connectionMade(self):
        """ For overriding. """
        pass

    def attachCmdSet(self, cname, path=None):
        """ (Re-)load and attach a named set of commands. """

        if path is None:
            path = [os.path.join(self.product_dir, 'python', self.productName, 'Commands')]

        self.logger.info("attaching command set %s from path %s", cname, path)

        file = None
        try:
            file, filename, description = imp.find_module(cname, path)
            self.logger.debug("command set file=%s filename=%s from path %s",
                              file, filename, path)
            mod = imp.load_module(cname, file, filename, description)
        except ImportError as e:
            raise RuntimeError('Import of %s failed: %s' % (cname, e))
        finally:
            if file:
                file.close()

        # Instantiate and save a new command handler.
        cmdSet = getattr(mod, cname)(self)

        # Check any new commands before finishing with the load. This
        # is a bit messy, as the commands might depend on a valid
        # keyword dictionary, which also comes from the module
        # file.
        #
        # BAD problem here: the Keys define a single namespace. We need
        # to check for conflicts and allow unloading. Right now we unilaterally
        # load the Keys and do not unload them if the validation fails.
        if hasattr(cmdSet, 'keys') and cmdSet.keys:
            keys.CmdKey.addKeys(cmdSet.keys)
        valCmds = []
        for v in cmdSet.vocab:
            try:
                verb, args, func = v
            except ValueError as e:
                raise RuntimeError("vocabulary word needs three parts: %s" % (v))

            # Check that the function exists and get its help.
            #
            funcDoc = inspect.getdoc(func)
            valCmd = validation.Cmd(verb, args, help=funcDoc) >> func
            valCmds.append(valCmd)

        # Got this far? Commit. Save the Cmds so that we can delete them later.
        oldCmdSet = self.commandSets.get(cname, None)
        cmdSet.validatedCmds = valCmds
        self.commandSets[cname] = cmdSet

        # Delete previous set of consumers for this named CmdSet, add new ones.
        if oldCmdSet:
            self.handler.removeConsumers(*oldCmdSet.validatedCmds)
        self.handler.addConsumers(*cmdSet.validatedCmds)

        self.logger.debug("handler verbs: %s" % (self.handler.consumers.keys()))

    def attachAllCmdSets(self, path=None):
        """ (Re-)load all command classes -- files in ./Command which end with Cmd.py.
        """

        if path is None:
            self.attachAllCmdSets(path=os.path.join(os.path.expandvars('$ACTORCORE_DIR'),
                                                    'python', 'actorcore', 'Commands'))
            # self.attachAllCmdSets(path=os.path.join(self.product_dir, 'python', self.productName,
            #                                         'Commands'))
            return

        dirlist = os.listdir(path)
        dirlist.sort()
        self.logger.info("loading %s" % (dirlist))

        for f in dirlist:
            if os.path.isdir(f) and not f.startswith('.'):
                self.attachAllCmdSets(path=f)
            if re.match('^[a-zA-Z][a-zA-Z0-9_-]*Cmd\.py$', f):
                self.attachCmdSet(f[:-3], [path])

    def cmdTraceback(self, e):
        eType, eValue, eTraceback = sys.exc_info()
        tbList = traceback.extract_tb(eTraceback)
        where = tbList[-1]

        return "%r at %s:%d" % (eValue, where[0], where[1])

    def runActorCmd(self, cmd):

        self.output_file()

        try:
            cmdStr = cmd.rawCmd
            self.cmdLog.debug('raw cmd: %s' % (cmdStr))

            try:
                validatedCmd, cmdFuncs = self.handler.match(cmdStr)
            except Exception as e:
                cmd.fail('text=%s' % (qstr("Unmatched command: %s (exception: %s)" %
                                           (cmdStr, e))))
                # tback('actor_loop', e)
                return

            if not validatedCmd:
                cmd.fail('text=%s' % (qstr("Unrecognized command: %s" % (cmdStr))))
                return

            self.cmdLog.info('< %s:%d %s' % (cmd.cmdr, cmd.mid, validatedCmd))
            if len(cmdFuncs) > 1:
                cmd.warn('text=%s' % (qstr("command has more than one callback (%s): %s" %
                                           (cmdFuncs, validatedCmd))))
            try:
                cmd.cmd = validatedCmd
                for func in cmdFuncs:
                    func(cmd)
            except Exception as e:
                oneLiner = self.cmdTraceback(e)
                cmd.fail('text=%s' % (qstr("command failed: %s" % (oneLiner))))
                # tback('newCmd', e)
                return

        except Exception as e:
            cmd.fail('text=%s' %
                     (qstr('completely unexpected exception when processing a new command: %s'
                      % (e))))
            try:
                tback('newCmdFail', e)
            except:
                pass

    def actor_loop(self):
        """ Check the command queue and dispatch commands."""

        while True:
            try:
                cmd = self.commandQueue.get(block=True, timeout=3)
            except Queue.Empty:
                if self.shuttingDown:
                    return
                else:
                    continue
            self.runActorCmd(cmd)

    def commandFailed(self, cmd):
        """ Gets called when a command has failed. """
        pass

    def newCmd(self, cmd):
        """ Dispatch a newly received command. """

        self.cmdLog.info('new cmd: %s' % (cmd))

        # Empty cmds are OK; send an empty response...
        if len(cmd.rawCmd) == 0:
            cmd.finish('')
            return None

        if self.runInReactorThread:
            self.runActorCmd(cmd)
        else:
            self.commandQueue.put(cmd)

        return self

    def callCommand(self, cmdStr):
        """ Send ourselves a command. """

        cmd = actorCmd.Command(self.commandSources, 'self.%d' % (self.selfCID),
                               cid=self.selfCID, mid=self.synthMID, rawCmd=cmdStr)
        self.synthMID += 1
        self.newCmd(cmd)

    def _shutdown(self):
        self.shuttingDown = True

    def run(self, doReactor=True):
        """ Actually run the twisted reactor. """
        try:
            self.runInReactorThread = self.config.getboolean(self.name, 'runInReactorThread')
        except:
            self.runInReactorThread = False

        self.logger.info("starting reactor (in own thread=%s)...." % (not self.runInReactorThread))
        try:
            if not self.runInReactorThread:
                threading.Thread(target=self.actor_loop).start()
            if doReactor:
                reactor.run()
        except Exception as e:
            tback('run', e)

        if doReactor:
            self.logger.info("reactor dead, cleaning up...")
            self._shutdown()

    def output_file(self):
        self.bcast.inform('guideState="on"')
        self.bcast.inform('file=/data/gcam/57831/,proc-gimg-{0}.fits.gz'.format(self.ii))
        self.ii += 1
        reactor.callLater(10, self.output_file)

if __name__ == '__main__':
    guider = FakeGuider('guider')
    guider.run()


#!/usr/bin/python3
#################################
## Author: Heini Bergsson Debes
#################################
# Purpose is to:
# (1) encode the adjacency list (optionally padded)
# (2) get the hash of the encoded adjacency list, translator, and recorded execution path (after padding)
# (3) format inputs for ZEKRA circuit

import sys, getopt, math
from poseidon.poseidon_hash import poseidon_hash, p

P_BITWIDTH=len(format(p,'0b'))
EMPTY_DEST_ADDR=0
JUMPKIND_BITWIDTH=2
LABEL_BITWIDTH=None
BUCKET_BITWIDTH=None
ADDR_BITWIDTH=None
ADJLIST_LEVELS=None
ADJLIST_FILENAME='adjlist'
NUMIFIED_ADJLIST_FILENAME='numified_adjlist'
NUMIFIED_PATH_FILENAME='numified_path'
RECORDED_PATH_FILENAME='recorded_path'
TRANSLATOR_FILENAME='translator'
PAD_ADJLIST=None
PAD_PATH=None

def format_adjlist(adjlist, delim=' '):
    tmp = {}
    for node in adjlist:
        neighbors = node.split(' ')
        node = neighbors[0]
        neighbors = neighbors[1:]
        tmp[node] = neighbors
    return tmp

def encode_adjlist(adjlist):
    encoded_adjlist = [] # list of tuples (node, {bucket-rems levels})
    for node in adjlist:
        levels = {} # dictionary of bucket-rems pairs: {'bucket1':'rems1', 'bucket2':'rems2'}
        for neighbor in adjlist[node]: # dividend = divisor * quotient + remainder
            neighbor = int(neighbor)
            bucket = int(neighbor / 8) # quotient
            rem = neighbor % 8 # remainder
            if bucket not in levels:
                levels[bucket] = 0
            levels[bucket] |= (1 << rem) # set bit
        encoded_adjlist.append((node, levels))
    return encoded_adjlist

def read_adjlist(adjlist_file, pad_adjlist=None):
    adjlist = []
    len_without_pad = 0
    with open(adjlist_file, 'r') as file_in:
        for line in file_in.readlines():
            node = line.rstrip()
            adjlist.append(node)
    len_without_pad = len(adjlist)
    if pad_adjlist:
        if pad_adjlist<len(adjlist):
            raise Exception('Adjacency list contains %s nodes. Cannot apply padding of %s nodes.'%(len(adjlist), pad_adjlist))
        # append nodes with no neighbors to adjacency list
        while len(adjlist)<pad_adjlist:
            fantom_node = str(len(adjlist))
            adjlist.append(fantom_node)
    return adjlist, len_without_pad

def read_translator(translator_file, pad_translator):
    translator=[]
    len_without_pad = 0
    with open(translator_file, 'r') as file_in:
        for hex_addr in file_in.readlines():
            hex_addr=hex_addr.rstrip()
            translator.append(int(hex_addr,16))
    len_without_pad = len(translator)
    if pad_translator:
        if pad_translator<len(translator):
            raise Exception('Translator contains %s entries. Cannot apply padding of %s entries.'%(len(translator), pad_translator))
        # append empty entries to translator
        translator.extend([0]*(pad_translator-len(translator)))
    # append one extra entry to allow for translation of empty destination addresses
    translator.append(EMPTY_DEST_ADDR)
    return translator, len_without_pad

def read_path(path_file, pad_path, empty_move_dst):
    transitions = []
    initial_node = None
    final_node = None
    len_without_pad = 0
    with open(path_file, 'r') as file_in: # don't include the starting node (it is already assumed in the circuit)
        initial_node, final_node = [node.split('=')[1] for node in file_in.readline().rstrip().split(' ')]
        for transition in file_in.readlines():
            transition = transition.rstrip().split(' ')
            jumpkind,dst = transition[:2]
            ret = transition[2] if jumpkind=='call' else empty_move_dst
            transitions.append({
                'jumpkind':jumpkind,
                'dst':dst,
                'ret':ret})
    len_without_pad = len(transitions)
    if pad_path:
        if pad_path<len(transitions):
            raise Exception('Execution path contains %s transitions. Cannot apply padding of %s moves.'%(len(transitions), pad_path))
        # append empty moves to execution path
        while len(transitions)<pad_path:
            transitions.append({
                'jumpkind':'empty',
                'dst':empty_move_dst,
                'ret':empty_move_dst})
    path={'transitions':transitions,'initial_node':initial_node,'final_node':final_node,'num_transitions_pre_pad':len_without_pad}
    return path

def binify_encoded_adjlist(adjlist_encoded):
    binified = []
    for node,levels in adjlist_encoded:
        neighbors = ''
        for bucket,rems in levels.items():
            neighbors += '%s%s' %(format(rems,'08b'),format(bucket,'0%sb'%int(BUCKET_BITWIDTH)))
        if len(neighbors)==0: neighbors='0'
        binified.append((node, neighbors))
    return binified

def numify_binified_adjlist(adjlist_binified):
    return [(node, int(encoded_neighbors,2)) for node,encoded_neighbors in adjlist_binified]

def binify_path(path):
    binified = []
    for transition in path['transitions']:
        jumpkind,dst,ret = (format(0,'0%sb'%JUMPKIND_BITWIDTH),format(int(transition['dst'],16),'0%sb'%ADDR_BITWIDTH),format(0,'0%sb'%ADDR_BITWIDTH))
        if transition['jumpkind']=='call':
            jumpkind=format(1,'0%sb'%JUMPKIND_BITWIDTH)
            ret=format(int(transition['ret'],16),'0%sb'%ADDR_BITWIDTH)
        elif transition['jumpkind']=='ret':
            jumpkind=format(2,'0%sb'%JUMPKIND_BITWIDTH)
        elif transition['jumpkind']=='empty':
            jumpkind=format(3,'0%sb'%JUMPKIND_BITWIDTH)
        encoded=ret+dst+jumpkind # reverse order
        binified.append(encoded)
    return binified

def numify_binified_path(path):
    return [int(transition, 2) for transition in path]

def hash(padded_list):
    # hash first chunk
    poseidon_state=[0]*9 # empty state
    i=0
    while i<8:
        poseidon_state[i+1]=padded_list[i]
        i+=1
    poseidon_state=poseidon_hash(poseidon_state)

    # hash remaining chunks
    remaining_chunks=int(len(padded_list)/8)-1
    i=0
    while i<remaining_chunks:
        j=0
        while j<8:
            poseidon_state[j+1]=padded_list[(i+1)*8+j]+poseidon_state[j+1]
            j+=1
        poseidon_state=poseidon_hash(poseidon_state)
        i+=1
    return poseidon_state[2]

def compress(tmp_list, elem_bitwidth):
    p_bitwidth=len(format(p,'0b'))
    elems_per_field_element=math.floor(p_bitwidth/elem_bitwidth)
    compressed=[0]*math.ceil(len(tmp_list)/elems_per_field_element)

    print('\telems_per_field_element: %s (using %s-bit p)' %(elems_per_field_element,p_bitwidth))
    print('\toccupies %s field elements after compression' %len(compressed))

    i=0
    while i<len(compressed):
        j=0
        k=0
        tmp_list_idx=i*elems_per_field_element
        while j<elems_per_field_element and tmp_list_idx<len(tmp_list):
            elem=tmp_list[tmp_list_idx]
            compressed[i]=compressed[i]+(elem*2**k)
            j+=1
            k+=elem_bitwidth
            tmp_list_idx+=1
        i+=1
    return compressed

def make_multiple_of(tmp_list, factor=8, extend=0):
    padded_len=int(math.ceil(float(len(tmp_list)+extend)/factor)*factor)
    padded=tmp_list.copy()
    padded.extend([0]*(padded_len-len(tmp_list)))
    return padded

def hash_translator(translator, nonce_translator):
    print('Starting hashing of the translator')
    print('\tADDR_BITWIDTH: %s'%(ADDR_BITWIDTH))

    translator_compressed=compress(translator,ADDR_BITWIDTH)
    translator_padded=make_multiple_of(translator_compressed,8,1) # we consider poseidon with 8 inputs, so we pad the translator to make it divisible by 8 (we reserve one field element for the nonce)

    translator_padded[len(translator_padded)-1]=nonce_translator

    print('\tpadding translator with %s additional field elements (Poseidon call has arity 8 and we need to reserve 1 element for the translator nonce)' %(len(translator_padded)-len(translator_compressed)))
    print('\tcalls to Poseidon needed: %s' %math.ceil(len(translator_padded)/8))

    return hash(translator_padded)

def hash_adjlist(adjlist, levels, nonce_adjlist):
    adjlist=[encoded_neighbors for node,encoded_neighbors in adjlist]

    neighbors_bitwidth=levels*(BUCKET_BITWIDTH+8)

    print('Starting hashing of the encoded adjacency list')
    print('\tneighbors_bitwidth: %s (%s levels * (%s-bit buckets + 8-bit rems))'%(neighbors_bitwidth,levels,BUCKET_BITWIDTH))

    adjlist_compressed=compress(adjlist,neighbors_bitwidth)
    adjlist_padded=make_multiple_of(adjlist_compressed,8,1) # we consider poseidon with 8 inputs, so we pad the adjlist to make it divisible by 8 (we reserve one field element for the nonce)

    adjlist_padded[len(adjlist_padded)-1]=nonce_adjlist

    print('\tpadding compressed path with %s additional field elements (Poseidon call has arity 8 and we need to reserve 1 element for the adjacency list nonce)' %(len(adjlist_padded)-len(adjlist_compressed)))
    print('\tcalls to Poseidon needed: %s' %math.ceil(len(adjlist_padded)/8))

    return hash(adjlist_padded)

def hash_path(path, nonce_verifier, nonce_path):
    transition_bitwidth=JUMPKIND_BITWIDTH+ADDR_BITWIDTH*2

    print('Starting hashing of the execution path')
    print('\ttransition_bitwidth: %s (%s-bit jumpkind||%s-bit dest address||%s-bit ret address)'%(transition_bitwidth,JUMPKIND_BITWIDTH,ADDR_BITWIDTH,ADDR_BITWIDTH))

    path_compressed=compress(path,transition_bitwidth)
    path_padded=make_multiple_of(path_compressed,8,2) # we consider poseidon with 8 inputs, so we pad the path to make it divisible by 8 (we reserve two field elements for the two nonces)

    path_padded[len(path_padded)-2]=nonce_verifier
    path_padded[len(path_padded)-1]=nonce_path

    print('\tpadding compressed path with %s additional field elements (Poseidon call has arity 8 and we need to reserve 2 elements for the verifier and execution path nonces)' %(len(path_padded)-len(path_compressed)))
    print('\tcalls to Poseidon needed: %s' %math.ceil(len(path_padded)/8))

    return hash(path_padded)

def main(in_dir, out_dir, nonce_verifier, nonce_path, nonce_translator, nonce_adjlist):
    numified_adjlist_filename_in = in_dir+NUMIFIED_ADJLIST_FILENAME
    numified_path_filename_in    = in_dir+NUMIFIED_PATH_FILENAME
    recorded_path_filename_in    = in_dir+RECORDED_PATH_FILENAME
    translator_filename_in       = in_dir+TRANSLATOR_FILENAME

    encoded_adjlist_filename_out        = out_dir+'in_encoded_adjlist'
    translator_filename_out             = out_dir+'in_%s'%TRANSLATOR_FILENAME
    recorded_path_filename_out          = out_dir+'in_%s'%RECORDED_PATH_FILENAME
    numified_path_filename_out          = out_dir+'in_%s'%NUMIFIED_PATH_FILENAME
    initial_node_filename_out           = out_dir+'in_initial_node'
    final_node_filename_out             = out_dir+'in_final_node'
    nonce_verifier_filename_out         = out_dir+'in_nonce_verifier'
    nonce_path_filename_out             = out_dir+'in_nonce_path'
    nonce_translator_filename_out       = out_dir+'in_nonce_translator'
    nonce_adjlist_filename_out          = out_dir+'in_nonce_adjlist'
    encoded_adjlist_digest_filename_out = out_dir+'in_encoded_adjlist_digest'
    recorded_path_digest_filename_out   = out_dir+'in_%s_digest'%RECORDED_PATH_FILENAME
    translator_digest_filename_out      = out_dir+'in_%s_digest'%TRANSLATOR_FILENAME

    #############################################################
    ## Create circuit input files for the encoded adjacency list
    adjlist,len_without_pad = read_adjlist(numified_adjlist_filename_in, PAD_ADJLIST)
    adjlist = format_adjlist(adjlist)
    adjlist_encoded  = encode_adjlist(adjlist)
    adjlist_binified = binify_encoded_adjlist(adjlist_encoded)
    adjlist_numified = numify_binified_adjlist(adjlist_binified)

    output='The encoded adjacency list contains %s nodes'%len(adjlist)
    if PAD_ADJLIST: output+=' (%s without padding)'%len_without_pad
    print(output)

    with open(encoded_adjlist_filename_out, 'w') as file_out:
        file_out.write('\n'.join(str(neighbors) for node,neighbors in adjlist_numified))
    print('Wrote encoded adjacency list to file \'%s\'' %encoded_adjlist_filename_out)

    adjlist_hash = hash_adjlist(adjlist_numified, ADJLIST_LEVELS, nonce_adjlist)

    with open(encoded_adjlist_digest_filename_out, 'w') as file_out:
        file_out.write(str(adjlist_hash))
    print('Wrote encoded adjlist digest to file \'%s\''%encoded_adjlist_digest_filename_out)
    print('Encoded adjacency list hash: %s'%adjlist_hash)

    #############################################################
    ## Create circuit input file for translator
    translator,len_without_pad=read_translator(translator_filename_in, PAD_ADJLIST) # the size should follow that of the adjacency list

    output='The translator contains %s addresses'%len(translator)
    if PAD_ADJLIST: output+=' (%s without padding)'%len_without_pad
    print(output)

    with open(translator_filename_out, 'w') as file_out:
        file_out.write('\n'.join(str(addr) for addr in translator))
    print('Wrote translator to file \'%s\'' %translator_filename_out)

    translator_hash=hash_translator(translator, nonce_translator)

    with open(translator_digest_filename_out, 'w') as file_out:
        file_out.write(str(translator_hash))
    print('Wrote translator digest to file \'%s\''%translator_digest_filename_out)
    print('Translator hash: %s'%translator_hash)

    #############################################################
    ## Create circuit input files for the numified execution path
    numified_path=read_path(numified_path_filename_in, PAD_PATH, len(adjlist))

    output='The numified execution path contains %s transitions'%len(numified_path['transitions'])
    if PAD_PATH: output+=' (%s without padding)'%numified_path['num_transitions_pre_pad']
    print(output)

    with open(numified_path_filename_out, 'w') as file_out:
        output=''
        for transition in numified_path['transitions']:
            output+='%s %s\n'%(transition['dst'],transition['ret'])
        file_out.write(output.rstrip())
    print('Wrote numified execution path to file \'%s\'' %numified_path_filename_out)

    with open(initial_node_filename_out, 'w') as file_out:
        file_out.write(numified_path['initial_node'])
    print('Wrote initial node = %s to file \'%s\''%(numified_path['initial_node'],initial_node_filename_out))
    with open(final_node_filename_out, 'w') as file_out:
        file_out.write(numified_path['final_node'])
    print('Wrote final node = %s to file \'%s\''%(numified_path['final_node'],final_node_filename_out))

    #############################################################
    ## Create circuit input files for the nonces
    with open(nonce_verifier_filename_out, 'w') as file_out:
        file_out.write(str(nonce_verifier))
    print('Wrote verifier\'s nonce to file \'%s\''%nonce_verifier_filename_out)
    with open(nonce_path_filename_out, 'w') as file_out:
        file_out.write(str(nonce_path))
    print('Wrote execution path\'s nonce to file \'%s\''%nonce_path_filename_out)
    with open(nonce_translator_filename_out, 'w') as file_out:
        file_out.write(str(nonce_translator))
    print('Wrote translator\'s nonce to file \'%s\''%nonce_translator_filename_out)
    with open(nonce_adjlist_filename_out, 'w') as file_out:
        file_out.write(str(nonce_adjlist))
    print('Wrote adjacency list\'s nonce to file \'%s\''%nonce_adjlist_filename_out)

    #############################################################
    ## Create circuit input files for the recorded execution path
    recorded_path=read_path(recorded_path_filename_in, PAD_PATH, str(hex(EMPTY_DEST_ADDR)))

    output='The recorded execution path contains %s transitions'%len(recorded_path['transitions'])
    if PAD_PATH: output+=' (%s without padding)'%recorded_path['num_transitions_pre_pad']
    print(output)

    with open(recorded_path_filename_out, 'w') as file_out:
        output=''
        for transition in recorded_path['transitions']:
            jumpkind=transition['jumpkind']
            if jumpkind=='jump':jumpkind=0
            elif jumpkind=='call':jumpkind=1
            elif jumpkind=='ret':jumpkind=2
            elif jumpkind=='empty':jumpkind=3
            output+='%s %s %s\n'%(jumpkind,int(transition['dst'],16),int(transition['ret'],16))
        file_out.write(output.rstrip())
    print('Wrote recorded execution path to file \'%s\'' %recorded_path_filename_out)

    recorded_path_binified = binify_path(recorded_path)
    recorded_path_numified = numify_binified_path(recorded_path_binified)
    recorded_path_hash = hash_path(recorded_path_numified, nonce_verifier, nonce_path)

    with open(recorded_path_digest_filename_out, 'w') as file_out:
        file_out.write(str(recorded_path_hash))
    print('Wrote recorded execution path digest to file \'%s\''%recorded_path_digest_filename_out)
    print('Recorded execution path hash: %s'%recorded_path_hash)

def get_min_adjlist_levels(in_dir):
    numified_adjlist_filename_in=in_dir+NUMIFIED_ADJLIST_FILENAME
    adjlist,len_without_pad = read_adjlist(numified_adjlist_filename_in,PAD_ADJLIST)
    adjlist = format_adjlist(adjlist)
    encoded_adjlist = encode_adjlist(adjlist)
    levels_required = len(max([list(levels) for node,levels in encoded_adjlist], key=len))
    return levels_required

def get_min_label_bitwidth(in_dir):
    numified_adjlist_filename_in=in_dir+NUMIFIED_ADJLIST_FILENAME
    adjlist,len_without_pad=read_adjlist(numified_adjlist_filename_in,PAD_ADJLIST)
    max_label=len(adjlist)
    bitwidth=len(format(max_label,'0b'))
    print('The input adjacency list contains %s entries/nodes (i.e., max label is %s, which occupies %s bits)' %(len(adjlist),max_label,bitwidth))
    return bitwidth

def get_min_bucket_bitwidth(in_dir):
    numified_adjlist_filename_in=in_dir+NUMIFIED_ADJLIST_FILENAME
    adjlist,len_without_pad=read_adjlist(numified_adjlist_filename_in,PAD_ADJLIST)
    max_label=len(adjlist) # the final label is used as the empty label
    max_bucket=math.floor(max_label/8)
    max_bucket_bitwidth=len(format(max_bucket,'0b'))
    return max_bucket_bitwidth

def get_min_addr_bitwidth(in_dir):
    adjlist_filename_in=in_dir+ADJLIST_FILENAME
    adjlist,len_without_pad=read_adjlist(adjlist_filename_in,PAD_ADJLIST)
    max_address=0
    for entry in adjlist:
        addresses=entry.split(' ')
        for address in addresses:
            val=int(address,16)
            if val>max_address:
                max_address=val
    bitwidth=len(format(max_address,'0b'))
    print('The maximum address in the input adjacency list is %s and occupies %s bits' %(hex(max_address),bitwidth))
    return bitwidth

def usage():
    print('Usage: %s -a <dir> [options]'%sys.argv[0])
    print('Options:')
    print('  -h                       This help message')
    print('  -a <dir>                 Path to specific target application\'s directory containing the \'adjlist\', \'numified_adjlist\', \'translator\', \'recorded_path\', and \'numified_path\' files')
    print('  --pad-adjlist-to <len>   Pad the adjlist and translator with zeros (empty entries) until their length is <len> (default is to not pad)')
    print('  --pad-path-to <len>      Pad the execution path with zeros (empty moves) until its length is <len> (default is to not pad)')
    print('  --adjlist-levels <num>   Use <num> levels (pairs of bucket-rems) for encoding the adjacency list. Note that this primarily affects the adjacency list compression which is done prior to hashing to reduce the number of calls to Poseidon (default is to use the minimum levels necessary to maximize compression and minimize the size of the generated circuit)')
    print('  --output-dir <dir>       Store the circuit input files in <dir> (default is to store the files in the same directory as the targeted application)')
    print('  --nonce-verifier <num>   Verifier\'s nonce to hash with the execution path (default 0)')
    print('  --nonce-path <num>       Blinding factor (nonce) to hash with the execution path (default 0)')
    print('  --nonce-translator <num> Blinding factor (nonce) to hash with the address-to-label translator (default 0)')
    print('  --nonce-adjlist <num>    Blinding factor (nonce) to hash with the encoded adjacency list (default 0)')
    print('  --label-bitwidth <num>   Use <num> bits to represent each numified destination address when compressing/hashing the numified execution path (default is to use the minimum number of bits as determined by the size of the adjacency list).')
    print('  --bucket-bitwidth <num>  Use <num> bits to represent each quotient (bucket) in the adjacency list encoding (default is to use the miminum number of bits as determined by the length of the adjacency list).')
    print('  --address-bitwidth <num> Use <num> bits to represent each destination address when compressing/hashing the raw/recorded execution path (default is to use the minimum number of bits as determined by the recorded execution path provided as input).')

if __name__ == '__main__':
    in_dir  = None
    out_dir = None
    nonce_verifier   = 0
    nonce_path       = 0
    nonce_translator = 0
    nonce_adjlist    = 0
    try:
        opts,args=getopt.getopt(sys.argv[1:],'ha:',['pad-adjlist-to=','pad-path-to=','adjlist-levels=','output-dir=','nonce-verifier=','nonce-path=','nonce-translator=','nonce-adjlist=','label-bitwidth=','bucket-bitwidth=','address-bitwidth='])
    except getopt.GetoptError as err:
        print(err)
        usage()
        sys.exit(2)
    for opt,arg in opts:
        if opt=='-h':
            usage()
            sys.exit()
        elif opt=='-a':
            if not arg.endswith('/'): arg=arg+'/'
            in_dir=arg
        elif opt=='--pad-adjlist-to':
            PAD_ADJLIST=int(arg)
        elif opt=='--pad-path-to':
            PAD_PATH=int(arg)
        elif opt=='--adjlist-levels':
            ADJLIST_LEVELS=int(arg)
        elif opt=='--output-dir':
            if not arg.endswith('/'): arg=arg+'/'
            out_dir=arg
        elif opt=='--nonce-verifier':
            nonce_verifier=int(arg)
            if len(format(nonce_verifier,'0b'))>=P_BITWIDTH:
                print('%s: the provided verifier nonce is too big. Maximum bitwidth is %s due to the currently considered finite field.'%(sys.argv[0],P_BITWIDTH))
                usage()
                sys.exit()
        elif opt=='--nonce-path':
            nonce_path=int(arg)
            if len(format(nonce_path,'0b'))>=P_BITWIDTH:
                print('%s: the provided execution path nonce is too big. Maximum bitwidth is %s due to the currently considered finite field.'%(sys.argv[0],P_BITWIDTH))
                usage()
                sys.exit()
        elif opt=='--nonce-translator':
            nonce_translator=int(arg)
            if len(format(nonce_translator,'0b'))>=P_BITWIDTH:
                print('%s: the provided translator nonce is too big. Maximum bitwidth is %s due to the currently considered finite field.'%(sys.argv[0],P_BITWIDTH))
                usage()
                sys.exit()
        elif opt=='--nonce-adjlist':
            nonce_adjlist=int(arg)
            if len(format(nonce_adjlist,'0b'))>=P_BITWIDTH:
                print('%s: the provided adjacency list nonce is too big. Maximum bitwidth is %s due to the currently considered finite field.'%(sys.argv[0],P_BITWIDTH))
                usage()
                sys.exit()
        elif opt=='--label-bitwidth':
            LABEL_BITWIDTH=int(arg)
        elif opt=='--bucket-bitwidth':
            BUCKET_BITWIDTH=int(arg)
        elif opt=='--address-bitwidth':
            ADDR_BITWIDTH=int(arg)
    if not in_dir:
        print('%s: fatal error: no application input directory specified \n'%sys.argv[0])
        usage()
        sys.exit()

    min_adjlist_levels=get_min_adjlist_levels(in_dir)
    if not ADJLIST_LEVELS:
        ADJLIST_LEVELS=min_adjlist_levels
    else:
        if min_adjlist_levels>ADJLIST_LEVELS:
            print('%s: the encoded adjacency list requires minimum %s levels.'%(sys.argv[0],min_adjlist_levels))
            usage()
            sys.exit()
    min_label_bitwidth=get_min_label_bitwidth(in_dir)
    if not LABEL_BITWIDTH:
        LABEL_BITWIDTH=min_label_bitwidth
    else:
        if min_label_bitwidth>LABEL_BITWIDTH:
            print('%s: the provided label bitwidth is too small. Minimum bitwidth is %s.'%(sys.argv[0],min_label_bitwidth))
            usage()
            sys.exit()
    min_bucket_bitwidth=get_min_bucket_bitwidth(in_dir)
    if not BUCKET_BITWIDTH:
        BUCKET_BITWIDTH=min_bucket_bitwidth
    else:
        if min_bucket_bitwidth>BUCKET_BITWIDTH:
            print('%s: the provided bucket bitwidth is too small. Minimum bitwidth is %s.'%(sys.argv[0],min_bucket_bitwidth))
            usage()
            sys.exit()
    min_addr_bitwidth=get_min_addr_bitwidth(in_dir)
    if not ADDR_BITWIDTH:
        ADDR_BITWIDTH=min_addr_bitwidth
    else:
        if min_addr_bitwidth>ADDR_BITWIDTH:
            print('%s: the provided address bitwidth is too small. Minimum bitwidth is %s.'%(sys.argv[0],min_addr_bitwidth))
            usage()
            sys.exit()
    encoded_neighbors_bitwidth=(BUCKET_BITWIDTH+8)*ADJLIST_LEVELS
    if encoded_neighbors_bitwidth>=P_BITWIDTH:
        print('%s: (BUCKET_BITWIDTH+8)*ADJ_LIST_LEVELS is %s which exceeds p\'s bitwidth of %s bits (see the implementation notes)'%(sys.argv[0],encoded_neighbors_bitwidth,P_BITWIDTH))
        usage()
        sys.exit()
    if not out_dir:
        out_dir=in_dir

    print('Minimum:     ADJLIST_LEVELS=%s LABEL_BITWIDTH=%s BUCKET_BITWIDTH=%s ADDR_BITWIDTH=%s' %(min_adjlist_levels,min_label_bitwidth,min_bucket_bitwidth,min_addr_bitwidth))
    print('Considering: ADJLIST_LEVELS=%s LABEL_BITWIDTH=%s BUCKET_BITWIDTH=%s ADDR_BITWIDTH=%s\n' %(ADJLIST_LEVELS,LABEL_BITWIDTH,BUCKET_BITWIDTH,ADDR_BITWIDTH))

    main(in_dir, out_dir, nonce_verifier, nonce_path, nonce_translator, nonce_adjlist)


from PyQt5 import QtGui
from PyQt5.QtGui import QIcon
from PyQt5.QtWidgets import QWidget

import ResourceNavigator
from back.css.style import cssLoader
from back.osuLoader.AppBackend import AppBackendInit
from view.window.osuLoader.layout.OsuLoaderWindowLayout import OsuLoaderWindowLayout

class OsuLoaderWindow(QWidget):
    osuLoaderWindowLayout = OsuLoaderWindowLayout
    appBackend = AppBackendInit

    def __init__(self):
        super(OsuLoaderWindow, self).__init__()

        print("Open OsuLoaderWindow")

        self.initUI()

    def initUI(self):
        print("Init UI...")

        self.setWindowTitle(ResourceNavigator.Variables.Strings.osuLoaderWindowName)

        self.setWindowIcon(QIcon(ResourceNavigator.MaterialNavigator.icoLogo))

        self.initFonts()

        self.initStyles()

        self.osuLoaderWindowLayout = OsuLoaderWindowLayout()

        self.appBackend = AppBackendInit(self.osuLoaderWindowLayout)

        self.setLayout(self.osuLoaderWindowLayout)

        self.setMinimumSize(1280, 720)

        self.appBackend.postInit()

        self.show()

    def initStyles(self):
        print("Init styles...")
        loader = cssLoader()
        css = loader.getStyleSheet()
        self.setStyleSheet(css)

    def initFonts(self):
        print("Init fonts...")
        QtGui.QFontDatabase.addApplicationFont(ResourceNavigator.FontsNavigator.fontExoRegular)
        QtGui.QFontDatabase.addApplicationFont(ResourceNavigator.FontsNavigator.fontExoThin)
        QtGui.QFontDatabase.addApplicationFont(ResourceNavigator.FontsNavigator.fontExoBold)


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

"""
Created on dim 07 fév 2021 09:27:34 UTC

@author: vekemans

"""

import time
import math as mt
import numpy as np
import scipy.sparse as spr
import matplotlib.pyplot as plt
nfig = 1

pi = mt.pi
# -----------------------------------------------
# Orginal Signal
N = np.power(2,12)
h = 2*pi / N
x = -pi + np.arange(1,N+1)*h

u = np.exp(np.sin(x))
uprime = np.cos(x) * u

plt.figure(nfig)
plt.plot(x,u, 'k--', label=r"$u$")
plt.plot(x,uprime, 'k', label=r"$u'$")
plt.title("Function $e^{sin(x)}$ and its derivative")
plt.legend()
plt.grid()
nfig += 1

# -----------------------------------------------
Nvec = np.power(2, np.arange(3,13))
timevec = np.zeros(Nvec.shape)

plt.figure(nfig)

for (i,N) in enumerate(Nvec):
	t = time.time()
	h = 2*pi / N
	x = -pi + np.arange(1,N+1)*h

	u = np.exp(np.sin(x))
	uprime = np.cos(x)*u

	# Construct the differentiation matrix
	e = np.ones(N)
	row = np.arange(0,N)
	col1 = np.append(np.arange(1,N), [0])
	col2 = np.append(np.arange(2,N), [0,1])
	D = spr.csr_matrix((2.*e/3., (row,col1)), shape=(N,N)) \
		- spr.csr_matrix((e/12., (row,col2)), shape=(N,N))
	D = (D - D.transpose())/h

	# Plot max(abs(D*u - uprime))
	error = max(np.abs(D*u - uprime))
	plt.loglog(N, error, 'ko')
	timevec[i] = time.time() - t

plt.loglog(Nvec, np.float64(Nvec)**(-4), 'k--')
plt.text(100, 1e-10, '$N^{-4}$', fontsize=14)
plt.title("Convergence of fourth-order finite differences")
plt.xlabel('$N$')
plt.ylabel('Error')
plt.grid(which='both', linestyle='--', linewidth=.5)
nfig += 1

# plt.figure(nfig)
# plt.loglog(Nvec, timevec, 'ko')
# plt.title(" ")
# plt.xlabel("$N$")
# plt.ylabel("Time [s]")
# plt.grid()
# nfig += 1

# -----------------------------------------------
plt.show()