import os
import pygame

def get_actor_display_name(actor, truncate=250):
    name = ' '.join(actor.type_id.replace('_', '.').title().split('.')[1:])
    return (name[:truncate - 1] + u'\u2026') if len(name) > truncate else name

# ==============================================================================
# -- HUD -----------------------------------------------------------------------
# ==============================================================================

class HUD(object):
    def __init__(self, width, height, gnss, imu):
        self.imu = imu
        self.gnss = gnss
        self.dim = (width, height)
        font = pygame.font.Font(pygame.font.get_default_font(), 20)
        font_name = 'courier' if os.name == 'nt' else 'mono'
        fonts = [x for x in pygame.font.get_fonts() if font_name in x]
        default_font = 'ubuntumono'
        mono = default_font if default_font in fonts else fonts[0]
        mono = pygame.font.match_font(mono)
        self._font_mono = pygame.font.Font(mono, 12 if os.name == 'nt' else 14)
        self._notifications = FadingText(font, (width, 40), (0, height - 40))
        self.server_fps = 0
        self.frame = 0
        self.simulation_time = 0
        self._show_info = True
        self._info_text = []
        self._server_clock = pygame.time.Clock()

    def on_world_tick(self, timestamp):
        self._server_clock.tick()
        self.server_fps = self._server_clock.get_fps()
        self.frame = timestamp.frame
        self.simulation_time = timestamp.elapsed_seconds

    def tick(self, world, clock, control):
        self._notifications.tick(world, clock)
        if not self._show_info:
            return

        self._info_text = [
            ('Throttle:', control.throttle, 0.0, 1.0),
            ('Steer:', control.steer, -1.0, 1.0),
            ('Brake:', control.brake, 0.0, 1.0),
            ('Reverse:', control.reverse),
            ('Hand brake:', control.handbrake),
            ('Manual:', control.manualgear),
            'Gear:        %s' % {-1: 'R', 0: 'N'}.get(control.gear, control.gear),
            ' '
        ]

        self._info_text += [
            ' ',
            'GNSS ',
            'Latitude: %2.6f' % self.gnss.latitude,
            'Longitude: %2.6f ' % self.gnss.longitude,
            f'Altitude: {self.gnss.altitude:2.6f}',
            '',
            'IMU ',
            u'Compass:% 17.0f\N{DEGREE SIGN} ' % (self.imu.compass),
            'Accelero: (%5.1f,%5.1f,%5.1f)' % (self.imu.accelerometer[0],self.imu.accelerometer[1],self.imu.accelerometer[2]),
            'Gyroscop: (%5.1f,%5.1f,%5.1f)' % (self.imu.gyroscope[0],self.imu.gyroscope[1],self.imu.gyroscope[2]),
            ' ',
             ]

    def toggle_info(self):
        self._show_info = not self._show_info

    def notification(self, text, seconds=2.0):
        self._notifications.set_text(text, seconds=seconds)

    def error(self, text):
        self._notifications.set_text('Error: %s' % text, (255, 0, 0))

    def render(self, display):
        if self._show_info:
            info_surface = pygame.Surface((220, self.dim[1]))
            info_surface.set_alpha(100)
            display.blit(info_surface, (0, 0))
            v_offset = 4
            bar_h_offset = 100
            bar_width = 106
            for item in self._info_text:
                if v_offset + 18 > self.dim[1]:
                    break
                if isinstance(item, list):
                    if len(item) > 1:
                        points = [(x + 8, v_offset + 8 + (1.0 - y) * 30) for x, y in enumerate(item)]
                        pygame.draw.lines(display, (255, 136, 0), False, points, 2)
                    item = None
                    v_offset += 18
                elif isinstance(item, tuple):
                    if isinstance(item[1], bool):
                        rect = pygame.Rect((bar_h_offset, v_offset + 8), (6, 6))
                        pygame.draw.rect(display, (255, 255, 255), rect, 0 if item[1] else 1)
                    else:
                        rect_border = pygame.Rect((bar_h_offset, v_offset + 8), (bar_width, 6))
                        pygame.draw.rect(display, (255, 255, 255), rect_border, 1)
                        f = (item[1] - item[2]) / (item[3] - item[2])
                        if item[2] < 0.0:
                            rect = pygame.Rect((bar_h_offset + f * (bar_width - 6), v_offset + 8), (6, 6))
                        else:
                            rect = pygame.Rect((bar_h_offset, v_offset + 8), (f * bar_width, 6))
                        pygame.draw.rect(display, (255, 255, 255), rect)
                    item = item[0]
                if item:  # At this point has to be a str.
                    surface = self._font_mono.render(item, True, (255, 255, 255))
                    display.blit(surface, (8, v_offset))
                v_offset += 18
        self._notifications.render(display)

# ==============================================================================
# -- FadingText ----------------------------------------------------------------
# ==============================================================================

class FadingText(object):
    def __init__(self, font, dim, pos):
        self.font = font
        self.dim = dim
        self.pos = pos
        self.seconds_left = 0
        self.surface = pygame.Surface(self.dim)

    def set_text(self, text, color=(255, 255, 255), seconds=2.0):
        text_texture = self.font.render(text, True, color)
        self.surface = pygame.Surface(self.dim)
        self.seconds_left = seconds
        self.surface.fill((0, 0, 0, 0))
        self.surface.blit(text_texture, (10, 11))

    def tick(self, _, clock):
        delta_seconds = 1e-3 * clock.get_time()
        self.seconds_left = max(0.0, self.seconds_left - delta_seconds)
        self.surface.set_alpha(500.0 * self.seconds_left)

    def render(self, display):
        display.blit(self.surface, self.pos)


import  cv2
import numpy as np

image =cv2.imread("Idris.jpg")

height , width = image.shape[:2]
dst_image = cv2.resize(image, (width*2,height*2), interpolation=cv2.INTER_CUBIC)

M = np.float32([[1, 0, -50],[0,1,-30]])

translate = cv2.warpAffine(image,M, (width,height))

M = cv2.getRotationMatrix2D((width/2.0,height/2.0),180,1)

Rotate = cv2.warpAffine(image,M,(width,height))
#
# cv2.imshow("Resized", dst_image)
# cv2.imshow("Original", image)
# cv2.imshow("Resized", dst_image)
cv2.imshow("Rotate", Rotate)
cv2.waitKey(0)


import os

''' TF_CPP_MIN_LOG_LEVEL
0 = all messages are logged (default behavior)
1 = INFO messages are not printed
2 = INFO and WARNING messages are not printed
3 = INFO, WARNING, and ERROR messages are not printed
'''
'''
print('backend :', keras.backend.backend())
print('keras version :', keras.__version__)
'''
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'

import io
import pandas as pd
import numpy
import scipy
import shutil
import datetime
import pxpLibreriaDataFrame as pd_pxp
from sklearn.model_selection import train_test_split
from sklearn.metrics import confusion_matrix
from sklearn.compose import ColumnTransformer
from sklearn.preprocessing import OneHotEncoder
from keras.models import Sequential
from keras.layers import Dense
from contextlib import redirect_stdout
from pickle import dump

logPrograma = []
logPrograma += [pd_pxp.registroMomento("*) Iniciando programa de entrenamiento", True)]

##################################################################
# Parametrizo
archivoGuardaModelo = "Diabetes_Modelo.json"
archivoGuardaPesos = "Diabetes_Peso.h5"
archivoGuardaTransformaciones = "Diabetes_Transformaciones.pkl"
archivoInfoEntrenamiento = "Diabetes_InfoEntrenamiento.txt"
archivoDeEntrenamiento = "DiabetesColor_ParaEntrenamientoCompleto.csv"  # "DiabetesColor_ParaEntrenamiento.csv"
archivoPrefijoPlot = "Diabetes_graph_"
columnaObjetivo='aparicion'
mostrarGraficos = False
mostrarMejoresCols = False
mostrarGraficoMejoresCols = False
kantidadColumnasBuscadas = 1
split_dataframe_para_test = 0.20
epocas = 20
lote = 5
split_validacion_fit_size = 0.20
##################################################################
# Parametrizo columnas
column_trans = ColumnTransformer(
    [('Colo', OneHotEncoder(dtype='int', handle_unknown='ignore'), ['COLOR'])],
    remainder='passthrough')

##################################################################
# Levanto los datos
logPrograma += [pd_pxp.registroMomento("*) Levantando datos de " + archivoDeEntrenamiento, True)]
df_leida = pd.read_csv(archivoDeEntrenamiento, sep=';')

# df = pd.read_csv("pima-indians-diabetesHEADANEXO.csv", sep=';')
if mostrarGraficoMejoresCols:
    pd_pxp.ExplorarDatosPrevios(df_leida)

##################################################################
logPrograma += [pd_pxp.registroMomento("*) Transformando Columnas ", True)]
df_leida.rename(columns={columnaObjetivo:'objetivo'}, inplace=True)

coltra = column_trans.fit(df_leida)
transformacion = column_trans.transform(df_leida)
# La transformacion puede devolver distintas cosas... no uso pd.DataFrame.sparse.from_spmatrix por que funciona pero adentro queda sparce igual
if type(transformacion) == scipy.sparse.csr.csr_matrix:
    transformacion=transformacion.toarray()
df_transformada = pd.DataFrame(transformacion, columns=coltra.get_feature_names())

# # # salta columnas # # #n
# df_transformada=df_leida.drop(["COLOR"], axis=1)
##############################################################
logPrograma += [pd_pxp.registroMomento("*) Iniciando Split de dataframes ", True)]
train, test = train_test_split(df_transformada, test_size=split_dataframe_para_test, random_state=42, shuffle=True)

# PREPARO ENTRENAMIENTO
train_entrada = pd.DataFrame(train).drop(["objetivo"], axis=1)  # Todos menos lo que voy a predecir
train_salida = pd.DataFrame(train['objetivo'])  # Lo que voy a predecir

# PREPARO TEST
test_entrada = pd.DataFrame(test).drop(["objetivo"], axis=1)  # Todos menos lo que voy a predecir
test_salida = pd.DataFrame(test['objetivo'])  # Lo que voy a predecir

# Mostrar Mejores Columnas
if mostrarMejoresCols:
    pd_pxp.MostrarMejoresColumnas(df_leida, train_entrada, train_salida, kantidadColumnasBuscadas)
    cero = input("\nPresionar 0 para terminar")
    if cero == '0':
        print("Chau!")
        quit()

# Verifico Variabilidad
analisisVariabilidad = ''
sets = (('train_salida', train_salida), ('test_salida', test_salida))
for set_name, set_data in sets:
    analisisVariabilidad = analisisVariabilidad + '-' * 10 + ' ' + set_name + ' ' + '-' * 10 + "\n"
    analisisVariabilidad = analisisVariabilidad + set_data['objetivo'].value_counts().to_string() + "\n"
print(analisisVariabilidad)

# Entrenar y Fit
numpy.random.seed(7)
q_dim_entradas = train_entrada.columns.size

# crea el modelo
model = Sequential()
model.add(Dense(12, input_dim=q_dim_entradas, activation='relu'))
# model.add(Dropout(0.4))
model.add(Dense(8, activation='relu'))
model.add(Dense(1, activation='sigmoid'))
# sigmoid  capa de salida, 1 neurona, Espero 1 salida: cero o uno. Recibe todas las salidas de la capa anterior
# por eso es densa. Pero debe devolver un numero entre cero y uno.

