#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Created on Mon Jul 01 15:53:41 2013
@author: <Ronny Eichler> ronny.eichler@gmail.com

"""
NO_EXIT_CONFIRMATION = True

# buitlin libs
import sys
import os
import platform
import time
import logging

# 3rd party
#import PyQt4 ## forces use of PyQt4 instead of PySide
from pyqtgraph.Qt import QtGui, QtCore
import numpy as np
import pyqtgraph as pg
import pyqtgraph.ptime as ptime

#Qt user interface files
sys.path.append('./ui')
from mainUi import Ui_MainWindow

# user
sys.path.append('./lib')
from spotter import Spotter

examples = [('media/video/r52r2f107.avi', 200),
            ('media/video/test.avi', 200)]

class Main(QtGui.QMainWindow):
    def __init__(self, *args, **kwargs): #, source, destination, fps, size, gui, serial

        if 'logger' in kwargs:
            self.logger = kwargs['logger']
        if 'app' in kwargs:
            self.app = kwargs['app']

        QtGui.QMainWindow.__init__(self)
#        mw = QtGui.QMainWindow()
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)
        self.resize(800,800)
        self.show()

        self.vb = pg.ViewBox()
        self.ui.graphicsView.setCentralItem(self.vb)
        self.vb.setAspectLocked()
        self.img = pg.ImageItem()
        self.vb.addItem(self.img)
        self.vb.setRange(QtCore.QRectF(0, 0, 512, 512))
#        self.img.setPxMode(True)

        self.logger.info('%s starting spotter', self)
        self.spotter = Spotter(*args, **kwargs)
        self.spotter.gui_grabber.displayTarget = self.img
        self.logger.info('%s spotter instantiated', self)

        self.lastTime = ptime.time()
        self.fps = None

        # main window refresh timer
#        self.timer = QtCore.QTimer()
#        self.timer.timeout.connect(self.update)
#        self.timer.start(0)
        self.update()

    def update(self):
        self.logger.info('%s:Processing Events', self)
        now = ptime.time()
        dt = now - self.lastTime
        self.lastTime = now
        if self.fps is None:
            self.fps = 1.0/dt
        else:
            s = np.clip(dt*3., 0, 1)
            self.fps = self.fps * (1-s) + (1.0/dt) * s
        self.ui.fpsLabel.setText('%0.2f fps' % self.fps)
#        self.app.processEvents()  ## force complete redraw for every plot
        QtCore.QTimer.singleShot(1, self.update)
#        global ui, lastTime, fps, img
#        rv, frame = src.read()
#        # rotate frame if wanted
#        frame = np.rot90(frame, 3)
#        # flip frame
#        #frame = np.fliplr(frame)

    def closeEvent(self, event):
        """
        Exiting the interface has to kill the spotter class and subclasses
        properly, especially the writer and serial handles, otherwise division
        by zero might be imminent.
        """
        if NO_EXIT_CONFIRMATION:
            reply = QtGui.QMessageBox.Yes
        else:
            reply = QtGui.QMessageBox.question(self,
                                               'Exiting...',
                                               'Are you sure?',
                                               QtGui.QMessageBox.Yes,
                                               QtGui.QMessageBox.No )
        if reply == QtGui.QMessageBox.Yes:
            self.spotter.stop_all()
#            time.sleep(1)
            event.accept()
        else:
            event.ignore()

#def main(*args, **kwargs): #source, destination, fps, size, gui, serial
#        window = Main(*args, **kwargs)
#        window.show()
#        window.raise_() # needed on OSX?

###############################################################################
#        MAIN LOOP
###############################################################################
if __name__ == '__main__':
    logging.basicConfig(level=logging.INFO)
    logger = logging.getLogger(__name__)

#    app = QtGui.QApplication([])
#    if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'):
#        QtGui.QApplication.instance().exec_()
    QtGui.QApplication.setGraphicsSystem('raster')
    app = QtGui.QApplication([])
    main = Main(logger=logger, app=app)
    rv = app.exec_()
    logger.info('Application return value: %d. Done.', rv)
    sys.exit(rv)


import sys
from io import StringIO
import unittest

class TestClass(unittest.TestCase):
    def assertIO(self, input, output):
        stdout, stdin = sys.stdout, sys.stdin
        sys.stdout, sys.stdin = StringIO(), StringIO(input)
        resolve()
        sys.stdout.seek(0)
        out = sys.stdout.read()[:-1]
        sys.stdout, sys.stdin = stdout, stdin
        self.assertEqual(out, output)
    def test_Sample_Input_1(self):
        input = """ABC"""
        output = """ARC"""
        self.assertIO(input, output)

from math import gcd
from functools import reduce
from itertools import product

def resolve():
  contest = input()

  print("ARC" if contest == "ABC" else "ABC")

if __name__ == "__main__":
    resolve()

if __name__ == "__main__":
    unittest.main()


import json
from functools import cmp_to_key
from typing import List, Tuple

from more_itertools import flatten

from adventofcode.utils import load_input

def get_packet_pairs() -> List[Tuple[List, List]]:
    raw_pairs = load_input().split("\n\n")
    pairs = []

    for pair in raw_pairs:
        first, second = pair.split("\n")
        pairs.append((json.loads(first), json.loads(second)))

    return pairs

def compare_packets(first: List, second: List) -> int:
    index = 0
    while index < len(first) and index < len(second):
        # Both values are integers
        if isinstance(first[index], int) and isinstance(second[index], int):
            first_value = int(first[index])
            second_value = int(second[index])

            if first_value == second_value:
                index += 1
                continue

            return first_value - second_value

        # If both values aren't ints, we'll need to compare lists

        # Wrap the first if necessary
        first_value = first[index]
        if not isinstance(first[index], list):
            first_value = [first_value]

        # Wrap the second if necessary
        second_value = second[index]
        if not isinstance(second[index], list):
            second_value = [second_value]

        result = compare_packets(first_value, second_value)

        if result == 0:
            index += 1
            continue

        return result

    # If we got here, one or both of the lists ran out of items
    if len(first) < len(second):
        return -1

    if len(first) > len(second):
        return 1

    return 0

def part_1() -> int:
    return sum(
        index + 1
        for index, pair in enumerate(get_packet_pairs())
        if compare_packets(*pair) < 0
    )

print(part_1())

def part_2() -> int:
    first_divider_packet = [[2]]
    second_divider_packet = [[6]]

    in_order = sorted(
        [first_divider_packet, second_divider_packet, *flatten(get_packet_pairs())],
        key=cmp_to_key(compare_packets),
    )

    return (in_order.index(first_divider_packet) + 1) * (
        in_order.index(second_divider_packet) + 1
    )

print(part_2())


#from autograd import numpy as numpy
import numpy
import scipy
from . import lauricella_fd
from . import llh_fast
from . import poisson_gamma_mixtures
import copy

########################################################################################
####### Relevant Poisson generalizations from the paper https://arxiv.org/abs/1712.01293
####### and the newer one https://arxiv.org/abs/1902.08831
####### All formulas return the log-likelihood or log-probability
####### Formulas are not optimized for speed, but for clarity (except c implementations to some extent).
####### They can definately be sped up by smart indexing etc., and everyone has to adjust them to their use case anyway.
####### Formulas are not necessarily vetted, please try them out yourself first.
####### Any questions: thorsten.gluesenkamp@fau.de
########################################################################################

numpy.seterr(divide="warn")

######################################
#### standard Poisson likelihood
######################################
def poisson(k, lambd):

    return (-lambd+k*numpy.log(lambd)-scipy.special.gammaln(k+1)).sum()

################################################################
### Simple Poisson-Gamma mixture with equal weights (eq. 21 - https://arxiv.org/abs/1712.01293)
### multi bin expression, one k, one k_mc and one avg_weight item for each bin, all given by an array
def pg_equal_weights(k,k_mc,avgweights,prior_factor=0.0):

    return (scipy.special.gammaln((k+k_mc+prior_factor)) -scipy.special.gammaln(k+1.0)-scipy.special.gammaln(k_mc+prior_factor) + (k_mc+prior_factor)* numpy.log(1.0/avgweights) - (k_mc+k+prior_factor)*numpy.log(1.0+1.0/avgweights)).sum()

#################################################################################
## Standard poisson-gamma mixture, https://arxiv.org/abs/1712.01293 eq.  ("L_G")
#################################################################################
def pg_log_python(k, weights, alpha_individual=0.0, extra_prior_counter=0.0, extra_prior_weight=1.0):

    log_deltas=[0.0]
    log_inner_factors=[]
    log_weight_prefactors=0.0

    log_weight_prefactors+=-((1.0+alpha_individual)*numpy.log(1.0+weights)).sum()

    first_fac=1.0+alpha_individual

    log_first_fac= numpy.log(first_fac)
    log_first_var=-numpy.log(1.0+1.0/weights)

    running_factor_vec=0.0

    if(k>0):

        for i in (numpy.arange(k)+1):

            running_factor_vec+=log_first_var

            # summing assuming all summands positive .. which is the only well-defined region here

            res=scipy.special.logsumexp(log_first_fac+running_factor_vec)

            log_inner_factors.append(res)
            new_delta=scipy.special.logsumexp( numpy.array(log_inner_factors[::-1])+numpy.array(log_deltas))-numpy.log(i)
            log_deltas.append(new_delta)

            #log_inner_factors.append((first_fac*(first_var**i)-second_fac*(second_var**i)).sum())
            #log_deltas.append( (numpy.array(inner_factors)*numpy.array(deltas[::-1])).sum()/float(i))

    return log_deltas[-1]+log_weight_prefactors

## fast methods that employ c implementations and only fall back to log-python from above when certain accuracy is required
def fast_pg_single_bin(k, weights, mean_adjustment=0.0):

    # alphas array corresponds to alpha/N in paper
    ## gamma poisson mixture based on gamma-poisson priors - general

    betas=1.0/weights
    alphas=numpy.ones(len(weights), dtype=float)+mean_adjustment
    ret=poisson_gamma_mixtures.c_generalized_pg_mixture(k, alphas, betas)

    if(ret>1e-300 and len(weights)>0):
        return numpy.log(ret)
    else:
        prinnt("calling log")
        return pg_log_python(k,weights, alpha_individual=mean_adjustment)

################## end standard Poisson mixture ####################
####################################################################

########################################
### generalization (1) https://arxiv.org/abs/1902.08831, eq. 35 / eq. 97
########################################

def pgpg_log_python(k, weights, mean_adjustment):

    ## fix extra adjustment in standard PG to 0
    alpha_individual=0.0

    log_weight_prefactors=-(alpha_individual*numpy.log(1.0+weights)).sum()

    Cs=1.0/(2+2*weights)

    log_weight_prefactors+=-((1.0+mean_adjustment)*numpy.log(2.0-2*Cs)).sum()

    log_E_s=-numpy.log(1.+1./weights)
    #one_minus_c=(1+2*weights)/(2+2*weights)

    first_fac=1.0+mean_adjustment
    signs_first=numpy.where(first_fac>0, 1.0, -1.0)
    log_first_fac=numpy.where(signs_first>0, numpy.log(first_fac), numpy.log(-first_fac))

    second_fac=-(1.0+mean_adjustment-alpha_individual)
    signs_second=numpy.where(second_fac>0, 1.0, -1.0)
    log_second_fac=numpy.where(signs_second>0, numpy.log(second_fac), numpy.log(-second_fac))

    log_first_var=log_E_s-numpy.log(1.0-Cs)
    log_second_var=log_E_s

    log_deltas=[0.0]
    log_inner_factors=[]

    running_factor_vec_first=0.0
    running_factor_vec_second=0.0

    if(k>0):

        for i in (numpy.arange(k)+1):

            running_factor_vec_first+=log_first_var
            running_factor_vec_second+=log_second_var

            sum1,sign1=scipy.special.logsumexp(log_first_fac+running_factor_vec_first, b=signs_first,return_sign=True)
            sum2,sign2=scipy.special.logsumexp(log_second_fac+running_factor_vec_second, b=signs_second,return_sign=True)

            res=scipy.special.logsumexp([sum1, sum2], b=[sign1,sign2])

            log_inner_factors.append(res)
            new_delta=scipy.special.logsumexp( numpy.array(log_inner_factors[::-1])+numpy.array(log_deltas))-numpy.log(i)
            log_deltas.append(new_delta)

            #log_inner_factors.append((first_fac*(first_var**i)-second_fac*(second_var**i)).sum())
            #log_deltas.append( (numpy.array(inner_factors)*numpy.array(deltas[::-1])).sum()/float(i))

    return log_deltas[-1]+log_weight_prefactors

def fast_pgpg_single_bin(k, weights, mean_adjustment=0):

    ## fast calculation in c without logarithm .. if return value is too small, go to
    ## more time consuming calculation in log space in python
    ## gamma poisson mixture based on gamma-poisson priors - general

    gammas=1.0/weights
    deltas=numpy.ones(len(weights), dtype=float)+mean_adjustment
    epsilons=numpy.ones(len(deltas), dtype=float)

    ret=poisson_gamma_mixtures.c_generalized_pg_mixture_marginalized(k, gammas, deltas, epsilons)

    if(ret>1e-300 and len(weights)>0):
        return numpy.log(ret)
    else:
        return pgpg_log_python(k,weights, mean_adjustment=mean_adjustment)

####################
### end generalization (1)
####################

##############################################################
### generalization (2) - allbin expression, https://arxiv.org/abs/1902.08831 eq. 47
##############################################################

## the next 3 functions are used to calculate the convolution of N poisson-gamma mixtures in a safe way
### PG conv PG conv PG ... etc
import itertools
def bars_and_stars_iterator(tot_k, num_bins):

    for c in itertools.combinations(range(tot_k+num_bins-1), num_bins-1):
        yield [b-a-1 for a, b in zip((-1,)+c, c+(tot_k+num_bins-1,))]

### calculate single poisson gamma mixture in calc_pg vectorized over alpha/beta
def calc_pg(k, alpha, beta):
    return (scipy.special.gammaln(k+alpha) -scipy.special.gammaln(k+1.0)-scipy.special.gammaln(alpha) + (alpha)* numpy.log(beta) - (alpha+k)*numpy.log(1.0+beta))

## second way to calculate generalized pg mixture, based on iterative sum
def generalized_pg_mixture_2nd(k, alphas, betas):

    iters=[numpy.array(i) for i in bars_and_stars_iterator(int(k), len(betas))]

    log_res=[]
    for it in iters:

        log_res.append(calc_pg(it, alphas, betas).sum())

    return scipy.special.logsumexp(log_res)

## calculate c-based version .. if it doesnt suffice in precision, go to direct convolution
def fast_pgmix(k, alphas, betas):
    ret=poisson_gamma_mixtures.c_generalized_pg_mixture(k, alphas, betas)

    if(ret>1e-300):
        return numpy.log(ret)
    else:
        return generalized_pg_mixture_2nd(k, alphas, betas)

def poisson_gen2(data, individual_weights_dict, mean_adjustments, larger_weight_variance=False):

    tot_llh=0.0

    for cur_bin_index, _ in enumerate(list(individual_weights_dict.values())[0]):

        alphas=[]
        betas=[]

        for src in individual_weights_dict.keys():

            this_weights=individual_weights_dict[src][cur_bin_index]

            if(len(this_weights)>0):
                kmc=float(len(this_weights))
                mu=float(len(this_weights))

                exp_w=0.0

                exp_w=numpy.mean(this_weights)
                var_w=0.0

                if(larger_weight_variance):
                    var_w=(this_weights**2).sum()/float(len(this_weights))
                else:
                    var_w=((this_weights-exp_w)**2).sum()/(float(len(this_weights)))

                var_z=(var_w+exp_w**2)

                beta=exp_w/var_z
                trad_alpha=(exp_w**2)/var_z

                #sumw=this_weights.sum()
                #sqrw=(this_weights**2).sum()

                extra_fac=mean_adjustments[src]

                alphas.append( (mu+extra_fac)*trad_alpha)
                betas.append(beta)

        if(len(alphas)>0):

            tot_llh+=fast_pgmix(data[cur_bin_index], numpy.array(alphas), numpy.array(betas))

    return tot_llh

########################################
# end generalization (2)
########################################

####################################################
### effective generalization (2) - allbin expression, https://arxiv.org/abs/1902.08831 , eq 48
####################################################

def poisson_gen2_effective(data, individual_weights_dict, mean_adjustments):

    tot_llh=0.0

    for cur_bin_index, _ in enumerate(list(individual_weights_dict.values())[0]):

        mus=[]
        all_weights=[]

        for src in individual_weights_dict.keys():

            this_weights=individual_weights_dict[src][cur_bin_index]

            if(len(this_weights)>0):

                all_weights.extend(this_weights.tolist())

                mus.append(float(len(this_weights))+mean_adjustments[src])

        all_weights=numpy.array(all_weights)

        if(len(all_weights)>0):
            #print all_weights
            kmc=float(len(all_weights))

            exp_w=numpy.mean(all_weights)
            var_w=((exp_w-all_weights)**2).sum()/kmc

            var_z=(var_w+exp_w**2)

            #print "expw,varw,varz", exp_w,var_w,var_z
            beta=exp_w/var_z
            trad_alpha=(exp_w**2)/var_z

            alpha=sum(mus)*trad_alpha
            k=data[cur_bin_index]

            #print "alpha,beta,k", alpha,beta,k

            this_llh= (scipy.special.gammaln((k+alpha)) -scipy.special.gammaln(k+1.0)-scipy.special.gammaln(alpha) + (alpha)* numpy.log(beta) - (alpha+k)*numpy.log(1.0+beta)).sum()

            tot_llh+=this_llh

    return tot_llh

##################################
### generalization (3) functions, https://arxiv.org/abs/1902.08831, eq. 51
##################################

### Genertes stirling numbers (logarithmic) up to maximum no of max_val
### returns a lower-triangular matrix
def generate_log_stirling(max_val=1000):

    arr=numpy.zeros(shape=(max_val+1, max_val+1))*(-numpy.inf)
    arr[0][0]=0.0
    for i in range(max_val+1):
        for j in range(i+1):
            if(i==0 and j==0):
                arr[i][j]=0.0
                continue

            if(j==0):
                arr[i][j]=-numpy.inf
                continue
            if(i==j):
                arr[i][j]=0.0
                continue

            arr[i][j]=scipy.special.logsumexp([numpy.log(i-1.0)+arr[i-1][j],arr[i-1][j-1]])

    return arr

def poisson_gen3(k, individual_weights_dict, mean_adjustments, log_stirlings,s_factor=1.0, larger_weight_variance=False):

    tot_llh=0.0

    num_sources=len(individual_weights_dict.keys())

    for cur_bin_index, _ in enumerate(list(individual_weights_dict.values())[0]):

        As=[]
        Bs=[]
        Qs=[]
        kmcs=[]
        gammas=[]

        for src in individual_weights_dict.keys():

            this_weights=individual_weights_dict[src][cur_bin_index]

            if(len(this_weights)>0):
                kmc=float(len(this_weights))
                mu=float(len(this_weights))

                Q=0.0
                if(larger_weight_variance>0):
                    exp_w=numpy.mean(this_weights)
                    var_w=0.0

                    ## pdf is a mixture of gammas
                    var_w=(this_weights**2).sum()/float(len(this_weights))

                    var_z=(var_w+exp_w**2)
                    beta=exp_w/var_z
                    trad_alpha=(exp_w**2)/var_z
                    Q=trad_alpha
                else:

                    sumw=this_weights.sum()
                    sumw2=(this_weights**2).sum()

                    beta=sumw/sumw2

                    trad_alpha=sumw**2/sumw2
                    Q=(1.0/kmc)*(trad_alpha)

                A=beta/(1.0+beta)
                B=1.0/(1.0+beta)

                extra_fac=mean_adjustments[src]

                As.append(A)
                Bs.append(B)
                Qs.append(Q)

                kmcs.append( (mu+extra_fac)/s_factor)
                gammas.append(1.0/s_factor)

        As=numpy.array(As)
        Bs=numpy.array(Bs)
        Qs=numpy.array(Qs)
        kmcs=numpy.array(kmcs)
        gammas=numpy.array(gammas)

        tot_llh+=poisson_gamma_mixtures.c_multi_pgg(int(k[cur_bin_index]), As,Bs,Qs,kmcs,gammas, log_stirlings)

    return tot_llh

######### ##################
#### end generalization (3)
############################

############################################
### generic preprocessing to include prior information and empty bins as described
### in paper (1) https://arxiv.org/abs/1712.01293 and  paper (2) https://arxiv.org/abs/1902.08831
############################################

def generic_pdf(k_list, dataset_weights, type="gen2", empty_bin_strategy=1, empty_bin_weight="max", mean_adjustment=True, s_factor=1.0, larger_weight_variance=False, log_stirling=None):
    """
    k_list - a numpy array of counts for each bin
    dataset_weights_list - a dictionary of lists of numpy arrays. Each list corresponds to a dataset and contains numpy arrays with weights for a given bin. empty bins here mean an empty array
    type - basic_pg/gen1/gen2/gen2_effective/gen3 - handles the various formulas from the two papers - (basic_pg (paper 1), all others (paper 2))
    empty_bin_strategy - 0 (no filling), 1 (fill up bins which have at least one event from other sources), 2 (fill up all bins)
    empty_bin_weight - what weight to use for pseudo counts in empty  bins? "max" , maximum of all weights of dataset (used in paper) .. could be mean etc
    mead_adjustment - apply mean adjustment as implemented in the paper? yes/no
    weight_moments - change to more "unbiased" way of determining weight distribution moments as implemented in the paper

    default settings (as stated towards the end of the paper): gen2 , empty_bin_strategy=1, mead_adjustment=True
    """

    ## calculate number of mc events / bin / dataset
    kmc_dict=dict()
    max_weights=dict()
    for dsname in dataset_weights.keys():
        mw=max([max(w) if len(w)>0 else 1.0 for w in dataset_weights[dsname]])
        kmc_dict[dsname]=numpy.array([len(w) for w in dataset_weights[dsname]])
        max_weights[dsname]=mw

    ## calculate mean adjustment per dataset
    mean_adjustments=dict()
    for dsname in kmc_dict.keys():

        avg_kmc=numpy.mean(kmc_dict[dsname])

        delta_alpha=0.0
        if(avg_kmc<1.0):
            delta_alpha=-(1.0-avg_kmc)+1e-3
        mean_adjustments[dsname]=delta_alpha

    ## fill in empty bins - update the weights
    new_weights=copy.deepcopy(dataset_weights)

    ## strategy 1 - fill up only bins that have at least 1 mc event from any dataset
    if(empty_bin_strategy==1):

        for bin_index in range(len(k_list)):

            weight_found=False
            for dsname in kmc_dict.keys():
                if(kmc_dict[dsname][bin_index] > 0):
                    weight_found=True

            if(weight_found):

                for dsname in kmc_dict.keys():
                    if(kmc_dict[dsname][bin_index]==0):

                        new_weights[dsname][bin_index]=numpy.array([max_weights[dsname]])

    # strategy 2 - fill up all bins
    elif(empty_bin_strategy==2):
        for bin_index in range(len(k_list)):

            for dsname in kmc_dict.keys():
                if(kmc_dict[dsname][bin_index]==0):
                    new_weights[dsname][bin_index]=numpy.array([max_weights[dsname]])

    ## now loop through all bins and call respective likelihood
    ## manifest mean adjustment possible only in gen2 and gen3 (see table in paper)

    llh_res=0.0

    if(type=="gen3"):
        if(log_stirling is None):
            log_stirling=generate_log_stirling(max_val=max([max(k_list),1]))

        llh_res=poisson_gen3(k_list, new_weights, mean_adjustments, log_stirling,s_factor=s_factor, larger_weight_variance=larger_weight_variance)

    elif(type=="gen2"):
        llh_res=poisson_gen2(k_list, new_weights, mean_adjustments, larger_weight_variance=larger_weight_variance)
    elif(type=="gen2_effective"):
        llh_res=poisson_gen2_effective(k_list, new_weights, mean_adjustments)
    else:

        ## calculate an effective mean adjustment per weight (no manifest mean adjustment possible)

        for bin_index in range(len(k_list)):
            total_weights=[]
            individual_mean_adjustments=[]

            for dsname in new_weights.keys():
                this_weights=new_weights[dsname][bin_index].tolist()
                this_len=len(this_weights)
                total_weights.extend(this_weights)

                ## alpha* = alpha/N
                if(this_len>0):
                    individual_mean_adjustments.extend(this_len*[mean_adjustments[dsname]/float(this_len)])

            if(len(total_weights)>0):

                total_weights=numpy.array(total_weights)
                individual_mean_adjustments=numpy.array(individual_mean_adjustments)

                if(type=="basic_pg"):
                    llh_res+=fast_pg_single_bin(k_list[bin_index], total_weights, mean_adjustment=individual_mean_adjustments)
                elif(type=="gen1"):
                    llh_res+=fast_pgpg_single_bin(k_list[bin_index], total_weights, mean_adjustment=individual_mean_adjustments)

    return llh_res

#################################
### arXiv:1901.04645, Arg+elles et al.
##################################
## a=1 is effective version, recommended by the authors
##########################################
def asy_llh(data,all_weights,weight_indices, a_prior=1):
    """
    data - array of data counts of size J
    all_weights - array of all weights of size N
    weight_indices - list of numpy arrays of size J (one index array per bin, picks out the wieghts from all_weights)
    """
    tot_llh=0.0
    for ind, cur_weight_mask in enumerate(weight_indices):

        cur_weights=all_weights[cur_weight_mask]
        weight_sum=cur_weights.sum()
        sqr_weight_sum=(cur_weights**2).sum()

        alpha=(weight_sum**2)/sqr_weight_sum+a_prior
        beta=weight_sum/sqr_weight_sum
        tot_llh+= (scipy.special.gammaln((data[ind]+alpha)) -scipy.special.gammaln(data[ind]+1.0)-scipy.special.gammaln(alpha) + (alpha)* numpy.log(beta) - (alpha+data[ind])*numpy.log(1.0+beta)).sum()

    return tot_llh

##########################
###### Barlow/Beeston (https://www.sciencedirect.com/science/article/pii/001046559390005W) (without const terms)
#########################

def barlow_beeston_llh(data, weights_dict, indices_dict):
    """
    data - array of data counts of size J
    all_weights - array of all weights of size N
    weight_indices - list of numpy arrays of size J (one index array per bin, picks out the wieghts from all_weights)
    """

    def func(x, w, d):
        #print "x ", x
        #print "w ", w
        #print "d ", d
        """
        Reweighting function: 1/sum(w/(1+xw))
        The function should be equal to (1-x)/N_exp
        for reweighting variable x. Note, that w is an array
        since it is the (i,j) entry of w_hist.
        """
        return 1./numpy.sum(w/(1. + x*w)) - (1. - x)/d

    if data.ndim == 1:
        # array of reweighting factors

        new_avg_weights=[]
        new_kmcs=[]

        ## ind goes over all bins

        for ind in numpy.arange(len(list(indices_dict.values())[0])):
            these_weights=[]

            for src_key in indices_dict.keys():
                #print all_weights_src_list[ind_src][weight_indices_src_list[ind_src][ind]]

                if(len(indices_dict[src_key][ind])>0):
                    these_src_weights=weights_dict[src_key][indices_dict[src_key][ind]]

                    these_weights.extend([numpy.mean(these_src_weights)]*len(these_src_weights))

            new_avg_weights.append(numpy.array(these_weights))

        lagrange = numpy.array([(scipy.optimize.brentq(func, -0.999999/max(w), 1., args=(w,d), full_output=False)\
                    if d else 1.) if (len(w)>0) else 0. for (d, w) in zip(data, new_avg_weights)])

        # llh with new weights
        llh = numpy.array([numpy.sum((numpy.log(1. + lagrange[i]*w))) if(len(w)>0) else 0 for (i,w) in enumerate(new_avg_weights)])\
              + data * numpy.log(1.-(lagrange-(lagrange == 1.)))

    else:
        raise NotImplementedError("`data` has more than 1 dimensions.")

    return -llh.sum()

##############################################################################
### Chirkin (https://arxiv.org/abs/1304.0735)
###########################################################################################

def chirkin_llh(data, all_weights, weight_indices):
    """
    data - array of data counts of size J
    all_weights - array of all weights of size N
    weight_indices - list of numpy arrays of size J (one index array per bin, picks out the wieghts from all_weights)
    """

    def func(x, w, d):
        """
        Reweighting function: 1/sum(w/(1+xw))
        The function should be equal to (1-x)/N_exp
        for reweighting variable x. Note, that w is an array
        since it is the (i,j) entry of w_hist.
        """
        return 1./numpy.sum(w/(1. + x*w)) - (1. - x)/d

    if data.ndim == 1:
        # array of reweighting factors
        lagrange = numpy.array([(scipy.optimize.brentq(func, -0.999999/max(all_weights[w]), 1., args=(all_weights[w],d), full_output=False)\
                    if d else 1.) if (len(w)>0) else 0. for (d, w) in zip(data, weight_indices)])
        # llh with new weights

        llh = numpy.array([numpy.sum(numpy.log(1. + lagrange[i]*all_weights[w])) if(len(w)>0) else 0 for (i,w) in enumerate(weight_indices)])\
              + data * numpy.log(1.-(lagrange-(lagrange == 1.)))
        raise NotImplementedError("`data` has more than 1 dimensions.")

    return -llh.sum()


import os
import numpy as np
from glob import glob
from PIL import Image
from tqdm import tqdm

import torch
from torchvision import transforms

PIX2PIX_DATASETS = [
    'facades', 'cityscapes', 'maps', 'edges2shoes', 'edges2handbags']

def makedirs(path):
    if not os.path.exists(path):
        os.makedirs(path)

def pix2pix_split_images(root):
    paths = glob(os.path.join(root, "train/*"))

    a_path = os.path.join(root, "A")
    b_path = os.path.join(root, "B")

    makedirs(a_path)
    makedirs(b_path)

    for path in tqdm(paths, desc="pix2pix processing"):
        filename = os.path.basename(path)

        a_image_path = os.path.join(a_path, filename)
        b_image_path = os.path.join(b_path, filename)

        if os.path.exists(a_image_path) and os.path.exists(b_image_path):
            continue

        image = Image.open(os.path.join(path)).convert('RGB')
        data = np.array(image)

        height, width, channel = data.shape

        a_image = Image.fromarray(data[:,:width/2].astype(np.uint8))
        b_image = Image.fromarray(data[:,width/2:].astype(np.uint8))

        a_image.save(a_image_path)
        b_image.save(b_image_path)

class Dataset(torch.utils.data.Dataset):
    def __init__(self, root, scale_size, data_type, skip_pix2pix_processing=False):
        self.root = root
        if not os.path.exists(self.root):
            raise Exception("[!] {} not exists.".format(root))

        self.name = os.path.basename(root)
        if self.name in PIX2PIX_DATASETS and not skip_pix2pix_processing:
            pix2pix_split_images(self.root)

        self.paths = glob(os.path.join(self.root, '{}/*'.format(data_type)))
        if len(self.paths) == 0:
            raise Exception("No images are found in {}".format(self.root))
        self.shape = list(Image.open(self.paths[0]).size) + [3]

        self.transform = transforms.Compose([
            transforms.Scale(scale_size),
            transforms.ToTensor(),
            transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5)),
        ])

    def __getitem__(self, index):
        image = Image.open(self.paths[index]).convert('RGB')
        return self.transform(image)

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

def get_loader(root, batch_size, scale_size, num_workers=2,
               skip_pix2pix_processing=False, shuffle=True):
    a_data_set, b_data_set = \
        Dataset(root, scale_size, "A", skip_pix2pix_processing), \
        Dataset(root, scale_size, "B", skip_pix2pix_processing)
    a_data_loader = torch.utils.data.DataLoader(dataset=a_data_set,
                                                batch_size=batch_size,
                                                shuffle=True,
                                                num_workers=num_workers)
    b_data_loader = torch.utils.data.DataLoader(dataset=b_data_set,
                                                batch_size=batch_size,
                                                shuffle=True,
                                                num_workers=num_workers)
    a_data_loader.shape = a_data_set.shape
    b_data_loader.shape = b_data_set.shape

    return a_data_loader, b_data_loader


"""
    Telegram Bot
