from django.shortcuts import render
from django.shortcuts import render, get_object_or_404, redirect
from .models import Post
from .forms import PostForm
from django.views.decorators.http import require_POST
from django.db.models import Q

def main(request):
    return render(request, 'posts/main.html')

def show(request):
    posts = Post.objects.order_by('-updated_at')
    post_sorted3 = []
    post_sorted2 = []
    post_sorted0 = []

    for post in posts:
        if post._type == 3:
            post_sorted3.append(post)
        elif post._type == 2:
            post_sorted2.append(post)
        elif post._type == 0:
            post_sorted0.append(post)

    context = {
        'posts': posts,
        'post_sorted3': post_sorted3,
        'post_sorted2': post_sorted2,
        'post_sorted0': post_sorted0,
    }
    return render(request, 'posts/show.html', context)

def service(request):
    return render(request, 'posts/service.html')

def detail(request, post_id):
    post = get_object_or_404(Post, pk=post_id)
    post.save()
    context = {
        'post': post
    }
    return render(request, 'posts/detail.html', context)

def search(request):
    posts = Post.objects.all().order_by('-id')

    q = request.POST.get('q', "")

    if q:
        posts = posts.filter(Q(title__icontains=q) | Q(content__icontains=q))
        return render(request, 'posts/search.html', {'posts': posts, 'q': q})
    else:
        return render(request, 'posts/show.html')


"""
This script fetch an AAD token for an Azure Application using its client ID, client secret, and tenant ID. This AAD
token is then used to authenticate the Databricks service principal so it can then provision itself a personal access
token (PAT). The script was written in Python to be as platform-agnostic as possible (as compared to something like
curl) but that means Python3 is a necessary dependency to use this module.
"""
import urllib.request
import json
import sys

input = json.loads(sys.stdin.read())
url = f'https://login.microsoftonline.com/{input.get("tenant_id")}/oauth2/v2.0/token'
data = (f'client_id={input.get("client_id")}&'
        'grant_type=client_credentials&'
        'scope=2ff814a6-3304-4ab8-85cb-cd0e6f879c1d%2F.default&'  # programmatic ID for Azure Databricks
        f'client_secret={input.get("client_secret")}').encode('utf-8')

request = urllib.request.Request(url, data=data)
response = json.load(urllib.request.urlopen(request))
token = {
    "token": response.get("access_token")
}
print(json.dumps(token))


import os
import pickle
import numpy as np
import matplotlib.pyplot as plt
from parameters import *
from utils import figure_plot
from data.feature_extraction import mfcc_extraction

# path
dir_path = os.path.dirname(os.path.realpath(__file__))
path_pretrained_model = os.path.join(dir_path, 'pretrained_models/mfcc_delta')
path_training_data = os.path.join(dir_path, 'training_data/pomegranate_mfcc_delta')
test_wav_file = './test/reference_exercise_01_norm.wav'
scaler = pickle.load(open(os.path.join(path_training_data, 'scaler.pkl'), 'rb'))

# load the recognition HMM
hmm_conc = pickle.load(open(os.path.join(path_pretrained_model, 'hmm_conc.pkl'), 'rb'))

mfcc_test, sr_test = mfcc_extraction(test_wav_file, framesize_t=framesize_t, hopsize_t=hopsize_t)

# obtain the decoding path
path = hmm_conc.predict(scaler.transform(mfcc_test.T), algorithm='viterbi')

dict_state = dict()
for id, state in enumerate(hmm_conc.states):
    dict_state[id] = state.name

path = [dict_state[id] for id in path if dict_state[id] != 'hmm_conc-start']
onset_label = [[0, path[0]]]
for ii in range(1, len(path)):
    if path[ii].split('-')[0] != path[ii-1].split('-')[0] and path[ii][0] != path[ii-1][0]:
        onset_label.append((ii, path[ii]))

print(len(mfcc_test.T))
print(len(path))
print(onset_label)

figure_plot(plt=plt, mfcc=mfcc_test.T, onset_label=onset_label)
plt.show()


from marketing_automation.entities.object import Object
import requests
import json

class OntraportApi():

    url = "https://api.ontraport.com/1/"

    def contact(self, context, params):
        """Retrieve contact by id"""

        # Set headers
        headers = {
            "Api-Key": context.get('headers').get('api_key'),
            "Api-Appid": context.get('headers').get('app_id')
        }

        response = requests.request("GET", f'{self.url}Contact?id={params.get("id")}', headers= headers).text
        return json.loads(response)

    def objects(self, context, params):
        """Retrieve all objects"""

        # Set headers
        headers = {
            "Api-Key": context.get('headers').get('api_key'),
            "Api-Appid": context.get('headers').get('app_id')
        }

        params = {
            "objectID": params.get("objectID", 0),
            "sortDir": params.get("sortDir", "desc")
        }

        response = requests.request("GET", f'{self.url}objects', headers= headers, params=params).text
        return json.loads(response)

    def objects_by_tag_name(self, context, params):
        """List objects with certian tag"""

        # Set headers
        headers = {
            "Api-Key": context.get('headers').get('api_key'),
            "Api-Appid": context.get('headers').get('app_id')
        }

        params = {
            "objectID": params.get("objectID", 0),
            "tag_id": params.get("tag_id", 1),
            "listFields": params.get("listFields", None),
        }

        response = requests.request("GET", f'{self.url}objects/tag', headers= headers, params=params).text
        return json.loads(response)

    def verify(self, context, params):
        """Verify the app"""

        # Set headers
        headers = {
            "Api-Key": context.get('headers').get('api_key'),
            "Api-Appid": context.get('headers').get('app_id')
        }

        response = requests.request("GET", f'{self.url}CreditCards?range=1', headers= headers).text
        return json.loads(response)


#external library
import numpy as np
from matplotlib.pyplot import imshow, figure, draw
#internal library
from setproc.map.functions.map_functions import plot_profile_h, plot_profile
from setproc.data_containers.classes.sweep_set import SweepSet