logPrograma += [pd_pxp.registroMomento("*) Compilando Modelo ", True)]
# Compila el modelo: Internamente armo el grafo.
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
# adam es la mas completa de las funciones de ajustar pesos (adam: variante de pesos por gradiente)
# funcion de perdida: binary_crossentropy ideal para salidas entre cero y uno.
# metrics: lo que va imprimiendo de salida.

logPrograma += [pd_pxp.registroMomento("*) Creando Modelo ", True)]
# Ajusta el modelo
history = model.fit(x=train_entrada, y=train_salida, epochs=epocas, validation_split=split_validacion_fit_size,
                    batch_size=lote,
                    shuffle=True)  # 72.64 #72.80

# batch_size - cada cuanto reajusto los pesos?
# epochs - cuantas veces recorro los datos ajustando pesos?

logPrograma += [pd_pxp.registroMomento("*) Evaluando Modelo ", True)]
####################################################################
#  EVALUACION : Incluye evaluate y .predict con identico dataset TEST
scoresTrain = model.evaluate(test_entrada, test_salida)
test_predecido = model.predict(test_entrada)
confundida = confusion_matrix(test_salida, test_predecido.round())
confundidaPxp = pd_pxp.matrizConfusionPxp(confundida)

logPrograma += [pd_pxp.registroMomento("*) Guardando Modelo ", True)]
#####################################################################
# Guardar resultado del entrenamiento
model_json = model.to_json()
with open(archivoGuardaModelo, "w") as json_file:
    json_file.write(model_json)
# serializar los pesos a HDF5
model.save_weights(archivoGuardaPesos)

#SACAR DESDE ACA
# guardo las transformaciones
dump(coltra, open(archivoGuardaTransformaciones, "wb"))
#SACARE HASTA ACA

##################################################################################
logPrograma += [pd_pxp.registroMomento("*) Armando resultados finales ", True)]
resultadoContraTest = "\nEvaluacion contra grupo de test :\n" + \
                      "     {metrica} : {valormetrica:.2f}% \n" + \
                      "     {metrica0} : {valormetrica0:.2f}%\n"
resultadoContraTest = resultadoContraTest.format(metrica=model.metrics_names[1],
                                                 valormetrica=scoresTrain[1] * 100,
                                                 metrica0=model.metrics_names[0],
                                                 valormetrica0=scoresTrain[0] * 100)

resultadoEvaluacion = confundidaPxp.obtenerResultadoEvaluacion()

fileMem = io.StringIO()
with redirect_stdout(fileMem):
    print(" Archivos de entrada: ")
    print(' -' + archivoDeEntrenamiento)
    print(
        " Archivos de salida : ")
    print(' -' + archivoGuardaModelo)
    print(' -' + archivoGuardaPesos)
    print(' -' + archivoInfoEntrenamiento)
    print(' -' + archivoGuardaTransformaciones)
    print(resultadoEvaluacion)
    print(confundida)
    print(resultadoContraTest)
    print('#' * 10, "MODEL SUMMARY", '#' * 10)
    model.summary()
    print('Epochs: ' + str(epocas))
    print('batch_size: ' + str(lote))
    print('split_validacion_fit_size: ' + str(split_validacion_fit_size))
    print('split_dataframe_para_test: ' + str(split_dataframe_para_test))
    print('#' * 10, "SHAPE ENTRENAMIENTO", '#' * 10)
    print(train_entrada.shape)
    print(train_entrada.columns.tolist())
    print('#' * 10, "SHAPE TEST", '#' * 10)
    print(test_entrada.shape)
    print(train_entrada.columns.tolist())
    print('#' * 10, "Analisis de variabilidad", '#' * 10)
    print(analisisVariabilidad)
    print('#' * 10, "Log de performance", '#' * 10)
    logPrograma += [pd_pxp.registroMomento("*) FIN DEL PROCESO ", True)]
    for mom in logPrograma:
        print(mom)

# print(fileMem.getvalue())
with open(archivoInfoEntrenamiento, 'w') as fileDisk:
    fileDisk.write(fileMem.getvalue())  # Lo abro con w entonces lo pisa

# Imprimo
pd_pxp.mostrarPerformanceEntrenamiento(history, archivoPrefijoPlot, mostrarGraficos)
pd_pxp.mostrarMatriz(confundida, archivoPrefijoPlot, mostrarGraficos)

prefijo = datetime.datetime.now().strftime("%m_%d_%Y %H_%M_%S")+' '+' '#+str(tp)+' '
destino = 'Historia/'+prefijo+archivoInfoEntrenamiento
print('* Realizando copia en: '+destino)
# Copia el archivo desde la ubicación actual a Historia
shutil.copy(archivoInfoEntrenamiento, destino)
####################################### SALIDA FINAL
print("Modelo Guardado! Informacion en : " + archivoInfoEntrenamiento)
print('(' * 15, "SALIDA FINAL", ')' * 15)
print(resultadoEvaluacion)
print('Precision tp/(tp+fp): {mcPrecision:,.2%}'.format(mcPrecision=confundidaPxp.mcPrecision))
print('Recall    tp/(tp+fn): {mcRecall:,.2%}'.format(mcRecall=confundidaPxp.mcRecall))
print('Acurracy         : {mcAccuracy:,.2%}'.format(mcAccuracy=confundidaPxp.mcAccuracy))


"""Command line tool for creating premis events"""
from __future__ import unicode_literals

import os
import sys
from uuid import uuid4

import click
import six

import mets
import premis
import xml_helpers.utils
from siptools.utils import MdCreator, encode_id, encode_path
from siptools.xml.premis import PREMIS_EVENT_OUTCOME_TYPES, PREMIS_EVENT_TYPES

click.disable_unicode_literals_warning = True

def _list2str(lst):
    """Create a human readable list of words from list of strings.

    :param lst: list of strings
    :returns: list formatted as single string
    """
    first_words = ['"{}"'.format(string) for string in lst[:-1]]
    last_word = '"{}"'.format(lst[-1])
    return ', '.join(first_words) + ', and ' + last_word

@click.command()
@click.argument('event_type',
                type=click.Choice(PREMIS_EVENT_TYPES))
@click.argument('event_datetime', required=True,
                type=str)
@click.option('--workspace',
              type=click.Path(exists=True),
              default='./workspace',
              metavar='<WORKSPACE PATH>',
              help=("Directory where files are created. Defaults "
                    "to ./workspace/"))
@click.option('--base_path', type=click.Path(exists=True), default='.',
              metavar='<BASE PATH>',
              help=("Source base path of event_target. If used, give "
                    "event_target in relation to this base path."))
@click.option('--event_target',
              type=str,
              metavar='<EVENT TARGET PATH>',
              help=('Target for the event. Default is the root of '
                    'digital objects.'))
@click.option('--event_detail',
              type=str, required=True,
              metavar='<EVENT DETAIL>',
              help='Short information about the event')
@click.option('--event_outcome',
              type=click.Choice(PREMIS_EVENT_OUTCOME_TYPES),
              required=True,
              metavar='<EVENT OUTCOME>',
              help=('Event outcome type. Possible values are: ' +
                    _list2str(PREMIS_EVENT_OUTCOME_TYPES)))
@click.option('--event_outcome_detail',
              type=str,
              metavar='<EVENT OUTCOME DETAIL>',
              help='Detailed information about the event outcome.')
@click.option('--agent_name',
              required='--agent_type' in sys.argv,
              type=str,
              metavar='<AGENT NAME>',
              help='Agent name')
@click.option('--agent_type',
              required='--agent_name' in sys.argv,
              type=str,
              metavar='<AGENT TYPE>',
              help='Agent type.')
@click.option('--stdout',
              is_flag=True,
              help='Print output to stdout')
def main(event_type, event_datetime, event_detail, event_outcome,
         event_outcome_detail, workspace, base_path, agent_name, agent_type,
         stdout, event_target):
    """The script creates provenance metadata for the package. The metadata
    contains event and, if given, also agent of the event.

    \b
    EVENT_TYPE: Type of the event.
    EVENT_DATETIME: Timestamp of the event.
    """
    premis_event(event_type, event_datetime, event_detail, event_outcome,
                 event_outcome_detail, workspace, base_path, agent_name,
                 agent_type, stdout, event_target)

    return 0

def premis_event(event_type, event_datetime, event_detail, event_outcome,
                 event_outcome_detail=None, workspace="./workspace",
                 base_path=".", agent_name=None, agent_type=None, stdout=False,
                 event_target=None):
    """The script creates provenance metadata for the package. The metadata
    contains event and, if given, also agent of the event.
    """
    (directory, event_file) = event_target_path(base_path, event_target)

    if agent_name or agent_type:
        agent_identifier = six.text_type(uuid4())
        agent = create_premis_agent(agent_name,
                                    agent_type, agent_identifier)

        agent_creator = PremisCreator(workspace)
        agent_creator.add_md(agent, event_file, directory=directory)
        agent_creator.write(mdtype="PREMIS:AGENT", stdout=stdout)

        if stdout:
            print(xml_helpers.utils.serialize(agent).decode("utf-8"))
    else:
        agent_identifier = None

    event = create_premis_event(
        event_type,
        event_datetime,
        event_detail,
        event_outcome,
        event_outcome_detail,
        agent_identifier
    )

    creator = PremisCreator(workspace)
    creator.add_md(event, event_file, directory=directory)
    creator.write(mdtype="PREMIS:EVENT", stdout=stdout)

    if stdout:
        print(xml_helpers.utils.serialize(event).decode("utf-8"))

def event_target_path(base_path, event_target=None):
    """Returns the path to the event_target based on the base_path and
    event_target. If event_target is None, the event concerns the whole
    package.

    :returns: a tuple of directory and event_file.
    """
    event_file = None
    directory = None

    # If the given target path is an absolute path and base_path is
    # current path (i.e. not given), relpath will return ../../..
    # sequences, if current path is not part of the absolute path. In
    # such case we will use the absolute path for eventpath and omit
    # base_path relation.
    if event_target:
        if base_path not in ['.']:
            eventpath = os.path.normpath(os.path.join(base_path, event_target))
        else:
            eventpath = event_target

        if os.path.isdir(eventpath):
            directory = os.path.normpath(event_target)
        elif os.path.isfile(eventpath):
            event_file = event_target
        else:
            raise IOError
    else:
        directory = '.'

    return (directory, event_file)

class PremisCreator(MdCreator):
    """Subclass of MdCreator, which generates PREMIS event
    or agent metadata.
    """

    def write(self, mdtype="PREMIS", mdtypeversion="2.3",
              section="digiprovmd", stdout=False):
        super(PremisCreator, self).write(
            mdtype=mdtype, mdtypeversion=mdtypeversion, section=section)

def create_premis_agent(agent_name, agent_type, agent_identifier):
    """Creates METS digiprovMD element that contains PREMIS agent element with
    unique identifier.

    :param agent_name: content of PREMIS agentName element
    :param agent_type: content of PREMIS agentType element
    :param agent_identifier: content of PREMIS agentIdentifierValue element
    :returns: PREMIS event XML element
    """
    agent_identifier = premis.identifier(
        identifier_type='UUID',
        identifier_value=agent_identifier, prefix='agent'
    )
    premis_agent = premis.agent(agent_identifier, agent_name, agent_type)

    return premis_agent