"""
import logging

# Importing telegram python module
from telegram.ext import Updater, CommandHandler, MessageHandler, Filters

# Importing app modules
from twitter import models
import telegram_handler.utils as utils
import telegram_handler as handler

# Setting up the logger
logging.basicConfig(
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', level=logging.INFO)

# Global object to store last tweet data
tweet = models.Tweet(None, "", [])

def bot():
    """Main function to start the bot"""
    # Setting up the updater
    updater = Updater(token=utils.get_secret(), use_context=True)
    # Setting up the dispatcher
    dispatcher = updater.dispatcher

    # Handlers
    start_handler = CommandHandler('start', handler.start)
    message_handle = MessageHandler(Filters.text & ~Filters.command, handler.send_tweet)
    delete_handle = CommandHandler('delete', handler.delete_tweet)
    comment_handle = CommandHandler('comment', handler.comment_tweet, pass_args=True)
    test_handle = CommandHandler('test', handler.test)

    # Adding handlers to the dispatcher
    dispatcher.add_handler(start_handler)
    dispatcher.add_handler(message_handle)
    dispatcher.add_handler(delete_handle)
    dispatcher.add_handler(test_handle)
    dispatcher.add_handler(comment_handle)

    # Starting the bot
    updater.start_polling()


import tkinter
import customtkinter as ctk
import customtkinter
from utils.layout.front import *
import os
from banco_conections.conexao import *
from banco_conections.conexao_forncedores import query_fornecedor
from PIL import ImageTk, Image
from banco_conections.conexao_categorias import query_categoria

def cad_categoria():
    janela_categoria = customtkinter.CTkToplevel()
    janela_categoria.attributes("-topmost", True)
    janela_categoria.title("Cadastro de Categoria")
    janela_categoria.after(200, lambda: janela_categoria.iconbitmap("./imagens/logo_icone.ico")) # alterando o icone da janela
    janela_categoria.geometry("1000x550+250+70")
    janela_categoria.resizable(False, False)
    janela_categoria.grid_rowconfigure(0, weight=1)
    janela_categoria.grid_columnconfigure(1, weight=1)

    # Inserindo as imagens que serão utilizadas
    image_path = os.path.join(os.path.dirname(os.path.realpath(
        __file__)), "C:/sistema_estoque/imagens")

    background_image = customtkinter.CTkImage(dark_image=Image.open(
    os.path.join(image_path, "background_fornecedor.png")), size=(1000, 550))

    # Inserindo imagem de fundo
    label_background = customtkinter.CTkLabel(master=janela_categoria,
                                          text="",
                                          image=background_image)
    label_background.pack()

    label_combobox = customtkinter.CTkLabel(master=janela_categoria,
                                             text="SEGMENTO",
                                             font=('Poppins bold', 13),
                                             width=40,
                                             height=20,
                                             fg_color=co4,
                                             bg_color="transparent")
    label_combobox.place(x=330, y=150, anchor=tkinter.CENTER)

    #Caixa para selecionar segmento
    global var_combobox
    combobox = customtkinter.CTkOptionMenu(master=janela_categoria,
                                       values=["Alimentos", "Bebida", "Papelaria", "Informatica", "Cosmeticos", "Outros"])
    combobox.configure(fg_color=co0, width=180, height=30)
    combobox.set("Informatica")  # setando valor inicial
    combobox.place(x=294, y=168)
    var_combobox = combobox.get()

    label_categoria = customtkinter.CTkLabel(master=janela_categoria,
                                             text="CATEGORIA",
                                             font=('Poppins bold', 13),
                                             width=40,
                                             height=20,
                                             fg_color=co4,
                                             bg_color="transparent")
    label_categoria.place(x=600, y=150, anchor=tkinter.CENTER)

    # Criando e configurando a entry categoria
    entry_categoria = customtkinter.CTkEntry(master=janela_categoria,
                                        width=250,
                                        height=30,
                                        font=('Century gothic', 13),
                                        fg_color="transparent",
                                        bg_color="transparent",
                                        border_color=co0,
                                        placeholder_text='Insira o nome da categoria',
                                        justify='center')
    entry_categoria.place(x=687, y=183, anchor=tkinter.CENTER)

    def armazenar_categoria():

        global var_categoria
        var_categoria = entry_categoria.get()
    armazenar_categoria

    def clean_entryc():
        entry_categoria.delete(0, "end")
    clean_entryc

    # Criando e configurando o botão cadastrar
    button_cadastrar = customtkinter.CTkButton(master=janela_categoria, text="CADASTRAR",
                                            width=15,
                                            height=15,
                                            font=('Poppins Bold', 15),
                                            fg_color=co4,
                                            hover_color=co2,
                                            bg_color=co4,
                                            cursor='hand2')

    button_cadastrar.place(x=520, y=270, anchor=tkinter.CENTER)

    # Cadastrando as infomações do fornecedor no banco de dados
    button_cadastrar.configure(command=lambda:[armazenar_categoria(), query_categoria(), clean_entryc()])

    janela_categoria.mainloop()

cad_categoria


import asyncio
import serial
from serial.serialutil import SerialException
import json
import pytz
import time

from .models import RawMessage

from channels.db import database_sync_to_async

from channels.generic.websocket import AsyncWebsocketConsumer

class WSConsumer(AsyncWebsocketConsumer):
    async def connect(self):
        await self.accept()

        self.simulation_mode = False  # Set this flag to True for simulation mode

        try:
            self.serial = serial.Serial(
                port='/dev/ttyUSB0',
                baudrate=9600,
                bytesize=serial.EIGHTBITS,
                parity=serial.PARITY_NONE,
                stopbits=serial.STOPBITS_ONE,
                timeout=1
            )
        except SerialException as e:
            await self.send(f"Error opening serial port: {str(e)}")
            return

        # Start reading data from the serial port
        await self.read_data()

    async def disconnect(self, close_code):
        if hasattr(self, 'serial'):
            self.serial.close()

    @database_sync_to_async
    def save_message_to_db(self, data):
        # Check if the data contains null characters
        if '\x00' in data:
            # Replace null characters with a message
            sanitized_data = data.replace('\x00', 'null character were sent ---> \x00')
        else:
            sanitized_data = data

        message_instance = RawMessage(data=sanitized_data)
        message_instance.save()

# ...
    async def read_data(self):
        tz = pytz.timezone('Europe/London')

        while True:
            try:
                data = self.serial.readline().decode('utf-8')

                if data:
                    # Create and save a Message instance with the received message
                    try:
                        await self.save_message_to_db(data)
                    except Exception as e:
                        print(f"Error while saving the message: {str(e)}")

                    message = {"meta": f"{data}"}
                    print(message)

                    await self.send(text_data=json.dumps(message))
                else:
                    print(f'No incoming data from drystore')

            except SerialException as e:
                await self.send(f"Serial port error: {str(e)}")
            except Exception as e:
                await self.send(f"Error: {str(e)}")

            await asyncio.sleep(1)  # Sleep for 1 second before checking the serial port again


"""
Author : Dimitri Watel
Year : 2020