class Map(dict):
    """
    Create a Map object

    This object is used whenever a SweepSet can be represented by a colormap

    Keyword arguments
    data -- either a filename or a SweepSet object
    type -- either the filename extension or "obj" in case of SweepSet object

    Note : for the moment only *.npz and *.json files are supported

    """

    def __init__(self, data, data_type="json"):
        dict.__init__(self)

        self.fig = "None" #contains the figure related to the plot
        self.im = "None"  #contains the image related to the plot
        self.ax = "None"  #contains the axes related to the plot

        if data_type == "obj" :
            self.sweeps = data
        else :
            self.sweeps = SweepSet(data, data_type)

    def SetExtent(self, extent):
        """
        Define the extent of the map

        Keyword argument :
        extent -- array of the form [xmin, xmax, ymin, ymax]

        Notes :
        ymin and ymax can be different from the one of the sweeps.. be carreful !!
        """
        self["extent"] = extent
        try :
            self.im.set_extent(extent)
            self.ax.set_aspect("auto")
            draw()
        except AttributeError :
            print("You habe to create a plot first")

    def SetXLabel(self, label):
        """ Set the xlabel of the plot """
        self["xlabel"] =  label
        try :
            self.ax.set_xlabel(label)
            draw()
        except AttributeError:
            print("You habe to create a plot first")

    def SetYLabel(self, label):
        """ Set the ylabel of the plot """
        self["ylabel"] =  label
        try :
            self.ax.set_ylabel(label)
            draw()
        except AttributeError:
            print("You habe to create a plot first")

    def PlotMap(self):
        """Plot the colormap """
        #etxract data
        data = []
        si = self.sweeps.GetSize()
        for i in range(si) :
            temp_sweep = self.sweeps["sweeps"][i]
            data.append(temp_sweep.y)
        data = np.matrix(data)
        data = data.transpose()
        data = data.tolist()
        #plot data
        self.fig = figure()
        self.ax = self.fig.add_subplot(111)
        self.im = imshow(data, interpolation="nearest", origin="lower")

    def PlotExtrema(self, newplot=True,other_axes="None", color = ["blue", "red"]):
        """Plot the extream position"""
        toplot = self.sweeps.GetExtrema()
        si = self.sweeps.GetSize()
        proceed = False
        if newplot :
            fig = figure()
            ax = fig.add_subplot(111)
        elif other_axes != "None":
            ax = other_axes
        else :
            ax = self.ax

        try :
            xmin = self["extent"][0]
            xmax = self["extent"][1]
            proceed = True
        except KeyError:
            print("you have to defined extent first")

        if(proceed):
            bias = np.linspace(xmin, xmax, si)
            x =[]
            ymin = []
            ymax = []
            for i in range(si):
                x.append(bias[i])
                ymin.append(toplot[i][1])
                ymax.append(toplot[i][3])
            ax.plot(x, ymin, ".", color = color[0], markersize=1)
            ax.plot(x, ymax, ".", color = color[1], markersize=1)

    def PlotFilteredExtrema(self, sensitivity=10, newplot=True,
                            other_axes="None",mode ='max',
                            color =["blue","red"]):
        """
        Plot the filtered extrema
        """
        toplot = self.sweeps.GetFilteredExtrema(sensitivity, mode)
        si = self.sweeps.GetSize()
        proceed = False
        if newplot :
            fig = figure()
            ax = fig.add_subplot(111)
        elif other_axes != "None":
            ax = other_axes
        else :
            ax = self.ax

        try :
            xmin = self["extent"][0]
            xmax = self["extent"][1]
            proceed = True
        except KeyError:
            print("you have to defined extent first")

        if(proceed):
            bias = np.linspace(xmin, xmax, si)
            bmin = []
            ymin = []
            bmax = []
            ymax = []
            for i in range(si):
                #min first
                if np.size(toplot[i][1]) != 0:
                    bmin.append(bias[i])
                    ymin.append(toplot[i][1])
                #then max
                if np.size(toplot[i][3]) != 0:
                    bmax.append(bias[i])
                    ymax.append(toplot[i][3])
            ax.plot(bmin, ymin, ".", color = color[0], markersize=1)
            ax.plot(bmax, ymax, ".", color = color[1], markersize=1)

    def PlotSteps(self,i_start, width1, width2, stat_type="global",
                 span=50, normalized=True, power=1, newplot=True,
                 other_axes="None",seuil=False,seuil1=0,seuil2=1):
        """
        Plot the step positions in the set of sweep

        Keyword arguments :
        i_start    -- number of points truncated to the sweep before applying the filter
        width1     -- width in points of the first mowing average windows
        width2     -- width of the post filtering moving average
        normalized -- if set True, the signal is renormalized (default True)
        power      -- power applied after filtering (default 1 -- should be soon removed)
        newplot    -- if True plotted in a different plot (default True)
        other_axes -- axes, if newplot set to false, the curve will be plot using these axes
        stat_type  -- if set "global", use the global extrema, if set to local, use the local ones
        span       -- if stat_type set to "local", define the span between two extrema
        seuil      -- if True, the local minimum use the seuil parameters (default False)
        seuil1     -- minimum value for a jump to be taken (default 0)
        seuil2     -- maximum value for a jump to be taken (default 1)
        """
        toplot = self.sweeps.GetStat(i_start, width1, width2,
                                    normalized, power,
                                    stat_type, span,
                                    seuil, seuil1, seuil2)
        si = self.sweeps.GetSize()
        proceed = False

        if  newplot :
            fig = figure()
            ax = fig.add_subplot(111)
        elif other_axes != "None" :
            ax = other_axes
        else :
            ax = self.ax

        try :
            xmin = self["extent"][0]
            xmax = self["extent"][1]
            proceed = True
        except KeyError:
            print("You have to define the exetent first")

        if(proceed and stat_type == "global"):
            bias = np.linspace(xmin, xmax, si)
            x = []
            ymin = []
            ymax = []
            for i in range(si) :
                x.append(bias[i])
                ymin.append(toplot[i][1])
                ymax.append(toplot[i][3])
            ax.plot(x, ymin, ".b", markersize=1)
            ax.plot(x, ymax, ".r", markersize=1)

        elif proceed and stat_type == "local" :
            bias = np.linspace(xmin, xmax, si)
            xmin = []
            xmax = []
            ymin = []
            ymax = []
            for i in range(si):
                si_min = np.size(toplot[i][1])
                si_max = np.size(toplot[i][3])
                for j in range(si_min):
                    ymin.append(toplot[i][1][j])
                    xmin.append(bias[i])
                for j in range(si_max):
                    ymax.append(toplot[i][3][j])
                    xmax.append(bias[i])
            ax.plot(xmin, ymin, ".b", markersize=1)
            ax.plot(xmax, ymax, ".r", markersize=1)

    def PlotVProfile(self):
        """
        Plot a vertical profile of the Map

        Select a point on the colormap for which you want a profile

        """
        print('select a point on the colormap')
        return plot_profile(self.im)

    def PlotHProfile(self):
        """
        Plot a horizontal profile of the Map

        Select a point on the colormap for which you want a profile

        """
        print('select a point on the colormap')
        return plot_profile_h(self.im)


from setuptools import setup, find_packages  # Always prefer setuptools over distutils
from codecs import open  # To use a consistent encoding
from os import path

def read(*paths):
    """Build a file path from *paths* and return the contents."""
    with open(os.path.join(*paths), 'r') as f:
        return f.read()

here = path.abspath(path.dirname(__file__))

# Get the long description from the relevant file
with open(path.join(here, 'DESCRIPTION.rst'), encoding='utf-8') as f:
    long_description = f.read()

setup(
    name='Xymon_Class',

    # Versions should comply with PEP440.  For a discussion on single-sourcing
    # the version across setup.py and the project code, see
    # http://packaging.python.org/en/latest/tutorial.html#version
    version='0.1.0',

    description='A simple Class to manipulate Xymon test script',
    long_description=long_description,

    py_modules=['Xymon_Class'],

    # The project's main homepage.
    url='https://github.com/erikbeauvalot/Xymon_Class',

    # Author details
    author='Erik Beauvalot',
    author_email='erik@beauvalot.com',

  )


from django.contrib import admin
from contact import models

@admin.register(models.Message)
class MessageAdmin(admin.ModelAdmin):
    search_fields = [
        "name",
        "email",
        "phone",
        "country",
        "city",
        "subject",
        "message",
    ]
    list_display = [
        "subject",
        "name",
        "email",
        "date_created",
        "is_read",
    ]
    list_filter = ["country", "city"]
    readonly_fields = [
        "name",
        "email",
        "phone",
        "country",
        "city",
        "subject",
        "message",
    ]

    def has_add_permission(self, request, obj=None):
        return False


# import pandas, numpy, and matplotlib
import pandas as pd
from feature_engine.encoding import OneHotEncoder
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.neighbors import KNeighborsClassifier
from sklearn.ensemble import RandomForestClassifier
import sklearn.metrics as skmet
#import matplotlib.pyplot as plt
pd.set_option('display.width', 75)
pd.set_option('display.max_columns', 20)
pd.set_option('display.max_rows', 200)
pd.options.display.float_format = '{:,.2f}'.format

nls97compba = pd.read_csv("data/nls97compba.csv")

feature_cols = ['satverbal','satmath','gpaoverall',
  'parentincome','gender']

# separate NLS data into train and test datasets
X_train, X_test, y_train, y_test =  \
  train_test_split(nls97compba[feature_cols],\
  nls97compba[['completedba']], test_size=0.3, random_state=0)

# do one hot encoding and scaling
ohe = OneHotEncoder(drop_last=True, variables=['gender'])
ohe.fit(X_train)
X_train_enc, X_test_enc = \
  ohe.transform(X_train), ohe.transform(X_test)

scaler = StandardScaler()
standcols = X_train_enc.iloc[:,:-1].columns
scaler.fit(X_train_enc[standcols])
X_train_enc = \
  pd.DataFrame(scaler.transform(X_train_enc[standcols]),
  columns=standcols, index=X_train_enc.index).\
  join(X_train_enc[['gender_Female']])
X_test_enc = \
  pd.DataFrame(scaler.transform(X_test_enc[standcols]),
  columns=standcols, index=X_test_enc.index).\
  join(X_test_enc[['gender_Female']])

# k nearest neighbor classification
knn = KNeighborsClassifier(n_neighbors = 5)
knn.fit(X_train_enc, y_train.values.ravel())
pred = knn.predict(X_test_enc)

# show a confusion matrix
cm = skmet.confusion_matrix(y_test, pred, labels=knn.classes_)
cmplot = skmet.ConfusionMatrixDisplay(confusion_matrix=cm, \
 display_labels=['Negative--No BA', 'Positive--Completed BA'])
cmplot.plot()
cmplot.ax_.set(title='Confusion Matrix',
  xlabel='Predicted Value', ylabel='Actual Value')

# calculate accuracy, sensitivity, specificity, and precision
tn, fp, fn, tp = skmet.confusion_matrix(y_test.values.ravel(), pred).ravel()
tn, fp, fn, tp
accuracy = (tp + tn) / pred.shape[0]
accuracy
sensitivity = tp / (tp + fn)
sensitivity
specificity = tn / (tn+fp)
specificity
precision = tp / (tp + fp)
precision

print("accuracy: %.2f, sensitivity: %.2f, specificity: %.2f, precision: %.2f"  %
  (skmet.accuracy_score(y_test.values.ravel(), pred),
  skmet.recall_score(y_test.values.ravel(), pred),
  skmet.recall_score(y_test.values.ravel(), pred, pos_label=0),
  skmet.precision_score(y_test.values.ravel(), pred)))

# try this with a random forest classifier
rfc = RandomForestClassifier(n_estimators=100, max_depth=2,
  n_jobs=-1, random_state=0)