def create_premis_event(event_type, event_datetime, event_detail,
                        event_outcome, event_outcome_detail, agent_identifier):
    """Creates METS digiprovMD element that contains PREMIS event element.
    Linking agent identifier element is added to PREMIS event element, if agent
    identifier is provided as parameter.

    :param event_type: Event type
    :param event_datetime: Event time
    :param event_detail: Event details
    :param event_outcome: Event outcome ("success" or "failure")
    :param event_outcome_detail: Event outcome description
    :param agent_identifier: PREMIS agent identifier or ``None``
    :returns: PREMIS event XML element
    """
    event_identifier = premis.identifier(
        identifier_type='UUID',
        identifier_value=six.text_type(uuid4()),
        prefix='event'
    )

    premis_event_outcome = premis.outcome(event_outcome,
                                          event_outcome_detail)

    child_elements = [premis_event_outcome]

    # Create linkingAgentIdentifier element if agent identifier is provided
    if agent_identifier is not None:
        linking_agent_identifier = premis.identifier(
            identifier_type='UUID',
            identifier_value=agent_identifier,
            prefix='linkingAgent'
        )
        child_elements.append(linking_agent_identifier)

    premis_event_elem = premis.event(event_identifier, event_type,
                                     event_datetime, event_detail,
                                     child_elements=child_elements)

    return premis_event_elem

def create_premis_agent_file(workspace, event_type, agent_name, agent_type,
                             agent_identifier, event_target=None):
    """Creates `<event_type>-agent.xml` file. If path to target file is given
    as `event_target` parameter, the URL-encoded path is used as filename
    prefix. The file is METS XML file that contains PREMIS agent element inside
    digiprovMD element. The ID attribute of digiprovMD is hashed from the
    filename.

    :param workspace: path to directory where file is created
    :param event_type: event type (for filename)
    :param agent_name: PREMIS agentName
    :param agent_type: PREMIS agentType
    :param agent_identifier: PREMIS agentIdentifierValue
    :param event_target: event target file (for filename)
    :returns: output file path and METS XML element object
    """
    output_filename = '%s-agent-amd.xml' % (event_type)
    if event_target:
        output_filename = '%s-%s' % (event_target, output_filename)
    output_filename = encode_path(output_filename)

    agent_id = encode_id(output_filename)

    premis_agent = create_premis_agent(agent_name,
                                       agent_type,
                                       agent_identifier)

    agent_mets = _create_mets(premis_agent, agent_id, 'PREMIS:AGENT')
    _write_mets(agent_mets, os.path.join(workspace, output_filename))

    return (os.path.join(workspace, output_filename),
            agent_mets)

def create_premis_event_file(workspace, event_type, event_datetime,
                             event_detail, event_outcome, event_outcome_detail,
                             event_target=None, agent_identifier=None):
    """Creates `<event_type>-event.xml` file. If path to target file is given
    as `event_target` parameter, the URL-encoded path is used as filename
    prefix. The file is METS XML file that contains PREMIS event element inside
    digiprovMD element. The ID attribute of digiprovMD is hashed from the
    filename.

    :param workspace: path to directory where file is created
    :param event_type: PREMIS eventType
    :param event_datetime: PREMIS eventDateTime
    :param event_detail: PREMIS eventDetail
    :param event_outcome: PREMIS eventOutcome
    :param event_outcome_detail: PREMIS eventOutcomeDetail
    :param agent_identifier: PREMIS linkingAgentIdentifierValue
    :param event_target: event target file (for filename)
    :returns: output file path and METS XML element object
    """
    output_filename = '%s-event-amd.xml' % event_type
    if event_target:
        output_filename = '%s-%s' % (event_target, output_filename)
    output_filename = encode_path(output_filename)

    event_id = encode_id(output_filename)

    premis_event_elem = create_premis_event(
        event_type, event_datetime, event_detail,
        event_outcome, event_outcome_detail, agent_identifier
    )

    event_mets = _create_mets(premis_event_elem, event_id, 'PREMIS:EVENT')
    _write_mets(event_mets, os.path.join(workspace, output_filename))

    return (os.path.join(workspace, output_filename),
            event_mets)

def _write_mets(mets_element, output_file):
    """Write METS XML element to file.

    :param mets_element: METS XML element
    :param output: output file path
    :returns: ``None``
    """

    if not os.path.exists(os.path.dirname(output_file)):
        os.makedirs(os.path.dirname(output_file))

    with open(output_file, 'wb+') as output:
        output.write(xml_helpers.utils.serialize(mets_element))

def _create_mets(premis_element, digiprovmd_id, mdtype):
    """Creates a METS XML element that contains PREMIS element

    :param premis_element: PREMIS element
    :param digiprovmd_id: ID attribute of digiprovMD element
    :param mdtype: MDTYPE of mdWrap element
    :returns: METS XML element
    """
    xmldata = mets.xmldata(child_elements=[premis_element])
    mdwrap = mets.mdwrap(mdtype, '2.3', child_elements=[xmldata])
    digiprovmd = mets.digiprovmd(digiprovmd_id, child_elements=[mdwrap])
    amdsec = mets.amdsec(child_elements=[digiprovmd])
    _mets = mets.mets(child_elements=[amdsec])

    return _mets

if __name__ == '__main__':
    RETVAL = main()  # pylint: disable=no-value-for-parameter
    sys.exit(RETVAL)


from dataclasses import dataclass
from typing import List, Optional, Tuple

import numpy as np
import numpy.typing as npt
from shapely.geometry import CAP_STYLE, LineString, Polygon

from nuplan.common.actor_state.ego_state import EgoState
from nuplan.common.actor_state.scene_object import SceneObject
from nuplan.common.actor_state.state_representation import Point2D, StateSE2
from nuplan.common.maps.abstract_map import AbstractMap
from nuplan.common.maps.abstract_map_objects import Lane, StopLine
from nuplan.common.maps.maps_datatypes import SemanticMapLayer
from nuplan.planning.metrics.evaluation_metrics.base.violation_metric_base import ViolationMetricBase
from nuplan.planning.metrics.metric_result import MetricStatistics, MetricStatisticsType, Statistic, TimeSeries
from nuplan.planning.scenario_builder.abstract_scenario import AbstractScenario
from nuplan.planning.simulation.history.simulation_history import SimulationHistory, SimulationHistorySample
from nuplan.planning.simulation.observation.idm.utils import create_path_from_se2, path_to_linestring
from nuplan.planning.simulation.observation.observation_type import DetectionsTracks, Observation
from nuplan.planning.simulation.occupancy_map.strtree_occupancy_map import STRTreeOccupancyMapFactory
from nuplan.planning.simulation.path.utils import trim_path_up_to_progress

@dataclass
class VelocityRecord:
    """
    Class to track velocity and distance to stop line at a timestamp.
    """

    velocity: float  # [m/s^2], Velocity at the current timestamp
    timestamp: int  # timestamp
    distance_to_stop_line: float  # [m], Distance to the stop line

@dataclass
class VelocityData:
    """
    Class to track VelocityRecord over the simulation history.
    """

    data: List[VelocityRecord]

    def add_data(self, velocity: float, timestamp: int, distance_to_stop_line: float) -> None:
        """
        Add new data to the list
        :param velocity: [m/s^2], Velocity at the current timestamp
        :param timestamp: Timestamp
        :param distance_to_stop_line: [m], Distance to the stop line.
        """
        if self.data is None:
            self.data = []

        self.data.append(
            VelocityRecord(velocity=velocity, timestamp=timestamp, distance_to_stop_line=distance_to_stop_line)
        )

    @property
    def velocity_np(self) -> npt.NDArray[np.float32]:
        """
        Velocity in numpy representation.
        """
        return np.asarray([data.velocity for data in self.data])

    @property
    def timestamp_np(self) -> npt.NDArray[np.int32]:
        """
        Timestamp in numpy representation.
        """
        return np.asarray([data.timestamp for data in self.data])

    @property
    def distance_to_stop_line_np(self) -> npt.NDArray[np.float32]:
        """
        Distance to stop line in numpy representation.
        """
        return np.asarray([data.distance_to_stop_line for data in self.data])

    @property
    def min_distance_stop_line_record(self) -> VelocityRecord:
        """
        Return velocity record of minimum distance stop line
        :return A velocity record.
        """
        distance_to_stop_line = self.distance_to_stop_line_np
        index = np.argmin(distance_to_stop_line)
        return self.data[int(index)]

    @property
    def min_velocity_record(self) -> VelocityRecord:
        """
        Return minimum velocity record
        :return A velocity record.
        """
        index = np.argmin(self.velocity_np)
        return self.data[int(index)]