Model of the flask application, contains all the functions manipulating the database.

The database managed with TinyDB and stored in a file named **db.json**.
"""

from tinydb import TinyDB, Query, where
import networkx as nx
from networkx.algorithms import isomorphism as isoalg

# Build the database
db = TinyDB('db.json')

def add_iso(g_id):
    """
    Add the graph with id **g_id** in I by storing it in the database with the type 'iso'
    :param g_id: id of a graph
    :return: True
    """
    db.insert({'type': 'iso', 'g_id': g_id})
    return True

def remove_iso(g_id):
    """
    Remove the graph with id **g_id** in I by removing that id stored with the type 'iso' from the database
    :param g_id: id of a graph
    :return: True
    """
    q = Query()
    db.remove((q.type == 'iso') & (q.g_id == g_id))
    return True

def add_node(g_id, u_id, x, y):
    """
    Add a node with id **u_id** to the graph with id **g_id** at coordinates **x** and **y** by storing all those information in the
    database with the type 'node'. If such a node is already associated to the graph in the database, nothing is done.
    :param g_id: id of a graph
    :param u_id: id of a node
    :param x: x coordinate of the node
    :param y: y coordinate of the node
    :return: True if the node is added to the graph and False otherwise
    """
    q = Query()
    i = db.search((q.type == 'node') & (q.g_id == g_id) & (q.u_id == u_id))  # Prevent dupplicates
    if len(i) == 0:
        db.insert({'type': 'node', 'g_id': g_id, 'u_id': u_id, 'x': x, 'y': y})
        return True
    else:
        return False

def add_edge(g_id, u_id, v_id):
    """
    Add an edge linking the nodes with ids **u_id** and **v_id** to the graph with id **g_id** by storing all those information in
    the database with the type 'edge'. If such an edge is already associated to the graph in the database, if **u_id** equals **v_id**
    or if **u_id** or **v_id** do not belong to the graph in the database, nothing is done.
    :param g_id: id of a graph
    :param u_id: id of a node
    :param v_id: id of a node
    :return: True if the edge is added to the graph and False otherwise
    """
    if u_id == v_id:
        return False
    if v_id < u_id:
        u_id, v_id = v_id, u_id

    q = Query()
    i = db.search((q.type == 'node') & (q.g_id == g_id) & ((q.u_id == u_id) | (q.u_id == v_id)))
    if len(i) != 2:
        return False
    i = db.search((q.type == 'edge') & (q.g_id == g_id) & (q.u_id == u_id) & (q.v_id == v_id))  # Prevent dupplicates
    if len(i) == 0:
        db.insert({'type': 'edge', 'g_id': g_id, 'u_id': u_id, 'v_id': v_id})
        return True
    return False

def remove_node(g_id, u_id):
    """
    Remove the node with id **u_id** from the graph with id **g_id** by removing all those information stored in the
    database with the type 'node'. Remove also every edge incident to that node from the graph by removing every
    document from the database containing the type 'edge' and where the id of one of the two extremities is **u_id**
     If no such node exists in the graph in the database, nothing is done.
    :param g_id: id of a graph
    :param u_id: id of a node
    :return: True if the node is removed from the graph and False otherwise
    """
    q = Query()
    r = db.remove((q.type == 'node') & (q.g_id == g_id) & (q.u_id == u_id))
    if len(r) > 0:
        db.remove((q.type == 'edge') & (q.g_id == g_id) & ((q.u_id == u_id) | (q.v_id == u_id)))
        return True
    return False

def remove_edge(g_id, u_id, v_id):
    """
    Remove the edge linking the nodes with id **u_id** and **v_id** from the graph with id **g_id** by removing all those
    information stored in the database with the type 'edge'. If no such edge exists in the graph in the database, nothing is
    done.
    :param g_id: id of a graph
    :param u_id: id of a node
    :param v_id: id of a node
    :return: True if the edge is removed from the graph and False otherwise
    """
    if u_id == v_id:
        return False
    if v_id < u_id:
        u_id, v_id = v_id, u_id
    q = Query()
    r = db.remove((q.type == 'edge') & (q.g_id == g_id) & (q.u_id == u_id) & (q.v_id == v_id))
    return len(r) > 0

def move_node(g_id, u_id, x, y):
    """
    Update the coordinates of the node with id **u_id** in the graph with id **g_id** to **x** and **y** by updating
    the 'x' and 'y' fields of the document containing those ids with the type 'node'. If no such node is associated
    to the graph in the database, nothing is done.
    :param g_id: id of a graph
    :param u_id: id of a node
    :param x: x coordinate of the node
    :param y: y coordinate of the node
    :return: True if the node is moved and False otherwise
    """
    q = Query()
    r = db.update({'x': x, 'y': y}, (q.type == 'node') & (q.g_id == g_id) & (q.u_id == u_id))
    return len(r) > 0

def save_main_name(name):
    """
    Update the name of the graph with id 0 in the database to **name** by updating the field 'name' of the document containing that
    id with the type 'properties'
    :param name: new name of the graph with id 0
    :return: True if the name is not None and False otherwise
    """
    if name is None:
        return False
    q = Query()
    db.upsert({'type': 'properties', 'g_id': 0, 'name': name}, (q.type == 'properties') & (q.g_id == 0))
    return True

def remove_graph(g_id):
    """
    Remove every occurrence of the graph with id **g_id** from the database
    :param g_id: id of a graph
    :return: True
    """
    db.remove(where('g_id') == g_id)
    return True

def erase_graph(g1_id, g2_id, name=None):
    """
    Erase the graph with id **g2_id** with a copy of the graph with id **g1_id**. To do so, every document where
    the field 'g_id' equals **g2_id** is removed and every document where the type is not 'iso' and where
    the field 'g_id' equals **g1_id** is copied, modified so that the field is replaced by **g2_id** and reinserted
    in the database. If the parameter **name** is not None, the name of the copied graph is set to **name** by the
    field 'name' of the document
    containing that id with the type 'properties'.

    g1_id should not equal g2_id otherwise nothing is done.
    :param g1_id: id of a graph
    :param g2_id: id of a graph
    :param name: new name of the copied graph
    :return: False is g1_id equals g2_id and g2_id otherwise.
    """
    if g1_id == g2_id:
        return False
    if g2_id is None:
        g2_id = max(x['g_id'] for x in db.search(where('type') == 'node')) + 1
    remove_graph(g2_id)
    q = Query()
    for x in db.search((q.g_id == g1_id) & (q.type != 'iso')):
        y = dict(x)
        y['g_id'] = g2_id
        db.insert(y)
    if name is not None:
        db.upsert({'type': 'properties', 'g_id': g2_id, 'name': name}, (q.type == 'properties') & (q.g_id == g2_id))
    return g2_id

def _get_graph(g_id):
    """
    A networkx graph object corresponding to the graph with id **g_id**. If no such graph exists an empty graph is
    returned
    :param g_id: id of a graph
    :return: a networkx graph object corresponding to the graph with id **g_id**
    """
    q = Query()
    nodes = (res['u_id'] for res in db.search((q.g_id == g_id) & (q.type == 'node')))
    edges = ((res['u_id'], res['v_id']) for res in db.search((q.g_id == g_id) & (q.type == 'edge')))

    g = nx.Graph()
    g.add_nodes_from(nodes)
    g.add_edges_from(edges)
    return g

def get_graph_dict(g_id):
    """
    Return a dict containing all the information of the graph with id **g_id** stored in the database. The dict has the
    following format :
    {
    'nodes' : list of ids of the nodes of the graph,
    'edges' : list of edges of the graph, each edge is described by the ids of the two extremities of the edge
    'name': the name of the graph stored in the document with type 'properties',
    'iso': True if the graph id is stored with the type 'iso' and False otherwise
    }

    :param g_id: id of a graph
    :return: A dict containing all the information of the graph with id **g_id** stored in the database
    """
    q = Query()
    nodes = [(res['u_id'], res['x'], res['y']) for res in db.search((q.g_id == g_id) & (q.type == 'node'))]
    edges = [(res['u_id'], res['v_id']) for res in db.search((q.g_id == g_id) & (q.type == 'edge'))]
    try:
        name = db.search((q.type == 'properties') & (q.g_id == g_id))[0]['name']
    except IndexError:
        name = ''
    iso = len(db.search((q.type == 'iso') & (q.g_id == g_id))) != 0
    return {'nodes': nodes, 'edges': edges, 'name': name, 'iso': iso}

def get_graph_infos():
    """
    Return a list of dicts containing some information of all the graphs stored in the database. Each dict has the
    following format :
    {
        'graph_id': the id of the graph,
        'name': the name of the graph,
        'iso': True if the graph id is stored with the type 'iso' and False otherwise
    }
    :return: A list of dicts containing some information of all the graphs stored in the database.
    """
    q = Query()
    isos = [res['g_id'] for res in db.search(q.type == 'iso')]
    names = [{'graph_id': res['g_id'], 'name': res['name'], 'iso': res['g_id'] in isos}
             for res in db.search((q.type == 'properties'))]
    names.sort(key=lambda x: x['name'])
    return names

def get_induced_subgraphs():
    """
    Return a list of dicts describing all the subgraphs of the graph with id 0 that are isomorphic to at least one graph for
    which the id is stored in the database with the type 'iso'.
    The list has the following format:
    [
    For each subgraph
        {
            'subgraph_id': the id of the graph stored with the type 'iso' isommorphic to the subgraph
            'nodes': the list of nodes of the subgraph
            'edges': the list of edges of the subgraph, each edge is described by the ids of the two extremities of
            the edge
        }
    ]
    :return: a list of dicts describing all the subgraphs of the graph with id 0 that are isomorphic to at least one graph for
    which the id is stored in the database with the type 'iso'.
    """
    q = Query()
    g = _get_graph(0)
    isos = [res['g_id'] for res in db.search(q.type == 'iso')]
    subgraphs = ((id, _get_graph(id)) for id in isos)

    inds = set()
    induced_subgraphs = []

    for id, subgraph in subgraphs:
        gm = isoalg.GraphMatcher(g, subgraph)
        for gm in gm.subgraph_isomorphisms_iter():
            k = frozenset(gm.keys())
            if k not in inds:
                inds.add(k)
                induced_subgraphs.append({'subgraph_id': id, 'nodes': list(k), 'edges': list(nx.Graph.subgraph(g, k).edges())})

    return induced_subgraphs


import sys, argparse
from argparse import RawTextHelpFormatter

__author__ = "Ryan Smith (ryanpsmith@wustl.edu)"
__version__ = "$Revision: 0.1.0 $"
__date__ = "$Date: 2015-3-9 $"

def get_args():
    parser = argparse.ArgumentParser(formatter_class=RawTextHelpFormatter, description="\
fix_segs\n\
author: " + __author__ + "\n\
version: " + __version__ + "\n\
description: DESCRIPTION")
    parser.add_argument('-i', '--input', type=argparse.FileType('r'), required=False, default=None, help="Input file [stdin]")
    parser.add_argument('-o', '--output', type=argparse.FileType('w'), required=False, default=sys.stdout, help="Output file [stdout]")
    # parse the arguments
    args = parser.parse_args()

    # if no input, check if part of pipe and if so, read stdin.
    if args.input == None:
        if sys.stdin.isatty():
            parser.print_help()
            exit(1)
        else:
            args.input = sys.stdin
    # send back the user input
    return args

'''WARNING: THIS RUNS ONLY ON BEDTOOLS INTERSECT WITH FILTERED COLUMNS
Essentially a one-time use script.
Command used:
<(bedtools intersect -wa -wb -a <(bedtools slop -b 50 -g hg19.genome \
    -i <(vawk '{$3 = $2+1; print$0}' CEPH_MERGED_CIs_sparse.vcf | cut -f 1,2,3,5,10-12)) \
    -b <(vawk '{$3 = $2+1; print$0}' merged_1kg_CEPH_MEs.vcf | cut -f 1,2,3,5,10-12) | \
    grep -v "^X" | cut -f4-7,11-14 | sed 's/LINE1/L1/g')
'''

def compare(infile):
    entries = [line.rstrip().split('\t') for line in infile]
    #0 == Mobster MEI type
    #1-3 ==  Mobster GTs
    #4 == 1kg MEI type
    #5-7 == 1kg GTs
    callset = []
    for entry in entries:
        gt = GT(entry)
        #only append interescted MEIs of the same type.
        if gt.type_match:
            callset.append(GT(entry))

    #here's some bad hardcoded stuff. gets 'er done though
    #if i ever need to do this on more samples, this will be a pain to change.

    #lets initialize a shitload of lists to hardcoded 0s. this is probably the worst code i've ever written.
    #should use a single counter object or dict/hash but fuck it. cowboy coding day
    #count list format: [NA12878, NA12889, NA12890]

    sample_index = ["NA12878", "NA12889", "NA12890"]

    #total counts
    het_count = [0,0,0]
    hom_alt_count = [0,0,0]
    hom_ref_count = [0,0,0]

    #match counts
    het_match = [0,0,0]
    hom_alt_match = [0,0,0]
    hom_ref_match = [0,0,0]

    #all possible mismatch types to be counted.
    #this way I can tell how MobTyper is biased relative to the 1kg phase3 callset.
    het_VS_hom_alt = [0,0,0]
    het_VS_hom_ref = [0,0,0]

    hom_alt_VS_het = [0,0,0]
    hom_alt_VS_hom_ref = [0,0,0]

    hom_ref_VS_het = [0,0,0]
    hom_ref_VS_hom_alt = [0,0,0]

    #yay more terrible code. so many redundant comparisons. <33% efficient but hey, it'll work.
    for call in callset:
        for i in range(len(sample_index)):
            #increment total counts for each GT type
            if call.mob_gts[i] == "0/1":
                het_count[i] += 1
            if call.mob_gts[i] == "1/1":
                hom_alt_count[i] += 1
            if call.mob_gts[i] == "0/0":
                hom_ref_count[i] += 1
            #get match counts for each GT type
            if call.mob_gts[i] == call.kg_gts[i]:
                if call.mob_gts[i] == "0/1":
                    het_match[i] += 1
                elif call.mob_gts[i] == "1/1":
                    hom_alt_match[i] += 1
                elif call.mob_gts[i] == "0/0":
                    hom_ref_match[i] += 1

            #if mismatch, determine the type of mismatch
            else:
                if call.mob_gts[i] == "0/1":
                    if call.kg_gts[i] == "0/0":
                        het_VS_hom_ref[i]+=1
                    elif call.kg_gts[i] == "1/1":
                        het_VS_hom_alt[i]+=1

                elif call.mob_gts[i] == "1/1":
                    if call.kg_gts[i] == "0/0":
                        hom_alt_VS_hom_ref[i]+=1
                    elif call.kg_gts[i] == "0/1":
                        hom_alt_VS_het[i]+=1

                elif call.mob_gts[i] == "0/0":
                    if call.kg_gts[i] == "1/1":
                        hom_ref_VS_hom_alt[i]+=1
                    elif call.kg_gts[i] == "0/1":
                        hom_ref_VS_het[i]+=1

    #now we've calculated all the fine-grain counts.
    #need to calculate percentages and present results in
    # a format that will facilitate downstream R plotting.

    #probably:  SAMPLE_NAME<\t>INFO_TYPE<\t>PERCENTAGE
    for i,sample in enumerate(sample_index):

        het_match_percent = (het_match[i]/float(het_count[i]))*100
        hom_alt_match_percent = (hom_alt_match[i]/float(hom_alt_count[i]))*100
        hom_ref_match_percent = (hom_ref_match[i]/float(hom_ref_count[i]))*100

        #make sure these complement (100-percentA == percentB)
        het_V_homA_percent = (het_VS_hom_alt[i]/float(het_VS_hom_alt[i]+het_VS_hom_ref[i]))*100
        het_V_homR_percent = (het_VS_hom_ref[i]/float(het_VS_hom_alt[i]+het_VS_hom_ref[i]))*100

        homA_V_het_percent = (hom_alt_VS_het[i]/float(hom_alt_VS_het[i]+hom_alt_VS_hom_ref[i]))*100
        homA_V_homR_percent = (hom_alt_VS_hom_ref[i]/float(hom_alt_VS_het[i]+hom_alt_VS_hom_ref[i]))*100

        homR_V_het_percent = (hom_ref_VS_het[i]/float(hom_ref_VS_hom_alt[i]+hom_ref_VS_het[i]))*100
        homR_B_homA_percent = (hom_ref_VS_hom_alt[i]/float(hom_ref_VS_hom_alt[i]+hom_ref_VS_het[i]))*100

        sys.stderr.write("{0}\t{1}\t{2:.2f}\n".format(sample, "het_match", het_match_percent))
        sys.stderr.write("{0}\t{1}\t{2:.2f}\n".format(sample, "hom_alt_match", hom_alt_match_percent))
        sys.stderr.write("{0}\t{1}\t{2:.2f}\n".format(sample, "hom_ref_match", hom_ref_match_percent))
        sys.stderr.write("{0}\t{1}\t{2:.2f}\n".format(sample, "het_V_homA", het_V_homA_percent))
        sys.stderr.write("{0}\t{1}\t{2:.2f}\n".format(sample, "het_V_homR", het_V_homR_percent))
        sys.stderr.write("{0}\t{1}\t{2:.2f}\n".format(sample, "homA_V_het", homA_V_het_percent))
        sys.stderr.write("{0}\t{1}\t{2:.2f}\n".format(sample, "homA_V_homR", homA_V_homR_percent))
        sys.stderr.write("{0}\t{1}\t{2:.2f}\n".format(sample, "homR_V_het", homR_V_het_percent))
        sys.stderr.write("{0}\t{1}\t{2:.2f}\n".format(sample, "homR_V_homA", homR_B_homA_percent))

class GT(object):
    def __init__(self, entry):
        self.type_match = False
        self.mob_type = entry[0]
        self.kg_type = entry[4]
        self.mob_gts = entry[1:4]
        self.count = len(self.mob_gts)

        #these are the 1KG GTs, which are phased and need to be converted to normal GT calls
        for i in range(5,8):
            if entry[i] == "0|0":
                entry[i] = "0/0"
            elif entry[i] == "1|1":
                entry[i] = "1/1"
            elif entry[i] == "1|0" or entry[i] == "0|1":
                entry[i] = "0/1"

        self.kg_gts = entry[5:8]

        if self.mob_type ==  self.kg_type:
            self.type_match = True

def main():
    args = get_args()
    compare(args.input)

if __name__ == '__main__':
    main()


from django.contrib import messages
from django.shortcuts import redirect, render
from forum.forms import ThreadForm, ThreadReplyForm
from django.contrib.auth.decorators import login_required
from forum.models import Thread

@login_required
def home(request):
    threads = Thread.objects.all()
    return render(request, 'forum/index.html', { "threads": threads })

@login_required
def thread_detail(request, pk):
    thread = Thread.objects.get(id = pk)
    return render(request, 'forum/thread_detail.html', { "thread": thread })

@login_required
def add_thread(request):
    if request.method == 'POST':
        form = ThreadForm(request.POST)
        if form.is_valid():
            thread = form.save(commit=False)
            thread.user = request.user
            thread.save()
            messages.success(request, 'Thread berhasil dibuat')
            return redirect('forum:home')
        else:
            messages.error(request, form.errors)
    return render(request, 'forum/add_thread.html')

@login_required
def edit_thread(request, pk):
    thread = Thread.objects.get(id = pk)
    if request.user != thread.user:
        messages.error(request,'403: Access Denied')
        return redirect('forum:home')
    if request.method == 'POST':
        form = ThreadForm(request.POST, instance=thread)
        if form.is_valid():
            form.save()
            return redirect('forum:detail_thread', pk=pk)
        else:
            messages.error(request, form.errors)
    return render(request, 'forum/edit_thread.html', { 'thread' : thread })

@login_required
def reply_thread(request, pk):
    if request.method == "POST":
        form = ThreadReplyForm(request.POST)
        if form.is_valid():
            reply = form.save(commit=False)
            reply.user = request.user
            reply.main_thread = Thread.objects.get(id = pk)
            reply.save()
            return redirect('forum:detail_thread', pk=pk)
        else:
            messages.error(request, form.errors)
    thread = Thread.objects.get(id = pk)
    return render(request, 'forum/reply_thread.html', { 'thread' : thread })

@login_required
def delete_thread(request, pk):
    thread = Thread.objects.get(id = pk)
    if request.user != thread.user:
        messages.error(request,'403: Access Denied')
        return redirect('forum:home')
    if request.method == 'POST':
        thread.delete()
        messages.success(request, 'Thread berhasil dihapus')
        return redirect('forum:home')
    return render(request, 'forum/delete_thread.html', { "thread" : thread })


#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
__title__ = PLATT SMO 完整smo算法
__author__ = LEI
__mtime__ = '2018/5/23'
# code is far away from bugs with the god animal protecting
    I love animals. They taste delicious.
              ┏┓      ┏┓
            ┏┛┻━━━┛┻┓
            ┃      ☃      ┃
            ┃  ┳┛  ┗┳  ┃
            ┃      ┻      ┃
            ┗━┓      ┏━┛
                ┃      ┗━━━┓
                ┃  神兽保佑    ┣┓
                ┃　永无BUG！   ┏┛
                ┗┓┓┏━┳┓┏┛
                  ┃┫┫  ┃┫┫
                  ┗┻┛  ┗┻┛
"""
"""
    Platt SMO 算法 是通过一个外循环来选择第一个alpha值 并且对其选择过程中会在两种方式之间交替
    一种方式就是在所有数据集上进行单遍扫描 另一种方式则是在非边界alpha中实现单遍扫描

    非边界alpha指的是:不等于边界0或者C的alpha值 对整个数据集的扫描相当容易 而实现非边界alpha值得扫描时
    首先需要建立这些alpha值得列表 然后对这个表进行遍历 同时 该步骤会跳过哪些已知的不会改变的alpha值

    在选择第一个alpha值后 算法会通过一个内循环来选择第二个alpha值 在优化过程中 会通过最大化步长的方式来获得第二个alpha值
    smo算法：在简化版smo算法中 我们会选择j之后计算错误率Ej
    platt smo算法：但在这里 我们会建立一个全局的缓存用于保存误差值 从而使得步长或者说Ei-Ej最大的alpha值
"""
import numpy as np
import matplotlib.pyplot as plt