rfc.fit(X_train_enc, y_train.values.ravel())
pred = rfc.predict(X_test_enc)
tn, fp, fn, tp = skmet.confusion_matrix(y_test.values.ravel(), pred).ravel()
tn, fp, fn, tp

print("accuracy: %.2f, sensitivity: %.2f, specificity: %.2f, precision: %.2f"  %
  (skmet.accuracy_score(y_test.values.ravel(), pred),
  skmet.recall_score(y_test.values.ravel(), pred),
  skmet.recall_score(y_test.values.ravel(), pred, pos_label=0),
  skmet.precision_score(y_test.values.ravel(), pred)))


from flask import abort, flash, redirect, render_template

from settings import INDEX_URL, MAIN_PAGE_TEMPLATE, MAIN_URL, REDIRECT_URL
from yacut.forms import UrlForm
from yacut.models import URLMap
from . import app, db

@app.route(REDIRECT_URL, methods=['GET'])
def redirect_view(custom_id):
    urlmap = URLMap.check_custom_id_exists(custom_id)
    if urlmap is not None:
        original_url = urlmap.original
        return redirect(original_url)
    abort(404)

@app.route(INDEX_URL, methods=['GET', 'POST'])
def index_view():
    form = UrlForm()
    if form.validate_on_submit():
        custom_id = form.custom_id.data
        if custom_id is None or len(custom_id) == 0:
            custom_id = URLMap.generate_custom_id()
            short_url = URLMap.create_short_link(custom_id)
        else:
            if URLMap.check_custom_id_exists(custom_id):
                flash(f'Имя {custom_id} уже занято!')
                return render_template(MAIN_PAGE_TEMPLATE, form=form)
        urlmap = URLMap(
            original=form.original_link.data,
            short=custom_id
        )
        short_url = MAIN_URL + custom_id
        db.session.add(urlmap)
        db.session.commit()
        return render_template(MAIN_PAGE_TEMPLATE, short_url=short_url, form=form)
    return render_template(MAIN_PAGE_TEMPLATE, form=form)


import os
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler
import struct
#os.environ['MPLCONFIGDIR'] = "/home/rsa/.config/matplotlib"
#os.environ['MPLCONFIGDIR'] = "/home/rsa/.cache/matplotlib"
import matplotlib
import matplotlib.pyplot as plt
import matplotlib.animation as animation

#print (matplotlib.rcParams['backend']) #Muestra en backend utilizado: QtAgg
#matplotlib.use('QtAgg') #Forza a ultizar el backend QtAgg

#********************************************************************************
#Variables y parametros
#********************************************************************************

filepath = "/home/rsa/TMP/temporalCanal.txt"

#Variables globales
valCH1 = 0
valCH2 = 0
valCH3 = 0

#********************************************************************************
#Parametros del grafico

x_len = 120         # Number of points to display
y_range = [0, 4095]  # Range of possible Y values to display

# Crea la figura y los subplots
plt.style.use('dark_background') #Utiliza el modo oscuro
plt.rcParams['toolbar'] = 'None' #Oculta la barra de tareas
fig = plt.figure()
plt.get_current_fig_manager().full_screen_toggle() #Fullscreen mode

ax1 = fig.add_subplot(3, 1, 1)
ax2 = fig.add_subplot(3, 1, 2)
ax3 = fig.add_subplot(3, 1, 3)

#Establece los limistes del eje X
xs = list(range(0, 120))
ys1 = [0] * x_len
ys2 = [0] * x_len
ys3 = [0] * x_len

#Establece los limites del eje Y
ax1.set_ylim(y_range)
ax2.set_ylim(y_range)
ax3.set_ylim(y_range)

#Establece los colores de fondo de los subplots
ax1.set_facecolor('#181c1fff')
ax2.set_facecolor('#181c1fff')
ax3.set_facecolor('#181c1fff')

#Establece el estilo del grid
ax1.grid(linestyle='-',linewidth=0.2)
ax2.grid(linestyle='-',linewidth=0.2)
ax3.grid(linestyle='-',linewidth=0.2)

#Establece las marcas del eje X
plt.setp(ax1.get_xticklabels(), visible=False)     #Borra las marcar del plot x1
plt.setp(ax2.get_xticklabels(), visible=False)     #Borra las marcar del plot x2
ax3.set_xticks([0,20,40,60,80,100,120])            #Selecciona las marcas de los puntos extremos y mitad del eje X
ax3.set_xticklabels([-60,'','',-30,'','',0])       #Remplaza las marcas seleccionadas por los valores 0, 30 y 60
ax1.tick_params(labelsize=9,labelcolor='gray')
ax2.tick_params(labelsize=9,labelcolor='gray')
ax3.tick_params(labelsize=9,labelcolor='gray')

#Establece las etiquetas de los ejes X y Y
ax1.set_ylabel('CH1')
ax2.set_ylabel('CH2')
ax3.set_ylabel('CH3')
ax3.set_xlabel('Tiempo [seg]')

# Create a blank line. We will update the line in animate
line1, = ax1.plot(xs, ys1, color='#5bd15eff')
line2, = ax2.plot(xs, ys2, color='#5bd15eff')
line3, = ax3.plot(xs, ys3, color='#5bd15eff')

#********************************************************************************

#********************************************************************************
#Metodo para leer el archivo de texto y extraer los valores de los 3 ejes:
#********************************************************************************
def LeerArchivo():

    #variables globales
    global valCH1
    global valCH2
    global valCH3

    formatoUnpack = '<' + '3' + 'I'

    #print("imprimiendo...")
    # Abre el archivo para lectura de binarios "rb"
    #objFile = open(filepath, "rb")
    with open(filepath, "rb") as objFile:
        # Lee el total de bytes del archivo, se guarda en un array de bytes
        bytesLeidos = objFile.read()
        # Realiza la conversion de array de bytes a lista de enteros
        vectorDatos = struct.unpack(formatoUnpack, bytesLeidos)
    #Extrae los valores de los 3 ejes
    valCH1 = vectorDatos[0]
    valCH2 = vectorDatos[1]
    valCH3 = vectorDatos[2]
    print("%d   %d   %d" % (valCH1, valCH2, valCH3))

    # Al final cierra el archivo de lectura
    #objFile.close()
#********************************************************************************

#********************************************************************************
#Esta funcion se llama periodicamente desde FuncAnimation
#********************************************************************************
def animate(i):

    global xs
    global ys1
    global ys2
    global ys3

    # Actualiza la medicion de los canales CH1, CH2 y CH3
    medCH1 = valCH1
    medCH2 = valCH2
    medCH3 = valCH3

    # Add x and y to lists
    ys1.append(medCH1)
    ys2.append(medCH2)
    ys3.append(medCH3)

    # Limit y list to set number of items
    ys1 = ys1[-x_len:]
    ys2 = ys2[-x_len:]
    ys3 = ys3[-x_len:]

    line1.set_data(xs,ys1)
    line2.set_data(xs,ys2)
    line3.set_data(xs,ys3)

    return line1,line2,line3
#********************************************************************************

#********************************************************************************
#Clase para monitorizar cambios en los archivos:
#********************************************************************************
class MyEventHandler(FileSystemEventHandler):
    # def on_modified(self, event):
    #     #print(event.src_path, "modificado.")
    #     LeerArchivo()

    def on_closed(self, event):
        LeerArchivo()
#********************************************************************************

#********************************************************************************
#Main
#********************************************************************************
observer = Observer()
observer.schedule(MyEventHandler(), filepath, recursive=False)
observer.start()

# Set up plot to call animate() function periodically
ani = animation.FuncAnimation(fig, animate, interval=500, blit=True)
plt.show()

try:
    while observer.is_alive():
        observer.join(1)
        print("Verificando archivo...")
except KeyboardInterrupt:
    observer.stop()
observer.join()

#********************************************************************************


from django.db import models
from django.utils.safestring import mark_safe
from edc_constants.choices import YES_NO, YES_NO_NA
from edc_constants.constants import NOT_APPLICABLE
from edc_model import models as edc_models
from edc_model.models import date_not_future

class ClinicalReviewBaselineHtnModelMixin(models.Model):

    htn_test = models.CharField(
        verbose_name="Has the patient ever tested for Hypertension?",
        max_length=15,
        choices=YES_NO,
    )

    htn_test_ago = edc_models.DurationYMDField(
        verbose_name="If Yes, how long ago was the patient tested for Hypertension?",
        null=True,
        blank=True,
    )

    htn_test_estimated_datetime = models.DateTimeField(
        null=True, blank=True, help_text="calculated by the EDC using `htn_test_ago`",
    )

    htn_test_date = models.DateField(
        verbose_name="Date of patient's most recent Hypertension test?",
        validators=[date_not_future],
        null=True,
        blank=True,
    )

    htn_dx = models.CharField(
        verbose_name=mark_safe("Has the patient ever been diagnosed with Hypertension"),
        max_length=15,
        choices=YES_NO_NA,
        default=NOT_APPLICABLE,
        help_text="If yes, complete form `Hypertension Initial Review`",
    )

    def save(self, *args, **kwargs):
        if self.htn_test_ago:
            self.htn_test_estimated_datetime = edc_models.duration_to_date(
                self.htn_test_ago, self.report_datetime
            )
        super().save(*args, **kwargs)

    class Meta:
        abstract = True


