# -*- encoding: utf-8 -*-
from django.db import models
from django.conf import settings
from django.contrib.auth.models import User
from image_cropping import ImageRatioField, ImageCropField
from django.contrib.contenttypes import generic
from django.contrib.contenttypes.models import ContentType

import os

#Tratamientos
class Machine(models.Model):
	owner = models.ForeignKey(settings.AUTH_USER_MODEL)
	name = models.CharField('Nombre de la maquina', max_length=25)
	availability = models.PositiveIntegerField('Cantidad disponible')
	def __str__(self):
		return "{}".format(self.name)
	class Meta:
		verbose_name = "maquina"

class BaseTreatment(models.Model):
	TREATMENT_TYPES = (
		(0, 'Con maquinas'),
		(1, 'Sin maquinas')
	)
	name = models.CharField('Nombre', max_length=25)
	description = models.CharField('Descripción', max_length=1200)
	treatment_type = models.IntegerField('Tipo de tratamiento', null=True, choices=TREATMENT_TYPES)
	time_needed = models.DurationField('Duración del turno')
	class Meta:
		abstract = True

class MachineTreatment(models.Model):
	machine_used = models.ForeignKey(Machine)
	class Meta:
		abstract = True

class ByHandTreatment(models.Model):
	owner = models.ForeignKey(settings.AUTH_USER_MODEL)
	class Meta:
		abstract = True

class Treatment(ByHandTreatment, MachineTreatment, BaseTreatment):
	pass

	def __str__(self):
		return "{}".format(self.name)

	class Meta:
		verbose_name = "tratamiento"

#Gabinetes, Locales y Empresa
def logo_dir(instance, filename):
	return os.path.join("company-{0}".format(instance.name.replace(" ", "-")), filename)

class Company(models.Model):
	owner = models.ForeignKey(settings.AUTH_USER_MODEL)
	name = models.CharField("Nombre de la empresa", max_length=35, blank=True)
	cuit = models.PositiveIntegerField('CUIT', blank=True)
	loading_date = models.DateField(auto_now=True)
	logo = models.ImageField(upload_to = logo_dir)

	def __str__(self):
		return "{0}".format(self.name)

	class Meta:
		verbose_name = "empresa"

class Branch(models.Model):
	owner = models.ForeignKey(Company)

	street = models.CharField("calle", max_length=30)
	number = models.PositiveIntegerField("numero")
	flat = models.PositiveIntegerField("piso", default=0)
	department = models.CharField("depto.", max_length=2, null=True)
	postcode = models.PositiveIntegerField("codigo postal")

	def __str__(self):
		return "{} {} {}-{}".format(self.street, self.number, self.flat, self.department)

	class Meta:
		verbose_name = "local"
		verbose_name_plural = "locales"

class Cabinet(models.Model):
	branch = models.ForeignKey(Branch, verbose_name="local")
	number = models.PositiveIntegerField("Numero", help_text='Identificador para el gabinete')
	treatments = models.ManyToManyField(Treatment, verbose_name="tratamientos disponibles", help_text="tener en cuenta disponibilidad de maquinas")

	def __str__(self):
		return "Gabinete {} en local {}".format(self.number, self.branch)

	class Meta:
		verbose_name = "gabinete"
		verbose_name_plural = "gabinetes"

#Clientes
def customer_dir(instance, filename):
	return os.path.join("company-{0}".format(instance.loaded_by.name.replace(" ", "-")), filename)

class Customer(models.Model):
	WHATSAPP = "WA"
	FACEBOOK = "FB"
	EMAIL = "EM"

	COMMUNICATION_CHOICES = (
		(WHATSAPP, "Mensaje de WhatsApp"),
		(FACEBOOK, "Mensaje de Facebook"),
		(EMAIL, "Email"),
	)

	REFERIDO = "RE"
	PUBLI_CLASSIC = "CL"
	PUBLI_INET = "IN"
	OTRO = "OT"

	SOURCE_CHOICES = (
		(REFERIDO, "Por otra clienta"),
		(FACEBOOK, "Facebook Inc."),
		(PUBLI_CLASSIC, "Folleto y graficas"),
		(PUBLI_INET, "Publicidad en internet"),
		(OTRO, "Otro"),
	)

	FEMENINO = "MA"
	MASCULINO = "FE"
	OTRO = "OT"

	GENDER_CHOICES = (
		(FEMENINO, "Femenino"),
		(MASCULINO, "Masculino"),
		(OTRO, "Otro"),
	)

	name = models.CharField("Nombre", max_length=35)
	birthdate = models.DateField("Fecha de cumpleaños")

	owner = models.ForeignKey(settings.AUTH_USER_MODEL)

	phone = models.CharField("Telefono", max_length=16, blank=True)
	email = models.EmailField(blank=True)
	facebook = models.CharField(max_length=22, help_text="sin la url facebook.com", blank=True)
	whatsapp = models.BooleanField()

	communication = models.CharField("Medio de comunicación", max_length=2, choices=COMMUNICATION_CHOICES, blank=True)
	source = models.CharField("¿Como nos conociste?", max_length=2, choices=SOURCE_CHOICES)
	referer = models.ForeignKey("self", blank=True, null=True)

	photo = ImageCropField("Foto", upload_to=customer_dir)
	cropping = ImageRatioField('photo', '200x200')

	date = models.DateField(auto_now=True)
	gender = models.CharField(max_length=2, choices=GENDER_CHOICES)
	def thumbnail(self):
		return """<img border="0" alt="" src="/media/%s" height="40" />""" % (self.photo.name)
	thumbnail.allow_tags = True

	@property
	def age(self):
		today = datetime.date.today()
		return (today.year - self.birthdate.year) - int((today.month, today.day) < (self.birthdate.month, self.birthdate.day))

	def __str__(self):
		return "{0}".format(self.name)

	class Meta:
		verbose_name = "cliente"
		#verbose_name_plural = "clientes"

#Sesiones
class Session(models.Model):
	owner = models.ForeignKey(settings.AUTH_USER_MODEL)
	treatment = models.ForeignKey(Treatment)
	customer = models.ForeignKey(Customer)
	number_of_sessions = models.PositiveIntegerField('Cantidad de sesiones')
	price_total = models.FloatField('Precio total')
	price_cashed = models.FloatField('Precio pagado')
	date = models.DateField(auto_now=True)
	complete = models.BooleanField('Completado', default=False)

	def __str__(self):
		return "{} de {}".format(self.treatment.name, self.customer.name)

	class Meta:
		verbose_name = "sesion"
		verbose_name_plural = "sesiones"

#Turnos
class Turno(models.Model):
	owner = models.ForeignKey(settings.AUTH_USER_MODEL)

	date = models.DateTimeField("Fecha y hora")
	cabinet_used = models.ForeignKey(Cabinet, verbose_name="gabinete")
	limit = models.Q(app_label="gestor", model="comboasignado") | models.Q(app_label="gestor", model="session")
	content_type = models.ForeignKey(ContentType, limit_choices_to=limit)
	object_id = models.PositiveIntegerField()
	content_object = generic.GenericForeignKey('content_type', 'object_id')
	canceled = models.BooleanField('Cancelado', default=False)
	perdido = models.BooleanField(default=False)

	def __str__(self):
		return "el {} en gabinete {}".format(self.date.strftime("%d-%m-%Y %H:%M"), self.cabinet_used)

	class Meta:
		verbose_name = "turno"
		ordering = ['date',]

#Perfiles
def staff_directory(instance, filename):
	return os.path.join("company-{}".format(instance.user.company.name.replace(" ", "-")), "staff", filename)

class Profile(models.Model):
	FREE = "FR"
	PLATINUM = "PL"
	GOLD = "GL"
	ENTERPRISE = "EN"

	PLAN_CHOICES = (
		(FREE, "Gratis, 5 clientes 1 administrador"),
		(PLATINUM, "50 clientes, 2 administradores"),
		(GOLD, "250 clientes, 5 administradores"),
		(ENTERPRISE, "clientes y administradores ilimitados")
	)

	user = models.OneToOneField(settings.AUTH_USER_MODEL, primary_key=True)
	plan = models.CharField(max_length=2, choices=PLAN_CHOICES)
	photo = models.ImageField("Foto de perfil", upload_to=staff_directory)

	cropping = ImageRatioField('photo', '200x200')

	def __str__(self):
		return "{}".format(self.user.username)

	class Meta:
		verbose_name = "perfil"
		verbose_name_plural = "perfiles"

class Provider(models.Model):
	owner = models.ForeignKey(settings.AUTH_USER_MODEL)
	name = models.CharField('Nombre de fantasia', max_length=30)
	cuit = models.PositiveIntegerField('CUIT')

	street = models.CharField("calle", max_length=30)
	number = models.PositiveIntegerField("numero")
	flat = models.PositiveIntegerField("piso", default=0)
	department = models.CharField("depto.", max_length=2, null=True)
	postcode = models.PositiveIntegerField("codigo postal")

	phone = models.CharField('Telefono', max_length=25)
	mail = models.EmailField('email')
	bank_account = models.CharField('Cuenta', max_length=30, null=True, blank=True)

	def __str__(self):
		return "{}".format(self.name)

	class Meta:
		verbose_name = "proveedor"
		verbose_name_plural = "proveedores"

def product_dir(instance, filename):
	return os.path.join("company-{0}".format(instance.user.company.name.replace(" ", "-")), "products", filename)

class Product(models.Model):
	CENTIMETRO = "cc"
	MILILITRO = "ml"
	LITRO = "lt"
	KILO = "kg"
	GRAMO = "gr"

	SUFFIX_CHOICES = (
		(CENTIMETRO, "centimetros cubicos"),
		(MILILITRO, "mililitros"),
		(LITRO, "litro"),
		(KILO, "kilogramo"),
		(GRAMO, "gramo"),
	)

	owner = models.ForeignKey(settings.AUTH_USER_MODEL)
	provider = models.ForeignKey(Provider)

	product = models.CharField('Producto', max_length=35)
	sku = models.PositiveIntegerField('Codigo de barras')
	price = models.FloatField('Precio')
	porcentaje = models.PositiveIntegerField('Porcentaje de ganancia')
	quantity = models.PositiveIntegerField('Cantidad')

	presentation = models.PositiveIntegerField('presentacion')
	presentation_suffix = models.CharField('medida', max_length = 2, choices = SUFFIX_CHOICES)
	description = models.TextField('descripción')

	image = models.ImageField('Foto', upload_to = product_dir)
	cropping = ImageRatioField('image', '200x200')

	def __str__(self):
		return "{} de {} {}".format(self.product, self.presentation, self.presentation_suffix)

	class Meta:
		verbose_name = "producto"
		verbose_name_plural = "productos"

class Sale(models.Model):
	owner = models.ForeignKey(settings.AUTH_USER_MODEL)
	products = models.ManyToManyField(Product)
	cashed = models.FloatField('Cobrado')
	date = models.DateTimeField(auto_now = True)

	class Meta:
		verbose_name = "venta"
		verbose_name_plural = "ventas"

class AdminProfile(models.Model):
	owner = models.OneToOneField(settings.AUTH_USER_MODEL)
	image = models.ImageField(upload_to="staff")
	def __str__(self):
		return "Perfil administrativo de {}".format(self.user.username)

