import numpy as np
import h5py
import sys
import os
import scipy
from scipy import integrate
import shutil
import itertools
import argparse

## Camera geodesic evaluations

def GetCameraData(p):
    """ Get data about geodesic positions and fates
        in the plane of the camera """

    file = p + '/RefinementMethodData.h5'
    f = h5py.File(file, 'r')
    data = f['LensingCore.dat']

    tags = data[:,0]
    tags = tags.astype(int)
    x_pos = data[:,1]
    y_pos = data[:,2]
    surface = data[:,4]

    return tags, x_pos, y_pos, surface

def GrabSurfaceIndices(surface, fate):

    i = np.where(surface == fate)[0]
    return i

def SelectCameraGeodesics(p, fate):

    tags, x_pos, y_pos, surface = GetCameraData(p)

    i = np.where(surface == fate)[0]

    return tags[i], x_pos[i], y_pos[i], surface[i]

def GetInfinityGeodesics(p):
    """
    inf = np.where(surface == 1.)[0]
    infty = np.where(surface == 7.)[0]
    aha = np.where(surface == 2.)[0]
    ahb = np.where(surface == 3.)[0]
    ahc = np.where(surface == 4.)[0]
    """
    file = p + '/RefinementMethodData.h5'
    f = h5py.File(file, 'r')
    data = f['LensingCore.dat']
    surface = data[:,4]
    return GrabSurfaceIndices(surface, 7)

def GetCameraPosition(p):
    p = p.split('Trace')[1]
    x = p.split('_')[1]
    y = p.split('_')[2]
    z = p.split('_')[3]
    return '[' + x + ',' + y + ',' + z + ']'

def GetTime(p):
    p = p.split('Trace')[1]
    t = p.split('_')[4]
    t = t.split('/')[0]
    return t

## Geodesic data processing

def ReadGeodesicData(p, t_start, t_end):
    """ Read in an array of times and positions for all geodesics at once,
        and return the trajectories indexed by geodesic """

    def AppendGeodesicsTime(Lev):

        print("\n Reading Geodesic data for " + Lev)

        ## Use the first segement to grab the number of geodesics
        file = p + '/' + Lev + '/Run_AA/Run/Node0.h5'
        f = h5py.File(file, 'r')
        ## grab the .dat files
        keys = [k for k in f.keys() if 'dat' in k]
        ## Array of times from the .dat files
        times = [float(k.split('.dat')[0]) for k in keys]
        ## sort keys according to times
        times, keys = zip(*sorted(zip(times, keys)))
        # grab the number of geodesics
        N_geodesics = len(f[keys[-1]][:,0])
        print("Total geodesics: ", N_geodesics, "Time steps: ", len(times))
        ## Minimum index
        m = int(sorted(f[keys[-1]][:,0])[0])
        print("Geodesic index offset of this refinement iteration: ", m)

        ## Now make the arrays

        X = [ [] for _ in range(N_geodesics)]
        Y = [ [] for _ in range(N_geodesics)]
        Z = [ [] for _ in range(N_geodesics)]
        L = [ [] for _ in range(N_geodesics)]
        T = [ [] for _ in range(N_geodesics)]

        Segments = [el for el in os.listdir(p + '/' + lev) if "Run" in el][::-1]
        print(lev + " Segments:", Segments)

        for segment in Segments:

            print("\n Working on segment " + segment)

            file = p + '/' + Lev + '/' + segment + '/Run/Node0.h5'
            f = h5py.File(file, 'r')
            ## grab the .dat files
            keys = [k for k in f.keys() if 'dat' in k]
            ## Array of times from the .dat files
            times = [float(k.split('.dat')[0]) for k in keys]
            ## sort keys according to times
            times, keys = zip(*sorted(zip(times, keys)))

            print("Going to go through the keys and the times")
            for k, t in zip(keys, times):
                ## Check that time is within the bounds
                if ((t > t_start) and (t < t_end)):
                    ## Check that time is printed at the correct interval
                    if ((t % 0.1 == 0.0) or (abs(t % 0.1 - 0.09999999999999) < 1e-9)):
                        print("%.1f  " % t, end = '', flush=True)
                        data = f[k]
                        ## indices and positions for all geodesics at this time
                        indices = data[:,0]
                        if (len(data[0]) == 7):
                            """ If we've run the numerical evolution so that we haven't
                                evolved lapse p0 -- just set lapsep0 to 1 in the files.
                                This field need to be in the resulting .dat file for the
                                paraview trajectory visualization"""
                            x = data[:,4]
                            y = data[:,5]
                            z = data[:,6]
                            l = np.ones(len(x))
                        elif (len(data[0]) == 8):
                            """ If we have evolved lapse p0"""
                            l = data[:,1]
                            x = data[:,5]
                            y = data[:,6]
                            z = data[:,7]
                        else:
                            print("Unrecognized number of variables")
                        ## fill in the array for each index
                        for i, j in zip(indices.astype(int), range(len(indices))):
                            X[i-m] = np.append(X[i-m], x[j])
                            Y[i-m] = np.append(Y[i-m], y[j])
                            Z[i-m] = np.append(Z[i-m], z[j])
                            L[i-m] = np.append(L[i-m], l[j])
                            T[i-m] = np.append(T[i-m], t)

        print("\n")
        ## Once we have the arrays constructed, append them to the file
        print('Read the geodesic data, now writing the files')

        hf = h5py.File(p + '/Trajectories.h5', 'a')
        print(p)

        for a in range(len(T)):
            if (len(T[a]) > 1):
                my_data = np.c_[T[a],X[a],Y[a],Z[a],L[a]]
                ## Remember to add in the minimum index since the starting
                ## geodesic index just gets incremented during reach refinement
                ## level (by the number of geodesics that came from the levels before)
                ## Hence a + m
                hf.create_dataset('Geodesic' + str(a+m) + '.dat', data=my_data)

        hf.close()

        print('Finished writing the files')

    ## Go through the refinement levels and the segments
    RefinementLevs = [el for el in os.listdir(p) if "Lev" in el]
    print("RefinementLevs:", RefinementLevs)
    for lev in RefinementLevs:

        AppendGeodesicsTime(lev)

def MakeGeodesicDatFiles(p, t_start, t_end):
    """ Print the result of ReadGeodesicData to files """
    ReadGeodesicData(p, t_start, t_end)

def GetGeodesicTrajectory(p, n):
    """ Read in the post-processed trajectory for the nth geodesic """
    f = p + '/Trajectories.h5'
    hf = h5py.File(f, 'r')
    data = hf['Geodesic' + str(n) + '.dat']
    t = data[:,0]
    x = data[:,1]
    y = data[:,2]
    z = data[:,3]
    hf.close()
    ## Make sure the times are sorted
    t, x, y, z = zip(*sorted(zip(t, x, y, z)))
    t = np.array(t)
    x = np.array(x)
    y = np.array(y)
    z = np.array(z)
    # Former method of reading in
    #t, x, y, z, lapse = np.loadtxt(f, comments="#",usecols=([0,1,2,3,4]),unpack=True)
    return t, x, y, z

def WriteGeodesicTrajectoryDatFile(p, n):
    """ Print the post-processed trajectory for the nth geodesic
        to a .dat file """

    t, x, y, z = GetGeodesicTrajectory(p, n)
    ## Fake lapse array
    lapse = np.ones(len(t))
    ff = open(p + '/' + str(n) + '.dat', 'w')
    np.savetxt(ff, np.c_[t,x,y,z,lapse])
    ff.close()

def GetGeodesicIndices(p, infinity=False):
    """ Return the indices of all of the geodesics we have printed to file
        If infinity == True, only returnt the geodesics that make it out to infinity """
    f = p + '/Trajectories.h5'
    hf = h5py.File(f, 'r')
    Indices = [int(k.split('Geodesic')[1].split('.dat')[0]) for k in hf.keys()]
    Indices = sorted(Indices)
    if infinity:
        indices_infinity = GetInfinityGeodesics(p)
        Indices = list(set(indices_infinity) & set(Indices))
    return Indices

## Zero crossings computations

def ComputeZeroCrossings(p, n):
    """ Compute the number of zero crossings in the y-z plane -
        useful for head-on runs where the collision happens
        along the x axis """
    t, x, y, z = GetGeodesicTrajectory(p, n)
    theta = np.arctan2(z, y)
    zero_crossings = len(np.where(np.diff(np.sign(theta)))[0])
    return zero_crossings

def MakeZeroCrossingsFile(p):
    """ Make a file with the format [geodesic index, number of zero crossings] so
        that we only have to compute the number of zero crossings once """
    ns = GetGeodesicIndices(p)
    crossings = [ComputeZeroCrossings(p, n) for n in ns]
    np.savetxt(p + 'ZeroCrossings.dat', np.c_[ns, crossings], fmt = '%d %d')

def GetGeodesicsZeroCrossings(p):
    """ Return the zero crossings for each index """
    f = p + 'ZeroCrossings.dat'
    ns, zero_crossings = np.loadtxt(f, comments="#",usecols=([0,1]),unpack=True,dtype=int)
    return ns, zero_crossings

def GetGeodesicsZeroCrossingsIndices(p, N, infinity=False):
    """ Return the indices of the geodesics that make N zero-crossings
        If infinity == True, return only the ones that make it to infinity"""
    ns, zero_crossings = GetGeodesicsZeroCrossings(p)
    indices = ns[np.where(zero_crossings == N)[0]]
    if infinity:
        indices_infinity = GetInfinityGeodesics(p)
        indices = list(set(indices_infinity) & set(indices))
    return indices

def GetGeodesicsZeroCrossingsIndicesGreater(p, N, infinity=False):
    """ Return the indices of the geodesics that make N or more zero-crossings
        If infinity == True, return only the ones that make it to infinity"""
    ns, zero_crossings = GetGeodesicsZeroCrossings(p)
    indices = ns[np.where((zero_crossings >= N))[0]]
    if infinity:
        indices_infinity = GetInfinityGeodesics(p)
        indices = list(set(indices_infinity) & set(indices))
    return indices

def GetGeodesicsMaxZeroCrossings(p, infinity=False):
    """ Return the maximum number N of zero crossings for a given run,
        along with the indices of the geodesics that make N zero-crossings
        If infinity == Ture, only return the ones that make it to infinity"""
    ns, zero_crossings = GetGeodesicsZeroCrossings(p)
    max_N = max(zero_crossings)
    indices = GetGeodesicsZeroCrossingsIndices(p, max_N, infinity=infinity)
    return max_N, indices

## X Turns computations

def ComputeXTurns(p, n):
    """ Compute tbe number of turns a geodesic makes along the x direction
        Useful for head-on runs where the collision happens along the x axis"""
    print(n, end=' ')
    t, x, y, z = GetGeodesicTrajectory(p, n)
    x_diff = x[1:] - x[:-1]
    turns = len(list(itertools.groupby(x_diff, lambda x_diff: x_diff > 0)))
    ## Set to zero turns if the trajectory does not change in x - these end up being
    ## artifical turns hovering around zero (and unresolved)
    if np.max(np.abs(x)) < 1e-3:
        turns = 0
    return turns

def MakeXTurnsFile(p):
    """ Make a file with the format [geodesic index, number of X turns] so
        that we only have to compute the number of X turns once """
    ns = GetGeodesicIndices(p)
    print('TOTAL NUMBER: ', str(len(ns)))
    turns = [ComputeXTurns(p, n) for n in ns]
    np.savetxt(p + '/XTurns.dat', np.c_[ns, turns], fmt = '%d %d')
    print('Wrote the file')

