import numpy, time
import math
import itertools
from mapa import *
import sys
from tkinter import *
from PIL import ImageTk, Image
import os

##   Esta classe detém a implementação do algorítmo A*
class A_star(object):

    ##  Construtor da classe
    #   @param linhas Quantidade de linhas da matriz a ser gerada
    #   @param colunas Quantidade de colunas da matriz a ser gerada
    def __init__(self, linhas, colunas, height, width):
        ##  @var nodos_fechados
        #   @brief Guarda todos os nodos que já foram inspecionados
        self.nodos_fechados = []
        ##  @var nodos_abertos
        #   @brief Guarda todos os nodos que foram abertos por outro nodo
        self.nodos_abertos = []
        ##  @var nodo_atual
        #   @brief Detém o nodo atual da busca
        self.nodo_atual = None
        ##  @var nodo_objetivo
        #   @brief Detém o nodo escolhido como objetivo
        self.nodo_objetivo = None
        ##  @var mapa
        #   @brief  Uma instancia da classe Mapa
        self.height = height
        self.width = width
        self.mapa = Mapa(linhas, colunas)

    ##  Método da classe
    #   @param nodo Recebe um objeto da classe Nodo
    #   @brief Calcula o valor da função heurística h(x), que consiste na distância entre o nodo
    #   passado como parâmetro e o nodo objetivo
    #   @return Retorna a distância calculada
    def calcula_h(self, nodo):
        linha_objetivo, coluna_objetivo = self.mapa.obter_posicao(self.nodo_objetivo)
        linha_nodo, coluna_nodo = self.mapa.obter_posicao(nodo)
        abs_x = int(math.fabs(linha_objetivo - linha_nodo + 1))
        abs_y = int(math.fabs(coluna_objetivo - coluna_nodo + 1))

        return abs_y + abs_x

    ##  Método da classe
    #   @param linha Recebe o número da linha
    #   @param coluna Recebe o número da coluna
    #   @brief Seta o objetivo na posição do mapa indicado pelos parâmetros: linha e coluna
    def define_objetivo(self, linha, coluna):
        self.mapa.grade[linha][coluna].objetivo = True
        self.nodo_objetivo = self.mapa.grade[linha][coluna]

    ##  Método da classe
    #   @param linha Recebe o número da linha
    #   @param coluna Recebe o número da coluna
    #   @brief Seta o inicio na posição do mapa indicado pelos parâmetros: linha e coluna
    def define_inicio(self, linha, coluna):
        self.mapa.grade[linha][coluna].inicio = True
        self.nodo_atual = self.mapa.grade[linha][coluna]
        self.nodos_abertos.append(self.nodo_atual)

    ##  Método da classe
    #   @param linha Recebe o número da linha
    #   @param coluna Recebe o número da coluna
    #   @brief Bloqueia um nodo indicado pelos parâmetros: linha e coluna
    def bloqueia_nodo(self, linha, coluna):
        self.mapa.grade[linha][coluna].bloqueado = True

    ##  Método da classe
    #   @param nodo Recebe um objeto da classe Nodo
    #   @brief Calcula o valor da função de custo total f(x) = h(x) + g(x) e
    #   seta o nodo_atual como o nodo_pai do nodo passado como parâmetro
    #   @return None caso o nodo ainda não exista em nenhuma das listas (nodos_fechados e nodos_abertos),
    #   True caso o nodo exista em alguma das listas e o valor do f foi efetivamente trocado, False caso
    #   ele exista em alguma das listas e o valor do f não foi trocado.
    def calcula_f(self, nodo):
        if nodo:
            flag = None
            g_aux = 1 + self.nodo_atual.g
            if nodo.f == 0:
                nodo.g = g_aux
                nodo.h = self.calcula_h(nodo)
                nodo.f = g_aux + nodo.h
                nodo.nodo_pai = self.nodo_atual
            else:
                if g_aux < nodo.g:
                    flag = True
                    nodo.g = g_aux
                    nodo.f = g_aux + nodo.h
                    nodo.nodo_pai = self.nodo_atual
                else:
                    flag = False
        return flag

    ##  Método da classe
    #   @brief Obtém dos nodos vizinhos(direita, esquerda, cima, baixo) do nodo atual
    #   @return Retorna os vizinhos do nodo
    def obter_vizinhos(self):
        matrix_linhas = len(self.mapa.grade) - 1
        matrix_colunas = len(self.mapa.grade[0]) - 1
        linha_atual, coluna_atual = self.mapa.obter_posicao(self.nodo_atual)
        if (coluna_atual - 1) >= 0:
            if not self.mapa.grade[linha_atual][coluna_atual - 1].bloqueado:
                vizinho_esquerda = self.mapa.grade[linha_atual][coluna_atual - 1]
            else:
                vizinho_esquerda = None
        else:
            vizinho_esquerda = None
        if (coluna_atual + 1) <= matrix_colunas:
            if not self.mapa.grade[linha_atual][coluna_atual + 1].bloqueado:
                vizinho_direita = self.mapa.grade[linha_atual][coluna_atual + 1]
            else:
                vizinho_direita = None
        else:
            vizinho_direita = None
        if (linha_atual - 1) >= 0:
            if not self.mapa.grade[linha_atual - 1][coluna_atual].bloqueado:
                vizinho_cima = self.mapa.grade[linha_atual - 1][coluna_atual]
            else:
                vizinho_cima = None
        else:
            vizinho_cima = None
        if (linha_atual + 1) <= matrix_linhas:
            if not self.mapa.grade[linha_atual + 1][coluna_atual].bloqueado:
                vizinho_baixo = self.mapa.grade[linha_atual + 1][coluna_atual]
            else:
                vizinho_baixo = None
        else:
            vizinho_baixo = None

        return vizinho_esquerda, vizinho_direita, vizinho_baixo, vizinho_cima

    ##  Método da classe
    #   @param nodo Recebe um objeto da classe Nodo
    #   @brief Calcula o custo f do nodo, caso ele estreja presente na lista de nodos fechados
    #   e o valor de f foi alterado então ele é recolocado na lista de nodos abertos novamente,
    #   caso o nodo não esteja presente em nenhuma das listas (nodos_fechados e nodos_abertos), então
    #   ele é adicionado na lista de nodos_abertos
    def abre_nodo(self, nodo):
        if nodo and not nodo.inicio:
            flag = self.calcula_f(nodo)
            if flag is not None:
                if flag:
                    for fechados in self.nodos_fechados:
                        if fechados:
                            if fechados == nodo:
                                self.nodos_fechados.remove(nodo)
                                self.nodos_abertos.append(nodo)
                                break
            else:
                self.nodos_abertos.append(nodo)

    ##  Método da classe
    #   @brief Fecha o nodo atual, removendo-o da lista nodos_abertos e inserindo-o na lista
    #   nodos_fechados
    def fecha_nodo(self):
        self.nodos_abertos.remove(self.nodo_atual)
        self.nodos_fechados.append(self.nodo_atual)

    ##  Método da classe
    #   @brief Verifica dentre os nodos da lista nodos_abertos aquele com o menor custo e coloca-o
    #   como nodo atual
    #   @return Retorna True caso exista algum valor na lista, False caso contrário
    def muda_nodo(self):
        f = math.inf
        if self.nodos_abertos:
            for iterator in self.nodos_abertos:
                if iterator.f < f:
                    f = iterator.f
                    nodo = iterator
            self.nodo_atual = nodo
            return True
        else:
            return False

    ##  Método da classe
    #   @param nodo Recebe um objeto da classe tkinter.Tk
    #   @brief A partir do nodo atual, percorre através dos nodo_pai até não existir mais nenhum
    #   e substitui na interface grafica a imagem do nodo atual, para identificar o caminho percorrido.
    #   @brief Além de imprimir no terminal o custo total até o nodo objetivo
    def imprime_caminho(self, root):
        iterador_nodo = self.nodo_atual
        print("Custo total = {}".format(iterador_nodo.f))
        while iterador_nodo is not None:
            linha, coluna = self.mapa.obter_posicao(iterador_nodo)
            im = Image.open(os.path.join(r'.', 'path.jpg'))
            resized = im.resize((int(self.width), int(self.height)), Image.NEAREST)
            tkimage = ImageTk.PhotoImage(resized)
            myvar = Label(root, image=tkimage)
            myvar.image = tkimage
            myvar.grid(row=linha, column=coluna)
            iterador_nodo = iterador_nodo.nodo_pai

    ##  Método da classe
    #   @brief Imprime a lista nodos_abertos, mostrando a posição do nodo e seu custo
    def imprime_nodos(self):
        linha, coluna = self.mapa.obter_posicao(self.nodo_atual)
        print("Nodo atual: [{}][{}]".format(linha, coluna))
        print("[Nodos abertos:\n")
        for nodos in self.nodos_abertos:
            linha, coluna = self.mapa.obter_posicao(nodos)
            print("nó = [{}][{}], custo = {}".format(linha, coluna, nodos.f))
        print("]")

    ##  Método da classe
    #   @param nodo Recebe um objeto da classe tkinter.Tk
    #   @brief A partir do nodo atual, abre todos os seus nodos vizinhos e muda para o próximo nodo
    #   de acordo com a função @link muda_nodo()@endlink, até encontrar o nodo objetivo
    def busca_solucao(self, root):
        while True:
            self.fecha_nodo()
            if self.nodo_atual.objetivo:
                self.imprime_caminho(root)
                dialog = Toplevel(root)
                Label(dialog, text="Busca concluída!").pack(pady=5)
                break
            vizinho_esquerda, vizinho_direita, vizinho_baixo, vizinho_cima = self.obter_vizinhos()
            self.abre_nodo(vizinho_direita)
            self.abre_nodo(vizinho_esquerda)
            self.abre_nodo(vizinho_cima)
            self.abre_nodo(vizinho_baixo)
            self.imprime_nodos()
            if not self.muda_nodo():
                self.imprime_caminho(root)
                dialog = Toplevel(root)
                Label(dialog, text="Não foi possível concluir a busca!").pack(pady=5)
                break


#!/usr/bin/env python

import os
import rospy
from duckietown import DTROS
from std_msgs.msg import String
from duckietown_msgs.msg import Twist2DStamped, WheelsCmdStamped, LanePose
import numpy as np

class MyNode(DTROS):

    def __init__(self, node_name):
        # initialize the DTROS parent class
        super(MyNode, self).__init__(node_name=node_name)
        # construct publisher
        self.pub_wheels_cmd = self.publisher(str(os.environ['VEHICLE_NAME'])+"/wheels_driver_node/wheels_cmd", WheelsCmdStamped, queue_size=1)
        #subscriber
        self.sub_pose = rospy.Subscriber("marschla/lane_filter_node/lane_pose", LanePose, self.control, queue_size=1)
        #shutdown procedure
        rospy.on_shutdown(self.custom_shutdown)
        #def. variables
        self.vdiff = 0
        self.vref = 0.25
        self.dist = 0
        #self.k_p

    def getvdiff(self,dist):
        k_p = 1
        vdiff = k_p*dist
        return vdiff

    def run(self):
        # publish message every 1/x second
        rate = rospy.Rate(10) # 1Hz
        car_cmd_msg = WheelsCmdStamped()
        tnew = car_cmd_msg.header.stamp
        while not rospy.is_shutdown():

            self.vdiff = self.getvdiff(self.dist)

            #def. motor commands that will be published
            car_cmd_msg.header.stamp = rospy.get_rostime()
            car_cmd_msg.vel_left = self.vref + self.vdiff
            car_cmd_msg.vel_right = self.vref - self.vdiff

            self.pub_wheels_cmd.publish(car_cmd_msg)

            #printing messages to verfy that program is working
            told = tnew
            tnew = car_cmd_msg.header.stamp
            dt = tnew-told
            message = self.vdiff
            rospy.loginfo('Printed: %s' % message)
            rate.sleep()

        #shutdown procedure, stopping motor movement etc.
    def custom_shutdown(self):
        stop_msg = WheelsCmdStamped()
        stop_msg.header.stamp = rospy.get_rostime()
        stop_msg.vel_left = 0.0
        stop_msg.vel_right = 0.0
        self.pub_wheels_cmd.publish(stop_msg)
        rospy.sleep(0.5)
        rospy.loginfo("Shutdown complete oder?")

    def control(self,pose):
        self.dist = pose.d
        message = pose.d
        #rospy.loginfo('d =  %s' % message)

if __name__ == '__main__':
    # create the node
    node = MyNode(node_name='my_node')
    # run node
    node.run()
    # keep spinning
    rospy.spin()


