#!/usr/bin/env python3
import sys
import os
import numpy as np

in_fp = sys.argv[1]
align_fp = sys.argv[2]

# function to get overlap in intervals
# https://stackoverflow.com/questions/2953967/built-in-function-for-computing-overlap-in-python
def getOverlap(a, b):
    return max(0, min(a[1], b[1]) - max(a[0], b[0]))
def annotate_read(paf_list) :
    # making a list of lists
    # each row will have : qname, qlen, qstart, qend, rname, rstart, rend, direction
    anno_list = []
    qlen = int(paf_list[0][1])
    qname = paf_list[0][0]
    for paf in paf_list :
        qstart = int(paf[2])
        qend = int(paf[3])
        direction = paf[4]
        rname = paf[5]
        rstart = int(paf[7])
        rend = int(paf[8])
        anno_list.append([qname,qlen,qstart,qend,rname,rstart,rend,direction])
    return anno_list

# first parsing plasmid alignments
rlen_dict = dict()
reads_dict = dict()
hits_dict = dict()
paf_dict = dict()
# get coordinates and query matches
# let's also record subject hits
with open(in_fp,"r") as fh :
    for line in fh :
        fields = line.strip().split("\t")
        qname = fields[0]
        # add the raw data to paf_dict
        if qname not in paf_dict.keys() :
            paf_dict[qname] = []
        paf_dict[qname].append(fields)
        # get query coords and add to reads_dict
        query_coord = [ int(fields[2]), int(fields[3]) ]
        if qname not in reads_dict.keys() :
            reads_dict[qname] = []
        reads_dict[qname].append(query_coord)
        rlen_dict[qname] = int(fields[1])
        # subject hits
        subject_coord = [ int(fields[7]),int(fields[8]) ]
        if qname not in hits_dict.keys() :
            hits_dict[qname] = []
        hits_dict[qname].append(subject_coord)
# let's get total width of alignments
matchlen_dict = dict()
for key in reads_dict.keys() :
    query_coords = reads_dict[key]
    pos_list = [list(range(x[0],x[1])) for x in query_coords]
    pos = set([ x for y in pos_list for x in y ])
    matchlen_dict[key] = len(pos)

# maximum of the total match in host cells is ~1.4kb
# so let's require at least 2kb total match to consider a real hit
qnames_hit = [ key for key in matchlen_dict.keys() if matchlen_dict[key] > 2e3 ]
if len(qnames_hit) == 0 :
    print("No reads with valid hits", file = sys.stderr)
    sys.exit()
else :
    print("{} reads with valid hits".format(len(qnames_hit)),file = sys.stderr)

###########################################
# Start parsing valid hits
###########################################
# get min start and max end
minmax_dict = dict()
for key in qnames_hit :
    coords = reads_dict[key]
    minstart = min([x[0] for x in coords ])
    maxend = max([x[1] for x in coords ])
    minmax_dict[key] = [minstart,maxend]
    al_list = annotate_read(paf_dict[key])
    for al in al_list :
        print("\t".join([str(x) for x in al]))

###########################################
# Flanking reads
###########################################
# parse flanking - how much of non-plasmid sequence on each side of the query?
# we also don't want reads that are solely on plasmid
thr = 1e3
# each list will have [ left flanking bps, right flanking bps, length match ]
flank_dict = dict()
for key in minmax_dict.keys() :
    left = minmax_dict[key][0]
    end = minmax_dict[key][1]
    rlen = rlen_dict[key]
    right = rlen - end
    matchlen = matchlen_dict[key]
    if left < thr and right < thr :
        continue
    # if both sides are flanking, then unless at least one whole plasmid is in the match, this is error
    if left > thr and right > thr and matchlen < 10e3 :
        continue
    flank_dict[key] = [left,right, matchlen]
qnames = flank_dict.keys()

if len(qnames) == 0 :
    print("No flanking reads", file = sys.stderr)
    sys.exit()
else :
    print("{} flanking reads".format(len(qnames)), file = sys.stderr)

###########################################
# Parse flanking reads
###########################################
flankcoord_dict = { x:[] for x in flank_dict.keys() }
for key in flank_dict.keys() :
    rlen = rlen_dict[key]
    left = flank_dict[key][0]
    right = flank_dict[key][1]
    if left > thr :
        coord = [0,left]
        flankcoord_dict[key].append(coord)
    if right > thr :
        coord = [rlen - right,rlen]
        flankcoord_dict[key].append(coord)

# let's read in the reference alignment paf
ref_dict = dict()
with open(align_fp,"r") as fh :
    for line in fh :
        fields = line.strip().split("\t")
        qname = fields[0]
        if qname in flank_dict.keys() :
            qstart = int(fields[2])
            qend = int(fields[3])
            contig = fields[5]
            rstart = int(fields[7])
            rend = int(fields[8])
            if qname not in ref_dict.keys() :
                ref_dict[qname] = []
            ref_dict[qname].append([qstart,qend,fields[5],fields[4],rstart,rend])

# get reference coordinates
for key in ref_dict.keys() :
    flanks = flankcoord_dict[key]
    for align in ref_dict[key]:
        qcoords = [align[0],align[1]]
        for flank in flanks :
            if getOverlap(qcoords,flank) > 0 :
                print("\t".join([key] +[str(x) for x in align]),file = sys.stderr)


import argparse

def gumarum(a,b):
    c = a+b
    return c

def Main():
    parser = argparse.ArgumentParser()
    group = parser.add_mutually_exclusive_group()
    group.add_argument("-v","--verbose",action="store_true")
    group.add_argument("-q","--quiet",action="store_true")
    parser.add_argument("num",help="the fibonacci number you wish to calculate.",type=int)
    parser.add_argument("num1",help="the fibonacci number you wish to calculate.",type=int)
    parser.add_argument("-o","--output",help="output result to a file",action="store_true")
    args = parser.parse_args()
    result = gumarum(args.num,args.num1)
    if args.verbose:
        print("The " +str(args.num)+" + "+str(args.num1)+" = "+str(result))
    elif args.quiet:
        print(result)
    else:
        print("fib("+str(args.num)+") = "+str(result))

if __name__=="__main__":
    Main()


import write_tool
#python 3

def write_class( filepath, filename ):

    write_tool.write_top_file( filepath, filename, "cc" )
    fileclass = open(filepath+filename+".cc", 'a')
    fileclass.write( "%s::%s(){\n}\n\n" % (filename,filename) )
    fileclass.write( "%s::~%s(){\n}\n\n" % (filename,filename) )
    fileclass.close()

def write_header( filepath, filename ):

    write_tool.write_top_file( filepath, filename, "hh" )
    fileclass = open(filepath+filename+".hh", 'a')
    fileclass.write( "class %s\n{\n\n \tpublic:\n\n" % filename )
    fileclass.write( "\t\t//! Default Constructor\n" )
    fileclass.write( "\t\t%s();\n\n" % filename )
    fileclass.write( "\t\t//! Destructor\n" )
    fileclass.write( "\t\tvirtual ~%s();\n\n" % filename )
    fileclass.write( "\tpublic:\n\n" )
    fileclass.write( "\t\t// Write members here\n\n" )
    fileclass.write( "};\n\n" )
    fileclass.write( "#endif\n" )
    fileclass.close()

def write_rootclass( filepath, filename ):

    write_tool.write_top_file( filepath, filename, "cc" )
    fileclass = open(filepath+filename+".cc", 'a')
    write_tool.write_function_comment( fileclass, "Constructor" )
    fileclass.write( "%s::%s( TTree *tree )\n{\n" % (filename,filename) )
    fileclass.write( "\tmTree = tree;\n\n" )
    fileclass.write( "\tmTree->SetBranchAddress(\" \", , );\n\n" )
    fileclass.write( "\tmNevents = mTree->GetEntries();\n}\n\n" )
    write_tool.write_function_comment( fileclass, "Destructor" )
    fileclass.write( "%s::~%s()\n{\n\tdelete mTree->GetCurrentFile();\n}\n\n" % (filename,filename) )
    write_tool.write_function_comment( fileclass, "GetEntry" )
    fileclass.write( "Int_t %s::GetEntry( Long64_t entry )\n{\n" % filename )
    fileclass.write( "\treturn mTree->GetEntry( entry );\n}\n\n" )
    fileclass.write( "#endif")
    fileclass.close()

def write_rootheader( filepath, filename ):

    write_tool.write_top_file( filepath, filename, "hh" )
    fileclass = open(filepath+filename+".hh", 'a')
    fileclass.write( "class %s\n{\n\n \tpublic:\n\n" % filename )
    fileclass.write( "\t\t//! Default Constructor\n" )
    fileclass.write( "\t\t%s( TTree *tree );\n\n" % filename )
    fileclass.write( "\t\t//! Destructor\n" )
    fileclass.write( "\t\tvirtual ~%s();\n\n" % filename )
    fileclass.write( "\tpublic:\n\n" )
    fileclass.write( "\t\tTTree\t\t\t*mTree;\n" )
    fileclass.write( "\t\tLong64_t\t\tmNevents;\n\n" )
    fileclass.write( "\t\t// Declaration of leaf types\n\n" )
    fileclass.write( "\t\t// List of branches\n\n" )
    fileclass.write( "\t\tInt_t GetEntry( Long64_t entry );\n" )
    fileclass.write( "\t\tinline Long64_t GetEntries(){ return mNevents; };\n" )
    fileclass.write( "};\n\n" )
    fileclass.write( "#endif\n" )
    fileclass.close()

def write_histos( filepath, classname, filename ):

    write_tool.write_top_file( filepath, filename+"Histos", "cc" )
    filehistos = open( filepath+filename+"Histos.cc", "a" )
    filehistos.write("#include \"%s.hh\"\n\n" % classname )
    write_tool.write_mainfunction_comment( filehistos, "%sHistos" % filename )
    filehistos.write( "int %sHistos( TString dirin, TString dirout )\n{\n" % filename )
    filehistos.write( "\t// Create file to store histograms\n" )
    filehistos.write( "\tTFile *rootfile = new TFile( dirout+\"rootfiles/out_name.root\",\"RECREATE\");\n" )
    filehistos.write( "\tTH1F *htest = Utils1::bookTH1F( \"htest\", \"title;xtitle;ytitle;units\", nbins, xmin, xmax, true);\n\n" )
    filehistos.write( "\t// TChain to retrieve data\n" )
    filehistos.write( "\tTChain *c%s = new TChain(\"tree_name\");\n" % classname.lower() )
    filehistos.write( "\tc%s->Add(dirin+\"/file_name\");\n" % classname.lower() )
    filehistos.write( "\t%s *%s = new %s( c%s );\n" % (classname, classname.lower(), classname, classname.lower()) )
    filehistos.write( "\tLong64_t nevents = %s->GetEntries();\n\n" % classname.lower() )
    filehistos.write( "\t// Loop\n" )
    filehistos.write( "\tfor ( Int_t index = 0; index < nevents; index++)\n\t{\n" )
    filehistos.write( "\t\t%s->GetEntry(index);\n\n\t}\n\n" % classname.lower() )
    filehistos.write( "\trootfile->Write();\n")
    filehistos.write( "\trootfile->Close();\n\n")
    filehistos.write( "\treturn 0;\n\n}\n\n")
    filehistos.close()
    write_tool.write_help( filepath, filename+"Histos" )
    write_tool.write_main( filepath, filename+"Histos" )

def write_plots( filepath, classname, filename ):

    write_tool.write_top_file( filepath, filename+"Plots", "cc" )
    filehistos = open( filepath+filename+"Plots.cc", "a" )
    filehistos.write("#include <Plot1.hh>\n" )
    filehistos.write("#include <Utils1.hh>\n\n" )
    write_tool.write_mainfunction_comment( filehistos, "%sPlots" % filename )
    filehistos.write( "int %sPlots( TString dirin, TString dirout )\n{\n" % filename )
    filehistos.write( "\t// Create file to store histograms\n" )
    filehistos.write( "\tTFile *rootfile = new TFile( dirin+\"rootfiles/out_name.root\");\n" )
    filehistos.write( "\tTH1F *htest = Utils1::getTH1F( rootfile, \"htest\");\n\n" )
    filehistos.write( "\tTCanvas *c1 = NULL;\n" );
    filehistos.write( "\tc1 = Plot1::getCanvas(\"c1\",\"c1\");\n" )
    filehistos.write( "\thtest->Draw();\n" );
    filehistos.write( "\tUtils1::MyPrint(c1, dirout, \"Basic\", \"example\");\n" )
    filehistos.write( "\treturn 0;\n\n}\n\n" )
    filehistos.close()
    write_tool.write_help( filepath, filename+"Plots" )
    write_tool.write_main( filepath, filename+"Plots" )