class EgoStopAtStopLineStatistics(ViolationMetricBase):
    """
    Ego stopped at stop line metric.
    """

    def __init__(
        self,
        name: str,
        category: str,
        max_violation_threshold: int,
        distance_threshold: float,
        velocity_threshold: float,
    ) -> None:
        """
        Initializes the EgoProgressAlongExpertRouteStatistics class
        Rule formulation: 1. Get the nearest stop polygon (less than the distance threshold).
                          2. Check if the stop polygon is in any lanes.
                          3. Check if front corners of ego cross the stop polygon.
                          4. Check if no any leading agents.
                          5. Get min_velocity(distance_stop_line) until the ego leaves the stop polygon.
        :param name: Metric name
        :param category: Metric category
        :param max_violation_threshold: Maximum threshold for the violation when computing the score
        :param distance_threshold: Distances between ego front side and stop line lower than this threshold
        assumed to be the first vehicle before the stop line
        :param velocity_threshold: Velocity threshold to consider an ego stopped.
        """
        super().__init__(name=name, category=category, max_violation_threshold=max_violation_threshold)
        self._distance_threshold = distance_threshold
        self._velocity_threshold = velocity_threshold
        self._stopping_velocity_data: List[VelocityData] = []
        self._previous_stop_polygon_fid: Optional[str] = None

    @staticmethod
    def get_nearest_stop_line(map_api: AbstractMap, ego_pose_front: LineString) -> Optional[Tuple[str, Polygon]]:
        """
        Retrieve the nearest stop polygon
        :param map_api: AbstractMap map api
        :param ego_pose_front: Ego pose front corner line
        :return Nearest stop polygon fid if distance is less than the threshold.
        """
        center_x, center_y = ego_pose_front.centroid.xy
        center = Point2D(center_x[0], center_y[0])

        # If ego is not in lane, then we do not need to proceed.
        if not map_api.is_in_layer(center, layer=SemanticMapLayer.LANE):
            return None

        stop_line_fid, distance = map_api.get_distance_to_nearest_map_object(center, SemanticMapLayer.STOP_LINE)

        if stop_line_fid is None:
            return None

        stop_line: StopLine = map_api.get_map_object(stop_line_fid, SemanticMapLayer.STOP_LINE)
        lane: Optional[Lane] = map_api.get_one_map_object(center, SemanticMapLayer.LANE)

        # Check if the stop polygon intersects with the ego lane
        if lane is not None:
            return stop_line_fid, stop_line.polygon if stop_line.polygon.intersects(lane.polygon) else None

        return None

    @staticmethod
    def check_for_leading_agents(detections: Observation, ego_state: EgoState, map_api: AbstractMap) -> bool:
        """
        Get the nearest leading agent
        :param detections: Detection class
        :param ego_state: Ego in oriented box representation
        :param map_api: AbstractMap api
        :return True if there is a leading agent, False otherwise
        """
        if isinstance(detections, DetectionsTracks):

            if len(detections.tracked_objects.tracked_objects) == 0:
                return False

            ego_agent = ego_state.agent

            # Check if any missing instance token
            for index, box in enumerate(detections.tracked_objects):
                if box.token is None:
                    box.token = str(index + 1)
            scene_objects: List[SceneObject] = [ego_agent]
            scene_objects.extend([scene_object for scene_object in detections.tracked_objects])

            occupancy_map = STRTreeOccupancyMapFactory.get_from_boxes(scene_objects)
            agent_states = {
                scene_object.token: StateSE2(
                    x=scene_object.center.x, y=scene_object.center.y, heading=scene_object.center.heading
                )
                for scene_object in scene_objects
            }
            ego_pose: StateSE2 = agent_states['ego']
            lane = map_api.get_one_map_object(ego_pose, SemanticMapLayer.LANE)

            # Construct ego's path to go
            ego_baseline = lane.baseline_path
            ego_progress = ego_baseline.get_nearest_arc_length_from_position(ego_pose)
            progress_path = create_path_from_se2(ego_baseline.discrete_path)
            ego_path_to_go = trim_path_up_to_progress(progress_path, ego_progress)

            # Check for intersection between the path and the any other agents
            ego_path_to_go = path_to_linestring(ego_path_to_go)
            intersecting_agents = occupancy_map.intersects(
                ego_path_to_go.buffer((scene_objects[0].box.width / 2), cap_style=CAP_STYLE.flat)
            )

            # If there are other agents ahead of the ego in the same lane there should be at least two agents
            if intersecting_agents.size > 1:
                return True

        return False

    def _compute_velocity_statistics(self, scenario: AbstractScenario) -> List[MetricStatistics]:
        """
        Compute statistics in each stop line
        :param scenario: Scenario running this metric
        :return A list of metric statistics.
        """
        if not self._stopping_velocity_data:
            return []

        mean_ego_min_distance_to_stop_line = []
        mean_ego_min_velocity_before_stop_line = []
        aggregated_timestamp_velocity = []
        aggregated_timestamps = []
        ego_stop_status = []

        for velocity_data in self._stopping_velocity_data:

            # Stop at stop line success rate, we check the velocity of minimum distance to the stop line in each record
            min_distance_velocity_record = velocity_data.min_distance_stop_line_record
            mean_ego_min_distance_to_stop_line.append(min_distance_velocity_record.distance_to_stop_line)
            mean_ego_min_velocity_before_stop_line.append(min_distance_velocity_record.velocity)

            if (
                min_distance_velocity_record.distance_to_stop_line < self._distance_threshold
                and min_distance_velocity_record.velocity < self._velocity_threshold
            ):
                stop_status = True
            else:
                stop_status = False

            ego_stop_status.append(stop_status)
            aggregated_timestamp_velocity.append(velocity_data.velocity_np)
            aggregated_timestamps.append(velocity_data.timestamp_np)

        # Aggregate
        statistics = [
            Statistic(
                name='number_of_ego_stop_before_stop_line',
                unit=MetricStatisticsType.COUNT.unit,
                value=sum(ego_stop_status),
                type=MetricStatisticsType.COUNT,
            ),
            Statistic(
                name='number_of_ego_before_stop_line',
                unit=MetricStatisticsType.COUNT.unit,
                value=len(ego_stop_status),
                type=MetricStatisticsType.COUNT,
            ),
            Statistic(
                name='mean_ego_min_distance_to_stop_line',
                unit='meters',
                value=float(np.mean(mean_ego_min_distance_to_stop_line)),
                type=MetricStatisticsType.VALUE,
            ),
            Statistic(
                name='mean_ego_min_velocity_before_stop_line',
                unit='meters_per_second_squared',
                value=float(np.mean(mean_ego_min_velocity_before_stop_line)),
                type=MetricStatisticsType.VALUE,
            ),
        ]

        aggregated_timestamp_velocity = np.hstack(aggregated_timestamp_velocity)  # type: ignore
        aggregated_timestamps = np.hstack(aggregated_timestamps)  # type: ignore
        velocity_time_series = TimeSeries(
            unit='meters_per_second_squared',
            time_stamps=list(aggregated_timestamps),
            values=list(aggregated_timestamp_velocity),
        )

        results = self._construct_metric_results(
            metric_statistics=statistics, time_series=velocity_time_series, scenario=scenario
        )
        return results  # type: ignore

    def _save_stopping_velocity(
        self,
        current_stop_polygon_fid: str,
        history_data: SimulationHistorySample,
        stop_polygon_in_lane: Polygon,
        ego_pose_front: LineString,
    ) -> None:
        """
        Save velocity, timestamp and distance to a stop line if the ego is stopping
        :param current_stop_polygon_fid: Current stop polygon fid
        :param history_data: History sample data at current timestamp
        :param stop_polygon_in_lane: The stop polygon where the ego is in
        :param ego_pose_front: Front line string (front right corner and left corner) of the ego.
        """
        # Distance between the front stop line and ego's front footprint
        stop_line: LineString = LineString(stop_polygon_in_lane.exterior.coords[:2])
        distance_ego_front_stop_line = stop_line.distance(ego_pose_front)
        current_velocity = history_data.ego_state.dynamic_car_state.speed
        current_timestamp = history_data.ego_state.time_point.time_us

        # If it is in the same stop polygon
        if current_stop_polygon_fid == self._previous_stop_polygon_fid:
            self._stopping_velocity_data[-1].add_data(
                velocity=current_velocity,
                timestamp=current_timestamp,
                distance_to_stop_line=distance_ego_front_stop_line,
            )
        else:
            # If it is a new stop polygon
            self._previous_stop_polygon_fid = current_stop_polygon_fid
            velocity_data = VelocityData([])
            velocity_data.add_data(
                velocity=current_velocity,
                timestamp=current_timestamp,
                distance_to_stop_line=distance_ego_front_stop_line,
            )
            self._stopping_velocity_data.append(velocity_data)

    def compute(self, history: SimulationHistory, scenario: AbstractScenario) -> List[MetricStatistics]:
        """
        Returns the ego stopped at stop line metric
        :param history: History from a simulation engine
        :param scenario: Scenario running this metric
        :return the estimated ego stopped at stop line metric.
        """
        # Extract ego pose in box3d.
        ego_states: List[EgoState] = history.extract_ego_state

        # Get egos' front footprint
        ego_pose_fronts: List[LineString] = [
            LineString(
                [
                    state.car_footprint.oriented_box.geometry.exterior.coords[0],
                    state.car_footprint.oriented_box.geometry.exterior.coords[3],
                ]
            )
            for state in ego_states
        ]

        # Get stop polygons
        scenario_map: AbstractMap = history.map_api

        # Get the nearest stop polygon.
        for ego_pose_front, ego_state, history_data in zip(ego_pose_fronts, ego_states, history.data):

            # 1) Get the nearest stop polygon if it is in the same lane as ego.
            stop_polygon_info: Optional[Tuple[str, Polygon]] = self.get_nearest_stop_line(
                map_api=scenario_map, ego_pose_front=ego_pose_front
            )

            if stop_polygon_info is None:
                continue

            fid, stop_polygon_in_lane = stop_polygon_info

            # 2) Check if front corners cross the stop polygon
            ego_pose_front_stop_polygon_distance: float = ego_pose_front.distance(stop_polygon_in_lane)

            # The front corners cross the stop polygon if distance is zero
            if ego_pose_front_stop_polygon_distance != 0:
                continue

            # 3) Check if no any leading agents.
            detections: Observation = history_data.observation
            has_leading_agent = self.check_for_leading_agents(
                detections=detections, ego_state=ego_state, map_api=scenario_map
            )

            # Skip if there is any leading agent in the stop polygon (means the ego is not the first vehicle)
            if has_leading_agent:
                continue

            # 4) Accumulate velocity
            self._save_stopping_velocity(
                current_stop_polygon_fid=fid,
                history_data=history_data,
                stop_polygon_in_lane=stop_polygon_in_lane,
                ego_pose_front=ego_pose_front,
            )

        results = self._compute_velocity_statistics(scenario=scenario)
        return results


import ply.lex as lex
import sys
import re

file = open("read.py")

# Diccionario de palabras reservadas
reservadas = {
    'if': 'IF',
    'else': 'ELSE',
    'while': 'WHILE',
    'for': 'FOR',
    'break': 'BREAK',
    'continue': 'CONTINUE',
    'True': 'TRUE',
    'False': 'FALSE',
    'and': 'AND',
    'or': 'OR',
    'not': 'NOT',
}

# Lista de tokens
tokens = [
    'ID',
    'NUMBER',
    'PLUS',
    'MINUS',
    'TIMES',
    'DIVIDE',
    'EQUALS',
    'LPAREN',
    'RPAREN',
    'LBRACE',
    'RBRACE',
    'COMMA',
    'SEMI',
    'GREATER',
    'LESS',
    'GREATER_EQUAL',
    'LESS_EQUAL',
    'DOUBLE_EQUAL',
    'NOT_EQUAL',
] + list(reservadas.values())

# Expresiones regulares para tokens simples
t_PLUS = r'\+'
t_MINUS = r'-'
t_TIMES = r'\*'
t_DIVIDE = r'/'
t_EQUALS = r'='
t_LPAREN = r'\('
t_RPAREN = r'\)'
t_LBRACE = r'{'
t_RBRACE = r'}'
t_COMMA = r','
t_SEMI = r';'
t_GREATER = r'>'
t_LESS = r'<'
t_GREATER_EQUAL = r'>='
t_LESS_EQUAL = r'<='
t_DOUBLE_EQUAL = r'=='
t_NOT_EQUAL = r'!='

# Expresiones regulares con acciones asociadas
def t_ID(t):
    r'[a-zA-Z_][a-zA-Z0-9_]*'
    t.type = reservadas.get(t.value, 'ID')
    return t

def t_NUMBER(t):
    r'\d+'
    t.value = int(t.value)
    return t

# Manejo de espacios en blanco y comentarios
def t_whitespace(t):
    r'\s+'
    pass

def t_comment(t):
    r'\#.*'
    pass

# Manejo de errores
def t_error(t):
    print(f"Carácter ilegal '{t.value[0]}' en línea {t.lineno}, posición {t.lexpos}")
    t.lexer.skip(1)

# Construcción del lexer
lexer = lex.lex()
contents = file.read()
print("Analizador Léxico")
print("----------------------------------")

count=0
program = contents.split("\n")
print("Archivo leido\n",contents)
print("----------------------------------")
print("Division en tokens")
for line in program:
    count = count + 1
    tokens=line.split(' ')
    print("Linea ",count, " Tokens: ",tokens)

# Leer archivo de texto
#filename = 'read.py'
#with open(filename, "r") as file:
    #contents = file.read()
    #tokens=line.split(' ')
    #print("Los tokens son:" , tokens)

# Análisis léxico
print("\n CLASIFICACION DE TOKENS \n")
lexer.input(contents)
for tok in lexer:
    print(f"Linea {tok.lineno:3} Posicion {tok.lexpos:3} Tipo {tok.type:16} Valor {tok.value:10}")


import numpy as np
from collections import Counter

###################### IMPACT AND LEADING PERSISTENT USERS ######################
def temporal_highimpact_impacts( edgelists, num_highimpact_users, target='target', weight='weight'):
    """Return an array with the leading impact vector over time as well as the array of leading users.

    Inputs:
        - edgelists: array of edgelists for each time with the number of retweets from user i to user j.
    """

    temporal_highimpact_impact_array = []
    temporal_highimpact_users_array = []
    for edgelist in edgelists:

        leading_impact_vector = get_leading_impact_vector( edgelist, num_highimpact_users, target=target, weight=weight )

        temporal_highimpact_impact_array.append( leading_impact_vector )
        temporal_highimpact_users_array.append( set( leading_impact_vector.index ) )

    return temporal_highimpact_impact_array, temporal_highimpact_users_array