class Tip(models.Model):
	admin = models.ForeignKey(AdminProfile)
	message = models.CharField(max_length=200)
	url = models.URLField()
	def __str__(self):
		return "{}".format(self.message)

class Combo(models.Model):
	owner = models.ForeignKey(settings.AUTH_USER_MODEL)
	nombre = models.CharField(max_length=35)
	tratamientos = models.ManyToManyField(Treatment, through='ComboTratamiento')
	def __str__(self):
		return "{}".format(self.nombre)

class ComboTratamiento(models.Model):
	owner = models.ForeignKey(settings.AUTH_USER_MODEL)
	combo = models.ForeignKey(Combo)
	tratamiento = models.ForeignKey(Treatment)
	cantidad = models.PositiveIntegerField()

class ComboAsignado(models.Model):
	owner = models.ForeignKey(settings.AUTH_USER_MODEL)
	customer = models.ForeignKey(Customer)
	combo = models.ForeignKey(Combo)
	asignado = models.DateField(auto_now=True)
	complete = models.BooleanField('Completado', default=False)
	def __str__(self):
		return "{} {}".format(self.combo.nombre, self.customer.name)

def seguimiento_dir(instance, filename):
	return os.path.join("company-{0}".format(instance.owner.name.replace(" ", "-")), "seguimiento", instance.customer.name, filename)

class Seguimiento(models.Model):
	owner = models.ForeignKey(settings.AUTH_USER_MODEL)
	customer = models.ForeignKey(Customer)
	photo = models.ImageField('Foto', upload_to = seguimiento_dir)
	date = models.DateField('Fecha')


from PIL import Image
import os

print("Shrink images in the folder")
folder = r"..\..\projects\destiny-dc\leon-guide"
w = int('320')
h = int('240')
for i in os.listdir(folder):
    file = f"{folder}\\{i}"
    im = Image.open(file)
    im = im.resize((w, h), Image.ANTIALIAS)
    im.save(file,quality=20,optimize=True) # change 'file' to something else to avoid overwriting image in the same folder


# Bellman-Ford Algorithm

from .helpers import parse_graph
from math import inf, isinf

def nedges(graph):
    count = 0
    for _, outs in graph.items():
        for _ in outs:
            count += 1
    return count

def nodes(graph):
    s = list(graph.keys())
    e = [y["n"] for v in graph.values() for y in v]
    return set(s) | set(e)

def bf(graph, start=1):
    d = {n: inf for n in nodes(graph)}
    d[start] = 0
    for _ in range(nedges(graph) - 1):
        for u, x in graph.items():
            for v in x:
                if d[u] + v["w"] < d[v["n"]]:
                    d[v["n"]] = d[u] + v["w"]
    return ["x" if isinf(v) else v for k, v in d.items()]

def main(file):
    print(*bf(parse_graph(open(file), directed=True, weighted=True)))


#! /usr/bin/env python
# -*- coding: utf-8 -*-
# Coursework in Python
from IDAPICourseworkLibrary import *
from numpy import *
import math
import operator
#
# Coursework 1 begins here
#
# Function to compute the prior distribution of the variable root from the data set
def Prior(theData, root, noStates):
    prior = zeros((noStates[root]), float )
# Coursework 1 task 1 should be inserted here

    for i in xrange(theData.shape[0]):
        dp = theData[i, :] # Select a datapoint
        s = dp[root]    # State of the variable
        prior[s] += 1   # Increment

    prior_sum = sum(prior)
    # Normalize
    if prior_sum != 0:
        prior /= prior_sum
# end of Coursework 1 task 1
    return prior
# Function to compute a CPT with parent node varP and xchild node varC from the data array
# it is assumed that the states are designated by consecutive integers starting with 0
def CPT(theData, varC, varP, noStates):
    cPT = zeros((noStates[varC], noStates[varP]), float)
# Coursework 1 task 2 should be inserte4d here
    nP = zeros((noStates[varP]), float)
    # N(c2&d4)
    for i in xrange(noStates[varC]):
        for j in xrange(noStates[varP]):
            for k in xrange(theData.shape[0]):
                cPT[i, j] += (theData[k, varC] == i and theData[k, varP] == j)
    # N(c2)
    for j in xrange(noStates[varP]):
        for k in xrange(theData.shape[0]):
            nP[j] += (theData[k, varP] == j)

    # P(d4|c2) = N(c2&d4) / N(c2)
    for i in xrange(noStates[varC]):
        for j in xrange(noStates[varP]):
            if nP[j] != 0:
                cPT[i, j] /= nP[j]
# end of coursework 1 task 2
    return cPT
# Function to calculate the joint probability table of two variables in the data set
def JPT(theData, varRow, varCol, noStates):
    jPT = zeros((noStates[varRow], noStates[varCol]), float )
#Coursework 1 task 3 should be inserted here
    # P(c2&d4) == N(c2&d4) / len(theData)
    # N(c2&d4)
    for i in xrange(noStates[varRow]):
        for j in xrange(noStates[varCol]):
            for k in xrange(theData.shape[0]):
                jPT[i, j] += (theData[k, varRow] == i and theData[k, varCol] == j)
            # Normalize by the number of data points
            jPT[i, j] /= theData.shape[0]

# end of coursework 1 task 3
    return jPT
#
# Function to convert a joint probability table to a conditional probability table
def JPT2CPT(aJPT):
#Coursework 1 task 4 should be inserted here
    # Normalize columns to make them sum to 1
    for i in xrange(aJPT.shape[1]):
        norm_sum = sum(aJPT[:, i])
        if norm_sum != 0:
            aJPT[:, i] /= norm_sum
# coursework 1 taks 4 ends here
    return aJPT

#
# Function to query a naive Bayesian network
def Query(theQuery, naiveBayes):
    rootPdf = zeros((naiveBayes[0].shape[0]), float)
# Coursework 1 task 5 should be inserted here
    # naive Bayes - [Prior, cpt1, cpt2, cpt3]
    # the Query - instantiated states [....]
    for i in xrange(naiveBayes[0].shape[0]):
        # Prior for ci
        rootPdf[i] = naiveBayes[0][i]
        for j in xrange(1, len(theQuery)+1):
            # CPT - j | ci
            rootPdf[i] *= naiveBayes[j][theQuery[j - 1],i]

    # Normalize
    norm_sum = sum(rootPdf)

    if norm_sum != 0:
        rootPdf /= norm_sum
# end of coursework 1 task 5
    return rootPdf
#
# End of Coursework 1
#
# Coursework 2 begins here
#
# Calculate the mutual information from the joint probability table of two variables
def MutualInformation(jP):
    mi=0.0
# Coursework 2 task 1 should be inserted here

    for i in xrange(jP.shape[0]):
        for j in xrange(jP.shape[1]):
            if(jP[i,j]!=0):
                mi += jP[i,j] * math.log((jP[i,j] /(sum(jP[i,:])*sum(jP[:,j]))))/math.log(2)

# end of coursework 2 task 1
    return mi
#
# construct a dependency matrix for all the variables
def DependencyMatrix(theData, noVariables, noStates):
    MIMatrix = zeros((noVariables,noVariables))
# Coursework 2 task 2 should be inserted here
    for i in xrange(noVariables):
        for j in xrange(noVariables):
            jPT = JPT(theData,i,j,noStates)
            mutInfo = MutualInformation(jPT)
            MIMatrix[i,j] = MIMatrix[j,i] = mutInfo
            if (i==j):
                MIMatrix[i,j] = MIMatrix[j,i] = 0

# end of coursework 2 task 2
    return MIMatrix
# Function to compute an ordered list of dependencies
def DependencyList(depMatrix):
    depList=[]
# Coursework 2 task 3 should be inserted here
    copMatrix = depMatrix

    while (copMatrix.sum()!=0):
        #var1, var2 = max(enumerate(copMatrix), key=operator.itemgetter(1))
        maxNum = 0
        for i in xrange(copMatrix.shape[0]):
            for j in xrange(copMatrix.shape[1]):
                if(copMatrix[i,j]>maxNum):
                    maxNum = copMatrix[i,j]
                    node1 = i
                    node2 = j

        entry = [maxNum,node1,node2]
        depList = depList+[entry]
        copMatrix[node1,node2] = copMatrix[node2, node1] = 0

# end of coursework 2 task 3
    return array(depList)
#
# Functions implementing the spanning tree algorithm
# Coursework 2 task 4

def Root(unions, b):
    """Return the root set of an item
    Re-parents nodes while traversing them to minimize depth of a tree"""

    root = unions[b]

    while root != unions[root]:
        oldRoot = root
        root = unions[root]
        unions[oldRoot] = root

    unions[b] = root
    return root

def Unify(unions, a, b):
    """Merge two items into the same set"""
    rootA = Root(unions, a)
    rootB = Root(unions, b)

    unions[rootA] = rootB

def SpanningTreeAlgorithm(depList, noVariables):
    # unions[i] - root of a set tree to which the node belongs
    unions = zeros(noVariables, dtype=float32)

    spanningTree = []
    # Assume it is sorted
    sortedDepList = depList
    # Set each variable to be in its own set
    for i in xrange(noVariables):
        unions[i] = i

    # Iterate over the list of `dependencies`
    for i in xrange(sortedDepList.shape[0]):
        dep = sortedDepList[i, :]
        rootA = Root(unions, dep[1])
        rootB = Root(unions, dep[2])

        # To avoid loops check if variables do not belong to the same set
        if(rootA != rootB):
            Unify(unions, dep[1], dep[2])
            spanningTree.append(dep)

    return array(spanningTree)
#
# End of coursework 2
#
# Coursework 3 begins here
#
# Function to compute a CPT with multiple parents from he data set
# it is assumed that the states are designated by consecutive integers starting with 0
def CPT_2(theData, child, parent1, parent2, noStates):
    cPT = zeros([noStates[child],noStates[parent1],noStates[parent2]], float )
# Coursework 3 task 1 should be inserted here
    # Number of states for {}
    nsc = noStates[child]
    nsp1 = noStates[parent1]
    nsp2 = noStates[parent2]
    nP = zeros([noStates[parent1], noStates[parent2]], float)
    #N(c&p1&p2)
    for i in xrange(nsc):
        for j in xrange(nsp1):
            for k in xrange(nsp2):
                for l in xrange(theData.shape[0]):
                    cPT[i, j, k] += (theData[l, child] == i and
                                theData[l, parent1] == j and
                                theData[l, parent2] == k)

    #N(p1&p2)
    for j in xrange(nsp1):
        for k in xrange(nsp2):
            for l in xrange(theData.shape[0]):
                nP[j, k] += (
                            theData[l, parent1] == j and
                            theData[l, parent2] == k)

    #P(c|p1&p2) = N(c1&p1&p2) / N(p1&p2)
    for i in xrange(nsc):
        for j in xrange(nsp1):
            for k in xrange(nsp2):
                if nP[j, k] != 0:
                    cPT[i, j, k] /= nP[j, k]
# End of Coursework 3 task 1
    return cPT
#
# Definition of a Bayesian Network
def ExampleBayesianNetwork(theData, noStates):
    arcList = [[0],[1],[2,0],[3,2,1],[4,3],[5,3]]
    cpt0 = Prior(theData, 0, noStates)
    cpt1 = Prior(theData, 1, noStates)
    cpt2 = CPT(theData, 2, 0, noStates)
    cpt3 = CPT_2(theData, 3, 2, 1, noStates)
    cpt4 = CPT(theData, 4, 3, noStates)
    cpt5 = CPT(theData, 5, 3, noStates)
    cptList = [cpt0, cpt1, cpt2, cpt3, cpt4, cpt5]
    return arcList, cptList