def GetGeodesicsXTurns(p):
    """ Return the x turns for each index """
    f = p + 'XTurns.dat'
    ns, turns = np.loadtxt(f, comments="#",usecols=([0,1]),unpack=True,dtype=int)
    return ns, turns

def GetGeodesicsXTurnsIndices(p, N, infinity=False):
    """ Return the indices of the geodesics that make N x turns
        If infinity == True, return only the ones that make it to infinity"""
    ns, turns = GetGeodesicsXTurns(p)
    indices = ns[np.where(turns == N)[0]]
    if infinity:
        indices_infinity = GetInfinityGeodesics(p)
        indices = list(set(indices_infinity) & set(indices))
    return indices

def GetGeodesicsXTurnsIndicesGreater(p, N, infinity=False, N_less = 1e6):
    """ Return the indices of the geodesics that make N or more x turns
        If infinity == True, return only the ones that make it to infinity"""
    ns, turns = GetGeodesicsXTurns(p)
    indices = ns[np.where(turns >= N)[0]]
    indices_less = ns[np.where(turns <= N_less)[0]]
    indices = list(set(indices) & set(indices_less))
    if infinity:
        indices_infinity = GetInfinityGeodesics(p)
        indices = list(set(indices_infinity) & set(indices))
    return indices

def GetGeodesicsMaxXTurns(p, infinity=False):
    """ Return the maximum number N of zero crossings for a given run,
        along with the indices of the geodesics that make N zero-crossings
        If infinity == Ture, only return the ones that make it to infinity"""
    f = p + 'ZeroCrossings.dat'
    ns, turns = GetGeodesicsXTurns(p)
    max_N = max(turns)
    indices = GetGeodesicsXTurnsIndices(p, max_N, infinity=infinity)
    return max_N, indices

## Frenet-Serret computations

def ComputeArcLength(t, x, y, z):
    """ For a given trajectory {x(t), y(t), z(t)}, compute and return
        the arclength s(t) as a function of time"""
    dx = np.gradient(x, t)
    dy = np.gradient(y, t)
    dz = np.gradient(z, t)

    ## Compute the magnitude
    mag = np.sqrt(dx**2 + dy**2 + dz**2)

    ## Take a running integral
    s = integrate.cumtrapz(mag, t, initial = 0.0)

    ## check that s(t) is monotonically increasing
    check = np.where((s[1:] - s[:-1]) <= 0.0)[0]
    if len(check) > 0:
        print("s(t) is non-monotonically increasing!")

    return s

def ComputeFrenetSerretTNB(t, x, y, z):
    s = ComputeArcLength(t, x, y, z)

    T_x = np.gradient(x, s)
    T_y = np.gradient(y, s)
    T_z = np.gradient(z, s)

    T_mag = np.sqrt(T_x**2 + T_y**2 + T_z**2)

    T_x = T_x / T_mag
    T_y = T_y / T_mag
    T_z = T_z / T_mag

    dTds_x = np.gradient(T_x, s)
    dTds_y = np.gradient(T_y, s)
    dTds_z = np.gradient(T_z, s)

    dTds_mag = np.sqrt(dTds_x**2 + dTds_y**2 + dTds_z**2)

    N_x = dTds_x / dTds_mag
    N_y = dTds_y / dTds_mag
    N_z = dTds_z / dTds_mag

    B_x = T_y * N_z - T_z * N_y
    B_y = - T_x * N_z + T_z * N_x
    B_z = T_x * N_y - T_y * N_x

    kappa = dTds_mag ## curvature

    return T_x, T_y, T_z, N_x, N_y, N_z, B_x, B_y, B_z, kappa

def MakeFrenetSerretDatFiles(p):
    """ For all geodesics .dat files in a given directory, dump the Frenet-Serret Frame
        data (so we only have to compute it once)"""
    ns = GetGeodesicIndices(p)
    for n in ns:
        t, x, y, z = GetGeodesicTrajectory(p, n)
        t, x, y, z = zip(*sorted(zip(t, x, y, z)))
        T_x, T_y, T_z, N_x, N_y, N_z, B_x, B_y, B_z, kappa = ComputeFrenetSerretTNB(t, x, y, z)
        np.savetxt(p + '/FrenetSerret/' + str(n) + '.dat', np.c_[t, kappa, T_x, T_y, T_z, \
                                                                        N_x, N_y, N_z, \
                                                                        B_x, B_y, B_z])

def GetFrenetSerretVectors(p, n):
    """ Read in the post-processed trajectory for the nth geodesic """
    f = p + '/FrenetSerret/' + str(n) + '.dat'
    t, kappa, T_x, T_y, T_z, N_x, N_y, N_z, B_x, B_y, B_z \
        = np.loadtxt(f, comments="#",usecols=(range(11)),unpack=True)
    return t, kappa, T_x, T_y, T_z, N_x, N_y, N_z, B_x, B_y, B_z

def GetFrenetSerretCurvature(p, n):
    """ Read in the post-processed curvature for the nth geodesic """
    f = p + '/FrenetSerret/' + str(n) + '.dat'
    t, kappa = np.loadtxt(f, comments="#",usecols=([0,1]),unpack=True)
    return t, kappa

def MakeMaxCurvatureFile(p):
    """ Make file constraining the geodesic ID, the maximum value of the curvature,
        and the x, y, z, coordinates of this point"""
    ns = GetGeodesicIndices(p)
    N = len(ns)
    MaxKappa = np.zeros(N)
    T = np.zeros(N)
    X = np.zeros(N)
    Y = np.zeros(N)
    Z = np.zeros(N)

    for i in range(N):
        n = ns[i]
        t, x, y, z = GetGeodesicTrajectory(p, n)
        time, kappa = GetFrenetSerretCurvature(p, n)
        index = np.argmax(kappa)
        MaxKappa[i] = kappa[index]
        T[i] = t[index]
        X[i] = x[index]
        Y[i] = y[index]
        Z[i] = z[index]

    np.savetxt(p + '/MaxCurvatures.dat', np.c_[ns, MaxKappa, T, X, Y, Z], fmt = '%d %f %f %f %f %f')

def main():

    p = argparse.ArgumentParser(description="Post-process geodesics evolution data")
    p.add_argument("--dir", required=True, \
           help="Root directory of geodesic evolution data to post-process")
    p.add_argument("--trajectories", help='Post-process the trajectories', \
        dest='trajectories', action='store_true')
    p.add_argument("--zerocrossings", help='Post-process the zero-crossings', \
        dest='zerocrossings', action='store_true')
    p.add_argument("--xturns", help='Post-process the x-turns', \
        dest='xturns', action='store_true')
    p.add_argument("--frenetserret", help='Perform the Frenet-Serret analysis', \
        dest='frenetserret', action='store_true')

    p.set_defaults(trajectories=False)
    p.set_defaults(zerocrossings=False)
    p.set_defaults(xturns=False)
    p.set_defaults(frenetserret=False)

    args = p.parse_args()

    print("Processing geodesics for " + args.dir)

    ## Make geodesic dat files
    if (args.trajectories):
        print("Making the geodesic trajectory file")
        try:
            os.remove(args.dir + '/Trajectories.h5')
            print("Removed previous Trajectories.h5 file")
        except:
            print("Trajectories.h5 file did not previously exist")
        MakeGeodesicDatFiles(args.dir, 0, 10000)

    ## Compute zero crossings
    if (args.zerocrossings):
        print("Computing zero crossings")
        MakeZeroCrossingsFile(args.dir)

    ## Compute x turns
    if (args.xturns):
        print("Computing x turns")
        MakeXTurnsFile(args.dir)

    ## Compute Frenet-Serret
    if (args.frenetserret):
        print("Computing Frenet-Serret")
        try:
            os.mkdir(p + '/FrenetSerret')
        except:
            print("FrenetSerret directory already exists")
        MakeFrenetSerretDatFiles(p)
        print("Computing max curvatures")
        MakeMaxCurvatureFile(p)

if __name__ == "__main__":
    main()


from scipy.signal import butter, lfilter

def butterworth(lowcut, highcut, fs, order=5):
    """
    Function for applying butterworth filter to a signal.

    Wiki: The Butterworth filter is a type of signal processing filter designed to have a frequency response
            as flat as possible in the passband. It is also referred to as a maximally flat magnitude filter.

    :param lowcut:
    :param highcut:
    :param fs:
    :param order:
    :return:
    """
    nyq = 0.5 * fs
    low = lowcut / nyq
    high = highcut / nyq
    b, a, c = butter(order, [low, high], btype='band')
    return b, a


import socket
from sys import argv

# Creditos:Alameda
"""
Adicionei o 'getservbyport' para informa qual eh versao da porta que esta aberta na maquina do alvo
"""

# uso try e except pra capturar o erro e informa ao usuario modo de uso do script
# try e except eh usado para capturar e manipular excecoes
# try age na parte "normal" do programa. Codigo except eh a resposta do programa a qual quer erro

try:
	# faco um range pra regar portas do 1 ate 65535 "Limite de porta eh ate 65535"
	for porta in range(1,65535):
		# Faco um socket de tcp
		c = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
		c.settimeout(0.1) #  Uso settimeout para nao fica esperando muito tempo se porta nao da resultado de = 0
		if c.connect_ex((argv[1],porta)) == 0: # Verifico se a conexao do alvo e porta da igual 0, se for igual 0 eh por que esta aberta
			print(f"PORTA: {porta} {socket.getservbyport(porta)} ABERTA [+]") # Imprimo na tela
except Exception as Error: # Uso except pra mostra na tela o erro e mensagem do uso do script pro usuario
	print("Scanner De Portas\nModo de uso python3 script www.url.com\nSaida do erro >> ",Error," <<")


from workflow.customworkflow import customworkflow
import pygraphviz

def plotPNG():
	graph = pygraphviz.AGraph( directed = True, strict = False )
	for state in customworkflow.ALL_STATES:
		graph.add_node( state.name, shape = state.plotShape )
	for state in customworkflow.ALL_STATES:
		for transition in state.transitions():
			graph.add_edge( state.name, transition.targetState, label = transition.name )
		for spawnChild in state.spawnChilds:
			graph.add_edge( state.name, spawnChild.childState, label = spawnChild.name, style = 'dotted' )
	graph.layout( 'dot' )
	return graph.draw( path = None, format = "png" )

if __name__ == "__main__":
	open( "/tmp/test.png", "wb" ).write( plotPNG() )


#!/usr/bin/python

# Test some issues report in #254

# Github issue: #254
# Author: j123123

from keystone import *

import regress

class TestX86(regress.RegressTest):
    def runTest(self):
        # Initialize Keystone engine
        ks = Ks(KS_ARCH_X86, KS_MODE_64)

        encoding, _ = ks.asm(b"mov [rax+rsp], rsi")
        self.assertEqual(encoding, [ 0x48, 0x89, 0x34, 0x04 ])

        encoding, _ = ks.asm(b"mov [rsp+rax], rsi")
        self.assertEqual(encoding, [ 0x48, 0x89, 0x34, 0x04 ])

if __name__ == '__main__':
    regress.main()


from utils.db import db
import datetime as dt