def write_makefile( path, dirname, classname  ):

    filem = open( path+"/"+dirname+"/Makefile", "w" )
    filem.write("all:\n")
    filem.write("\tmake -C src\n")
    filem.write("\tmake -C make_histos\n")
    filem.write("\tmake -C make_plots\n\n")
    filem.write("clean:\n")
    filem.write("\tmake -C src clean\n")
    filem.write("\tmake -C make_histos clean\n")
    filem.write("\tmake -C make_plots clean\n")
    filem.close()

    filesrcm = open( path+"/"+dirname+"/src/Makefile", "w" )
    filesrcm.write( "CXX = g++\n" )
    filesrcm.write( "CXXFLAGS = -c -g -Wall -fPIC `root-config --cflags`\n")
    filesrcm.write( "ROOTLDFLAGS =  `root-config --glibs`\n" )
    filesrcm.write( "INCLUDE += -I$(JOYROOTROOT)/include -I$(%sROOT)/include\n" % dirname.upper() )
    filesrcm.write( "LDLIBS += -L$(JOYROOTROOT)/lib -lJOYROOT\n\n")
    filesrcm.write( "OBJS = %s.o\n" % classname )
    filesrcm.write( "all: $(OBJS)\n\n" )
    filesrcm.write( "%.o: %.cc\n" )
    filesrcm.write( "\t $(CXX) $(CXXFLAGS) $(INCLUDE) $< -o $@\n\n")
    filesrcm.write( "clean:\n\t rm -f $(OBJS)" )
    filesrcm.close()

    filehism = open( path+"/"+dirname+"/make_histos/Makefile", "w" )
    filehism.write( "CXX = g++\n" )
    filehism.write( "CXXFLAGS = -c -g -Wall -fPIC `root-config --cflags`\n")
    filehism.write( "ROOTLDFLAGS =  `root-config --glibs`\n" )
    filehism.write( "INCLUDE += -I$(JOYROOTROOT)/include -I$(%sROOT)/include\n" % dirname.upper() )
    filehism.write( "LDLIBS += -L$(JOYROOTROOT)/lib -lJOYROOT\n\n")
    filehism.write( "OBJS = $(%sROOT)/src/%s.o\n" % (dirname.upper(),classname) )
    filehism.write( "TARGETS = BasicHistos.o\n" )
    filehism.write( "BINARIES = $(TARGETS:.o=)\n\n")
    filehism.write( "all: $(TARGETS) $(BINARIES)\n\n" )
    filehism.write( "%: %.o\n" )
    filehism.write( "\t$(CXX) $(ROOTLDFLAGS) $(INCLUDE) $(LDLIBS) $(OBJS) $< -o $@\n\n")
    filehism.write( "%.o: %.cc\n" )
    filehism.write( "\t $(CXX) $(CXXFLAGS) $(INCLUDE) $< -o $@\n\n")
    filehism.write( "clean:\n\t rm -f $(BINARIES) $(TARGETS)" )
    filehism.close()

    fileplom = open( path+"/"+dirname+"/make_plots/Makefile", "w" )
    fileplom.write( "CXX = g++\n" )
    fileplom.write( "CXXFLAGS = -c -g -Wall -fPIC `root-config --cflags`\n")
    fileplom.write( "ROOTLDFLAGS =  `root-config --glibs`\n" )
    fileplom.write( "INCLUDE += -I$(JOYROOTROOT)/include -I$(%sROOT)/include\n" % dirname.upper() )
    fileplom.write( "LDLIBS += -L$(JOYROOTROOT)/lib -lJOYROOT\n\n")
    fileplom.write( "OBJS = $(%sROOT)/src/%s.o\n" % (dirname.upper(),classname) )
    fileplom.write( "TARGETS = BasicPlots.o\n" )
    fileplom.write( "BINARIES = $(TARGETS:.o=)\n\n")
    fileplom.write( "all: $(TARGETS) $(BINARIES)\n\n" )
    fileplom.write( "%: %.o\n" )
    fileplom.write( "\t$(CXX) $(ROOTLDFLAGS) $(INCLUDE) $(LDLIBS) $(OBJS) $< -o $@\n\n")
    fileplom.write( "%.o: %.cc\n" )
    fileplom.write( "\t $(CXX) $(CXXFLAGS) $(INCLUDE) $< -o $@\n\n")
    fileplom.write( "clean:\n\t rm -f $(BINARIES) $(TARGETS)" )
    fileplom.close()

def write_makefile2( path, dirname ):

    filem = open( path+"/"+dirname+"/Makefile", "w" )
    filem.write("all:\n")
    filem.write("\tmake -C make_plots\n\n")
    filem.write("clean:\n")
    filem.write("\tmake -C make_plots clean\n")
    filem.close()

    fileplom = open( path+"/"+dirname+"/make_plots/Makefile", "w" )
    fileplom.write( "CXX = g++\n" )
    fileplom.write( "CXXFLAGS = -c -g -Wall -fPIC `root-config --cflags`\n")
    fileplom.write( "ROOTLDFLAGS =  `root-config --glibs`\n" )
    fileplom.write( "INCLUDE += -I$(JOYROOTROOT)/include -I$(%sROOT)/include\n" % dirname.upper() )
    fileplom.write( "LDLIBS += -L$(JOYROOTROOT)/lib -lJOYROOT\n\n")
    fileplom.write( "TARGETS = BasicPlots.o\n" )
    fileplom.write( "BINARIES = $(TARGETS:.o=)\n\n")
    fileplom.write( "all: $(TARGETS) $(BINARIES)\n\n" )
    fileplom.write( "%: %.o\n" )
    fileplom.write( "\t$(CXX) $(ROOTLDFLAGS) $(INCLUDE) $(LDLIBS) $< -o $@\n\n")
    fileplom.write( "%.o: %.cc\n" )
    fileplom.write( "\t $(CXX) $(CXXFLAGS) $(INCLUDE) $< -o $@\n\n")
    fileplom.write( "clean:\n\t rm -f $(BINARIES) $(TARGETS)" )
    fileplom.close()

def write_setup( joypath, path, dirname ):
    fileset = open( path+"/"+dirname+"/setup.sh", "w" )
    fileset.write( "#!/bin/bash\n\n" )
    fileset.write( "source %s/setup.sh\n\n" % joypath )
    fileset.write( "export %sROOT=%s/%s" % (dirname.upper(), path, dirname) )
    fileset.close()


from flask import Flask
from flask_bootstrap import Bootstrap
import os

app = Flask(__name__)
Bootstrap(app)

try:
    app.config.from_object('config')
except:
    app.config.update(
        SECRET_KEY = 'secret_key',
        DBHOST = 'localhost',
        DBUSER = 'pricosha',
        DBPASS = 'cs3083',
        DBNAME = 'pricosha',
        PHOTO_DIRECTORY = os.path.join(os.getcwd(), 'app', 'photos')
    )

if not 'PHOTO_DIRECTORY' in app.config:
    app.config.update(
        PHOTO_DIRECTORY = os.path.join(os.getcwd(), 'app', 'photos')
    )

app.jinja_env.auto_reload = True

from datetime import datetime