# Coursework 3 task 2 begins here
def HepatitisCBayesianNetwork(theData, noStates):
    arcList = [[0],[1],[2,0],[3,4],[4,1],[5,4],[6,1],[7,0,1],[8,7]]
    cpt0 = Prior(theData, 0, noStates)
    cpt1 = Prior(theData, 1, noStates)
    cpt2 = CPT(theData, 2, 0, noStates)
    cpt3 = CPT(theData, 3, 4, noStates)
    cpt4 = CPT(theData, 4, 1, noStates)
    cpt5 = CPT(theData, 5, 4, noStates)
    cpt6 = CPT(theData, 6, 1, noStates)
    cpt7 = CPT_2(theData, 7, 0, 1, noStates)
    cpt8 = CPT(theData, 8, 7, noStates)
    cptList = [cpt0, cpt1, cpt2, cpt3, cpt4, cpt5, cpt6, cpt7, cpt8]
    return arcList, cptList
# end of coursework 3 task 2
#
# Function to calculate the MDL size of a Bayesian Network
def MDLSize(arcList, cptList, noDataPoints, noStates):
    mdlSize = 0.0
    Bn = 0.0
# Coursework 3 task 3 begins here
    # arcList connectivity - [0] is node [1:] are parents
    # cptList, conditional probability table for each nodes
    # N is the number of cases used to compute the probabilites
    N = noDataPoints

    # Compute number of parameters required to get probabilities for a node
    for i in xrange(len(arcList)):
        n = arcList[i][0]
        sh = cptList[n].shape

        shp = list(sh)
        shp[0] -= 1
        Bn += prod(shp)

    mdlSize = abs(Bn)
    mdlSize *= log2(N)
    mdlSize /= 2

# Coursework 3 task 3 ends here
    return mdlSize
#
# Function to calculate the joint probability of a single data point in a Network
def JointProbability(dataPoint, arcList, cptList):
    jP = 1.0
# Coursework 3 task 4 begins here
    # Get conditional probability for a node
    def getProbability(node):
        # Get correct probability table
        cpt = cptList[node]

        # Create index to the right entry in the table
        cptIndices = []
        for n in arcList[node]:
            cptIndices.append(dataPoint[n])

        # Return probablity
        prob = cpt[tuple(cptIndices)]
        return prob

    nodesToTraverse = range(len(arcList))
    while nodesToTraverse:
        # Get the first node in the queue
        node = nodesToTraverse.pop(0)
        # Get probability
        jP *= getProbability(node)

# Coursework 3 task 4 ends here
    return jP
#
# Function to calculate the MDLAccuracy from a data set
def MDLAccuracy(theData, arcList, cptList):
    mdlAccuracy=0
# Coursework 3 task 5 begins here
    for i in xrange(theData.shape[0]):
        jP = JointProbability(theData[i], arcList, cptList)
        if(jP != 0):
            mdlAccuracy += log2(jP)

# Coursework 3 task 5 ends here
    return mdlAccuracy

#Coursework 3 task 6 begins here
def BestScoringNet(theData, arcList, cptList, noDataPoints, noStates):
    import copy

    def buildNetwork(arcList):
        cptList = []
        for nodes in arcList:
            node = nodes[0]
            if(len(nodes) == 1):
                cpt = Prior(theData, node, noStates)
            elif(len(nodes) == 2):
                cpt = CPT(theData, node, nodes[1], noStates)
            else:
                cpt = CPT_2(theData, node, nodes[1], nodes[2], noStates)

            cptList.append(cpt)
        return arcList, cptList

    nnodes = len(arcList)
    init = True
    bestMDLScore = 0
    bestArcList = []
    bestCptList = []
    # Iterate over all possible arcs
    for arc in map(tuple, ([n1, n2] for n1 in range(nnodes) for n2 in range(nnodes) if n1 != n2)):
        # Check if this arc exists
        if arc[1] in arcList[arc[0]]:
            # Make a copy of the list
            newArcList = copy.deepcopy(arcList)
            # Remove the arc
            newArcList[arc[0]].remove(arc[1])

            # Build network
            _, newCptList = buildNetwork(newArcList)

            # Compute mdlScore for the new network
            mdlScore = MDLSize(newArcList, newCptList, noDataPoints, noStates) - MDLAccuracy(theData, newArcList, newCptList)

            # Save the best results (if there is a previous result)
            if mdlScore < bestMDLScore or init:
                init = False
                bestMDLScore = mdlScore
                bestArcList = newArcList
                bestCptList = newCptList

    return bestArcList, bestCptList

#
# End of coursework 3
#
# Coursework 4 begins here
#
def Mean(theData):
    realData = theData.astype(float)
    noVariables=theData.shape[1]
    mean = []
    # Coursework 4 task 1 begins here
    for i in xrange(noVariables):

        mean.append(sum(realData[:,i])/realData.shape[0])

    # Coursework 4 task 1 ends here
    return array(mean)

def Covariance(theData):
    realData = theData.astype(float)
    noVariables=theData.shape[1]
    covar = zeros((noVariables, noVariables), float)
    # Coursework 4 task 2 begins here
    #calculate mean
    mean  = Mean(theData)

    #iterate to find variance and covariance of variables
    for i in xrange(noVariables):
        for j in xrange(noVariables):
            covar[i,j] = sum((realData[:,i]-mean[i])*(realData[:,j]-mean[j]))/theData.shape[0]

    # Coursework 4 task 2 ends here
    return covar
def CreateEigenfaceFiles(theBasis):

    # Coursework 4 task 3 begins here

    #read mean face image
    meanIm = ReadOneImage("MeanImage.jpg")

    #eigenface = eigenvector*mean image
    # repeat for all eigenvectors
    for i in xrange(theBasis.shape[0]):
        basisImage = theBasis[i] * meanIm
        filename = "PrincipalComponent" + str(i+1) + ".jpg"
        SaveEigenface(basisImage,filename)
    # Coursework 4 task 3 ends here

def ProjectFace(theBasis, theMean, theFaceImage):
    magnitudes = []
    # Coursework 4 task 4 begins here
    # p = (x-miu)*basis_vectors
    #project by taking dot product
    for i in xrange(theBasis.shape[0]):
        magnitudes.append(dot((array(theFaceImage) - array(theMean)),theBasis[i]))
    # Coursework 4 task 4 ends here
    return array(magnitudes)

def CreatePartialReconstructions(aBasis, aMean, componentMags):

    # Coursework 4 task 5 begins here
    #just mean image
    filename = "MeanComponent.jpg"
    SaveEigenface(aMean,filename)
    for i in xrange(aBasis.shape[0]):
    #start with mean image
        reconstr = aMean
        #and add projections of consecutive basis images
        for j in xrange(0,i+1):
            reconstr = reconstr + componentMags[j]*aBasis[j]

        #save image
        filename = "Reconstruction" + str(i+1) + ".jpg"
        SaveEigenface(reconstr,filename)
    # Coursework 4 task 5 ends here

def PrincipalComponents(theData):
    orthoPhi = []
    # Coursework 4 task 3 begins here
    # The first part is almost identical to the above Covariance function, but because the
    # data has so many variables you need to use the Kohonen Lowe method described in lecture 15
    # The output should be a list of the principal components normalised and sorted in descending
    # order of their eignevalues magnitudes

    # Coursework 4 task 6 ends here
    return array(orthoPhi)

#
# main program part for Coursework 4
#
noVariables, noRoots, noStates, noDataPoints, datain = ReadFile("HepatitisC.txt")
theData = array(datain)
AppendString("results4.txt","Coursework One Results by Lukasz Koprowski (lk1510)& Agata Mosinska (am9310)")
AppendString("results4.txt","Mean Vector")
meanV = Mean(theData)
AppendString("results4.txt",meanV)
AppendString("results4.txt","Covariance Matrix")
covM = Covariance(theData)
AppendString("results4.txt",covM)
AppendString("results4.txt","Component Magnitudes")
theFaceImage = ReadOneImage("c.pgm")
meanFace = ReadOneImage("MeanImage.jpg")
theBasis = ReadEigenfaceBasis()
CreateEigenfaceFiles(theBasis)
compMag = ProjectFace(theBasis, meanFace, theFaceImage)
AppendString("results4.txt",compMag)
CreatePartialReconstructions(theBasis, array(meanFace), compMag)


#!/usr/bin/env python3.4
__author__ = 'mdc_hk'
version = '1.0'
#===========================================================================================================
import datetime, logging, multiprocessing, os, re, subprocess, sys, time
import pandas as pd
from pandas import Series
from bs4 import BeautifulSoup
#===========================================================================================================
# Functions:

# 1: Checks if in proper number of arguments are passed gives instructions on proper use.
def argsCheck(numArgs):
	if len(sys.argv) < numArgs or len(sys.argv) > numArgs:
		print('To learn about contamination rate from system control')
		print('Usage:', sys.argv[0], '<FolderInput>',' <DateOfRunInYYMMDD>')
		print('Examples:', sys.argv[0], 'FolderMS2_001', '151225')
		exit(1) # Aborts program. (exit(1) indicates that an error occurred)
#===========================================================================================================
# Housekeeping.
argsCheck(3) # Checks if the number of arguments are correct.

# Stores file one for input checking.
inFolder  = sys.argv[1]
dateOfRun = sys.argv[2]

# Setting up working and fluSeq directories...
workingFolder_tmp = '~/FluSeq/' + inFolder
os.chdir(os.path.expanduser(workingFolder_tmp))
workingFolder = os.getcwd()
fluSeqFolder = os.path.expanduser('~/FluSeq/')

# Logging events...
logging.basicConfig(filename=workingFolder + '/Log.txt', level=logging.INFO,
                    format='%(asctime)s - %(levelname)s - %(message)s')
startTime = time.time()
logging.info('Command-line invocation: ' + sys.argv[0] + ' ' + sys.argv[1])
logging.info('Runfolder path: ' + workingFolder)

# determining number of logical CPUs availalbe in your PC...
numberOfProcessors = multiprocessing.cpu_count()
print('>> '+ datetime.datetime.now().strftime('%Y/%m/%d %H:%M:%S'), '- The program will be optimized to use '
      + str(numberOfProcessors) + ' logical CPUs available in your PC.')
logging.info('Detected logical CPUs: ' + str(numberOfProcessors))

# Filing number of unique samples found in the working folder...
workingFilesR1 = [f for f in os.listdir(workingFolder) if re.match(r'[\S]+S\d+_L001_R1_001\.fastq\.gz', f)]
fastqFileNameR1 = re.compile(r'(([\S]+)_S\d+_L001_R)1_001\.fastq\.gz')
fastqFilesR1 = []
for file in workingFilesR1:
    fastqFilesR1.append(fastqFileNameR1.findall(file))