def temporal_leading_impacts(edgelists, num_highimpact_users, num_persistent_users, target='target', weight='weight'):
    """ Return impact vector for leading (N) persistent (M) users in edgelist.

    If num_highimpact_users:float in [0,1], it is treated as a percentage. If num_leading_users:int > 0, it is treated as absolute number of users.

    Inputs:
        - edgelists: array of edgelists for each time with the number of retweets from user i to user j.
        - num_highimpact_users: number of high-impact users (N in the paper).
        - num_persistent_users: number of leading users considered as persistent (M in the paper).
    Outputs:
        - persistent_impact_vec: array of impact vectors of the leading persistent users
        - persistent_users_vec: array of the leading persistent users
        - users_persistence: persistence of the leading users
    """

    leading_impact_vec, leading_users_vec = temporal_highimpact_impacts( edgelists, num_highimpact_users, target=target, weight=weight )

    users_persistence = get_users_persistence( leading_users_vec )
    users_persistence = users_persistence.most_common( num_persistent_users )

    persistent_users = get_users_from_users_persistence_dict( users_persistence )

    persistent_impact_vec = []
    persistent_users_vec  = []
    for leading_impact in leading_impact_vec:
        persistent_impacts = leading_impact[ leading_impact.index.isin( persistent_users ) ]

        persistent_impact_vec.append( persistent_impacts  )
        persistent_users_vec.append( set( persistent_impacts.index )  )

    return persistent_impact_vec, persistent_users_vec, users_persistence

def get_impact_vector(edgelist, target='target', weight='weight'):
    """ Returns impact vector for all users in edgelist.
    """
    return edgelist.groupby( target ).sum().sort_values( weight )

# In the article, N = 50 leading weekly users, M = 50 of persistent users
def get_leading_impact_vector(edgelist, num_leading_users, target='target', weight='weight'):
    """ Return impact vector for leading (N) persistent (M) users in edgelist.
    If num_leading_users:float in [0,1], it is treated as a percentage. If num_leading_users:int > 0, it is treated as absolute number of users.
    """

    impact_vec = get_impact_vector( edgelist, target=target, weight=weight )

    if 0 < num_leading_users < 1:

        ## Option 1: based on percentage of retweets
        impact_cum_dist = impact_vec[ weight ].cumsum()
        impact_cum_dist /= impact_cum_dist.iloc[-1]

        return impact_vec[ impact_cum_dist > num_leading_users]

        ## Option 2: based on percentage of population
        # population_cum_dist = pd.Series(range(1 , len(impact_vec)+1), index=impact_vec.index)
        # population_cum_dist /= population_cum_dist.iloc[-1]

        # return impact_vec[ population_cum_dist > num_leading_users]

    elif (type(num_leading_users) == int) & (num_leading_users > 0):

        return impact_vec.iloc[ -num_leading_users: ]

    else:
        print('Some error for {}'.format(num_leading_users))

def get_users_persistence(users_array):#, num_users=None):
    '''Return a dictionary of all the users in `influential_users:list[set]` as well as their persistence.
    '''

    users_persistence = np.array([])

    # append all users into a single array
    for users in users_array:

        users_persistence = np.append(users_persistence, np.array(list(users)))

    users_persistence = Counter( users_persistence )
    users_persistence = {k: v for k, v in sorted(users_persistence.items(), key=lambda item: item[1], reverse=True)}

    return Counter(users_persistence)

def get_users_from_users_persistence_dict( users_persistence ):
    return [ users for (users, persistence) in users_persistence ]

# TODO: audiences:array[dict], chambers:array[dict], array of overlap matrices, chambers/audiences networks

###################### CHAMBERS & AUDIENCES ######################

def get_audience( user, edgelist, source='source', target='target' ):
    '''Returns the audience:set of the user given an edgelist.
    '''
    return set( edgelist[ edgelist[ target ] == user ][ source ].unique() )

def get_chamber( user, edgelist, users_excluded=False, source='source', target='target'):
    """Returns the chamber:set of the user given an edgelist.

    users_excluded can be either False or a list of users to exclude from chamber.
    """

    audience = get_audience( user, edgelist, source=source, target=target )
    audience_out_ego_network = edgelist[ edgelist[ source ].isin( audience ) ]
    # remove the leading user from the audience ego network
    audience_out_ego_network = audience_out_ego_network[ audience_out_ego_network[ target ] != user ]

    # exclude specific users from chamber.
    if users_excluded != False:
        audience_out_ego_network = audience_out_ego_network[ ~audience_out_ego_network[ target ].isin( users_excluded ) ]

    chamber = set( audience_out_ego_network[ target ].unique() )
    return chamber

def get_chamber_from_audience(user, edgelist, audience, users_excluded=False, source='source', target='target'):
    """Returns the chamber:set of the user given an edgelist and a given audience.

    users_excluded can be either False or a list of users to exclude from chamber.
    """

    audience_out_ego_network = edgelist[ edgelist[ source ].isin( audience ) ]
    # remove the leading user from the audience ego network
    audience_out_ego_network = audience_out_ego_network[ audience_out_ego_network[ target ] != user ]

    # exclude specific users from chamber.
    if users_excluded != False:
        audience_out_ego_network = audience_out_ego_network[ ~audience_out_ego_network[ target ].isin( users_excluded ) ]

    chamber = set( audience_out_ego_network[ target ].unique() )
    return chamber

def get_audience_edgelist( user, edgelist, source='source', target='target' ):
    '''Builds audience network of leading user `user`.
    '''

    audience = get_audience( user, edgelist, source, target )

    audience_edgelist = get_edgelist_from_audience( audience, edgelist, source, target )
    return audience_edgelist

def get_chamber_edgelist( user, edgelist, users_excluded=False, source='source', target='target'):
    '''Builds chamber network of leading user `user`.
    '''

    chamber = get_chamber( user, edgelist, users_excluded, source, target )

    chamber_edgelist = get_edgelist_from_chamber( chamber, edgelist, source, target )
    return chamber_edgelist

# helper
def get_edgelist_from_chamber(chamber, edgelist, source='source', target='target'):
    chamber_edgelist = edgelist[ (edgelist[ source ].isin( chamber )) & (edgelist[ target ].isin( chamber )) ]
    return chamber_edgelist

def get_edgelist_from_audience(audience, edgelist, source='source', target='target'):
    audience_edgelist = edgelist[ (edgelist[ source ].isin( audience )) & (edgelist[ target ].isin( audience )) ]
    return audience_edgelist

def get_chambers_of_users( users, edgelist, users_excluded=False, source='source', target='target', return_network=False ):
    """Get the chamber of all the users in `users`.

    users_excluded can be {False, list:str (list of global excluded users), list:list:str (list of excluded users per week)}
    """

    chambers_dict = {}
    chamber_networks_dict = {}
    for i, user in enumerate(users):

        chamber = get_chamber( user, edgelist, users_excluded=users_excluded, source=source, target=target )
        chambers_dict[user] = chamber

        if return_network:
            chamber_edgelist = get_edgelist_from_chamber( chamber, edgelist, source, target )
            chamber_networks_dict[user] = chamber_edgelist

    if return_network:
        return chambers_dict, chamber_networks_dict
    else:
        return chambers_dict

def get_audiences_of_users( users, edgelist, source='source', target='target', return_network=False ):
    """Get the audience of all the users in `users`.

    users_excluded can be {False, list:str (list of global excluded users), list:list:str (list of excluded users per week)}
    """

    audiences_dict = {}
    audience_networks_dict = {}
    for i, user in enumerate(users):

        audience = get_audience( user, edgelist, source=source, target=target )
        audiences_dict[user] = audience

        if return_network:
            audience_edgelist = get_edgelist_from_audience( audience, edgelist, source, target )
            audience_networks_dict[user] = audience_edgelist

    if return_network:
        return audiences_dict, audience_networks_dict
    else:
        return audiences_dict

def temporal_chambers(users, edgelists, users_excluded=False, source='source', target='target', return_networks=False):
    """Get the chambers of all the users in users for every edgelist in edgelists. It is assumed that edgelists are ordered temporally.
    """

    # preallocation
    temporal_chambers_vec = [{}] * len(edgelists)
    temporal_chamber_networks_vec = [{}] * len(edgelists)

    # check if there is a list of excluded users. If there is, check if it's a temporal (leading) or a static (persistent) list
    list_of_lists = False
    if users_excluded != False:
        list_of_lists = (type(users_excluded[0]) == list) | (type(users_excluded[0]) == set)

    for (t,edgelist) in enumerate(edgelists):

        if return_networks:
            if list_of_lists:
                chamber_per_user_dict, chamber_network_per_user_dict = get_chambers_of_users( users[t], edgelist, users_excluded[t], source, target, return_networks )
            else:
                chamber_per_user_dict, chamber_network_per_user_dict = get_chambers_of_users( users[t], edgelist, users_excluded, source, target, return_networks )

            # append chamber networks for time t
            temporal_chamber_networks_vec[t] = chamber_network_per_user_dict

        else:
            if list_of_lists:
                chamber_per_user_dict = get_chambers_of_users( users[t], edgelist, users_excluded[t], source, target, return_networks )
            else:
                chamber_per_user_dict = get_chambers_of_users( users[t], edgelist, users_excluded, source, target, return_networks )

        # append chambers for time t
        temporal_chambers_vec[t] = chamber_per_user_dict

    if return_networks:
        return temporal_chambers_vec, temporal_chamber_networks_vec
    else:
        return temporal_chambers_vec

def temporal_audiences( users, edgelists, source='source', target='target', return_networks=False ):
    """Get the audiences of all the users in users for every edgelist in edgelists. It is assumed that edgelists are ordered temporally.
    """

    # preallocation
    temporal_audiences_vec = [{}] * len(edgelists)
    temporal_audience_networks_vec = [{}] * len(edgelists)

    for (t,edgelist) in enumerate(edgelists):

        if return_networks:
            audience_per_user_dict, audience_network_per_user_dict = get_audiences_of_users( users[t], edgelist, source, target, return_networks )
            # append audience networks for time t
            temporal_audience_networks_vec[t] = audience_network_per_user_dict

        else:
            audience_per_user_dict = get_audiences_of_users( users[t], edgelist, source, target, return_networks )

        # append audiences for time t
        temporal_audiences_vec[t] = audience_per_user_dict

    if return_networks:
        return temporal_audiences_vec, temporal_audience_networks_vec
    else:
        return temporal_audiences_vec

# helper
def get_chamber_from_audience(user, edgelist, audience, users_excluded=False, source='source', target='target'):
    """Returns the chamber:set of the user given an edgelist and a given audience.

    users_excluded can be either False or a list of users to exclude from chamber.
    """

    audience_out_ego_network = edgelist[ edgelist[ source ].isin( audience ) ]
    # remove the leading user from the audience ego network
    audience_out_ego_network = audience_out_ego_network[ audience_out_ego_network[ target ] != user ]

    # exclude specific users from chamber.
    if users_excluded != False:
        audience_out_ego_network = audience_out_ego_network[ ~audience_out_ego_network[ target ].isin( users_excluded ) ]

    chamber = set( audience_out_ego_network[ target ].unique() )
    return chamber


import torch
import torch.nn as nn
from torch import optim
import torch.nn.functional as F
import numpy as np
import utils