# -*- coding: utf-8 -*-
from five import grok
from zope import schema
from plone.directives import form
from plone.app.textfield import RichText
from plone.namedfile.field import NamedFile
from plone.formwidget.multifile import MultiFileFieldWidget
from plone.directives import dexterity
from genweb.rectorat import _
from plone.app.dexterity import PloneMessageFactory as _PMF
from z3c.form.interfaces import INPUT_MODE, DISPLAY_MODE, HIDDEN_MODE
from collective import dexteritytextindexer
from genweb.rectorat import utils

class IActa(form.Schema):
    """ Tipus Sessio: Per a cada Òrgan de Govern es podran crear
        totes les sessions que es considerin oportunes
    """
    dexteritytextindexer.searchable('title')
    title = schema.TextLine(
        title=_PMF(u'label_title', default=u'Title'),
        required=True
    )

    dataSessio = schema.Date(
        title=_(u"Session date"),
        required=True,
    )

    llocConvocatoria = schema.TextLine(
        title=_(u"Session place"),
        required=False,
    )

    horaInici = schema.Time(
        title=_(u"Session start time"),
        required=False,
    )

    horaFi = schema.Time(
        title=_(u"Session end time"),
        required=False,
    )

    dexteritytextindexer.searchable('membresConvocats')
    membresConvocats = RichText(
        title=_(u"Attending members"),
        required=False,
    )

    dexteritytextindexer.searchable('membresConvidats')
    membresConvidats = RichText(
        title=_(u"Invited members"),
        required=False,
    )

    dexteritytextindexer.searchable('llistaExcusats')
    llistaExcusats = RichText(
        title=_(u"Excused members"),
        required=False,
    )

    dexteritytextindexer.searchable('llistaNoAssistens')
    llistaNoAssistens = RichText(
        title=_(u"Missing members"),
        required=False,
    )

    dexteritytextindexer.searchable('ordreSessio')
    ordreSessio = RichText(
        title=_(u"Session order"),
        required=False,
    )

    dexteritytextindexer.searchable('actaBody')
    actaBody = RichText(
        title=_(u"Acta Body"),
        required=False,
    )

    dexteritytextindexer.searchable('footer')
    footer = RichText(
        title=_(u"Footer"),
        required=False,
    )

    dexteritytextindexer.searchable('OriginalFiles')
    form.widget(OriginalFiles=MultiFileFieldWidget)
    OriginalFiles = schema.List(title=_(u"Files"),
                                description=_(u"Attached files description"),
                                value_type=NamedFile(),
                                required=False,)

@form.default_value(field=IActa['membresConvidats'])
def membresConvidatsDefaultValue(data):
    # copy membresConvidats from Session (parent object)
    return data.context.membresConvidats

@form.default_value(field=IActa['membresConvocats'])
def membresConvocatsDefaultValue(data):
    # copy membresConvocats from Session (parent object)
    return data.context.membresConvocats

@form.default_value(field=IActa['llistaExcusats'])
def llistaExcusatsDefaultValue(data):
    # copy llistaExcusats from Session (parent object)
    return data.context.llistaExcusats

@form.default_value(field=IActa['ordreSessio'])
def ordreSessioDefaultValue(data):
    # copy ordreSessio from Session (parent object)
    return data.context.ordreSessio

@form.default_value(field=IActa['actaBody'])
def actaBodyDefaultValue(data):
    # copy ordreSessio from Session in Acta
    return data.context.ordreSessio

# Hidden field used only to render and generate the PDF
@form.default_value(field=IActa['dataSessio'])
def dataSessioDefaultValue(data):
    # copy dataSessio from Session (parent object)
    return data.context.dataSessio

# Hidden field used only to render and generate the PDF
@form.default_value(field=IActa['llocConvocatoria'])
def llocConvocatoriaDefaultValue(data):
    # copy llocConvocatoria from Session (parent object)
    return data.context.llocConvocatoria

# Hidden field used only to render and generate the PDF
@form.default_value(field=IActa['horaInici'])
def horaIniciDefaultValue(data):
    # copy horaInici from Session (parent object)
    return data.context.horaInici

# Hidden field used only to render and generate the PDF
@form.default_value(field=IActa['horaFi'])
def horaFiDefaultValue(data):
    # copy horaFi from Session (parent object)
    return data.context.horaFi

class View(dexterity.DisplayForm):
    grok.context(IActa)
    grok.template('acta_view')

    def isReader(self):
        return utils.isReader(self)

class Edit(dexterity.EditForm):
    """A standard edit form.
    """
    grok.context(IActa)

    def updateWidgets(self):
        super(Edit, self).updateWidgets()
        # Desactivem el hidden dels camps, sembla que no sigui necessari
        # self.widgets['dataSessio'].mode = HIDDEN_MODE
        # self.widgets['llocConvocatoria'].mode = HIDDEN_MODE
        # self.widgets['horaInici'].mode = HIDDEN_MODE
        # self.widgets['horaFi'].mode = HIDDEN_MODE


import bpy

from shape_keys_plus import core

class DRIVER_OT_skp_variable_move(bpy.types.Operator):
    bl_idname = 'driver.skp_variable_move'
    bl_label = core.strings['operators.VariableMove.bl_label']
    bl_description = core.strings['operators.VariableMove.bl_description']
    bl_options = {'REGISTER', 'UNDO'}

    index: bpy.props.IntProperty(options={'HIDDEN'})

    type: bpy.props.EnumProperty(
        items=(
            ('TOP', "", ""),
            ('UP', "", ""),
            ('DOWN', "", ""),
            ('BOTTOM', "", "")
        ),
        options={'HIDDEN'})

    @classmethod
    def poll(cls, context):
        return context.object and context.object.active_shape_key

    def execute(self, context):
        driver = core.key.get_driver(context.object.active_shape_key)

        if driver and len(driver.variables) > self.index:
            vars = list(driver.variables)

            if self.type == 'TOP':
                vars.insert(0, vars.pop(self.index))
            elif self.type == 'UP' and self.index > 0:
                vars.insert(self.index - 1, vars.pop(self.index))
            elif self.type == 'DOWN' and self.index < len(vars) - 1:
                vars.insert(self.index + 1, vars.pop(self.index))
            elif self.type == 'BOTTOM':
                vars.insert(len(vars) - 1, vars.pop(self.index))

            core.driver.reconstruct_variables(driver, vars)

        return {'FINISHED'}


import HeapSort as hs
import math
'''
We generally have two operations: insert (to the back) and
extract (from the front)
'''
def parent(index):
    parent = int((index - 1) / 2)
    print(parent)
    return parent

def extract_max(arr):
    size = len(arr)
    if (size < 1):
        print("Error!")
        return
    max_ele = arr[0]
    arr[0], arr[size - 1] = arr[size - 1], arr[0]
    heap_size = size - 1
    hs.max_heapify(arr, heap_size, 0)
    # arr = arr[0:size - 1]
    del arr[size - 1]
    return max_ele

def increase(arr, index, new_element):
    if (new_element <= arr[index]):
        print("New element smaller than original value!")
        return
    arr[index] = new_element
    while (parent(index) >= 0) and (arr[index] > arr[parent(index)]):
        arr[index], arr[parent(index)] = arr[parent(index)], arr[index]
        index = parent(index)

def insert(arr, new_element):
    heap_size = len(arr)
    heap_size += 1
    arr += [new_element - 1]
    increase(arr, heap_size - 1, new_element)

arr = []
insert(arr, 5)
insert(arr, 100)
insert(arr, -16)
insert(arr, 99)
insert(arr, 24)
insert(arr, 6)

print(arr)

increase(arr, 3, 2037)

print(arr)

print(extract_max(arr))
print(extract_max(arr))
print(extract_max(arr))
print(extract_max(arr))
print(extract_max(arr))
print(arr)


# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import models, migrations

class Migration(migrations.Migration):

    dependencies = [
    ]

    operations = [
        migrations.CreateModel(
            name='Movies',
            fields=[
                ('id', models.AutoField(verbose_name='ID', serialize=False, primary_key=True, auto_created=True)),
                ('name', models.CharField(max_length=200, unique=True)),
                ('rating', models.FloatField()),
            ],
        ),
        migrations.CreateModel(
            name='Projections',
            fields=[
                ('id', models.AutoField(verbose_name='ID', serialize=False, primary_key=True, auto_created=True)),
                ('movie_id', models.IntegerField()),
                ('movie_type', models.CharField(max_length=200)),
                ('date', models.DateTimeField(verbose_name='projection date')),
                ('time', models.DateTimeField(verbose_name='time of projection')),
            ],
        ),
        migrations.CreateModel(
            name='Reservations',
            fields=[
                ('id', models.AutoField(verbose_name='ID', serialize=False, primary_key=True, auto_created=True)),
                ('username', models.CharField(max_length=200)),
                ('row', models.IntegerField()),
                ('col', models.IntegerField()),
                ('projection_id', models.ForeignKey(to='Kino.Projections')),
            ],
        ),
    ]


""" Test exporting TDMS data to HDF
"""
import pytest
import numpy as np
try:
    import h5py
except ImportError:
    pytest.skip("Skipping HDF tests as h5py is not installed", allow_module_level=True)

from nptdms import TdmsFile
from nptdms.test.util import (
    GeneratedFile,
    basic_segment,
    channel_metadata,
    compare_arrays,
    hexlify_value,
    segment_objects_metadata,
    string_hexlify,
)
from nptdms.test import scenarios

def test_hdf_channel_data(tmp_path):
    """ Test basic conversion of channel data to HDF
    """
    test_file, expected_data = scenarios.single_segment_with_two_channels().values

    tdms_data = test_file.load()
    h5_path = tmp_path / 'h5_data_test.h5'
    h5 = tdms_data.as_hdf(h5_path)

    for ((group, channel), expected_data) in expected_data.items():
        h5_channel = h5[group][channel]
        assert h5_channel.dtype.kind == 'i'
        np.testing.assert_almost_equal(h5_channel[...], expected_data)
    h5.close()

def test_streaming_to_hdf(tmp_path):
    """ Test conversion of channel data to HDF when streaming data from disk
    """
    test_file, expected_data = scenarios.chunked_segment().values

    with test_file.get_tempfile() as temp_file:
        with TdmsFile.open(temp_file.file) as tdms_file:
            h5_path = tmp_path / 'h5_streaming_data_test.h5'
            h5 = tdms_file.as_hdf(h5_path)

    for ((group, channel), expected_data) in expected_data.items():
        h5_channel = h5[group][channel]
        np.testing.assert_almost_equal(h5_channel[...], expected_data)
    h5.close()

def test_int_data_types(tmp_path):
    """ Test conversion of signed and unsigned integer types to HDF
    """
    test_file = GeneratedFile()
    test_file.add_segment(
        ("kTocMetaData", "kTocRawData", "kTocNewObjList"),
        segment_objects_metadata(
            channel_metadata("/'group'/'i8'", 1, 4),
            channel_metadata("/'group'/'u8'", 5, 4),
            channel_metadata("/'group'/'i16'", 2, 4),
            channel_metadata("/'group'/'u16'", 6, 4),
            channel_metadata("/'group'/'i32'", 3, 4),
            channel_metadata("/'group'/'u32'", 7, 4),
            channel_metadata("/'group'/'i64'", 4, 4),
            channel_metadata("/'group'/'u64'", 8, 4),
        ),
        "01 02 03 04"
        "01 02 03 04"
        "01 00 02 00 03 00 04 00"
        "01 00 02 00 03 00 04 00"
        "01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00"
        "01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00"
        "01 00 00 00 00 00 00 00 02 00 00 00 00 00 00 00 03 00 00 00 00 00 00 00 04 00 00 00 00 00 00 00"
        "01 00 00 00 00 00 00 00 02 00 00 00 00 00 00 00 03 00 00 00 00 00 00 00 04 00 00 00 00 00 00 00"
    )

    tdms_data = test_file.load()
    h5_path = tmp_path / 'h5_data_test.h5'
    h5 = tdms_data.as_hdf(h5_path)

    for chan, expected_dtype in [
            ('i8', np.dtype('int8')),
            ('u8', np.dtype('uint8')),
            ('i16', np.dtype('int16')),
            ('u16', np.dtype('uint16')),
            ('i32', np.dtype('int32')),
            ('u32', np.dtype('uint32')),
            ('i64', np.dtype('int64')),
            ('u64', np.dtype('uint64'))]:
        h5_channel = h5['group'][chan]
        assert h5_channel.dtype == expected_dtype
        np.testing.assert_almost_equal(h5_channel[...], [1, 2, 3, 4])
    h5.close()