class Project(db.Model):
    codigo = db.Column(db.Integer, primary_key=True)
    id_cliente = db.Column(db.Integer)
    id_producto = db.Column(db.Integer)
    version = db.Column(db.String(10))
    customizacion = db.Column(db.String(60))
    nombre = db.Column(db.String(60))
    fecha_inicio = db.Column(db.DateTime())
    fecha_fin_estimada = db.Column(db.DateTime(), default=None)
    estado = db.Column(db.Integer)
    horas_consumidas = db.Column(db.Integer, default=0)
    costo_estimado = db.Column(db.Integer)
    ultima_tarea = db.Column(db.Integer, default=0)

    def __init__(self, data):
        self.id_cliente = data["id_cliente"]
        self.id_producto = data["id_producto"]
        self.version = data["version"]
        self.customizacion = data["customizacion"]
        self.nombre = data["nombre"]
        self.estado = data["estado"]
        self.costo_estimado = data["costo_estimado"]
        if "fecha_fin_estimada" in list(data.keys()) and data["fecha_fin_estimada"]:
            self.fecha_fin_estimada = dt.datetime.strptime(
                data["fecha_fin_estimada"], "%Y-%m-%dT%H:%M:%S.%fZ"
            )
        self.fecha_inicio = dt.datetime.strptime(
            data["fecha_inicio"], "%Y-%m-%dT%H:%M:%S.%fZ"
        )

    def update_data(self, data):
        # self.id_cliente = data["id_cliente"]
        # self.id_producto = data["id_producto"]
        # self.version = data["version"]
        # self.customizacion = data["customizacion"]
        self.nombre = data["nombre"]
        self.estado = data["estado"]
        self.horas_consumidas = data["horas_consumidas"]
        self.costo_estimado = data["costo_estimado"]
        self.fecha_inicio = data["fecha_inicio"]
        if "fecha_fin_estimada" in list(data.keys()) and data["fecha_fin_estimada"]:
            self.fecha_fin_estimada = dt.datetime.strptime(
                data["fecha_fin_estimada"], "%Y-%m-%dT%H:%M:%S.%fZ"
            )

    def to_dict(self):
        return {
            "codigo": self.codigo,
            "id_cliente": self.id_cliente,
            "id_producto": self.id_producto,
            "version": self.version,
            "customizacion": self.customizacion,
            "nombre": self.nombre,
            "fecha_inicio": self.fecha_inicio.strftime("%Y-%m-%dT%H:%M:%S.%fZ"),
            "fecha_fin_estimada": self.fecha_fin_estimada.strftime(
                "%Y-%m-%dT%H:%M:%S.%fZ"
            )
            if self.fecha_fin_estimada
            else None,
            "estado": self.estado,
            "horas_consumidas": self.horas_consumidas,
            "costo_estimado": self.costo_estimado,
            "ultima_tarea": self.ultima_tarea,
        }


from flask_wtf import Form #, RecaptchaField
from wtforms import StringField, PasswordField, SubmitField, SelectField, TextAreaField, RadioField, IntegerField
from application.treasure_mod.models import Treasure
from application.clue_mod.models import Clue
from wtforms.validators import DataRequired

class ClueForm(Form):
    """
    clue add and edit form
    """
    treasure_id = SelectField(
        'Treasure',
        choices=Treasure.get_clue_treasures(),
        validators = [DataRequired()]
    )
    description = TextAreaField(
        'Description',
        validators = [DataRequired()]
    )
    startpoint = RadioField(
        'Startpoint',
         choices=[('True', 'Yes'), ('False', 'No')]
    )
    endpoint = RadioField(
        'Endpoint',
        choices=[('True', 'Yes'), ('False', 'No')]
    )
    marker_pos = StringField(
        'Clue Coordinates',
        validators=[DataRequired()]
    )
    is_correct = RadioField(
        'Is this path correct',
         choices=[('True', 'Yes'), ('False', 'No')]
    )
    is_bonus = RadioField(
        'Bonus path',
         choices=[('True', 'Yes'), ('False', 'No')]
    )
    slug = StringField(
        'Clue slugs',
        validators=[DataRequired()]
    )
    submit = SubmitField('Submit')

class ClueOptionForm(Form):
    """
    clue options
    """
    clue_id = SelectField(
        'Clue',
        choices=Clue.get_option_clues(),
        validators = [DataRequired()]
    )
    name = StringField(
        'Name',
        validators = [DataRequired()]
    )
    slug = StringField(
        'Slug',
        validators = [DataRequired()]
    )
    coordinates = StringField(
        'Map Coordinates',
        validators = [DataRequired()]
    )
    points = IntegerField(
        'Points',
        validators = [DataRequired()]
    )
    is_correct = RadioField(
        'Is this point correct',
        choices = [(True, 'True'), (False, 'False')]
    )

    submit = SubmitField('Submit')


from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker

# Define your MySQL connection string
# Replace 'username', 'password', 'hostname', and 'database' with your actual values
db_uri = 'mysql+pymysql://aashish:Aashish%4099@localhost/endurunz'

# Create a SQLAlchemy engine
engine = create_engine(db_uri)

SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)

Base = declarative_base()

# Dependency to get the database session
def get_db():
    db = SessionLocal()
    try:
        yield db
    finally:
        db.close()


'''
Author: philosophylato
Date: 2022-10-01 21:21:27
LastEditors: philosophylato
LastEditTime: 2022-10-01 21:24:35
Description: your project
version: 1.0

'''
def removeElement(nums,val):
    n=len(nums)
    i=-1
    j=0
    while j<=n-1:
        if nums[j] != val:
            i+=1
            nums[i]=nums[j]
        j+=1
    return i+1


# List Comprehension(리스트를 만드는 쉬운 방법들)
# append 시킬 변수 선언 x
# []에 한 줄로 조건절 넣기

numbers = []

# 일반적인 방법
# for n in range(1 ,101) :
#     numbers.append(n)
# print(numbers)

# 리스트 컴프리헨션
numbers2 = [x for x in range(1, 101)]
print(numbers2)

# 응용
# 다음 리스트 중에서 '정' 글자를 제외하고 출력하세요.
q3 = ["갑", "을", "병", "정"]
# q3.remove(q3[3])
# for i in q3 :
#     print(i, end=' ')
# print()
print([x for x in q3 if x != "정"])


import os

import numpy as np
from tqdm import tqdm

class SearchEvaluator:
    def __init__(self, metrics):
        self.metrics = metrics

    @staticmethod
    def precision_at_k(relevant, k):
        return sum(relevant[:k]) / k

    @staticmethod
    def mean_reciprocal_rank(relevant):
        for idx, value in enumerate(relevant):
            if value == 1:
                return 1 / (idx + 1)
        return 0

    @staticmethod
    def calculate_average_precision(relevant):
        pred_rel = [1] * len(relevant)
        relevant_documents_count = 0
        cumulative_precision = 0.0

        # We iterate through the predicted relevance scores
        for i in range(len(pred_rel)):
            # Check if the prediction at this rank is correct (i.e., if it is a relevant document)
            if pred_rel[i] == 1 and relevant[i] == 1:
                relevant_documents_count += 1
                precision_at_i = relevant_documents_count / (i + 1)
                cumulative_precision += precision_at_i

        # The average precision is the cumulative precision divided by the number of relevant documents
        average_precision = cumulative_precision / sum(relevant) if sum(relevant) > 0 else 0
        return average_precision

    # @staticmethod
    # def calculate_recall(relevant, total_modified_files, k):
    #   # Does not work for commit based approach as it can have multiple mentions of the same file across commits leading to a higher than 1 recall
    #     print(total_modified_files)
    #     print(relevant)
    #     return sum(relevant[:k]) / total_modified_files

    @staticmethod
    def calculate_recall(retrieved_files, actual_modified_files, relevant, k):
        # this complicated mess is required as compared to the above much simpler code to support both commit-based and file-based approaches
        # in file-based approach, this is equivalent to the above code
        # in code-based approach, duplicates could be present in retrieved_files, which is why we need to filter them out (the above code would not work in this case)

        return len({file for idx, file in enumerate(retrieved_files[:k])
                        if relevant[idx] == 1
                    }) / len(actual_modified_files) if len(actual_modified_files) > 0 else 0

    def evaluate(self, search_results, actual_modified_files):
        retrieved_files = [result.file_path for result in search_results]
        relevant = [1 if file in actual_modified_files else 0 for file in retrieved_files]

        evaluations = {}
        for metric in self.metrics:
            if metric == 'MAP':
                evaluations[metric] = self.calculate_average_precision(relevant)
            elif metric == 'MRR':
                evaluations[metric] = self.mean_reciprocal_rank(relevant)
            elif metric.startswith('P@'):
                k = int(metric.split('@')[1])
                evaluations[metric] = self.precision_at_k(relevant, k)
            elif metric.startswith('Recall@'):
                k = int(metric.split('@')[1])
                evaluations[metric] = self.calculate_recall(retrieved_files, actual_modified_files, relevant, k)

        return {k: round(v, 4) for k, v in evaluations.items()}

class ModelEvaluator:
    def __init__(self, model, eval_model, combined_df, seed=42):
        self.model = model
        self.eval_model = eval_model
        self.combined_df = combined_df
        self.seed = seed

    def sample_commits(self, n):
        if self.combined_df.commit_id.nunique() < n:
            raise ValueError(f'Not enough commits to sample. Required: {n}, available: {self.combined_df.commit_id.nunique()}')

        midpoint_date = np.median(self.combined_df['commit_date'])
        recent_df = self.combined_df[self.combined_df['commit_date'] > midpoint_date]

        return recent_df.drop_duplicates(subset='commit_id').sample(n=n, replace=False, random_state=self.seed)

    def evaluate_df(self, df, k=1000, aggregation_strategy=None, rerankers=None):
        results = []
        for _, row in tqdm(df.iterrows(), total=df.shape[0]):
            cur_query = row['commit_message']
            search_results = self.model.pipeline(cur_query, row['commit_date'], ranking_depth=k, aggregation_method=aggregation_strategy)
            for reranker in rerankers:
                search_results = reranker.rerank_pipeline(cur_query, search_results)
            evaluation = self.eval_model.evaluate(search_results,
                                                   self.combined_df[self.combined_df['commit_id'] == row['commit_id']]['file_path'].tolist())
            results.append(evaluation)
        return results

    def evaluate_sampling(self, n=100, k=1000, output_file_path=None, overwrite_eval=False, aggregation_strategy=None, rerankers=None, gold_df=None): #, repo_path=None):
        # if repo_path is None:
        #     print("Repo path not provided, using current working directory")
            # repo_path = os.getcwd()
        if rerankers is None:
            rerankers = []

        if output_file_path is None:
            print("WARNING: Output file path not provided, not writing results to file")
            # output_file_path = os.path.join(repo_path, f'{self.model.__class__.__name__}_results.txt')

        # output_file_path = os.path.join(repo_path, output_file)
        model_name = self.model.__class__.__name__

        if not overwrite_eval and output_file_path and os.path.exists(output_file_path):
            print(f'Output file {output_file_path} already exists, set overwrite_eval flag to False, skipping...')
            # print the contents of the file
            with open(output_file_path, "r") as file:
                print(file.read())
            return
        if gold_df is None:
            sampled_commits = self.sample_commits(n)
            results = self.evaluate_df(sampled_commits, k, aggregation_strategy, rerankers)
        else:
            print(f'Found gold_df, evaluating on {len(gold_df)} commits')
            print(gold_df.info())
            results = self.evaluate_df(gold_df, k, aggregation_strategy, rerankers)

        avg_scores = {metric: round(np.mean([result[metric] for result in results]), 4) for metric in results[0]}

        if output_file_path is not None:
            with open(output_file_path, "w") as file:
                file.write(f"Model Name: {model_name}\n")
                # write name of each reranker
                if len(rerankers) > 0:
                    file.write("Rerankers:\n")
                    for reranker in rerankers:
                        reranker_model_name = reranker.model.config.name_or_path
                        # replace / with _
                        reranker_model_name = reranker_model_name.replace('/', '_')
                        file.write(f"{reranker.__class__.__name__} ({reranker_model_name}) @ {reranker.rerank_depth}\n")

                file.write(f"Sample Size: {n}\n")
                file.write("Evaluation Metrics:\n")
                for key, value in avg_scores.items():
                    file.write(f"{key}: {value}\n")

            print(f'Evaluation results written to {output_file_path}')

        return avg_scores