# Starting the analyses...
for file in fastqFilesR1:
    # bwa aln...
    print('>> '+ datetime.datetime.now().strftime('%Y/%m/%d %H:%M:%S'), '- Performing bwa aln for paired-end reads '
                                                    'of sample ' + file[0][1])
    proc1 = subprocess.Popen(['bwa', 'aln', '-t', str(numberOfProcessors), '-q', '15', '-f',
                                  workingFolder + '/' + file[0][0] + '1_001.sai',
                                  fluSeqFolder + 'GENOMERepository/H3N2Genome_annotated.fa',
                                  workingFolder + '/' + file[0][0]+'1_001.fastq.gz'],
                                 stdin=subprocess.PIPE, stdout=subprocess.PIPE)
    out, err = proc1.communicate()
    logging.info('bwa aln -t ' + str(numberOfProcessors) + ' -q 15 -f ' + workingFolder + '/'
                    + file[0][0] + '1_001.sai ' + fluSeqFolder + 'GENOMERepository/H3N2Genome_annotated.fa '
                    + workingFolder + '/' + file[0][0]+'1_001.fastq.gz')

    proc2 = subprocess.Popen(['bwa', 'aln', '-t', str(numberOfProcessors), '-q', '15',
                              '-f', workingFolder + '/' + file[0][0] + '2_001.sai',
                              fluSeqFolder + 'GENOMERepository/H3N2Genome_annotated.fa',
                              workingFolder + '/' + file[0][0]+'2_001.fastq.gz'],
                             stdin=subprocess.PIPE, stdout=subprocess.PIPE)
    out, err = proc2.communicate()
    logging.info('bwa aln -t ' + str(numberOfProcessors) + ' -q 15 -f ' + workingFolder + '/'
                     + file[0][0] + '2_001.sai ' + fluSeqFolder + 'GENOMERepository/H3N2Genome_annotated.fa '
                     + workingFolder + '/' + file[0][0]+'2_001.fastq.gz')

#     bwa sampe...
    print('>> '+ datetime.datetime.now().strftime('%Y/%m/%d %H:%M:%S'), '- Performing bwa sampe for sample ' +
              file[0][1])
    proc3 = subprocess.Popen(['bwa', 'sampe', '-r' + '@RG\tID:'+file[0][1]+'\tPL:ILLUMINA\tSM:'+file[0][1],
                               '-f', workingFolder + '/' + file[0][1] + '.uncompressed.bam',
                               fluSeqFolder + 'GENOMERepository/H3N2Genome_annotated.fa',
                               workingFolder + '/' + file[0][0] + '1_001.sai',
                               workingFolder + '/' + file[0][0] + '2_001.sai',
                               workingFolder + '/' + file[0][0] + '1_001.fastq.gz',
                               workingFolder + '/' + file[0][0] + '2_001.fastq.gz'],
                              stdin=subprocess.PIPE, stdout=subprocess.PIPE)
    out, err = proc3.communicate()
    logging.info('bwa sampe -r @RG\tID:'+file[0][1]+'\tPL:ILLUMINA\tSM:'+file[0][1] +
                     ' -f '+ workingFolder + '/' + file[0][1] + '.uncompressed.bam ' +
                     fluSeqFolder + 'GENOMERepository/H3N2Genome_annotated.fa ' +
                     workingFolder + '/' + file[0][0] + '1_001.sai ' +
                     workingFolder + '/' + file[0][0] + '2_001.sai ' +
                     workingFolder + '/' + file[0][0] + '1_001.fastq.gz ' +
                     workingFolder + '/' + file[0][0] + '2_001.fastq.gz')

    # Performing bam sorting using samtools...
    print('>> '+ datetime.datetime.now().strftime('%Y/%m/%d %H:%M:%S'), '- Performing bam sorting for sample '
              + file[0][1] + ' using samtools sort module')
    proc4 = subprocess.Popen(['samtools', 'sort', workingFolder + '/' + file[0][1] +
                               '.uncompressed.bam', workingFolder + '/' + file[0][1]],
                                stdin=subprocess.PIPE, stdout=subprocess.PIPE)
    out, err = proc4.communicate()
    logging.info('samtools sort ' + workingFolder + '/' + file[0][1] +
                     '.uncompressed.bam ' + workingFolder + '/' + file[0][1])

    # Performing bam indexing using samtools...
    print('>> '+ datetime.datetime.now().strftime('%Y/%m/%d %H:%M:%S'), '- Performing samtools indexing for sample '
              + file[0][1] + ' using samtools index module')
    proc5 = subprocess.Popen(['samtools', 'index', workingFolder + '/' + file[0][1]+'.bam'],
                              stdin=subprocess.PIPE, stdout=subprocess.PIPE)
    out, err = proc5.communicate()
    logging.info('samtools index ' + workingFolder + '/' + file[0][1]+'.bam')

    print('>> '+ datetime.datetime.now().strftime('%Y/%m/%d %H:%M:%S'), '- Analysing Depth of Coverage for each '
            'gene segments of sample ' + file[0][1] + ' using GATK DepthOfCoverage')
    proc6 = subprocess.Popen(['java', '-Xmx4g', '-jar', '/home/hklee/Software/GenomeAnalysisTK.jar', '-T',
                              'DepthOfCoverage', '-R', fluSeqFolder + 'GENOMERepository/H3N2Genome_annotated.fa',
                              '-o', workingFolder + '/' + 'MS2SysCtrl_base',
                              '-I', workingFolder + '/' + file[0][1]+'.bam', '-omitIntervals',
                              '-omitSampleSummary'],
                              stdin=subprocess.PIPE, stdout=subprocess.PIPE)
    out, err = proc6.communicate()
    logging.info('java -Xmx4g -jar /home/hklee/Software/GenomeAnalysisTK.jar -T DepthOfCoverage -R'
                 + fluSeqFolder + 'GENOMERepository/H3N2Genome_annotated.fa -o ' + workingFolder + '/'
                 + 'MS2SysCtrl_base -I ' + workingFolder + '/' + file[0][1]
                 + '.bam -omitIntervals -omitSampleSummary')

    # Housekeeping...
    os.unlink(workingFolder + '/' + file[0][0] + '1_001.sai')
    os.unlink(workingFolder + '/' + file[0][0] + '2_001.sai')
    os.unlink(workingFolder + '/' + file[0][1] + '.uncompressed.bam')
    os.unlink(workingFolder + '/' + file[0][1]+'.bam')
    os.unlink(workingFolder + '/' + file[0][1]+'.bam.bai')

dataFromTable = pd.read_table(workingFolder + '/MS2SysCtrl_base', sep='\t')
columns_tojoin = dataFromTable[('Locus')].str.split(":").apply(Series, 1)
columns_tojoin.columns = ['CHROM', 'POS']
dataFromTable = pd.merge(dataFromTable, columns_tojoin, left_index=True, right_index=True)
dataFromTable = dataFromTable.set_index(['CHROM'], drop=False)

try:
    bsObj = BeautifulSoup(open(workingFolder + '/ResequencingRunStatistics.xml'), 'lxml-xml')

except IOError:
    errorFile = open('Error.txt', 'a')
    errorFile.write('Please make sure the run-specific ResequencingRunStatistics.xml is placed in the run folder'
                    + '\n')
    errorFile.close()
    exit(1)

xmlOfSamples = bsObj.findAll('SummarizedSampleStatistics')
if not xmlOfSamples:
    xmlOfSamples = bsObj.findAll('SummarizedSampleStatisics')

listOfSamples = []
for name in xmlOfSamples:
    listOfSamples.append(name.SampleName.get_text())
listOfPFReads = []
for name in xmlOfSamples:
    listOfPFReads.append(round(int(name.NumberOfClustersPF.get_text())/1000000, 2))
if len(listOfSamples) == len(listOfPFReads):
    dictOfSamplesAndPFreads = dict(zip(listOfSamples, listOfPFReads))

geneList = []

def geneAnalysis(Chrom, Gene):
    GeneData = dataFromTable.ix[Chrom]
    GeneData.is_copy = False
    GeneData['PFreads_inMillion'] = dictOfSamplesAndPFreads['MS2SysCtrl']
    GeneData['DateOfRun'] = dateOfRun
    GeneData['GeneSegment'] = Gene
    GeneData = GeneData.set_index(['POS'], drop=False)
    geneSeq = list(dictOfGeneSegment[Chrom])
    for k in range(0, len(geneSeq), 150):
        GeneData_a = GeneData.ix[[k],['DateOfRun', 'CHROM', 'GeneSegment', 'POS', 'Total_Depth', 'PFreads_inMillion']]
        geneList.append(GeneData_a)
    return

with open(fluSeqFolder + 'GENOMERepository/H3N2Genome_annotated.fa' ,'r') as refFile:
    content1 = refFile.read().splitlines()

geneName = []
for i in range(len(content1)):
    if content1.index(content1[i]) % 2 == 0 or content1.index(content1[i]) == 0:
        geneName.append(content1[i][1:])

geneCont = []
for i in range(len(content1)):
    if content1.index(content1[i]) % 2 != 0:
        geneCont.append(content1[i])

if len(geneName) == len(geneCont):
    dictOfGeneSegment = dict(zip(geneName, geneCont))

with open(fluSeqFolder + 'GENOMERepository/H3N2Genome_annotated.fa','r') as refFile:
    sequences = refFile.read()

segmentRegex = re.compile(r'((Segment\d)_[\S]*)')
segment = segmentRegex.findall(sequences)

for seg in segment:
    try:
        geneAnalysis(seg[0], seg[1])
    except:
        errorFile = open('Error.txt', 'a')
        errorFile.write(seg[1] + ' of MS2 System Control was not analysed. Suggested solution: Something is wrong '
                                 'with the formatting of the AllGenes.xls file' + '\n')
        errorFile.close()

try:
    print('>> '+ datetime.datetime.now().strftime('%Y/%m/%d %H:%M:%S'), '- Updating existing ms2SysCtrl.db')
    dataBase = pd.read_csv(fluSeqFolder + 'ms2SysCtrl.db', sep=',')
    dataBase_tmp = pd.concat(geneList, axis=0)
    with open(fluSeqFolder + 'ms2SysCtrl.db', 'a') as f:
        dataBase_tmp.to_csv(f, header=False)

except OSError:
    print('Warning: The MS2 contamination database file is not found in the designated directory. '
          'A new database will be created. Please note that it is important to have sufficient data in the database '
          'to provide a confident contamination statistics for data analyses')
    errorFile = open('Error.txt', 'a')
    errorFile.write('Warning: The MS2 contamination database file is not found in the designated directory. A new '
                    'database will be created. Please note that it is important to have sufficient data in the '
                    'database to provide a confident contamination statistics for data analyses.\n')
    errorFile.close()
    pd.concat(geneList, axis=0).to_csv(fluSeqFolder + 'ms2SysCtrl.db')

# Housekeeping...
try:
    os.unlink(workingFolder + '/MS2SysCtrl_base.sample_cumulative_coverage_counts')
except OSError:
    print(workingFolder + '/MS2SysCtrl_base.sample_cumulative_coverage_counts is not found')
try:
    os.unlink(workingFolder + '/MS2SysCtrl_base.sample_cumulative_coverage_proportions')
except OSError:
    print(workingFolder + '/MS2SysCtrl_base.sample_cumulative_coverage_proportions is not found')

print('>> '+ datetime.datetime.now().strftime('%Y/%m/%d %H:%M:%S'), '- MS2 System contamination learning done ')


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import os
import sys
import subprocess
import time

'''

CPU内存统计工具
v1.0

'''

DEFAULT_APP = "com.xxxxxxx"