def test_floating_point_data_types(tmp_path):
    """ Test conversion of f32 and f64 types to HDF
    """
    test_file = GeneratedFile()
    test_file.add_segment(
        ("kTocMetaData", "kTocRawData", "kTocNewObjList"),
        segment_objects_metadata(
            channel_metadata("/'group'/'f32'", 9, 4),
            channel_metadata("/'group'/'f64'", 10, 4),
        ),
        hexlify_value('<f', 1) +
        hexlify_value('<f', 2) +
        hexlify_value('<f', 3) +
        hexlify_value('<f', 4) +
        hexlify_value('<d', 1) +
        hexlify_value('<d', 2) +
        hexlify_value('<d', 3) +
        hexlify_value('<d', 4)
    )

    tdms_data = test_file.load()
    h5_path = tmp_path / 'h5_data_test.h5'
    h5 = tdms_data.as_hdf(h5_path)

    for chan, expected_dtype in [
            ('f32', np.dtype('float32')),
            ('f64', np.dtype('float64'))]:
        h5_channel = h5['group'][chan]
        assert h5_channel.dtype == expected_dtype
        np.testing.assert_almost_equal(h5_channel[...], [1.0, 2.0, 3.0, 4.0])
    h5.close()

def test_timestamp_data(tmp_path):
    """ Test conversion of timestamp channel data to HDF
        HDF doesn't support timestamps natively, so these are converted to strings
    """

    test_file, expected_data = scenarios.timestamp_data().values
    tdms_data = test_file.load()
    h5_path = tmp_path / 'h5_timestamp_test.h5'
    h5 = tdms_data.as_hdf(h5_path)

    for (group, channel), expected_values in expected_data.items():
        h5_channel = h5[group][channel]
        assert h5_channel.dtype.kind == 'S'
        expected_strings = np.datetime_as_string(expected_values, unit='us', timezone='UTC')
        expected_ascii = [s.encode('ascii') for s in expected_strings]
        compare_arrays(h5_channel[...], expected_ascii)
    h5.close()

def test_hdf_properties(tmp_path):
    """ Test properties are converted to attributes in HDF files
    """
    test_file = GeneratedFile()
    test_file.add_segment(*basic_segment())
    tdms_data = test_file.load()

    h5_path = tmp_path / 'h5_properties_test.h5'
    h5 = tdms_data.as_hdf(h5_path)

    # File level properties
    assert h5.attrs['num'] == 15

    # Group properties
    assert h5['Group'].attrs['prop'] == 'value'
    assert h5['Group'].attrs['num'] == 10

    # Channel properties
    assert h5['Group']['Channel2'].attrs['wf_start_offset'] == 0.0
    assert h5['Group']['Channel2'].attrs['wf_increment'] == 0.1

def test_timestamp_property(tmp_path):
    """ Test a timestamp property is converted to an attribute in an HDF file
        HDF doesn't support timestamps natively, so these are converted to strings
    """
    test_file = GeneratedFile()
    properties = {
        "wf_start_time": (0x44, hexlify_value("<Q", 0) + hexlify_value("<q", 3524551547))
    }
    test_file.add_segment(
        ("kTocMetaData", "kTocRawData", "kTocNewObjList"),
        segment_objects_metadata(
            channel_metadata("/'group'/'channel1'", 3, 2, properties),
        ),
        "01 00 00 00" "02 00 00 00"
    )
    tdms_data = test_file.load()

    h5_path = tmp_path / 'h5_properties_test.h5'
    h5 = tdms_data.as_hdf(h5_path)

    assert h5['group']['channel1'].attrs['wf_start_time'] == b'2015-09-08T10:05:47.000000Z'

def test_as_hdf_string(tmp_path):
    """ Test HDF5 conversion for string datatype
    """
    strings = ["abc123", "?<>~`!@#$%^&*()-=_+,.;'[]:{}|"]

    test_file = GeneratedFile()
    toc = ("kTocMetaData", "kTocRawData", "kTocNewObjList")
    metadata = (
        # Number of objects
        "01 00 00 00"
        # Length of the object path
        "11 00 00 00")
    metadata += string_hexlify("/'Group'/'String'")
    metadata += (
        # Length of index information
        "1C 00 00 00"
        # Raw data data type
        "20 00 00 00"
        # Dimension
        "01 00 00 00"
        # Number of raw data values
        "02 00 00 00"
        "00 00 00 00"
        # Number of bytes in data
        "2B 00 00 00"
        "00 00 00 00"
        # Number of properties (0)
        "00 00 00 00")
    data = (
        "06 00 00 00"  # index to after first string
        "24 00 00 00"  # index to after second string
    )
    for string in strings:
        data += string_hexlify(string)
    test_file.add_segment(toc, metadata, data)
    tdms_data = test_file.load()

    data = tdms_data["Group"]["String"].data
    assert len(data) == len(strings)
    for expected, read in zip(strings, data):
        assert expected == read

    h5_path = tmp_path / 'h5_strings_test.h5'
    h5 = tdms_data.as_hdf(h5_path)
    h5_strings = h5['Group']['String']
    assert h5_strings.dtype.kind == 'O'
    assert h5_strings.shape[0] == len(strings)
    for expected, read in zip(strings, h5_strings[...]):
        assert expected == _as_string(read)
    h5.close()

def test_unicode_string_data(tmp_path):
    """ Test HDF5 conversion for string datatype with non-ASCII data
    """
    strings = ["Hello, \u4E16\u754C", "\U0001F600"]
    sizes = [len(s.encode('utf-8')) for s in strings]

    test_file = GeneratedFile()
    toc = ("kTocMetaData", "kTocRawData", "kTocNewObjList")
    metadata = (
        # Number of objects
        "01 00 00 00"
        # Length of the object path
        "11 00 00 00")
    metadata += string_hexlify("/'Group'/'String'")
    metadata += (
        # Length of index information
        "1C 00 00 00"
        # Raw data data type
        "20 00 00 00"
        # Dimension
        "01 00 00 00"
        # Number of raw data values
        "02 00 00 00"
        "00 00 00 00" +
        # Number of bytes in data, including index
        hexlify_value('q', sum(sizes) + 4 * len(sizes)) +
        # Number of properties (0)
        "00 00 00 00")
    data = ""
    offset = 0
    for size in sizes:
        # Index gives end positions of strings:
        offset += size
        data += hexlify_value('i', offset)
    for string in strings:
        data += string_hexlify(string)
    test_file.add_segment(toc, metadata, data)
    tdms_data = test_file.load()

    data = tdms_data["Group"]["String"].data
    assert len(data) == len(strings)
    for expected, read in zip(strings, data):
        assert expected == read

    h5_path = tmp_path / 'h5_unicode_strings_test.h5'
    h5 = tdms_data.as_hdf(h5_path)
    h5_strings = h5['Group']['String']
    assert h5_strings.dtype.kind == 'O'
    assert h5_strings.shape[0] == len(strings)
    for expected, read in zip(strings, h5_strings[...]):
        assert expected == _as_string(read)
    h5.close()

def test_add_to_file_under_group(tmp_path):
    """ Test adding TDMS data to an HDF file under a group
    """
    test_file, expected_data = scenarios.single_segment_with_two_channels().values
    preexisting_data = np.array([1.0, 2.0, 3.0])

    tdms_data = test_file.load()
    h5_path = tmp_path / 'h5_data_test.h5'
    h5 = h5py.File(h5_path, 'w')
    h5['preexisting_data'] = preexisting_data
    h5.close()

    h5 = tdms_data.as_hdf(h5_path, mode='a', group='tdms_data')

    for ((group, channel), expected_data) in expected_data.items():
        h5_channel = h5['tdms_data'][group][channel]
        np.testing.assert_almost_equal(h5_channel[...], expected_data)
    np.testing.assert_almost_equal(h5['preexisting_data'], preexisting_data)
    h5.close()

def _as_string(bytes_or_string):
    # h5py reads string data as bytes by default since 3.0
    if isinstance(bytes_or_string, bytes):
        return bytes_or_string.decode('UTF-8')
    return bytes_or_string


class Queue:
    def __init__(self):
        self.__queue = []

    def enqueue(self, data):
        self.__queue.insert(0, data)

    def dequeue(self):
        if len(self.__queue) > 0:
            return self.__queue.pop()
        return None

    def size(self):
        return len(self.__queue)

queue = Queue()
queue.enqueue('Mon')
queue.enqueue('Tue')
queue.enqueue('Wed')
print(queue.dequeue())
print(queue.dequeue())
print(queue.size())
queue.__queue = [1, 2, 3, 4, 5, 6, 7]
print(queue.dequeue())


from typing import Any, List
import logging

from PyQt5.QtCore import pyqtSlot as Slot

from .command import InstantCommand, CommandArgument, Command
from .commandargument import StringArgument
from ..devices.device.frontend import DeviceFrontend

logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)

class GetVar(InstantCommand):
    name="getvar"
    description = "Get the value of a device variable"
    arguments = [StringArgument('device', 'The name of the device'),
                 StringArgument('variable', 'The name of the variable')]

    def run(self, device: str, variable: str) -> Any:
        try:
            self.instrument.devicemanager[device]
        except (KeyError, IndexError):
            raise RuntimeError(f'No such device {device}')
        try:
            self.message.emit(f'{self.instrument.devicemanager[device][variable]}')
            return self.instrument.devicemanager[device][variable]
        except (KeyError, IndexError):
            raise RuntimeError(f'Device {device} has no variable named {variable}')

class DevCommand(Command):
    name = "devcommand"
    description="Execute a low-level command on a device"
    arguments=[StringArgument('device', 'The name of the device'),
               StringArgument('commandname', 'The name of the low-level command'),
               ...]
    sentcommand:str
    timerinterval = None
    device: DeviceFrontend

    def _connectDevice(self):
        self.device.commandResult.connect(self.onDeviceCommandResult)

    def _disconnectDevice(self):
        self.device.commandResult.disconnect(self.onDeviceCommandResult)

    def initialize(self, device: str, commandname: str, *args):
        self.device = self.instrument.devicemanager[device]
        self._connectDevice()
        self.sentcommand = commandname
        try:
            self.device.issueCommand(commandname, args)
        except:
            self._disconnectDevice()
            raise

    @Slot(bool, str, str)
    def onDeviceCommandResult(self, success: bool, commandname: str, message: str):
        if commandname == self.sentcommand:
            self._disconnectDevice()
            if success:
                self.finish(message)
            else:
                self.fail(message)
        else:
            logger.warning(f'Unexpected reply: expected reply to command {self.sentcommand}, got reply to command {commandname}')

class ListVariables(InstantCommand):
    name='listvars'
    description = 'List the names of all variables of a device'
    arguments = [StringArgument('device', 'The name of the device')]

    def run(self, device: str) -> List[str]:
        self.message.emit(f'{", ".join(self.instrument.devicemanager[device].keys())}')
        return list(self.instrument.devicemanager[device].keys())


import pandas as pd

def optimize_data(data):
    # Initialize year and month
    year = 2017
    month = 1
    data["Date"] = ""

    #clean 'nan'-s and unnecessary rows:
    for i in range(len(data)):
        if ((str(data['Hónap'][i]) == "nan") | ((str(data['Hónap'][i]).find("jan") != -1) & (str(data['Hónap'][i]).find("dec") != -1))):
            data.drop(i, axis=0, inplace=True)
            month -= 1
            continue
        elif str(data['Év'][i]) != "nan":
            year = data['Év'][i]
        else:
            data['Év'][i] = year
        if i != 0:
            if month <= 11:
                month += 1
            else:
                month = 1
            data['Date'][i] = str(data['Év'][i]).replace('.', '') + '-' + str(month)

    # change column labels:
    column_labels = {
             'Közép- hõmérséklet, °C': 'Average_temperature_C',
             'Maximális hõmérséklet, °C': 'Max_temperature_C',
             'Minimális hõmérséklet, °C': 'Min_temperature_C',
             'Csapadékos nap ': 'Rainy_days',
             'Csapadékos nap': 'Rainy_days',
             'Lehullott csapadék, mm ': 'Precipitation_mm',
             'Lehullott csapadék, mm': 'Precipitation_mm',
             'A napsütéses órák száma ': 'Sunny_hours',
             'A napsütéses órák száma': 'Sunny_hours',
             'Szeles napok száma, szélsebesség>=10 m/s ': 'Windy_days_windspeed>=10m/s',
             'Szeles napok száma, szélsebesség>=10 m/s': 'Windy_days_windspeed>=10m/s'}
    data.rename(columns= column_labels, inplace=True)

    #optimize dtype:
    data['Average_temperature_C'] = data['Average_temperature_C'].apply(lambda x: float(x.replace(',', '.')))
    data['Max_temperature_C'] = data['Max_temperature_C'].apply(lambda x: float(x.replace(',', '.')))
    data['Min_temperature_C'] = data['Min_temperature_C'].apply(lambda x: float(x.replace(',', '.')))
    data['Sunny_hours'] = data['Sunny_hours'].apply(lambda x: float(x.split()[0].replace(',', '.')) if x!= ".." else -1)
    data['Date'] = pd.to_datetime(data['Date'])
    data['Precipitation_mm'] = data['Precipitation_mm'].apply(lambda x: int(x))

    #reorder & delete unnecessary columns:
    data = data[['Date', 'Average_temperature_C', 'Max_temperature_C', 'Min_temperature_C', 'Sunny_hours', 'Rainy_days',
    'Precipitation_mm', 'Windy_days_windspeed>=10m/s']]

    return data