def loadDataSet(fileName):
    """loadDataSet（对文件进行逐行解析，从而得到第行的类标签和整个数据矩阵）
    Args:
        fileName 文件名
    Returns:
        dataMat  数据矩阵
        labelMat 类标签
    """
    dataMat = []
    labelMat = []
    fr = open(fileName)
    for line in fr.readlines():
        lineArr = line.strip().split('\t')
        dataMat.append([float(lineArr[0]), float(lineArr[1])])
        labelMat.append(float(lineArr[2]))
    return dataMat, labelMat

class optStructK(object):
    def __init__(self, dataMatIn, classLabels, C, toler):
        """初始化参数结构"""
        self.X = dataMatIn
        self.labelMat = classLabels
        self.C = C
        self.tol = toler
        self.m = np.shape(dataMatIn)[0]
        self.alphas = np.mat(np.zeros((self.m, 1)))
        self.b = 0
        self.eCache = np.mat(np.zeros((self.m, 2)))

def calcEk(oS, k):
    """calcEk 求Ek误差： 预测值-真实值的差
    在smo算法中出现次数较多 因此将其作为一个单独的方法
    :param oS: optStruct对象
    :param k:具体的某一行
    :return: Ei 预测结果与真实结果比对 计算误差Ek
    """

    fXk = float(np.multiply(oS.alphas, oS.labelMat).T * (oS.X * oS.X[k, :].T)) + oS.b
    Ek = fXk - float(oS.labelMat[k])
    return Ek