def time_ago(time=False):
    """
    Get a datetime object or a int() Epoch timestamp and return a
    pretty string like 'an hour ago', 'Yesterday', '3 months ago',
    'just now', etc
    """
    now = datetime.now()
    if type(time) is int:
        diff = now - datetime.fromtimestamp(time)
    elif isinstance(time,datetime):
        diff = now - time
    elif not time:
        diff = now - now
    second_diff = diff.seconds
    day_diff = diff.days

    if day_diff < 0:
        return ''

    if day_diff == 0:
        if second_diff < 5:
            return "just now"
        if second_diff < 60:
            return str(second_diff) + " seconds ago"
        if second_diff < 120:
            return "a minute ago"
        if second_diff < 3600:
            return str(second_diff // 60) + " minutes ago"
        if second_diff < 7200:
            return "an hour ago"
        if second_diff < 86400:
            return str(second_diff // 3600) + " hours ago"
    if day_diff == 1:
        return "yesterday"
    if day_diff < 7:
        return str(day_diff) + " days ago"
    if day_diff < 14:
        return "a week ago"
    if day_diff < 31:
        return str(day_diff // 7) + " weeks ago"
    if day_diff < 62:
        return "a month ago"
    if day_diff < 365:
        return str(day_diff // 30) + " months ago"
    if day_diff < 730:
        return "a year ago"
    return str(day_diff // 365) + " years ago"

app.jinja_env.filters['time_ago'] = time_ago

from app import views


# -*- coding: utf-8 -*-
from util import *

class F1_Calculator() :

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

    def clear(self) :
        self.counter = {
            'num_true_positive'       : 0,
            'num_true_negative'       : 0,
            'num_false_positive'      : 0,
            'num_false_negative'      : 0,
            'num_prediction_positive' : 0,
            'num_truth_positive'      : 0,
        }

    def add_sample(self, prediction, truth) :
        if prediction == truth and prediction == 1 :
            self.counter['num_true_positive'] += 1
        if prediction == truth and prediction == 0 :
            self.counter['num_true_negative'] += 1
        if prediction != truth and prediction == 1 :
            self.counter['num_false_positive'] += 1
        if prediction != truth and prediction == 0 :
            self.counter['num_false_negative'] += 1
        if prediction == 1 :
            self.counter['num_prediction_positive'] += 1
        if truth == 1 :
            self.counter['num_truth_positive'] += 1

    def calc_precision(self) :
        return 1.0 * self.counter['num_true_positive'] / self.counter['num_prediction_positive']

    def calc_recall(self) :
        return 1.0 * self.counter['num_true_positive'] / self.counter['num_truth_positive']

    def calc_f1(self) :
        precision = self.calc_precision()
        recall    = self.calc_recall()
        return 2.0 * precision * recall / (precision + recall)

    def __str__(self) :
        format = 'true_positive : %(num_true_positive)d\tprediction_positive : %(num_prediction_positive)d\ttruth_positive : %(num_truth_positive)d\n'
        format += 'precision : %(precision).4f\trecall : %(recall).4f\tF1 : %(f1).4f'
        data = self.counter
        data.update({
            'precision' : self.calc_precision(),
            'recall'    : self.calc_recall(),
            'f1'        : self.calc_f1(),
        })
        return format % data


""" Controller for AI Move"""

from collections import namedtuple
from Back import ComputerAI
from Back.Tree import Tree
from Back.Tree import Node

MovingLetter = namedtuple('MovingLetter', 'letter, position')

class AIController:
    """ Controller for AI Turn """

    def __init__(self, board, player, letter_set):
        self.computer_ai = ComputerAI.ComputerAI(player, letter_set)
        self.board = board
        self.places_on_board = list()

    @staticmethod
    def check_tuple(pair):
        """
        :param pair: tuple to check if contain zero
        :return: true if contains zero
        """
        for i in pair:
            if i == 0:
                return True

        return False

    @staticmethod
    def check_range(position):
        """
        :param position: position to check if isn't  out of range
        :return: False if is out of range
        """
        x_coor = position[0]
        y_coor = position[1]

        return (-1 <= x_coor <= 15) and (-1 <= y_coor <= 15)

    def find_empty_spaces_on_board(self):
        """
        find letter on BOARD where Ai can put the word
        """
        self.places_on_board = list()
        for row in range(15):
            for column in range(15):
                field = self.board.get_letter_from_position((row, column))

                if field is not None:
                    letter = MovingLetter(letter=field, position=(row, column))
                    row_range = self.row_space((row, column))
                    column_range = self.column_space((row, column))

                    if self.check_tuple(row_range):
                        row_range = [0, 0]

                    if self.check_tuple(column_range):
                        column_range = [0, 0]

                    if row_range == column_range == [0, 0]:
                        continue

                    self.places_on_board.append([letter, column_range, row_range])

    def row_space(self, pos):
        """
        :param pos: start position with letter to look for empty spaces around it in row
        :return: tuple: [empty fields on the left, empty fields on the right]
        """

        left_space = 0
        right_space = 0

        x_coor = pos[0]
        y_coor = pos[1]

        left_pos = x_coor - left_space - 1

        while 0 <= left_pos <= 14:
            if self.board.get_letter_from_position((left_pos, y_coor)) is None:
                if self.board.get_letter_from_position(
                        (left_pos, y_coor + 1)) is not None or self.board.get_letter_from_position(
                    (left_pos, y_coor - 1)) is not None:
                    break
                else:
                    left_space += 1
            elif left_space == 0:
                break
            else:
                left_space -= 1
                break

            left_pos = x_coor - left_space - 1

        right_pos = x_coor + right_space + 1

        while 0 <= right_pos <= 14:
            if self.board.get_letter_from_position((right_pos, y_coor)) is None:
                if self.board.get_letter_from_position(
                        (right_pos, y_coor + 1)) is not None or self.board.get_letter_from_position(
                    (right_pos, y_coor - 1)) is not None:
                    break
                else:
                    right_space += 1
            elif right_space == 0:
                break
            else:
                right_space -= 1
                break

            right_pos = x_coor + right_space + 1

        return [left_space, right_space]

    def column_space(self, pos):
        """
        :param pos: start position with letter to look for empty spaces around it in row
        :return: tuple: [empty fields on the left, empty fields on the right]
        """

        top_space = 0
        down_space = 0

        x_coor = pos[0]
        y_coor = pos[1]

        top_pos = y_coor - top_space - 1
        down_pos = y_coor + down_space + 1

        while 0 <= top_pos <= 14:
            if self.board.get_letter_from_position((x_coor, top_pos)) is None:
                if self.board.get_letter_from_position(
                        (x_coor + 1, top_pos)) is not None or self.board.get_letter_from_position(
                    (x_coor - 1, top_pos)) is not None:
                    break
                else:
                    top_space += 1
            elif top_space == 0:
                break
            else:
                top_space -= 1
                break

            top_pos = y_coor - top_space - 1

        while 0 <= down_pos <= 14:
            if self.board.get_letter_from_position((x_coor, down_pos)) is None:
                if self.board.get_letter_from_position(
                        (x_coor + 1, down_pos)) is not None or self.board.get_letter_from_position(
                    (x_coor - 1, down_pos)) is not None:
                    break
                else:
                    down_space += 1
            elif down_space == 0:
                break
            else:
                down_space -= 1
                break

            down_pos = y_coor + down_space + 1

        return [top_space, down_space]

    def check_if_blank(self):
        """
        :return: true if blank is in COMPUTER' holder, false otherwise
        """
        return '?' in self.computer_ai.player.holder

    def create_moving_word(self, word, direction, pos):
        """
        :param word: list of splited by letter from BOARD word's part
        :param direction: row or column
        :param pos: letter from BOARD position
        :return: list with MovingLetter word
        """
        prefix = word[0]
        suffix = word[2]

        moving_word = list()

        prefix_pos = suffix_pos = [pos[0], pos[1]]

        if direction == 'r':
            prefix_adder = [0, -1]
            suffix_adder = [0, 1]

        elif direction == 'c':
            prefix_adder = [-1, 0]
            suffix_adder = [1, 0]

        for i in range(len(prefix) - 1, -1, -1):
            prefix_pos = (prefix_pos[0] + prefix_adder[0], prefix_pos[1] + prefix_adder[1])
            moving_word.append(MovingLetter(letter=prefix[i], position=prefix_pos))
            self.computer_ai.player.remove_letter_from_holder(prefix[i])

        moving_word.reverse()

        for i in suffix:
            suffix_pos = (suffix_pos[0] + suffix_adder[0], suffix_pos[1] + suffix_adder[1])
            moving_word.append(MovingLetter(letter=i, position=suffix_pos))
            self.computer_ai.player.remove_letter_from_holder(i)

        return moving_word

    def make_move(self):
        """
        :return: word build with moving LETTERS
        """
        self.find_empty_spaces_on_board()

        move_info = self.computer_ai.find_move(self.places_on_board)

        i = 0
        while self.check_if_blank() and i <= 10:
            i += 1
            self.computer_ai.player.exchange_letter(['?'])

        if move_info:
            word = move_info[0][1]
            direction = move_info[1]
            letter_from_board_position = move_info[2]
            moving_word = self.create_moving_word(word, direction, letter_from_board_position)
            return moving_word

        else:
            self.computer_ai.player.exchange_letter(self.computer_ai.player.holder)
            self.computer_ai.player.amount_of_pass += 1
            return False


from django.conf.urls import url
from django.urls import include, path
from . import views

app_name = 'alfworldsapp'

urlpatterns = [
    path('querry_form',views.users_form,name='userquerryform'),
    path('test', views.test, name='test'),
    path('thank_you/',views.thankyou,name='thankyoupage'),
    path('allspecialities/category/<slug:slug>/', views.get_queryset, name='hospitalspage'),
    path('allspecialities/',views.allspecialitiesview,name='allspecialities'),
    path('search_by_speciality',views.get_selected_items,name='search_by_speciality'),
    path('medical-center/<slug:slug>/', views.hospital_details, name='hospitaldetails'),
]


# %% --------------------
import sys

# local
BASE_DIR = "D:/GWU/4 Spring 2021/6501 Capstone/VBD CXR/PyCharm Workspace/vbd_cxr"
# cerberus
# BASE_DIR = "/home/ssebastian94/vbd_cxr"

# add HOME DIR to PYTHONPATH
sys.path.append(BASE_DIR)

# %% --------------------start here
import os
import pandas as pd
from common.utilities import multi_label_split_based_on_percentage, display_fold_distribution

# %% --------------------splits for object detection
# read train.csv file
data = pd.read_csv(f"{BASE_DIR}/2_data_split/512/unmerged/100_percent_train/unmerged.csv")

# %% --------------------
# split into train-holdout sets 90%-10%
train_df, holdout_df = multi_label_split_based_on_percentage(data, 1, 0.1, "image_id",
                                                             "class_id", seed=42)

# %% --------------------
# visualize the split
display_fold_distribution(train_df, holdout_df, "class_id", color=list('rgbkymc'))

# %% --------------------
# drop the fold column
train_df = train_df.drop(["fold"], axis=1)
holdout_df = holdout_df.drop(["fold"], axis=1)

# %% --------------------
os.makedirs(f"{BASE_DIR}/2_data_split/512/unmerged/90_percent_train", exist_ok=True)
os.makedirs(f"{BASE_DIR}/2_data_split/512/unmerged/10_percent_holdout", exist_ok=True)

# %% --------------------
# save in csv
train_df.to_csv(f"{BASE_DIR}/2_data_split/512/unmerged/90_percent_train/train_df.csv", index=False)
holdout_df.to_csv(f"{BASE_DIR}/2_data_split/512/unmerged/10_percent_holdout/holdout_df.csv",
                  index=False)


N = int(input())
happy = []  # 快乐指数
for i in range(N):
    happy.append(int(input()))
mat = [[0 for _ in range(N)] for _ in range(N)]  # 连通矩阵
for i in range(N-1):
    L, K = [int(x) for x in input().split()]
    mat[K-1][L-1] = 1  # 建立上下级关系/填充连通矩阵
input()  # 把最后一行没用的数据去掉
dp = [[0, happy[m]] for m in range(N)]  # dp[i][0]表示第i+1个人不参加时最大的快乐指数,dp[i][1]表示参加时的最大快乐指数

def dfs(p):  # p为当前搜索到的人
    ind = -1
    sub = []
    while True:  # 寻找下属
        try:
            ind = mat[p-1].index(1, ind+1)
            sub.append(ind)
        except ValueError:
            break
    if len(sub) == 0:
        dp[p-1][0] = 0
        dp[p-1][1] = happy[p-1]
        return
    for j in sub:
        dfs(j+1)
        dp[p-1][0] += max(dp[j][0], dp[j][1])
    for j in sub:
        dp[p-1][1] += dp[j][0]

headmaster = 1
for i in range(N):  # 寻找校长
    flag = True
    for j in range(N):
        if mat[j][i] == 1:  # 校长没有入度
            flag = False
            break
    if flag:
        headmaster = i+1
        break
dfs(headmaster)
print(max(dp[headmaster-1]), end='')


import tensorflow as tf
#import tensorflow.contrib.layers as layers

class MixtureModel(tf.keras.Model):
    def __init__(self, dropout_rate, n_mixtures):
        super().__init__()

        self.sigma_max = 5
        self.keep_prob = 1 - dropout_rate

        self.n_mixtures = n_mixtures

        self.model = tf.keras.Sequential([
            tf.keras.layers.Dense(50, activation=tf.keras.activations.relu),
            tf.keras.layers.Dropout(self.keep_prob),
            tf.keras.layers.Dense(50, activation=tf.keras.activations.relu),
            tf.keras.layers.Dropout(self.keep_prob),
            tf.keras.layers.Dense(self.n_mixtures * 3)
        ])

    def call(self, x):
        output_layer = self.model(x)

        raw_output = tf.reshape(output_layer, [-1, self.n_mixtures, 3])
        mixture_weights = tf.nn.softmax(raw_output[:, :, 0] - tf.expand_dims(tf.reduce_max(raw_output[:, :, 0],
                                                                                axis=1), 1))
        mixture_means = raw_output[:, :, 1]
        mixture_variances = self.sigma_max * tf.sigmoid(raw_output[:, :, 2])

        # Stacking along axis=1 might be easier
        gmm = tf.stack([mixture_weights, mixture_means, mixture_variances])

        mean = tf.reduce_sum(mixture_weights * mixture_means, axis=1)
        aleatoric_uncertainty = tf.reduce_sum(mixture_weights * mixture_variances, axis=1)
        epistemic_uncertainty = tf.reduce_sum(mixture_weights *
                                              tf.square(mixture_means - tf.expand_dims(
                                                  tf.reduce_sum(mixture_weights * mixture_means, axis=1),
                                                  axis=1
                                              )), axis=1)

        uncertainties = tf.stack([aleatoric_uncertainty, epistemic_uncertainty])

        return gmm, mean, uncertainties

    def get_layers(self):
        return self.model.layers

    def set_dropout_rate(self, dropout_rate):
        layers = self.get_layers()
        for layer in layers:
            if "dropout" in layer.name:
                layer.rate = dropout_rate

def mixture_model(x, dropout_rate, n_mixtures):
    """
    Constructs a Mixture Density Network to process simple 2D data

    :param x: Input feature x
    :param dropout_rate:
    :param n_mixtures: Number of mixtures
    :return: gmm, mean, uncertainties
    """

    return MixtureModel(dropout_rate, n_mixtures)(x)


""" init py report account.report.profit """

from datetime import datetime
from dateutil.relativedelta import relativedelta

from odoo import models, fields, api, _
from odoo.tools.misc import format_date

# pylint: disable=no-member, unused-argument, consider-using-ternary
# pylint: disable=no-self-use, unused-variable, redefined-outer-name
# pylint: disable=too-many-arguments, too-many-locals, protected-access
# pylint: disable=too-many-nested-blocks
class AccountReportProfit(models.AbstractModel):
    """ init py report account.report.profit """
    _name = "account.report.profit"
    _description = "account.report.profit"
    _inherit = "account.report.assets"
    _group_model = 'profit.group'

    filter_date = {'mode': 'range', 'filter': 'this_year',
                   'date_from': fields.Date.to_string(
                       datetime.now().replace(month=1, day=1))}

    def _get_date_from(self, options, period_fiscal_year=None):
        """
        Get Date From
        :return:
        """
        if options and options.get('date'):
            if period_fiscal_year:
                date_to = options.get('date').get('date_to')
                return self._get_from_fiscal_year(date_to)[1]
            return options and options.get('date').get('date_from')
        return '1900-01-01'

    @api.model
    def _get_templates(self):
        """
        Override function _get_templates
        """
        templates = super(AccountReportProfit, self)._get_templates()
        templates['main_template'] = 'account_morocco_reports.' \
                                     'morocco_main_template'
        templates['search_template'] = 'account_morocco_reports.' \
                                       'search_template_profit'
        return templates

    @api.model
    def _get_columns_name(self, options):
        """
        Override function _get_columns_name
        """
        columns = [{'name': '', 'style': 'width:2%'},
                   {'name': '', 'style': 'width:80%'},
                   {'name': _('Current Year'), 'class': 'number'},
                   {'name': _('Previous Year'), 'class': 'number'},
                   {'name': _('Net'), 'class': 'number '}, ]
        count_opt = len(options['comparison']['periods'])
        if options.get('comparison') and options['comparison'].get('periods'):
            columns += [{'name': _('Net'), 'class': 'number '}] * count_opt
        return columns

    @api.model
    def _get_dates_period(self, options, date_from, date_to, mode,
                          period_type=None, strict_range=False):
        """
        Override _get_dates_period
        """
        super(AccountReportProfit, self)._get_dates_period(
            options, date_from, date_to, mode, period_type=period_type,
            strict_range=strict_range
        )
        dt_from_str = format_date(self.env, fields.Date.to_string(date_from))
        dt_to_str = format_date(self.env, fields.Date.to_string(date_to))
        string = _('Form %s To %s') % (dt_from_str, dt_to_str)
        return {
            'string': string,
            'period_type': 'year',
            'mode': 'range',
            'date_from': fields.Date.to_string(date_from),
            'date_to': fields.Date.to_string(date_to),
        }

    @api.model
    def _get_options(self, previous_options=None):
        """
        Override _get_options
        """
        res = super(AccountReportProfit, self)._get_options(
            previous_options=previous_options)
        dateto_datetime = datetime.strptime(res['date']['date_to'], "%Y-%m-%d")
        count_opt = res['comparison']['number_period']
        comparison_filter = res['comparison']['filter']
        if comparison_filter == 'previous_period':
            periods = []
            for index in range(1, count_opt + 1):
                x_dateto = dateto_datetime - relativedelta(years=index)
                x_datefrom = x_dateto.replace(day=1, month=1)
                dt_to_str = format_date(self.env, x_dateto)
                dt_from_str = format_date(self.env, x_datefrom)
                string = _('From %s To %s ') % (dt_from_str, dt_to_str)
                periods.append({
                    'string': string,
                    'period_type': 'year',
                    'mode': 'range',
                    'date_from': res['date']['date_from'],
                    'date_to': fields.Date.to_string(x_dateto),
                })
            res['comparison']['periods'] = periods
        return res

    def _set_context(self, options):
        """
        _set_context
        """
        ctx = super(AccountReportProfit, self)._set_context(options)
        ctx['date_from'] = options['date']['date_from']
        ctx['date_to'] = options['date']['date_to']
        return ctx

    @api.model
    def _get_report_name(self):
        """
        Override  _get_report_name
        """
        return _("Profit and Loss Part 1")


import sys
import json
import websocket

# config
def load_config(filename):
    config = {}
    with open(filename, 'r', encoding='utf8') as f:
        config = json.load(f)
    return config

config = load_config('./config.json')

# Initialize Flask app
from flask import Flask, jsonify
from flask_cors import CORS

app = Flask(__name__)
cors = CORS(app)
app.config['CORS_HEADERS'] = 'Content-Type'
app.config['JWT_SECRET_KEY'] = 'ntp-team-g'
app.config['WEBSOCKET_SERVER'] = config['websocket_server']
if not config['server']['debug']:
    app.config['SERVER_NAME'] = '{}:{}'.format(config['server']['server_name'], str(config['server']['port']))

# DB connection
from sqlalchemy import create_engine, text
app.config.from_pyfile('config.py')
database = create_engine(app.config['DB_URL'],encoding='utf-8',max_overflow=0)
app.database = database

# JWT Manager
from flask_jwt_extended import JWTManager
jwt_manager = JWTManager(app)
app.jwt_manager = jwt_manager

@jwt_manager.expired_token_loader
def my_expired_token_callback(expired_token):
    return jsonify({
        'status': 401,
        'sub_status': 42,
        'msg': '세션이 만료되었습니다.'
    }), 401

# API
from app.api import build_api
build_api(app)

if __name__ == "__main__":
    app.run(debug=True, host='0.0.0.0', port=config['server']['port'])


from math import log
import fileinput
from numpy import *
import numpy as np
import pandas as pd
import scipy.stats as stats
import statsmodels.api as sm
import matplotlib.pyplot as plt

def extract_diff_ret_or_fol(source_path_param, choose_str):
    list1 = []
    for line in fileinput.input([source_path_param], openhook=fileinput.hook_encoded("utf8")):
        if choose_str == 'retweet':
            diff_ret = line.split(',')[3]
            dot_index = diff_ret.find(".")
            diff_ret_int = int(diff_ret[0:dot_index])
            list1.append(diff_ret_int)  # Normal

        elif choose_str == 'follower_wt_mc':
            diff_fol = float(line.split(',')[10])
            list1.append(diff_fol)  # Normal

        elif choose_str == 'follower_wo_mc':
            diff_fol = float(line.split(',')[13])
            list1.append(diff_fol)  # Normal
    fileinput.close()
    return list1

def write_date_date_csv(output_path, list_diff_ret_param, list_diff_fol_param, choice):
    fo = open(output_path, "w")

    if choice == 'all_tweet':
        for j in range(0, len(list_diff_ret_param)):
            result = str(list_diff_ret_param[j]) + "," + str(list_diff_fol_param[j]) + "\n"
            # print(result)  # TEST
            fo.write(result)
    elif choice == 'kde':
        for j in range(1, len(list_diff_ret_param)):
            diff_ret_str = str(list_diff_ret_param[j])
            diff_fol_str = str(list_diff_fol_param[j])
            if diff_fol_str == '0.0':
                diff_fol_str = 'NA'
            if diff_ret_str == '0.0':
                diff_ret_str = 'NA'
            result = diff_ret_str + "," + diff_fol_str + "\n"
            # print(result)  # TEST
            fo.write(result)
    fo.close()
    return

def process_data(source_path_param, output, choice):
    for line in fileinput.input([source_path_param]):
        value = line.split(',')
        # print(value)
        x = int(value[12].strip())  # hour
        y = 0.0
        if choice == 'retweet':
            y = float(value[3].strip())  # diff_retweet
        elif choice == 'follower_wt_mc':
            y = float(value[10].strip())  # diff_follower_wt_mc
        elif choice == 'follower_wo_mc':
            y = float(value[13].strip())  # diff_follower_wo_mc
        output[x].append(y)

def estimate(input_param, output, hour):
    if not input_param:
        nothing_message = "Nothing at t: " + str(hour)
        # print(nothing_message)
        output.append(0.0)
    elif len(input_param) == 1:
        nothing_message = "Only One Source Tweet at t: " + str(hour)
        # print(nothing_message)
        output.append(0.0)
    else:
        # print("Round :" + str(hour))
        # print("input_param:  " + str(input_param))
        x = array(input_param)
        # print("Array x: " + str(x))
        try:
            kde = stats.gaussian_kde(x)
        except np.linalg.linalg.LinAlgError:
            # print("Singular Matrix at t: " + str(hour))
            output.append(0.0)
            return
        xs = linspace(min(input_param), max(input_param), num=100)
        kde.set_bandwidth(bw_method='silverman')
        kde.set_bandwidth(bw_method=kde.factor / 2)
        y = kde(xs)
        sum_weight = 0
        value = 0
        for j in range(0, len(xs)):
            value += xs[j]*y[j]
            sum_weight += y[j]

        avg = value/sum_weight
        output.append(avg)

def normal_boxplot(output_kde_ret_fol_csv_path_param):
    kde_df_ret_fol = pd.read_csv(output_kde_ret_fol_csv_path_param, names=['DeltaRetweet', 'DeltaFollower'])
    # kde_df_ret_fol2 = pd.read_csv(output_kde_ret_fol_csv_path_param, names=['DeltaRetweet2', 'DeltaFollower2'])
    print(kde_df_ret_fol)
    plotx = kde_df_ret_fol.boxplot(return_type='both')
    # plotx2 = kde_df_ret_fol2.boxplot(return_type='both')

    # plotx = kde_df_ret_fol.boxplot(return_type='both', column='DeltaRetweet')
    # kde_df_ret_fol.plot(title='Delta Retweet - Delta Follower')
    # df_follower.boxplot(by='DeltaRetweet')
    print(plotx)
    plt.title('Delta Retweet - Delta Follower (' + each_topic + ', ' + each_fold + ')')
    axes = plt.gca()
    axes.set_ylim([-10, 50])
    plt.show()

def create_low_medium_high(output_kde_ret_fol_csv_path_param, topic_name, fold_num, is_interpolate_param, is_log_y_axis_param, logarithm_base_num_param):
    topic_cal = 0
    fold_cal = 0
    if topic_name == 'apple':
        topic_cal = 0
    elif topic_name == 'aroii':
        topic_cal = 1
    elif topic_name == 'hormonestheseries':
        topic_cal = 2
    elif topic_name == 'thefacethailand':
        topic_cal = 3

    if fold_num == '1':
        fold_cal = 0
    elif fold_num == '2':
        fold_cal = 1
    elif fold_num == '3':
        fold_cal = 2
    elif fold_num == '4':
        fold_cal = 3
    elif fold_num == '5':
        fold_cal = 4

    lowwer_bound = float(bound_delta_follower[(10 * topic_cal) + (2 * fold_cal) + 0])
    upper_bound = float(bound_delta_follower[(10 * topic_cal) + (2 * fold_cal) + 1])
    # print(lowwer_bound, upper_bound)

    low_follower_list = []
    medium_follower_list = []
    high_follower_list = []
    dataframe_low_medium_high = []
    kde_df_ret_fol = pd.read_csv(output_kde_ret_fol_csv_path_param, names=['DeltaRetweet', 'DeltaFollower'])
    kde_df_ret_fol_interpolated = kde_df_ret_fol.interpolate().bfill()

    if is_interpolate_param:
        if is_log_y_axis_param:
            # print(kde_df_ret_fol_interpolated.DeltaRetweet)
            for j in range(0, len(kde_df_ret_fol_interpolated)):
                if kde_df_ret_fol_interpolated.DeltaRetweet.values[j] <= 0:
                    kde_df_ret_fol_interpolated.DeltaRetweet.values[j] = np.nan
                kde_df_ret_fol_interpolated.DeltaRetweet.values[j] = math.log(kde_df_ret_fol_interpolated.DeltaRetweet.values[j], logarithm_base_num_param)
            # print(len(kde_df_ret_fol_interpolated))

        for j in range(0, len(kde_df_ret_fol_interpolated)):
            # print(kde_df_ret_fol_interpolated.DeltaFollower.values[j])
            if float(kde_df_ret_fol_interpolated.DeltaFollower.values[j]) <= lowwer_bound:
                low_follower_list.append(kde_df_ret_fol_interpolated.DeltaRetweet.values[j])
                medium_follower_list.append(np.nan)
                high_follower_list.append(np.nan)
            elif lowwer_bound < float(kde_df_ret_fol_interpolated.DeltaFollower.values[j]) <= upper_bound:
                low_follower_list.append(np.nan)
                medium_follower_list.append(kde_df_ret_fol_interpolated.DeltaRetweet.values[j])
                high_follower_list.append(np.nan)
            else:
                low_follower_list.append(np.nan)
                medium_follower_list.append(np.nan)
                high_follower_list.append(kde_df_ret_fol_interpolated.DeltaRetweet.values[j])

        # print(len(high_follower_list))
        combined_data = list(zip(low_follower_list, medium_follower_list, high_follower_list))
        # print(combined_data)

        dataframe_low_medium_high = pd.DataFrame(combined_data, columns=['Low', 'Medium', 'High'])
        # print(dataframe_low_medium_high)

        # df3 = kde_df_ret_fol_interpolated.append(df2, ignore_index=True)
        # print(df3)
        # df3_delete_last = df3.drop(df3.index[[1649]])
        # print(df3_delete_last.DeltaRetweet.values[1649])

    else:
        if is_log_y_axis_param:
            # print(kde_df_ret_fol.DeltaRetweet)
            for j in range(0, len(kde_df_ret_fol)):
                if kde_df_ret_fol.DeltaRetweet.values[j] <= 0:
                    kde_df_ret_fol.DeltaRetweet.values[j] = np.nan
                kde_df_ret_fol.DeltaRetweet.values[j] = math.log(kde_df_ret_fol.DeltaRetweet.values[j], logarithm_base_num_param)
            # print(len(kde_df_ret_fol))
        for j in range(0, len(kde_df_ret_fol)):
            # print(kde_df_ret_fol.DeltaFollower.values[j])
            if float(kde_df_ret_fol.DeltaFollower.values[j]) <= lowwer_bound:
                low_follower_list.append(kde_df_ret_fol.DeltaRetweet.values[j])
                medium_follower_list.append(np.nan)
                high_follower_list.append(np.nan)
            elif lowwer_bound < float(kde_df_ret_fol.DeltaFollower.values[j]) <= upper_bound:
                low_follower_list.append(np.nan)
                medium_follower_list.append(kde_df_ret_fol.DeltaRetweet.values[j])
                high_follower_list.append(np.nan)
            else:
                low_follower_list.append(np.nan)
                medium_follower_list.append(np.nan)
                high_follower_list.append(kde_df_ret_fol.DeltaRetweet.values[j])

        # print(len(high_follower_list))
        combined_data = list(zip(low_follower_list, medium_follower_list, high_follower_list))
        # print(combined_data)

        dataframe_low_medium_high = pd.DataFrame(combined_data, columns=['Low', 'Medium', 'High'])
        # print(dataframe_low_medium_high)

    return dataframe_low_medium_high

def low_medium_high_boxplot_from_df(df_low_medium_high_param, is_log_y_axis_param):
    plotx = df_low_medium_high_param.boxplot(return_type='both')
    # plotx = kde_df_ret_fol.boxplot(return_type='both', column='DeltaRetweet')
    # kde_df_ret_fol.plot(title='Delta Retweet - Delta Follower')
    # df_follower.boxplot(by='DeltaRetweet')
    # print(plotx)

    axes = plt.gca()

    axes.set_xlabel("Delta Follower Group")
    if is_log_y_axis_param:
        axes.set_ylabel("Density of Log(Delta Retweet)")
        axes.set_ylim([-5, 10])
        # plt.title('Density of Log(Delta Retweet) - Delta Follower Group (Low, Medium, High) Box plot (' + each_topic + ', ' + each_fold + ')')
        plt.title('Box plot: Density of Log Delta Retweet - Delta Follower Group (' + each_topic + ', ' + each_fold + ')')
    else:
        axes.set_ylabel("Density of Delta Retweet")
        axes.set_ylim([-10, 100])
        # plt.title('Density of Delta Retweet - Delta Follower Group (Low, Medium, High) Box plot (' + each_topic + ', ' + each_fold + ')')
        plt.title('Box plot: Density of Delta Retweet - Delta Follower Group (Low, Medium, High) (' + each_topic + ', ' + each_fold + ')')
    plt.show()

def print_info_quartile_median(df_low_medium_high_param, is_log_y_axis_param):
    # if is_log_y_axis_param:
    #     print("Y Axis: Log(Delta Retweet)")
    # else:
    #     print("Y Axis: Delta Retweet")
    # print("----- Low Delta_Follower -----")
    # print("1-Quartile: " + str(df_low_medium_high_param.Low.quantile(q=0.25)))
    print("Median: %.5f" % df_low_medium_high_param.Low.median())
    # print("3-Quartile: " + str(df_low_medium_high_param.Low.quantile(q=0.75)))

    # print("----- Medium Delta_Follower -----")
    # print("1-Quartile: " + str(df_low_medium_high_param.Medium.quantile(q=0.25)))
    print("Median: %.5f" % df_low_medium_high_param.Medium.median())
    # print("3-Quartile: " + str(df_low_medium_high_param.Medium.quantile(q=0.75)))

    # print("----- High Delta_Follower -----")
    # print("1-Quartile: " + str(df_low_medium_high_param.High.quantile(q=0.25)))
    print("Median: %.5f" % df_low_medium_high_param.High.median())
    # print("3-Quartile: " + str(df_low_medium_high_param.High.quantile(q=0.75)))

# SET PARAMETER
# y_axis_choices = ['retweet', 'follower_wt_mc', 'follower_wo_mc']
y_axis_choices = ['follower_wo_mc']
topics = ["apple", "aroii", "hormonestheseries", "thefacethailand"]
# folds = ["1", "2", "3", "4", "5"]
folds = ["4"]

last_hour_app_aroii = 1651
last_hour_hor_theface = 1627

is_interpolate = False  # Must False

is_log_y_axis = True
logarithm_base_num = 2

bound_delta_follower = ['1.67',  '7.40',         # Apple 1
                        '2.10',  '8.00',         # Apple 2
                        '3.8',   '16.6',         # Apple 3
                        '2.2',   '4.4',          # Apple 4
                        '3.53',  '6.2',          # Apple 5
                        '0.92',  '2.1',          # Aroii 1
                        '7.3',   '12.1',         # Aroii 2
                        '0.585', '1.2',          # Aroii 3
                        '0.98',  '1.76',         # Aroii 4
                        '2.7',   '4.1',          # Aroii 5
                        '1.1',   '2.35',         # Hormones 1
                        '2.7',   '3.9',          # Hormones 2    !!!
                        '6.52',  '10',           # Hormones 3
                        '2.25',  '4.1',          # Hormones 4
                        '2.5',   '5',            # Hormones 5
                        '1.59',  '3.5',          # TheFace 1
                        '0.995', '1.51',         # TheFace 2
                        '4.7',   '7.3',          # TheFace 3     !!!
                        '2.8',   '4.1',          # TheFace 4
                        '2.87',  '4.75']         # TheFace 5

for each_choice in y_axis_choices:
    for each_topic in topics:
        for each_fold in folds:
            print("============ Topic: " + each_topic + ", Fold: " + each_fold + " =============")

            source_path = "E:/tweet_process/result_follower-ret/06_diff_ret_fol_result/" + each_topic + "/fold_" + each_fold + "/all_tweet.csv"
            output_follower_csv = "E:/tweet_process/result_follower-ret/09_follower_retweet_csv/" + each_topic + "/fold_" + each_fold + "/all_tweet-diff_ret-diff_fol.csv"
            output_kde_ret_fol_csv = "E:/tweet_process/result_follower-ret/10_KDE_ret_fol_csv/" + each_topic + "/fold_" + each_fold + "/kde-diff_ret-diff_fol.csv"

            """
            Read & Write Data
            """
            # list_diff_ret = extract_diff_ret_or_fol(source_path, 'retweet')
            # list_diff_fol = extract_diff_ret_or_fol(source_path, each_choice)
            # write_date_date_csv(output_follower_csv, list_diff_ret, list_diff_fol, 'all_tweet')
            # print(list_diff_fol)
            # print(list_diff_ret)
            # print("================= End Read & Write Data ==================")

            # """
            # NOT KDE
            # """
            # df_follower = pd.read_csv(output_follower_csv, names=['DeltaRetweet', 'DeltaFollower'])
            # print(df_follower)
            # df_follower.boxplot()
            # # df_follower.boxplot(by='DeltaRetweet')
            # plt.show()

            """
            Process Data
            """
            # data_retweet = []  # Array for collect original data
            # data_follower = []  # Array for collect original data
            # data_estimate_retweet = []  # Array for collect KDE processed data
            # data_estimate_follower = []  # Array for collect KDE processed data
            #
            # if each_topic == "apple" or each_topic == "aroii":
            #     for i in range(0, last_hour_app_aroii):
            #         data_retweet.append([])
            #         data_follower.append([])
            # else:
            #     for i in range(0, last_hour_hor_theface):
            #         data_retweet.append([])
            #         data_follower.append([])
            #
            # process_data(source_path, data_retweet, 'retweet')
            # process_data(source_path, data_follower, 'follower_wo_mc')

            """
            KDE processing
            """
            # for i in range(0, len(data_retweet)):
            #     estimate(data_retweet[i], data_estimate_retweet, i)
            #     estimate(data_follower[i], data_estimate_follower, i)

            """
            Write KDE Data
            """
            # print(len(data_estimate_retweet))
            # print(data_estimate_retweet)
            # print(len(data_estimate_follower))
            # print(data_estimate_follower)
            # write_date_date_csv(output_kde_ret_fol_csv, data_estimate_retweet, data_estimate_follower, 'kde')

            """
            Normal BoxPlot Test
            """
            # normal_boxplot(output_kde_ret_fol_csv)

            """
            Create Dataframe (Low, Medium, High)
            Plot
            """
            df_low_medium_high = create_low_medium_high(output_kde_ret_fol_csv, each_topic, each_fold, is_interpolate, is_log_y_axis, logarithm_base_num)
            print_info_quartile_median(df_low_medium_high, is_log_y_axis)
            # low_medium_high_boxplot_from_df(df_low_medium_high, is_log_y_axis)


import numpy as np
import random
import gym
from collections import deque
import torch
import torch.nn as nn
import torch.nn.functional as F
from torch.distributions import Normal, MultivariateNormal
from torch.nn.utils import clip_grad_norm_
import torch.optim as optim
import gym.spaces
import argparse
from torch.utils.tensorboard import SummaryWriter
import time

def hidden_init(layer):
    fan_in = layer.weight.data.size()[0]
    lim = 1. / np.sqrt(fan_in)
    return (-lim, lim)

class Actor(nn.Module):
    """Actor (Policy) Model."""

    def __init__(self, state_size, action_size, seed, hidden_size=256, init_w=3e-3, log_std_min=-20, log_std_max=2):
        """Initialize parameters and build model.
        Params
        ======
            state_size (int): Dimension of each state
            action_size (int): Dimension of each action
            seed (int): Random seed
            fc1_units (int): Number of nodes in first hidden layer
            fc2_units (int): Number of nodes in second hidden layer
        """
        super(Actor, self).__init__()
        self.seed = torch.manual_seed(seed)
        self.log_std_min = log_std_min
        self.log_std_max = log_std_max

        self.fc1 = nn.Linear(state_size, hidden_size)
        self.fc2 = nn.Linear(hidden_size, hidden_size)

        self.mu = nn.Linear(hidden_size, action_size)
        self.log_std_linear = nn.Linear(hidden_size, action_size)

    def reset_parameters(self):
        self.fc1.weight.data.uniform_(*hidden_init(self.fc1))
        self.fc2.weight.data.uniform_(*hidden_init(self.fc2))
        self.mu.weight.data.uniform_(-init_w, init_w)
        self.log_std_linear.weight.data.uniform_(-init_w, init_w)

    def forward(self, state):
        x = F.relu(self.fc1(state))
        x = F.relu(self.fc2(x))
        mu = self.mu(x)
        log_std = self.log_std_linear(x)
        log_std = torch.clamp(log_std, self.log_std_min, self.log_std_max)
        return mu, log_std

    def evaluate(self, state, epsilon=1e-6):
        mu, log_std = self.forward(state)
        std = log_std.exp()

        dist = Normal(0, 1)
        e = dist.sample().to(device)
        action = torch.tanh(mu + e * std)
        log_prob = Normal(mu, std).log_prob(mu + e * std) - torch.log(1 - action.pow(2) + epsilon)
        return action, log_prob

    def get_action(self, state):
        """
        returns the action based on a squashed gaussian policy. That means the samples are obtained according to:
        a(s,e)= tanh(mu(s)+sigma(s)+e)
        """
        mu, log_std = self.forward(state.unsqueeze(0))
        std = log_std.exp()

        dist = Normal(0, 1)
        e      = dist.sample().to(device)
        action = torch.tanh(mu + e * std).cpu()
        return action[0]

class Critic(nn.Module):
    """Critic (Value) Model."""

    def __init__(self, state_size, action_size, seed, hidden_size=256):
        """Initialize parameters and build model.
        Params
        ======
            state_size (int): Dimension of each state
            action_size (int): Dimension of each action
            seed (int): Random seed
            hidden_size (int): Number of nodes in the network layers

        """
        super(Critic, self).__init__()
        self.seed = torch.manual_seed(seed)
        self.fc1 = nn.Linear(state_size+action_size, hidden_size)
        self.fc2 = nn.Linear(hidden_size, hidden_size)
        self.fc3 = nn.Linear(hidden_size, 1)
        self.reset_parameters()

    def reset_parameters(self):
        self.fc1.weight.data.uniform_(*hidden_init(self.fc1))
        self.fc2.weight.data.uniform_(*hidden_init(self.fc2))
        self.fc3.weight.data.uniform_(-3e-3, 3e-3)

    def forward(self, state, action):
        """Build a critic (value) network that maps (state, action) pairs -> Q-values."""
        x = torch.cat((state, action), dim=1)
        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        return self.fc3(x)

class Agent():
    """Interacts with and learns from the environment."""

    def __init__(self, state_size, action_size, random_seed, action_prior="uniform"):
        """Initialize an Agent object.

        Params
        ======
            state_size (int): dimension of each state
            action_size (int): dimension of each action
            random_seed (int): random seed
        """
        self.state_size = state_size
        self.action_size = action_size
        self.seed = random.seed(random_seed)

        self.target_entropy = -action_size  # -dim(A)
        self.alpha = 1
        self.log_alpha = torch.tensor([0.0], requires_grad=True)
        self.alpha_optimizer = optim.Adam(params=[self.log_alpha], lr=LR_ACTOR)
        self._action_prior = action_prior

        print("Using: ", device)

        # Actor Network
        self.actor_local = Actor(state_size, action_size, random_seed).to(device)
        self.actor_optimizer = optim.Adam(self.actor_local.parameters(), lr=LR_ACTOR)

        # Critic Network (w/ Target Network)
        self.critic1 = Critic(state_size, action_size, random_seed).to(device)
        self.critic2 = Critic(state_size, action_size, random_seed).to(device)

        self.critic1_target = Critic(state_size, action_size, random_seed).to(device)
        self.critic1_target.load_state_dict(self.critic1.state_dict())

        self.critic2_target = Critic(state_size, action_size, random_seed).to(device)
        self.critic2_target.load_state_dict(self.critic2.state_dict())

        self.critic1_optimizer = optim.Adam(self.critic1.parameters(), lr=LR_CRITIC, weight_decay=WEIGHT_DECAY)
        self.critic2_optimizer = optim.Adam(self.critic2.parameters(), lr=LR_CRITIC, weight_decay=WEIGHT_DECAY)

        # Replay memory
        self.memory = PrioritizedReplay(capacity=BUFFER_SIZE)

    def step(self, state, action, reward, next_state, done, step):
        """Save experience in replay memory, and use random sample from buffer to learn."""
        # Save experience / reward
        self.memory.push(state, action, reward, next_state, done)

        # Learn, if enough samples are available in memory
        if len(self.memory) > BATCH_SIZE:
            experiences = self.memory.sample(BATCH_SIZE)
            self.learn(step, experiences, GAMMA)

    def act(self, state, add_noise=True):
        """Returns actions for given state as per current policy."""
        state = torch.from_numpy(state).unsqueeze(0).float().to(device)
        action = self.actor_local.get_action(state).detach()
        return action

    def learn(self, step, experiences, gamma, d=1):
        """Updates actor, critics and entropy_alpha parameters using given batch of experience tuples.
        Q_targets = r + γ * (min_critic_target(next_state, actor_target(next_state)) - α *log_pi(next_action|next_state))
        Critic_loss = MSE(Q, Q_target)
        Actor_loss = α * log_pi(a|s) - Q(s,a)
        where:
            actor_target(state) -> action
            critic_target(state, action) -> Q-value
        Params
        ======
            experiences (Tuple[torch.Tensor]): tuple of (s, a, r, s', done) tuples
            gamma (float): discount factor
        """
        states, actions, rewards, next_states, dones, idx, weights = experiences
        states      = torch.FloatTensor(np.float32(states)).to(device)
        next_states = torch.FloatTensor(np.float32(next_states)).to(device)
        actions     = torch.cat(actions).to(device)
        rewards     = torch.FloatTensor(rewards).to(device).unsqueeze(1)
        dones       = torch.FloatTensor(dones).to(device).unsqueeze(1)
        weights    = torch.FloatTensor(weights).unsqueeze(1)
        #print(actions.shape)
        # ---------------------------- update critic ---------------------------- #
        # Get predicted next-state actions and Q values from target models
        next_action, log_pis_next = self.actor_local.evaluate(next_states)

        Q_target1_next = self.critic1_target(next_states.to(device), next_action.squeeze(0).to(device))
        Q_target2_next = self.critic2_target(next_states.to(device), next_action.squeeze(0).to(device))

        # take the mean of both critics for updating
        Q_target_next = torch.min(Q_target1_next, Q_target2_next).cpu()

        # Compute Q targets for current states (y_i)
        Q_targets = rewards.cpu() + (gamma * (1 - dones.cpu()) * (Q_target_next - self.alpha * log_pis_next.mean(1).unsqueeze(1).cpu()))

        # Compute critic loss
        Q_1 = self.critic1(states, actions).cpu()
        Q_2 = self.critic2(states, actions).cpu()
        td_error1 = Q_targets.detach()-Q_1#,reduction="none"
        td_error2 = Q_targets.detach()-Q_2
        critic1_loss = 0.5* (td_error1.pow(2)*weights).mean()
        critic2_loss = 0.5* (td_error2.pow(2)*weights).mean()
        prios = abs(((td_error1 + td_error2)/2.0 + 1e-5).squeeze())

        # Update critics
        # critic 1
        self.critic1_optimizer.zero_grad()
        critic1_loss.backward()
        self.critic1_optimizer.step()
        # critic 2
        self.critic2_optimizer.zero_grad()
        critic2_loss.backward()
        self.critic2_optimizer.step()

        self.memory.update_priorities(idx, prios.data.cpu().numpy())
        if step % d == 0:
        # ---------------------------- update actor ---------------------------- #

            alpha = torch.exp(self.log_alpha)
            # Compute alpha loss
            actions_pred, log_pis = self.actor_local.evaluate(states)
            alpha_loss = - (self.log_alpha.cpu() * (log_pis.cpu() + self.target_entropy).detach().cpu()).mean()
            self.alpha_optimizer.zero_grad()
            alpha_loss.backward()
            self.alpha_optimizer.step()

            self.alpha = alpha
            # Compute actor loss
            if self._action_prior == "normal":
                policy_prior = MultivariateNormal(loc=torch.zeros(self.action_size), scale_tril=torch.ones(self.action_size).unsqueeze(0))
                policy_prior_log_probs = policy_prior.log_prob(actions_pred)
            elif self._action_prior == "uniform":
                policy_prior_log_probs = 0.0

            actor_loss = ((alpha * log_pis.squeeze(0).cpu() - self.critic1(states, actions_pred.squeeze(0)).cpu() - policy_prior_log_probs )*weights).mean()

            # Minimize the loss
            self.actor_optimizer.zero_grad()
            actor_loss.backward()
            self.actor_optimizer.step()

            # ----------------------- update target networks ----------------------- #
            self.soft_update(self.critic1, self.critic1_target, TAU)
            self.soft_update(self.critic2, self.critic2_target, TAU)

    def soft_update(self, local_model, target_model, tau):
        """Soft update model parameters.
        θ_target = τ*θ_local + (1 - τ)*θ_target
        Params
        ======
            local_model: PyTorch model (weights will be copied from)
            target_model: PyTorch model (weights will be copied to)
            tau (float): interpolation parameter
        """
        for target_param, local_param in zip(target_model.parameters(), local_model.parameters()):
            target_param.data.copy_(tau*local_param.data + (1.0-tau)*target_param.data)

class PrioritizedReplay(object):
    """
    Proportional Prioritization
    """
    def __init__(self, capacity, alpha=0.6,beta_start = 0.4,beta_frames=100000):
        self.alpha = alpha
        self.beta_start = beta_start
        self.beta_frames = beta_frames
        self.frame = 1 #for beta calculation
        self.capacity   = capacity
        self.buffer     = []
        self.pos        = 0
        self.priorities = np.zeros((capacity,), dtype=np.float32)

    def beta_by_frame(self, frame_idx):
        """
        Linearly increases beta from beta_start to 1 over time from 1 to beta_frames.

        3.4 ANNEALING THE BIAS (Paper: PER)
        We therefore exploit the flexibility of annealing the amount of importance-sampling
        correction over time, by defining a schedule on the exponent
        that reaches 1 only at the end of learning. In practice, we linearly anneal from its initial value 0 to 1
        """
        return min(1.0, self.beta_start + frame_idx * (1.0 - self.beta_start) / self.beta_frames)

    def push(self, state, action, reward, next_state, done):
        assert state.ndim == next_state.ndim
        state      = np.expand_dims(state, 0)
        next_state = np.expand_dims(next_state, 0)

        max_prio = self.priorities.max() if self.buffer else 1.0 # gives max priority if buffer is not empty else 1

        if len(self.buffer) < self.capacity:
            self.buffer.append((state, action, reward, next_state, done))
        else:
            # puts the new data on the position of the oldes since it circles via pos variable
            # since if len(buffer) == capacity -> pos == 0 -> oldest memory (at least for the first round?)
            self.buffer[self.pos] = (state, action, reward, next_state, done)

        self.priorities[self.pos] = max_prio
        self.pos = (self.pos + 1) % self.capacity # lets the pos circle in the ranges of capacity if pos+1 > cap --> new posi = 0

    def sample(self, batch_size):
        N = len(self.buffer)
        if N == self.capacity:
            prios = self.priorities
        else:
            prios = self.priorities[:self.pos]

        # calc P = p^a/sum(p^a)
        probs  = prios ** self.alpha
        P = probs/probs.sum()

        #gets the indices depending on the probability p
        indices = np.random.choice(N, batch_size, p=P)
        samples = [self.buffer[idx] for idx in indices]

        beta = self.beta_by_frame(self.frame)
        self.frame+=1

        #Compute importance-sampling weight
        weights  = (N * P[indices]) ** (-beta)
        # normalize weights
        weights /= weights.max()
        weights  = np.array(weights, dtype=np.float32)

        states, actions, rewards, next_states, dones = zip(*samples)
        return np.concatenate(states), actions, rewards, np.concatenate(next_states), dones, indices, weights

    def update_priorities(self, batch_indices, batch_priorities):
        for idx, prio in zip(batch_indices, batch_priorities):
            self.priorities[idx] = abs(prio)

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

def SAC(n_episodes=200, max_t=1000, print_every=10):

    scores_deque = deque(maxlen=args.print_every)
    t = 0
    for i_episode in range(1, n_episodes+1):

        state = env.reset()
        score = 0
        while True:
            t += 1
            action = agent.act(state)
            action_v = action[0].numpy()
            action_v = np.clip(action_v*action_high, action_low, action_high)
            next_state, reward, done, info = env.step(action_v)
            agent.step(state, action, reward, next_state, done, t)
            state = next_state
            score += reward

            if done:
                break

        scores_deque.append(score)
        writer.add_scalar("Reward", score, i_episode)
        writer.add_scalar("average_X", np.mean(scores_deque), i_episode)

        print('\rEpisode {} Reward: {:.2f}  Average100 Score: {:.2f}'.format(i_episode, score, np.mean(scores_deque)), end="")
        if i_episode % print_every == 0:
            print('\rEpisode {}  Reward: {:.2f}  Average100 Score: {:.2f}'.format(i_episode, score, np.mean(scores_deque)))

    torch.save(agent.actor_local.state_dict(), args.info + ".pt")

def play():
    agent.actor_local.eval()
    for i_episode in range(1):

        state = env.reset()

        while True:
            action = agent.act(state)
            action_v = action[0].numpy()
            action_v = np.clip(action_v*action_high, action_low, action_high)
            next_state, reward, done, info = env.step(action_v)
            next_state = next_state
            state = next_state

            if done:
                break

parser = argparse.ArgumentParser()
parser.add_argument("-env", type=str, default="Pendulum-v0", help="Name of the Environment")
parser.add_argument("-ep", type=int, default=100, help="Number of Episodes to train, default = 100")
parser.add_argument("-bs", "--buffer_size", type=int, default=int(1e6), help="Size of the Replay buffer, default= 1e6")
parser.add_argument("-bsize", "--batch_size", type=int, default=256, help="Batch size for the optimization process, default = 256")
parser.add_argument("-seed", type=int, default=0, help="Seed for the env and torch network weights, default is 0")
parser.add_argument("-lr", type=float, default=5e-4, help="Learning Rate, default = 5e-4")
parser.add_argument("-g", type=float, default=0.99, help="discount factor gamma, default = 0.99")
parser.add_argument("-wd", type=float, default=0, help="Weight decay, default = 0")
parser.add_argument("-ls", "--layer_size", type=int, default=256, help="Number of nodes per neural network layer, default = 256")
parser.add_argument("--print_every", type=int, default=100, help="Prints every x episodes the average reward over x episodes")
parser.add_argument("-info", type=str, help="tensorboard test run information")
parser.add_argument("-device", type=str, default="cuda:0", help="Change to CPU computing or GPU, default=cuda:0")
parser.add_argument("--saved_model", type=str, default=None, help="Load a saved model to perform a test run!")
parser.add_argument("-t", "--tau", type=float, default=1e-2, help="Softupdate factor tau, default is 1e-2")

args = parser.parse_args()

if __name__ == "__main__":
    seed = args.seed
    BUFFER_SIZE = args.buffer_size
    BATCH_SIZE = args.batch_size        # minibatch size
    GAMMA = args.g            # discount factor
    TAU = args.tau           # for soft update of target parameters
    LR_ACTOR = args.lr         # learning rate of the actor
    LR_CRITIC = args.lr       # learning rate of the critic
    WEIGHT_DECAY = args.wd#1e-2        # L2 weight decay
    HIDDEN_SIZE = args.layer_size
    saved_model = args.saved_model

    env_name = args.env
    device = args.device
    env = gym.make(env_name)
    env.seed(seed)
    np.random.seed(seed)
    state_size = env.observation_space.shape[0]
    action_size = env.action_space.shape[0]
    action_high = env.action_space.high[0]
    action_low = env.action_space.low[0]

    writer = SummaryWriter("runs/"+args.info)
    agent = Agent(state_size=state_size, action_size=action_size, random_seed=seed, action_prior="uniform") #"normal"

    start_time = time.time()
    if saved_model != None:
        agent.actor_local.load_state_dict(torch.load(saved_model))
        play()
    else:
        SAC(n_episodes=args.ep, max_t=500   , print_every=args.print_every)
    end_time = time.time()
    env.close()
    print("Training took: {} min".format((end_time-start_time)/60))
    #writer.add_hparams()


#!/usr/bin/env python3.6

import http.client
import json
import pprint
import datetime
import argparse
import ssl
import sys
import thetvdbproxy
import copy

parser = argparse.ArgumentParser()
parser.add_argument('hostname', metavar='SERVER')
parser.add_argument('type', metavar='MEDIA_TYPE', choices=['section', 'movie', 'show'],
                    help='One of section, movie, or show')
parser.add_argument('-s', '--skip-section', action='append', default=[], help='Name of section to exclude from results')
parser.add_argument('--summary', action='store_true', help='For show, only include summary information of seasons')
parser.add_argument('--plex-user', help='Plex username')
parser.add_argument('--plex-pass', help='Plex password')
parser.add_argument('--remap', action='store_true')
args = parser.parse_args()
hostname = args.hostname

def remap(item):
    result = copy.deepcopy(item)
    if args.remap and item["guid"].startswith("com.plexapp.agents.thetvdb://"):
        parts = item["guid"].split("/")
        seriesId = parts[2]
        seasonNumber = item["season"]
        episodeNumber = item["episode"]
        if int(seriesId) in thetvdbproxy.episodeMappings:
            inverted_map = dict(map(reversed, thetvdbproxy.episodeMappings[int(seriesId)].items()))
            if (seasonNumber, episodeNumber) in inverted_map:
                mapped_season, mapped_episode = inverted_map[(seasonNumber, episodeNumber)]
                result["season"] = mapped_season
                result["episode"] = mapped_episode
                result["guid"] = f'com.plexapp.agents.thetvdb://{seriesId}/{mapped_season}/{mapped_episode}?lang=en'
    return result

def log_error(msg):
    print(msg, file=sys.stderr)

def getAuthToken():
    conn = http.client.HTTPSConnection('plex.tv', context=ssl._create_unverified_context())

    payload = '------WebKitFormBoundary7MA4YWxkTrZu0gW\r\n' \
              'Content-Disposition: form-data; ' \
              'name="user[login]"\r\n\r\n' \
              + args.plex_user + \
              '\r\n------WebKitFormBoundary7MA4YWxkTrZu0gW\r\n' \
              'Content-Disposition: form-data; ' \
              'name="user[password]"\r\n\r\n' \
              + args.plex_pass + \
              '\r\n------WebKitFormBoundary7MA4YWxkTrZu0gW--'

    headers = {
        'content-type': 'multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW',
        'x-plex-client-identifier': 'orphoto',
        'x-plex-product': 'orphoto-scanner',
        'x-plex-version': '1.0',
        'cache-control': 'no-cache',
    }

    conn.request('POST', '/users/sign_in.json', payload, headers)

    res = conn.getresponse()
    if res.status != 201:
        log_error("Unable to login")
        log_error(res.read().decode('utf-8'))
        sys.exit(1)
    data = res.read()
    datajson = json.loads(data.decode('utf-8'))
    if "user" not in datajson or "authToken" not in datajson["user"]:
        log_error("Unexpected output")
        log_error(datajson)
        sys.exit(1)
    authToken = datajson['user']['authToken']
    conn.close()
    return authToken

def getJson(conn, path, headers):
    conn.request('GET', path, headers=headers)
    res = conn.getresponse()
    if res.status != 200:
        log_error("Unexpected results getting " + path)
        log_error(res.read().decode('utf-8'))
    data = res.read()
    try:
        return json.loads(data.decode('utf-8'))
    except Exception as e:
        print(e)
        print(data.decode('utf-8'))
        sys.exit(1)

def get_video_info(item):
    resolution = 480
    if "Media" not in item or item["Media"] is None or len(item["Media"]) < 1:
        log_error("No media information found for item")
        log_error(item)
        return {}
    primedia = item['Media'][0]
    for media in item['Media']:
        if 'videoResolution' in media and media['videoResolution'] == '4k':
            # resolution = media['videoResolution']
            resolution = 2160
            primedia = media
        elif 'videoResolution' in media and media['videoResolution'] not in ['sd'] and resolution < int(
                media['videoResolution']):
            resolution = int(media['videoResolution'])
            primedia = media
    duration = datetime.timedelta()
    for part in primedia.get('Part', []):
        if 'duration' in part:
            m, s = divmod(part['duration'] / 1000, 60)
            h, m = divmod(m, 60)
            duration += datetime.timedelta(hours=h, minutes=m, seconds=s)
    return {'resolution': str(resolution), 'duration': str(duration)}

def process_movie(item):
    title = item.get('title', None)
    # title = item.get('originalTitle', item.get('title', None))
    # addedAt = datetime.datetime.fromtimestamp(item['addedAt']).isoformat() if 'addedAt' in item else None
    return {'title': title, 'guid': item.get('guid'), **get_video_info(item)}

def process_show(item, conn, headers, sectionTitle):
    alldata = []
    if 'key' in item:
        showchildren = getJson(conn, item['key'], headers)
        if 'MediaContainer' in showchildren and 'Metadata' in showchildren['MediaContainer']:
            for child in showchildren['MediaContainer']['Metadata']:
                childtype = child.get('type')
                if childtype == 'season':
                    if args.summary:
                        alldata.append([child.get('parentTitle'), child.get('index'), child.get('title')])
                    else:
                        alldata.extend(process_season(child, conn, headers))
                else:
                    log_error('!!!! SHOW ' + childtype)
        else:
            log_error('No MediaContainer in item')
            log_error(item)
    else:
        log_error('No key in item')
        log_error(item)
    return alldata

def process_season(season, conn, headers):
    alldata = []
    if 'key' in season:
        seasondetails = getJson(conn, season['key'], headers)
        if "MediaContainer" in seasondetails and "Metadata" in seasondetails.get("MediaContainer"):
            for child in seasondetails['MediaContainer']['Metadata']:
                if child.get('type') == 'episode':
                    addedAt = datetime.datetime.fromtimestamp(child['addedAt']).isoformat() if "addedAt" in child else None
                    item = {
                            'addedAt': addedAt,
                            'show': seasondetails.get('MediaContainer', {}).get('title1'),
                            'season_name': seasondetails.get('MediaContainer', {}).get('title2'),
                            'season': child.get('parentIndex'),
                            'guid': child.get('guid'),
                            'episode_name': child.get('title', "")
                                .replace(' (1)', '')
                                .replace(' (2)', '')
                                .replace(' (3)', '')
                                .replace(' (Part 1)', '')
                                .replace(' (Part 2)', '')
                                .replace(' (Part 3)', ''),
                            'episode': child.get('index', '?'),
                            **get_video_info(child)
                            }
                    alldata.append(remap(item))
                else:
                    log_error('!!!! SEASON ' + child.get('type'))
    else:
        log_error('No key in season')
        log_error(season)
    return alldata

def process_sections(conn, headers):
    sections = getJson(conn, '/library/sections', headers)
    data = []
    if "MediaContainer" in sections and "Directory" in sections["MediaContainer"]:
        for section in sections['MediaContainer']['Directory']:
            if section.get('title') in args.skip_section:
                continue
            if args.type == 'section':
                data.append([section.get('key'), section.get('type'), section.get('title')])
                continue
            if section.get('type') != args.type:
                continue
            if "key" in section:
                alldata = getJson(conn, f'/library/sections/{section["key"]}/all', headers)
                if "MediaContainer" in alldata and 'Metadata' in alldata['MediaContainer']:
                    for item in alldata['MediaContainer']['Metadata']:
                        if item.get('type') == 'movie':
                            data.append(process_movie(item))
                        elif item.get('type') == 'show':
                            newdata = process_show(item, conn, headers, alldata["MediaContainer"].get("title1"))
                            data.extend(newdata)
                        else:
                            pprint.pprint(item)
            else:
                log_error("no key for section")
                log_error(section)
    else:
        log_error('No Directory for sections')
        log_error(sections)
    return data

def summarize_data(data):
    datadict = dict([(x, set()) for x in set([x[0] for x in data])])
    for row in data:
        datadict[row[0]].add(row[1])
    for show, seasons_set in datadict.items():
        seasons = list(seasons_set)
        if len(seasons) == 1:
            datadict[show] = f'{seasons[0]}'
        elif max(seasons) - min(seasons) + 1 == len(seasons):
            datadict[show] = f'{min(seasons)} - {max(seasons)}'
    return [{'show': x, 'seasons': y} for (x, y) in datadict.items()]

headers = {
    'accept': 'application/json',
    'cache-control': 'no-cache',
}
if args.plex_user and args.plex_pass:
    headers['x-plex-token'] = getAuthToken()
data = process_sections(http.client.HTTPConnection(hostname + ':32400'), headers)
if args.summary:
    data = summarize_data(data)

if args.type == 'section':
    print('ID  Type    Name')
    print('--- ------- -----')
    data.sort(key=lambda x: x[0])
    for id, type, name in data:
        print(f'{id:3s} {type:7s} {name}')
else:
    json.dump(data, sys.stdout)
    #pprint.pprint(data)


#!/usr/bin/python
# ! -*- coding: utf8 -*-

import lorun
import os
from signal import alarm, signal, SIGALRM, SIGKILL
from subprocess import PIPE, Popen

RESULT_STR = [
    'Accepted',
    'Presentation Error',
    'Time Limit Exceeded',
    'Memory Limit Exceeded',
    'Wrong Answer',
    'Runtime Error',
    'Output Limit Exceeded',
    'Compile Error',
    'System Error'
]

def run(args, cwd=None, shell=False, kill_tree=True, timeout=-1, env=None):
    '''
    Run a command with a timeout after which it will be forcibly
    killed.
    '''

    class Alarm(Exception):
        pass

    def alarm_handler(signum, frame):
        raise Alarm

    p = Popen(args, shell=shell, cwd=cwd, stdout=PIPE, stderr=PIPE, env=env)
    if timeout != -1:
        signal(SIGALRM, alarm_handler)
        alarm(timeout)
    try:
        stdout, stderr = p.communicate()
        if timeout != -1:
            alarm(0)
    except Alarm:
        pids = [p.pid]
        if kill_tree:
            pids.extend(get_process_children(p.pid))
        for pid in pids:
            # process might have died before getting to this line
            # so wrap to avoid OSError: no such process
            try:
                os.kill(pid, SIGKILL)
            except OSError:
                pass
        return -9, '', ''
    return p.returncode, stdout, stderr

def get_process_children(pid):
    p = Popen('ps --no-headers -o pid --ppid %d' % pid, shell=True,
              stdout=PIPE, stderr=PIPE)
    stdout, stderr = p.communicate()
    return [int(p) for p in stdout.split()]

def compile_src(src_path):
    if run('gcc %s -o m' % src_path, shell=True, timeout=3) != 0:
        print('compile failure!')
        return False
    return True

def runone(p_path, in_path, out_path):
    fin = open(in_path)
    ftemp = open('temp.out', 'w')

    runcfg = {
        'args': ['./m'],
        'fd_in': fin.fileno(),
        'fd_out': ftemp.fileno(),
        'timelimit': 1000,  # in MS
        'memorylimit': 20000,  # in KB
    }

    rst = lorun.run(runcfg)
    fin.close()
    ftemp.close()

    if rst['result'] == 0:
        ftemp = open('temp.out')
        fout = open(out_path)
        crst = lorun.check(fout.fileno(), ftemp.fileno())
        fout.close()
        ftemp.close()
        os.remove('temp.out')
        if crst != 0:
            return {'result': crst}
    return rst

def judge(src_path, td_path, td_total):
    if not compile_src(src_path):
        return
    for i in range(td_total):
        in_path = os.path.join(td_path, '%d.in' % i)
        out_path = os.path.join(td_path, '%d.out' % i)
        if os.path.isfile(in_path) and os.path.isfile(out_path):
            rst = runone('./m', in_path, out_path)
            rst['result'] = RESULT_STR[rst['result']]
            print(rst)
        else:
            print('testdata:%d incompleted' % i)
            os.remove('./m')
            exit(-1)
    os.remove('./m')

if __name__ == '__main__':
    import sys

    if len(sys.argv) != 4:
        print('Usage:%s srcfile testdata_pth testdata_total')
        exit(-1)
    judge('a+b.c', 'testdata', 3)


class test8:
    def __init__(self,a,b,*c):
        self.__a = a
        self.__b = b
        self.__c = list(c)
        print("参数为：",self.__a,self.__b,self.__c)
    def sum_num(self):
        return sum(self.__c) +self.__a+self.__b
    def gai(self,v1,v2):
        self.__a = v1
        self.__b = v2
        return self.__a,self.__b

if __name__ == '__main__':
    test = test8(1,2,3,4,4)
    print("求和结果：",test.sum_num())
    print("a、b重新赋值为：",test.gai(1515,1616))


#!/usr/bin/python3
#
# Fruit2pi Bluetooth keyboard emulation service
# keyboard copy client.
# Reads local key events and forwards them to the btk_server DBUS service
#
import os  # used to all external commands
import sys  # used to exit the script
import dbus
import dbus.service
import dbus.mainloop.glib
import time
import evdev  # used to get input from the keyboard
from evdev import *
import keymap  # used to map evdev input to hid keodes
import selectors
from cbor._cbor import dumps, loads
import socket

programs_dir = os.path.join(sys.path[0], 'programs')

def list_programs():
    global current_program
    return {'programs': os.listdir(programs_dir), 'current_program': current_program['name']}

def edit_program(name, code):
    with open(os.path.join(programs_dir, name), 'w') as f:
        f.write(code)
    return {'status': 'success'}

def delete_programs(names):
    for name in names:
        f = os.path.join(programs_dir, name)
        if os.path.exists(f):
            os.remove(f)
    return {'status': 'success'}

def load_program(name):
    with open(os.path.join(programs_dir, name)) as f:
        program = f.read()
    return {'program': program}

def set_program(name):
    global current_program
    with open(os.path.join(programs_dir, name)) as f:
        program = f.read()
        current_program = {'name': name, 'program': program}
    with open(os.path.join(sys.path[0], 'current_program'), 'w') as f:
        f.write(name)
    return {'status': 'success', 'current_program': name}

def process_command(data):
    try:
        cmds = loads(data)
    except:
        return {'error': 'parse'}
    if type(cmds) != list or not cmds:
        return {'error': 'format'}
    cmd = cmds[0]
    args = cmds[1:]
    if cmd == 'list':
        return list_programs()
    elif cmd == 'edit':
        if len(args) != 2:
            return {'error': 'format'}
        name = args[0]
        code = args[1]
        return edit_program(name, code)
    elif cmd == 'delete':
        if not args:
            return {'error': 'format'}
        return delete_programs(args)
    elif cmd == 'set':
        if len(args) != 1:
            return {'error': 'format'}
        name = args[0]
        return set_program(name)
    elif cmd == 'load':
        if len(args) != 1:
            return {'error': 'format'}
        name = args[0]
        return load_program(name)
    else:
        return {'error': 'format'}

fruit2pi = None
current_program = None

# Define a client to listen to local key events
class Keyboard():

    def __init__(self):
        name = None
        with open(os.path.join(sys.path[0], 'current_program')) as f:
            try:
                name = f.read()
            except:
                name = 'default'
        set_program(name)

        # the structure for a bt keyboard input report (size is 10 bytes)
        self.state = [
            0xA1,  # this is an input report
            0x01,  # Usage report = Keyboard
            # Bit array for Modifier keys
            [0,  # Right GUI - Windows Key
             0,  # Right ALT
             0,  # Right Shift
             0,  # Right Control
             0,  # Left GUI
             0,  # Left ALT
             0,  # Left Shift
             0],  # Left Control
            0x00,  # Vendor reserved
            0x00,  # rest is space for 6 keys
            0x00,
            0x00,
            0x00,
            0x00,
            0x00]

        print("setting up DBus Client")

        self.config_dbus()
        global fruit2pi
        fruit2pi = self
        print("waiting for keyboard")
        # keep trying to key a keyboard
        have_dev = False
        self.scommand = socket.socket(
            socket.AF_BLUETOOTH, socket.SOCK_SEQPACKET, socket.BTPROTO_L2CAP)
        self.scommand.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        self.scommand.bind((socket.BDADDR_ANY, 21))
        self.scommand.listen(5)
        self.scommand.setblocking(False)
        while have_dev == False:
            try:
                # try and get a keyboard - should always be event0 as
                # we're only plugging one thing in
                self.dev = InputDevice("/dev/input/event0")
                have_dev = True
            except OSError:
                print("Keyboard not found, waiting 3 seconds and retrying")
                time.sleep(3)
            print("found a keyboard")

    def config_dbus(self):
        self.bus = dbus.SystemBus()
        self.btkservice = self.bus.get_object(
            'org.fruit2pi.btkbservice', '/org/fruit2pi/btkbservice')
        self.iface = dbus.Interface(self.btkservice, 'org.fruit2pi.btkbservice')

    def change_state(self, event):
        evdev_code = ecodes.KEY[event.code]
        modkey_element = keymap.modkey(evdev_code)

        if modkey_element > 0:
            if self.state[2][modkey_element] == 0:
                self.state[2][modkey_element] = 1
            else:
                self.state[2][modkey_element] = 0
        else:
            # Get the keycode of the key
            hex_key = keymap.convert(ecodes.KEY[event.code])
            # Loop through elements 4 to 9 of the inport report structure
            for i in range(4, 10):
                if self.state[i] == hex_key and event.value == 0:
                    # Code 0 so we need to depress it
                    self.state[i] = 0x00
                elif self.state[i] == 0x00 and event.value == 1:
                    # if the current space if empty and the key is being pressed
                    self.state[i] = hex_key
                    break
        return self.state

    # poll for keyboard events
    def event_loop(self):
        sel = selectors.DefaultSelector()
        def do_kbd_ev(fd, mask):
            for event in self.dev.read():
                if event.type == ecodes.EV_KEY and event.value < 2:
                    event = self.change_state(event)
                    eval(compile(current_program['program'], current_program['name'], 'exec'))
        def do_cmd(conn, mask):
            data = conn.recv(65535)  # Should be ready
            if data:
                resp = process_command(data)
                conn.send(dumps(resp))
            else:
                print('closing', conn)
                sel.unregister(conn)
                conn.close()
        def do_cmd_conn(sock, mask):
            self.ccommand, cinfo = sock.accept()
            self.ccommand.setblocking(False)
            print (
                "\033[0;32mGot a connection on the command port from %s \033[0m" % cinfo[0])
            sel.register(self.ccommand, selectors.EVENT_READ, do_cmd)
        sel.register(self.dev.fd, selectors.EVENT_READ, do_kbd_ev)
        sel.register(self.scommand, selectors.EVENT_READ, do_cmd_conn)
        global current_program
        while True:
            try:
                events = sel.select()
                for key, mask in events:
                    callback = key.data
                    callback(key.fileobj, mask)
            except dbus.DBusException as e:
                print('A dbus error occurred:', file=sys.stderr)
                print(e.__repr__(), file=sys.stderr)
                print('reconfig dbus', file=sys.stderr)
                self.config_dbus()
            except BaseException as e:
                print('An error occurred:', file=sys.stderr)
                print(e.__repr__(), file=sys.stderr)
                print(e, file=sys.stderr)

    # forward keyboard events to the dbus service
    def send(self, event):
        bin_str = ""
        state = event
        print(*state)
        element = state[2]
        for bit in element:
            bin_str += str(bit)
        self.iface.send_key(int(bin_str, 2), self.state[4:10])

if __name__ == "__main__":
    print("Setting up keyboard")
    kb = Keyboard()

    print("starting event loop")
    kb.event_loop()


import asyncio
from concurrent.futures import Executor
from multiprocessing import Pool, cpu_count
from typing import Any, Callable, Set, Tuple, TypeVar

from .compat import EventLoopMixin
from .counters import Statistic
from .utils import set_exception

T = TypeVar("T")
FuturesSet = Set[asyncio.Future]
_CreateFutureType = Tuple[
    Callable[[T], None],
    Callable[[T], None],
    asyncio.Future,
]

class ProcessPoolStatistic(Statistic):
    processes: int
    done: int
    error: int
    success: int
    submitted: int
    sum_time: float

class ProcessPoolExecutor(Executor, EventLoopMixin):
    __slots__ = (
        "__futures", "__pool", "_statistic",
    ) + EventLoopMixin.__slots__

    DEFAULT_MAX_WORKERS = max((cpu_count(), 4))

    def __init__(self, max_workers: int = DEFAULT_MAX_WORKERS, **kwargs: Any):
        self.__futures = set()      # type: FuturesSet
        self.__pool = Pool(processes=max_workers, **kwargs)
        self._statistic = ProcessPoolStatistic()
        self._statistic.processes = max_workers

    def _create_future(self) -> _CreateFutureType:
        future = self.loop.create_future()  # type: asyncio.Future

        self.__futures.add(future)
        future.add_done_callback(self.__futures.remove)
        start_time = self.loop.time()

        def callback(result: T) -> None:
            self._statistic.success += 1
            self._statistic.done += 1
            self._statistic.sum_time += self.loop.time() - start_time
            self.loop.call_soon_threadsafe(future.set_result, result)

        def errorback(exc: T) -> None:
            self._statistic.error += 1
            self._statistic.done += 1
            self._statistic.sum_time += self.loop.time() - start_time
            self.loop.call_soon_threadsafe(future.set_exception, exc)

        return callback, errorback, future

    def submit(           # type: ignore
        self, fn: Callable[..., T],
        *args: Any, **kwargs: Any,
    ) -> asyncio.Future:
        """
        Submit blocking function to the pool
        """
        if fn is None or not callable(fn):
            raise ValueError("First argument must be callable")

        callback, errorback, future = self._create_future()

        self.__pool.apply_async(
            fn,
            args=args,
            kwds=kwargs,
            callback=callback,
            error_callback=errorback,
        )

        self._statistic.submitted += 1
        return future

    # noinspection PyMethodOverriding
    def shutdown(self, wait: bool = True) -> None:  # type: ignore
        if not self.__pool:
            return

        self.__pool.terminate()

        set_exception(self.__futures, asyncio.CancelledError())

        if wait:
            self.__pool.join()

        self.__pool.close()

    def __del__(self) -> None:
        self.shutdown()


"""Cédulas"""
valor = float(input())

cedula = 0
atual = 100.00
apagar = valor

print(int(valor))
while True:
    if(atual == 0):
        break
    if atual < apagar:
        apagar-=atual
        cedula+=1

    else:

        print (str("%d nota(s) de R$ %.2f" %(cedula, atual)).replace('.',','))

        if apagar == 0:
            break
        if atual == 100:
            atual = 50
        elif atual == 50:
            atual = 20
        elif atual == 20:
            atual = 10
        elif atual == 10:
            atual = 5
        elif atual ==5:
            atual = 2
        elif atual ==2:
            atual =1
        elif atual ==1:
            atual=0
        cedula = 0