def get_path(city):
    list_of_cities= {'Budapest': 'kor0070', 'Debrecen': 'kor0071', 'Győr': 'kor0072',
    'Kecskemét': 'kor0073', 'Kékestető': 'kor0074', 'Miskolc': 'kor0075', 'Pogány (Pécs)': 'kor0077',
    'Siófok (Balaton)': 'kor0078', 'Szeged': 'kor0079', 'Szombathely': 'kor0080'}
    return "https://www.ksh.hu/stadat_files/kor/hu/" + list_of_cities[city] + ".csv"

def get_name(path):
    return pd.read_csv(path, encoding='unicode_escape', header=None, nrows=1).values[0][0].split()[1]

def get_dataframe(path):
    return optimize_data(pd.read_csv(path, encoding = 'unicode_escape', header = 1 ,sep=";"))


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

class Solution(object):
    def invertBinaryTree(self, root):
        """
        :param root:TreeNode
        :return:TreeNode
        """
        if not root:
            return
        else:
            root.left,root.right = root.right,root.left
            root.left = self.invertBinaryTree(root.left)
            root.right = self.invertBinaryTree(root.right)
        return root


import copy
import random
from typing import List

from game_core.field import Point, OutsideStone
from game_core.special_exceptions import IncorrectMove

class AIEnemy:
    """Класс с реализацией компьютерного противника"""

    def __init__(self, player, game=None):
        self._player = player
        self._interior_game = game
        self.points_set = [Point(x, y) for x in range(game.field_size)
                           for y in range(game.field_size)]

    @property
    def player(self):
        return self._player

    def _copy_game(self, game):
        self._interior_game = copy.deepcopy(game)

    def get_cell_attractiveness(self, point: Point) -> int:
        attractiveness = 0
        if not self._interior_game.game_field\
                .get_obj_on_position(point.x, point.y):
            is_have_exit = False
            is_all_friend = True
            is_one_breath = False
            for neighbor in self._interior_game. \
                    game_field.get_neighbor_on_position(point):
                if isinstance(neighbor, self._player.stone_type):
                    if neighbor.breaths == 1:
                        is_one_breath = True
                        attractiveness += 100
                    attractiveness += 100 - neighbor.breaths * 2
                elif isinstance(neighbor, OutsideStone):
                    pass
                elif neighbor is None:
                    is_have_exit = True
                else:
                    is_all_friend = False
                    if neighbor.breaths == 1:
                        attractiveness += 100
                    attractiveness += 100 - neighbor.breaths * 2

            if is_all_friend or (is_one_breath and not is_have_exit):
                attractiveness = 0

        return attractiveness

    def get_best_move(self) -> List[Point]:
        results = list()
        for point in self.points_set:
            results.append(self.get_cell_attractiveness(point))

        best_point = self.points_set[
            random.randint(0, len(self.points_set) - 1)]
        best_score = 0
        best_points = [best_point]
        for index, point_score in enumerate(results):
            if point_score > best_score:
                best_score = point_score
                best_points = [self.points_set[index]]
            elif point_score == best_score:
                best_points.append(self.points_set[index])
        return best_points

    def make_move(self, game):
        if game.is_field_filled:
            game.make_move('pass', True)

        best_move_points = self.get_best_move()
        points_iter = iter(best_move_points)

        move_point = next(points_iter)
        x_move = move_point.x
        y_move = move_point.y
        while True:
            try:
                game.make_move('move', x_move + 1, y_move + 1, True)
                break
            except IncorrectMove:
                try:
                    move_point = next(points_iter)
                    x_move = move_point.x
                    y_move = move_point.y
                except StopIteration:
                    x_move = random.randint(0, game.field_size)
                    y_move = random.randint(0, game.field_size)


import argparse
from typing import List, Optional

from ..ui.utils import create_table
from ... import utils
from ...exceptions import PrivilegeError
from ...foundation.cli.command.Command import Command
from ...manager.Kathara import Kathara
from ...strings import strings, wiki_description
from ...trdparty.curses.curses import Curses

class ListCommand(Command):
    def __init__(self) -> None:
        Command.__init__(self)

        self.parser: argparse.ArgumentParser = argparse.ArgumentParser(
            prog='kathara list',
            description=strings['list'],
            epilog=wiki_description,
            add_help=False
        )

        self.parser.add_argument(
            '-h', '--help',
            action='help',
            default=argparse.SUPPRESS,
            help='Show a help message and exit.'
        )

        self.parser.add_argument(
            '-a', '--all',
            required=False,
            action='store_true',
            help='Show all running Kathara devices of all users. MUST BE ROOT FOR THIS OPTION.'
        )

        self.parser.add_argument(
            '-w', '-l', '--watch', '--live',
            required=False,
            action='store_true',
            help='Watch mode.'
        )

        self.parser.add_argument(
            '-n', '--name',
            metavar='DEVICE_NAME',
            required=False,
            help='Show only information about a specified device.'
        )

    def run(self, current_path: str, argv: List[str]) -> None:
        self.parse_args(argv)
        args = self.get_args()

        if args['all'] and not utils.is_admin():
            raise PrivilegeError("You must be root in order to show all Kathara devices of all users.")

        all_users = bool(args['all'])

        if args['watch']:
            self._get_live_info(machine_name=args['name'], all_users=all_users)
        else:
            machines_stats = Kathara.get_instance().get_machines_stats(machine_name=args['name'], all_users=all_users)
            print(next(create_table(machines_stats)))

    @staticmethod
    def _get_live_info(machine_name: Optional[str], all_users: bool) -> None:
        machines_stats = Kathara.get_instance().get_machines_stats(machine_name=machine_name, all_users=all_users)
        table = create_table(machines_stats)

        Curses.get_instance().init_window()

        try:
            while True:
                Curses.get_instance().print_string(next(table))
        except StopIteration:
            pass
        finally:
            Curses.get_instance().close()


import numpy as np
from pandas import Series
import scipy.optimize as op
import matplotlib.pyplot as plt

######################Functions
def PlotData(X, y, show= True):
    p= y==1
    n= y==0
    pos1= X[:, 0:1][p]
    pos2= X[:, 1:2][p]
    neg1 = X[:, 0:1][n]
    neg2 = X[:, 1:2][n]

    pos, = plt.plot(pos1, pos2, 'b+')
    neg, =plt.plot(neg1, neg2, 'yo')

    plt.xlabel('Exam 1 Score')
    plt.ylabel('Exam 2 Score')
    plt.legend([pos, neg], ['Admitted', 'Not Admitted'])
    if show:
        plt.show()
    else:
        pass
    #end

def CostFunc(theta, X, y):
    m= X.shape[0]
    z= X.dot(theta)
    h= (1/(1+ np.exp(-z)))
    cost= (-1/m)*((1-y).T.dot(np.log(1-h)) + y.T.dot(np.log(h)))
    return cost
    #end

def sigmoid(z):
    return(1/(1+ np.exp(-z)))
    #end

def Grad(theta, X, y):
    m= X.shape[0]
    z= X.dot(theta)
    h= sigmoid(z)
    grad= (1/m)*X.T.dot(h-y)
    return grad
    #end

def PlotDecisionBoundary(theta, X, y):
    PlotData(X[:,1:], y, show=False)

    if X.shape[1] <= 3:
        # Only need 2 points to define a line, so choose two endpoints
        plot_x = np.array([min(X[:, 2]),  max(X[:, 2])])

        # Calculate the decision boundary line
        plot_y = (-1./theta[2])*(theta[1]*plot_x + theta[0])

        # Plot, and adjust axes for better viewing
        plt.plot(plot_x, plot_y)

    else:
        # Here is the grid range
        u = np.linspace(-1, 1.5, 50)
        v = np.linspace(-1, 1.5, 50)
        z = [
                np.array([mapFeature2(u[i], v[j]).dot(theta) for i in range(len(u))])
                for j in range(len(v))
            ]
        plt.contour(u,v,z, levels=[0.0])

    # Legend, specific for the exercise
    # axis([30, 100, 30, 100])
    #end

def mapFeature2(X1, X2, degree=6):
    quads = Series([X1**(i-j) * X2**j for i in range(1,degree+1) for j in range(i+1)])
    return Series([1]).append([Series(X1), Series(X2), quads])
    #end

def predict(theta, X):
    p= sigmoid(X.dot(theta))
    return(p>=0.5)
####################Loading and Visualising Data
print('Loading Data.....\n')
data= np.loadtxt("data.txt")
m= data.shape[0]
n= data.shape[1]
X= data[:, 0:2]
y= data[:, 2].reshape(m, 1)

print('Plotting data with + indicating (y = 1) examples and o indicating (y = 0) examples.\n')
PlotData(X, y)

####################Compute Cost and Gradient
X= np.append(np.ones((m,1)), X, axis=1)
theta= np.zeros(n).reshape(n,1)
cost, grad= CostFunc(theta, X, y), Grad(theta, X, y)

print('Cost at initial theta (zeros): \n', cost)
print('Expected cost (approx): 0.693\n')
print('Gradient at initial theta (zeros): \n', grad)
print('Expected gradients (approx):\n -0.1000\n -12.0092\n -11.2628\n')

test= [[-24], [0.2], [0.2]]
cost, grad= CostFunc(test, X, y), Grad(test, X, y)
print('\nCost at test theta: \n', cost)
print('Expected cost (approx): 0.218\n')
print('Gradient at test theta: \n', grad)
print('Expected gradients (approx):\n 0.043\n 2.566\n 2.647\n')

#############Optimizing using fmin
theta= op.fmin(func=CostFunc, x0=np.zeros(3), args=(X, y))
theta= theta.reshape(n,1)

cost= CostFunc(theta, X, y)
print('Cost at theta found by fmin: ', cost)
print('Expected cost (approx): 0.203\n')
print('theta: \n', theta);
print('Expected theta (approx):\n')
print(' -25.161\n 0.206\n 0.201\n')

PlotDecisionBoundary(theta, X, y)

################Prediction and Accuracy
prob= sigmoid(np.array([1, 45, 85]).dot(theta))
print(['For a student with scores 45 and 85, we predict an admission probability of '], prob)
print('Expected value: 0.775 +/- 0.002\n\n')

p = predict(theta, X);

print('Train Accuracy: %f\n', np.mean((p == y)) * 100);
print('Expected accuracy (approx): 89.0\n');
print('\n')


from smtplib import SMTP_SSL
from email.mime.text import MIMEText

from config import email_id
from config import email_pw

class Sender:
    """ This class sends an email to a given recipient regarding Github info

    """

    def __init__(self, receiver):
        self.__sender = email_id
        self.__receiver = receiver
        self.__msg = self.__init_msg()

    def __init_msg(self):
        content = """ You don't have any pushed commit today! """

        msg = MIMEText(content)
        msg['Subject'] = "Daily commit notification on your Github account"
        return msg

    def send(self):
        smtp = SMTP_SSL('smtp.gmail.com', 465)
        smtp.login(self.__sender, email_pw)
        smtp.sendmail(self.__sender, self.__receiver, self.__msg.as_string())
        smtp.quit()


def extractAshenfeatherWordpressCom(item):
	'''
	Parser for 'ashenfeather.wordpress.com'
	'''

	vol, chp, frag, postfix = extractVolChapterFragmentPostfix(item['title'])
	if not (chp or vol) or "preview" in item['title'].lower():
		return None

	tagmap = [
		('Sweet Curse! Battle-Android summoned to a Different world!',       'Sweet Curse! Battle-Android summoned to a Different world!',                      'translated'),
		('She was called God, as well as Satan',                             'She was called God, as well as Satan',                                            'translated'),
		('She was Called Both God & Satan',                                  'She was called God, as well as Satan',                                            'translated'),
		('At the Northern Fort',                                             'At the Northern Fort',                                                            'translated'),
		('Girl with the Golden-Cat Eyes',                                    'Girl with the Golden-Cat Eyes',                                                   'oel'),
		('One in the Chamber',                                               'One in the Chamber',                                                              'oel'),
		('Parabellum',                                                       'Parabellum',                                                                      'oel'),
		('Sky Gardens',                                                      'Sky Gardens',                                                                     'oel'),
		('Manuke FPS',                                                       'Manuke FPS',                                                                      'translated'),
		('PRC',       'PRC',                      'translated'),
		('Loiterous', 'Loiterous',                'oel'),
	]

	for tagname, name, tl_type in tagmap:
		if tagname in item['tags']:
			return buildReleaseMessageWithType(item, name, vol, chp, frag=frag, postfix=postfix, tl_type=tl_type)
	if item['tags'] == ['Uncategorized']:
		titlemap = [
			('Flowered Metal | ',           'Flowered Metal',                  'translated'),
			('Master of Dungeon',           'Master of Dungeon',               'oel'),
		]

		for titlecomponent, name, tl_type in titlemap:
			if titlecomponent.lower() in item['title'].lower():
				return buildReleaseMessageWithType(item, name, vol, chp, frag=frag, postfix=postfix, tl_type=tl_type)

	return False