import threading
import socketserver
import queue
import collections
import cv2
import numpy as np
import math
import socket
import base64
from imutils.perspective import four_point_transform
from scipy.interpolate import interp1d

sensor_data = " "
test_finish = True
control_queue = queue.Queue(128)
web_queue = queue.Queue(1)
sensor_data_queue = collections.deque(maxlen=3)
sign_active_global = False
manual_control = 1  # 0 - autonomous
                    # 0.5 - semi-autonomous
                    # 1 - manueln

class NeuralNetwork(object):

    def __init__(self):
        self.model = None

    def create(self):
        self.model = cv2.ml.ANN_MLP_load('mlp_xml/mlp.xml')

    def predict(self, samples):
        ret, resp = self.model.predict(samples)
        return resp.argmax(-1)

class RCControl(object):

    def __init__(self):
        pass

    def steer(self, prediction):
        global control_queue
        if prediction == 2:
            control_queue.put('1')
            # print("Forward")
        elif prediction == 0:
            control_queue.put('2')
            # print("Forward-Left")
        elif prediction == 1:
            control_queue.put('8')
            # print("Forward-Right")
        else:
            self.stop()

    def stop(self):
        global control_queue
        control_queue.put('0')

class DistanceToCamera(object):

    def __init__(self):
        # camera params
        self.alpha = 8.0 * math.pi / 180
        self.v0 = 119.865631204
        self.ay = 332.262498472

    def calculate(self, v, h, x_shift, image):
        # compute and return the distance from the target point to the camera
        d = h / math.tan(self.alpha + math.atan((v - self.v0) / self.ay))
        return d