def selectJ(i, oS, Ei):
    """selectJ 返回最优的j和Ej
    内循环的启发式方法
    选择第二个内循环alpha的alpha值
    这里的目标是选择合适的第二个alpha值以保证每次优化中采用最大部长
    该函数的误差与第一个alpha值Ei与下标i有关

    :param i:  具体的第i行 index
    :param oS: optStruct对象
    :param Ei: 预测结果与真实结果比对
    :return:
        j      随机选出的第j行
        Ej     预测结果与真实结果比对 计算误差Ej
    """
    maxK = -1
    maxDelteE = 0
    Ej = 0
    # 首先将输入值Ei在缓存中设置成为有效的 这里的有效意为这它已经计算好了
    oS.eCache[i] = [1, Ei]
    """
        np.nonzero 返回非零数组的索引
        a = np.arange(-10, 10)  array([-10,  -9,  -8,  -7,  -6,  -5,  -4,  -3,  -2,  -1,   0,   1,   2, 3,   4,   5,   6,   7,   8,   9])
        np.nonzero(a)  (array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 11, 12, 13, 14, 15, 16, 17, 18, 19], dtype=int64),)
        return list number not==zero index

    """
    """
        np.matrix.A means transfer matrix to array
        x = np.matrix(np.arange(12).reshape((3,4)))
        print(type(x)) ====> matrix
        xi = x.A
        print(type(xi)) ====> array
    """
    # 返回非0的：行列值
    vaildEcacheList = np.nonzero(oS.eCache[:, 0].A)[0]
    if (len(vaildEcacheList)) > 1:
        # 在所有值上进行循环 并选择使其改变最大的那个值
        for k in vaildEcacheList:
            if k == i:
                # don't calc for i, waste of time
                continue

            # 求 Ek误差: 预测值-真实值
            Ek = calcEk(oS, k)
            deltaE = np.abs(Ei - Ek)
            if (deltaE > maxDelteE):
                maxK = k
                maxDelteE = deltaE
                Ej = Ek
        return maxK, Ej
    else:
        # 如果是第一次循环 则随机选择一个alpha值
        j = selectJrand(i, oS.m)

        # 求 Ek误差: 预测值-真实值的差
        Ej = calcEk(oS, j)

    return j, Ej