import os
import re
import json
import pprint
import subprocess
from google.cloud import storage

PROJECT = "kb-encoder2"
BUCKET = "kb-encoder"
MODEL_DIR = "arc/"
OUTPUT_DIR = "arc/"

if __name__ == "__main__":
    client = storage.Client(PROJECT)
    checkpoint_steps = []
    for blob in client.list_blobs(BUCKET, prefix=MODEL_DIR):
        result = re.search(r"model\.ckpt-([0-9]+)\.data", blob.name)
        if result is not None:
            step = int(result[1])
            if step not in checkpoint_steps:
                checkpoint_steps.append(step)

    checkpoint_steps = sorted(checkpoint_steps)
    print(f"Checkpoint steps: {checkpoint_steps}")
    checkpoint_precision = {}
    for step in checkpoint_steps:
        print(f"Evaluating checkpoint {step}")
        process = subprocess.Popen(
            f'bash -c "./eval_tpu.sh {step}"', shell=True, stderr=subprocess.PIPE,
        )
        found = False
        for line in iter(process.stderr.readline, b""):
            line = line.decode("utf-8")
            print(line, end=" ")
            result = re.search(
                r"precision at step [0-9]+: ([+-]?([0-9]*[.])?[0-9]+)", line
            )
            if result is not None:
                checkpoint_precision[step] = float(result[1])
                found = True
        if not found:
            raise RuntimeError("An error occured during bash execution")

    with open("batch_eval_result.json", "w") as file:
        json.dump(checkpoint_precision, file)

    bucket = client.bucket(BUCKET)
    blob = bucket.blob(os.path.join(OUTPUT_DIR, "batch_eval_result.json"))
    blob.upload_from_filename("batch_eval_result.json")
    pprint.pprint(checkpoint_precision)
    print("Batch evaluation result saved")


#####################################################
# Obtains random samples for testing the algorithms #
#####################################################

import os
import random
import codecs
import translationMatrixLS as tmls

sbin = os.getcwd()+'/regul_vec/en/bin/vecs.bin'
svocab = os.getcwd()+'/regul_vec/en/bin/vocab.txt'
sbin_full = os.getcwd()+'/regul_vec/en/bin_full/vecs_full.bin'
svocab_full = os.getcwd()+'/regul_vec/en/bin_full/vocab_full.txt'

en = tmls.generateVectors(sbin, svocab, 300, 'en')

indexes = random.sample(range(len(en[0])),500)
samples = dict((x,y) for x,y in zip(en[0][indexes],en[1][indexes]))
with codecs.open(os.getcwd()+'/samples_en_full.txt', 'w') as txt:
    for s in samples:
        txt.write(s+'\n')

'''
d_en_es = {}
d_es_en = {}
with open(os.getcwd()+'/../word2vec/en2es-lemma-dict.txt','r') as lemmas:
    for line in lemmas:
        (key,val) = line.split(':') #EN -> SP
        d_en_es[key] = val.strip('\n')
        (val,key) = line.split(':') #SP -> EN
        d_es_en[key.strip('\n')] = val
with open(os.getcwd()+'/../word2vec/en_es.txt','r') as syncons:
    for line in syncons:
        (key,val) = line.split()
        d_en_es[key] = val
        (val,key) = line.split()
        d_es_en[key] = val

i = 0
with codecs.open(os.getcwd()+'/samples_en_full.txt', 'r', encoding = 'utf-8') as txt:
    for l in txt:
        if '#' in l:
            try:
                d_en_es[l.strip('\n')]
	    except KeyError:
                i += 1
		print(l.strip('\n'))
        else:
            try:
                d_en_es[l.strip('\n')]
	    except KeyError:
                i += 1
		print(l.strip('\n'))
print(i)
'''


from __future__ import print_function
import os, sys, time, argparse
from datetime import date
import numpy as np
import scipy.io as sio
import tensorflow as tf
from tensorflow.keras import layers
import matplotlib.pyplot as plt
import math
from absl import app
from absl import flags
import json

from gan_data import *
from gan_src import *

import tensorflow_probability as tfp
tfd = tfp.distributions
from matplotlib.backends.backend_pgf import PdfPages
from scipy.interpolate import interp1d
mse = tf.keras.losses.MeanSquaredError(reduction = tf.keras.losses.Reduction.SUM)
from ops import *

from itertools import product,combinations,combinations_with_replacement

'''
GAN_topic is the Overarching class file, where corresponding parents are instantialized, along with setting up the calling functions for these and files and folders for resutls, etc. data reading is also done from here. Sometimes display functions, architectures, etc may be modified here if needed (overloading parent classes)
'''

'''***********************************************************************************
********** GAN Baseline setup ********************************************************
***********************************************************************************'''
class GAN_Base(GAN_SRC, GAN_DATA_Base):

	def __init__(self,FLAGS_dict):
		''' Set up the GAN_SRC class - defines all fundamental ops and metric functions'''
		GAN_SRC.__init__(self,FLAGS_dict)
		''' Set up the GAN_DATA class'''
		GAN_DATA_Base.__init__(self)

	def initial_setup(self):
		''' Initial Setup function. define function names '''
		self.gen_func = 'self.gen_func_'+self.data+'()'
		self.gen_model = 'self.generator_model_'+self.arch+'_'+self.data+'()'
		self.disc_model = 'self.discriminator_model_'+self.arch+'_'+self.data+'()'
		self.loss_func = 'self.loss_'+self.loss+'()'
		self.dataset_func = 'self.dataset_'+self.data+'(self.train_data, self.batch_size)'
		self.show_result_func = 'self.show_result_'+self.data+'(images = predictions, num_epoch=epoch, show = False, save = True, path = path)'
		self.FID_func = 'self.FID_'+self.data+'()'

		self.noise_setup()

		''' Define dataset and tf.data function. batch sizing done'''
		# self.get_data()

		# self.create_models()

		# self.create_optimizer()

		# self.create_load_checkpoint()

	def get_data(self):
		with tf.device('/CPU'):
			self.train_data = eval(self.gen_func)

			self.num_batches = int(np.floor((self.train_data.shape[0] * self.reps)/self.batch_size))
			''' Set PRINT and SAVE iters if 0'''
			self.print_step = tf.constant(max(int(self.num_batches/10),1),dtype='int64')
			self.save_step = tf.constant(max(int(self.num_batches/2),1),dtype='int64')

			self.train_dataset = eval(self.dataset_func)
			self.train_dataset_size = self.train_data.shape[0]

			# self.train_dataset = self.strategy.experimental_distribute_dataset(self.train_dataset)

			print(" Batch Size {}, Final Num Batches {}, Print Step {}, Save Step {}".format(self.batch_size,  self.num_batches,self.print_step, self.save_step))

	###### WGAN-FS overloads this function. Need a better way to execute it.... The overload has to do for now.....
	def create_models(self):
		# with self.strategy.scope():
		self.total_count = tf.Variable(0,dtype='int64')
		self.generator = eval(self.gen_model)
		self.discriminator = eval(self.disc_model)

		if self.res_flag == 1:
			with open(self.run_loc+'/'+self.run_id+'_Models.txt','a') as fh:
				# Pass the file handle in as a lambda function to make it callable
				fh.write("\n\n GENERATOR MODEL: \n\n")
				self.generator.summary(line_length=80, print_fn=lambda x: fh.write(x + '\n'))
				fh.write("\n\n DISCRIMINATOR MODEL: \n\n")
				self.discriminator.summary(line_length=80, print_fn=lambda x: fh.write(x + '\n'))

		print("Model Successfully made")

		print(self.generator.summary())
		print(self.discriminator.summary())
		return

	###### WGAN-FS overloads this function. Need a better way to execute it.... The overload has to do for now.....
	def create_load_checkpoint(self):

		self.checkpoint = tf.train.Checkpoint(G_optimizer = self.G_optimizer,
								 Disc_optimizer = self.Disc_optimizer,
								 generator = self.generator,
								 discriminator = self.discriminator,
								 total_count = self.total_count)
		self.manager = tf.train.CheckpointManager(self.checkpoint, self.checkpoint_dir, max_to_keep=10)
		self.checkpoint_prefix = os.path.join(self.checkpoint_dir, "ckpt")

		if self.resume:
			try:
				self.checkpoint.restore(tf.train.latest_checkpoint(self.checkpoint_dir))
			except:
				print("Checkpoint loading Failed. It could be a model mismatch. H5 files will be loaded instead")
				try:
					self.generator = tf.keras.models.load_model(self.checkpoint_dir+'/model_generator.h5')
					self.discriminator = tf.keras.models.load_model(self.checkpoint_dir+'/model_discriminator.h5')
				except:
					print("H5 file loading also failed. Please Check the LOG_FOLDER and RUN_ID flags")

			print("Model restored...")
			print("Starting at Iteration - "+str(self.total_count.numpy()))
			print("Starting at Epoch - "+str(int((self.total_count.numpy() * self.batch_size) / (self.train_data.shape[0])) + 1))
		return

	def noise_setup(self):

		if self.noise_kind == 'non_para':
			self.non_para_dist_mat = sio.loadmat('data/non_param_pdf.mat')

		if self.noise_kind == 'gamma':
			self.gamma_shape = 0.5
			self.gamma_scale = 1.0

		if self.noise_kind == 'trip':
			self.num_latents_trip = 128
			self.num_components_trip = 10
			self.tt_int_trip = 40

		return

	def get_noise(self, shape):
		#shape = [self.batch_size, self.noise_dims]

		def random_gen(shape, pdf, points, epsilon):
			assert len(shape) == 2
			rn = np.random.choice(points, size = shape, p=pdf).astype(np.float32)
			for i in range(shape[0]):
				for j in range(shape[1]):
					rn[i,j] = np.random.uniform(rn[i,j], rn[i,j]+epsilon, 1).astype(np.float32)
			return rn

		def sample_spherical(npoints, ndim=3):
			vec = np.random.randn(ndim, npoints)
			vec /= np.linalg.norm(vec, axis=0)
			return vec

		# def TRIP()

		if self.noise_kind == 'non_para':
			pdf = np.reshape(self.non_para_dist_mat['X_final'], (1024))
			points = np.linspace(-2, 2, 1024)
			epsilon = 4./1024.
			noise = random_gen(shape, pdf, points, epsilon)

		elif self.noise_kind == 'gaussian':
			noise = tf.random.normal(shape, mean = self.noise_mean, stddev = self.noise_stddev)

		elif self.noise_kind == 'gaussian075':
			noise = tf.random.normal(shape, mean = self.noise_mean, stddev = 0.75)

		elif self.noise_kind == 'gamma':
			nu = sample_spherical(shape[0], shape[1]).transpose()
			r = np.random.gamma(self.gamma_shape, scale=self.gamma_scale, size=shape[0])
			root_r_mat = np.repeat(np.expand_dims(np.sqrt(r),axis=1), shape[1], axis = 1)

			noise = np.multiply(root_r_mat,nu)
			# print(root_r_mat.shape,nu.shape,noise.shape)
		elif self.noise_kind == 'cauchy':
			noise = np.random.standard_cauchy(size=shape)

		elif self.noise_kind == 'trip':
			prior = TRIP(self.num_latents_trip * (('c', self.num_components_trip),),tt_int=self.tt_int_trip, distr_init='uniform')

		return noise

	def train(self):
		start = int((self.total_count.numpy() * self.batch_size) / (self.train_data.shape[0])) + 1
		for epoch in range(start,self.num_epochs):
			if self.pbar_flag:
				bar = self.pbar(epoch)
			start = time.perf_counter()
			batch_count = tf.Variable(0,dtype='int64')
			start_time =0

			for image_batch in self.train_dataset:
				# print(image_batch.shape)
				self.total_count.assign_add(1)
				batch_count.assign_add(1)
				start_time = time.perf_counter()
				# with self.strategy.scope():
				self.train_step(image_batch.numpy())
				self.eval_metrics()

				train_time = time.perf_counter()-start_time

				if self.pbar_flag:
					bar.postfix[0] = f'{batch_count.numpy():6.0f}'
					bar.postfix[1] = f'{self.D_loss.numpy():2.4e}'
					bar.postfix[2] = f'{self.G_loss.numpy():2.4e}'
					bar.update(self.batch_size.numpy())
				if (batch_count.numpy() % self.print_step.numpy()) == 0 or self.total_count <= 2:
					if self.res_flag:
						self.res_file.write("Epoch {:>3d} Batch {:>3d} in {:>2.4f} sec; D_loss - {:>2.4f}; G_loss - {:>2.4f} \n".format(epoch,batch_count.numpy(),train_time,self.D_loss.numpy(),self.G_loss.numpy()))

				self.print_batch_outputs(epoch)

				# Save the model every SAVE_ITERS iterations
				if (self.total_count.numpy() % self.save_step.numpy()) == 0:
					if self.save_all:
						self.checkpoint.save(file_prefix = self.checkpoint_prefix)
					else:
						self.manager.save()

				if self.iters_flag:
					if self.num_iters == self.total_count.numpy():
						tf.print("\n Training for {} Iterations completed".format( self.total_count.numpy()))
						if self.pbar_flag:
							bar.close()
							del bar
						tf.print('Time for epoch {} is {} sec'.format(epoch, time.perf_counter()-start))
						self.save_epoch_h5models()
						return

			if self.pbar_flag:
				bar.close()
				del bar
			tf.print('Time for epoch {} is {} sec'.format(epoch, time.perf_counter()-start))
			self.save_epoch_h5models()

	def save_epoch_h5models(self):

		self.generator.save(self.checkpoint_dir + '/model_generator.h5', overwrite = True)

		if self.loss == 'FS':
			self.discriminator_A.save(self.checkpoint_dir + '/model_discriminator_A.h5', overwrite = True)
			self.discriminator_B.save(self.checkpoint_dir + '/model_discriminator_B.h5', overwrite = True)
		elif self.loss == 'RBF':
			self.discriminator_RBF.save(self.checkpoint_dir +'/model_discriminator_RBF.h5',overwrite=True)
		elif self.topic != 'SnakeGAN':
			self.discriminator.save(self.checkpoint_dir + '/model_discriminator.h5', overwrite = True)
		return

	def print_batch_outputs(self,epoch):
		if ((self.total_count.numpy() % 5) == 0 and self.data in ['g1', 'g2']):### Was 10 - ICML22 plots
			self.generate_and_save_batch(epoch)
		if (self.total_count.numpy() <= 5) and self.data in [ 'g1', 'g2', 'gmm2', 'gmm8']:
			self.generate_and_save_batch(epoch)
		if ((self.total_count.numpy() % 100) == 0 and self.data in ['gmm2', 'gmm8']):
			self.generate_and_save_batch(epoch)
		if ((self.total_count.numpy() % 100) == 0 and self.data in ['celeba']):
			self.generate_and_save_batch(epoch)
		if (self.total_count.numpy() % self.save_step.numpy()) == 0:
			self.generate_and_save_batch(epoch)

	def eval_sharpness(self):
		i = 0
		for train_batch in self.train_dataset:
			noise = self.get_noise([self.batch_size, self.noise_dims])
			preds = self.generator(noise, training = False)

			sharp = self.find_sharpness(preds)
			base_sharp = self.find_sharpness(train_batch)
			try:
				sharp_vec.append(sharp)
				base_sharp_vec.append(base_sharp)

			except:
				sharp_vec = [sharp]
				base_sharp_vec = [base_sharp]
			i += 1
			if i == 10:
				break
		###### Sharpness averaging measure
		sharpness = np.mean(np.array(sharp_vec))
		baseline_sharpness = np.mean(np.array(base_sharp_vec))

		return baseline_sharpness, sharpness

	def test(self):
		num_interps = 10
		if self.mode == 'test':
			num_figs = 20#int(400/(2*num_interps))
		else:
			num_figs = 9
		# there are 400 samples in the batch. to make 10x10 images,
		for j in range(num_figs):
			# print("Interpolation Testing Image ",j)
			path = self.impath+'_TestingInterpolationV2_'+str(self.total_count.numpy())+'_TestCase_'+str(j)+'.png'
			# noise = self.get_noise([20*num_figs, self.noise_dims])
			# current_batch = noise[2*num_interps*j:2*num_interps*(j+1)]
			# image_latents = self.generator(current_batch)
			for i in range(num_interps):
				# print("Pair ",i)
				# current_batch = self.get_noise([20*num_figs, self.noise_dims])
				start = self.get_noise([1, self.noise_dims])#current_batch[i:1+i].numpy()
				end = self.get_noise([1, self.noise_dims]) #current_batch[num_interps+i:num_interps+1+i].numpy()
				stack = np.vstack([start, end])
				# print(stack)

				linfit = interp1d([1,num_interps+1], stack, axis=0)
				interp_latents = linfit(list(range(1,num_interps+1)))

				# print(interp_latents)
				cur_interp_figs = self.generator(interp_latents)

				# print(cur_interp_figs)

				sharpness = self.find_sharpness(cur_interp_figs)

				try:
					sharpness_vec.append(sharpness)
				except:
					shaprpness_vec = [sharpness]
				# cur_interp_figs_with_ref = np.concatenate((current_batch[i:1+i],cur_interp_figs.numpy(),current_batch[num_interps+i:num_interps+1+i]), axis = 0)
				# print(cur_interp_figs_with_ref.shape)
				try:
					batch_interp_figs = np.concatenate((batch_interp_figs,cur_interp_figs),axis = 0)
				except:
					batch_interp_figs = cur_interp_figs

			images = (batch_interp_figs + 1.0)/2.0
			# print(images.shape)
			size_figure_grid = num_interps
			images_on_grid = self.image_grid(input_tensor = images, grid_shape = (size_figure_grid,size_figure_grid),image_shape=(self.output_size,self.output_size),num_channels=images.shape[3])
			fig1 = plt.figure(figsize=(num_interps,num_interps))
			ax1 = fig1.add_subplot(111)
			ax1.cla()
			ax1.axis("off")
			if images_on_grid.shape[2] == 3:
				ax1.imshow(np.clip(images_on_grid,0.,1.))
			else:
				ax1.imshow(np.clip(images_on_grid[:,:,0],0.,1.), cmap='gray')

			label = 'INTERPOLATED IMAGES AT ITERATION '+str(self.total_count.numpy())
			plt.title(label)
			plt.tight_layout()
			plt.savefig(path)
			plt.close()
			del batch_interp_figs

		###### Interpol samples - Sharpness
		overall_sharpness = np.mean(np.array(shaprpness_vec))
		if self.mode == 'test':
			print("Interpolation Sharpness - " + str(overall_sharpness))
		if self.res_flag:
			self.res_file.write("Interpolation Sharpness - "+str(overall_sharpness))

		# for i in range(self.num_test_images):

		# 	path = self.impath+'_Testing_'+str(self.total_count.numpy())+'_TestCase_'+str(i)+'.png'
		# 	label = 'TEST SAMPLES AT ITERATION '+str(self.total_count.numpy())

		# 	size_figure_grid = self.num_to_print
		# 	test_batch_size = size_figure_grid*size_figure_grid
		# 	noise = tf.random.normal([self.batch_size, self.noise_dims],self.noise_mean, self.noise_stddev)

		# 	images = self.generator(noise, training=False)
		# 	if self.data != 'celeba':
		# 		images = (images + 1.0)/2.0

		# 	self.save_image_batch(images = images,label = label, path = path)

		# self.impath += '_Testing_'
		# for img_batch in self.train_dataset:
		# 	self.reals = img_batch
		# 	self.generate_and_save_batch(0)
		# 	return