class ObjectDetection(object):

    def __init__(self):
        self.red_light = False
        self.green_light = False
        self.yellow_light = False

    # detecting stop traffic sigh
    def detect(self, cascade_classifier, gray_image, image):

        # y camera coordinate of the target point 'P'
        v = 0

        # detection
        cascade_obj = cascade_classifier.detectMultiScale(
            gray_image,
            scaleFactor=1.1,
            minNeighbors=5,
            minSize=(30, 30),
            flags=cv2.CASCADE_SCALE_IMAGE
        )

        # draw a rectangle around the objects
        for (x_pos, y_pos, width, height) in cascade_obj:
            v = y_pos + height - 5

        return v

    # derection for turn left and turn right traffic sign
    def findTrafficSign(self, frame):
        lower_blue = np.array([85, 100, 70])
        upper_blue = np.array([115, 255, 255])

        frameArea = frame.shape[0] * frame.shape[1]

        hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)

        kernel = np.ones((3, 3), np.uint8)
        mask = cv2.inRange(hsv, lower_blue, upper_blue)

        mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel)
        mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel)

        cnts = cv2.findContours(mask.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[-2]

        largestArea = 0
        largestRect = None

        detectedTrafficSign = None

        if len(cnts) > 0:
            for cnt in cnts:
                rect = cv2.minAreaRect(cnt)
                box = cv2.boxPoints(rect)
                box = np.int0(box)

                sideOne = np.linalg.norm(box[0] - box[1])
                sideTwo = np.linalg.norm(box[0] - box[3])

                area = sideOne * sideTwo

                if area > largestArea:
                    largestArea = area
                    largestRect = box

        v = 0

        if largestArea > frameArea * 0.02:
            v = largestRect[1][1] + (largestRect[0][1] - largestRect[1][1]) - 5
            warped = four_point_transform(mask, [largestRect][0])
            detectedTrafficSign = self.identifyTrafficSign(warped)

        return detectedTrafficSign, v

    def identifyTrafficSign(self, image):

        SIGNS_LOOKUP = {
            (1, 0, 0, 1): 'Turn Right',  # turnRight
            (0, 0, 1, 1): 'Turn Left',  # turnLeft
        }

        THRESHOLD = 150

        image = cv2.bitwise_not(image)
        (subHeight, subWidth) = np.divide(image.shape, 10)
        subHeight = int(subHeight)
        subWidth = int(subWidth)

        leftBlock = image[4 * subHeight:9 * subHeight, subWidth:3 * subWidth]
        centerBlock = image[4 * subHeight:9 * subHeight, 4 * subWidth:6 * subWidth]
        rightBlock = image[4 * subHeight:9 * subHeight, 7 * subWidth:9 * subWidth]
        topBlock = image[2 * subHeight:4 * subHeight, 3 * subWidth:7 * subWidth]

        leftFraction = np.sum(leftBlock) / (leftBlock.shape[0] * leftBlock.shape[1])
        centerFraction = np.sum(centerBlock) / (centerBlock.shape[0] * centerBlock.shape[1])
        rightFraction = np.sum(rightBlock) / (rightBlock.shape[0] * rightBlock.shape[1])
        topFraction = np.sum(topBlock) / (topBlock.shape[0] * topBlock.shape[1])

        segments = (leftFraction, centerFraction, rightFraction, topFraction)
        segments = tuple(1 if segment > THRESHOLD else 0 for segment in segments)

        if segments in SIGNS_LOOKUP:
            return SIGNS_LOOKUP[segments]
        else:
            return None

class SensorDataHandler(socketserver.BaseRequestHandler):

    data = " "

    def handle(self):
        global sensor_data
        global sensor_data_queue
        try:
            while self.data:
                self.data = self.request.recv(1024)
                sensor_data_queue.append(self.data)
        except:
            print("Connection closed on thread 2")

class VideoStreamHandler(socketserver.StreamRequestHandler):

    # h1: stop sign
    h1 = 15.5 - 10  # cm
    # h2: traffic light
    h2 = 15.5 - 10

    # create neural network
    model = NeuralNetwork()
    model.create()

    obj_detection = ObjectDetection()
    rc_car = RCControl()

    # cascade classifiers
    stop_cascade = cv2.CascadeClassifier('cascade_xml/stop_sign.xml')

    d_to_camera = DistanceToCamera()
    d_stop_sign = 60

    stop_start = 0              # start time when stop at the stop sign
    stop_finish = 0
    stop_time = 0
    drive_time_after_stop = 0
    sign_start = 0
    drive_time_after_sign = 0

    sensor_x = [25, 30, 43, 60, 87, 165, 255] # values that we get from IR sensors
    sensor_y = [30, 25, 20, 15, 10, 5, 1] # real distance from car in cm

    def recvall(self, sock, count):
        buf = b''
        while count:
            newbuf = sock.read(count)
            if not newbuf:
                return None
            buf += newbuf
            count -= len(newbuf)
        return buf

    def handle(self):
        global test_finish
        global sensor_data
        global sensor_data_queue
        global sign_active_global
        global web_queue
        stop_flag = False
        stop_sign_active = True
        sign_active = False
        sign_sent = False

        interpolate_sensor = interp1d(self.sensor_x, self.sensor_y, kind='cubic')
        interpolate_sensor.bounds_error = False

        try:
            # stream video frames one by one
            sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
            while test_finish:
                length = self.recvall(self.rfile, 16)
                stringData = self.recvall(self.rfile, int(length))
                data = np.fromstring(stringData, dtype='uint8')
                image = cv2.imdecode(data, 1)
                gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

                _, t12 = cv2.imencode('.jpg', image)
                b64_img = base64.b64encode(t12)

                sock.sendto(b64_img, ('localhost', 8993))

                # lower half of the image
                half_gray = gray[120:240, :]

                # object detection
                v_param1 = self.obj_detection.detect(self.stop_cascade, gray, image)
                detected_sign, v_param2 = self.obj_detection.findTrafficSign(image)

                if detected_sign is not None and not sign_active:
                    sign_active = True
                    self.sign_start = cv2.getTickCount()

                # distance measurement
                if v_param1 > 0:
                    self.d_stop_sign = self.d_to_camera.calculate(v_param1, self.h1, 300, image)

                # showing video
                # cv2.imshow('image', image)
                # if cv2.waitKey(1) & 0xFF == ord('q'):
                #     pass

                # stop conditions
                sensor_data = []
                try:
                    sensor_data.append(sensor_data_queue.popleft().decode().split(";"))
                    sensor_data.append(sensor_data_queue.popleft().decode().split(";"))
                    sensor_data.append(sensor_data_queue.popleft().decode().split(";"))
                except:
                    pass

                each_sensor_data = [0, 0, 0, 0, 0]
                for data in sensor_data:
                    each_sensor_data[0] += int(data[0])
                    each_sensor_data[1] += int(data[1])
                    each_sensor_data[2] += int(data[2])
                    each_sensor_data[3] += int(data[3])
                    each_sensor_data[4] += int(data[4])

                if sensor_data:
                    each_sensor_data[0] /= len(sensor_data)
                    each_sensor_data[1] /= len(sensor_data)
                    each_sensor_data[2] /= len(sensor_data)
                    each_sensor_data[3] /= len(sensor_data)
                    each_sensor_data[4] /= len(sensor_data)

                tmp_str = ''
                tmp_str += '%.1f' % interpolate_sensor(each_sensor_data[0]) + ';'
                tmp_str += '%.1f' % interpolate_sensor(each_sensor_data[1]) + ';'
                tmp_str += '%.1f' % interpolate_sensor(each_sensor_data[2]) + ';'
                tmp_str += '%.1f' % interpolate_sensor(each_sensor_data[3]) + ';'
                tmp_str += '%.1f' % interpolate_sensor(each_sensor_data[4]) + ';'
                tmp_str += str(detected_sign) + ';'
                tmp_str += str(True if v_param1 > 0 else False) + '\n'

                if web_queue.empty():
                    web_queue.put(tmp_str)

                # for manuel controll we do not need any AI comands
                if manual_control == 1:
                    continue

                # for semi-autonomous we have collision detection and collision avoidance system
                if manual_control == 0.5:
                    if int(each_sensor_data[2]) > 100:
                        self.rc_car.stop()
                        continue
                    continue

                # reshape image
                image_array = half_gray.reshape(1, 38400).astype(np.float32)

                # neural network makes prediction
                prediction = self.model.predict(image_array)

                if int(each_sensor_data[2]) > 100:
                    # print("Stop, obstacle in front")
                    self.rc_car.stop()

                elif 0 < self.d_stop_sign < 55 and stop_sign_active:
                    # print("Stop sign ahead")
                    self.rc_car.stop()

                    # stop for 5 seconds
                    if stop_flag is False:
                        self.stop_start = cv2.getTickCount()
                        stop_flag = True
                    self.stop_finish = cv2.getTickCount()

                    self.stop_time = (self.stop_finish - self.stop_start)/cv2.getTickFrequency()
                    # print("Stop time: %.2fs" % self.stop_time)

                    # 3 seconds later, continue driving
                    if self.stop_time > 3:
                        # print("Waited for 3 seconds")
                        if each_sensor_data[1] > 35 or each_sensor_data[2] > 50:
                            pass
                        else:
                            stop_flag = False
                            stop_sign_active = False

                elif sign_active and not sign_sent:
                    if detected_sign == 'Turn Left':
                        # print('Turn Left sign')
                        control_queue.put('l')
                        sign_sent = True
                    elif detected_sign == 'Turn Right':
                        # print('Turn Right sign')
                        control_queue.put('r')
                        sign_sent = True

                elif int(each_sensor_data[1]) > 90:
                    if int(each_sensor_data[4]) > 70:
                        # print("Stop front-left obstacle")
                        self.rc_car.stop()
                    else:
                        # print("Avoid front-left obstacle")
                        control_queue.put('8')

                elif int(each_sensor_data[3]) > 90:
                    if int(each_sensor_data[0]) > 70:
                        # print("Stop front-right obstacle")
                        self.rc_car.stop()
                    else:
                        # print("Avoid front-right obstacle")
                        control_queue.put('2')

                else:
                    self.rc_car.steer(prediction)
                    self.stop_start = cv2.getTickCount()
                    self.d_stop_sign = 50
                    self.d_sign = 50

                if stop_sign_active is False:
                    self.drive_time_after_stop = (self.stop_start - self.stop_finish)/cv2.getTickFrequency()
                    if self.drive_time_after_stop > 5:
                        stop_sign_active = True

                if sign_active is True:
                    self.drive_time_after_sign = (cv2.getTickCount() - self.sign_start) / cv2.getTickFrequency()
                    if self.drive_time_after_sign > 3:
                        sign_active = False
                        sign_active_global = False
                        sign_sent = False
                        # print("Finish sign detection")

            sock.close()

        except Exception as e:
            print("Connection closed on thread 1")

class ThreadServer(object):

    def __init__(self):
        # sensor - receive data from RPi
        distance_thread = threading.Thread(target=self.server_thread2, args=('localhost', 8002))
        distance_thread.start()
        # video - receive video (jpeg) images from RPi
        video_thread = threading.Thread(target=self.server_thread, args=('localhost', 8000))
        video_thread.start()
        # keyboard i AI controll
        control_thread = threading.Thread(target=self.server_thread3, args=('localhost', 8004))
        control_thread.start()
        # send to web (sensor & sign) - send to client sensor values and detected traffic sign
        web_data_thread = threading.Thread(target=self.server_thread4, args=('localhost', 8992))
        web_data_thread.start()

    def server_thread(self, host, port):
        server = socketserver.TCPServer((host, port), VideoStreamHandler)
        server.serve_forever()

    def server_thread2(self, host, port):
        server = socketserver.TCPServer((host, port), SensorDataHandler)
        server.serve_forever()

    def server_thread3(self, host, port):
        server_socket = socket.socket()
        server_socket.bind((host, port))
        server_socket.listen(0)
        self.server_thread3_rec(server_socket)

    def server_thread3_rec(self, server_socket):
        global control_queue
        global test_finish
        global sign_active_global
        connection, _ = server_socket.accept()

        try:
            while test_finish:

                cmd = control_queue.get(block=True, timeout=None)

                b = bytearray()
                b.extend(map(ord, cmd))
                if not sign_active_global:
                    connection.send(b)
                if cmd == 'l' or cmd == 'r':
                    sign_active_global = True
                control_queue.task_done()
        except ConnectionResetError:
            print("Connection closed on thread 3")
            self.server_thread3_rec(server_socket)
        except ConnectionAbortedError:
            print("Connection closed on thread 3")
            self.server_thread3_rec(server_socket)

    def server_thread4(self, host, port):

        global manual_control
        global control_queue
        lock = threading.Lock()

        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

        while True:
            try:
                s.connect((host, port))
            except:
                continue
            else:
                break
        s.setblocking(True)
        s.settimeout(0.1)

        while test_finish:
            try:
                cmd = web_queue.get(block=True, timeout=None)
                s.send(cmd.encode())
                web_queue.task_done()

                tmp = s.recv(64).decode()
                tmp = tmp[:-2]

                if tmp == 'manual':
                    lock.acquire()
                    manual_control = 1
                    lock.release()
                    control_queue.put('0')
                    # print('manual')
                    continue
                elif tmp == 'auto':
                    lock.acquire()
                    manual_control = 0
                    lock.release()
                    control_queue.put('0')
                    # print('auto')
                    continue
                elif tmp == 'semi':
                    lock.acquire()
                    manual_control = 0.5
                    lock.release()
                    control_queue.put('0')
                    # print('semi')
                    continue

                if manual_control == 1 or manual_control == 0.5:  # jeste mauelno, i onda nase komande stavljaj u queue
                    if tmp != "":
                        control_queue.put(tmp)
            except socket.error as e:
                if e.errno is None:
                    pass
                if e.errno == 10054:
                    print("Connection closed on thread 4")
                    try:
                        self.server_thread4(host, port)
                    except:
                        pass

if __name__ == '__main__':
    ThreadServer()


def log_format(request, response, exception=None):
    user_id = request.user.id if request.user.is_authenticated else None
    user_info ={
        'user_id':user_id,
        'user_email': request.user.email if request.user.is_authenticated else ' ',
    }
    remote_host = request.META.get("REMOTE_ADDR",'-')
    request_line = request.method

    status_code = response.status_code if not exception else 500

    response_size = response.get('Content-Length', ' ') if response else ""
    print(response_size)
    referrer = request.META.get('HTTP_REFERRER', '-')
    elapsed_time = response.elapsed.total_seconds() if hasattr(response, 'elapsed') else None
    user_agent = request.headers.get('user-agen')
    event = f"{request.get_full_path()} HTTP/1.1"

    message = str(exception) if exception else 'Request is successfully'

    return {
        'user_info': user_info,
        'remote_host': remote_host,
        'request_line': request_line,
        'status_code': status_code,
        'response_size': response_size,
        'referrer': referrer,
        'elapsed_time': elapsed_time,
        'message': message,
        'user_agent': user_agent,
        'event': event,
    }

def authentication_logs_format(user, body, exception=None):
    message = str(exception) if exception else 'Consume is seccssfully'

    return {
        'user_id': str(user.id ),
        'user_phone': str(user.phone),
        'user_agent': body["user_agent"],
        'event': f"consumer.{body['routing_key']}",
        "status": "success",
        'message': message
    }

def rss_log_format(body, exception=None):

    message = str(exception) if exception else 'Consume is successfully'

    return {
        'event': f"consumer.{body['routing_key']}",
        "status": "success",
        'message': message
    }

import json
import logging

logger = logging.getLogger('elastic-logger')

def log_to_elasticsearch(log_data, log_level):
    if log_level == 'info':
        logger.info(json.dumps(log_data))
    elif log_level == 'error':
        logger.error(json.dumps(log_data))

class CustomLoggingMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        response = self.get_response(request)
        log_data = log_format(request, response)
        log_to_elasticsearch(log_data=log_data, log_level='info')
        return response
    def process_exception(self, request, exception):
        log_data = log_format(request, None, exception)
        log_to_elasticsearch(log_data=log_data, log_level='error')


from googleapiclient.discovery import build
import requests
import json

api_key ='CLE_API'

youtube = build ('youtube', 'v3', developerKey=api_key)

request = youtube.channels().list(
		part='statistics',
		id='ID_CHAINE'
	)

response: object = request.execute()

print(response)

abo = response['items'][0]['statistics']['subscriberCount']

print (abo)

aboint = float(abo)

abok = float(aboint/1000)

print (abok)

abodisplay = str(abok)+"K"

print (abodisplay)


import helper_const
import helper_global
import helper_database
import telegram
import threading
from telegram import InlineKeyboardButton, InlineKeyboardMarkup
from telegram.ext import MessageHandler, Filters
from ninesix import Logger

def add_record(bot, channel_id, msg_id, message):
    logger = Logger.logger
    ori_msg_id = message.message_id
    user = message.from_user
    username = user.username
    user_id = user.id
    name = user.first_name
    if user.last_name:
        name += " " + user.last_name
    date = message.date.strftime("%Y-%m-%d %H:%M:%S")

    msg_type = "text"
    msg_content = ""
    media_id = ""
    if message.text:
        msg_type = "text"
        msg_content = message.text
    elif message.sticker:
        msg_type = 'sticker'
        media_id = message.sticker.file_id
        if message.sticker.emoji:
            msg_content = message.sticker.emoji
    elif message.photo:
        msg_type = 'photo'
        media_id = message.photo[-1].file_id
        if message.caption:
            msg_content = message.caption
    elif message.video:
        msg_type = 'video'
        media_id = message.video.file_id
        if message.caption:
            msg_content = message.caption
    elif message.document:
        msg_type = 'document'
        media_id = message.document.file_id
        if message.document.file_name:
            msg_content = message.document.file_name
    elif message.audio:
        msg_type = 'audio'
        media_id = message.audio.file_id
        if message.audio.title:
            msg_content = message.audio.title
    elif message.voice:
        msg_type = 'voice'
        media_id = message.voice.file_id

    msg_content = helper_global.parse_entity(msg_content, message.entities)

    if message.reply_markup and message.reply_markup.inline_keyboard:
        keyboard = message.reply_markup.inline_keyboard
        if len(keyboard) > 0 and len(keyboard[0]) > 0:
            query = keyboard[0][0]
            if query.callback_data:
                args = query.callback_data.split(",")
                if len(args) == 4 and args[0] == "notify":
                    target_channel_id = int(args[1])
                    target_msg_id = int(args[2])
                    target_row_id = args[3]
                    record = helper_database.get_record_by_rowid(target_row_id)
                    if len(record) > 0 and target_channel_id == int(record[0][0]) and target_msg_id == int(record[0][1]):
                        target_name = record[0][3]
                        target_user_id = record[0][8]
                        config = helper_database.get_channel_config(channel_id)
                        if config is None:
                            return
                        channel_lang, channel_username = config[1], config[4]
                        msg_content = "<b>(➤%s) </b> " % target_name.replace('<', '<').replace('>', '>') + msg_content
                        if channel_username is not None:
                            logger.msg({
                                "channel_id": channel_id,
                                "msg_id": msg_id,
                                "target_user": target_user_id,
                                "action": "notify reply"
                            }, tag="private", log_level=80)
                            bot.send_message(
                                chat_id=target_user_id,
                                text=helper_global.value("new_reply_message", "You receive a reply message.", lang=channel_lang) + "\n" + helper_global.value("target_message", "", lang=channel_lang) + "https://t.me/%s/%d" % (channel_username, target_msg_id)
                            )
                        else:
                            link_id = abs(channel_id) % 10000000000
                            bot.send_message(
                                chat_id=target_user_id,
                                text=helper_global.value("new_reply_message", "You receive a reply message.", lang=channel_lang) + "\n" + helper_global.value("target_message", "", lang=channel_lang) + "https://t.me/c/%d/%d" % (link_id, target_msg_id)
                            )

    return helper_database.add_record(channel_id, msg_id, username, name, msg_type, msg_content, media_id, date, user_id, ori_msg_id)

def update_comments(bot, channel_id, msg_id, update_mode):
    logger = Logger.logger
    config = helper_database.get_channel_config(channel_id)
    if config is None:
        return
    channel_lang = config[1]
    mode = config[2]
    recent = config[3]
    logger.msg({
        "channel_id": channel_id,
        "msg_id": msg_id,
        "update_mode": update_mode
    }, tag="private", log_level=80)

    # For mode 3
    if mode == 3 and update_mode == 2:
        buttons = helper_database.get_button_options(channel_id, msg_id)
        stat = helper_database.get_reaction_stat(channel_id, msg_id)
        # Prepare Keyboard
        motd_keyboard = [[
            InlineKeyboardButton(
                value + (" (%d)" % stat[idx] if idx in stat else ""),
                callback_data="like,%s,%s,%d" % (channel_id, msg_id, idx)
            )
        for idx, value in enumerate(buttons)]] + [[
            InlineKeyboardButton(
                helper_global.value("add_comment", "Add Comment", lang=channel_lang),
                url="http://telegram.me/%s?start=add_%d_%d" % (helper_global.value('bot_username', ''), channel_id, msg_id)
            ),
            InlineKeyboardButton(
                helper_global.value("show_all_comments", "Show All", lang=channel_lang),
                url="http://telegram.me/%s?start=show_%s_%d" % (helper_global.value('bot_username', ''), channel_id, msg_id)
            )
        ]]
        motd_markup = InlineKeyboardMarkup(motd_keyboard)

        records = helper_database.get_recent_records(channel_id, msg_id, recent)
        origin_post = helper_database.get_origin_post(channel_id, msg_id)

        try:
            bot.edit_message_caption(
                caption=origin_post + "\n\n" + helper_global.records_to_str(records, channel_lang),
                chat_id=channel_id,
                message_id=msg_id,
                parse_mode=telegram.ParseMode.HTML,
                reply_markup=motd_markup
            )
        except:
            bot.edit_message_text(
                text=origin_post + "\n\n" + helper_global.records_to_str(records, channel_lang),
                chat_id=channel_id,
                message_id=msg_id,
                parse_mode=telegram.ParseMode.HTML,
                reply_markup=motd_markup
            )
        return

    # update comments in channel
    comment_id = helper_database.get_comment_id(channel_id, msg_id)
    if comment_id is None:
        # If no comment message, just update Like buttons
        buttons = helper_database.get_button_options(channel_id, msg_id)
        stat = helper_database.get_reaction_stat(channel_id, msg_id)
        # Prepare Keyboard
        motd_keyboard = [[
            InlineKeyboardButton(
                value + (" (%d)" % stat[idx] if idx in stat else ""),
                callback_data="like,%s,%s,%d" % (channel_id, msg_id, idx)
            )
        for idx, value in enumerate(buttons)]] + [[
            InlineKeyboardButton(
                helper_global.value("add_comment", "Add Comment", lang=channel_lang),
                url="http://telegram.me/%s?start=add_%d_%d" % (helper_global.value('bot_username', ''), channel_id, msg_id)
            ),
            InlineKeyboardButton(
                helper_global.value("show_all_comments", "Show All", lang=channel_lang),
                url="http://telegram.me/%s?start=show_%s_%d" % (helper_global.value('bot_username', ''), channel_id, msg_id)
            )
        ]]
        motd_markup = InlineKeyboardMarkup(motd_keyboard)
        bot.edit_message_reply_markup(
            chat_id=channel_id,
            message_id=msg_id,
            reply_markup=motd_markup
        )
        return

    # Otherwise
    # Update Like buttons
    if update_mode == 0:
        buttons = helper_database.get_button_options(channel_id, msg_id)
        stat = helper_database.get_reaction_stat(channel_id, msg_id)
        # Prepare Keyboard
        motd_keyboard = [[
            InlineKeyboardButton(
                value + (" (%d)" % stat[idx] if idx in stat else ""),
                callback_data="like,%s,%s,%d" % (channel_id, msg_id, idx)
            )
        for idx, value in enumerate(buttons)]]
        if comment_id - msg_id > 1:
            link_id = abs(channel_id) % 10000000000
            motd_keyboard += [[
                InlineKeyboardButton(
                    helper_global.value("jump_to_comment", "Jump to Comment", lang=channel_lang),
                    url="https://t.me/c/%d/%d" % (link_id, comment_id)
                )
            ]]
        motd_markup = InlineKeyboardMarkup(motd_keyboard)
        bot.edit_message_reply_markup(
            chat_id=channel_id,
            message_id=msg_id,
            reply_markup=motd_markup
        )
        return

    # Update comment message
    records = helper_database.get_recent_records(channel_id, msg_id, recent)

    # Prepare Keyboard
    motd_keyboard = [[
        InlineKeyboardButton(
            helper_global.value("add_comment", "Add Comment", lang=channel_lang),
            url="http://telegram.me/%s?start=add_%d_%d" % (helper_global.value('bot_username', ''), channel_id, msg_id)
        ),
        InlineKeyboardButton(
            helper_global.value("show_all_comments", "Show All", lang=channel_lang),
            url="http://telegram.me/%s?start=show_%s_%d" % (helper_global.value('bot_username', ''), channel_id, msg_id)
        )
    ]]
    motd_markup = InlineKeyboardMarkup(motd_keyboard)

    bot.edit_message_text(
        text=helper_global.records_to_str(records, channel_lang),
        chat_id=channel_id,
        message_id=comment_id,
        parse_mode=telegram.ParseMode.HTML,
        reply_markup=motd_markup
    )

def update_dirty_list():
    lock.acquire()
    dirty_list = helper_global.value("dirty_list", [])
    bot = helper_global.value("bot", None)
    for item in dirty_list:
        channel_id, msg_id, update_mode = item
        threading.Thread(
            target=update_comments,
            args=(bot, channel_id, msg_id, update_mode)
        ).start()
    helper_global.assign("dirty_list", [])
    lock.release()

def check_channel_message(bot, message):
    logger = Logger.logger
    chat_id = message.chat_id
    if not message.forward_from_chat:
        helper_global.send_intro_template(bot, chat_id, helper_const.DEFAULT_LANG, "register_invalid", "register_cmd_invalid")
        return
    chat_type = message.forward_from_chat.type
    if not chat_type == "channel":
        helper_global.send_intro_template(bot, chat_id, helper_const.DEFAULT_LANG, "register_invalid", "register_cmd_invalid")
        return
    channel_username = message.forward_from_chat.username
    channel_id = message.forward_from_chat.id
    user_id = message.from_user.id
    logger.msg({
        "user_id": chat_id,
        "channel_id": channel_id,
        "action": "check channel"
    }, tag="private", log_level=90)
    bot_id = int(helper_const.BOT_TOKEN.split(":")[0])
    try:
        chat_members = bot.get_chat_administrators(chat_id=channel_id).result()
        chat_member_ids = [member.user.id for member in chat_members]
        if not user_id in chat_member_ids:
            helper_global.send_intro_template(bot, chat_id, helper_const.DEFAULT_LANG, "register_not_admin", "register_cmd_not_admin")
            return
        for member in chat_members:
            if member.user.id == bot_id:
                post_permission = member.can_post_messages if member.can_post_messages else False
                edit_permission = member.can_edit_messages if member.can_edit_messages else False
                delete_permission = member.can_delete_messages if member.can_delete_messages else False
                if not post_permission or not edit_permission or not delete_permission:
                    helper_global.send_intro_template(bot, chat_id, helper_const.DEFAULT_LANG, "register_no_permission", "register_cmd_no_permission")
                    return
                break
    except:
        helper_global.send_intro_template(bot, chat_id, helper_const.DEFAULT_LANG, "register_no_info", "register_cmd_no_info")
        return
    try:
        helper_database.add_channel_config(channel_id, helper_const.DEFAULT_LANG, 1, 10, channel_username, chat_id, 1, 1)
    except:
        helper_global.assign(str(chat_id) + "_status", "0,0")
        helper_global.send_intro_template(bot, chat_id, helper_const.DEFAULT_LANG, "register_failed", "register_cmd_failed")
        return

    helper_global.assign(str(chat_id) + "_status", "0,0")
    helper_global.send_intro_template(bot, chat_id, helper_const.DEFAULT_LANG, "register_success", "register_cmd_success")

def private_msg(bot, update):
    logger = Logger.logger
    message = update.edited_message if update.edited_message else update.message
    chat_id = message.chat_id
    args = helper_global.value(str(chat_id) + "_status", "0,0")
    logger.msg({
        "user_id": chat_id,
        "status": args
    }, tag="private", log_level=90)

    params = args.split(",")
    channel_id = int(params[0])
    msg_id = int(params[1])
    if channel_id == 0:
        if msg_id == 1:
            check_channel_message(bot, message)
        return

    # Check comment message
    comment_exist = helper_database.check_reflect(channel_id, msg_id)
    config = helper_database.get_channel_config(channel_id)
    if config is None:
        return
    channel_lang = config[1]
    mode, recent, username, admin_id, notify = config[2], config[3], config[4], config[5], config[6]
    logger.msg({
        "user_id": chat_id,
        "channel_id": channel_id,
        "msg_id": msg_id,
        "action": "add comment"
    }, tag="private", log_level=90)

    # For Auto Mode = 2
    if not comment_exist:
        logger.msg({
            "user_id": chat_id,
            "channel_id": channel_id,
            "msg_id": msg_id,
            "action": "add comment area"
        }, tag="private", log_level=80)
        comment_message = bot.send_message(
            chat_id=channel_id,
            text=helper_global.value("comment_refreshing", "Refreshing...", lang=channel_lang),
            reply_to_message_id=msg_id,
            parse_mode=telegram.ParseMode.HTML
        ).result()
        helper_database.add_reflect(channel_id, msg_id, comment_message.message_id)
        #bot.edit_message_reply_markup(
        #    chat_id=channel_id,
        #    message_id=msg_id,
        #    reply_markup=None
        #)
        update_dirty_msg(channel_id, msg_id, update_mode=0)

    result = add_record(bot, channel_id, msg_id, message)

    # Update Dirty List
    update_dirty_msg(channel_id, msg_id, update_mode=(2 if mode == 3 else 1))
    if notify == 1 and not int(chat_id) == int(admin_id):
        logger.msg({
            "user_id": chat_id,
            "channel_id": channel_id,
            "msg_id": msg_id,
            "admin_id": admin_id,
            "action": "notify channel owner"
        }, tag="private", log_level=80)
        if username is not None:
            bot.send_message(
                chat_id=admin_id,
                text=helper_global.value("new_comment_message", "You have a new comment message.", lang=channel_lang) + "\n" + helper_global.value("target_message", "", lang=channel_lang) + "https://t.me/%s/%d" % (username, msg_id)
            )
        else:
            link_id = abs(channel_id) % 10000000000
            bot.send_message(
                chat_id=admin_id,
                text=helper_global.value("new_comment_message", "You have a new comment message.", lang=channel_lang) + "\n" + helper_global.value("target_message", "", lang=channel_lang) + "https://t.me/c/%d/%d" % (link_id, msg_id)
            )

    if result == 0:
        bot.send_message(chat_id=chat_id, text=helper_global.value("comment_success", "Success!", lang=channel_lang))
    elif result == 1:
        bot.send_message(chat_id=chat_id, text=helper_global.value("comment_edit_success", "Success!", lang=channel_lang))

def update_dirty_msg(channel_id, msg_id, update_mode=1):
    lock.acquire()
    dirty_list = helper_global.value("dirty_list", [])
    if not (channel_id, msg_id, update_mode) in dirty_list:
        dirty_list.append((channel_id, msg_id, update_mode))
    helper_global.assign("dirty_list", dirty_list)
    lock.release()

def set_interval(func, sec):
    def func_wrapper():
        set_interval(func, sec)
        func()
    t = threading.Timer(sec, func_wrapper)
    t.start()
    return t

refresh_status = helper_global.value("refresh_status", False)
if not refresh_status:
    set_interval(update_dirty_list, helper_const.MIN_REFRESH_INTERVAL)
    helper_global.assign("refresh_status", True)
lock = threading.Lock()
_handler = MessageHandler(Filters.private, private_msg, edited_updates=True)


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

from square.api_helper import APIHelper
from square.http.api_response import ApiResponse
from square.api.base_api import BaseApi
from square.http.auth.o_auth_2 import OAuth2

class MobileAuthorizationApi(BaseApi):

    """A Controller to access Endpoints in the square API."""

    def __init__(self, config, call_back=None):
        super(MobileAuthorizationApi, self).__init__(config, call_back)

    def create_mobile_authorization_code(self,
                                         body):
        """Does a POST request to /mobile/authorization-code.

        Generates code to authorize a mobile application to connect to a
        Square card reader
        Authorization codes are one-time-use and expire __60 minutes__ after
        being issued.
        __Important:__ The `Authorization` header you provide to this endpoint
        must have the following format:
        ```
        Authorization: Bearer ACCESS_TOKEN
        ```
        Replace `ACCESS_TOKEN` with a
        [valid production authorization
        credential](https://developer.squareup.com/docs/docs/build-basics/acces
        s-tokens).

        Args:
            body (CreateMobileAuthorizationCodeRequest): An object containing
                the fields to POST for the request.  See the corresponding
                object definition for field details.

        Returns:
            CreateMobileAuthorizationCodeResponse: Response from the API.
                Success

        Raises:
            APIException: When an error occurs while fetching the data from
                the remote API. This exception includes the HTTP Response
                code, an error message, and the HTTP body that was received in
                the request.

        """

        # Prepare query URL
        _url_path = '/mobile/authorization-code'
        _query_builder = self.config.get_base_uri()
        _query_builder += _url_path
        _query_url = APIHelper.clean_url(_query_builder)

        # Prepare headers
        _headers = {
            'accept': 'application/json',
            'content-type': 'application/json; charset=utf-8'
        }

        # Prepare and execute request
        _request = self.config.http_client.post(_query_url, headers=_headers, parameters=APIHelper.json_serialize(body))
        OAuth2.apply(self.config, _request)
        _response = self.execute_request(_request)

        decoded = APIHelper.json_deserialize(_response.text)
        if type(decoded) is dict:
            _errors = decoded.get('errors')
        else:
            _errors = None
        _result = ApiResponse(_response, body=decoded, errors=_errors)
        return _result


# script for PPO, modified from existing repo minimal-isaac-gym

from env import BoxEnv
import torch
import torch.nn as nn
import torch.nn.functional as F
from torch.distributions import MultivariateNormal
import matplotlib.pyplot as plt

class Net(nn.Module):
    def __init__(self, num_obs=2, num_act=1):
        super(Net, self).__init__()

        # create a shared structre for actor/critic
        # sharing a network can increase performance in low-state systems
        self.shared_net = nn.Sequential(
            nn.Linear(num_obs, 256),
            nn.LeakyReLU(),
            nn.Linear(256,256),
            nn.LeakyReLU()
        )

        # set mean/variance of actor network
        # outputs action as a probability distribution
        self.to_mean = nn.Sequential(
            nn.Linear(256, 256),
            nn.LeakyReLU(),
            nn.Linear(256, num_act),
            nn.Tanh()
        )

        # value for critic network
        # evaluates the value of being in a specific state
        self.to_value = nn.Sequential(
            nn.Linear(256, 256),
            nn.LeakyReLU(),
            nn.Linear(256, 1)
        )

    # passes a value through the actor network
    def pi(self, x):
        x = self.shared_net(x)
        self.gamma = 0.99
        mu = self.to_mean(x)
        return mu

    # passes a value through the critic network (state-value function)
    def v(self, x):
        x = self.shared_net(x)
        x = self.to_value(x)
        return x

class PPO:
    def __init__(self, args):
        self.args = args

        # initializes the environment
        self.env = BoxEnv(args)

        # hyperparamters for learning
        self.epoch = 5
        self.lr = 3e-4  # how often the nn updates weights
        self.gamma = 0.99
        self.lmbda = 0.95
        self.clip = 0.25
        self.rollout_size = 128
        self.chunk_size = 32
        self.mini_chunk_size = self.rollout_size // self.chunk_size
        self.mini_batch_size = self.args.num_envs * self.mini_chunk_size
        self.num_eval_freq = 275

        self.data = []
        self.score = 0
        self.run_step = 0
        self.optim_step = 0

        self.net = Net(self.env.num_obs, self.env.num_act).to(args.sim_device)

        # adds variance to the action space
        self.action_var = torch.full((self.env.num_act,), 0.1).to(args.sim_device)

        # optimizes the parameters of the nn
        self.optim = torch.optim.Adam(self.net.parameters(), lr=self.lr)

    def make_data(self):
        # organize the data/make batch
        data = []

        for _ in range(self.chunk_size):
            obs_lst, a_lst, r_lst, next_obs_lst, log_prob_lst, done_lst = [], [], [], [], [], []
            for _ in range(self.mini_chunk_size):
                # pops out the first entry of data and sets it to rollout
                rollout = self.data.pop(0)

                # all of those are contained in data, in that order
                obs, action, reward, next_obs, log_prob, done = rollout

                obs_lst.append(obs)
                a_lst.append(action)
                r_lst.append(reward.unsqueeze(-1))
                next_obs_lst.append(next_obs)
                log_prob_lst.append(log_prob)
                done_lst.append(done.unsqueeze(-1))

            obs, action, reward, next_obs, done = \
                torch.stack(obs_lst), torch.stack(a_lst), torch.stack(r_lst), torch.stack(next_obs_lst), torch.stack(done_lst)

            # compute the reward-to-go
            with torch.no_grad():
                # calculates target as current reward + value of the next state (discounted by gamma)
                reward = reward.squeeze(-1)
                target = reward + self.gamma * self.net.v(next_obs) * done

                # delta is the difference between the what the expected value of the state is and the
                # actual value of the current observation, if delta > 0 then it was worse, delta < 0 means
                # the value is more than thought

                # also called the TD error
                delta = target - self.net.v(obs)

            # compute the advantage of the action
            adv_list = []
            advantage = 0.0

            # maps the advantage of each action to show relative impact
            for delta_t in reversed(delta):
                advantage = self.gamma * self.lmbda * advantage + delta_t
                adv_list.insert(0, advantage)

            advantage = torch.stack(adv_list)
            log_prob = torch.stack(log_prob_lst)

            mini_batch = (obs, action, log_prob, target, advantage)
            data.append(mini_batch)
        return data

    def update(self):
        # update actor/critic network
        data = self.make_data()

        for i in range(self.epoch):
            for mini_batch in data:
                obs, action, old_log_prob, target, advantage = mini_batch

                # pass the observations through actor network
                mu = self.net.pi(obs)

                # creates convariance matrix
                cov_mat = torch.diag(self.action_var)

                # creates guassian distribution with output of actor (mu) as mean and covariance matrix
                dist = MultivariateNormal(mu, cov_mat)

                # returns log probability of an action
                log_prob = dist.log_prob(action)

                # returns log probability of an action
                ratio = torch.exp(log_prob - old_log_prob).unsqueeze(-1)

                # create the surrogate funcitons w/ clip
                surr1 = ratio * advantage
                surr2 = torch.clamp(ratio, 1 - self.clip, 1 + self.clip) * advantage

                # loss is the minimum of the surrogates + loss from the critic network eval of state and target
                loss = -torch.min(surr1, surr2) + F.smooth_l1_loss(self.net.v(obs), target)

                # zeros out the gradients for a clean slate
                self.optim.zero_grad()

                # initialize backprop on the mean of the gradients
                loss.mean().backward()

                # scale the gradients to prevent large policy updates
                nn.utils.clip_grad_norm_(self.net.parameters(), 1.0)

                # perform single optimization step
                self.optim.step()

                self.optim_step += 1

    def run(self):
        # collect data
        # receive observations from env
        obs = self.env.obs_buf.clone()     # size(num_envs, num_obs)

        with torch.no_grad():

            # passes obs through actor net
            mu = self.net.pi(obs)

            # creates another covariance matrix
            cov_mat =  torch.diag(self.action_var)

            # calculates action distrubution using (mean, variance)
            dist = MultivariateNormal(mu, cov_mat)

            # samples action from a distribution
            action = dist.sample()

            # determines prob of policy taking that action
            log_prob = dist.log_prob(action)

            # clips the action from -1 to 1 (because of the cartpole env?)
            # the action space = num_envs
            action = action.clip(-1, 1)

        # sends action to env to simulate
        self.env.step(action)
        next_obs, reward, done = self.env.obs_buf.clone(), self.env.reward_buf.clone(), self.env.reset_buf.clone()
        self.env.reset()

        self.data.append((obs, action, reward, next_obs, log_prob, 1 - done))

        self.score += torch.mean(reward.float()).item() / self.num_eval_freq

        self.action_var = torch.max(0.01 * torch.ones_like(self.action_var), self.action_var - 0.00002)

        # training mode
        if len(self.data) == self.rollout_size:
            self.update()

        # evaluation mode
        if self.run_step % self.num_eval_freq == 0:
            print('Steps: {:04d} | Reward {:.04f} | Action Var {:.04f}'
                  .format(self.run_step, self.score, self.action_var[0].item()))
            self.score = 0

        self.run_step += 1


import os
from setuptools import setup, find_packages

with open("README.md", "r") as f:
    long_description = f.read()

setup(
    name='snaketrace',
    version='0.3.1',
    description='An strace-like tool for Python audit events',
    long_description=long_description,
    long_description_content_type="text/markdown",
    url='https://github.com/dcoles/snaketrace',
    packages=find_packages(),
    classifiers=[
        "Programming Language :: Python :: 3",
        "Programming Language :: Python :: 3.8",
        "License :: OSI Approved :: MIT License",
        "Operating System :: OS Independent",
    ],
    python_requires='>=3.8',
    entry_points={
        'console_scripts': [
            'snaketrace = snaketrace.__main__:main',
        ] + ([
            '\N{SNAKE}trace = snaketrace.__main__:main',
        ] if os.getenv('ANTIGRAVITY') else []),
    },
)


"""
-*- coding: utf-8 -*-

@Time    : 2021/10/21 10:03

@Author  : Wang Ziming

@Email   : zi_ming_wang@outlook.com

@File    : snn.py

Reference:
    1. Gu, Pengjie, et al. "STCA: Spatio-Temporal Credit Assignment with Delayed Feedback in Deep Spiking Neural Networks." IJCAI. 2019.
    2. Zimmer, Romain, et al. "Technical report: supervised training of convolutional spiking neural networks with PyTorch." arXiv preprint arXiv:1911.10124 (2019).
    3. 加速自定义RNN Cell: https://github.com/pytorch/pytorch/blob/963f7629b591dc9750476faf1513bc7f1fb4d6de/benchmarks/fastrnns/custom_lstms.py#L246
"""
import torch
import numpy as np
from .function import td_Dropout

class SNN(torch.nn.Module):

    def __init__(self, layers):

        super(SNN, self).__init__()
        self.layers = torch.nn.ModuleList(layers)

    def forward(self, x):
        loss_seq = []
        for l in self.layers:
            # if isinstance(l, tdBatchNorm):
            #     x = x.unsqueeze(1)
            #     x = x.unsqueeze(-1)
            #     # print(x.shape)
            #     x = l(x)
            #     x = x.squeeze()
            # else:
                x, loss = l(x)
                loss_seq.append(loss)

        return x, loss_seq

    def clamp(self):

        for l in self.layers:
                l.clamp()

    def reset_parameters(self):

        for l in self.layers:
                l.reset_parameters()

class STCADenseLayer(torch.nn.Module):

    def __init__(self, input_shape, output_shape, spike_fn, w_init_mean, w_init_std,
                 recurrent=False, lateral_connections=True, rc_drop=-1, fc_drop=-1, eps=1e-8):

        super(STCADenseLayer, self).__init__()

        self.input_shape = input_shape
        self.output_shape = output_shape
        self.spike_fn = spike_fn
        self.recurrent = recurrent
        self.eps = eps
        self.lateral_connections = lateral_connections

        self.w_init_mean = w_init_mean
        self.w_init_std = w_init_std

        self.w = torch.nn.Parameter(torch.empty((input_shape, output_shape)), requires_grad=True)
        if recurrent:
            self.v = torch.nn.Parameter(torch.empty((output_shape, output_shape)), requires_grad=True)

        # RNN Dropout
        self.fc_drop = fc_drop
        self.rc_drop = rc_drop
        if fc_drop > 0:
            self.drop_fc = td_Dropout(fc_drop, True)
        if rc_drop > 0:
            self.drop_rc = td_Dropout(rc_drop, True)

        self.b = torch.nn.Parameter(torch.empty(output_shape), requires_grad=True)  # threshhold

        # decay
        self.decay_m = torch.nn.Parameter(torch.empty(1), requires_grad=True)
        self.decay_s = torch.nn.Parameter(torch.empty(1), requires_grad=True)
        self.decay_e = torch.nn.Parameter(torch.empty(1), requires_grad=True)

        self.reset_parameters()
        self.clamp()

        self.spk_rec_hist = None

        self.training = True

    def forward(self, x):

        batch_size = x.shape[0]
        # update drop out mask
        if self.fc_drop > 0:
            self.drop_fc.reset()
        if self.rc_drop > 0:
            self.drop_rc.reset()
        # todo: 爱因斯坦求和标记，支持torch BP
        h = torch.einsum("abc,cd->abd", x, self.w)
        nb_steps = h.shape[1]

        # output spikes
        spk = torch.zeros((batch_size, self.output_shape), dtype=x.dtype, device=x.device)
        # refractory period kernel
        E = torch.zeros((batch_size, self.output_shape), dtype=x.dtype, device=x.device)
        # input response kernel
        M = torch.zeros((batch_size, self.output_shape), dtype=x.dtype, device=x.device)
        S = torch.zeros((batch_size, self.output_shape), dtype=x.dtype, device=x.device)

        # output spikes recording
        spk_rec = torch.zeros((batch_size, nb_steps, self.output_shape), dtype=x.dtype, device=x.device)

        if self.lateral_connections:  # 计算侧抑制权重
            d = torch.einsum("ab, ac -> bc", self.w, self.w)

        norm = (self.w ** 2).sum(0)  # 对每个输出神经元计算norm以约束权重

        for t in range(nb_steps):
            # input term
            input_ = h[:, t, :]
            if self.recurrent:
                if self.rc_drop > 0:
                    input_ = input_ + torch.einsum("ab,bc->ac", self.drop_rc(spk), self.v)
                else:
                    input_ = input_ + torch.einsum("ab,bc->ac", spk, self.v)

            # todo: add reset mechanism
            if self.lateral_connections:
                # 模拟侧抑制
                E = torch.einsum("ab,bc ->ac", spk, d)
            else:
                # 模拟refractory period
                E = self.decay_m * norm * (E + spk)

            M = self.decay_m * (M + input_)
            S = self.decay_s * (S + input_)

            # membrane potential update
            mem = M - S - E
            mthr = torch.einsum("ab,b->ab", mem, 1. / (norm + self.eps)) - self.b

            spk = self.spike_fn(mthr)
            spk_rec[:, t, :] = spk
            if self.fc_drop > 0:
                spk = self.drop_fc(spk)

            # save spk_rec for plotting
        self.spk_rec_hist = spk_rec.detach().cpu().numpy()  # 记录该层的脉冲发放 shape: batch_size x T x NeuIn

        loss = 0.5 * (spk_rec ** 2).mean()

        return spk_rec, loss

    # todo: 将权重的初始化逻辑从module中独立出来形成Initilizer
    def reset_parameters(self):

        torch.nn.init.normal_(self.w, mean=self.w_init_mean, std=self.w_init_std * np.sqrt(1. / self.input_shape))
        if self.recurrent:
            torch.nn.init.normal_(self.v, mean=self.w_init_mean, std=self.w_init_std * np.sqrt(1. / self.output_shape))
        torch.nn.init.normal_(self.decay_m, mean=0.6, std=0.01)
        torch.nn.init.normal_(self.decay_s, mean=0.9, std=0.01)
        torch.nn.init.normal_(self.decay_e, mean=0.9, std=0.01)
        torch.nn.init.normal_(self.b, mean=1., std=0.01)

    def reset_parameters_v2(self):
        torch.nn.init.normal_(self.w, mean=self.w_init_mean, std=self.w_init_std * np.sqrt(1. / self.input_shape))
        if self.recurrent:
            torch.nn.init.orthogonal(self.v)
        torch.nn.init.normal_(self.decay_m, mean=0.6, std=0.01)
        torch.nn.init.normal_(self.decay_s, mean=0.9, std=0.01)
        torch.nn.init.normal_(self.decay_e, mean=0.9, std=0.01)
        torch.nn.init.normal_(self.b, mean=1., std=0.01)

    def reset_parameters_v3(self):
        torch.nn.init.orthogonal(self.w)
        if self.recurrent:
            torch.nn.init.orthogonal(self.v)
        torch.nn.init.normal_(self.decay_m, mean=0.6, std=0.01)
        torch.nn.init.normal_(self.decay_s, mean=0.9, std=0.01)
        torch.nn.init.normal_(self.decay_e, mean=0.9, std=0.01)
        torch.nn.init.normal_(self.b, mean=1., std=0.01)

    def reset_parameters_v4(self):
        torch.nn.init.xavier_normal_(self.w)
        if self.recurrent:
            torch.nn.init.xavier_normal_(self.v)
        torch.nn.init.normal_(self.decay_m, mean=0.6, std=0.01)
        torch.nn.init.normal_(self.decay_s, mean=0.9, std=0.01)
        torch.nn.init.normal_(self.decay_e, mean=0.9, std=0.01)
        torch.nn.init.normal_(self.b, mean=1., std=0.01)

    # todo: 将decay改为可学习的softmax门控机制
    def clamp(self):
        self.decay_m.data.clamp_(0., 1.)
        self.decay_e.data.clamp_(0., 1.)
        self.decay_s.data.clamp_(0., 1.)
        self.b.data.clamp_(min=0.)

class ReadoutLayer(torch.nn.Module):
    "Fully connected readout"

    def __init__(self, input_shape, output_shape, w_init_mean, w_init_std, eps=1e-8, time_reduction="mean"):

        assert time_reduction in ["mean", "max"], 'time_reduction should be "mean" or "max"'

        super(ReadoutLayer, self).__init__()

        self.input_shape = input_shape
        self.output_shape = output_shape

        self.w_init_mean = w_init_mean
        self.w_init_std = w_init_std

        self.eps = eps
        self.time_reduction = time_reduction

        self.w = torch.nn.Parameter(torch.empty((input_shape, output_shape)), requires_grad=True)
        if time_reduction == "max":
            self.beta = torch.nn.Parameter(torch.tensor(0.7 * np.ones((1))), requires_grad=True)
        self.b = torch.nn.Parameter(torch.empty(output_shape), requires_grad=True)

        self.reset_parameters()
        self.clamp()

        self.mem_rec_hist = None

    def forward(self, x):

        batch_size = x.shape[0]

        h = torch.einsum("abc,cd->abd", x, self.w)

        norm = (self.w ** 2).sum(0)

        if self.time_reduction == "max":
            nb_steps = x.shape[1]
            # membrane potential
            mem = torch.zeros((batch_size, self.output_shape), dtype=x.dtype, device=x.device)

            # memrane potential recording
            mem_rec = torch.zeros((batch_size, nb_steps, self.output_shape), dtype=x.dtype, device=x.device)

            for t in range(nb_steps):
                # membrane potential update
                mem = mem * self.beta + (1 - self.beta) * h[:, t, :]
                mem_rec[:, t, :] = mem

            output = torch.max(mem_rec, 1)[0] / (norm + 1e-8) - self.b

        elif self.time_reduction == "mean":

            mem_rec = h
            output = torch.mean(mem_rec, 1) / (norm + 1e-8) - self.b

        # save mem_rec for plotting
        self.mem_rec_hist = mem_rec.detach().cpu().numpy()

        loss = None

        return output, loss

    def reset_parameters(self):
        torch.nn.init.normal_(self.w, mean=self.w_init_mean,
                              std=self.w_init_std * np.sqrt(1. / (self.input_shape)))

        if self.time_reduction == "max":
            torch.nn.init.normal_(self.beta, mean=0.7, std=0.01)

        torch.nn.init.normal_(self.b, mean=0., std=0.01)

    def reset_parameters_v4(self):
        torch.nn.init.xavier_normal_(self.w)

        if self.time_reduction == "max":
            torch.nn.init.normal_(self.beta, mean=0.7, std=0.01)

        torch.nn.init.normal_(self.b, mean=1., std=0.01)

    def clamp(self):

        if self.time_reduction == "max":
            self.beta.data.clamp_(0., 1.)


# -*- encoding=utf8 -*-
__author__ = "TS"

from airtest.core.api import *
from airtest.report.report import simple_report
from global_auto_agr import AUTO_SETUP_ARG
from try_test_method import run_logger, remove_log_dir
from general_steps_tasia import *

def skip_daily_popup():
    if exists(button_pass()):
        touch_button_back_popup()

def test_debug_clear():
    touch_debug()
    for i in range(5):
        (touch_minus_1())
    for i in range(3):
        (touch_minus_10())
    touch_hide()

def test_press_market_button():
    touch_icon_shop()
    assert_text_shop()

def test_locked_purchases():
    touch_50()
    assert_not_exists_claim()
    touch_200()
    assert_not_exists_claim()
    touch_600()
    assert_not_exists_claim()

def test_ads_hint():
    touch_ads_hint()
    touch_close_ads()
    assert_hint_x1()
    assert_x1()
    assert_claim()

def test_receiving_hint():
    touch_button_claim()
    assert_1()

def test_ads_coins():
    touch_debug()
    touch_plus_100()
    touch_hide()
    touch_ads_coins()
    touch_close_ads()
    assert_coins_x10()
    assert_x10()
    assert_claim()

def test_receiving_coins():
    touch_button_claim()
    assert_coins11()

def debug():
    touch_debug()
    for i in range(8):
        (touch_plus_100())
    touch_plus_1()
    touch_reload()
    assert_91()

def test_purchases_for_50coins():
    touch_icon_shop()
    touch_50()
    assert_hint_x1()
    assert_x1()
    touch_button_claim()
    assert_hint3()

def test_purchases_for_200coins():
    touch_200()
    assert_hint_x1()
    assert_5()
    touch_button_claim()
    assert_8()

def test_purchases_for_600coins():
    touch_600()
    assert_hint_x1()
    assert_20()
    touch_button_claim()
    assert_28()

def test_purchases_for_0dollars():
    touch_price_0()
    assert_text_hint_ads()
    android_quantity1()
    android_price0()
    touch_buy()
    assert_hint_x1()
    assert_x1()
    touch_button_claim()
    assert_29()

def test_purchase_failed():
    touch_price_4()
    touch_loading()
    assert_text_oops()
    touch_button_yes()

def run_shop_new():
    remove_log_dir('shop_new')
    auto_setup(
        __file__,
        logdir=AUTO_SETUP_ARG.get('logdir'),
        devices=[AUTO_SETUP_ARG.get('devices'), ],
        project_root=AUTO_SETUP_ARG.get('project_root'),
    )
    start_app("com.jollyco.jbpuzzleadventure")
    run_logger(skip_system_pop)
    run_logger(skip_daily_popup)
    run_logger(test_debug_clear)
    run_logger(test_press_market_button)
    run_logger(test_locked_purchases)
    run_logger(test_ads_hint)
    run_logger(test_receiving_hint)
    run_logger(test_ads_coins)
    run_logger(test_receiving_coins)
    run_logger(debug)
    run_logger(test_purchases_for_50coins)
    run_logger(test_purchases_for_200coins)
    run_logger(test_purchases_for_600coins)
    run_logger(test_purchases_for_0dollars)
    run_logger(test_purchase_failed)
    stop_app("com.jollyco.jbpuzzleadventure")
    simple_report(__file__, logpath=True, output='html_report/shop.html')