import matplotlib.pyplot as plt

fig = plt.figure()
ax = fig.add_subplot(111)

def draw(xCords, yCords, filename, col):
    plt.xlabel("x")
    plt.ylabel("y")
    plt.title(filename)
    plt.plot(xCords, yCords, '-o', color=col, markersize = 1, linewidth = 2)
    for xy in zip(xCords, yCords): # If you don't want the co-ordinates to show up delete this loop
        ax.annotate('(%s, %s)' % xy, xy=xy, textcoords='data')

def toXandY(unorderedData):
    "This method converts seperates x and y co-ordinates for plotting"
    orderedData = []
    orderedData.append([])        # Add a new sublist every time
    orderedData.append([])        # Add a new sublist every time
    listSize = len(unorderedData)
    for x in range(0, listSize):
        orderedData[0].append(unorderedData[x][0])  # Seperates the x-cords
    for y in range(0, listSize):
        orderedData[1].append(unorderedData[y][1])  # Seperates the y-cords
    return orderedData

def plotLines(data):
    "Pass list of points to this method, two consecutive points must be a line"
    newData = []
    line_x = []
    line_y = []
    file_name = "file"
    list_size = len(data)
    for i in range(0, list_size):    # Converting the string list to float
        newData.append([])          # Add a new sublsit every time
        for j in range(0, 2):       # Append converted data to the new list
            newData[i].append(float(data[i][j]))
    DataXandY = toXandY(newData)     # DataXandY -> [[Xs][Ys]]
    while len(DataXandY[0]) != 0:
        # Pop two points to form a line
        line_x.append(DataXandY[0].pop(0))
        line_y.append(DataXandY[1].pop(0))
        line_x.append(DataXandY[0].pop(0))
        line_y.append(DataXandY[1].pop(0))
        draw(line_x, line_y, file_name, "g")
        line_x[:] = []          # Delete the contents
        line_y[:] = []          # Delete the contents

    plt.gca().set_aspect('equal', adjustable='box')
    plt.show()

def main():
    data = [[5.09,5.80], [1.68,4.90],[1.68,4.90], [1.48,1.38],[1.48,1.38], [4.76,0.10],[4.76,0.10], [7.00,2.83],[7.00,2.83],[5.09,5.80]]
    plotLines(data)
    # Plot pentagon

if __name__ == "__main__":
    main()


from lib2to3.pgen2.token import TILDE
from telnetlib import PRAGMA_HEARTBEAT
from utils.asa import ÁrbolSintáxisAbstracta, NodoÁrbol, TipoNodo
from utils.tipos_datos import TipoDatos

class TablaSímbolos:
    """
    Almacena información auxiliar para decorar el árbol de sintáxis
    abstracta con información de tipo y alcance.

    La estructura de símbolos es una lista de diccionarios
    """

    profundidad: int = 0
    símbolos: list = []

    def abrir_bloque(self):
        """
        Inicia un bloque de alcance (scope)
        """
        self.profundidad += 1

    def cerrar_bloque(self):
        """
        Termina un bloque de alcance y al acerlo elimina todos los
        registros de la tabla que estan en ese bloque
        """

        for registro in self.símbolos:
            if registro['profundidad'] == self.profundidad:
                self.símbolos.remove(registro)

        self.profundidad -= 1

    def nuevo_registro(self, nodo, nombre_registro=''):
        """
        Introduce un nuevo registro a la tabla de símbolos
        """
        # El nombre del identificador + el nivel de profundidad

        """
        Los atributos son: nombre, profundidad, referencia

        referencia es una referencia al nodo dentro del árbol
        (Técnicamente todo lo 'modificable (mutable)' en python es una
        referencia siempre y cuando use la POO... meh... más o menos.
        """

        diccionario = {}

        diccionario['nombre'] = nodo.contenido
        diccionario['profundidad'] = self.profundidad
        diccionario['referencia'] = nodo

        self.símbolos.append(diccionario)

    def verificar_existencia(self, nombre):
        """
        Verficia si un identificador existe cómo variable/función global o local
        """
        for registro in self.símbolos:

            # si es local
            if registro['nombre'] == nombre and \
                    registro['profundidad'] <= self.profundidad:
                return registro

        return -1

    def __str__(self):

        resultado = 'TABLA DE SÍMBOLOS\n\n'
        resultado += 'Profundidad: ' + str(self.profundidad) + '\n\n'
        for registro in self.símbolos:
            resultado += str(registro) + '\n'

        return resultado