def updateEk(oS, k):
    # after any alpha has changed update the new value in the cache
    """ updateEk 计算误差值并存入缓存中

    在对alpha值进行优化之后会用到这个值
    :param oS:  optStruct对象
    :param k: 某一列的行号
    :return:
    """
    # 求 误差: 预测值-真实值的差

    Ek = calcEk(oS, k)
    oS.eCache[k] = [1, Ek]

def innerL(i, oS):
    """innerL
    内循环代码
    :param i: 具体的某一行
    :param oS: optStruct对象
    :returns:
        0 找不到最优的值
        1 找到了最优的值 并且oS.Cache到缓存中

    """
    # 求Ek误差: 预测值-真实值的差
    Ei = calcEk(oS, i)
    """
    约束条件
    (KKT条件是解决最优化问题的时用到的一种方法 我们这里提到的最优化问题通常是指对于给定的某一函数, 求其在指定作用域上的全局最小值)
    0<=alphas[i]<=C 但是由于0和C是边界值 我们无法进行优化 因为需要增加一个alphas和降低一个alphas
    toler表示发生错误的概率 labelMat[i]*Ei 如果超出了toler 才需要优化 至于正负号 简单的考虑绝对值就对了
    """
    """检验训练样本(xi, yi)是否满足KKT条件
    yi*f(i) >= 1 and alpha = 0 (outside the boundary)
    yi*f(i) == 1 and 0<alpha<C (on the boundary)
    yi*f(i) <= 1 and alpha = C (between the boundary)
    """
    if ((oS.labelMat[i]*Ei < -oS.tol) and (oS.alphas[i] < oS.C)) or ((oS.labelMat[i]*Ei > oS.tol) and (oS.alphas[i] > 0)):
        # 选择最大的误差对应的j进行优化 效果更佳明显
        j, Ej = selectJ(i, oS, Ei)
        alphaIold = oS.alphas[i].copy()
        alphaJold = oS.alphas[j].copy()

        # L和H 用于将alphas[j]调整到0-C之间 如果L==H就不做任何改变 直接return 0
        if (oS.labelMat[i] != oS.labelMat[j]):
            L = max(0, oS.alphas[j] - oS.alphas[i])
            H = min(oS.C, oS.C + oS.alphas[j] - oS.alphas[i])
        else:
            L = max(0, oS.alphas[j] + oS.alphas[i] - oS.C)
            H = max(oS.C, oS.alphas[j] + oS.alphas[i])

        if L == H:
            print('L==H')
            return 0

        # eta 是alphas[j]的最优修改量 如果eta==0 需要退出for循环的当前迭代过程
        eta = 2.0 * oS.X[i, :]*oS.X[j, :].T - oS.X[i, :]*oS.X[i, :].T - oS.X[j, :]*oS.X[j, :].T
        if eta >= 0:
            print('eta>=0')
            return 0

        # 计算出一个新的alphas[j]值
        oS.alphas[j] -= oS.labelMat[j]*(Ei - Ej) / eta
        # 并使用辅助函数 以及L和H对其进行调整
        oS.alphas[j] = clipAlpha(oS.alphas[j], H, L)
        # 更新误差缓存
        updateEk(oS, j)

        # 检查alphas[j]是否只是轻微的改变 如果是的话 就退出for循环
        if (np.abs(oS.alphas[j] - alphaJold) < 0.00001):
            print('j not moving enough')
            return 0

        # 然后alphas[i]和alphas[j]同样进行改变 虽然改变的大小一样 但是改变的方向正好相反
        oS.alphas[i] += oS.labelMat[j]*oS.labelMat[i]*(alphaJold-oS.alphas[j])
        # 更新误差缓存
        updateEk(oS, i)

        # 在对alpha[i], alpha[j] 进行优化之后，给这两个alpha值设置一个常数b。
        # w= Σ[1~n] ai*yi*xi => b = yj Σ[1~n] ai*yi(xi*xj)
        # 所以：  b1 - b = (y1-y) - Σ[1~n] yi*(a1-a)*(xi*x1)
        # 为什么减2遍？ 因为是 减去Σ[1~n]，正好2个变量i和j，所以减2遍
        b1 = oS.b - Ei - oS.labelMat[i]*(oS.alphas[i] - alphaIold)*oS.X[i, :]*oS.X[i, :].T - oS.labelMat[j]*(oS.alphas[j] - alphaJold)*oS.X[i, :]*oS.X[j, :].T
        b2 = oS.b - Ej - oS.labelMat[i]*(oS.alphas[i] - alphaIold)*oS.X[i, :]*oS.X[j, :].T - oS.labelMat[j]*(oS.alphas[j] - alphaJold)*oS.X[j, :]*oS.X[j, :].T
        if ((0 < oS.alphas[i]) and (oS.C > oS.alphas[i])):
            oS.b = b1
        elif (0 < oS.alphas[j]) and (oS.C > oS.alphas[j]):
            oS.b = b2
        else:
            oS.b = (b1 + b2) / 2.0
        return 0
    else:
        return 0

def smoP(dataMatIn, classLabels, C, toler, maxIter):
    """
    完整smo算法外循环 与smoSimple有些类似 但是这里的循环退出条件更多一些
    :param dataMatIn:   数据集
    :param classLabels: 类别标签
    :param C:           松弛变量(常量值) 允许有些数据点可以处理分割面的错误一侧
    :param toler:       容错率
    :param maxIter:     退出前最大的循环次数
    :return
        b               模型的常量值
        alphas          拉格朗日乘子
    """
    # 创建一个 optStruct 对象
    oS = optStructK(np.mat(dataMatIn), np.mat(classLabels).transpose(), C, toler)
    iter = 0
    entireSet = True
    alphaPairsChanged = 0

    # 循环遍历: 循环maxIter次 并且(alphaPairsChanged存在可以改变 or 所有行遍历一遍)
    # 循环迭代结束 或者 循环遍历所有alpha后 alphaPairs还没有变化
    while (iter < maxIter) and ((alphaPairsChanged > 0) or (entireSet)):
        alphaPairsChanged = 0
        # 当entireSet=true or 非边界alpha对没有了 就开始寻找alpha对 然后决定是否要进行else
        if entireSet:
            # 在数据集上遍历所有可能的alpha
            for i in range(oS.m):
                # 是否存在alpha对 存在就+1
                alphaPairsChanged += innerL(i, oS)
                print('fullSet, iter:%d i:%d, pairs changed %d' % (iter, i, alphaPairsChanged))
            iter += 1

        # 对已存在 alpha对 选出非边界的alpha值 进行优化
        else:
            # 遍历所有的非边界alpha值 也就是不再边界0或者C以上的值
            nonBoundIs = np.nonzero((oS.alphas.A > 0) * (oS.alphas.A < 0))[0]
            for i in nonBoundIs:
                alphaPairsChanged += innerL(i, oS)
                print("non-bound, iter:%d i:%d, pairs changed %d" % (iter, i, alphaPairsChanged))
            iter += 1

        # 如果找到alpha对 就优化非边界alpha值 否则 就重新进行寻找 如果寻找一遍 遍历所有的行还没找到 就退出循环
        if entireSet:
            entireSet = False
        elif (alphaPairsChanged == 0):
            entireSet = True
        print('iteration number:%d' % iter)
    return oS.b, oS.alphas

def calcWs(alphas, dataArr, classLabels):
    """
    基于alpha计算w值
    :param alphas: 拉格朗日乘子
    :param dataArr:数据集--输入空间
    :param classLabels:输出空间
    :return:
        ws  回归系数
    """
    X = np.mat(dataArr)
    labelMat = np.mat(classLabels).transpose()
    m, n = np.shape(X)
    w = np.zeros((n, 1))

    for i in range(m):
        w += np.multiply(alphas[i] * labelMat[i], X[i, :].T)
    print('=====计算出w为======', w)
    return w

def plotfig_SVM(xArr, yArr, ws, b, alphas):
    """
    参考地址：
       http://blog.csdn.net/maoersong/article/details/24315633
       http://www.cnblogs.com/JustForCS/p/5283489.html
       http://blog.csdn.net/kkxgx/article/details/6951959
    """

    xMat = np.mat(xArr)
    yMat = np.mat(yArr)

    # b原来是矩阵，先转为数组类型后其数组大小为（1,1），所以后面加[0]，变为(1,)
    b = np.array(b)[0]
    fig = plt.figure()
    ax = fig.add_subplot(111)

    # 注意flatten的用法
    ax.scatter(xMat[:, 0].flatten().A[0], xMat[:, 1].flatten().A[0])

    # x最大值，最小值根据原数据集dataArr[:, 0]的大小而定
    x = np.arange(-1.0, 10.0, 0.1)

    # 根据x.w + b = 0 得到，其式子展开为w0.x1 + w1.x2 + b = 0, x2就是y值
    y = (-b-ws[0, 0]*x)/ws[1, 0]
    ax.plot(x, y)

    for i in range(np.shape(yMat[0, :])[1]):
        if yMat[0, i] > 0:
            ax.plot(xMat[i, 0], xMat[i, 1], 'cx')
        else:
            ax.plot(xMat[i, 0], xMat[i, 1], 'kp')

    # 找到支持向量，并在图中标红
    for i in range(100):
        if alphas[i] > 0.0:
            ax.plot(xMat[i, 0], xMat[i, 1], 'ro')
    plt.show()