class TemporalVAE(nn.Module):

    def __init__(self, input_size, hidden_size, latent_size, k_step, activation_func='tanh'):
        super(TemporalVAE, self).__init__()

        self.k_step = k_step
        self.input_size = input_size
        self.latent_size = latent_size

        # Encoder
        self.f_enc1 = nn.Linear(input_size, hidden_size)
        self.f_mu = nn.Linear(hidden_size, latent_size)
        self.f_logvar = nn.Linear(hidden_size, latent_size)

        # Decoder
        self.f_dec1 = nn.Linear(latent_size, hidden_size)
        self.f_dec2 = nn.Linear(hidden_size, input_size)

        # Transition Function
        self.f_trainsition = nn.Linear(latent_size, latent_size)
        # self.f_trainsition2 = nn.Linear(latent_size, latent_size)

        # Activation Function
        self.act_func = getattr(torch, activation_func)

    def encode(self, state):
        hidden = self.act_func(self.f_enc1(state))
        return self.f_mu(hidden), self.f_logvar(hidden)

    def predict(self, prev_states):
        next_states = self.f_trainsition(prev_states)
        # next_state = self.f_trainsition2(hidden)
        return next_states

    def decode(self, hidden):
        hidden = self.act_func(self.f_dec1(hidden))
        decoded = self.f_dec2(hidden)
        # decoded = torch.sigmoid(decoded)
        return decoded

    def sample(self, mu, logvar):
        std = torch.exp(0.5 * logvar)
        eps = torch.randn_like(std)
        return mu + eps * std

    def forward(self, states):

        # Reconstruct the trajectory
        mu, logvar = self.encode(states[:, 0:2])
        latent = self.sample(mu, logvar)
        recon = self.decode(latent)

        z_next_pred = self.predict(latent)

        mu_next, logvar_next = self.encode(states[:, 3:5])
        z_next_sampled = self.sample(mu_next, logvar_next)

        return recon, mu, logvar, z_next_sampled, z_next_pred

    def loss_func(self, recon, states, mu, logvar, z_next_sampled, z_next_pred):
        MSE_REC = F.mse_loss(input=recon, target=states[:, 0:2], reduction='sum')
        MSE_PRED = F.mse_loss(input=z_next_pred, target=z_next_sampled, reduction='sum')
        KLD = -0.5 * torch.sum(1 + logvar - mu.pow(2) - logvar.exp())

        return MSE_REC, MSE_PRED, KLD

def train_epoch(model, optimizer, beta, train_data_loader, device):
    model.train()
    total_loss, recon_loss, pred_loss, kld_loss = 0, 0, 0, 0
    for states in train_data_loader:
        states_batch = states.to(device)

        optimizer.zero_grad()

        recon, mu, logvar, z_next_sampled, z_next_pred = model(states_batch)
        MSE_REC, MSE_PRED, KLD = model.loss_func(recon, states_batch, mu, logvar, z_next_sampled, z_next_pred)
        # loss = MSE_REC + beta * KLD + MSE_PRED
        loss = MSE_REC + MSE_PRED
        loss.backward()
        total_loss += loss.item()
        recon_loss += MSE_REC.item()
        pred_loss += MSE_PRED.item()
        kld_loss += KLD.item()

        optimizer.step()

    total_loss /= len(train_data_loader.dataset)
    recon_loss /= len(train_data_loader.dataset)
    pred_loss /= len(train_data_loader.dataset)
    kld_loss /= len(train_data_loader.dataset)

    loss_dict = {'total': total_loss, 'recon': recon_loss,
                 'pred': pred_loss, 'kld': kld_loss}

    return loss_dict

def evaluate_epoch(model, beta, valid_data_loader, device):
    model.eval()
    total_loss, recon_loss, pred_loss, kld_loss = 0, 0, 0, 0
    with torch.no_grad():
        for states in valid_data_loader:
            states_batch = states.to(device)

            recon, mu, logvar, z_next_sampled, z_next_pred = model(states_batch)
            MSE_REC, MSE_PRED, KLD = model.loss_func(recon, states_batch, mu, logvar, z_next_sampled, z_next_pred)
            # loss = MSE_REC + MSE_PRED + beta * KLD
            loss = MSE_REC + MSE_PRED

            total_loss += loss.item()
            recon_loss += MSE_REC.item()
            pred_loss += MSE_PRED.item()
            kld_loss += KLD.item()

        total_loss /= len(valid_data_loader.dataset)
        recon_loss /= len(valid_data_loader.dataset)
        pred_loss /= len(valid_data_loader.dataset)
        kld_loss /= len(valid_data_loader.dataset)

        loss_dict = {'total': total_loss, 'recon': recon_loss,
                     'pred': pred_loss, 'kld': kld_loss}

    return loss_dict

def train(model, config, train_data_loader, valid_data_loader, checkpoint_path, loss_path, device):
    optimizer = optim.Adam(params=model.parameters(), lr=config.lr)
    print('Starting training...')
    best_eval_loss = 100000.0
    # betas = np.linspace(0, 0.1, config.num_epochs)
    epoch_loss = np.zeros((config.num_epochs, 8))

    for epoch_i in range(config.num_epochs):
        train_loss_dict = train_epoch(model, optimizer, config.beta, train_data_loader, device)
        valid_loss_dict = evaluate_epoch(model, config.beta, valid_data_loader, device)

        print('====> Epoch: {}/{}'.format(epoch_i+1, config.num_epochs))
        print('====> Train loss:     {:.7f} Eval Loss: {:.7f} '.format(train_loss_dict['total'],
                                                                       valid_loss_dict['total']))

        print('====> Train MSE Loss: {:.7f} MSE T Loss {:.7f} KLD Loss:  {:.7f} '.format(train_loss_dict['recon'],
                                                                                train_loss_dict['pred'],
                                                                                train_loss_dict['kld']))

        print('====> Eval  MSE Loss: {:.7f} MSE T Loss {:.7f} KLD Loss:  {:.7f} '.format(valid_loss_dict['recon'],
                                                                                valid_loss_dict['pred'],
                                                                                valid_loss_dict['kld']))

        epoch_loss[epoch_i] = np.hstack((list(train_loss_dict.values()), list(valid_loss_dict.values())))

        is_best = valid_loss_dict['total'] <= best_eval_loss
        if is_best:
            print('====> New best checkpoint!')
            best_eval_loss = valid_loss_dict['total']

        if config.save:
            utils.save_checkpoint(state=model.state_dict(),
                                  checkpoint_path=checkpoint_path,
                                  is_best=is_best,
                                  save_only_best=False)

        print('----------------------------------------------------------------------------')

    if config.save:
        with open(loss_path, 'wb') as f:
            np.savetxt(f, epoch_loss, delimiter=',')


import numpy as np
from traitlets import Enum, Integer, default, Float, Bool, Unicode, List

from mrHARDI.base.application import (mrHARDIConfigurable,
                                           convert_enum,
                                           ChoiceList)

from mrHARDI.base.dwi import Direction, AcquisitionType
from mrHARDI.compute.b0 import B0PostProcess, B0Reference

_b0_aliases = dict(
    mean="B0UtilsConfiguration.mean_strategy",
    ref="B0UtilsConfiguration.reference_strategy",
    type="B0UtilsConfiguration.dtype",
    strides="B0UtilsConfiguration.strides",
    ceil="B0UtilsConfiguration.ceil_value"
)

_b0_flags = dict(
    strict=(
        {'B0UtilsConfiguration': {'strict': True}},
        "Test b0 b-values using \"less\" comparator "
        "instead of \"less or equal\""
    ),
)

class B0UtilsConfiguration(mrHARDIConfigurable):
    def _validate(self):
        pass

    def serialize(self, *args, **kwargs):
        pass

    @default("app_aliases")
    def _app_aliases_default(self):
        return _b0_aliases

    @default("app_flags")
    def _app_flags_default(self):
        return _b0_flags

    current_util = Enum(
        ["extract", "squash", "normalize", None], None
    ).tag(config=True, required=True)

    mean_strategy = convert_enum(
        B0PostProcess, B0PostProcess.batch, allow_none=True,
        description="Strategy to use when averaging the b0 volume(s). "
                    "Either averages the whole set of b0s (whole), does "
                    "the averages by clump of continuous b0 (batch) or "
                    "takes the first on of each clump (none)."
    ).tag(config=True)

    reference_strategy = convert_enum(
        B0Reference, B0Reference.linear,
        description="ONLY USED WHEN DOING NORMALIZATION. Defines which "
                    "strategy will be used to select b0 volumes for "
                    "averaging. Can either do a linear interpolation between "
                    "b0 volumes appearing before and after each group of "
                    "diffusion volumes (linear), take the one appearing "
                    "before (first) or after (last)."
    ).tag(config=True)

    ceil_value = Float(
        0.9, help="Higher bound determining a valid b-value for a b0 volume"
    ).tag(config=True)

    strict = Bool(
        False, help="If True, test b0 b-values with "
                    "\"<\" comparator instead of \"<=\""
    ).tag(config=True)

    dtype = Enum(
        [
            np.dtype(t).name
            for t in [np.int16, np.int32, np.float32, np.float64]
        ], allow_none=True
    ).tag(config=True)

    strides = Integer(None, allow_none=True).tag(config=True)

    def get_mean_strategy_enum(self):
        return B0PostProcess[self.mean_strategy]

    def get_ref_strategy_enum(self):
        return B0Reference[self.reference_strategy]

_meta_aliases = dict(
    dir="DwiMetadataUtilsConfiguration.direction",
    mb="DwiMetadataUtilsConfiguration.multiband_factor",
    sd="DwiMetadataUtilsConfiguration.slice_direction",
    si="DwiMetadataUtilsConfiguration.slice_indexes",
    gsl="DwiMetadataUtilsConfiguration.gslider_factor",
    acq="DwiMetadataUtilsConfiguration.acquisition",
    readout="DwiMetadataUtilsConfiguration.readout",
    coils="DwiMetadataUtilsConfiguration.number_of_coils"
)

_meta_flags = dict(
    interleaved=(
        {"DwiMetadataUtilsConfiguration": {'interleaved': True}},
        "Set dataset acquisition as interleaved order (0, 2, 4, 1, 3 ...)"
    ),
    mbc=(
        {"DwiMetadataUtilsConfiguration": {'multiband_corrected': True}},
        "Set dataset as already corrected for multiband artifacts"
    ),
    tv=(
        {"DwiMetadataUtilsConfiguration": {'tensor_valued': True}},
        "Set dataset as tensor-valued acquisition"
    )
)

class DwiMetadataUtilsConfiguration(mrHARDIConfigurable):
    @default("app_aliases")
    def _app_aliases_default(self):
        return _meta_aliases

    @default("app_flags")
    def _app_flags_default(self):
        return _meta_flags

    direction = ChoiceList(
        [d.name for d in Direction], Unicode(),
        help="List of phase encoding directions of the input datasets. "
             "There can be N directions, with N either :\n"
             "   - 1 : the same direction will apply to all datasets\n"
             "   - N : one direction per dataset, applied to all slices"
    ).tag(config=True, required=True)

    slice_direction = ChoiceList(
        [d.name for d in Direction], Unicode(),
        help="List of acquisition directions of the input datasets. There can "
             "be N directions, with N either :\n"
             "   - 1 : the same direction will apply to all datasets\n"
             "   - N : one direction per dataset, applied to all slices"
    ).tag(config=True)

    readout = Float(help="Acquisition readout time (in ms)").tag(
        config=True, required=True
    )

    gslider_factor = Integer(None, allow_none=True).tag(config=True)

    multiband_factor = Integer(1, allow_none=True).tag(config=True)

    interleaved = Bool(
        None, allow_none=True,
        help="If True, will output interleaved "
             "slices in the multiband index definition"
    ).tag(config=True)

    slice_indexes = List(
        List(Integer()), None, allow_none=True
    ).tag(config=True)

    multiband_corrected = Bool(
        False, allow_none=True,
        help="Specifies if the dataset has been corrected "
             "for iter-slice and slice-to-vol motion"
    ).tag(config=True)

    tensor_valued = Bool(
        None, allow_none=True, help="Dataset acquisition is tensor-valued"
    ).tag(config=True)

    acquisition = convert_enum(
        AcquisitionType, None, allow_none=True
    ).tag(config=True)

    number_of_coils = Integer(
        0, help="Number of coils used for the image acquisition"
    )

    def _validate(self):
        pass

    def serialize(self, *args, **kwargs):
        pass