'''***********************************************************************************
********** The RBF-PHS Solver *************************************************
***********************************************************************************'''
class RBFSolver():

	def __init__(self):
		from itertools import product as cart_prod

		if self.data in ['g2', 'gmm8']:
			self.latent_dims = 2
		self.N = self.rbf_n = self.latent_dims

		self.c = 0

		### Generating MultiIndices of polynomials
		if self.gan in ['LSGAN']:
			self.multi_index = np.zeros((1,self.rbf_n))
			## m^th order penalty has an (m-1)^th order polynomial
			for j in range(1,self.rbf_m): #### Used to use rbf_m+1
				x = np.arange(0,self.rbf_n,1)
				bins = np.arange(0,self.rbf_n+1,1)
				a = combinations_with_replacement(x,j)
				for elem in a:
					elem_arr = np.asarray(elem)
					elem_arr = np.expand_dims(elem_arr,axis = 0)
					h,bins = np.histogram(elem_arr,bins=list(bins))
					h = np.expand_dims(h,axis = 0)
					self.multi_index = np.concatenate((self.multi_index,h),axis = 0)
			print(self.multi_index)
			self.indices = tf.cast(self.multi_index, dtype = 'float32')
			print("~~~~~~~~~")

			self.dim_v = self.multi_index.shape[0]
			print("Dimensionality of PolyCoeff vector =",self.dim_v)
			self.LZeroMat = np.zeros((self.dim_v,self.dim_v))
			self.lambda_D = self.LSGANlambdaD

		## Defining the Solution cases based on m and n

		self.target_data = 'self.reals'
		self.generator_data = 'self.fakes'
		return

	def discriminator_model_RBF(self):

		if self.data not in ['g2','gmm8']:
			inputs = tf.keras.Input(shape=(self.output_size,self.output_size,self.output_dims))
			inputs_res = tf.keras.layers.Reshape(target_shape = [self.output_size*self.output_size*self.output_dims])(inputs)
		else:
			inputs = tf.keras.Input(shape=(self.latent_dims,))
			inputs_res = inputs

		num_centers = 2*self.batch_size

		if self.gan == 'LSGAN':
			[Out,A,B] = PHSLayer(num_centres=num_centers, output_dim=1,  dim_v = self.dim_v, rbf_k = self.rbf_m, batch_size = self.batch_size, multi_index = self.multi_index)(inputs_res)
			model = tf.keras.Model(inputs=inputs, outputs= [Out,A,B])

		return model

	def PHS_MatrixSolver(self, vals):#, centers, vals, phs_deg, poly_deg):
		N = self.A.shape[0]
		# print(self.B)
		Correction = -96*3.14159*self.lambda_D*tf.eye(N) ### Constants from Aronjszan et al, 1893 (Check Main Manuscript)

		self.BT = tf.transpose(self.B)
		M = tf.concat( (tf.concat((self.A+Correction,self.B), axis = 1),tf.concat((self.BT,self.LZeroMat), axis = 1)), axis = 0)

		y = tf.concat((vals,tf.zeros((self.dim_v,1))), axis = 0)
		sols = tf.linalg.solve(M,y)

		Weights = tf.squeeze(sols[0:N])
		PolyWts = sols[N:]

		return Weights, PolyWts

	def find_rbf_centres_weights(self):

		C_d = eval(self.target_data)[0:self.N_centers] #SHould be NDxn
		C_g = eval(self.generator_data)[0:self.N_centers]
		check = 1
		if self.data not in ['g2','gmm8']:
			C_d = tf.reshape(C_d, [C_d.shape[0], C_d.shape[1]*C_d.shape[2]*C_d.shape[3]])
			C_g = tf.reshape(C_g, [C_g.shape[0], C_g.shape[1]*C_g.shape[2]*C_g.shape[3]])

		Centres = np.concatenate((C_d,C_g), axis = 0)

		if self.gan == 'LSGAN':
			d_vals = self.label_b*tf.ones((C_d.shape[0],1))
			g_vals = self.label_a*tf.ones((C_g.shape[0],1))
			Values = np.concatenate((d_vals,g_vals), axis = 0)

			Weights, PolyWeights = self.PHS_MatrixSolver(vals = Values)

			return Centres, Weights, PolyWeights