CMD_CPU_TPL = "adb shell top -s cpu|grep --line-buffered -E '%s'"
CMD_MEM_TPL = "adb shell dumpsys meminfo %s | grep --line-buffer 'TOTAL' | awk -F ' ' '{print $2}'"
STAT_TPL = "%s【CPU】实时:%s%% 均值:%s%% 峰值:%s%% 【内存】实时:%sM 均值:%sM 峰值:%sM 历时:%s 次数:%d"

def main():
    parse_args()
    start_stat()
    return

def parse_args():
    global target_app
    if len(sys.argv) > 1:
        target_app = sys.argv[1]
    else:
        target_app = DEFAULT_APP
    return

def start_stat():
    print_stat_info()
    total_cpu = 0
    total_mem = 0
    max_cpu = 0
    max_mem = 0

    stat_count = 0
    start_time = time.time()

    print("统计：" + target_app + "\n")

    # 组装命令
    cmd_cpu = CMD_CPU_TPL % target_app
    cmd_mem = CMD_MEM_TPL % target_app
    #print("---" + cmd_cpu)
    #print("---" + cmd_mem)
    cpu_fd = os.popen(cmd_cpu, 'r')
    while True:
        # CPU
        cpu_line = cpu_fd.readline()
        # print("---" + cpu_line)
        # print(cpu_line.split(" "))
        if len(cpu_line) == 0:
            # print("进程未启动")
            continue

        sp = cpu_line.split(" ");
        for i in range(len(sp)):
            if (sp[i].endswith("%")):
                cpu = float(sp[i][0:-1])
                # print(cpu)
                if cpu > max_cpu:
                    max_cpu = cpu
                    pass
                total_cpu += cpu

        # cpu_fd.close()

        # 内存
        mem_fd = os.popen(cmd_mem, 'r')
        mem_line = mem_fd.readline()
        # print(cmd_mem)
        # print(mem_line)
        mem = 0
        if mem_line.endswith("\n"):
            mem_line = mem_line[0:-1]
            if mem_line.isdigit():
                mem = float(mem_line) / 1024
                # print(mem)
                if mem > max_mem:
                    max_mem = mem
                    pass
                total_mem += mem

        mem_fd.close()

        stat_count += 1

        # 统计
        # 21:11:12【CPU】实时:9.3% 均值:9.3% 峰值:9.3% 【内存】实时:149.2M 均值:149.2M 峰值:149.2M 历时:0时0分0秒
        avg_cpu = total_cpu / stat_count
        avg_mem = total_mem / stat_count

        spend_time = get_spend_time(start_time)

        print(STAT_TPL % (cur_time(), str(round(cpu, 2)), str(round(avg_cpu, 2)), str(round(max_cpu, 2))
                          , str(round(mem, 2)), str(round(avg_mem, 2)), str(round(max_mem, 2)), spend_time, stat_count))
        time.sleep(3)
    return

def cur_time():
    return time.strftime('%H:%M:%S',time.localtime(time.time()))

def get_spend_time(start_time:float):
    total_time = time.time() - start_time
    m, s = divmod(total_time, 60)
    h, m = divmod(m, 60)
    return "%02d:%02d:%02d" % (h, m, s)

def print_stat_info():
    print("")
    print("====================================")
    print("")
    print("Android性能测试统计工具 v1.0")
    print("")
    print("本工具基于top命令统计CPU的实时、均值和峰值")
    print("CPU计算方法，CPU均值=周期内每次CPU占用之和/总次数")
    print("内存统计基于dumpsys meminfo中TOTAL SWAP PSS的值")
    print("内存计算方法，内存均值=周期内每次内存占用之和/总次数")
    print("")
    print("停止统计按下ctrl+c（MAC下）")
    print("====================================")
    return

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


# encoding: utf-8

import contextlib

from .common import test

from vendor import (
    create_compute_instance,
    create_block_storage_instance,
    create_compute_ssh_client,

    attach_block_storage_to_compute,
    remove_block_storage_from_compute,
)

@test
def test_block_storage(resource_group_name):
    with create_block_storage_instance(resource_group_name) as block, \
            create_compute_instance(resource_group_name) as compute1, \
            create_compute_instance(resource_group_name) as compute2:

        phrase = b"Nobody inspects the spammish repetition"

        ssh = create_compute_ssh_client(compute1)
        path = attach_block_storage_to_compute(compute1, block)
        sftp = ssh.open_sftp()

        fo = sftp.file(path, 'wb')
        fo.seek(1337)
        fo.write(phrase)
        fo.flush()
        fo.close()
        remove_block_storage_from_compute(compute1, block)

        ssh = create_compute_ssh_client(compute2)
        path = attach_block_storage_to_compute(compute2, block)
        sftp = ssh.open_sftp()
        fo = sftp.file(path, 'rb')
        fo.seek(1337)
        read_back = fo.read(len(phrase))
        remove_block_storage_from_compute(compute2, block)

        assert read_back == phrase, \
            "Data node 1 wrote to block storage didn't read on node 2."


import os
import torch

from dataloader.data_loader import train_dataloader,test_dataloader
from utils import Adder, Timer, check_lr
from torch.utils.tensorboard import SummaryWriter
from valid import _valid
import torch.nn.functional as F

import torch
import torch.nn as nn
import torch.nn.functional as F
import numpy as np
class Unet(nn.Module):
    def __init__(self, in_channels=4, out_channels=4):
        super(Unet, self).__init__()

        # device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')
        self.conv1_1 = nn.Conv2d(in_channels, 32, kernel_size=3, stride=1, padding=1)
        self.conv1_2 = nn.Conv2d(32, 32, kernel_size=3, stride=1, padding=1)
        self.pool1 = nn.MaxPool2d(kernel_size=2)

        self.conv2_1 = nn.Conv2d(32, 64, kernel_size=3, stride=1, padding=1)
        self.conv2_2 = nn.Conv2d(64, 64, kernel_size=3, stride=1, padding=1)
        self.pool2 = nn.MaxPool2d(kernel_size=2)

        self.conv3_1 = nn.Conv2d(64, 128, kernel_size=3, stride=1, padding=1)
        self.conv3_2 = nn.Conv2d(128, 128, kernel_size=3, stride=1, padding=1)
        self.pool3 = nn.MaxPool2d(kernel_size=2)

        self.conv4_1 = nn.Conv2d(128, 256, kernel_size=3, stride=1, padding=1)
        self.conv4_2 = nn.Conv2d(256, 256, kernel_size=3, stride=1, padding=1)
        self.pool4 = nn.MaxPool2d(kernel_size=2)

        self.conv5_1 = nn.Conv2d(256, 512, kernel_size=3, stride=1, padding=1)
        self.conv5_2 = nn.Conv2d(512, 512, kernel_size=3, stride=1, padding=1)

        self.upv6 = nn.ConvTranspose2d(512, 256, 2, stride=2)
        self.conv6_1 = nn.Conv2d(512, 256, kernel_size=3, stride=1, padding=1)
        self.conv6_2 = nn.Conv2d(256, 256, kernel_size=3, stride=1, padding=1)

        self.upv7 = nn.ConvTranspose2d(256, 128, 2, stride=2)
        self.conv7_1 = nn.Conv2d(256, 128, kernel_size=3, stride=1, padding=1)
        self.conv7_2 = nn.Conv2d(128, 128, kernel_size=3, stride=1, padding=1)

        self.upv8 = nn.ConvTranspose2d(128, 64, 2, stride=2)
        self.conv8_1 = nn.Conv2d(128, 64, kernel_size=3, stride=1, padding=1)
        self.conv8_2 = nn.Conv2d(64, 64, kernel_size=3, stride=1, padding=1)

        self.upv9 = nn.ConvTranspose2d(64, 32, 2, stride=2)
        self.conv9_1 = nn.Conv2d(64, 32, kernel_size=3, stride=1, padding=1)
        self.conv9_2 = nn.Conv2d(32, 32, kernel_size=3, stride=1, padding=1)

        self.conv10_1 = nn.Conv2d(32, out_channels, kernel_size=1, stride=1)

    def forward(self, x):
        n, c, h, w = x.shape
        h_pad = 32 - h % 32 if not h % 32 == 0 else 0
        w_pad = 32 - w % 32 if not w % 32 == 0 else 0
        padded_image = F.pad(x, (0, w_pad, 0, h_pad), 'replicate')

        conv1 = self.leaky_relu(self.conv1_1(padded_image))
        conv1 = self.leaky_relu(self.conv1_2(conv1))
        pool1 = self.pool1(conv1)

        conv2 = self.leaky_relu(self.conv2_1(pool1))
        conv2 = self.leaky_relu(self.conv2_2(conv2))
        pool2 = self.pool1(conv2)

        conv3 = self.leaky_relu(self.conv3_1(pool2))
        conv3 = self.leaky_relu(self.conv3_2(conv3))
        pool3 = self.pool1(conv3)

        conv4 = self.leaky_relu(self.conv4_1(pool3))
        conv4 = self.leaky_relu(self.conv4_2(conv4))
        pool4 = self.pool1(conv4)

        conv5 = self.leaky_relu(self.conv5_1(pool4))
        conv5 = self.leaky_relu(self.conv5_2(conv5))

        up6 = self.upv6(conv5)
        up6 = torch.cat([up6, conv4], 1)
        conv6 = self.leaky_relu(self.conv6_1(up6))
        conv6 = self.leaky_relu(self.conv6_2(conv6))

        up7 = self.upv7(conv6)
        up7 = torch.cat([up7, conv3], 1)
        conv7 = self.leaky_relu(self.conv7_1(up7))
        conv7 = self.leaky_relu(self.conv7_2(conv7))

        up8 = self.upv8(conv7)
        up8 = torch.cat([up8, conv2], 1)
        conv8 = self.leaky_relu(self.conv8_1(up8))
        conv8 = self.leaky_relu(self.conv8_2(conv8))

        up9 = self.upv9(conv8)
        up9 = torch.cat([up9, conv1], 1)
        conv9 = self.leaky_relu(self.conv9_1(up9))
        conv9 = self.leaky_relu(self.conv9_2(conv9))

        conv10 = self.conv10_1(conv9)
        out = conv10[:, :, :h, :w]

        return out

    def leaky_relu(self, x):
        out = torch.max(0.2 * x, x)
        return out