class Visitante:
    tabla_símbolos: TablaSímbolos

    REGLAS_VISITAR: dict

    def __init__(self, tabla_símbolos):
        self.tabla_símbolos = tabla_símbolos

        self.REGLAS_VISITAR = {
            TipoNodo.PROGRAMA: self.__visitar_programa,
            TipoNodo.PARAMETROS: self.__visitar_parametros,
            TipoNodo.CONDICIONAL: self.__visitar_condicional,
            TipoNodo.INVOCACION: self.__visitar_invocacion,
            TipoNodo.REPETICION: self.__visitar_repeticion,
            TipoNodo.OPERAR: self.__visitar_operación,
            TipoNodo.ASIGNACION: self.__visitar_asignacion,
            TipoNodo.COMPARACION: self.__visitar_comparacion,
            TipoNodo.EXPRCONDICIONAL: self.__visitar_ExpCondicional,
            TipoNodo.VARIABLE_OPERADOR: self._visitar_operar_variable,
            TipoNodo.OPERADOR: self.__visitar_operador,
            TipoNodo.COMPARADOR_LOGICO: self.__visitar_comparador_logico,
            TipoNodo.INSTRUCCIONES: self.__visitar_bloque_instrucciones,
            TipoNodo.INSTRUCCIÓN: self.__visitar_instruccion,
            TipoNodo.TIPO_VARIABLE: self.__visitar_tipo_variable,
            TipoNodo.TIPO_VALOR: self.__visitar_tipo_valor,
            TipoNodo.NULO: self.__visitar_nulo,
            TipoNodo.RETORNO: self.__visitar_retorno,
            TipoNodo.ROMPE: self.__visitar_rompe,
            TipoNodo.COMPARADOR_MATEMATICO: self.__visitar_comparador_matematico,
            TipoNodo.TEXTO: self.__visitar_texto,
            TipoNodo.IDENTIFICADOR: self.__visitar_identificador,
            TipoNodo.ENTERO: self.__visitar_entero,
            TipoNodo.FLOTANTE: self.__visitar_flotante,
            TipoNodo.FUNCIÓN: self.__visitar_funcion
        }

    def generar_error_identificación(self, nodo_actual):
        """
        Por ahora imprime un error con la linea, y los números de línea y columna

        Por ahora la estrategia escogida fue que terminara inmediatamente el programa
        """

        print()
        print()
        print()
        print(
            "Se ha encontrado un error de identificación en la línea "
            + str(nodo_actual.atributos['numeroLinea'])
            + ":\n\n" + nodo_actual.atributos['textoLinea'] + "\n\n"
            + "Indetificador no encontrado, porfavor corregir el error respectivo"
        )

        print(self.tabla_símbolos)

        quit()

    def generar_error_inferencia(self, nodo_actual):
        """
        Por ahora imprime un error con la linea, y los números de línea y columna

        Por ahora la estrategia escogida fue que terminara inmediatamente el programa
        """

        print()
        print()
        print()
        print(
            "Se ha encontrado un error de inferencia en la línea "
            + str(nodo_actual.atributos['numeroLinea'])
            + ":\n\n" + nodo_actual.atributos['textoLinea'] + "\n\n"
            + "Porfavor corregir el error respectivo"
        )

        quit()

    def visitar(self, nodo: TipoNodo):

        if (nodo.tipo in self.REGLAS_VISITAR):
            self.REGLAS_VISITAR[nodo.tipo](nodo)

    def __visitar_programa(self, nodo_actual):
        """
        Programa ::= (Función | Condicional | Asignación | Ciclo | Invocar)+
        """
        for nodo_hijo in nodo_actual.nodos:
            nodo_hijo.visitar(self)

    """
    -------------------------------------------------
    - Bloque de funciones para analizar una función -
    -------------------------------------------------
    """

    def __visitar_funcion(self, nodo_actual):
        """
        Func Identificador {Parametro} -> (Instrucciones)+ <-
        """

        self.tabla_símbolos.nuevo_registro(nodo_actual)
        self.tabla_símbolos.abrir_bloque()

        tipo_valor = ""
        for nodo in nodo_actual.nodos:
            nodo.visitar(self)

            if nodo.tipo == TipoNodo.RETORNO:
                tipo_valor = nodo.nodos[0].atributos['tipo']

        self.tabla_símbolos.cerrar_bloque()

        #for nodo in nodo_actual.nodos:
         #   if nodo.tipo == TipoNodo.RETORNO:
          #      nodo_actual.atributos['tipo'] = nodo.nodos[0].atributos['tipo']
           #     break

        nodo_actual.atributos['tipo'] = tipo_valor

    def __visitar_invocacion(self, nodo_actual):
        """
        Invocar ::= Inv Identificador {Parámetro}
        """
        registro = self.tabla_símbolos.verificar_existencia(nodo_actual.nodos[0].contenido)

        if registro == -1:
            self.generar_error_identificación(nodo_actual)

        if registro['referencia'].tipo != TipoNodo.FUNCIÓN:
            self.generar_error_inferencia(nodo_actual)

        for nodo in nodo_actual.nodos:
            nodo.visitar(self)

        nodo_actual.atributos['tipo'] = registro['referencia'].atributos['tipo']

    def __visitar_parametros(self, nodo_actual):
        """
        Parametros ::= TipoValor Identificador (, TipoValor Identificador)+
        """

        tipo_valor = " "
        for nodo in nodo_actual.nodos:

            if nodo.tipo == TipoNodo.IDENTIFICADOR:

                self.tabla_símbolos.nuevo_registro(nodo)

                if tipo_valor == 'Entero' or tipo_valor == 'Flotante':
                    nodo.atributos['tipo'] = TipoDatos.NÚMERO

                if tipo_valor == 'Texto':
                    nodo.atributos['tipo'] = TipoDatos.TEXTO

                continue

            tipo_valor = nodo.contenido

            nodo.visitar(self)

    """
    -----------------------------------------------------
    - Bloque de funciones para analizar una condicional -
    -----------------------------------------------------
    """

    def __visitar_condicional(self, nodo_actual):
        """
        Condicional ::= Si {ExpCondicional} ->  Instrucciones + <-
        """

        self.tabla_símbolos.abrir_bloque()

        for nodo in nodo_actual.nodos:
            nodo.visitar(self)

        self.tabla_símbolos.cerrar_bloque()

        nodo_actual.atributos['tipo'] = nodo_actual.nodos[1].atributos['tipo']

    def __visitar_ExpCondicional(self, nodo_actual):
        """
        ExpCondicional ::= (Comparación (( ^ | ~^) Comparación)*))
        """
        for nodo in nodo_actual.nodos:
            nodo.visitar(self)

        nodo_actual.atributos['tipo'] = TipoDatos.VALOR_VERDAD

    def __visitar_comparador_logico(self, nodo_actual):
        nodo_actual.atributos['tipo'] = TipoDatos.NÚMERO

    """
    -----------------------------------------------------
    - Bloque de funciones para analizar una repeticion --
    -----------------------------------------------------
    """

    def __visitar_repeticion(self, nodo_actual):
        """
        Ciclo ::= Rep {Comparación}  -> Instrucciones + <-
        """
        self.tabla_símbolos.abrir_bloque()

        for nodo in nodo_actual.nodos:
            nodo.visitar(self)

        # nodo_actual.nodos[0].visitar(self)

        self.tabla_símbolos.cerrar_bloque()

        # Anoto el tipo de retorno (TIPO)
        nodo_actual.atributos['tipo'] = nodo_actual.nodos[1].atributos['tipo']

    """
    -----------------------------------------------------
    - Bloque de funciones para analizar una comparacion -
    -----------------------------------------------------
    """

    def __visitar_comparacion(self, nodo_actual):
        """
        Comparación ::= ((Valor | Operación) Comparador (Valor | Operación)
        """
        for nodo in nodo_actual.nodos:
            if nodo.tipo == TipoNodo.IDENTIFICADOR:
                registro = self.tabla_símbolos.verificar_existencia(nodo.contenido)
                if registro == -1:
                    self.generar_error_identificación(nodo_actual)

            nodo.visitar(self)

        valor_izq = nodo_actual.nodos[0]
        comparador = nodo_actual.nodos[1]
        valor_der = nodo_actual.nodos[2]

        if valor_izq.atributos['tipo'] == valor_der.atributos['tipo']:
            comparador.atributos['tipo'] = valor_izq.atributos['tipo']

            # Una comparación siempre tiene un valor de verdad
            nodo_actual.atributos['tipo'] = TipoDatos.VALOR_VERDAD

        elif valor_izq.atributos['tipo'] == TipoDatos.CUALQUIERA or \
                valor_der.atributos['tipo'] == TipoDatos.CUALQUIERA:

            comparador.atributos['tipo'] = TipoDatos.CUALQUIERA

            # Todavía no estoy seguro.
            nodo_actual.atributos['tipo'] = TipoDatos.CUALQUIERA

        else:

            self.generar_error_inferencia(nodo_actual)

    def __visitar_comparador_matematico(self, nodo_actual):
        """
        Comparador ::= (<|>|<=|>=|~==|==)
        """
        if nodo_actual.contenido not in ['~==^', '==']:
            nodo_actual.atributos['tipo'] = TipoDatos.NÚMERO

        else:
            nodo_actual.atributos['tipo'] = TipoDatos.CUALQUIERA

    """
    ---------------------------------------------------------------
    - Bloque de funciones para analizar un bloque de instrucciones -
    ----------------------------------------------------------------
    """

    def __visitar_bloque_instrucciones(self, nodo_actual):
        """
        BloqueInstrucciones ::= -> Instrucciones+ | Rompe <-
        Instrucciones ::= (Ciclo | Condicional | Retorna | Asignación | OperarVariable | Invocar)
        """
        # Visita todas las instrucciones que contiene
        for nodo in nodo_actual.nodos:
            nodo.visitar(self)

        nodo_actual.atributos['tipo'] = TipoDatos.NINGUNO

        for nodo in nodo_actual.nodos:
            if nodo.atributos['tipo'] != TipoDatos.NINGUNO:
                nodo_actual.atributos['tipo'] = nodo.atributos['tipo']

    def __visitar_instruccion(self, nodo_actual):
        """
        Instrucciones ::= (Ciclo | Condicional | Retorna | Asignación | OperarVariable | Invocar)
        """
        for nodo in nodo_actual.nodos:
            nodo.visitar(self)
            nodo_actual.atributos['tipo'] = nodo.atributos['tipo']

    """
    -----------------------------------------------------
    - Bloque de funciones para analizar una instruccion -
    -----------------------------------------------------
    """

    def _visitar_operar_variable(self, nodo_actual):
        """
        OperarVariable::= Identificador ( <=> ) (Operación | Valor);

        Valor ::= (Identificador | Literal)
        Literal ::= (Texto | Entero | Flotante | Lectura | Nulo)
        """

        #Si se va a operar una variable es que ya existe
        registro = self.tabla_símbolos.verificar_existencia(nodo_actual.nodos[0].contenido)
        if registro == -1:
            self.generar_error_identificación(nodo_actual)

        #self.tabla_símbolos.nuevo_registro(nodo_actual.nodos[0])

        for nodo in nodo_actual.nodos:

            if nodo.tipo == TipoNodo.IDENTIFICADOR:
                registro = self.tabla_símbolos.verificar_existencia(nodo.contenido)

                nodo.atributos['tipo'] = registro['referencia'].atributos['tipo']
                continue

            nodo.visitar(self)

        """
        for nodo in nodo_actual.nodos:
            if nodo.tipo == TipoNodo.OPERAR:
                for nodo_operar in nodo.nodos:
                    if nodo_operar.tipo != nodo_actual.nodos[0].tipo and \
                        nodo_operar.tipo != TipoNodo.OPERADOR:
                        raise Exception('Esa vara no existe', str(nodo_actual))
        """

        # Si es una función verifico el tipo que retorna para incluirlo en
        # la asignación y si es un literal puedo anotar el tipo (TIPO)

        nodo_actual.atributos['tipo'] = nodo_actual.nodos[1].atributos['tipo']

        nodo_actual.nodos[0].atributos['tipo'] = nodo_actual.nodos[1].atributos['tipo']

        tipo_dato = nodo_actual.nodos[0].atributos['tipo']
        for nodo in nodo_actual.nodos:
            if nodo.tipo != TipoNodo.TIPO_VARIABLE:
                if nodo.atributos['tipo'] != tipo_dato:
                    self.generar_error_inferencia(nodo_actual)

    def __visitar_asignacion(self, nodo_actual):
        """
        Asignación ::= TipoVariable TipoValor Identificador <=> (Operación | Valor | Invocación);

        Valor ::= (Identificador | Literal)
        Literal ::= (Texto | Entero | Flotante | Lectura | Nulo)
        """
        self.tabla_símbolos.nuevo_registro(nodo_actual.nodos[2])

        for nodo in nodo_actual.nodos:
            if nodo.tipo == TipoNodo.IDENTIFICADOR and nodo != nodo_actual.nodos[2]:
                registro = self.tabla_símbolos.verificar_existencia(nodo.contenido)

                if registro == -1:
                    self.generar_error_identificación(nodo_actual)

                nodo.atributos['tipo'] = registro['referencia'].atributos['tipo']
                continue

            nodo.visitar(self)

        nodo_actual.atributos['tipo'] = nodo_actual.nodos[1].atributos['tipo']

        nodo_actual.nodos[2].atributos['tipo'] = nodo_actual.nodos[1].atributos['tipo']

        tipo_dato = nodo_actual.nodos[1].atributos['tipo']
        for nodo in nodo_actual.nodos:
            if nodo.tipo != TipoNodo.TIPO_VARIABLE:
                if nodo.tipo == TipoNodo.INVOCACION:
                    continue
                if nodo.atributos['tipo'] != tipo_dato:
                    self.generar_error_inferencia(nodo_actual)

    def __visitar_operación(self, nodo_actual):
        """
        Operación ::= Operar Valor  (Operadores Valor)+

        Valor ::= (Identificador | Literal)
        Literal ::= (Texto | Entero | Flotante | Lectura | Nulo)

        Ojo esto soportaría un texto
        """
        for nodo in nodo_actual.nodos:

            # Verifico que exista si es un identificador (IDENTIFICACIÓN)
            if nodo.tipo == TipoNodo.IDENTIFICADOR:
                registro = self.tabla_símbolos.verificar_existencia(nodo.contenido)

                if registro == -1:
                    self.generar_error_identificación(nodo_actual)

                nodo.atributos['tipo'] = registro['referencia'].atributos['tipo']
                continue

            nodo.visitar(self)

        # Anoto el tipo de datos 'NÚMERO' (TIPO)
        nodo_actual.atributos['tipo'] = TipoDatos.NÚMERO

        tipo_dato = TipoDatos.NÚMERO
        for nodo in nodo_actual.nodos:
            if nodo.tipo != TipoNodo.TIPO_VARIABLE:
                if nodo.tipo == TipoNodo.INVOCACION:
                    continue

                if nodo.atributos['tipo'] != tipo_dato:
                    self.generar_error_inferencia(nodo_actual)

    def __visitar_retorno(self, nodo_actual):
        """
        Retorna ::= messirve Valor;

        Valor ::= (Identificador | Literal)
        Literal ::= (Texto | Entero | Flotante | Lectura | Nulo)
        """

        for nodo in nodo_actual.nodos:
            nodo.visitar(self)

        if nodo_actual.nodos == []:
            # Si no retorna un valor no retorna un tipo específico
            nodo_actual.atributos['tipo'] = TipoDatos.NINGUNO

        else:

            for nodo in nodo_actual.nodos:

                nodo.visitar(self)

                if nodo.tipo == TipoNodo.IDENTIFICADOR:
                    # Verifico si valor es un identificador que exista (IDENTIFICACIÓN)
                    registro = self.tabla_símbolos.verificar_existencia(nodo.contenido)
                    if registro == -1:
                        self.generar_error_identificación(nodo_actual)

                    # le doy al sarpe el tipo de retorno del identificador encontrado
                    nodo_actual.atributos['tipo'] = registro['referencia'].atributos['tipo']

                else:
                    # Verifico si es un Literal de que tipo es (TIPO)
                    nodo_actual.atributos['tipo'] = nodo.atributos['tipo']

    def __visitar_rompe(self, nodo_actual):
        """
        Rompe ::= siu;

        """
        nodo_actual.atributos['tipo'] = TipoDatos.NINGUNO

    """
    ---------------------------------------------------------------------
    - Bloque de funciones para verificar componentes léxicos o un texto -
    ---------------------------------------------------------------------
    """

    def __visitar_operador(self, nodo_actual):
        """
        Operador ::= ( + | - | ** | * | // | / | % )
        """
        # Operador para trabajar con números (TIPO)
        nodo_actual.atributos['tipo'] = TipoDatos.NÚMERO

    def __visitar_texto(self, nodo_actual):
        """
        Texto ::= ~/\w(\s\w)*)?~
        """
        nodo_actual.atributos['tipo'] = TipoDatos.TEXTO

    def __visitar_entero(self, nodo_actual):
        """
        Entero ::= (-)?\d+
        """
        nodo_actual.atributos['tipo'] = TipoDatos.NÚMERO

    def __visitar_flotante(self, nodo_actual):
        """
        Flotante ::= (-)?\d+.(-)?\d+
        """
        nodo_actual.atributos['tipo'] = TipoDatos.NÚMERO

    def __visitar_identificador(self, nodo_actual):
        """
        Identificador ::= [a-z][a-zA-Z0-9]+
        """
        nodo_actual.atributos['tipo'] = TipoDatos.CUALQUIERA

    def __visitar_tipo_variable(self, nodo_actual):
        """
        TipoVariable ::= (GLOB | CONS | LOC)
        """
        nodo_actual.atributos['tipo'] = TipoDatos.NINGUNO

    def __visitar_tipo_valor(self, nodo_actual):
        """
        TipoValor::= (Texto |  Entero | Flotante)
        """

        if nodo_actual.contenido == 'Entero' or nodo_actual.contenido == 'Flotante':
            nodo_actual.atributos['tipo'] = TipoDatos.NÚMERO

        if nodo_actual.contenido == 'Texto':
            nodo_actual.atributos['tipo'] = TipoDatos.TEXTO

    def __visitar_nulo(self, nodo_actual):
        """
        Nulo ::= Nulo
        """
        nodo_actual.atributos['tipo'] = TipoDatos.NINGUNO