class PHSLayer(tf.keras.layers.Layer):
	""" Layer of Gaussian RBF units.
	# Example
	```python
		model = Sequential()
		model.add(RBFLayer(10,
						   initializer=InitCentersRandom(X),
						   betas=1.0,
						   input_shape=(1,)))
		model.add(Dense(1))
	```
	# Arguments
		output_dim: number of hidden units (i.e. number of outputs of the
					layer)
		initializer: instance of initiliazer to initialize centers
		betas: float, initial value for betas
	"""

	def __init__(self, num_centres, output_dim, dim_v, rbf_k, multi_index, batch_size, initializer=None, **kwargs):

		# self.m = order_m
		self.dim_v = dim_v
		self.output_dim = output_dim #1 for us
		self.num_centres = num_centres #N for us
		self.rbf_k =rbf_k ## Shoudl be m?
		self.multi_index = tf.cast(multi_index, dtype = 'float32')
		print(self.multi_index.shape)
		# self.unif_weight = 1/batch_size
		if not initializer:
			self.initializer = tf.keras.initializers.RandomUniform(0.0, 1.0)
		else:
			self.initializer = initializer
		super(PHSLayer, self).__init__(**kwargs)

	def build(self, input_shape):
		# print(input_shape) ## Should be NB x n
		self.n = input_shape[1]
		self.centers = self.add_weight(name='centers',
									   shape=(self.num_centres, input_shape[1]), ## Nxn
									   initializer=self.initializer,
									   trainable=True)
		self.rbf_weights = self.add_weight(name='rbf_weights',
									 shape=(self.num_centres,), ## N,1
									 # initializer=tf.keras.initializers.Constant(value=self.unif_weight),
									 initializer='ones',
									 trainable=True)
		self.poly_weights = self.add_weight(name='poly_weights',
									 shape=(self.dim_v,1), ## L,1
									 # initializer=tf.keras.initializers.Constant(value=self.unif_weight),
									 initializer='ones',
									 trainable=True)

		super(PHSLayer, self).build(input_shape)

	def call(self, X):

		def odd_PHS(f,order):
			norm_f = tf.norm(f, ord = 'euclidean', axis = 2)
			ord_tensor = order*tf.ones_like(norm_f)
			Phi = 1*tf.pow(norm_f, ord_tensor) ## Nx1
			return Phi

		def even_PHS(f,order):
			norm_f = tf.norm(f, ord = 'euclidean', axis = 2)
			ord_tensor = order*tf.ones_like(norm_f)
			Phi = 1*tf.multiply(tf.pow(norm_f, ord_tensor),tf.math.log(norm_f+10.0**(-100)))##Nx1
			return Phi

		X = tf.expand_dims(X, axis = 2) ## X in Nonexnx1
		# print('Input X',X, X.shape)
		Cp = C = tf.expand_dims(self.centers, axis = 2) ## Nxnx1
		# print('Centers C', C, C.shape)
		C = tf.expand_dims(C, axis = 0) ## 1xNxnx1
		C_tiled = tf.tile(C, [tf.shape(X)[0],1,1,1]) ## NonexNxnx1
		X = tf.expand_dims(X, axis = 1) ## Nonex1xnx1
		X_tiled = tf.tile(X, [1,self.num_centres,1,1]) ## NonexNxnx1
		# print('C_tiled', C_tiled, C_tiled.shape)
		# print('X_tiled', X_tiled, X_tiled.shape)
		Tau = C_tiled - X_tiled ## NonexNxnx1 = NonexNxnx1 - NonexNxnx1
		# print('Tau', Tau)

		#### 1) We compute the Polyharmonic part of PHS D(x)
		self.m_given_k = tf.math.ceil((self.rbf_k + self.n)/2.)
		if self.rbf_k%2 == 1:
			Phi = odd_PHS(Tau,self.rbf_k) ## NonexNx1
		else:
			Phi = even_PHS(Tau,self.rbf_k) ## NonexNx1

		# print('Phi', Phi)
		W = tf.expand_dims(self.rbf_weights, axis = 1) ## Nx1
		# print('W', W)
		D_PHS = tf.squeeze(tf.linalg.matmul(W, Phi, transpose_a=True, transpose_b=False),axis = 2) ## Nonex1

		PolyPow = tf.expand_dims(self.multi_index, axis = 2) ## Lxnx1
		PolyPow = tf.expand_dims(PolyPow, axis = 0) ## 1xLxnx1
		# print('PolyPow',PolyPow)
		PolyPow_PowTiled = tf.tile(PolyPow, [tf.shape(X)[0],1,1,1]) ## NonexLxnx1
		# print('PolyPow_PowTiled',PolyPow_PowTiled)
		X_PowTiled = tf.tile(X, [1,self.dim_v,1,1]) ## NonexLxnx1
		# print('X_PowTiled',X_PowTiled)
		X_Pow = tf.pow(X_PowTiled, PolyPow_PowTiled) ## NonexLxnx1
		# print('X_Pow',X_Pow)
		X_PowPord = tf.reduce_prod(X_Pow, axis = 2) ## NonexLx1
		# print('X_PowPord',X_PowPord)
		# V = tf.expand_dims(self.poly_weights, axis = 1) ## Lx1
		V = self.poly_weights
		# print('V',V)
		D_Poly = tf.squeeze(tf.linalg.matmul(V, X_PowPord, transpose_a=True, transpose_b=False),axis = 2) ## Nonex1

		D = D_PHS + D_Poly

		#### 3) We compute the matrix A for PHS weight computation

		C_NxN = tf.tile(C, [self.num_centres,1,1,1]) ## 1xNxnx1 -> ## NxNxnx1
		Tau_C = C_NxN - tf.transpose(C_NxN, perm=[1,0,2,3]) ## NxNxnx1

		corr = 8*tf.acos(-1.)*10e-1*tf.eye(self.num_centres)
		corr = tf.expand_dims(corr,axis = 2)
		corr = tf.expand_dims(corr,axis = 3)
		corr = tf.tile(corr, [1,1,self.n,1])

		Tau_C = Tau_C + corr

		# print('Tau_C',Tau_C)
		if self.rbf_k%2 == 1:
			A = odd_PHS(Tau_C,self.rbf_k) ## NxNx1
		else:
			A = even_PHS(Tau_C,self.rbf_k) ## NxNx1
		# print('A', A)
		A = tf.squeeze(A) ## NxN
		# print('A squeezed', A)

		#### 4) We compute the matrix B for PHS weight computation

		PolyPow_CTiled = tf.tile(PolyPow, [self.num_centres,1,1,1]) ## NxLxnx1
		# print('PolyPow_CTiled',PolyPow_CTiled)
		Cp = tf.expand_dims(Cp, axis = 1) ## Nx1xnx1
		# print('Cp',Cp)
		Cp_Tiled = tf.tile(Cp, [1, self.dim_v,1,1]) ## NxLxnx1
		# print('Cp_Tiled',Cp_Tiled)
		C_Pow = tf.pow(Cp_Tiled, PolyPow_CTiled) ## NxLxnx1
		# print('C_Pow',C_Pow)
		C_PowPord = tf.reduce_prod(C_Pow, axis = 2) ## NxLx1
		# print('C_PowPord',C_PowPord)
		B = tf.squeeze(C_PowPord) ## NxL
		if self.rbf_k == 1: ###  1 if the monomials code does not include rbf_m + 1
			B = tf.expand_dims(B,axis = 1)
		# print('B squeezed', B)
		return [D,A,B]

	def compute_output_shape(self, input_shape):
		return [(input_shape[0], self.output_dim), \
				(self.num_centres, self.num_centres), \
				(self.dim_v, self.num_centres)]

	def get_config(self):
		# have to define get_config to be able to use model_from_json
		config = {
			'output_dim': self.output_dim
		}
		base_config = super(PHSLayer, self).get_config()
		return dict(list(base_config.items()) + list(config.items()))


import sys
import maya.OpenMaya as OpenMaya
import maya.OpenMayaMPx as OpenMayaMPx

kPluginNodeName = "CyclesObjectAreaLightShader"
kPluginNodeClassify = "shader/surface"
kPluginNodeId = OpenMaya.MTypeId(0x87024)

class arealight(OpenMayaMPx.MPxNode):
    def __init__(self):
        OpenMayaMPx.MPxNode.__init__(self)
        mOutColor = OpenMaya.MObject()
        mRadiance = OpenMaya.MObject()
        mSamplingWeight = OpenMaya.MObject()

    def compute(self, plug, block):
        if plug == arealight.mOutColor:
            resultColor = OpenMaya.MFloatVector(0.0,0.0,0.0)

            outColorHandle = block.outputValue( arealight.mOutColor )
            outColorHandle.setMFloatVector(resultColor)
            outColorHandle.setClean()
        else:
            return OpenMaya.kUnknownParameter

def nodeCreator():
    return arealight()

def nodeInitializer():
    nAttr = OpenMaya.MFnNumericAttribute()

    try:
        arealight.mRadiance = nAttr.createColor("radiance", "rd")
        nAttr.setDefault(1.0, 1.0, 1.0)
        nAttr.setKeyable(1)
        nAttr.setStorable(1)
        nAttr.setReadable(1)
        nAttr.setWritable(1)

        arealight.mSamplingWeight = nAttr.create("samplingWeight", "sw", OpenMaya.MFnNumericData.kInt, 1)
        nAttr.setKeyable(1)
        nAttr.setStorable(1)
        nAttr.setReadable(1)
        nAttr.setWritable(1)

        arealight.mOutColor = nAttr.createColor("outColor", "oc")
        nAttr.setStorable(0)
        nAttr.setHidden(0)
        nAttr.setReadable(1)
        nAttr.setWritable(0)

    except:
        sys.stderr.write("Failed to create attributes\n")
        raise

    try:
        arealight.addAttribute(arealight.mRadiance)
        arealight.addAttribute(arealight.mSamplingWeight)
        arealight.addAttribute(arealight.mOutColor)
    except:
        sys.stderr.write("Failed to add attributes\n")
        raise

    try:
        arealight.attributeAffects (arealight.mRadiance, arealight.mOutColor)
    except:
        sys.stderr.write("Failed in setting attributeAffects\n")
        raise

# initialize the script plug-in
def initializePlugin(mobject):
    mplugin = OpenMayaMPx.MFnPlugin(mobject)
    try:
        mplugin.registerNode( kPluginNodeName, kPluginNodeId, nodeCreator,
                    nodeInitializer, OpenMayaMPx.MPxNode.kDependNode, kPluginNodeClassify )
    except:
        sys.stderr.write( "Failed to register node: %s" % kPluginNodeName )
        raise

# uninitialize the script plug-in
def uninitializePlugin(mobject):
    mplugin = OpenMayaMPx.MFnPlugin(mobject)
    try:
        mplugin.deregisterNode( kPluginNodeId )
    except:
        sys.stderr.write( "Failed to deregister node: %s" % kPluginNodeName )
        raise


#!/usr/bin/python3

import pyndri

index = pyndri.Index("FinalIndex")

f = index.get_term_frequencies()
dm = index.maximum_document()
t = index.document_base()
m = max(f.keys())

o=open("docs_vec.txt","w")

for i in range(t,dm):
    d = index.document(i)
    c = 0
    s=""
    for j in range(1,m):
        if d[1].count(j) == 0:
           c = c+1
        else:
           if c > 0:
              s+= "0," +str(c)+","
           s += str(d[1].count(j)) +","
           c = 0
    o.write(s[:len(s)-1] +"\n")


'''
Dynamitelaw

Plotter for simulation results
'''

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd

def plotResults(results):
    '''
    Plots the results of a single simulation run. results must be a dictionary
    in the following format:
        {
            "General Stats":
            {
                "Start Date":str, "End Date":str, "Days Run":int, "Starting Assets":float, "Ending Assets":float,
                Yearly Growth Rate":float, "Average Trades Per Day":float, "Average Trade %Profit":float, "Average Hold Length":float
            },
            "Stats vs Time":dataFrame,
            "Trade Stats":dataFrame
        }
    '''
    #Extract Stats
    generalStats = results["General Stats"]
    statsVsTime = results["Stats vs Time"]
    tradeStats = results["Trade Stats"]

    #RGB Color Values
    textColor = (230/255,219/255,116/255) #Sublime Text Yellow
    facecolor=(39/255,40/255,34/255) #Sublime Dark Grey
    graphcolor = (49/255,50/255,44/255) #Slightly lighter grey
    axisColor = (200/255,200/255,200/255) #Mostly White
    green = (76/255,255/255,0/255)
    red = (255/255,20/255,0/255)

    #Set up Subplots
    fig, axes = plt.subplots(facecolor=facecolor,nrows=2, ncols=2)
    fig.set_size_inches((9,6))
    axes[0, 1].axis('off')
    axes[1, 1].axis('off')
    #axes[2, 1].axis('off') (76/255,255/255,0/255)

    #Assets over Time
    if (generalStats["Ending Assets"] > generalStats["Starting Assets"]):
        assetLineColor = green
    else:
        assetLineColor = red

    assets = statsVsTime["TotalAssets"].plot(ax=axes[0, 0], color=assetLineColor)
    assets.set_facecolor(graphcolor)
    assets.spines['bottom'].set_color(axisColor)
    assets.spines['top'].set_color(axisColor)
    assets.spines['right'].set_color(axisColor)
    assets.spines['left'].set_color(axisColor)
    assets.tick_params(axis='x', colors=axisColor)
    assets.tick_params(axis='y', colors=axisColor)
    assets.yaxis.label.set_color(axisColor)
    assets.xaxis.label.set_color(axisColor)
    assets.set_ylabel("Total Assets ($)", color=textColor)

    assetsDescription = generalStats["Start Date"] + " to " + generalStats["End Date"] + " | " + str(generalStats["Days Run"]) + " Days\n"
    assetsDescription += "Starting Assets: \$" + str(generalStats["Starting Assets"]) + "  | Ending Assets: \$" + str(generalStats["Ending Assets"]) + "\n"
    assetsDescription += "Estimated Yearly Growth Rate: " + str(int(generalStats["Yearly Growth Rate"] * 10000)/100.0) + "%"
    axes[0,1].text(-0.14, 0.4, assetsDescription, color=textColor)

    '''
    #Growth Rate over Time
    statsVsTime.loc[:,"EstYearlyGrowthRate(Past30Days)"] *= 100
    growthRate = statsVsTime["EstYearlyGrowthRate(Past30Days)"].plot(ax=axes[1,0])
    growthRate.set_facecolor(graphcolor)
    growthRate.set_ylabel("Est Growth Rate (%)", color=textColor)
    growthRateDescription = "Estimated Yearly Growth Rate: " + str(int(generalStats["Yearly Growth Rate"] * 10000)/100.0) + "%"
    axes[1,1].text(-0.14, 0.4, growthRateDescription, color=textColor)
    '''

    #Trade Histogram
    maxProfit = tradeStats["Percent Profit"].max()
    minProfit = tradeStats["Percent Profit"].min()

    #Split trades into positive and negative profits
    positiveProfits = []
    negativeProfits = []
    for i in range(0, len(tradeStats["Percent Profit"]), 1):
        profit = tradeStats.at[i, "Percent Profit"]
        if (profit>0):
            positiveProfits.append(profit)
        else:
            negativeProfits.append(profit)

    #Generate Bins
    numberOfBins = 30
    binWidth = (maxProfit - minProfit) / numberOfBins
    bins = []
    bins.append(0)

    #Negative Bins
    while (True):
        newBin = bins[0] - binWidth
        bins.insert(0, newBin)
        if (newBin < minProfit):
            break

    #Postive Bins
    while (True):
        newBin = bins[len(bins)-1] + binWidth
        bins.append(newBin)
        if (newBin > maxProfit):
            break

    #Generate Histograms
    axes[1,0].hist(negativeProfits, bins, label='y', color=red)
    axes[1,0].hist(positiveProfits, bins,  label='x', color=green)

    #Histogram Styling
    axes[1,0].set_facecolor(graphcolor)
    axes[1,0].spines['bottom'].set_color(axisColor)
    axes[1,0].spines['top'].set_color(axisColor)
    axes[1,0].spines['right'].set_color(axisColor)
    axes[1,0].spines['left'].set_color(axisColor)
    axes[1,0].tick_params(axis='x', colors=axisColor)
    axes[1,0].tick_params(axis='y', colors=axisColor)
    axes[1,0].yaxis.label.set_color(axisColor)
    axes[1,0].xaxis.label.set_color(axisColor)
    axes[1,0].set_xlabel("Per Trade Profit (%)", color=textColor)
    axes[1,0].set_ylabel("Frequency", color=textColor)
    HistogramDescription = "Average Trades Per Day: " + str(int(generalStats["Average Trades Per Day"] * 100)/100.0) + "\n"
    HistogramDescription += "Average Profit Per Trade: " + str(int(generalStats["Average Trade %Profit"] * 100)/100.0) + "%\n"
    HistogramDescription += "Average Hold Length:       " + str(int(generalStats["Average Hold Length"] * 100)/100.0) + " days\n"
    axes[1,1].text(-0.14, 0.2, HistogramDescription, color=textColor)

    #Show Plot
    plt.tight_layout()  #NOTE https://matplotlib.org/users/tight_layout_guide.html
    plt.show()

def plotMultipleResults(listOfResults):
    '''
    Plots the results of a multple simulation runs. Each result must be a dictionary
    in the following format:
        {
            "General Stats":
            {
                "Start Date":str, "End Date":str, "Days Run":int, "Starting Assets":float, "Ending Assets":float,
                Yearly Growth Rate":float, "Average Trades Per Day":float, "Average Trade %Profit":float, "Average Hold Length":float
            },
            "Stats vs Time":dataFrame,
            "Trade Stats":dataFrame
        }
    '''
    #RGB Color Values
    textColor = (230/255,219/255,116/255) #Sublime Text Yellow
    facecolor=(39/255,40/255,34/255) #Sublime Dark Grey
    graphcolor = (49/255,50/255,44/255) #Slightly lighter grey
    axisColor = (200/255,200/255,200/255) #Mostly White
    green = (76/255,255/255,0/255)
    red = (255/255,20/255,0/255)

    #Set up Subplots
    fig, axes = plt.subplots(facecolor=facecolor,nrows=3, ncols=2)
    axes[0, 1].axis('off')
    axes[1, 1].axis('off')
    axes[2, 1].axis('off')

    #Extract Stats Over Time

    #Assets over Time
    statsVsTimeColumns = []
    for simNumber in range(0, len(listOfResults), 1):
        columnName = "Simulation " + str(simNumber + 1)
        statsVsTimeColumns.append(columnName)

    statsVsTime = pd.DataFrame(columns=statsVsTimeColumns)

    lineColors = []
    for columnNumber in range(0, len(statsVsTimeColumns), 1):
        statsVsTime[statsVsTimeColumns[columnNumber]] = listOfResults[columnNumber]["Stats vs Time"]["TotalAssets"]

        if (listOfResults[columnNumber]["General Stats"]["Ending Assets"] > listOfResults[columnNumber]["General Stats"]["Starting Assets"]):
            assetLineColor = green
        else:
            assetLineColor = red
        lineColors.append(assetLineColor)

    #Average Ending Assets
    endingAssetsList = []
    for result in listOfResults:
        endingAssets = result["General Stats"]["Ending Assets"]
        endingAssetsList.append(endingAssets)
    endingAssetsList = sorted(endingAssetsList)

    averageEndingAssets = int((sum(endingAssetsList) / len(endingAssetsList))*100)/100.0

    #Plot Assets over Time
    assets = statsVsTime.plot(ax=axes[0, 0], color=lineColors, legend=False)
    assets.set_facecolor(graphcolor)
    assets.spines['bottom'].set_color(axisColor)
    assets.spines['top'].set_color(axisColor)
    assets.spines['right'].set_color(axisColor)
    assets.spines['left'].set_color(axisColor)
    assets.tick_params(axis='x', colors=axisColor)
    assets.tick_params(axis='y', colors=axisColor)
    assets.yaxis.label.set_color(axisColor)
    assets.xaxis.label.set_color(axisColor)
    assets.set_ylabel("Total Assets ($)", color=textColor)

    assetsDescription = listOfResults[0]["General Stats"]["Start Date"] + " to " + listOfResults[0]["General Stats"]["End Date"] + " | " + str(listOfResults[0]["General Stats"]["Days Run"]) + " Days\n"
    assetsDescription += "Starting Assets: \$" + str(listOfResults[0]["General Stats"]["Starting Assets"]) + "  | Average Ending Assets: \$" + str(averageEndingAssets) + "\n"
    assetsDescription += "Minimum Ending Assets: \$" + str(endingAssetsList[0]) + "\n"
    assetsDescription += "Maximum Ending Assets: \$" + str(endingAssetsList[-1])
    axes[0,1].text(-0.14, 0.3, assetsDescription, color=textColor)

    #Average Growth Rates
    growthRates = []
    positiveGrowthRates = []
    negativeGrowthRates = []
    for result in listOfResults:
        growthRate = result["General Stats"]["Yearly Growth Rate"] * 100
        growthRates.append(growthRate)
        if (growthRate>=0):
            positiveGrowthRates.append(growthRate)
        else:
            negativeGrowthRates.append(growthRate)

    growthRates = sorted(growthRates)
    averageGrowthRate = int((sum(growthRates) / len(growthRates))*100)/100.0

    #Generate Bins
    numberOfBins = 20
    maxRate = growthRates[-1]
    minRate = growthRates[0]
    binWidth = (maxRate - minRate) / numberOfBins
    bins = []
    bins.append(0)

    #Negative Bins
    while (True):
        newBin = bins[0] - binWidth
        bins.insert(0, newBin)
        if (newBin < minRate):
            break

    #Postive Bins
    while (True):
        newBin = bins[len(bins)-1] + binWidth
        bins.append(newBin)
        if (newBin > maxRate):
            break

    #Generate Growth Rate Histograms
    axes[1,0].hist(negativeGrowthRates, bins, label='y', color=red)
    axes[1,0].hist(positiveGrowthRates, bins,  label='x', color=green)

    #Growth Histogram Styling
    axes[1,0].set_facecolor(graphcolor)
    axes[1,0].spines['bottom'].set_color(axisColor)
    axes[1,0].spines['top'].set_color(axisColor)
    axes[1,0].spines['right'].set_color(axisColor)
    axes[1,0].spines['left'].set_color(axisColor)
    axes[1,0].tick_params(axis='x', colors=axisColor)
    axes[1,0].tick_params(axis='y', colors=axisColor)
    axes[1,0].yaxis.label.set_color(axisColor)
    axes[1,0].xaxis.label.set_color(axisColor)
    axes[1,0].set_xlabel("Year Growth Rate (%)", color=textColor)
    axes[1,0].set_ylabel("Frequency", color=textColor)

    growthHistogramDescription = "Average Yearly Growth Rate: " + str(averageGrowthRate) + "%"
    axes[1,1].text(-0.14, 0.4, growthHistogramDescription, color=textColor)

    #Extract Trade Stats
    tradeStats = listOfResults[0]["Trade Stats"]["Percent Profit"]

    for i in range(1, len(listOfResults), 1):
        tradeStats = tradeStats.append(listOfResults[1]["Trade Stats"]["Percent Profit"], ignore_index=True)

    #Trade Histogram
    maxProfit = tradeStats.max()
    minProfit = tradeStats.min()

    #Split trades into positive and negative profits
    positiveProfits = []
    negativeProfits = []
    for i in range(0, len(tradeStats), 1):
        profit = tradeStats[i]
        if (profit>0):
            positiveProfits.append(profit)
        else:
            negativeProfits.append(profit)

    #Generate Bins
    numberOfBins = 35
    binWidth = (maxProfit - minProfit) / numberOfBins
    bins = []
    bins.append(0)

    #Negative Bins
    while (True):
        newBin = bins[0] - binWidth
        bins.insert(0, newBin)
        if (newBin < minProfit):
            break

    #Postive Bins
    while (True):
        newBin = bins[len(bins)-1] + binWidth
        bins.append(newBin)
        if (newBin > maxProfit):
            break

    #Generate Histograms
    axes[2,0].hist(negativeProfits, bins, label='y', color=red)
    axes[2,0].hist(positiveProfits, bins,  label='x', color=green)

    #Extract averages
    tradesPerDay = []
    holdLengths = []
    for result in listOfResults:
        tradesPerDay.append(result["General Stats"]["Average Trades Per Day"])
        holdLengths.append(result["General Stats"]["Average Hold Length"])

    averageTradesPerDay = int(sum(tradesPerDay)/len(tradesPerDay)*100)/100.0
    averageHoldLength = int(sum(holdLengths)/len(holdLengths)*100)/100.0
    averageTradeProfit = int(tradeStats.mean()*100)/100.0

    #Trade Histogram Styling
    axes[2,0].set_facecolor(graphcolor)
    axes[2,0].spines['bottom'].set_color(axisColor)
    axes[2,0].spines['top'].set_color(axisColor)
    axes[2,0].spines['right'].set_color(axisColor)
    axes[2,0].spines['left'].set_color(axisColor)
    axes[2,0].tick_params(axis='x', colors=axisColor)
    axes[2,0].tick_params(axis='y', colors=axisColor)
    axes[2,0].yaxis.label.set_color(axisColor)
    axes[2,0].xaxis.label.set_color(axisColor)
    axes[2,0].set_xlabel("Per Trade Profit (%)", color=textColor)
    axes[2,0].set_ylabel("Frequency", color=textColor)

    tradeHistogramDescription = "Average Trades Per Day: " + str(averageTradesPerDay) + "\n"
    tradeHistogramDescription += "Average Profit Per Trade: " + str(averageTradeProfit) + "%\n"
    tradeHistogramDescription += "Average Hold Length:       " + str(averageHoldLength) + " days\n"
    axes[2,1].text(-0.14, 0.2, tradeHistogramDescription, color=textColor)

    #Show Plot
    plt.tight_layout()  #NOTE https://matplotlib.org/users/tight_layout_guide.html
    plt.show()


from django.conf.urls import url
from users import views

urlpatterns = [
    url(r'^$', views.UserList.as_view(), name='user-list'),
    url(r'^user/create/$', views.UserCreate.as_view(), name='create-user'),
    url(r'^user/(?P<pk>\d+)/edit/$', views.UserUpdate.as_view(), name='user-edit'),
    url(r'^user/(?P<pk>\d+)/remove/$', views.UserRemove.as_view(), name='remove-user'),
    url(r'^user/(?P<pk>\d+)/$', views.UserDetail.as_view(), name='user-detail'),
    url(r'^user/export_csv/$', views.export_users_csv, name='export-users-csv'),
]