import numpy as np
import matplotlib
import matplotlib.pyplot as plt
from keras.models import Sequential
from keras.optimizers import Adam
from keras.callbacks import ModelCheckpoint
from keras.models import load_model
from keras.layers import Lambda,Conv2D,MaxPooling2D,Dropout,Dense,Flatten,Activation

from helper import get_class_names,get_train_data,get_test_data,plot_images,plot_model

matplotlib.style.use('ggplot')

#import class names
class_names = get_class_names()
#print(class_names)
num_classes = len(class_names)
#print(num_classes)

#height and width of the images
IMAGE_SIZE=32
#3 channels RGB
CHANNELS = 3

#Fetch and decode Data
#Load the training dataset, labels are integers whereas class is one-hot vectors

images_train, labels_train, class_train = get_train_data()
#print('Labels_Train: ',labels_train)
#print('Class_Train: ',class_train)

images_test, labels_test, class_test = get_test_data()
#print('Training set size:\t',len(images_train))
#print('Testing set size:\t',len(images_test))

def cnn_model():
    model = Sequential()

    model.add(Conv2D(32,(3,3), activation='relu', padding='same', input_shape=(IMAGE_SIZE,IMAGE_SIZE,CHANNELS)))
    model.add(Conv2D(32,(3,3), activation='relu'))
    model.add(MaxPooling2D(pool_size=(2,2)))
    model.add(Dropout(0.25))

    model.add(Conv2D(64,(3,3), activation='relu', padding='same'))
    model.add(Conv2D(64,(3,3), activation='relu'))
    model.add(MaxPooling2D(pool_size=(2,2)))
    model.add(Dropout(0.25))

    model.add(Flatten())

    model.add(Dense(512, activation='relu'))
    model.add(Dropout(0.5))

    model.add(Dense(num_classes, activation='softmax'))
    model.save('cifar10_cnn_model')

    model.summary()

    return model

model = cnn_model()
#print(model)

checkpoint = ModelCheckpoint('best_model_simple.h5', #model filename
                            monitor='val_loss', #quantity to monitor
                            verbose=0,#verbosity = 0 or 1
                            save_best_only=True,#The latest best model will not be overwritten
                            mode='auto')#The decision to overwrite model is made)
                                    #automatically depending on the quantity to monitor

model.compile(loss='categorical_crossentropy',#Better loss function for neural networs
            optimizer=Adam(lr=1.0e-4),#Adam optimizer with 1.0e-4 learning rate
            metrics=['accuracy'])#Metrics to be evaluted by model

model_details = model.fit(images_train,class_train,
                          batch_size=128,#number of sample per gradient update
                          epochs=10,#number of iterations
                          validation_data=(images_test,class_test),
                          callbacks=[checkpoint],
                          verbose=1)
#print(model_details)

scores = model.evaluate(images_test,class_test,verbose=0)
#print('Accuracy: %.2f%%'%(scores[1]*100))

#plot_model(model_details)

class_pred = model.predict(images_test,batch_size=32)
#print(class_pred[0])

labels_pred = np.argmax(class_pred,axis=1)
#print(labels_pred)

correct = (labels_pred==labels_test)
#print(correct)
#print('Number of currect prediction: %d'%sum(correct))

num_images = len(correct)
#print('Accurecy: %.2f%%'%((sum(currect)*100)/num_images))

incorrect = (correct == False)
#Images of the test-set that have been incorrectly classified.
images_error = images_test[incorrect]
#Get predicted classes for those images
labels_error = labels_pred[incorrect]
#Get true classes for those images.
labels_true = labels_test[incorrect]

prediction = model.predict(images_test)

def plot_images(i,prediction_array,true_label,img):
	prediction_array, true_label, img = prediction_array[i], true_label[i], img[i]
	plt.xticks([])
	plt.yticks([])
	plt.imshow(img, cmap = plt.cm.binary)
	predicted_label = np.argmax(prediction_array)
	if predicted_label == true_label:
		color = 'blue'
	else:
		color = 'red'

	plt.xlabel('{} {:2.0f}% ({})'.format(class_names[predicted_label],
				    100*np.max(prediction_array),
				    class_names[true_label],
                                    color = color))

def plot_value_array(i,prediction_array,true_label):
	prediction_array, true_label = prediction_array[i], true_label[i]
	plt.xticks([])
	plt.yticks([])
	thisplot = plt.bar(range(10), prediction_array, color = '#777777' )
	plt.ylim([0,1])
	predicted_label = np.argmax(prediction_array)
	thisplot[predicted_label].set_color('red')
	thisplot[true_label].set_color('blue')

num_rows = 5
num_cols = 3
num_images = num_rows * num_cols
plt.figure(figsize=(2*2*num_cols,2*num_rows))
for i in range(num_images):
	plt.subplot(num_rows, num_cols*2, 2*i+1)
	plot_images(i,prediction,labels_test, images_test)
	plt.subplot(num_rows,num_cols*2, 2*i+2)
	plot_value_array(i,prediction,labels_test)
plt.show()

'''plot_images(images=images_error[0:9],
            labels_true=labels_true[0:9],
            class_names=class_names,
            labels_pred=labels_error[0:9])'''


from collections import deque
from contextlib import contextmanager
from typing import IO, ContextManager, Deque, Generator, List

from .search import find_sum_two

@contextmanager
def file_read(filename: str) -> Generator:
    f = open(filename)
    yield f
    f.close()

def process_list(numbers: List[int], n: int) -> int:
    """
    This function returns the first number in the list (after the preamble)
    which is not a sum of two of the X numbers before it.
    Uses the search function from day1
    """
    d: Deque[int] = deque(numbers[:n], maxlen=n)
    for number in numbers[n:]:
        if len(find_sum_two(list(d), number)) == 2:
            d.append(number)
        else:
            return number
    return -1

def break_encryption(numbers: List[int], n: int) -> int:
    """
    This function returns the sum of the smallest and largest
    number in a contiguous set of at least two numbers from the
    list that sum up to the number `n`.
    """
    # first try 2, then 3, then 4, and so on
    for i in range(2, len(numbers)):
        d: Deque[int] = deque(numbers[:i], maxlen=i)
        for j in numbers[i:]:
            if sum(d) == n:
                return min(d) + max(d)
            else:
                d.append(j)
    return -1

if __name__ == "__main__":
    cm: ContextManager[IO] = file_read("input")
    with cm as input_file:
        numbers: List[int] = [int(line) for line in input_file.read().splitlines()]
    # print(numbers)
    ans: int = process_list(numbers, 25)
    print(ans)
    index: int = numbers.index(ans)
    # only send it the part of the list until that number
    print(break_encryption(numbers[:index], ans))


# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import models, migrations

class Migration(migrations.Migration):

    dependencies = [
        ('tandem', '0006_tandemfile_project_name'),
    ]

    operations = [
        migrations.RemoveField(
            model_name='tandemfile',
            name='project_name',
        ),
        migrations.DeleteModel(
            name='Tandemfile',
        ),
    ]


#import time
import time
import logging
import random

#10 questions total
correct_answers = 0
noOfQuestions = 3
for question in range(noOfQuestions):      #testing only 3 cases for now
    num1 = random.randint(0, 9)
    num2 = random.randint(0, 9)

    chances = 3
    while chances>0:
        try:
            print('You have 8 seconds to answer - ')
            timeStart = time.time()
            answer = int(input((f'{num1}*{num2} = ')))
            endTime = time.time()
            if (endTime - timeStart) > 8:
                print('Out of time!')
                break

        except:
            print('Please enter an integer value')
            chances -= 1

        if answer == num1*num2:
            print('Correct!')
            correct_answers += 1
            break
        else:
            print('Incorrect!')
            chances -= 1
    else:
        print('Out of tries!')

print(f'Score - {correct_answers}/{noOfQuestions}')


#######################################
########### BATTLESHIP ################
#######################################
# A ship is randomly hidden in a board#
# The user must guess its location    #
# before they run out of turns        #
#######################################
#######################################

from random import randint

board=[]

for x in range(5):
    board.append(["O"] * 5)
#This function displays the board
def print_board(board):
    for row in board:
        print(" ".join(row))

print("\n Let's play Battleship!",print_board(board))

#These functions hide the "ship" inside the board we created
def random_row(board):
    return randint(0, len(board) - 1)

def random_col(board):
    return randint(0, len(board[0]) - 1)

ship_row = random_row(board)
ship_col = random_col(board)

#This "for" loop gives the player four turns to find the ship
for turn in range(4):
    guess_row=int(int(input("Guess Row: ")))
    guess_col=int(int(input("Guess Col: ")))

    if guess_row == ship_row and guess_col == ship_col:
        print("Congratulations! You sunk my battleship!")
        break
if (guess_row < 0 or guess_row > 4) or (guess_col < 0 or guess_col > 4):
    print
    "Oops, that's not even in the ocean."
elif (board[guess_row][guess_col] == "X"):
    print("You guessed that one already.")
else:
    print("You missed my battleship!")
    board[guess_row][guess_col] = "X"
print(turn + 1)
if turn == 3:
    print("Game Over")
    print_board(board)
    print("Turn", turn + 1)


import re
import shutil
import os
import subprocess
import itertools
import collections
import argparse
import multiprocessing

compilers = {
    'g++': (4.9, 6),
    'clang++': (3.6, 3.7, 3.8),
}

settings = {
    'osize': '-g -Os -fPIC',
    'o1':    '-g -O1',
    'o2':    '-g -O2',
    'o3':    '-g -O3',
    'o2n':   '-g -O2 -march=native',
    'o3n':   '-g -O3 -march=native',
}

config = collections.namedtuple('config', 'comp version name cxxflags')
def get_configs():
    versioned_comps = [(comp,v) for comp,versions in compilers.items() for v in versions]
    all_configs = itertools.product(versioned_comps, settings.items())
    return [config(c[0][0], c[0][1], c[1][0], c[1][1]) for c in all_configs]

root = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))

def _cmake_c(c):
    dirname = os.path.join(root, 'builds', c.comp, str(c.version), c.name)
    if not os.path.isdir(dirname):
        os.makedirs(dirname)

    cmake_cxxflags = '-DCMAKE_CXX_FLAGS=%s' % c.cxxflags
    cmake_cxx = '-DCMAKE_CXX_COMPILER=%s-%s' % (c.comp, str(c.version))
    subprocess.check_call(['rm', '-rf'], cwd=dirname)
    subprocess.check_call(['cmake', cmake_cxx, cmake_cxxflags, root], cwd=dirname)