class Verificador:
    asa: ÁrbolSintáxisAbstracta
    visitador: Visitante
    tabla_símbolos: TablaSímbolos

    def __init__(self, nuevo_asa: ÁrbolSintáxisAbstracta):

        self.asa = nuevo_asa

        self.tabla_símbolos = TablaSímbolos()
        self.__cargar_ambiente_estándar()

        self.visitador = Visitante(self.tabla_símbolos)

    def __cargar_ambiente_estándar(self):

        funciones_estandar = [('pinte', TipoDatos.NINGUNO), ('reemplazar', TipoDatos.NINGUNO),
        ('aleatorio', TipoDatos.NÚMERO)]

        for nombre, tipo in  funciones_estandar:
            nodo = NodoÁrbol(TipoNodo.FUNCIÓN, contenido=nombre, atributos= {'tipo': tipo})
            self.tabla_símbolos.nuevo_registro(nodo)

    def imprimir_asa(self):
        """
        Imprime el árbol de sintáxis abstracta
        """

        if self.asa.raiz is None:
            print([])
        else:
            print("\n \n-----------------------------------------------------")
            print("Árbol Decorado")
            print("-----------------------------------------------------")
            self.asa.imprimir_preorden()

    def imprimir_tabla_simbolos(self):
        print(self.tabla_símbolos)

    def verificar(self):
        self.visitador.visitar(self.asa.raiz)


from django.http import Http404, HttpResponse
from rest_framework import status
from rest_framework.decorators import action
from rest_framework.response import Response
from rest_framework.viewsets import ModelViewSet
from rest_framework.permissions import IsAuthenticated

from alert.models import Projects, Contributors, Issues, Comments
from alert.serializers import ProjectsListSerializer, ProjectsDetailSerializer,\
    ContributorsSerializer, IssuesSerializer, CommentsSerializer
from alert.permissions import ProjectIsUserAuthorOrContributorPermissions,\
    IssuesPermissions, CommentsPermissions

# 3 Récupérer la liste de tous les projets (projects) rattachés à l'utilisateur (user) connecté
# 5 Récupérer les détails d'un projet (project) via son id