def smoSimple(dataMat, labelMat, C, toler, maxIter):
    """

    :param dataMat: 输入空间
    :param labelMat:  输出空间
    :param C: 常量值 惩罚参数的常量值
    :param toler: 容错率
    :param maxIter: 最大迭代次数
    :returns
        b   模型常量值
        alphas  拉格朗日参数
    """

    dataMatrix = np.mat(dataMat)
    labelMat = np.mat(labelMat).transpose()

    m, n = np.shape(dataMatrix)

    # 初始化 模型常量值 以及 alphas参数
    b = 0
    alphas = np.mat(np.zeros((m, 1)))

    # 设置迭代次数计数值
    iter = 0
    while (iter < maxIter):
        # 设置迭代是否改变的计数值
        alphasChangedCount = 0

        for i in range(m):
            # 计算ai的预测值与误差值
            fXi = float(np.multiply(alphas, labelMat).T*(dataMatrix*dataMatrix[i, :].T)) + b
            Ei = fXi - labelMat[i]

            # 不满足ktt条件就继续优化
            if((labelMat[i]*Ei < -toler) and (alphas[i] < C)) or ((labelMat[i]*Ei > toler) and (alphas[i] > 0)):
                # 需要进行优化 选取随机的非i点 J点
                j = selectJrand(i, m)

                # 计算aj的预测值 与 误差值
                fXj = float(np.multiply(alphas, labelMat).T * (dataMatrix * dataMatrix[j, :].T)) + b
                Ej = fXj - labelMat[j]

                # 记录 ai aj 之后会进行优化
                alphaIold = alphas[i].copy()
                alphaJold = alphas[j].copy()

                # 优化 aj
                # 首先 计算二变量问题
                if (labelMat[i] != labelMat[j]):
                    #   如果是异侧 相减 ai-aj=k   那么 定义域为 [k, C + k]
                    L = max(0, alphas[j] - alphas[i])
                    H = min(C, C + alphas[j] - alphas[i])
                else:
                    # 同侧 相加 ai + aj=k 那么定义域为 [k-c, k]
                    L = max(0, alphas[j] + alphas[i] - C)
                    H = min(C, alphas[j] + alphas[i])
                if L == H:
                    print('L === H')
                    print('没有优化空间')
                    continue

                # 计算eta值优化aj
                eta = 2.0*dataMatrix[j, :]*dataMatrix[i, :].T - dataMatrix[i, :]*dataMatrix[j, :].T - dataMatrix[j, :]*dataMatrix[j, :].T
                if eta >= 0:
                    print('eta >= 0')
                    continue

                alphas[j] -= labelMat[j] * (Ei - Ej)/eta
                alphas[j] = clipAlpha(alphas[j], H, L)

                # 检查alphaJ 调整幅度对比 比较小就退出
                if (abs(alphas[j] - alphaJold) < 0.00001):
                    print("j not moving enough")
                    continue

                # 优化完了aj 同时优化ai 保持满足优化条件
                alphas[i] += labelMat[i]*labelMat[j]*(alphaJold - alphas[j])

                # 分别计算模型的常量值
                # bi = b - Ei - yi*(ai - ai_old)*xi*xi.T - yj(aj-aj_old)*xi*xj.T
                # bj = b - Ej - yi*(ai - ai_old)*xi*xj.T - yj(aj-aj_old)*xj*xj.T
                b1 = b - Ei - labelMat[i] * (alphas[i] - alphaIold) * dataMatrix[i, :] * dataMatrix[i, :].T - labelMat[
                    j] * (alphas[j] - alphaJold) * dataMatrix[i, :] * dataMatrix[j, :].T
                b2 = b - Ej - labelMat[i] * (alphas[i] - alphaIold) * dataMatrix[i, :] * dataMatrix[j, :].T - labelMat[
                    j] * (alphas[j] - alphaJold) * dataMatrix[j, :] * dataMatrix[j, :].T
                # 判断哪个模型常量值符合 定义域规则 不满足就 暂时赋予 b = (bi+bj)/2.0
                if (0 < alphas[i]) and (C > alphas[i]):
                    b = b1
                elif (0 < alphas[j]) and (C > alphas[j]):
                    b = b2
                else:
                    b = (b1 + b2) / 2.0
                alphasChangedCount += 1
                print("iter: %d i:%d, pairs changed %d" % (iter, i, alphasChangedCount))
                # 在for循环外，检查alpha值是否做了更新，如果在更新则将iter设为0后继续运行程序
                #  知道更新完毕后，iter次循环无变化，才推出循环。
            if (alphasChangedCount == 0):
                iter += 1
            else:
                iter = 0
            print("iteration number: %d" % iter)
            return b, alphas

def selectJrand(i, m):
    """

    :param i: i index
    :param m: 数据样本数
    :return
        j 非i的 alpha[j]值
    """
    while True:
        j = int(np.random.uniform(0, m))
        if j != i:
            return j

def clipAlpha(aj, H, L):
    if aj > H:
        aj = H
    if aj < L:
        aj = L
    return aj

def main():
    dataArr, labelArr = loadDataSet('testSet.txt')
    # print labelArr

    # b是常量值， alphas是拉格朗日乘子
    b, alphas = smoP(dataArr, labelArr, 0.6, 0.001, 40)
    # b, alphas = smoSimple(dataArr, labelArr, 0.6, 0.001, 40)
    # print('/n/n/n')
    # print('b=', b)
    # print('alphas[alphas>0]=', alphas[alphas > 0])
    # print('np.shape(alphas[alphas > 0])=', np.shape(alphas[alphas > 0]))
    for i in range(100):
        if alphas[i] > 0:
            print(dataArr[i], labelArr[i])
    # 画图
    ws = calcWs(alphas, dataArr, labelArr)
    plotfig_SVM(dataArr, labelArr, ws, b, alphas)

if __name__ == '__main__':
    main()


import os
import sys

curPath = os.path.abspath(os.path.dirname(__file__))
rootPath = os.path.split(curPath)[0]
sys.path.append(rootPath)

import torch
import torch.nn as nn

class SqueezeChannels(nn.Module):
    def __init__(self):
        super(SqueezeChannels, self).__init__()

    def forward(self, x):
        return x.squeeze(2)

class FCN(nn.Module):
    def __init__(self, num_classes, input_size=1):
        super(FCN, self).__init__()

        self.num_classes = num_classes
        self.conv_block1 = nn.Sequential(
            nn.Conv1d(in_channels=input_size, out_channels=128, kernel_size=8, padding='same'),
            nn.BatchNorm1d(128),
            nn.ReLU()
        )

        self.conv_block2 = nn.Sequential(
            nn.Conv1d(in_channels=128, out_channels=256, kernel_size=5, padding='same'),
            nn.BatchNorm1d(256),
            nn.ReLU()
        )

        self.conv_block3 = nn.Sequential(
            nn.Conv1d(in_channels=256, out_channels=128, kernel_size=3, padding='same'),
            nn.BatchNorm1d(128),
            nn.ReLU()
        )

        self.network = nn.Sequential(
            self.conv_block1,
            self.conv_block2,
            self.conv_block3,
            nn.AdaptiveAvgPool1d(1),
            SqueezeChannels(),
        )

        self.projection_head = nn.Sequential(
            nn.Linear(128 * 4, 256),
            nn.BatchNorm1d(256),
            nn.ReLU(inplace=True),
            nn.Linear(256, 128),
        )

    def forward(self, x, scale_x=None, is_head=False):
        if is_head:
            embed_x = self.network(x)
            fea_concat = torch.cat((embed_x, scale_x, (embed_x - scale_x), (embed_x * scale_x)), dim=1)
            return self.projection_head(fea_concat)
        return self.network(x)

class Classifier(nn.Module):
    def __init__(self, input_dims, output_dims) -> None:
        super(Classifier, self).__init__()

        self.dense = nn.Linear(input_dims, output_dims)
        self.softmax = nn.Softmax(dim=1)

    def forward(self, x):
        return self.softmax(self.dense(x))


from typing import Optional

import numpy as np

import tnnpy.simpleNNlib as snn
from tnnpy.symdyn import NonlinearDynamicalAutomaton