def _train(model, args):
    device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
    mse_criterion = torch.nn.MSELoss(reduce=True, size_average=True, reduction='none')
    l1_criterion = torch.nn.L1Loss(reduction='none')
    optimizer = torch.optim.Adam(model.parameters(),
                                 lr=args.learning_rate,
                                 weight_decay=args.weight_decay,
                                 betas=(0.9, 0.999))
    dataloader = train_dataloader(args.data_dir, args.batch_size, 0)
    max_iter = len(dataloader)
    scheduler = torch.optim.lr_scheduler.MultiStepLR(optimizer, args.lr_steps, args.gamma)
    epoch = 1
    writer = SummaryWriter()
    epoch_pixel_adder = Adder()
    epoch_fft_adder = Adder()
    iter_pixel_adder = Adder()
    iter_fft_adder = Adder()
    epoch_timer = Timer('m')
    iter_timer = Timer('m')
    best_psnr = -1
    best_ssim = -1
    for epoch_idx in range(epoch, args.num_epoch + 1):

        epoch_timer.tic()
        iter_timer.tic()
        for iter_idx, batch_data in enumerate(dataloader):
            input_img, label_img = batch_data
            input_img = input_img.to(device)
            label_img = label_img.to(device)

            input_img = input_img.squeeze(dim = 1)
            label_img = label_img.squeeze(dim = 1)

            optimizer.zero_grad()
            pred_img = model(input_img)

            loss_content = mse_criterion(pred_img, label_img)
            label_fft = torch.fft.fft2(label_img, dim=(-2, -1))
            pred_fft = torch.fft.fft2(pred_img, dim=(-2, -1))
            loss_fft = l1_criterion(pred_fft, label_fft)

            loss = 0.8 * loss_content + 0.2 * loss_fft
            loss.backward()
            optimizer.step()

            iter_pixel_adder(loss_content.item())
            iter_fft_adder(loss_fft.item())

            epoch_pixel_adder(loss_content.item())
            epoch_fft_adder(loss_fft.item())

            if (iter_idx + 1) % args.print_freq == 0:
                lr = check_lr(optimizer)
                print("Time: %7.4f Epoch: %03d Iter: %4d/%4d LR: %.10f Loss content: %7.4f Loss fft: %7.4f" % (
                    iter_timer.toc(), epoch_idx, iter_idx + 1, max_iter, lr, iter_pixel_adder.average(),
                    iter_fft_adder.average()))
                writer.add_scalar('Pixel Loss', iter_pixel_adder.average(), iter_idx + (epoch_idx-1)* max_iter)
                writer.add_scalar('FFT Loss', iter_fft_adder.average(), iter_idx + (epoch_idx - 1) * max_iter)
                iter_timer.tic()
                iter_pixel_adder.reset()
                iter_fft_adder.reset()

        if epoch_idx > 100 and  epoch_idx % args.save_freq == 0:
            save_name = os.path.join(args.model_save_dir, 'model_%d.pth' % epoch_idx)
            torch.save({'model': model.state_dict()}, save_name)
            #if need resume, use this method to save model
            # torch.save({'model': model.state_dict(),
            #             'optimizer': optimizer.state_dict(),
            #             'scheduler': scheduler.state_dict(),
            #             'epoch': epoch_idx}, save_name)
        print("EPOCH: %02d\nElapsed time: %4.2f Epoch Pixel Loss: %7.4f Epoch FFT Loss: %7.4f" % (
            epoch_idx, epoch_timer.toc(), epoch_pixel_adder.average(), epoch_fft_adder.average()))
        epoch_fft_adder.reset()
        epoch_pixel_adder.reset()
        scheduler.step()
        if epoch_idx % 1 == 0:
            psnr,ssim = _valid(model, args, epoch_idx)
            print('%03d epoch \n Average GOPRO PSNR %.2f dB SSIM %.2f' % (epoch_idx, psnr,ssim))
            writer.add_scalar('PSNR_GOPRO', psnr, epoch_idx)
            writer.add_scalar('SSIM_GOPRO', ssim, epoch_idx)
            if psnr >= best_psnr and ssim >= best_ssim:
                best_psnr = psnr
                best_ssim = ssim
                torch.save({'model': model.state_dict()}, os.path.join(args.model_save_dir, 'best_model.pth'))
    save_name = os.path.join(args.model_save_dir, 'final.pth')
    torch.save({'model': model.state_dict()}, save_name)

model = Unet()

def train(DataLoader, model, criterion, optimizer):
    model.cuda()
    # 指定为train模式
    model.train()

    for i, (img, target) in enumerate(DataLoader):
        img = img.cuda()
        target = target.cuda()
        # 计算网络输出
        output = model(img)

        # 计算损失
        loss = criterion(output, target)

    # 计算梯度和做反向传播
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()


from flask import Flask
from flask_restful import Api
from flask_mongoengine import MongoEngine
from resources.diff_resource import *
from logging.config import fileConfig

app = Flask(__name__)

if app.config['ENV'] == 'production':
    app.config['MONGODB_SETTINGS'] = {
        'db': 'diff_db',
        'host': 'mongodb',
        'port': 27017,
    }
else:
    #configuration for tests and development purposes
    app.config['MONGODB_SETTINGS'] = {
        'db': 'diff_db',
        'host': 'localhost',
        'port': 27017,
    }

api = Api(app)
db = MongoEngine(app)

#registering all endpoints
api.add_resource(Diff, '/v1/diff/<id>')
api.add_resource(AddRight, '/v1/diff/<id>/right')
api.add_resource(AddLeft, '/v1/diff/<id>/left')
app.logger.info('Application Started')

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


#!/usr/bin/env python

import os
import sys

from pylab import *
import PIL.Image as Image
# from scipy.misc import imsave

from bjg.obj import OBJ

o = OBJ()

objFilename = '/Users/graham/Desktop/mesh_fill/cropped.obj'  # 'scans/K3/Scan05/skull.obj'
textureFilename = '/Users/graham/Desktop/mesh_fill/cropped.png'  # 'scans/K3/Scan05/skull.png'

if len(sys.argv) == 3:
    objFilename = sys.argv[1]
    textureFilename = sys.argv[2]

o.load(objFilename, textureFilename)

# im = imread(o.textureFilename)
im = Image.open(o.textureFilename)

# h, w, d = im.shape
w, h = im.size

uvs = o.texCoords

xys = transpose(vstack((uvs[:, 0] * w, h - uvs[:, 1] * h)))

# figure out x,y bounds (look for edges of pixels)
# give myself a N=2 pixel border
# crop the texture
# xm, ym = (xys.min(0) - 2) #.astype(int)
# xM, yM = (xys.max(0) + 2) #.astype(int)
# cim = im.crop((int(round(xm)),int(round(ym)),int(round(xM)),int(round(yM))))

xm, ym = (xys.min(0) - 2).astype(int)
xM, yM = (xys.max(0) + 2).astype(int)
cim = im.crop((xm, ym, xM, yM))

# scale the uvs
# ch, cw, cd = cim.shape
cw, ch = cim.size
# um, vm = float(xm) / w, float(ym) / h
# uM, vM = float(xM) / w, float(yM) / h
# nuvs = transpose(vstack(((uvs[:,0]-um)/(uM-um),(uvs[:,1]-vm)/(vM-vm))))
nuvs = transpose(vstack(((xys[:, 0] - xm) / cw, 1 - (xys[:, 1] - ym) / ch)))

# save changes
newObjFilename = os.path.splitext(
    objFilename)[0] + '_cropped' + os.path.splitext(objFilename)[1]
newTextureFilename = os.path.splitext(
    textureFilename)[0] + '_cropped' + os.path.splitext(textureFilename)[1]

# imsave(newTextureFilename, cim)
cim.save(newTextureFilename)
o.texCoords = nuvs
o.save(newObjFilename)


#!/usr/bin/env python
# coding: utf-8
#uvicorn main:app --reload --ssl-keyfile localhost-key.pem --ssl-certfile localhost.pem

#sqlite3.IntegrityError: UNIQUE constraint failed: donations.donation_address

import configparser
import logging
from fastapi import FastAPI, Request
from fastapi.responses import HTMLResponse
from fastapi.staticfiles import StaticFiles
import pprint
from starlette.responses import FileResponse
import os
from urllib.parse import urlparse, parse_qs
from html import escape
import json
from datetime import datetime
import setup_wallets
from helper_create import bit_online, get_unused_address
import sqlite3
import time
from fastapi.responses import JSONResponse
from starlette.responses import PlainTextResponse, RedirectResponse
from starlette.middleware.cors import CORSMiddleware
from filelock import FileLock
import math
import start_daemons

import uvicorn
import threading

import schedule_fee

from typing import List
from starlette.responses import HTMLResponse
from starlette.websockets import WebSocket, WebSocketDisconnect
import subprocess
import uuid

import rss_feed
# To read your secret credentials
#config = configparser.ConfigParser()
#config.read("config.ini")

#screen -L -Logfile lolokk.txt uvicorn main:app --reload --ssl-keyfile /var/www/letsencrypt/.lego/certificates/rucknium.me.key --ssl-certfile /var/www/letsencrypt/.lego/certificates/rucknium.me.crt
#ssl_certificate ;
#ssl_certificate_key
app = FastAPI()
app.mount("/donate/static", StaticFiles(directory="static"), name="static")

##
##Ticket price
ticket_normal = 49.99 #euros
ticket_vip = 99

app.add_middleware(
CORSMiddleware,
allow_origins=["*"], # Allows all origins
allow_credentials=True,
allow_methods=["*"], # Allows all methods
allow_headers=["*"], # Allows all headers
)

class Notifier:
    def __init__(self):
        self.connections: List[WebSocket] = []
        self.generator = self.get_notification_generator()

    async def get_notification_generator(self):
        while True:
            message = yield
            await self._notify(message)

    async def push(self, msg: str):
        await self.generator.asend(msg)

    async def connect(self, websocket: WebSocket):
        await websocket.accept()
        self.connections.append(websocket)

    def remove(self, websocket: WebSocket):
        self.connections.remove(websocket)

    async def _notify(self, message: str):
        living_connections = []
        while len(self.connections) > 0:
            # Looping like this is necessary in case a disconnection is handled
            # during await websocket.send_text(message)
            websocket = self.connections.pop()
            await websocket.send_text(message)
            living_connections.append(websocket)
        self.connections = living_connections

notifier = Notifier()

@app.websocket("/donate/ws")
async def websocket_endpoint(websocket: WebSocket):
    await notifier.connect(websocket)
    try:
        while True:
            data = await websocket.receive_text()
            await websocket.send_text(f"Message text was: {data}")
    except WebSocketDisconnect:
        notifier.remove(websocket)

@app.get("/push/{message}")
async def push_to_connected_websockets(message: str):
    #uid = uuid.uuid4().hex
    #os.system(f"ws_uid={uid} && export ws_uid")
    con = sqlite3.connect('./db/ws_update.db')
    cur = con.cursor()
    create_modified_table = """ CREATE TABLE IF NOT EXISTS uid (
                                data string PRIMARY KEY default 0
                            ); """
    cur.execute(create_modified_table)
    cur.execute('SELECT * FROM uid')
    try:
        rows = cur.fetchall()
        uid = rows[0][0]
        pass
    except:
        return
    if message == uid:
        await notifier.push("trigger")
        #stop this uid from working
        sql = '''delete from uid'''
        cur.execute(sql)
        sql = '''INSERT INTO uid (data) VALUES(?)'''
        cur.execute(sql, (uid,))
    else:
        await notifier.push("trigger")
        os.system(f'python3 static/static_html_loop.py')
    con.commit()
    con.close()

@app.on_event("startup")
async def startup():
    # Prime the push notification generator
    await notifier.generator.asend(None)

@app.get("/donate/", response_class=HTMLResponse)
async def read_root():
    return FileResponse('./static/index.html')

@app.get("/donate/api/price")
async def return_price(status_code=200):
    return db_get_prices()

def db_get_prices():
    con = sqlite3.connect('./db/crypto_prices.db')
    cur = con.cursor()
    create_price_table = """ CREATE TABLE IF NOT EXISTS crypto_prices (
                                data default 0,
                                xmr integer,
                                btc integer,
                                bch integer,
                                wow integer
                            ); """
    cur.execute(create_price_table)
    cur.execute('SELECT * FROM crypto_prices WHERE data = ?',[0])
    rows = cur.fetchall()
    con.close()
    try:
        return_me = {
        "bitcoin-cash": rows[0][3],
        "monero": rows[0][1],
        "bitcoin": rows[0][2],
        "wownero": rows[0][4]
        }
        return return_me
    except:
        return False