class ProjectsViewset(ModelViewSet):

    permission_classes = [IsAuthenticated, ProjectIsUserAuthorOrContributorPermissions]

    serializer_class = ProjectsDetailSerializer

    def get_queryset(self):
        # si l'url est /api/projects/, alors self.kwargs = {}
        # si l'url est /api/projects/2/, alors self.kwargs = {'pk': '2'}
        # Si je veux le détail d'un projet, je retourne toutes les valeurs à la permission
        # (l'affichage du détail étant géré par modelVieSet)
        if self.kwargs:
            return Projects.objects.all()
        # sinon, je n'adresse que ce qui ne concerne que l'utilisateur
        return Projects.objects.filter(author_user=self.request.user)

    # Pour pouvoir faire un update partiel
    # https://tech.serhatteker.com/post/2020-09/enable-partial-update-drf/
    def update(self, request, *args, **kwargs):
        kwargs['partial'] = True
        return super().update(request, *args, **kwargs)

    # Surcharge du class DestroyModelMixin pour modifier le message retourné
    # à l'origine "return Response(status=status.HTTP_204_NO_CONTENT)"
    def destroy(self, request, *args, **kwargs):
        instance = self.get_object()
        self.perform_destroy(instance)
        return Response({"message": "Le projet et ses problèmes associés ont bien été supprimés."},
                        status=200)

    # --------------------------C O N T R I B U T O R S (USERS)----------------------

    # ------------------------------------------------------------------------------ #
    # Via @action, création de l'url : /projects/<id>/users (ici, users est
    # automatiquement le nom de la fonction, car aucun url_path de précisé)
    # ------------------------------------------------------------------------------ #
    @action(detail=True, methods=['get', 'post'])
    def users(self, request, pk=None):
        """Création d'un path /projects/<id>/users pour afficher les contributeurs sur un projet,
        et enregistrer de nouveaux contributors"""
        if request.method == "GET":
            queryset = Contributors.objects.filter(project=pk)
            if len(queryset) == 0:
                raise Http404(f"Aucun projet {pk} n'a de contributeur.")

            serializer = ContributorsSerializer(queryset, many=True)
            return Response(serializer.data, status=200)

        # Ajout d'un contributeur :
        if request.method == "POST":
            # Vérification que le projet existe
            try:
                project = Projects.objects.get(pk=pk)
            except Projects.DoesNotExist:
                return HttpResponse({f"Le projet {pk} n'existe pas."}, status=404)

            # Si vérification passée :
            # Informations partielles adressées au sérializer (pas le projet puisque abs du body)
            serializer = ContributorsSerializer(data=request.data,
                                                partial=True)
            if serializer.is_valid():
                # Si Informations partielles validées :
                # Création du contributeur par le serializer en lui adressant le projet récupéré
                # dans le try précédent, grace au pk de l'url
                contributor = serializer.create(project=project)
                return Response(contributor, status=200)

            return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    # ------------------------------------------------------------------------------ #
    # Via @action, création de l'url : /project/{id}/users/{id}/ ici, l'url n'est pas
    # le nom de la fonction mais remplacé par url_path. Comme pk, user_id devient
    # récupérable
    # ------------------------------------------------------------------------------ #
    @action(detail=True, methods=['delete'], url_path='users/(?P<user_id>\d+)')
    def remove_contributor_from_project(self, request, user_id, pk=None):
        # Attention : même si le paramètre request n'est pas utilisé,
        # il faut le conserver à défaut d'obtenir un mesage d'erreur :
        # TypeError: remove_contributor_from_project() got multiple values for argument 'user_id'

        # Vérification que le projet existe
        try:
            Projects.objects.get(pk=pk)
        except Projects.DoesNotExist:
            return HttpResponse({f"Le projet {pk} n'existe pas."}, status=404)

        # récupération des contributions liées au projet et à l'user (auteur et contributeur)
        contribution_concerned = Contributors.objects.filter(project=pk).filter(user=user_id)

        # Si ce contibuteur n'est pas associé à ce projet, alors len = 0 :
        if len(contribution_concerned) == 0:
            return HttpResponse({f"Aucun contributeur {user_id} associé au projet {pk}."},
                                status=404
                                )
        else:
            for contribution in contribution_concerned:
                contribution.delete()

        return Response({"message": "L'utilisateur a bien été supprimé de ce projet."}, status=200)

    # -------------------------------I S S U E S-------------------------------------

    # GET: /project/{id}/issues/
    @action(detail=True, methods=['get', 'post'], permission_classes=[IssuesPermissions])
    def issues(self, request, pk=None):
        """Création d'un path /projects/<id>/issues pour afficher les problèmes d'un projet,
        et en enregistrer de nouveaux """
        # récupération de <id> du projet dans /projects/<id>/issues via pk
        if request.method == "GET":
            # Vérification qu'il y a un problème d'enregisté sur le projet
            queryset = Issues.objects.filter(project=pk)
            if not queryset:
                return HttpResponse({"Aucun problème pour ce projet, ou projet inexistant."},
                                    status=404)

            self.check_object_permissions(request, Projects.objects.get(pk=pk))
            serializer = IssuesSerializer(queryset, many=True)
            return Response(serializer.data, status=200)
            # for element in queryset:
            #     if element.author_user != request.user:
            #         return Response({f"Vous n'avez pas accès à cet objet"}, status=404)
            # self.check_object_permissions(request, Issues.objects.get(pk=queryset.first().pk))
            # serializer = IssuesSerializer(queryset, many=True)
            # return Response(serializer.data, status=200)

        # Enregistrer un problème pour un projet
        if request.method == "POST":
            # Vérification que le projet existe
            try:
                project = Projects.objects.get(pk=pk)
            except Projects.DoesNotExist:
                return HttpResponse({f"Le projet {pk} n'existe pas."}, status=404)

            # Si vérification passée :
            # Informations partielles adressées au sérializer (pas le projet puisque abs du body et
            # présent dans l'url)
            serializer = IssuesSerializer(data=request.data, partial=True)
            if serializer.is_valid():
                # Si Informations partielles validées :
                # Vérification des permissions
                self.check_object_permissions(request, Projects.objects.get(pk=pk))
                # Enregistrement du problème par le serializer en lui adressant le projet récupéré
                # dans le try précédent, grace au pk de l'url et l'auteur via request.user
                issue = serializer.create(project=project, author_user=request.user)
                return Response(issue, status=200)
            return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

        # ------------------------------------------------------------------------------ #
        # Via @action, création de l'url : /project/{id}/issues/{id}/ ici, l'url n'est pas
        # le nom de la fonction mais remplacé par url_path. Comme pk, issue_id devient
        # récupérable
        # ------------------------------------------------------------------------------ #
    # @action(detail=True, methods=['put', 'delete'], url_path='issues/(?P<issue_id>\d+)',
    #         permission_classes=[AuthorIsRequestUserPermissions])
    @action(detail=True, methods=['put', 'delete'], url_path='issues/(?P<issue_id>\d+)',
            permission_classes=[IssuesPermissions])
    def update_or_delete_issue(self, request, issue_id, pk=None):
        """Création d'un path /projects/<id>/issues/<id> pour mettre à jour un problème,
        ou le supprimer"""
        # Vérification que le projet existe
        try:
            Projects.objects.get(pk=pk)
        except Projects.DoesNotExist:
            return HttpResponse({f"Le projet {pk} n'existe pas."}, status=404)

        # récupération des problèmes liés au projet
        issue_concerned = Issues.objects.filter(project=pk).filter(pk=issue_id)
        # Si aucun problème n'est associé à ce projet, alors len = 0 :
        if len(issue_concerned) == 0:
            return HttpResponse({f"Aucun problème {issue_id} associé au projet {pk}."},
                                status=404
                                )

        if request.method == "PUT":
            serializer = IssuesSerializer(partial=True)
            print("ICI PUT COTE VIEW")
            # Pas de création d'un update dans le serializers.py car utilisation de ipdate()
            # Vérification des permissions
            self.check_object_permissions(request, Projects.objects.get(pk=pk))
            issue_modified = serializer.update(instance=issue_concerned.first(),
                                               validated_data=request.data)

            # reserialization de issue_modified pour passage en Response
            issue_serialized = IssuesSerializer(instance=issue_modified).data

            return Response(issue_serialized, status=200)

        if request.method == "DELETE":
            # Vérification des permissions
            self.check_object_permissions(request, Projects.objects.get(pk=pk))
            # si permission, suppression du problème :
            issue_concerned.delete()

            return Response({"message": "Le problème a bien été supprimé."}, status=200)

        # ----------------------------------C O M M E N T S-----------------------------

        # ------------------------------------------------------------------------------ #
        # Via @action, création de l'url : /project/{id}/issues/{id}/comments/
        # ici, l'url n'est pas le nom de la fonction mais remplacé par url_path.
        # Comme pk, issue_id devient récupérable
        # ------------------------------------------------------------------------------ #
    @action(detail=True, methods=['post', 'get'],
            url_path='issues/(?P<issue_id>\d+)/comments', permission_classes=[CommentsPermissions])
    def comments(self, request, issue_id, pk=None):
        """Création d'un path /projects/<id>/issues/<id>/comments pour créer, récupérer
         un commentaire"""
        # Vérification que le projet existe
        try:
            Projects.objects.get(pk=pk)
        except Projects.DoesNotExist:
            return HttpResponse({f"Le projet {pk} n'existe pas."}, status=404)

        # Vérification qu'il y a bien un problème 'issue_id' lié au projet
        issue_concerned = Issues.objects.filter(project=pk).filter(pk=issue_id)
        # Si aucun problème n'est associé à ce projet, alors len = 0 :
        if len(issue_concerned) == 0:
            return HttpResponse({f"Aucun problème {issue_id} associé au projet {pk}."},
                                status=404
                                )
        # Enregistrer un commentaire pour un problème
        if request.method == "POST":
            # Informations partielles adressées au sérializer (pas l'ID de l'issue puisque abs
            # du body et présent dans l'url). Ci-dessous, request.data est vide, donc utilisation
            # de request.query_params (phénomène inverse, le lendemain, retour au request.data)
            # serializer = CommentsSerializer(data=request.query_params, partial=True)

            serializer = CommentsSerializer(data=request.data, partial=True)
            if serializer.is_valid():
                # Si Informations partielles validées :
                # Vérification des permissions
                self.check_object_permissions(request, Projects.objects.get(pk=pk))
                # Enregistrement du commentaire par le serializer en lui adressant l'issue concernée
                # dans le try précédent, grace au issue_id de l'url
                # !!! si, issue_concerned récupérée avec filter et non get, il faut ajouter .first()
                # car il s'agit alors d'un queryset et non plus d'une instance avec get
                # issue_concerned = Issues.objects.get(pk=issue_id)
                comment = serializer.create(issue_concerned=issue_concerned.first(),
                                            author_user=request.user)
                return Response(comment, status=200)
            return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

        # Récupérer les commentaires d'un problème
        if request.method == 'GET':
            # Vérification des permissions
            self.check_object_permissions(request, Projects.objects.get(pk=pk))
            # récupération des commentaires liés à une issue
            all_comments_for_issue = Comments.objects.filter(issue=issue_id)
            datas = []
            for comment in all_comments_for_issue:
                serializer = CommentsSerializer(comment)
                datas.append(serializer.data)

            return Response(datas, status=200)

        # ------------------------------------------------------------------------------ #
        # Via @action, création de l'url : /project/{id}/issues/{id}/comments/{id}
        # ici, l'url n'est pas le nom de la fonction mais remplacé par url_path.
        # Comme pk, issue_id et comment_id deviennent récupérables
        # ------------------------------------------------------------------------------ #
    @action(detail=True, methods=['get', 'put', 'delete'],
            url_path='issues/(?P<issue_id>\d+)/comments/(?P<comment_id>\d+)',
            permission_classes=[CommentsPermissions])
    def update_or_delete_or_get_comment(self, request, issue_id, comment_id, pk=None):
        """Création d'un path /projects/<id>/issues/<id>/comments pour créer, récupérer,
        modifier, supprimer un commentaire"""
        # Vérification qu'il y a bien un projet pk
        try:
            Projects.objects.get(pk=pk)
        except Projects.DoesNotExist:
            return HttpResponse({f"Le projet {pk} n'existe pas."}, status=404)

        # Vérification qu'il y a bien un problème 'issue_id' lié au projet
        issue_concerned = Issues.objects.filter(project=pk).filter(pk=issue_id)
        # Si aucun problème n'est associé à ce projet, alors len = 0 :
        if len(issue_concerned) == 0:
            return HttpResponse({f"Aucun problème {issue_id} associé au projet {pk}."},
                                status=404
                                )
        # Enfin, vérification que le commentaire existe et est bien lié à issue_id
        comment_concerned = Comments.objects.filter(pk=comment_id).filter(issue=issue_id)

        # Si aucun problème n'est associé à ce projet, alors len = 0 :
        if len(comment_concerned) == 0:
            return HttpResponse({f"Aucun commentaire {comment_id} associé au problème {issue_id}."},
                                status=404
                                )

        # Modifier un commentaire
        if request.method == "PUT":
            # Vérification des permissions
            self.check_object_permissions(request, Projects.objects.get(pk=pk))
            serializer = CommentsSerializer(partial=True)

            # Pas de création d'un update dans le serializers.py car utilisation de update()
            comment_modified = serializer.update(instance=comment_concerned.first(),
                                                 validated_data=request.data)

            # reserialization de comment_modified pour passage en Response
            comment_serialized = CommentsSerializer(instance=comment_modified).data

            return Response(comment_serialized, status=200)

        if request.method == "DELETE":
            # Vérification des permissions
            self.check_object_permissions(request, Projects.objects.get(pk=pk))
            comment_concerned.delete()

            return Response({"message": "Le commentaire a bien été supprimé."}, status=200)

        # Récupérer un commentaire
        if request.method == "GET":
            # Vérification des permissions
            self.check_object_permissions(request, Projects.objects.get(pk=pk))
            # reserialization de comment_modified pour passage en Response
            comment_find = CommentsSerializer(instance=comment_concerned.first()).data

            return Response(comment_find, status=200)