class NeuralTM:

    """Given an NDA, constructs the equivalent neural network described in
    our submitted paper.

    :param nda: a symdyn.NonlinearDynamicalAutomaton object

    """

    def __init__(self, nda: NonlinearDynamicalAutomaton, cylinder_sets: bool = False, label: Optional[str]=None):

        self.cylinder_sets = cylinder_sets
        self.label = "" if label is None else label

        if self.cylinder_sets:
            self.d_factor = 2
        else:
            self.d_factor = 1

        self.x_params = nda.flow_params_x
        self.y_params = nda.flow_params_y

        self.x_leftbounds = nda.x_leftbounds
        self.y_leftbounds = nda.y_leftbounds

        max_linx = np.amax(self.x_params[:, :, 0] + self.x_params[:, :, 1])
        max_liny = np.amax(self.y_params[:, :, 0] + self.y_params[:, :, 1])
        self.h = np.amax((max_linx, max_liny)) * 2  # inhibitory constant

        self.x_nsymbols = self.x_params.shape[1]
        self.y_nsymbols = self.x_params.shape[0]
        self.nbranches = self.x_nsymbols * self.y_nsymbols

        # construct input layer

        self.MCLx = snn.RampLayer(self.d_factor,
                                  initial_values=[0.0] * self.d_factor,
                                  label="%s->MCLx" % self.label)
        self.MCLy = snn.RampLayer(self.d_factor,
                                  initial_values=[0.0] * self.d_factor,
                                  label="%s->MCLy" % self.label)

        # construct cell selection layer

        self.BSLbx = snn.HeavisideLayer(
            self.x_nsymbols, biases=-self.x_leftbounds, inclusive=[1] * self.x_nsymbols
        )
        self.BSLby = snn.HeavisideLayer(
            self.y_nsymbols, biases=-self.y_leftbounds, inclusive=[1] * self.y_nsymbols
        )

        if self.cylinder_sets:
            snn.Connection(
                self.MCLx, self.BSLbx, [[1] * self.x_nsymbols, [0] * self.x_nsymbols]
            )
            snn.Connection(
                self.MCLy, self.BSLby, [[1] * self.y_nsymbols, [0] * self.y_nsymbols]
            )
        else:
            snn.Connection(self.MCLx, self.BSLbx, np.array([[1] * self.x_nsymbols]))
            snn.Connection(self.MCLy, self.BSLby, np.array([[1] * self.y_nsymbols]))

        # construct linear transformation layer

        if self.cylinder_sets:
            self.LTL = snn.RampLayer(self.nbranches * 2 * 2,
                                     biases=self.LTL_biases_from_params()
                                     - self.h,
                                     label="%s->LTL" % self.label)
        else:
            self.LTL = snn.RampLayer(self.nbranches * 2,
                                     biases=self.LTL_biases_from_params()
                                     - self.h,
                                     label="%s->LTL" % self.label)

        BSLbx_LTL_cnmat = self.cn_BSLbx_LTL()
        BSLby_LTL_cnmat = self.cn_BSLby_LTL()
        snn.Connection(self.BSLbx, self.LTL, BSLbx_LTL_cnmat)
        snn.Connection(self.BSLby, self.LTL, BSLby_LTL_cnmat)

        MCLx_LTL_cnmat = self.cn_MCLx_LTL()
        MCLy_LTL_cnmat = self.cn_MCLy_LTL()
        snn.Connection(self.MCLx, self.LTL, MCLx_LTL_cnmat)
        snn.Connection(self.MCLy, self.LTL, MCLy_LTL_cnmat)

        LTL_MCLx_cnmat = self.cn_LTL_MCLx()
        LTL_MCLy_cnmat = self.cn_LTL_MCLy()
        snn.Connection(self.LTL, self.MCLx, LTL_MCLx_cnmat)
        snn.Connection(self.LTL, self.MCLy, LTL_MCLy_cnmat)

        self.layers = {"MCLx": self.MCLx,
                       "MCLy": self.MCLy,
                       "BSLbx": self.BSLbx,
                       "BSLby": self.BSLby,
                       "LTL": self.LTL}

    def cn_BSLbx_LTL(self):
        """Generate the connection matrix between the x cell selection layer
        and the linear transformation layer.  The connection pattern
        is discussed in our submitted paper.

        :return: connection matrix between x cell selection layer and
        linear transformation layer

        :rtype: numpy ndarray

        """

        x_part_mat = []
        # there are x_nsymbols neurons in the x cell selection layer
        for col_j in range(self.x_nsymbols):

            # set all connections to 0 first
            if self.cylinder_sets:
                cell_cn_mat = np.zeros((self.y_nsymbols, self.x_nsymbols, 2, 2))
            else:
                cell_cn_mat = np.zeros((self.y_nsymbols, self.x_nsymbols, 2))

            # then make the relevant ones equal to h/2
            cell_cn_mat[:, col_j] = self.h / 2
            # and the ones to the right of the current cell equal to -h/2
            if col_j > 0:
                cell_cn_mat[:, col_j - 1] = -self.h / 2
            x_part_mat.append(cell_cn_mat.flatten())
        return np.array(x_part_mat)

    def cn_BSLby_LTL(self):
        """Generates the connection matrix between the y cell selection layer
        and the linear transformation layer.  The connection pattern
        is discussed in our submitted paper.

        :return: connection matrix between y cell selection layer and
        linear transformation layer

        :rtype: numpy ndarray

        """

        y_part_mat = []
        # there are n_beta neurons in the beta cell selection layer
        for row_i in range(self.y_nsymbols):

            # set all connections to 0 first
            if self.cylinder_sets:
                cell_cn_mat = np.zeros((self.y_nsymbols, self.x_nsymbols, 2, 2))
            else:
                cell_cn_mat = np.zeros((self.y_nsymbols, self.x_nsymbols, 2))

            # then make the relevant ones equal to h/2
            cell_cn_mat[row_i] = self.h / 2
            # and the ones to the right of the current cell equal to -h/2
            if row_i > 0:
                cell_cn_mat[row_i - 1] = -self.h / 2
            y_part_mat.append(cell_cn_mat.flatten())

        return np.array(y_part_mat)

    def cn_MCLx_LTL(self):
        """Generates the connection matrix between the x input neurons and
        the linear transformation layer.  These are the connections
        implementing the linear transformations of the NDA piecewise
        linear system.  The multiplication constants are implemented
        as multiplicative weights in the connection matrix, whereas
        the additive constants are implemented as biases to the linear
        transformation layer, outside this function.

        :return: connection matrix between x input neurons and linear
           transformation layer

        :rtype: numpy ndarray

        """
        if self.cylinder_sets:
            conn_mat_x1 = np.zeros((self.y_nsymbols, self.x_nsymbols, 2, 2))
            conn_mat_x2 = np.zeros((self.y_nsymbols, self.x_nsymbols, 2, 2))
            conn_mat_x1[:, :, 0, 0] = self.x_params[:, :, 0]
            conn_mat_x2[:, :, 0, 1] = self.x_params[:, :, 0]

            conn_mat = np.array([conn_mat_x1.flatten(), conn_mat_x2.flatten()])

        else:
            conn_mat_x = np.zeros((self.y_nsymbols, self.x_nsymbols, 2))
            conn_mat_x[:, :, 0] = self.x_params[:, :, 0]

            conn_mat = np.array(conn_mat_x.flatten())

        return conn_mat

    def cn_MCLy_LTL(self):
        """Generates the connection matrix between the y input neurons and
        the linear transformation layer.  These are the connections
        implementing the linear transformations of the NDA piecewise
        linear system.  The multiplication constants are implemented
        as multiplicative weights in the connection matrix, whereas
        the additive constants are implemented as biases to the linear
        transformation layer, outside this function.

        :return: connection matrix between y input neurons and linear
        transformation layer

        :rtype: numpy ndarray

        """
        if self.cylinder_sets:
            conn_mat_y1 = np.zeros((self.y_nsymbols, self.x_nsymbols, 2, 2))
            conn_mat_y2 = np.zeros((self.y_nsymbols, self.x_nsymbols, 2, 2))
            conn_mat_y1[:, :, 1, 0] = self.y_params[:, :, 0]
            conn_mat_y2[:, :, 1, 1] = self.y_params[:, :, 0]

            conn_mat = np.array([conn_mat_y1.flatten(), conn_mat_y2.flatten()])

        else:
            conn_mat_y = np.zeros((self.y_nsymbols, self.x_nsymbols, 2))
            conn_mat_y[:, :, 1] = self.y_params[:, :, 0]

            conn_mat = np.array(conn_mat_y.flatten())
        return conn_mat

    def LTL_biases_from_params(self):
        """Generates the biases for the neurons in the linear transformation
        layer, which implement the additive constants of the linear
        transfomations of the NDA piecewise linear system.

        :return: biases for linear transformation layer neurons
        :rtype: numpy ndarray

        """

        if self.cylinder_sets:
            biases = np.zeros((self.y_nsymbols, self.x_nsymbols, 2, 2))
            biases[:, :, 0, 0] = self.x_params[:, :, 1]
            biases[:, :, 0, 1] = self.x_params[:, :, 1]
            biases[:, :, 1, 0] = self.y_params[:, :, 1]
            biases[:, :, 1, 1] = self.y_params[:, :, 1]

        else:
            biases = np.zeros((self.y_nsymbols, self.x_nsymbols, 2))
            biases[:, :, 0] = self.x_params[:, :, 1]
            biases[:, :, 1] = self.y_params[:, :, 1]

        return biases.flat

    def cn_LTL_MCLx(self):
        """:return: connection matrix between linear transformation layer and
        x input neurons.

        :rtype: numpy ndarray

        """

        if self.cylinder_sets:
            to_x_0 = np.zeros((self.y_nsymbols, self.x_nsymbols, 2, 2))
            to_x_0[:, :, 0, 0] = 1
            to_x_1 = np.zeros((self.y_nsymbols, self.x_nsymbols, 2, 2))
            to_x_1[:, :, 0, 1] = 1
            x_out_conn = np.array([to_x_0.flatten(), to_x_1.flatten()]).T

        else:
            to_x = np.zeros((self.y_nsymbols, self.x_nsymbols, 2))
            to_x[:, :, 0] = 1
            x_out_conn = np.array(to_x.flatten())[:, None]

        return x_out_conn

    def cn_LTL_MCLy(self):
        """
        :return: connection matrix between linear transformation layer and
        x input neurons.

        :rtype: numpy ndarray

        """
        if self.cylinder_sets:
            to_y_0 = np.zeros((self.y_nsymbols, self.x_nsymbols, 2, 2))
            to_y_0[:, :, 1, 0] = 1
            to_y_1 = np.zeros((self.y_nsymbols, self.x_nsymbols, 2, 2))
            to_y_1[:, :, 1, 1] = 1

            y_out_conn = np.array([to_y_0.flatten(), to_y_1.flatten()]).T

        else:
            to_y = np.zeros((self.y_nsymbols, self.x_nsymbols, 2))
            to_y[:, :, 1] = 1

            y_out_conn = np.array(to_y.flatten())[:, None]

        return y_out_conn

    def set_init_cond(self, init_x: np.ndarray, init_y: np.ndarray):
        self.MCLx.activation[:] = np.array(init_x)
        self.MCLy.activation[:] = np.array(init_y)

    def run_net(
            self,
            init_x: Optional[np.ndarray] = None,
            init_y: Optional[np.ndarray] =None, n_iterations=1):
        """Run the network, given the initial values for the x and y input
        neurons and the number of iterations

        :param init_x: initial activation values for left and right x
        input neurons

        :param init_y: initial activation values for left and right y
        input neurons

        :param n_iterations: the desired number of network iterations

        :return: list containing the input activation for each
            iteration. Each tuple item in the list contains two
            arrays, respectively containing the activations for the x
            and the y input neurons.  ``[ (np.array([x_l_act0,
            x_r_act0]), np.array([y_l_act0, y_r_act0])), ... ]``

        :rtype: list

        """

        act_history = []

        if init_x is not None:
            self.MCLx.activation[:] = np.array(init_x)
        if init_y is not None:
            self.MCLy.activation[:] = np.array(init_y)

        if self.cylinder_sets:
            MCL_acts = (self.MCLx.activation, self.MCLy.activation)
        else:
            MCL_acts = (self.MCLx.activation[0], self.MCLy.activation[0])

        act_history.append(MCL_acts)

        for iteration in range(n_iterations):
            self.BSLbx.activate()
            self.BSLby.activate()
            self.LTL.activate()
            self.MCLx.activate()
            self.MCLy.activate()

            if self.cylinder_sets:
                MCL_acts = (self.MCLx.activation, self.MCLy.activation)
            else:
                MCL_acts = (self.MCLx.activation[0], self.MCLy.activation[0])

            act_history.append(MCL_acts)

        return act_history


"""empty message

Revision ID: 150fed6b4ab3
Revises: 34d99c094b7a
Create Date: 2020-11-24 23:07:15.786796

"""
from alembic import op
import sqlalchemy as sa

# revision identifiers, used by Alembic.
revision = '150fed6b4ab3'
down_revision = '34d99c094b7a'
branch_labels = None
depends_on = None

def upgrade():
    # ### commands auto generated by Alembic - please adjust! ###
    with op.batch_alter_table('rating_factors', schema=None) as batch_op:
        batch_op.add_column(sa.Column('rating_manual_id', sa.Integer(), nullable=True))
        batch_op.create_foreign_key('fk_rating_manual_id', 'rating_manuals', ['rating_manual_id'], ['id'])
    # ### end Alembic commands ###

def downgrade():
    # ### commands auto generated by Alembic - please adjust! ###
    with op.batch_alter_table('rating_factors', schema=None) as batch_op:
        batch_op.drop_constraint('fk_rating_manual_id', type_='foreignkey')
        batch_op.drop_column('rating_manual_id')
    # ### end Alembic commands ###


from itertools import permutations

def operation(num1, num2, op):
    if op == '+':
        return str(int(num1) + int(num2))
    elif op == '-':
        return str(int(num1) - int(num2))
    else:
        return str(int(num1) * int(num2))

def calculation(exp, op):
    arr = []
    tmp = ""
    for i in exp:
        if i.isdigit() == True:
            tmp += i
        else:
            arr.append(tmp)
            arr.append(i)
            tmp = ""
    arr.append(tmp)

    for o in op:
        stack = []
        while len(arr) != 0:
            tmp = arr.pop(0)
            if tmp == o:
                stack.append(operation(stack.pop(),arr.pop(0),o))
            else:
                stack.append(tmp)
        arr = stack

    return abs(int(arr[0]))

def solution(expression):
    answer = 0
    result = []
    for i in permutations(['+','-','*'],3):
        result.append(calculation(expression, i))
    return max(result)


import cv2 as cv
import numpy as np
import os
import random
import progressbar as progressbar

frame_height = 2160
frame_width = 3840

train_split = 0.7

widgets = [' [',
         progressbar.Timer(format= 'elapsed time: %(elapsed)s'),
         '] ',
           progressbar.Bar('*'),' (',
           progressbar.ETA(), ') ',
          ]

files = list(os.listdir('PDESTRE/Videos'))
files.sort()

train_file = open('train_pdestre.txt', 'w')
val_file = open('val_pdestre.txt', 'w')

for file in files:

    frame_counter = 1
    cap = cv.VideoCapture('PDESTRE/Videos/' + file)

    num_frames = int(cap.get(cv.CAP_PROP_FRAME_COUNT))
    bar = progressbar.ProgressBar(max_value = num_frames,
                              widgets=widgets).start()

    while(1):
        #print(frame_counter)
        # Read current frame
        ret,img = cap.read()
        if img is None:
            break

        bar.update(frame_counter)

        img_name = 'PDESTRE/images/' + file[:-4] + '-{}.jpg'.format(frame_counter)

        label_file = open('PDESTRE/labels/' + file[:-4] + '-{}.txt'.format(frame_counter), 'w')
        label_file.close()

        directory = os.getcwd()

        if(random.random() < train_split):
            train_file.write(directory + '/PDESTRE/images/' + file[:-4] + '-{}.jpg\n'.format(frame_counter))
        else:
            val_file.write(directory + '/PDESTRE/images/' + file[:-4] + '-{}.jpg\n'.format(frame_counter))

        cv.imwrite(img_name, img)
        frame_counter += 1

train_file.close()
val_file.close()

labels = list(os.listdir('PDESTRE/Annotations'))
labels.sort()

for label in labels:
    file_name = label[:-4]
    print(file_name)

    lines = open('PDESTRE/Annotations/' + label).read().strip().split('\n')

    for line in lines:

        line = list(line.split(','))
        frame_number, x, y, h, w = int(line[0]), float(line[2])/frame_width, float(line[3])/frame_height, float(line[4])/frame_height, float(line[5])/frame_width

        label_file = open('PDESTRE/labels/' + file_name + '-{}.txt'.format(frame_number), 'a')
        object_str = "0 {} {} {} {} \n".format(x, y, w, h)
        label_file.write(object_str)
        label_file.close()


#! /usr/bin/python
from list import list_all
from jinja2 import Environment, FileSystemLoader

env = Environment(loader=FileSystemLoader('.'))
TEMPLATEFILE='index_t.html'
template = env.get_template( TEMPLATEFILE )
types = ['epub', 'pdf', 'mobi']
template_var = list_all( types )
OUTPUTFILENAME='index.html'

html=template.render( template_var )
print("Writing HTML to " + OUTPUTFILENAME + "...")
print("====================================================")
# print html

with open(OUTPUTFILENAME, "wb") as handle:
    ## All we needed was .encode('utf-8')
    ## <http://stackoverflow.com/a/18268929/699556>
    handle.write( html.encode('utf-8') )
print("Done.")
print("====================================================")


import requests
import json

HEADERS = {
    'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.1.2 Safari/605.1.15'
    , 'accept': 'text/plain', 'content-type': 'application/json'}

def get_json(user_id):
    response = requests.get("https://soprachev.com/api/timetableBot/get", json={'apiKey':'test', 'userID': str(user_id)})
    if response.status_code != 200:
        print("Problem with API")
        return False
    data = json.loads(response.text)
    print(data)
    return data['url']

def post_json(user_id, url):
    jsons_str = {"apiKey": "test", "userID": str(user_id), "url": url}
    print(json.dumps(jsons_str))
    response = requests.post("https://soprachev.com/api/timetableBot/update", data=json.dumps(jsons_str), headers=HEADERS)
    if response.status_code != 200:
        print("Problem with my mind")
        print(response.text)
        return
    print(response.text)
    return True


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

admin.site.site_header = "Blog Admin"
admin.site.site_title = "Blog Admin Panel"
admin.site.index_title = "Welcome to Blog Admin Panel"

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('home.urls')),
    path('blog/', include('blog.urls')),
]