@app.post("/donate/crypto_donate")
async def handle_crypto_form(request: Request):
    global ticket_normal, ticket_vip
    body = await request.body()
    #old ini file! :'(
    wish_config = configparser.ConfigParser()
    wish_config.read("./db/wishlist.ini")
    #b'amount=1&coins=xmr&choice=tax&fname=&fname=&street=&zip=&email=&rfund='
    #pprint.pprint(body)
    client_host = request.client.host
    print(client_host)
    print("hello world")
    try:
        client_address = request.client.host
        print(client_address)
        vals = parse_qs(body)

        for x in vals:
            try:
                escape(vals[x][0].decode("utf-8"))
                pass
            except Exception as e:
                print("fix the problem?")
                vals[x] = [b'']

        comment = null_if_not_exists(vals,b"comment")
        comment_name = null_if_not_exists(vals,b"comment_name")
        if len(comment) > 140 or len(comment_name) > 12:
            return
        #vals[b'uid'][0] = wish id
        #20 clicks per day per ip...
        if not clicks_today(client_address):
            print("Rejected")
            return
        #add into database? a thread to remove in 15 mins? hm
        #pprint.pprint(vals)
        #print(f"the choise is {vals[b'choice'][0]}")
        if vals[b'choice'][0] == b'tax':
            #database entry
            #tax receipt
            #send_email(send_to,address,amount)
            the_email = null_if_not_exists(vals,b"email")
            #if not valid_email(the_email):
            #    return
            #print(f"we chose: {vals[b'coins'][0]}")
            valid_coin = 0
            ticker =  null_if_not_exists(vals,b"coins")
            if ticker == "xmr":
                valid_coin = 1
            if ticker == "bch":
                valid_coin = 1
            if ticker == "btc":
                valid_coin = 1
            if ticker == "wow":
                valid_coin = 1

            if valid_coin == 0:
                return
            if ticker == "bch":
                bchuser = wish_config["bch"]["rpcuser"]
                bchpass = wish_config["bch"]["rpcpassword"]
                bchport = wish_config["bch"]["rpcport"]
                if not bit_online(bchuser,bchpass,bchport):
                    return
            if ticker == "btc":
                btcuser = wish_config["btc"]["rpcuser"]
                btcpass = wish_config["btc"]["rpcpassword"]
                btcport = wish_config["btc"]["rpcport"]
                if not bit_online(btcuser,btcpass,btcport):
                    return
            if ticker == "xmr":
                xmrport = wish_config["monero"]["daemon_port"]
                rpc_url = "http://localhost:" + str(xmrport) + "/json_rpc"
                if not setup_wallets.monero_rpc_online(rpc_url):
                    return
            if ticker == "wow":
                wowport = wish_config["wow"]["daemon_port"]
                rpc_url = "http://localhost:" + str(wowport) + "/json_rpc"
                if not setup_wallets.monero_rpc_online(rpc_url):
                    return

            address = get_unused_address(wish_config,ticker)
            if not address:
                return
            #does there need to be a time contraint on when donations can receive a receipt?
            #or they can only be used once?

            price_ticker = ""
            ticket_valid = 1
            expected = 0
            wish_id = null_if_not_exists(vals,b"uid")
            #enforce ticker symbols

            ticket_amount = null_if_not_exists(vals,b'quantity')

            if ticker == "xmr":
                ticker = "monero"
            elif ticker == "bch":
                ticker = "bitcoin-cash"
            elif ticker == "btc":
                ticker = "bitcoin"
            elif ticker == "wow":
                ticker = "wownero"
            else:
                ticket_valid = 0

            try:
                if ticket_amount == "":
                    ticket_valid = 0
                elif int(ticket_amount) >= 1:
                    ticket_amount = math.ceil(int(ticket_amount))
                else:
                    ticket_valid = 0
            except Exception as e:
                print(e)
                ticket_valid = 0

            if wish_id == "ticket":
                #ticket
                ticket_price = ticket_normal
            elif wish_id == "ticket_vip":
                #vip
                ticket_price = ticket_vip
            else:
                ticket_valid = 0

            if ticket_valid == 1:
                crypto_price = db_get_prices()[ticker]
                print(f"crypto price = {crypto_price}")
                ticket_total = ticket_price * ticket_amount
                print(f"ticket total = {ticket_total}")
                expected = round((ticket_total / crypto_price),12)
            else:
                print("error ticket_valid = 0")

            print(f"the donation address is {address}")
            weird = null_if_not_exists(vals,b"comment")
            print(f"the comment is {weird}")
            db_data = {
            "email": null_if_not_exists(vals,b"email"),
            #the amount selected by the form is meaningless
            #we only care about what gets deposited at the end
            #"amount": null_if_not_exists(vals,b"amount"),
            "amount": 0,
            "fname": null_if_not_exists(vals,b"fname"),
            "donation_address": address,
            "zipcode": null_if_not_exists(vals,b"zip"),
            "address": null_if_not_exists(vals,b"street"),
            "date_time": datetime.now(),
            "refund_address": null_if_not_exists(vals,b"rfund"),
            "crypto_ticker": null_if_not_exists(vals,b"coins"),
            "wish_id": null_if_not_exists(vals,b"uid"),
            "comment": comment,
            "comment_name": comment_name,
            "amount_expected": expected,
            "consent": null_if_not_exists(vals,b"consent"),
            "quantity": ticket_amount,
            "type": wish_id
            }
            db_receipts_add(db_data)
            info = {
            "address": address,
            "amount_expected": expected
            }
            #pprint.pprint(vals)
            #pprint.pprint(db_data)
            test = json.dumps(info)
            return JSONResponse(content=test)

    except Exception as e:
        raise e

def null_if_not_exists(vals,index):
    try:
        if index == b"comment":
            return escape(vals[index][0].decode("utf-8"))
        else:
            return escape(vals[index][0].decode("utf-8"))
        pass
    except Exception as e:
        return ""

def clicks_today(client_ip):
    if client_ip == "127.0.0.1":
        return True
    con = sqlite3.connect('./db/clicks.db')
    cur = con.cursor()
    create_clicks_table = """ CREATE TABLE IF NOT EXISTS clicks (
                                clicks integer default 0 not null,
                                ip text PRIMARY KEY,
                                time_last integer default 0
                            ); """

    cur.execute(create_clicks_table)
    con.commit()
    cur.execute('SELECT * FROM clicks WHERE ip = ?',[client_ip])
    rows = cur.fetchall()
    if len(rows) == 0:
        #we didnt click today
        #insert into db then return true
        sql = ''' INSERT INTO clicks (ip,clicks,time_last)
                  VALUES(?,?,?) '''
        cur.execute(sql, (client_ip,1,time.time()))
        con.commit()
        return True

    if rows[0][0] > 19:
        return False
    if (int(time.time()) - int(rows[0][2])) < 1:
        #1 click per second per ip
        return
    else:
        print(f"time since last click = {(int(time.time()) - int(rows[0][2]))}")
        clicks = rows[0][0]
        clicks +=  1
        print(f"clicks={clicks}")
        sql = ''' UPDATE clicks
                  SET clicks = ?,
                  time_last = ?
                  WHERE ip = ?'''
        cur.execute(sql, (clicks,int(time.time()),client_ip))
        con.commit()
        return True

def logit(s):
    try:
        with open("logged.text", "a+") as f:
            f.write(pprint.pprint(s))
            pass
    except Exception as e:
        raise e

def rss_check(wish_config):
    changed = 0
    if wish_config["RSS"]["enable"] != os.environ['waas_RSS_ON']:
        changed = 1
    if wish_config["RSS"]["title"] != os.environ['waas_RSS_TITLE'].replace('"',''):
        changed = 1
    if wish_config["RSS"]["description"] != os.environ['waas_RSS_DESC'].replace('"',''):
        changed = 1
    if wish_config["RSS"]["link"] != os.environ['waas_RSS_LINK'].replace('"',''):
        changed = 1
    if changed == 1:
        return True

#if we have a list with no wownero addresses
#we must run the wow_much_updates.py script to create wallet/add wishes
def wow_check():
    with open("./static/data/wishlist-data.json", "r") as f:
        wishlist = json.load(f)
    for wish in wishlist["wishlist"]:
        try:
            if wish["wow_address"]:
                pass
        except Exception as e:
            return False
    return True

def db_receipts_add(data):
    con = sqlite3.connect('./db/receipts.db')
    cur = con.cursor()
    sql = ''' INSERT INTO donations (email,amount,fname,donation_address,zipcode,address,date_time,refund_address,crypto_ticker,wish_id,comment,comment_name,amount_expected,consent,quantity,type)
              VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?) '''
    cur.execute(sql, (data["email"],data["amount"],data["fname"],data["donation_address"],data["zipcode"],data["address"],data["date_time"],data["refund_address"],data["crypto_ticker"],data["wish_id"],data["comment"],data["comment_name"],data["amount_expected"],data["consent"],data["quantity"],data["type"]))
    con.commit()

if __name__ == "__main__":
    #use ENV variables from docker compose
    #old ini file! :'(
    wish_config = configparser.ConfigParser()
    wish_config.read("./db/wishlist.ini")
    #create new rss feed if info is changed
    remake_rss = rss_check(wish_config)
    wish_config["RSS"]["enable"] = os.environ['waas_RSS_ON']
    wish_config["RSS"]["title"] = os.environ['waas_RSS_TITLE'].replace('"','')
    wish_config["RSS"]["description"] = os.environ['waas_RSS_DESC'].replace('"','')
    wish_config["RSS"]["link"] = os.environ['waas_RSS_LINK'].replace('"','')
    wish_config["monero"]["remote_node_1"] = os.environ['waas_remote_node_1'].replace('"','')
    wish_config["monero"]["remote_node_2"] = os.environ['waas_remote_node_2'].replace('"','')
    wish_config["monero"]["remote_node_3"] = os.environ['waas_remote_node_3'].replace('"','')
    wish_config["monero"]["remote_node_4"] = os.environ['waas_remote_node_4'].replace('"','')
    wish_config["monero"]["remote_node_5"] = os.environ['waas_remote_node_5'].replace('"','')
    try:
        if wish_config["wow"]["wallet_file"]:
            pass
    except Exception as e:
        wish_config["wow"] = {}
        wish_config["wow"]["wallet_file"] = ""
        wish_config["wow"]["bin"] = "bin/wownero-wallet-rpc"

    wish_config["wow"]["fallback_remote_nodes"] = "5"
    wish_config["wow"]["daemon_port"] = "15112"
    wish_config["wow"]["remote_node_1"] = os.environ['waas_wow_remote_node_1'].replace('"','')
    wish_config["wow"]["remote_node_2"] = os.environ['waas_wow_remote_node_2'].replace('"','')
    wish_config["wow"]["remote_node_3"] = os.environ['waas_wow_remote_node_3'].replace('"','')
    wish_config["wow"]["remote_node_4"] = os.environ['waas_wow_remote_node_4'].replace('"','')
    wish_config["wow"]["remote_node_5"] = os.environ['waas_wow_remote_node_5'].replace('"','')
    wish_config["wishlist"]["intro"] = os.environ['waas_INTRO'].replace('"','')
    wish_config["wishlist"]["title"] = os.environ['waas_TITLE'].replace('"','')
    if remake_rss:
        rss_feed.create_fresh_feed(wish_config)

    #start recurring fee loop
    th = threading.Thread(target=schedule_fee.schedule_main)
    th.start()

    with open('./db/wishlist.ini', 'w') as configfile:
        wish_config.write(configfile)
    #if wishlist file exists - assume we can start_daemons
    if os.path.isfile("./static/data/wishlist-data.json"):
        if wow_check():
            th = threading.Thread(target=start_daemons.main, args=(wish_config,))
            th.start()
        else:
            print("Run wow_such_update.py to setup your WOWnero wallet")
    else:
        print("Run setup_wallets.py")
    #ssl certs should be in ./ssl folder
    uvicorn.run("main:app", port=8000, host="0.0.0.0", reload=True)