import json
from torch.utils.data import Dataset
from torch.utils.data import DataLoader

import rdkit.Chem as Chem
import numpy as np

import pdb

class PropDataset(Dataset):
    def __init__(self, data_dir, data_type, split=0, parse_func=None, n_labels=1):
        self.n_labels = n_labels
        self.data = []

        # Read the split indices for the relevant split of the data
        indices_path = '%s/split_%d.json' % (data_dir, split)
        with open(indices_path, 'r+') as indices_file:
            indices_dict = json.load(indices_file)
            data_indices = indices_dict[data_type]

        if len(data_indices) == 0:
            print('No data indices loaded at: %s' % indices_path)

        with open('%s/raw.csv' % data_dir, 'r+') as data_file:
            for line_idx, line in enumerate(data_file.readlines()):
                if line_idx not in data_indices:
                    continue
                else:
                    if parse_func is None:
                        if n_labels == 1:
                            smiles, label = line.strip().split(',')
                            label = float(label)
                            self.data.append((smiles, label))
                        else:
                            splits = line.strip().split(',')
                            smiles = splits[0]
                            labels = splits[1:]
                            self.data.append((smiles, labels))
                    else:
                        self.data.append(parse_func(line.strip()))

        self.smiles, self.labels = zip(*self.data)

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

    def parse_multi_labels(self, label_list):
        labels, mask = [], []
        for label in label_list:
            if label == '':
                labels.append(0)
                mask.append(0)
            else:
                labels.append(float(label))
                mask.append(1)
        return labels, mask

    def __getitem__(self, idx):
        if self.n_labels == 1:
            return self.data[idx]
        else:
            smiles, labels = self.data[idx]
            parsed_labels, mask = self.parse_multi_labels(labels)
            return (smiles, parsed_labels, mask)

def get_loader(data_dir, data_type, batch_size, split=0, parse_func=None,
               shuffle=False, num_workers=1, n_labels=1):
    prop_dataset = PropDataset(
        data_dir, data_type, split=split, parse_func=parse_func, n_labels=n_labels)

    def combine_data(data):
        if n_labels == 1:
            batch_smiles, batch_labels = zip(*data)
            return batch_smiles, batch_labels
        else:
            batch_smiles, batch_labels, mask = zip(*data)
            return batch_smiles, batch_labels, mask

    data_loader = DataLoader(
        prop_dataset,
        batch_size=batch_size,
        shuffle=shuffle,
        collate_fn=combine_data,
        num_workers=num_workers)
    return data_loader


from . import views
from django.urls import path

urlpatterns = [
    path('image',views.add_image,name='image'),
    path('register',views.register,name='register'),
    path('login',views.login,name='login'),
    path('logout',views.logout,name='logout'),
    path('get/<int:image_id>',views.show,name='show'),
    path('test',views.test,name='test'),
    path('getall',views.get_all,name='get_all'),
    path('delete/<int:image_id>',views.delete,name='delete'),
    path('delete',views.delete_all,name='delete_all'),
]


from datetime import datetime
import os
import re

# extensions
extensions = [
    "breathe",
    "exhale",
]

# obtain version
cmake = os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "app", "CMakeLists.txt")
with open(cmake) as f:
    version = re.search(r"project\(.*VERSION\s+([0-9\.]+).*\)", f.read()).group(1)

# general
project = "app"
author = "Teslabs Engineering S.L."
year = datetime.now().year
copyright = "{:d}, Teslabs Engineering S.L.".format(year)
source_suffix = [".rst"]
master_doc = "index"

# html
html_static_path = ["_static"]
html_theme = "sphinx_rtd_theme"
html_logo = "_static/images/logo.png"
html_theme_options = {
    "logo_only": False,
    "display_version": True
}

# others
pygments_style = "sphinx"
numfig = True
mermaid_version = "8.5.2"

# breather & exhale
breathe_projects = {
    "app": "./doxyoutput/xml"
}

breathe_default_project = "app"

exhale_args = {
    "containmentFolder": "./api",
    "rootFileName": "index.rst",
    "rootFileTitle": "Application API",
    "doxygenStripFromPath": "..",
    "createTreeView": True,
    "exhaleExecutesDoxygen": True,
    "exhaleDoxygenStdin": "\n".join([
        "INPUT = ../app/include",
        "FILE_PATTERNS = *.h",
        "JAVADOC_AUTOBRIEF = YES",
        "OPTIMIZE_OUTPUT_FOR_C = YES",
        "EXCLUDE_SYMBOLS = z_*",
        "TAB_SIZE = 8",
    ])
}

cpp_id_attributes = [
    "__syscall"
]

c_id_attributes = cpp_id_attributes

def setup(app):
    app.add_stylesheet("css/custom.css")