def cmake(jobs):
    bdir = os.path.join(root, 'builds')
    if not os.path.isdir(bdir):
        os.mkdir(bdir)
    p = multiprocessing.Pool(jobs)
    p.map(_cmake_c, get_configs())
    p.close()

def _make_c(c):
    dirname = os.path.join(root, 'builds', c.comp, str(c.version), c.name)
    subprocess.check_call(['make'], cwd=dirname)

def make(jobs):
    p = multiprocessing.Pool(jobs)
    p.map(_make_c, get_configs())
    p.close()

_r = re.compile('Ran [0-9]+ iterations in [0-9\.]+ \[s\] \(([0-9\.]+) \[ms\] per iteration\)')
def benchmark(args=None):
    for c in get_configs():
        dirname = os.path.join('builds', c.comp, str(c.version), c.name)
        cmdline = ['./profit-cli']
        if args:
            cmdline += args
        else:
            cmdline += ['-w', '400', '-H', '400', ]
            cmdline += ['-p', 'sersic:xcen=201:ycen=201:mag=15.87:re=4.65:nser=4.7:ang=-21:axrat=0.74:box=0']
            cmdline += ['-p', 'sersic:xcen=201:ycen=201:mag=16.63:re=41:nser=1:axrat=0.29:box=0']
            cmdline += ['-i', '100']
        out = subprocess.check_output(cmdline, cwd=dirname).strip()
        ms_per_iter = _r.match(out).group(1)
        print('%s, %s, %s, %s' % (c.comp, str(c.version), c.name, ms_per_iter))

if __name__ == '__main__':

    parser = argparse.ArgumentParser(description="A tool to run commands through different builds")
    g = parser.add_mutually_exclusive_group(required=True)
    g.add_argument('-c', '--cmake', help="Runs CMake to prepare the build", action="store_true")
    g.add_argument('-m', '--make', help="Runs make in the builds", action="store_true")
    g.add_argument('-b', '--benchmark', help="Runs a benchmark in the builds. -j has no effect", action="store_true")
    parser.add_argument('-j', help="Numbers of jobs to run in parallel (processes)", type=int, dest="jobs", default=1)
    parser.add_argument('args', help="Arguments to use for benchmarking (optional)", nargs=argparse.REMAINDER)

    args = parser.parse_args()
    if args.cmake:
        cmake(args.jobs)
    if args.make:
        make(args.jobs)
    elif args.benchmark:
        # -- is there? it shouldn't...
        if len(args.args) > 0 and args.args[0] == '--':
            args.args = args.args[1:]
        benchmark(args.args)


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

"""
@Author: Yacan Man
@Email: myxc@live.cn
@Website: https://www.manyacan.com
@software: PyCharm
@file: main.py
@time: 2023/6/26 21:04
"""
import os
import time
import hues
import torch
import torchvision
from torch.utils.data import DataLoader
from torch.utils.tensorboard.writer import SummaryWriter
from torch.nn import Conv2d, MaxPool2d, Flatten, Linear, CrossEntropyLoss

# 数据路径
DATA_DIR = './data/'

# ToTensor
transformer = torchvision.transforms.Compose([
    torchvision.transforms.ToTensor()
])

# Train data and test data
train_data = torchvision.datasets.CIFAR10(
    root=DATA_DIR,
    transform=transformer,
    train=True,
    download=True
)

test_data = torchvision.datasets.CIFAR10(
    root=DATA_DIR,
    transform=transformer,
    train=False,
    download=True
)

# Data loader
train_loader = DataLoader(
    dataset=train_data,
    batch_size=64,
    shuffle=True,
    num_workers=2,
    drop_last=True
)

test_loader = DataLoader(
    dataset=test_data,
    batch_size=64,
    shuffle=True,
    num_workers=2,
    drop_last=True
)

# VGG Model
vgg_pretrained = torchvision.models.vgg16(weights=torchvision.models.VGG16_Weights.IMAGENET1K_V1)

# Training function
def train(dataloader, model, loss_fn, optimizer, lr_scheduler=None, verbose=True):
    size = len(dataloader.dataset)
    num_batches = len(dataloader)  # dataloader中的批量样本数
    model.train()
    train_loss, correct = 0, 0
    for batch, (X, y) in enumerate(dataloader):
        X, y = X.to(device), y.to(device)

        # Compute prediction error
        y_pred = model(X)
        loss = loss_fn(y_pred, y)
        train_loss += loss

        # Backpropagation
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
        if lr_scheduler:
            lr_scheduler.step()

        if verbose:
            if batch % 50 == 0:
                loss, current = loss.item(), batch * len(X)
                hues.info(f"Loss: {loss:>7f}  [{current:>5d}/{size:>5d}]")

        correct += (y_pred.argmax(1) == y).type(torch.float).sum().item()
    train_loss /= num_batches
    correct /= size
    return train_loss, correct

# Training function
def test(dataloader, model, loss_fn, verbose=True):
    size = len(dataloader.dataset)  # 样本总数
    num_batches = len(dataloader)  # dataloader中的批量样本数
    model.eval()
    test_loss, correct = 0, 0
    with torch.no_grad():
        for X, y in dataloader:
            X, y = X.to(device), y.to(device)
            y_pred = model(X)
            test_loss += loss_fn(y_pred, y).item()
            correct += (y_pred.argmax(1) == y).type(torch.float).sum().item()
    test_loss /= num_batches
    correct /= size
    if verbose:
        hues.info(f"Test Error: Accuracy: {(100 * correct):>0.1f}%, Avg loss: {test_loss:>8f} \n")
    return test_loss, correct  # For reporting tuning results/ early stopping

if __name__ == '__main__':
    hues.info(f'The length of train data is {len(train_data)}, the length of test data is {len(test_data)}.')

    # Finding device
    device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')

    # Building model
    model = vgg_pretrained
    model.classifier.add_module('Linear', torch.nn.Linear(1000, 10))
    model.to(device)
    hues.info(model)

    # Loss function
    loss_fun = CrossEntropyLoss()
    loss_fun.to(device)

    # Optimizer
    learning_rate = 0.0001
    optimizer = torch.optim.SGD(vgg_pretrained.parameters(), lr=learning_rate)
    # 学习率的衰减, 每经过5轮更新梯度，学习率衰减为原来的0.9
    scheduler = torch.optim.lr_scheduler.StepLR(optimizer, step_size=5, gamma=.9)

    # Using tensorboard to visualize network structure
    LOG_DIR = 'logs'
    if not os.path.exists(LOG_DIR):
        os.mkdir(LOG_DIR)
    writer = SummaryWriter(LOG_DIR)

    # Running model
    epochs = 300
    for i in range(epochs):
        print('+' * 25, f'Epoch {i}'.center(10), '+' * 25)
        train_loss, train_cor = train(train_loader, model, loss_fun, optimizer)
        scheduler.step()
        test_loss, test_cor = test(test_loader, model, loss_fun)
        writer.add_scalar('Loss/Train', train_loss, i)
        writer.add_scalar('Loss/Test', test_loss, i)
        writer.add_scalar('Accuracy/Train', train_cor, i)
        writer.add_scalar('Accuracy/Test', test_cor, i)
        writer.add_scalar('Learning Rate', optimizer.state_dict()["param_groups"][0]["lr"], i)

    hues.success("Done!")

    # Saving model
    timer = time.strftime('%Y-%m-%d_%H-%M-%S', time.localtime())
    MODEL_DIR = 'model'
    if not os.path.exists(MODEL_DIR):
        os.mkdir(MODEL_DIR)
    torch.save(model, f'{MODEL_DIR}/model_{timer}.pth')

    # Saving the structure of model
    demo_input = torch.ones(64, 3, 32, 32).to(device)  # batch_size=6, in_channels=3, height=28, weight=28.
    writer.add_graph(model, demo_input)

    writer.close()  # Closing writer
    # tensorboard --logdir='logs'


from __future__ import division

from datetime import date, datetime

from dateutil.relativedelta import relativedelta

from indico.core.db import db
from indico.modules.rb.models.locations import Location
from indico.modules.rb.models.reservation_occurrences import ReservationOccurrence
from indico.modules.rb.models.reservations import Reservation
from indico.util.date_time import iterdays

def calculate_rooms_bookable_time(rooms, start_date=None, end_date=None):
    if end_date is None:
        end_date = date.today() - relativedelta(days=1)
    if start_date is None:
        start_date = end_date - relativedelta(days=29)
    working_time_per_day = sum((datetime.combine(date.today(), end) - datetime.combine(date.today(), start)).seconds
                               for start, end in Location.working_time_periods)
    working_days = sum(1 for __ in iterdays(start_date, end_date, skip_weekends=True))
    return working_days * working_time_per_day * len(rooms)

def calculate_rooms_booked_time(rooms, start_date=None, end_date=None):
    if end_date is None:
        end_date = date.today() - relativedelta(days=1)
    if start_date is None:
        start_date = end_date - relativedelta(days=29)
    # Reservations on working days
    reservations = Reservation.find(Reservation.room_id.in_(r.id for r in rooms),
                                    db.extract('dow', ReservationOccurrence.start_dt).between(1, 5),
                                    ReservationOccurrence.start_dt >= start_date,
                                    ReservationOccurrence.end_dt <= end_date,
                                    ReservationOccurrence.is_valid,
                                    _join=ReservationOccurrence)

    rsv_start = db.cast(ReservationOccurrence.start_dt, db.TIME)
    rsv_end = db.cast(ReservationOccurrence.end_dt, db.TIME)
    slots = ((db.cast(start, db.TIME), db.cast(end, db.TIME)) for start, end in Location.working_time_periods)

    # this basically handles all possible ways an occurrence overlaps with each one of the working time slots
    overlaps = sum(db.case([
                ((rsv_start < start) & (rsv_end > end), db.extract('epoch', end - start)),
                ((rsv_start < start) & (rsv_end > start) & (rsv_end <= end), db.extract('epoch', rsv_end - start)),
                ((rsv_start >= start) & (rsv_start < end) & (rsv_end > end), db.extract('epoch', end - rsv_start)),
                ((rsv_start >= start) & (rsv_end <= end), db.extract('epoch', rsv_end - rsv_start))
            ], else_=0) for start, end in slots)

    return reservations.with_entities(db.func.sum(overlaps)).scalar() or 0

def calculate_rooms_occupancy(rooms, start=None, end=None):
    bookable_time = calculate_rooms_bookable_time(rooms, start, end)
    booked_time = calculate_rooms_booked_time(rooms, start, end)
    return booked_time / bookable_time if bookable_time else 0

def compose_rooms_stats(rooms):
    reservations = Reservation.find(Reservation.room_id.in_(r.id for r in rooms))
    return {
        'active': {
            'valid': reservations.filter(Reservation.is_valid, ~Reservation.is_archived).count(),
            'pending': reservations.filter(Reservation.is_pending, ~Reservation.is_archived).count(),
            'cancelled': reservations.filter(Reservation.is_cancelled, ~Reservation.is_archived).count(),
            'rejected': reservations.filter(Reservation.is_rejected, ~Reservation.is_archived).count(),
        },
        'archived': {
            'valid': reservations.filter(Reservation.is_valid, Reservation.is_archived).count(),
            'pending': reservations.filter(Reservation.is_pending, Reservation.is_archived).count(),
            'cancelled': reservations.filter(Reservation.is_cancelled, Reservation.is_archived).count(),
            'rejected': reservations.filter(Reservation.is_rejected, Reservation.is_archived).count()
        }
    }