#!/usr/bin/env python3

import os
import time
import argparse
import json

# iot/raw/nrf24/47 h=321,t=261,p=10044,v=3290
# iot/data/sensor47/temperature 26.1
# iot/data/sensor47/humidity 32.1
# iot/data/sensor47/pressure 1004.4
# iot/data/sensor47/vcc 3290

# TODO: discovery: https://www.home-assistant.io/docs/mqtt/discovery/

def activate(basedir: str):
    """ Look for and activate a virtualenv within the given base directory """

    print(f'activate({basedir})')

    for dir in [f.path for f in os.scandir(basedir) if f.is_dir()]:
        print(f'Checking directory ({dir})')
        activate = os.path.join(basedir, dir, 'bin', 'activate_this.py')
        if os.path.isfile(activate):
            print('Found virtualenv in {}, activating'.format(dir))
            try:
                exec(open(activate).read(), {'__file__': activate})
            except Exception as exc:
                print('Could not run activate script. Module imports will most likely fail.', exc)

def parse_args() -> argparse.Namespace:
    parser = argparse.ArgumentParser(
        description="Serial monitor to capture NRF24 radio data via Arduino modem and publish to MQTT")

    parser.add_argument('--port',
        required=False,
        default="/dev/ttyUSB0",
        help="Serial (USB) port to listen on")

    parser.add_argument('--baudrate',
        required=False,
        default=9600,
        help='Set baud rate on serial connection')

    parser.add_argument('--mqtt',
        required=True,
        help='Mosquitto server to connect to')

    return parser.parse_args()

def serial_init(args: argparse.Namespace):
    return serial.Serial(port=args.port, timeout=2, baudrate=args.baudrate, bytesize=8, stopbits=serial.STOPBITS_ONE)

# Not using home-assistant status data yet for anything
def on_connect(client, userdata, flags, rc):
    print("MQTT connected")
    client.subscribe("homeassistant/status")

def on_message(client, userdata, msg):
    if msg.payload == b"online":
        print("Home-assistant restart detected")

def debug_print(msg: str):
    print(f"{time.ctime()} | {msg}")

def main(args: argparse.Namespace):
    print("NRF24 serial monitor starting")

    port = serial_init(args)
    print(f"Serial connected via {port}")

    pid = os.getpid()
    client = mqtt.Client(client_id = f"serialmonitor_{pid}")
    client.on_connect = on_connect
    client.on_message = on_message

    print(f"MQTT connecting to {args.mqtt}")
    client.connect(args.mqtt, 1883, 60)
    client.loop_start()

    lastmsg = dict()

    while (1):
        if(port.in_waiting > 0):
            try:
                buffer = port.readline().decode("ASCII").strip()
            except UnicodeDecodeError as exc:
                print(f"Cannot decode data: {exc}")
                print(f"Input was: '{buffer}'")
                continue

            if not buffer.startswith("R "):
                debug_print(buffer)
                continue

            try:
                # limit number of splits to 2 in case of any short values e.g. 'p= 9999'
                (_, datalen, payload) = buffer.split(' ', 2)
            except ValueError as exc:
                print(f"Cannot extract data: {exc}")
                print(f"Data was: {buffer}")
                continue

            if int(datalen) > 32:
                print("Possible data corruption - NRF24 max payload size exceeded")
                continue

            try:
              (address, measurement) = payload.split(':')
              (network,channel,nodeid) = address.split(',')
            except Exception as exc:
              print(f'Error processing input: {exc}')
              print(payload)
              continue

            now = time.time()
            timedelta = now - lastmsg[address] if lastmsg.get(address) else -1
            lastmsg[address] = time.time()

            debug_print(f"{buffer} | {timedelta:.2f}")

            try:
                # Publishing the raw data
                client.publish('iot/raw/nrf24/{}.{}/{}'.format(network, channel, nodeid), measurement)

                data = {item[0]: item[1] for item in [chunk.split('=')
                                        for chunk in measurement.split(',')]}

                client.publish('iot/data/sensor{}/temperature'.format(nodeid), int(data['t'])/10)
                client.publish('iot/data/sensor{}/humidity'.format(nodeid), int(data['h'])/10)
                client.publish('iot/data/sensor{}/pressure'.format(nodeid), int(data['p'])/10)
                client.publish('iot/data/sensor{}/vcc'.format(nodeid), data['v'])
                client.publish('iot/data/sensor{}/timedelta'.format(nodeid), timedelta)

            except Exception as exc:
                print(f"Failed to process message: {exc}")
                print(f"Data line was {payload}")

        time.sleep(0.1)

if __name__ == '__main__':

    BASEDIR = os.path.abspath(os.path.dirname(__file__))
    activate(BASEDIR)

    import serial
    import paho.mqtt.client as mqtt

    args = parse_args()

    try:
        main(args)
    except KeyboardInterrupt:
        print("Ctrl-C pressed, exiting")


from spacy.matcher import PhraseMatcher
from scipy import spatial

import spacy

# method for reading a pdf file
def readPdfFile():
    return open("text.txt").read()

# customer sentence segmenter for creating spacy document object
def setCustomBoundaries(doc):
    # traversing through tokens in document object
    for token in doc[:-1]:
        if token.text == ";":
            doc[token.i + 1].is_sent_start = True
        if token.text == ".":
            doc[token.i + 1].is_sent_start = False
    return doc

# create spacy document object from pdf text
def getSpacyDocument(pdf_text, nlp):
    main_doc = nlp(pdf_text)  # create spacy document object

    return main_doc

# method for searching keyword from the text
def search_for_keyword(keyword, doc_obj, nlp):
    phrase_matcher = PhraseMatcher(nlp.vocab)
    phrase_list = [nlp(keyword)]
    phrase_matcher.add("Text Extractor", None, *phrase_list)

    matched_items = phrase_matcher(doc_obj)

    matched_text = []
    for match_id, start, end in matched_items:
        text = nlp.vocab.strings[match_id]
        span = doc_obj[start:end]
        matched_text.append(span.sent.text)
    return matched_text

# convert keywords to vector
def createKeywordsVectors(keyword, nlp):
    doc = nlp(keyword)  # convert to document object

    return doc.vector

# method to find cosine similarity
def cosineSimilarity(vect1, vect2):
    # return cosine distance
    return 1 - spatial.distance.cosine(vect1, vect2)

# method to find similar words
def getSimilarWords(keyword, nlp):
    similarity_list = []

    keyword_vector = createKeywordsVectors(keyword, nlp)

    for tokens in nlp.vocab:
        if tokens.has_vector:
            if tokens.is_lower:
                if tokens.is_alpha:
                    similarity_list.append(
                        (tokens, cosineSimilarity(keyword_vector, tokens.vector))
                    )

    similarity_list = sorted(similarity_list, key=lambda item: -item[1])
    similarity_list = similarity_list[:30]

    top_similar_words = [item[0].text for item in similarity_list]

    top_similar_words = top_similar_words[:3]
    top_similar_words.append(keyword)

    for token in nlp(keyword):
        top_similar_words.insert(0, token.lemma_)

    for words in top_similar_words:
        if words.endswith("s"):
            top_similar_words.append(words[0 : len(words) - 1])

    top_similar_words = list(set(top_similar_words))

    top_similar_words = [words for words in top_similar_words]

    return ", ".join(top_similar_words)

if __name__ == "__main__":
    # spacy english model (large)
    nlp = spacy.load("en_core_web_lg")
    # nlp.add_pipe(setCustomBoundaries, before="parser")
    keywords = "how"
    main_doc = nlp(readPdfFile())
    # similar_keywords = getSimilarWords(keywords, nlp)
    print(search_for_keyword(keywords, main_doc, nlp))


from tqdm import tqdm
import numpy as np
import torch
from torch import optim, nn

F = nn.functional

to4dec = lambda a: np.around(a, decimals=4) if not a==None else None

listNumpy = lambda l: [x.item() for x in l]

sumLoss = lambda loss_list: np.sum(listNumpy(loss_list)) / len(loss_list)

caculate_metric = lambda metric: lambda predb, yb, : [ metric(predb, yb).item() for predb, yb in zip(predb, yb)]

def print_epoch_progress(epoch, train_loss=None, valid_loss=None, metrics=[]):
    metrics = [f"{key}: {to4dec(value)}" for key, value in metrics.items()]
    print(epoch, 'train loss: ', to4dec(train_loss),'valid loss: ', to4dec(valid_loss,), ' '.join(metrics))

class Learner(object):
    """
        Learner object holds model, optimizer and dataloaders
    """
    def __init__(self, path, model, opt, loss_fn, dls={}, metrics={}):
        self.model = model
        self.opt = opt
        self.loss_fn = loss_fn
        # assumes { trn: train_dl, val: valid_dl)
        self.data = dls
        self.metrics = metrics
        self.models_path = path/'models'
#         self.schedule

    def modelNameToPath(self, m): return str(self.models_path/f"{m}.pth")

    def save(self, model_name):
        torch.save(self.model.state_dict(), self.modelNameToPath(model_name))

    def load(self, model_name=None):
        p = self.modelNameToPath(model_name)
        if not model_name==None: self.model.load_state_dict(torch.load(p))

    def descend_(self, xb, yb, is_valid=False):

        predb = self.model(xb)
        loss = self.loss_fn(predb, yb)

        if is_valid is not True:
            # cloze {
            loss.backward()
            self.opt.step()
            self.opt.zero_grad()
            # } cloze
        return loss, predb

    def fit_(self, epochs=1):
        for epoch in range(epochs):

             # training
            self.model.train()
            trn_losses = []
            for d in tqdm(self.data['trn']):
                xb, yb = d
                loss, predb = self.descend_(xb, yb)
                trn_losses.append(loss)

            # validation
            validation_loss = None
            if self.data['val'] is not None:
                self.model.eval()
                with torch.no_grad():
                    val_losses = []
                    for d in tqdm(self.data['val']):
                        xb, yb = d
                        loss, predb = self.descend_(xb, yb, is_valid=True)
                        val_losses.append(loss)
                validation_loss = sumLoss(val_losses)

            training_loss = sumLoss(trn_losses)

            metrics = {
                name:np.mean(caculate_metric(fn)(predb.detach(),yb.detach())) for name, fn in self.metrics.items()
            }
#             = [ m for predb, yb in zip(predb, yb)]

#             print_epoch_progress(epoch+1, training_loss, validation_loss, {'accuracy': epoch_accuracy})
            print(epoch+1, training_loss, validation_loss, metrics)