diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..dfe0770 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +# Auto detect text files and perform LF normalization +* text=auto diff --git a/corporate_finances_back_py/--pycache--/app.cpython-311.pyc b/corporate_finances_back_py/--pycache--/app.cpython-311.pyc new file mode 100644 index 0000000..8676a5a Binary files /dev/null and b/corporate_finances_back_py/--pycache--/app.cpython-311.pyc differ diff --git a/corporate_finances_back_py/account-classification-from-current/decorators.py b/corporate_finances_back_py/account-classification-from-current/decorators.py new file mode 100644 index 0000000..071760a --- /dev/null +++ b/corporate_finances_back_py/account-classification-from-current/decorators.py @@ -0,0 +1,63 @@ +#version 2023 - 05 - 04 +import logging +import sys +import traceback +from functools import wraps +from time import time + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + +def handler_wrapper(start, satisfactory_log, error_log, raise_error): + #esto se ejecuta en la inicializacion de primero + def decorator(func): + #print(message1) + #lo que yo ponga acá se ejecuta antes de hacer el llamado a la funcion + @wraps(func) + def wrapper(*args, **kwargs): + #esto sí se ejecuta solo cuando llama a la funcion decorada + #print(message2) + try: + logger.info(f'[{func.__name__}] {start}...') + resultado = func(*args, **kwargs) + logger.info(f'[{func.__name__}] {satisfactory_log}') + return resultado + except Exception as e: + logger.error(f"[{func.__name__}] {error_log}, linea: {get_especific_error_line(func.__name__)}, motivo: {str(e)}") + raise Exception(f"{raise_error}") + + return wrapper + return decorator + +def debugger_wrapper(error_log, raise_error): + def decorator(func): + @wraps(func) + def wrapper(*args, **kwargs): + try: + resultado = func(*args, **kwargs) + return resultado + except Exception as e: + logger.error(f"[{func.__name__}] {error_log}, linea: {get_especific_error_line(func.__name__)}, motivo: {str(e)}") + raise Exception(f"{raise_error}") + return wrapper + return decorator + + +def get_especific_error_line(func_name): + _, _, exc_tb = sys.exc_info() + for trace in traceback.extract_tb(exc_tb): + if func_name in trace: + return str(trace[1]) + +def timing(f): + @wraps(f) + def wrap(*args, **kw): + ts = time() + result = f(*args, **kw) + te = time() + taken_time_message = '[timing] La funcion {}, toma: {:.2f} sec en ejecutarse'.format(f.__name__, te-ts) + logger.info(taken_time_message) + return result + return wrap + + diff --git a/corporate_finances_back_py/account-classification-from-current/lambda_function.py b/corporate_finances_back_py/account-classification-from-current/lambda_function.py new file mode 100644 index 0000000..68d5497 --- /dev/null +++ b/corporate_finances_back_py/account-classification-from-current/lambda_function.py @@ -0,0 +1,179 @@ + +import datetime +import json +import logging +from queue import Queue +from threading import Thread +import sys +from boto3 import client as boto3_client +import sqlalchemy +import traceback +import pandas as pd +import os +from decorators import handler_wrapper, timing +from utils import * + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + + + +def lambda_handler(event, context): + sc_obj = script_object(event) + return sc_obj.starter() + + +class script_object: + @handler_wrapper('inicializando objeto lambda','Objeto inicializado','Error tomando los valores de event','Problemas con los valores a calcular') + def __init__(self, event): + try: + logger.info('[__INIT__] Inicializando objeto lambda ...') + self.failed_init = False + logger.info(f'event de entrada: {str(event)}') + self.db_connection = 0 + self.final_response = {'headers':{'Access-Control-Allow-Headers': '*', 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Methods': '*'}} + + event_body_json = event["body"] + event_body_dict = json.loads(event_body_json) + self.nit = event_body_dict['nit'] + self.assessment_data = event_body_dict['assessment_data'] + self.id_assessment = self.assessment_data['ID'] + self.to_classify_short_date = event_body_dict['date'] + self.to_classify_long_date = datetime.datetime.strptime(event_body_dict['date'], '%d-%m-%Y').strftime('%Y-%m-%d %H:%M:%S') + + self.to_classify_periodicity = event_body_dict['periodicity'] + self.context = event_body_dict['context'] + + self.classifications_to_avoid_depurate = ["Depreciación del periodo", "Depreciación acumulada", "Propiedad, planta y equipo", "Intangibles", "Amortización acumulada", "Amortización del periodo"] + + self.user_classified_df = pd.core.frame.DataFrame() + self.default_classified_historic_df = pd.core.frame.DataFrame() + self.archive_id = int() + self.complete_classified_df = pd.core.frame.DataFrame() + self.df_original = pd.core.frame.DataFrame() + self.classification_summary_df = pd.core.frame.DataFrame() + + + except Exception as e: + self.failed_init = True + logger.error(f"[__INIT__] error en inicializacion, linea: {get_current_error_line()}, motivo: "+str(e)) + + + def starter(self): + try: + if self.failed_init: + raise AttributeError ('Error al inicializar lambda') + + self.create_conection_to_resources() + self.acquire_id_archive() + self.get_current_archive_clasification() + self.get_initialy_classified_data() + self.clasify_historic_data_with_current() + self.summary_builder_caller() + self.prepare_dataframe_to_front() + + self.db_connection.close() + logger.info(f'[lambda_handler] Tareas de lambda terminadas satisfactoriamente') + return self.response_maker(succesfull = True) + + except Exception as e: + if self.db_connection: + self.db_connection.close() + logger.error(f'[lambda_handler] Tareas de la lambda reportan errores fatales en el comando de la linea: {get_current_error_line()}, motivo: {str(e)}, creando respuesta...') + return self.response_maker(succesfull = False, exception_str = str(e)) + + + + @handler_wrapper('Creando conexion a bd','Conexion a bd creada con exito','Error en la conexion a bd','Problemas creando la conexion a bd') + def create_conection_to_resources(self): + db_schema = os.environ['DB_SCHEMA'] + secret_db_region = os.environ['SECRET_DB_REGION'] + secret_db_name = os.environ['SECRET_DB_NAME'] + db_secret = get_secret(secret_db_region, secret_db_name) + self.db_connection = connect_to_db(db_schema, db_secret) + + @handler_wrapper('obteniendo Id archive de este hilo', 'Id archive obtenido con exito', 'Error obteniendo id_Archive', 'Error obteniendo id del archive del presente hilo') + def acquire_id_archive(self): + query = f"SELECT B.ID FROM COMPANY A, ARCHIVE B WHERE A.ID = B.ID_COMPANY AND A.NIT = '{self.nit}' AND B.INITIAL_DATE = '{self.to_classify_long_date}' LIMIT 1" + logger.info(f"[acquire_id_archive] Query a base de datos para obtener el id_archive de este hilo {query}") + self.current_thread_id_archive = self.db_connection.execute(query).scalar() + + + @handler_wrapper('Buscando la clasificacion del analista','Clasificacion del analista encontrada','Error al buscar la clasificacion del analista','Error buscando la clasificacion del analista') + def get_current_archive_clasification(self): + query = f"SELECT A.CLASSIFICATION, B.ACCOUNT_NUMBER FROM RAW_CLASSIFICATION A, USER_CLASSIFICATION B WHERE A.ID = B.ID_RAW_CLASSIFICATION AND ID_ASSESSMENT = {self.assessment_data['ID']} ORDER BY ACCOUNT_NUMBER" + logger.info(f"[get_current_archive_clasification] Query a base de datos para obtener la clasificacion del usuario {query}") + self.user_classified_df = pd.read_sql(query, self.db_connection) + + + @handler_wrapper('Obteniendo la informacion chequeada del puc','Informacion de puc encontrada', 'Error al hacer query de los datos chequeados','Error al buscar los datos de puc') + def get_initialy_classified_data(self): + data = {'pathParameters' : {'id_assessment' : self.id_assessment, 'id_archive': self.current_thread_id_archive}} + logger.info(f'[]data que voy a lanzar a initial: {data}') + #logger.warning(f"[get_initialy_classified_data] body que va a initial_classified:\n{data}\nEn la url:\n'{self.api_address}fincor/pucs/processed/classification'") + data = json.dumps(data).encode() + lambda_client = boto3_client('lambda') + + lambda_slave_initial_classification = os.environ['LAMBDA_SLAVE_INITIAL_CLASSIFICATION'] + invoke_response = lambda_client.invoke(FunctionName = lambda_slave_initial_classification, + Payload=data) + + response_object = json.loads(json.loads(invoke_response['Payload'].read().decode())['body'])[0] + + del response_object['sector'] + dataframe_dict = response_object['data'] + + self.default_classified_historic_df = pd.DataFrame.from_records(dataframe_dict) + self.archive_id = response_object['archive_id'] + + + @handler_wrapper('Clasificando historico con actual','Data historica clasificada correctamente','Error al clasificar data historica','Error fatal al clasificar data historica') + def clasify_historic_data_with_current(self): + self.complete_classified_df = self.default_classified_historic_df.copy() + for classified_row in self.user_classified_df.itertuples(): + self.complete_classified_df.loc[self.complete_classified_df['account'].str.startswith(classified_row[2]), 'classification'] = classified_row[1] + + @handler_wrapper('Enviando a calculo y guardado de summary e items','Guardado de resultados exitoso','Error calculando y guardando datos', 'Error guardando resultados') + def summary_builder_caller(self): + data = {'full_records':self.complete_classified_df.to_dict('records'), 'assessment_id':self.assessment_data['ID'], 'archive_id': self.current_thread_id_archive} + logger.warning(f'[summary_builder_caller] body que va a builder:\n{data}') + + data = json.dumps({'body': json.dumps(data)}).encode() + lambda_client = boto3_client('lambda') + + lambda_slave_summary_builder = os.environ['LAMBDA_SLAVE_SUMMARY_BUILDER'] + invoke_response = lambda_client.invoke(FunctionName = lambda_slave_summary_builder, + Payload=data) + + response_object = json.loads(json.loads(invoke_response['Payload'].read().decode())['body']) + + + @handler_wrapper('Preparando dataframe para front','Dataframe preparado con exito','Error al preparar dataframe','Error fatal al preparar dataframe') + def prepare_dataframe_to_front(self): + to_front_df = self.complete_classified_df.copy() + to_front_df.fillna('No aplica', inplace=True) + to_front_df.sort_values(by=['account'], inplace=True) + to_front_df['nivel'] = to_front_df['account'].str.len() + + to_front_df['account2'] = to_front_df['account'] + to_front_df.set_index('account', inplace=True) + to_front_df.rename(columns={'account2': 'account','account_name':'name'},inplace=True) + logger.warning(f"Salida a front sin depurar y en records:\n{to_front_df.to_dict('records')}") + self.final_response['body'] = {self.to_classify_short_date : to_front_df.to_dict('index')} + + + def response_maker(self, succesfull = False, exception_str = str): + + if not succesfull: + self.final_response['body'] = json.dumps(exception_str) + return self.final_response + else: + self.final_response['body'] = json.dumps(self.final_response['body']) + return self.final_response + + + +def get_current_error_line(): + return str(sys.exc_info()[-1].tb_lineno) + + diff --git a/corporate_finances_back_py/account-classification-from-current/utils.py b/corporate_finances_back_py/account-classification-from-current/utils.py new file mode 100644 index 0000000..9efbdea --- /dev/null +++ b/corporate_finances_back_py/account-classification-from-current/utils.py @@ -0,0 +1,33 @@ +#version 2023 - 05 - 04 +import base64 +import boto3 +import json +import logging + +from sqlalchemy import create_engine + +from decorators import handler_wrapper, debugger_wrapper + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + + +@debugger_wrapper('Error al obtener secreto','Error fatal de back conectando a base de datos') +def get_secret(secret_region, secret_name): + session = boto3.session.Session() + client_secrets_manager = session.client(service_name='secretsmanager', region_name=secret_region) + secret_data = client_secrets_manager.get_secret_value(SecretId=secret_name) + if 'SecretString' in secret_data: + secret_str = secret_data['SecretString'] + else: + secret_str = base64.b64decode(secret_data['SecretBinary']) + logger.info('[utils] (get_secret) Se obtuvo el secreto') + return json.loads(secret_str) + + +@debugger_wrapper('Error en la conexion a base de datos','Error fatal de back conectando a base de datos') +def connect_to_db(db_schema, db_secret): + conn_string = ('mysql+mysqlconnector://' + db_secret["username"] + ':' + db_secret["password"] + '@' + db_secret["host"] + ':' + str(db_secret["port"]) + '/' + db_schema) + sql_engine = create_engine(conn_string) + db_connection = sql_engine.connect() + return db_connection \ No newline at end of file diff --git a/corporate_finances_back_py/app.log b/corporate_finances_back_py/app.log new file mode 100644 index 0000000..c8cd0b3 --- /dev/null +++ b/corporate_finances_back_py/app.log @@ -0,0 +1,219 @@ +WARNING:werkzeug: * Debugger is active! +INFO:werkzeug: * Debugger PIN: 738-130-175 +INFO:werkzeug:WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. + * Running on http://127.0.0.1:5000 +INFO:werkzeug:Press CTRL+C to quit +INFO:werkzeug: * Restarting with stat +WARNING:werkzeug: * Debugger is active! +INFO:werkzeug: * Debugger PIN: 738-130-175 +INFO:werkzeug:127.0.0.1 - - [12/Mar/2024 16:55:45] "GET /recovery/assessment/51 HTTP/1.1" 500 - +INFO:werkzeug:127.0.0.1 - - [12/Mar/2024 16:55:45] "GET /recovery/assessment/51?__debugger__=yes&cmd=resource&f=style.css HTTP/1.1" 304 - +INFO:werkzeug:127.0.0.1 - - [12/Mar/2024 16:55:45] "GET /recovery/assessment/51?__debugger__=yes&cmd=resource&f=debugger.js HTTP/1.1" 304 - +INFO:werkzeug:127.0.0.1 - - [12/Mar/2024 16:55:45] "GET /recovery/assessment/51?__debugger__=yes&cmd=resource&f=console.png HTTP/1.1" 304 - +INFO:werkzeug:127.0.0.1 - - [12/Mar/2024 16:55:45] "GET /recovery/assessment/51?__debugger__=yes&cmd=resource&f=console.png HTTP/1.1" 304 - +INFO:werkzeug: * Detected change in 'C:\\Users\\JeissonBotache\\OneDrive - PRECIA Proveedor de precios para valoracin S.A\\Documentos\\all lambdas MVP copia original\\new\\corporate_finances_back_py\\app.py', reloading +INFO:werkzeug: * Restarting with stat +WARNING:werkzeug: * Debugger is active! +INFO:werkzeug: * Debugger PIN: 738-130-175 +INFO:werkzeug:127.0.0.1 - - [12/Mar/2024 16:59:42] "GET /recovery/assessment/51 HTTP/1.1" 308 - +INFO:werkzeug:127.0.0.1 - - [12/Mar/2024 16:59:42] "GET /recovery/assessment/51/ HTTP/1.1" 500 - +INFO:werkzeug:127.0.0.1 - - [12/Mar/2024 16:59:42] "GET /recovery/assessment/51/?__debugger__=yes&cmd=resource&f=style.css HTTP/1.1" 200 - +INFO:werkzeug:127.0.0.1 - - [12/Mar/2024 16:59:42] "GET /recovery/assessment/51/?__debugger__=yes&cmd=resource&f=debugger.js HTTP/1.1" 200 - +INFO:werkzeug:127.0.0.1 - - [12/Mar/2024 16:59:42] "GET /recovery/assessment/51/?__debugger__=yes&cmd=resource&f=console.png HTTP/1.1" 200 - +INFO:werkzeug:127.0.0.1 - - [12/Mar/2024 16:59:42] "GET /recovery/assessment/51/?__debugger__=yes&cmd=resource&f=console.png HTTP/1.1" 304 - +INFO:werkzeug: * Detected change in 'C:\\Users\\JeissonBotache\\OneDrive - PRECIA Proveedor de precios para valoracin S.A\\Documentos\\all lambdas MVP copia original\\new\\corporate_finances_back_py\\app.py', reloading +INFO:werkzeug: * Restarting with stat +WARNING:werkzeug: * Debugger is active! +INFO:werkzeug: * Debugger PIN: 738-130-175 +INFO:werkzeug:127.0.0.1 - - [12/Mar/2024 17:01:25] "GET /recovery/assessment/51/ HTTP/1.1" 500 - +INFO:werkzeug:127.0.0.1 - - [12/Mar/2024 17:01:25] "GET /recovery/assessment/51/?__debugger__=yes&cmd=resource&f=debugger.js HTTP/1.1" 304 - +INFO:werkzeug:127.0.0.1 - - [12/Mar/2024 17:01:25] "GET /recovery/assessment/51/?__debugger__=yes&cmd=resource&f=style.css HTTP/1.1" 304 - +INFO:werkzeug:127.0.0.1 - - [12/Mar/2024 17:01:25] "GET /recovery/assessment/51/?__debugger__=yes&cmd=resource&f=console.png HTTP/1.1" 304 - +INFO:werkzeug:127.0.0.1 - - [12/Mar/2024 17:01:25] "GET /recovery/assessment/51/?__debugger__=yes&cmd=resource&f=console.png HTTP/1.1" 304 - +INFO:werkzeug:WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. + * Running on http://127.0.0.1:5000 +INFO:werkzeug:Press CTRL+C to quit +INFO:werkzeug: * Restarting with stat +WARNING:werkzeug: * Debugger is active! +INFO:werkzeug: * Debugger PIN: 738-130-175 +INFO:werkzeug:127.0.0.1 - - [13/Mar/2024 10:22:27] "GET / HTTP/1.1" 404 - +INFO:werkzeug:127.0.0.1 - - [13/Mar/2024 10:22:27] "GET /favicon.ico HTTP/1.1" 404 - +INFO:werkzeug:127.0.0.1 - - [13/Mar/2024 10:24:43] "GET /recovery/assessment/51/ HTTP/1.1" 500 - +INFO:werkzeug:127.0.0.1 - - [13/Mar/2024 10:24:43] "GET /recovery/assessment/51/?__debugger__=yes&cmd=resource&f=style.css HTTP/1.1" 304 - +INFO:werkzeug:127.0.0.1 - - [13/Mar/2024 10:24:43] "GET /recovery/assessment/51/?__debugger__=yes&cmd=resource&f=debugger.js HTTP/1.1" 304 - +INFO:werkzeug:127.0.0.1 - - [13/Mar/2024 10:24:43] "GET /recovery/assessment/51/?__debugger__=yes&cmd=resource&f=console.png HTTP/1.1" 304 - +INFO:werkzeug:127.0.0.1 - - [13/Mar/2024 10:24:43] "GET /recovery/assessment/51/?__debugger__=yes&cmd=resource&f=console.png HTTP/1.1" 304 - +INFO:werkzeug: * Detected change in 'C:\\Users\\JeissonBotache\\OneDrive - PRECIA Proveedor de precios para valoracin S.A\\Documentos\\all lambdas MVP copia original\\new\\corporate_finances_back_py\\assessment_retrieve\\lambda_function.py', reloading +INFO:werkzeug: * Restarting with stat +WARNING:werkzeug: * Debugger is active! +INFO:werkzeug: * Debugger PIN: 738-130-175 +INFO:werkzeug: * Detected change in 'C:\\Users\\JeissonBotache\\OneDrive - PRECIA Proveedor de precios para valoracin S.A\\Documentos\\all lambdas MVP copia original\\new\\corporate_finances_back_py\\assessment_retrieve\\lambda_function.py', reloading +INFO:werkzeug: * Restarting with stat +WARNING:werkzeug: * Debugger is active! +INFO:werkzeug: * Debugger PIN: 738-130-175 +INFO:werkzeug:127.0.0.1 - - [13/Mar/2024 10:25:47] "GET /recovery/assessment/51/ HTTP/1.1" 500 - +INFO:werkzeug:127.0.0.1 - - [13/Mar/2024 10:25:47] "GET /recovery/assessment/51/?__debugger__=yes&cmd=resource&f=style.css HTTP/1.1" 304 - +INFO:werkzeug:127.0.0.1 - - [13/Mar/2024 10:25:47] "GET /recovery/assessment/51/?__debugger__=yes&cmd=resource&f=debugger.js HTTP/1.1" 304 - +INFO:werkzeug:127.0.0.1 - - [13/Mar/2024 10:25:47] "GET /recovery/assessment/51/?__debugger__=yes&cmd=resource&f=console.png HTTP/1.1" 304 - +INFO:werkzeug:127.0.0.1 - - [13/Mar/2024 10:25:47] "GET /recovery/assessment/51/?__debugger__=yes&cmd=resource&f=console.png HTTP/1.1" 304 - +INFO:werkzeug: * Detected change in 'C:\\Users\\JeissonBotache\\OneDrive - PRECIA Proveedor de precios para valoracin S.A\\Documentos\\all lambdas MVP copia original\\new\\corporate_finances_back_py\\assessment_retrieve\\lambda_function.py', reloading +INFO:werkzeug: * Restarting with stat +WARNING:werkzeug: * Debugger is active! +INFO:werkzeug: * Debugger PIN: 738-130-175 +INFO:werkzeug:127.0.0.1 - - [13/Mar/2024 10:28:12] "GET /recovery/assessment/51/ HTTP/1.1" 500 - +INFO:werkzeug:127.0.0.1 - - [13/Mar/2024 10:28:12] "GET /recovery/assessment/51/?__debugger__=yes&cmd=resource&f=style.css HTTP/1.1" 304 - +INFO:werkzeug:127.0.0.1 - - [13/Mar/2024 10:28:12] "GET /recovery/assessment/51/?__debugger__=yes&cmd=resource&f=debugger.js HTTP/1.1" 304 - +INFO:werkzeug:127.0.0.1 - - [13/Mar/2024 10:28:12] "GET /recovery/assessment/51/?__debugger__=yes&cmd=resource&f=console.png HTTP/1.1" 304 - +INFO:werkzeug:127.0.0.1 - - [13/Mar/2024 10:28:12] "GET /recovery/assessment/51/?__debugger__=yes&cmd=resource&f=console.png HTTP/1.1" 304 - +INFO:werkzeug: * Detected change in 'C:\\Users\\JeissonBotache\\OneDrive - PRECIA Proveedor de precios para valoracin S.A\\Documentos\\all lambdas MVP copia original\\new\\corporate_finances_back_py\\assessment_retrieve\\lambda_function.py', reloading +INFO:werkzeug: * Restarting with stat +WARNING:werkzeug: * Debugger is active! +INFO:werkzeug: * Debugger PIN: 738-130-175 +INFO:werkzeug:127.0.0.1 - - [13/Mar/2024 10:28:46] "GET /recovery/assessment/51/ HTTP/1.1" 500 - +INFO:werkzeug:127.0.0.1 - - [13/Mar/2024 10:28:46] "GET /recovery/assessment/51/?__debugger__=yes&cmd=resource&f=style.css HTTP/1.1" 304 - +INFO:werkzeug:127.0.0.1 - - [13/Mar/2024 10:28:46] "GET /recovery/assessment/51/?__debugger__=yes&cmd=resource&f=debugger.js HTTP/1.1" 304 - +INFO:werkzeug:127.0.0.1 - - [13/Mar/2024 10:28:46] "GET /recovery/assessment/51/?__debugger__=yes&cmd=resource&f=console.png HTTP/1.1" 304 - +INFO:werkzeug:127.0.0.1 - - [13/Mar/2024 10:28:46] "GET /recovery/assessment/51/?__debugger__=yes&cmd=resource&f=console.png HTTP/1.1" 304 - +INFO:werkzeug:127.0.0.1 - - [13/Mar/2024 10:28:49] "GET /recovery/assessment/51/ HTTP/1.1" 500 - +INFO:werkzeug:127.0.0.1 - - [13/Mar/2024 10:28:49] "GET /recovery/assessment/51/?__debugger__=yes&cmd=resource&f=style.css HTTP/1.1" 304 - +INFO:werkzeug:127.0.0.1 - - [13/Mar/2024 10:28:49] "GET /recovery/assessment/51/?__debugger__=yes&cmd=resource&f=debugger.js HTTP/1.1" 304 - +INFO:werkzeug:127.0.0.1 - - [13/Mar/2024 10:28:49] "GET /recovery/assessment/51/?__debugger__=yes&cmd=resource&f=console.png HTTP/1.1" 304 - +INFO:werkzeug:127.0.0.1 - - [13/Mar/2024 10:28:49] "GET /recovery/assessment/51/?__debugger__=yes&cmd=resource&f=console.png HTTP/1.1" 304 - +INFO:werkzeug: * Detected change in 'C:\\Users\\JeissonBotache\\OneDrive - PRECIA Proveedor de precios para valoracin S.A\\Documentos\\all lambdas MVP copia original\\new\\corporate_finances_back_py\\company_assessments_info\\utils.py', reloading +INFO:werkzeug: * Restarting with stat +WARNING:werkzeug: * Debugger is active! +INFO:werkzeug: * Debugger PIN: 738-130-175 +INFO:werkzeug:WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. + * Running on http://127.0.0.1:5000 +INFO:werkzeug:Press CTRL+C to quit +INFO:werkzeug: * Restarting with stat +WARNING:werkzeug: * Debugger is active! +INFO:werkzeug: * Debugger PIN: 738-130-175 +INFO:werkzeug:WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. + * Running on http://127.0.0.1:5000 +INFO:werkzeug:Press CTRL+C to quit +INFO:werkzeug: * Restarting with stat +WARNING:werkzeug: * Debugger is active! +INFO:werkzeug: * Debugger PIN: 738-130-175 +INFO:werkzeug:127.0.0.1 - - [13/Mar/2024 17:29:03] "GET /recovery/assessment/2053 HTTP/1.1" 308 - +INFO:werkzeug:127.0.0.1 - - [13/Mar/2024 17:29:06] "GET /recovery/assessment/2053/ HTTP/1.1" 500 - +INFO:werkzeug:127.0.0.1 - - [13/Mar/2024 17:29:06] "GET /recovery/assessment/2053/?__debugger__=yes&cmd=resource&f=style.css HTTP/1.1" 200 - +INFO:werkzeug:127.0.0.1 - - [13/Mar/2024 17:29:06] "GET /recovery/assessment/2053/?__debugger__=yes&cmd=resource&f=debugger.js HTTP/1.1" 200 - +INFO:werkzeug:127.0.0.1 - - [13/Mar/2024 17:29:07] "GET /recovery/assessment/2053/?__debugger__=yes&cmd=resource&f=console.png HTTP/1.1" 200 - +INFO:werkzeug:127.0.0.1 - - [13/Mar/2024 17:29:07] "GET /recovery/assessment/2053/?__debugger__=yes&cmd=resource&f=console.png HTTP/1.1" 304 - +INFO:werkzeug: * Detected change in 'C:\\Users\\JeissonBotache\\OneDrive - PRECIA Proveedor de precios para valoracin S.A\\Documentos\\all lambdas MVP copia original\\new\\corporate_finances_back_py\\assessment_retrieve\\utils.py', reloading +INFO:werkzeug: * Restarting with stat +WARNING:werkzeug: * Debugger is active! +INFO:werkzeug: * Debugger PIN: 738-130-175 +INFO:werkzeug: * Restarting with stat +WARNING:werkzeug: * Debugger is active! +INFO:werkzeug: * Debugger PIN: 738-130-175 +INFO:werkzeug: * Restarting with stat +WARNING:werkzeug: * Debugger is active! +INFO:werkzeug: * Debugger PIN: 738-130-175 +INFO:werkzeug: * Restarting with stat +WARNING:werkzeug: * Debugger is active! +INFO:werkzeug: * Debugger PIN: 738-130-175 +INFO:werkzeug:WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. + * Running on http://127.0.0.1:5000 +INFO:werkzeug:Press CTRL+C to quit +INFO:werkzeug:WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. + * Running on http://127.0.0.1:5000 +INFO:werkzeug:Press CTRL+C to quit +INFO:werkzeug: * Restarting with stat +WARNING:werkzeug: * Debugger is active! +INFO:werkzeug: * Debugger PIN: 738-130-175 +INFO:werkzeug: * Detected change in 'C:\\Users\\JeissonBotache\\OneDrive - PRECIA Proveedor de precios para valoracin S.A\\Documentos\\all lambdas MVP copia original\\new\\corporate_finances_back_py\\folder_names.py', reloading +INFO:werkzeug: * Restarting with stat +WARNING:werkzeug: * Debugger is active! +INFO:werkzeug: * Debugger PIN: 738-130-175 +INFO:werkzeug: * Detected change in 'C:\\Users\\JeissonBotache\\OneDrive - PRECIA Proveedor de precios para valoracin S.A\\Documentos\\all lambdas MVP copia original\\new\\corporate_finances_back_py\\super_orchestrator\\_full_recurrence.py', reloading +INFO:werkzeug: * Restarting with stat +WARNING:werkzeug: * Debugger is active! +INFO:werkzeug: * Debugger PIN: 738-130-175 +INFO:werkzeug: * Detected change in 'C:\\Users\\JeissonBotache\\OneDrive - PRECIA Proveedor de precios para valoracin S.A\\Documentos\\all lambdas MVP copia original\\new\\corporate_finances_back_py\\super_orchestrator\\_full_recurrence.py', reloading +INFO:werkzeug: * Restarting with stat +WARNING:werkzeug: * Debugger is active! +INFO:werkzeug: * Debugger PIN: 738-130-175 +INFO:werkzeug: * Detected change in 'C:\\Users\\JeissonBotache\\OneDrive - PRECIA Proveedor de precios para valoracin S.A\\Documentos\\all lambdas MVP copia original\\new\\corporate_finances_back_py\\super_orchestrator\\lambda_function.py', reloading +INFO:werkzeug: * Restarting with stat +WARNING:werkzeug: * Debugger is active! +INFO:werkzeug: * Debugger PIN: 738-130-175 +INFO:werkzeug: * Detected change in 'C:\\Users\\JeissonBotache\\OneDrive - PRECIA Proveedor de precios para valoracin S.A\\Documentos\\all lambdas MVP copia original\\new\\corporate_finances_back_py\\super_orchestrator\\_full_recurrence.py', reloading +INFO:werkzeug: * Restarting with stat +WARNING:werkzeug: * Debugger is active! +INFO:werkzeug: * Debugger PIN: 738-130-175 +INFO:werkzeug: * Detected change in 'C:\\Users\\JeissonBotache\\OneDrive - PRECIA Proveedor de precios para valoracin S.A\\Documentos\\all lambdas MVP copia original\\new\\corporate_finances_back_py\\super_orchestrator\\lambda_function.py', reloading +INFO:werkzeug: * Restarting with stat +WARNING:werkzeug: * Debugger is active! +INFO:werkzeug: * Debugger PIN: 738-130-175 +INFO:werkzeug: * Detected change in 'C:\\Users\\JeissonBotache\\OneDrive - PRECIA Proveedor de precios para valoracin S.A\\Documentos\\all lambdas MVP copia original\\new\\corporate_finances_back_py\\super_orchestrator\\lambda_function.py', reloading +INFO:werkzeug: * Restarting with stat +WARNING:werkzeug: * Debugger is active! +INFO:werkzeug: * Debugger PIN: 738-130-175 +INFO:werkzeug: * Detected change in 'C:\\Users\\JeissonBotache\\OneDrive - PRECIA Proveedor de precios para valoracin S.A\\Documentos\\all lambdas MVP copia original\\new\\corporate_finances_back_py\\super_orchestrator\\lambda_function.py', reloading +INFO:werkzeug: * Restarting with stat +WARNING:werkzeug: * Debugger is active! +INFO:werkzeug: * Debugger PIN: 738-130-175 +INFO:werkzeug: * Detected change in 'C:\\Users\\JeissonBotache\\OneDrive - PRECIA Proveedor de precios para valoracin S.A\\Documentos\\all lambdas MVP copia original\\new\\corporate_finances_back_py\\super_orchestrator\\lambda_function.py', reloading +INFO:werkzeug: * Restarting with stat +WARNING:werkzeug: * Debugger is active! +INFO:werkzeug: * Debugger PIN: 738-130-175 +INFO:werkzeug:WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. + * Running on http://127.0.0.1:5000 +INFO:werkzeug:Press CTRL+C to quit +INFO:werkzeug: * Restarting with stat +WARNING:werkzeug: * Debugger is active! +INFO:werkzeug: * Debugger PIN: 738-130-175 +INFO:werkzeug:127.0.0.1 - - [20/Mar/2024 20:54:41] "GET / HTTP/1.1" 404 - +INFO:werkzeug:127.0.0.1 - - [20/Mar/2024 20:54:41] "GET /favicon.ico HTTP/1.1" 404 - +INFO:werkzeug:127.0.0.1 - - [20/Mar/2024 20:57:08] "GET /orchestrator/status/ HTTP/1.1" 404 - +INFO:werkzeug:127.0.0.1 - - [20/Mar/2024 20:57:13] "GET /orchestrator/status/47 HTTP/1.1" 500 - +INFO:werkzeug:127.0.0.1 - - [20/Mar/2024 20:57:14] "GET /orchestrator/status/47?__debugger__=yes&cmd=resource&f=style.css HTTP/1.1" 200 - +INFO:werkzeug:127.0.0.1 - - [20/Mar/2024 20:57:14] "GET /orchestrator/status/47?__debugger__=yes&cmd=resource&f=debugger.js HTTP/1.1" 200 - +INFO:werkzeug:127.0.0.1 - - [20/Mar/2024 20:57:14] "GET /orchestrator/status/47?__debugger__=yes&cmd=resource&f=console.png HTTP/1.1" 200 - +INFO:werkzeug:127.0.0.1 - - [20/Mar/2024 20:57:14] "GET /orchestrator/status/47?__debugger__=yes&cmd=resource&f=console.png HTTP/1.1" 304 - +INFO:werkzeug:127.0.0.1 - - [20/Mar/2024 21:00:05] "GET /recovery/assessment/47 HTTP/1.1" 308 - +INFO:werkzeug: * Restarting with stat +WARNING:werkzeug: * Debugger is active! +INFO:werkzeug: * Debugger PIN: 738-130-175 +INFO:werkzeug:127.0.0.1 - - [20/Mar/2024 21:07:28] "GET /recovery/capex/calculation/2060 HTTP/1.1" 500 - +INFO:werkzeug:127.0.0.1 - - [20/Mar/2024 21:07:29] "GET /recovery/capex/calculation/2060?__debugger__=yes&cmd=resource&f=style.css HTTP/1.1" 304 - +INFO:werkzeug:127.0.0.1 - - [20/Mar/2024 21:07:29] "GET /recovery/capex/calculation/2060?__debugger__=yes&cmd=resource&f=debugger.js HTTP/1.1" 304 - +INFO:werkzeug:127.0.0.1 - - [20/Mar/2024 21:07:29] "GET /recovery/capex/calculation/2060?__debugger__=yes&cmd=resource&f=console.png HTTP/1.1" 304 - +INFO:werkzeug:127.0.0.1 - - [20/Mar/2024 21:07:29] "GET /recovery/capex/calculation/2060?__debugger__=yes&cmd=resource&f=console.png HTTP/1.1" 304 - +INFO:werkzeug:127.0.0.1 - - [20/Mar/2024 21:08:19] "GET /assessment/classification/2060 HTTP/1.1" 500 - +INFO:werkzeug:127.0.0.1 - - [20/Mar/2024 21:08:19] "GET /assessment/classification/2060?__debugger__=yes&cmd=resource&f=style.css HTTP/1.1" 200 - +INFO:werkzeug:127.0.0.1 - - [20/Mar/2024 21:08:19] "GET /assessment/classification/2060?__debugger__=yes&cmd=resource&f=debugger.js HTTP/1.1" 200 - +INFO:werkzeug:127.0.0.1 - - [20/Mar/2024 21:08:19] "GET /assessment/classification/2060?__debugger__=yes&cmd=resource&f=console.png HTTP/1.1" 200 - +INFO:werkzeug:127.0.0.1 - - [20/Mar/2024 21:08:19] "GET /assessment/classification/2060?__debugger__=yes&cmd=resource&f=console.png HTTP/1.1" 304 - +INFO:werkzeug:127.0.0.1 - - [20/Mar/2024 21:08:52] "GET /orchestrator/status/2060 HTTP/1.1" 500 - +INFO:werkzeug:127.0.0.1 - - [20/Mar/2024 21:08:52] "GET /orchestrator/status/2060?__debugger__=yes&cmd=resource&f=style.css HTTP/1.1" 200 - +INFO:werkzeug:127.0.0.1 - - [20/Mar/2024 21:08:52] "GET /orchestrator/status/2060?__debugger__=yes&cmd=resource&f=debugger.js HTTP/1.1" 200 - +INFO:werkzeug:127.0.0.1 - - [20/Mar/2024 21:08:52] "GET /orchestrator/status/2060?__debugger__=yes&cmd=resource&f=console.png HTTP/1.1" 200 - +INFO:werkzeug:127.0.0.1 - - [20/Mar/2024 21:08:52] "GET /orchestrator/status/2060?__debugger__=yes&cmd=resource&f=console.png HTTP/1.1" 304 - +INFO:werkzeug:127.0.0.1 - - [20/Mar/2024 21:09:25] "GET /assessment/capex/assets/2060 HTTP/1.1" 500 - +INFO:werkzeug:127.0.0.1 - - [20/Mar/2024 21:09:25] "GET /assessment/capex/assets/2060?__debugger__=yes&cmd=resource&f=style.css HTTP/1.1" 200 - +INFO:werkzeug:127.0.0.1 - - [20/Mar/2024 21:09:25] "GET /assessment/capex/assets/2060?__debugger__=yes&cmd=resource&f=debugger.js HTTP/1.1" 200 - +INFO:werkzeug:127.0.0.1 - - [20/Mar/2024 21:09:25] "GET /assessment/capex/assets/2060?__debugger__=yes&cmd=resource&f=console.png HTTP/1.1" 200 - +INFO:werkzeug:127.0.0.1 - - [20/Mar/2024 21:09:25] "GET /assessment/capex/assets/2060?__debugger__=yes&cmd=resource&f=console.png HTTP/1.1" 304 - +INFO:werkzeug:127.0.0.1 - - [20/Mar/2024 21:11:59] "GET /companies/123456789-1 HTTP/1.1" 500 - +INFO:werkzeug:127.0.0.1 - - [20/Mar/2024 21:11:59] "GET /companies/123456789-1?__debugger__=yes&cmd=resource&f=style.css HTTP/1.1" 200 - +INFO:werkzeug:127.0.0.1 - - [20/Mar/2024 21:11:59] "GET /companies/123456789-1?__debugger__=yes&cmd=resource&f=debugger.js HTTP/1.1" 200 - +INFO:werkzeug:127.0.0.1 - - [20/Mar/2024 21:11:59] "GET /companies/123456789-1?__debugger__=yes&cmd=resource&f=console.png HTTP/1.1" 200 - +INFO:werkzeug:127.0.0.1 - - [20/Mar/2024 21:11:59] "GET /companies/123456789-1?__debugger__=yes&cmd=resource&f=console.png HTTP/1.1" 304 - +INFO:werkzeug:127.0.0.1 - - [20/Mar/2024 21:12:23] "GET /recovery/cash-flow/2060 HTTP/1.1" 500 - +INFO:werkzeug:127.0.0.1 - - [20/Mar/2024 21:12:23] "GET /recovery/cash-flow/2060?__debugger__=yes&cmd=resource&f=style.css HTTP/1.1" 200 - +INFO:werkzeug:127.0.0.1 - - [20/Mar/2024 21:12:23] "GET /recovery/cash-flow/2060?__debugger__=yes&cmd=resource&f=debugger.js HTTP/1.1" 200 - +INFO:werkzeug:127.0.0.1 - - [20/Mar/2024 21:12:23] "GET /recovery/cash-flow/2060?__debugger__=yes&cmd=resource&f=console.png HTTP/1.1" 200 - +INFO:werkzeug:127.0.0.1 - - [20/Mar/2024 21:12:23] "GET /recovery/cash-flow/2060?__debugger__=yes&cmd=resource&f=console.png HTTP/1.1" 304 - +INFO:werkzeug:127.0.0.1 - - [20/Mar/2024 21:14:21] "GET /recovery/capex/assets/2060 HTTP/1.1" 500 - +INFO:werkzeug:127.0.0.1 - - [20/Mar/2024 21:14:21] "GET /recovery/capex/assets/2060?__debugger__=yes&cmd=resource&f=style.css HTTP/1.1" 200 - +INFO:werkzeug:127.0.0.1 - - [20/Mar/2024 21:14:21] "GET /recovery/capex/assets/2060?__debugger__=yes&cmd=resource&f=debugger.js HTTP/1.1" 200 - +INFO:werkzeug:127.0.0.1 - - [20/Mar/2024 21:14:21] "GET /recovery/capex/assets/2060?__debugger__=yes&cmd=resource&f=console.png HTTP/1.1" 200 - +INFO:werkzeug:127.0.0.1 - - [20/Mar/2024 21:14:21] "GET /recovery/capex/assets/2060?__debugger__=yes&cmd=resource&f=console.png HTTP/1.1" 304 - +INFO:werkzeug:127.0.0.1 - - [20/Mar/2024 21:14:25] "GET /recovery/capex/assets/2060 HTTP/1.1" 500 - +INFO:werkzeug:127.0.0.1 - - [20/Mar/2024 21:14:25] "GET /recovery/capex/assets/2060?__debugger__=yes&cmd=resource&f=style.css HTTP/1.1" 304 - +INFO:werkzeug:127.0.0.1 - - [20/Mar/2024 21:14:25] "GET /recovery/capex/assets/2060?__debugger__=yes&cmd=resource&f=debugger.js HTTP/1.1" 304 - +INFO:werkzeug:127.0.0.1 - - [20/Mar/2024 21:14:25] "GET /recovery/capex/assets/2060?__debugger__=yes&cmd=resource&f=console.png HTTP/1.1" 304 - +INFO:werkzeug:127.0.0.1 - - [20/Mar/2024 21:14:25] "GET /recovery/capex/assets/2060?__debugger__=yes&cmd=resource&f=console.png HTTP/1.1" 304 - diff --git a/corporate_finances_back_py/app.py b/corporate_finances_back_py/app.py new file mode 100644 index 0000000..70c8511 --- /dev/null +++ b/corporate_finances_back_py/app.py @@ -0,0 +1,449 @@ +from flask import Flask, request +from flask_cors import CORS, cross_origin +import os +import sys +import logging + +cwd = os.getcwd() +app = Flask(__name__) +cors = CORS(app) +app.config['CORS_HEADERS'] = 'Content-Type' + + +logging.basicConfig(filename='app.log',level=logging.DEBUG) +handler = logging.FileHandler('app.log') # Log to a file +app.logger.addHandler(handler) +#################################### +@app.route('/assessment/pyg/projections-calculator', methods = ['POST']) +@cross_origin() +def pyg_projections_calculator(): + sys.path.insert(1, r'c:\Users\JeissonBotache\OneDrive - PRECIA Proveedor de precios para valoración S.A\Scripts 2024\0228 swagger to server\pyg_projections_calculator') + from pyg_projections_calculator.lambda_function import lambda_handler + event = request.query_string.decode() + response = lambda_handler(event, 'From_Flask') + return response + + +@app.route('/pucs/depurated/files', methods = ['POST']) +@cross_origin() +def multi_puc_depurate(): + sys.path.insert(2, r'c:\Users\JeissonBotache\OneDrive - PRECIA Proveedor de precios para valoración S.A\Scripts 2024\0228 swagger to server\multi_puc_depurate') + from multi_puc_depurate.lambda_function import lambda_handler + event = request.query_string.decode() + response = lambda_handler(event, 'From_Flask') + return response + + +@app.route('/assessment/assessment/database', methods = ['POST']) +@cross_origin() +def assessment_to_db(): + sys.path.insert(3, r'c:\Users\JeissonBotache\OneDrive - PRECIA Proveedor de precios para valoración S.A\Scripts 2024\0228 swagger to server\assessment_to_db') + from assessment_to_db.lambda_function import lambda_handler + event = request.query_string.decode() + response = lambda_handler(event, 'From_Flask') + return response + + +@app.route('/orchestrator/status/', methods = ['GET']) #TODO: Error de importaciones +@cross_origin() +def status_seeker(id_assessment): + sys.path.insert(4, r'c:\Users\JeissonBotache\OneDrive - PRECIA Proveedor de precios para valoración S.A\Scripts 2024\0228 swagger to server\status_seeker') + from status_seeker.lambda_function import lambda_handler + event = {"pathParameters":{"id_assessment": id_assessment}} + response = lambda_handler(event, 'From_Flask') + return response + + +@app.route('/recovery/assessment/', methods = ['GET']) #OK +@cross_origin() +def assessment_retrieve(id_assessment): + sys.path.insert(5, r'c:\Users\JeissonBotache\OneDrive - PRECIA Proveedor de precios para valoración S.A\Scripts 2024\0228 swagger to server\assessment_retrieve') + from assessment_retrieve.lambda_function import lambda_handler + event = {"pathParameters":{"id_assessment": id_assessment}} + response = lambda_handler(event, 'From_Flask') + return response + + +@app.route('/assessment/cash-flow/databases/basic-modal-windows', methods = ['POST']) +@cross_origin() +def modal_window_saver(): + sys.path.insert(6, r'c:\Users\JeissonBotache\OneDrive - PRECIA Proveedor de precios para valoración S.A\Scripts 2024\0228 swagger to server\modal_window_saver') + from modal_window_saver.lambda_function import lambda_handler + event = request.query_string.decode() + response = lambda_handler(event, 'From_Flask') + return response + + +@app.route('/assessment/pyg/implicit_growings', methods = ['POST']) +@cross_origin() +def implicit_growing(): + sys.path.insert(7, r'c:\Users\JeissonBotache\OneDrive - PRECIA Proveedor de precios para valoración S.A\Scripts 2024\0228 swagger to server\implicit_growing') + from implicit_growing.lambda_function import lambda_handler + event = request.query_string.decode() + response = lambda_handler(event, 'From_Flask') + return response + + +@app.route('/assessment/classification/', methods = ['GET']) #TODO: Error de importaciones +@cross_origin() +def initial_account_classification(id_assessment): + sys.path.insert(8, r'c:\Users\JeissonBotache\OneDrive - PRECIA Proveedor de precios para valoración S.A\Scripts 2024\0228 swagger to server\initial_account_classification') + from initial_account_classification.lambda_function import lambda_handler + event = {"pathParameters":{"id_assessment": id_assessment}} + response = lambda_handler(event, 'From_Flask') + return response + + +@app.route('/pucs/depurated/full-checks', methods = ['POST']) +@cross_origin() +def puc_checks(): + sys.path.insert(9, r'c:\Users\JeissonBotache\OneDrive - PRECIA Proveedor de precios para valoración S.A\Scripts 2024\0228 swagger to server\puc_checks') + from puc_checks.lambda_function import lambda_handler + event = request.query_string.decode() + response = lambda_handler(event, 'From_Flask') + return response + + +@app.route('/recovery/capex/calculation/', methods = ['GET']) #TODO: Error de importaciones +@cross_origin() +def capex_calculation_retrieve(id_assessment): + sys.path.insert(10, r'c:\Users\JeissonBotache\OneDrive - PRECIA Proveedor de precios para valoración S.A\Scripts 2024\0228 swagger to server\capex_calculation_retrieve') + from capex_calculation_retrieve.lambda_function import lambda_handler + event = {"pathParameters":{"id_assessment": id_assessment}} + response = lambda_handler(event, 'From_Flask') + return response + + +@app.route('/report', methods = ['GET']) #TODO: Error de importaciones +@cross_origin() +def assessment_report_update(): + sys.path.insert(11, r'c:\Users\JeissonBotache\OneDrive - PRECIA Proveedor de precios para valoración S.A\Scripts 2024\0228 swagger to server\assessment_report_update') + from assessment_report_update.lambda_function import lambda_handler + event = request.query_string.decode() + response = lambda_handler(event, 'From_Flask') + return response + + +@app.route('/assessment/capex/assets/', methods = ['GET']) #TODO: Error de importaciones +@cross_origin() +def capex_depreciation_items(id_assessment): + sys.path.insert(12, r'c:\Users\JeissonBotache\OneDrive - PRECIA Proveedor de precios para valoración S.A\Scripts 2024\0228 swagger to server\capex_depreciation_items') + from capex_depreciation_items.lambda_function import lambda_handler + event = {"pathParameters":{"id_assessment": id_assessment}} + response = lambda_handler(event, 'From_Flask') + return response + + +@app.route('/assessment/capex/assets', methods = ['POST']) +@cross_origin() +def capex_depreciation_items_to_db(): + sys.path.insert(13, r'c:\Users\JeissonBotache\OneDrive - PRECIA Proveedor de precios para valoración S.A\Scripts 2024\0228 swagger to server\capex_depreciation_items_to_db') + from capex_depreciation_items_to_db.lambda_function import lambda_handler + event = request.query_string.decode() + response = lambda_handler(event, 'From_Flask') + return response + + +@app.route('/assessment/capex/new_capex', methods = ['POST']) +@cross_origin() +def capex_calculation_to_db(): + sys.path.insert(14, r'c:\Users\JeissonBotache\OneDrive - PRECIA Proveedor de precios para valoración S.A\Scripts 2024\0228 swagger to server\capex_calculation_to_db') + from capex_calculation_to_db.lambda_function import lambda_handler + event = request.query_string.decode() + response = lambda_handler(event, 'From_Flask') + return response + + +@app.route('/assessment/classification/purged_results', methods = ['POST']) +@cross_origin() +def assessment_summary_builder(): + sys.path.insert(15, r'c:\Users\JeissonBotache\OneDrive - PRECIA Proveedor de precios para valoración S.A\Scripts 2024\0228 swagger to server\assessment_summary_builder') + from assessment_summary_builder.lambda_function import lambda_handler + event = request.query_string.decode() + response = lambda_handler(event, 'From_Flask') + return response + + +@app.route('/companies/', methods = ['GET']) #TODO: Error de importaciones +@cross_origin() +def companies_exists(nit): + sys.path.insert(16, r'c:\Users\JeissonBotache\OneDrive - PRECIA Proveedor de precios para valoración S.A\Scripts 2024\0228 swagger to server\companies_exists') + from companies_exists.lambda_function import lambda_handler + event = {"pathParameters":{"nit": nit}} + response = lambda_handler(event, 'From_Flask') + return response + + +@app.route('/recovery/cash-flow/', methods = ['GET']) #TODO: Error de importaciones +@cross_origin() +def cash_flow_retrieve(id_assessment): + sys.path.insert(17, r'c:\Users\JeissonBotache\OneDrive - PRECIA Proveedor de precios para valoración S.A\Scripts 2024\0228 swagger to server\cash_flow_retrieve') + from cash_flow_retrieve.lambda_function import lambda_handler + event = {"pathParameters":{"id_assessment": id_assessment}} + response = lambda_handler(event, 'From_Flask') + return response + + +@app.route('/companies', methods = ['GET', 'POST']) #TODO: revisar los casos de los dos metodos, va a tocar hacer un if request.method == 'POST':... +@cross_origin() +def company_assessments_info(): + sys.path.insert(19, r'c:\Users\JeissonBotache\OneDrive - PRECIA Proveedor de precios para valoración S.A\Scripts 2024\0228 swagger to server\company_assessments_info') + from company_assessments_info.lambda_function import lambda_handler + event = request.query_string.decode() + response = lambda_handler(event, 'From_Flask') + return response + + +@app.route('/recovery/capex/assets/', methods = ['GET']) #TODO: Error de importaciones +@cross_origin() +def capex_depreciation_items_retrieve(id_assessment): + sys.path.insert(20, r'c:\Users\JeissonBotache\OneDrive - PRECIA Proveedor de precios para valoración S.A\Scripts 2024\0228 swagger to server\capex_depreciation_items_retrieve') + from capex_depreciation_items_retrieve.lambda_function import lambda_handler + event = {"pathParameters":{"id_assessment": id_assessment}} + response = lambda_handler(event, 'From_Flask') + return response + + +@app.route('/recovery/classification/', methods = ['GET']) #OK +@cross_origin() +def classifications_retrieve(id_assessment): + sys.path.insert(21, r'c:\Users\JeissonBotache\OneDrive - PRECIA Proveedor de precios para valoración S.A\Scripts 2024\0228 swagger to server\classifications_retrieve') + from classifications_retrieve.lambda_function import lambda_handler + event = {"pathParameters":{"id_assessment": id_assessment}} + response = lambda_handler(event, 'From_Flask') + return response + + +@app.route('/pucs/client/data/', methods = ['GET']) #Candidato a depreciacion pero event ok +@cross_origin() +def companies_puc_archive_info(nit): + sys.path.insert(22, r'c:\Users\JeissonBotache\OneDrive - PRECIA Proveedor de precios para valoración S.A\Scripts 2024\0228 swagger to server\companies_puc_archive_info') + from companies_puc_archive_info.lambda_function import lambda_handler + event = {"pathParameters":{"nit": nit}} + response = lambda_handler(event, 'From_Flask') + return response + + +@app.route('/assessment/classification/user-classified-properties', methods = ['POST']) +@cross_origin() +def multi_account_classification(): + sys.path.insert(23, r'c:\Users\JeissonBotache\OneDrive - PRECIA Proveedor de precios para valoración S.A\Scripts 2024\0228 swagger to server\multi_account_classification') + from multi_account_classification.lambda_function import lambda_handler + event = request.query_string.decode() + response = lambda_handler(event, 'From_Flask') + return response + + +@app.route('/assessment/cash-flow/databases/finance-debt', methods = ['POST']) +@cross_origin() +def debt_saver(): + sys.path.insert(24, r'c:\Users\JeissonBotache\OneDrive - PRECIA Proveedor de precios para valoración S.A\Scripts 2024\0228 swagger to server\debt_saver') + from debt_saver.lambda_function import lambda_handler + event = request.query_string.decode() + response = lambda_handler(event, 'From_Flask') + return response + + +@app.route('/recovery/pyg/completed/', methods = ['GET']) #OK +@cross_origin() +def pyg_retrieve(id_assessment): + sys.path.insert(25, r'c:\Users\JeissonBotache\OneDrive - PRECIA Proveedor de precios para valoración S.A\Scripts 2024\0228 swagger to server\pyg_retrieve') + from pyg_retrieve.lambda_function import lambda_handler + event = {"pathParameters":{"id_assessment": id_assessment}} + response = lambda_handler(event, 'From_Flask') + return response + + +@app.route('/recovery/cash-flow/modal-window/projection', methods = ['GET']) #TODO: recrear event a objeto: {"queryStringParameters": {"context": "wk","id_assessment": "2028"}} +@cross_origin() +def modal_projections_retrieve(): + sys.path.insert(26, r'c:\Users\JeissonBotache\OneDrive - PRECIA Proveedor de precios para valoración S.A\Scripts 2024\0228 swagger to server\modal_projections_retrieve') + from modal_projections_retrieve.lambda_function import lambda_handler + event = request.query_string.decode() + response = lambda_handler(event, 'From_Flask') + return response + + +@app.route('/recovery/cash-flow/modal-window/summary', methods = ['GET']) #TODO: Error de importaciones +@cross_origin() +def modal_summary(): + sys.path.insert(27, r'c:\Users\JeissonBotache\OneDrive - PRECIA Proveedor de precios para valoración S.A\Scripts 2024\0228 swagger to server\modal_summary') + from modal_summary.lambda_function import lambda_handler + event = request.query_string.decode() + response = lambda_handler(event, 'From_Flask') + return response + + +@app.route('/assessment/classification/from-archive-clasifier', methods = ['POST']) +@cross_origin() +def account_classification_from_current(): + sys.path.insert(28, r'c:\Users\JeissonBotache\OneDrive - PRECIA Proveedor de precios para valoración S.A\Scripts 2024\0228 swagger to server\account_classification_from_current') + from account_classification_from_current.lambda_function import lambda_handler + event = request.query_string.decode() + response = lambda_handler(event, 'From_Flask') + return response + + +@app.route('/recurrence', methods = ['POST']) +@cross_origin() +def super_orchestrator(): + sys.path.insert(29, r'c:\Users\JeissonBotache\OneDrive - PRECIA Proveedor de precios para valoración S.A\Scripts 2024\0228 swagger to server\super_orchestrator') + from super_orchestrator.lambda_function import lambda_handler + event = request.query_string.decode() + response = lambda_handler(event, 'From_Flask') + return response + + +@app.route('/assessment/classification/skipped', methods = ['POST']) +@cross_origin() +def skipped_classifications_checker(): + sys.path.insert(30, r'c:\Users\JeissonBotache\OneDrive - PRECIA Proveedor de precios para valoración S.A\Scripts 2024\0228 swagger to server\skipped_classifications_checker') + from skipped_classifications_checker.lambda_function import lambda_handler + event = request.query_string.decode() + response = lambda_handler(event, 'From_Flask') + return response + + +@app.route('/model/catch-all', methods = ['POST']) +@cross_origin() +def full_model_saver(): + sys.path.insert(31, r'c:\Users\JeissonBotache\OneDrive - PRECIA Proveedor de precios para valoración S.A\Scripts 2024\0228 swagger to server\full_model_saver') + from full_model_saver.lambda_function import lambda_handler + event = request.query_string.decode() + response = lambda_handler(event, 'From_Flask') + return response + + +@app.route('/pucs/client/data/columns/', methods = ['GET']) #este está peligrosky, se supone que a esta area puedo acceder solo después de subir el archivo puc +@cross_origin() +def puc_columns_name(filename): + sys.path.insert(32, r'c:\Users\JeissonBotache\OneDrive - PRECIA Proveedor de precios para valoración S.A\Scripts 2024\0228 swagger to server\puc_columns_name') + from puc_columns_name.lambda_function import lambda_handler + event = {"pathParameters":{"filename": filename}} + response = lambda_handler(event, 'From_Flask') + return response + + +@app.route('/orchestrator', methods = ['GET']) #TODO, recrear event a objeto +@cross_origin() +def orchestrator(): + sys.path.insert(33, r'c:\Users\JeissonBotache\OneDrive - PRECIA Proveedor de precios para valoración S.A\Scripts 2024\0228 swagger to server\orchestrator') + from orchestrator.lambda_function import lambda_handler + event = request.query_string.decode() + response = lambda_handler(event, 'From_Flask') + return response + + +@app.route('/recovery/capex/summary/', methods = ['GET']) #TODO: error de importaciones +@cross_origin() +def capex_summary_retrieve(id_assessment): + sys.path.insert(34, r'c:\Users\JeissonBotache\OneDrive - PRECIA Proveedor de precios para valoración S.A\Scripts 2024\0228 swagger to server\capex_summary_retrieve') + from capex_summary_retrieve.lambda_function import lambda_handler + event = {"pathParameters":{"id_assessment": id_assessment}} + response = lambda_handler(event, 'From_Flask') + return response + + +@app.route('/assessment/cash-flow/projections_calculator', methods = ['POST']) +@cross_origin() +def cash_flow_projection_calculator(): + sys.path.insert(35, r'c:\Users\JeissonBotache\OneDrive - PRECIA Proveedor de precios para valoración S.A\Scripts 2024\0228 swagger to server\cash_flow_projection_calculator') + from cash_flow_projection_calculator.lambda_function import lambda_handler + event = request.query_string.decode() + response = lambda_handler(event, 'From_Flask') + return response + + +@app.route('/recovery/pyg/projections-only/', methods = ['GET']) #si error está devolviendo 0 +@cross_origin() +def pyg_projections_retrieve(id_assessment): + sys.path.insert(36, r'c:\Users\JeissonBotache\OneDrive - PRECIA Proveedor de precios para valoración S.A\Scripts 2024\0228 swagger to server\pyg_projections_retrieve') + from pyg_projections_retrieve.lambda_function import lambda_handler + event = {"pathParameters":{"id_assessment": id_assessment}} + response = lambda_handler(event, 'From_Flask') + return response + + +@app.route('/pucs/depurated/checks', methods = ['POST']) +@cross_origin() +def checker_to_db(): + sys.path.insert(37, r'c:\Users\JeissonBotache\OneDrive - PRECIA Proveedor de precios para valoración S.A\Scripts 2024\0228 swagger to server\checker_to_db') + from checker_to_db.lambda_function import lambda_handler + event = request.query_string.decode() + response = lambda_handler(event, 'From_Flask') + return response + + +@app.route('/recovery/cash-flow/debt/properties/', methods = ['GET']) #TODO error de importacion +@cross_origin() +def debt_retrieve(id_assessment): + sys.path.insert(38, r'c:\Users\JeissonBotache\OneDrive - PRECIA Proveedor de precios para valoración S.A\Scripts 2024\0228 swagger to server\debt_retrieve') + from debt_retrieve.lambda_function import lambda_handler + event = {"pathParameters":{"id_assessment": id_assessment}} + response = lambda_handler(event, 'From_Flask') + return response + + +@app.route('/classifications', methods = ['GET']) #TODO: no sé que le falla, al parecer necesitaba un query en la url +@cross_origin() +def classifications(): + sys.path.insert(39, r'c:\Users\JeissonBotache\OneDrive - PRECIA Proveedor de precios para valoración S.A\Scripts 2024\0228 swagger to server\classifications') + from classifications.lambda_function import lambda_handler + event = request.query_string.decode() + response = lambda_handler(event, 'From_Flask') + return response + + +@app.route('/recovery/cash-flow/debt/amortization/', methods = ['GET']) #TODO: ERROR de imporacion +@cross_origin() +def debt_amortize(id_assessment): + sys.path.insert(40, r'c:\Users\JeissonBotache\OneDrive - PRECIA Proveedor de precios para valoración S.A\Scripts 2024\0228 swagger to server\debt_amortize') + from debt_amortize.lambda_function import lambda_handler + event = {"pathParameters":{"id_assessment": id_assessment}} + response = lambda_handler(event, 'From_Flask') + return response + + +@app.route('/assessment/cash-flow/modal-windows/pool', methods = ['GET']) #TODO: acomodar query a event +@cross_origin() +def cash_flow_modal_pool(): + sys.path.insert(41, r'c:\Users\JeissonBotache\OneDrive - PRECIA Proveedor de precios para valoración S.A\Scripts 2024\0228 swagger to server\cash_flow_modal_pool') + from cash_flow_modal_pool.lambda_function import lambda_handler + event = request.query_string.decode() + response = lambda_handler(event, 'From_Flask') + return response + + + + + +############################################### +@app.route("/path//", methods = ['GET']) +def path_testing(id_assessment): + #http://127.0.0.1:5000/testing/heloo + sys.path.insert(1, f'{cwd}\testing') + from testing.lambda_function import lambda_handler + event = id_assessment #TODO: este event se tiene que mandar como query string parameters + response = lambda_handler(event, 'From_Flask') + return response + + +@app.route("/query", methods = ['GET']) +def query_testing(): + #http://127.0.0.1:5000/testing?heloo + sys.path.insert(2, f'{cwd}\testing') + from testing.lambda_function import lambda_handler + event = request.query_string.decode() #TODO: este event se tiene que mandar como query string parameters + response = lambda_handler(event, 'From_Flask') + return response + + +@app.route("/posting", methods = ['POST']) +def post_testing(): + #http://127.0.0.1:5000/posting + sys.path.insert(3, f'{cwd}\testing') + from testing.lambda_function import lambda_handler + event = request.get_json() + response = lambda_handler(event, 'From_Flask') + return response + diff --git a/corporate_finances_back_py/assessment-report-update/decorators.py b/corporate_finances_back_py/assessment-report-update/decorators.py new file mode 100644 index 0000000..071760a --- /dev/null +++ b/corporate_finances_back_py/assessment-report-update/decorators.py @@ -0,0 +1,63 @@ +#version 2023 - 05 - 04 +import logging +import sys +import traceback +from functools import wraps +from time import time + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + +def handler_wrapper(start, satisfactory_log, error_log, raise_error): + #esto se ejecuta en la inicializacion de primero + def decorator(func): + #print(message1) + #lo que yo ponga acá se ejecuta antes de hacer el llamado a la funcion + @wraps(func) + def wrapper(*args, **kwargs): + #esto sí se ejecuta solo cuando llama a la funcion decorada + #print(message2) + try: + logger.info(f'[{func.__name__}] {start}...') + resultado = func(*args, **kwargs) + logger.info(f'[{func.__name__}] {satisfactory_log}') + return resultado + except Exception as e: + logger.error(f"[{func.__name__}] {error_log}, linea: {get_especific_error_line(func.__name__)}, motivo: {str(e)}") + raise Exception(f"{raise_error}") + + return wrapper + return decorator + +def debugger_wrapper(error_log, raise_error): + def decorator(func): + @wraps(func) + def wrapper(*args, **kwargs): + try: + resultado = func(*args, **kwargs) + return resultado + except Exception as e: + logger.error(f"[{func.__name__}] {error_log}, linea: {get_especific_error_line(func.__name__)}, motivo: {str(e)}") + raise Exception(f"{raise_error}") + return wrapper + return decorator + + +def get_especific_error_line(func_name): + _, _, exc_tb = sys.exc_info() + for trace in traceback.extract_tb(exc_tb): + if func_name in trace: + return str(trace[1]) + +def timing(f): + @wraps(f) + def wrap(*args, **kw): + ts = time() + result = f(*args, **kw) + te = time() + taken_time_message = '[timing] La funcion {}, toma: {:.2f} sec en ejecutarse'.format(f.__name__, te-ts) + logger.info(taken_time_message) + return result + return wrap + + diff --git a/corporate_finances_back_py/assessment-report-update/lambda_function.py b/corporate_finances_back_py/assessment-report-update/lambda_function.py new file mode 100644 index 0000000..28b8f8b --- /dev/null +++ b/corporate_finances_back_py/assessment-report-update/lambda_function.py @@ -0,0 +1,320 @@ +import os +import datetime +import pandas as pd +import json +import io +import boto3 +import base64 +import sys +import logging +import xlsxwriter +from vars import queries, pyg_order, cash_flow_order +from decorators import handler_wrapper, timing, debugger_wrapper +from utils import get_secret, connect_to_db +from sqlalchemy import text + +#logging.basicConfig() #En lambdas borra este + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + + +def lambda_handler(event,context): + sc_obj = script_object(event) + lambda_response = sc_obj.starter() + logger.info(f'respuesta final de lambda: \n{lambda_response}') + return lambda_response + + +class script_object: + def __init__(self, event): + try: + self.failed_init = False + self.final_response = {'headers':{'Access-Control-Allow-Headers': '*', + 'Access-Control-Allow-Origin': '*', + 'Access-Control-Allow-Methods': '*'}, "statusCode": 500, 'body': {}} + self.db_connection = 0 + self.detailed_raise = '' + self.partial_response = list() + + logger.warning(f'event de entrada: {str(event)}') + + self.assessment_date = event["queryStringParameters"]["date"] + self.assessment_date_long = datetime.datetime.strptime(self.assessment_date, "%d-%m-%Y").strftime('%Y-%m-%d %H:%M:%S') + self.nit = event["queryStringParameters"]["nit"] + self.periodicity = event["queryStringParameters"]["periodicity"] + self.user = event["queryStringParameters"]["user"] + self.context_directory = {'wk': 'CAPITAL DE TRABAJO', 'patrimony': 'PATRIMONIO', 'other_projections': 'OTRAS PROYECCIONES'} + self.pyg_directory_order = {item:order for item, order in zip(pyg_order, range(len(pyg_order)))} + self.cash_flow_directory_order = {item:order for item, order in zip(cash_flow_order, range(len(cash_flow_order)))} + self.output = io.BytesIO() + self.writer = pd.ExcelWriter(self.output, engine='xlsxwriter') + self.id_assessment = int() + self.all_tables_dfs = dict() + self.exit_dataframes = dict() + self.assets_results = dict() + self.signed_url = False + + + except Exception as e: + logger.error(f'[__init__] Error inicializando objeto lambda, linea: {get_current_error_line()}, motivo: {str(e)}') + self.failed_init = True + + def starter(self): + try: + if self.failed_init: + raise AttributeError('Error con los datos recibidos al servicio') + self.create_conection_to_db() + self.get_assessment_id() + self.acquire_model_atributtes() + self.create_classification_table() + self.create_pyg_Table() + self.create_capex_table() + self.create_cash_flow_table() + self.create_debt_table() + for context, sheet_name in self.context_directory.items(): + self.create_modal_window_table(context, sheet_name) + self.create_excel_file() + self.save_to_s3() + self.generate_presigned_url() + self.create_response() + + + return self.response_maker(succesfull_run = True) + + except Exception as e: + logger.error(f'[starter] Hubieron problemas en el comando de la linea: {get_current_error_line()}') + return self.response_maker(succesfull_run = False, error_str = (str(e))) + + @handler_wrapper('Creando conexion a bd','Conexion a bd creada con exito','Error en la conexion a bd','Problemas creando la conexion a bd') + def create_conection_to_db(self): + db_schema = os.environ['DB_SCHEMA'] + secret_db_region = os.environ['SECRET_DB_REGION'] + secret_db_name = os.environ['SECRET_DB_NAME'] + db_secret = get_secret(secret_db_region, secret_db_name) + self.db_connection = connect_to_db(db_schema, db_secret) + + + @handler_wrapper('Obteniendo el id del proceso de valoración', 'Id del proceso de valoración obtenido con exito', 'Error obteniendo el id de assessment', 'Error adquiriendo identificador de assessment') + def get_assessment_id(self): + query = f"""SELECT C.ID FROM COMPANY A, ARCHIVE B, ASSESSMENT C WHERE A.ID = B.ID_COMPANY AND B.ID = C.ID_ARCHIVE + AND A.NIT = "{self.nit}" AND B.INITIAL_DATE = "{self.assessment_date_long}" AND B.PERIODICITY = '{self.periodicity}' AND C.USER = '{self.user}'""" + logger.info(f'[get_assessment_id] Query para buscar el id_Assessment:\n{query}') + rds_data = self.db_connection.execute(text(query)) + self.id_assessment = rds_data.scalar() + logger.info(f'[get_assessment_id] Assessment encontrado: {self.id_assessment}') + + + @handler_wrapper('Adquiriendo atributos de modelo del proceso de valoración', 'Atributos modelo adquiridos exitosamente', 'Error adquiriendo atributos del modelo de valoración', 'Error adquiriendo modelos') + def acquire_model_atributtes(self): + for query_name, query in queries.items(): + q = query.format(self.id_assessment) + logger.info(f'[acquire_model_atributtes] Query para traer información de la tabla {query_name}:\n{q}') + self.all_tables_dfs[query_name] = pd.read_sql(q, self.db_connection) + self.all_tables_dfs[query_name].drop(columns=['ID_ASSESSMENT'], errors = 'ignore', inplace = True) + + + @handler_wrapper('Emergiendo las información requeridas', 'Información adquirida emergida con exito', 'Error emergiendo información de assessment adquirida', 'Error emergiendo información requerida') + def create_classification_table(self): + id_clasification_dict = {row[1]['ID']:row[1]['CLASSIFICATION'] for row in self.all_tables_dfs['raw_classification'].iterrows()} + + for row in self.all_tables_dfs['Classification_B'].iterrows(): + self.all_tables_dfs['Classification_A'].loc[self.all_tables_dfs['Classification_A']['ACCOUNT_NUMBER'].str.startswith(row[1]['ACCOUNT_NUMBER']), 'Clasificación'] = id_clasification_dict[row[1]['ID_RAW_CLASSIFICATION']] + + self.all_tables_dfs['Classification_A'].fillna('No aplica', inplace=True) + self.all_tables_dfs['Classification_A'].drop(columns=['ID_ARCHIVE', 'ACCOUNT_ORDER', 'STATUS', 'ORIGINAL_BALANCE', 'CREATED_DATA', 'ID', 'ID_COMPANY', 'INITIAL_DATE', 'PERIODICITY', 'USER', 'ID', 'ASSESSMENT_DATE'], errors = 'ignore', inplace = True) + self.all_tables_dfs['Classification_A'].rename(columns = {'ACCOUNT_NUMBER':'Código', 'CHECKED_BALANCE': 'Saldo', 'ACCOUNT_NAME':'Nombre original'}, inplace = True) + self.all_tables_dfs['Classification_A'].to_excel(self.writer, sheet_name='CLASIFICACIÓN', startrow=0 , startcol=0, index=False) + + + + @handler_wrapper('Creando tabla de pyg', 'Tabla de pyg terminada', 'Error construyendo tabla de pyg', 'Error contruyendo tabla de pyg') + def create_pyg_Table(self): + self.all_tables_dfs['pyg_base'] = self.all_tables_dfs['pyg_base'].merge(self.all_tables_dfs['raw_pyg'], left_on = 'ID_RAW_PYG', right_on = 'ID') + self.all_tables_dfs['pyg_base'].drop(columns=['ID_RAW_PYG', 'ID', 'IS_SUB'], errors = 'ignore', inplace = True) + self.all_tables_dfs['pyg_base'] = self.all_tables_dfs['pyg_base'].pivot(index='PYG_ITEM_NAME', columns='DATES', values='VALUE') + self.all_tables_dfs['pyg_base']['order'] = self.all_tables_dfs['pyg_base'].index.map(self.pyg_directory_order) + self.all_tables_dfs['pyg_base'].sort_values(['order'], inplace = True) + self.all_tables_dfs['pyg_base'].drop(columns=['order'], errors = 'ignore', inplace = True) + + self.exit_dataframes['PYG'] = self.all_tables_dfs['pyg_base'] + + self.all_tables_dfs['pyg_projections'] = self.all_tables_dfs['pyg_projections'].merge(self.all_tables_dfs['raw_pyg'], left_on = 'ID_RAW_PYG', right_on = 'ID') + + self.all_tables_dfs['pyg_projections_summary'] = self.all_tables_dfs['pyg_projections'][['PYG_ITEM_NAME', 'PROJECTION_TYPE', 'COMMENT', 'ID_DEPENDENCE']].drop_duplicates() #TODO: debo ver cómo junto pyg_projections_summary y pyg_projections con pyg_base en una sola hoja de excel + pyg_projections_years = self.all_tables_dfs['pyg_projections']['PROJECTED_DATE'].drop_duplicates() + + atributes_df = pd.DataFrame() + self.all_tables_dfs['pyg_projections'].fillna(0, inplace=True) + logger.info(f'[mirar aca] antes de for dataframe de summary:\n{self.all_tables_dfs["pyg_projections_summary"].to_string()}\n\nAtributos:{atributes_df.to_string()}') + for projected_row in self.all_tables_dfs['pyg_projections_summary'].to_dict(orient="records"): + atributes = self.all_tables_dfs['pyg_projections'].loc[self.all_tables_dfs['pyg_projections']['PYG_ITEM_NAME'] == projected_row['PYG_ITEM_NAME'], 'ATRIBUTE'].tolist() + row_atributes_df = pd.DataFrame([atributes], columns =pyg_projections_years, index =[0]) + atributes_df = pd.concat([atributes_df, row_atributes_df]) + + logger.info(f'[mirar aca] dataframe de summary:\n{self.all_tables_dfs["pyg_projections_summary"].to_string()}\n\nAtributos:{atributes_df.to_string()}') + self.all_tables_dfs['pyg_projections_summary'] = self.all_tables_dfs['pyg_projections_summary'].loc[self.all_tables_dfs['pyg_projections_summary']['PROJECTION_TYPE']!='sum'] + self.all_tables_dfs['pyg_projections_summary'].rename(columns = {'PYG_ITEM_NAME':'Linea', 'PROJECTION_TYPE': 'Tipo de proyeccion', 'COMMENT':'Comentario'}, inplace = True) + self.all_tables_dfs['pyg_projections_summary'] = self.all_tables_dfs['pyg_projections_summary'].merge(self.all_tables_dfs['raw_pyg'], left_on = 'ID_DEPENDENCE', right_on = 'ID') + + self.all_tables_dfs['pyg_projections_summary']['order'] = self.all_tables_dfs['pyg_projections_summary']['Linea'].map(self.pyg_directory_order) + self.all_tables_dfs['pyg_projections_summary'].sort_values(['order'], inplace = True) + + self.all_tables_dfs['pyg_projections_summary'].drop(columns=['ID_DEPENDENCE', 'ID', 'IS_SUB','order'], errors = 'ignore', inplace = True) + self.all_tables_dfs['pyg_projections_summary'].rename(columns = {'PYG_ITEM_NAME':'Cuennta dependiente'}, inplace = True) + self.all_tables_dfs['pyg_projections_summary'].to_excel(self.writer, sheet_name='PROYECCIONES DE PYG', startrow=0 , startcol=0, index=False) + atributes_df.to_excel(self.writer, sheet_name='PROYECCIONES DE PYG', startrow=0 , startcol=len(self.all_tables_dfs['pyg_projections_summary'].columns), index=False) + + + + + @handler_wrapper('Creando tabla de capex', 'Tabla de capex terminada', 'Error creando tabla de capex', 'Error creando tabla de capex') + def create_capex_table(self): + assets_properties_df = pd.DataFrame() + assets_projections_df = pd.DataFrame() + + items_groups = self.all_tables_dfs["fixed_assets"]["ID_ITEMS_GROUP"].unique() + current_row_writing = 0 + for group in items_groups: + logger.info(f'[mira aca] este es el group que busco: {group}') + group_df = self.all_tables_dfs['fixed_assets'].loc[self.all_tables_dfs['fixed_assets']['ID_ITEMS_GROUP'] == group] + used_accounts = group_df[['ASSET_ACCOUNT', 'ACUMULATED_ACCOUNT', 'PERIOD_ACCOUNT']].iloc[0] + logger.info(f'\n{used_accounts}') + + original_values = group_df[['ASSET_ORIGINAL_VALUE', 'ACUMULATED_ORIGINAL_VALUE', 'PERIOD_ORIGINAL_VALUE']].iloc[0] + logger.info(f'\n{original_values}') + this_group_properties_df = pd.DataFrame(list(zip(used_accounts, original_values)), columns =['Numero de cuenta', 'Saldo original']) + + group_df.drop(columns=['ID_ITEMS_GROUP', 'PROJECTION_TYPE', 'ASSET_ACCOUNT', 'ACUMULATED_ACCOUNT', 'PERIOD_ACCOUNT', 'ASSET_ORIGINAL_VALUE', 'ACUMULATED_ORIGINAL_VALUE' ,'PERIOD_ORIGINAL_VALUE' ,'PROJECTED_YEARS'], errors = 'ignore', inplace = True) + + dates = group_df.pop('PROJECTED_DATE') + group_df.rename(columns = {'ASSET_VALUE':'Activo Bruto', 'ACUMULATED_VALUE': 'Depreciación/Amortizacion acumulada', 'PERIOD_VALUE':'Depreciación/Amortizacion del periodo', 'EXISTING_ASSET_VALUE': 'Activo Neto Existente'}, inplace = True) + group_df = group_df.T + group_df.columns = dates + logger.info(f'[create_capex_table] Resultado de grupo:\n{group_df.to_string()}\n\nResultado de propiedades:\n{this_group_properties_df.to_string()}') + this_group_properties_df.to_excel(self.writer, sheet_name='ACTIVOS DE DEPRECIACIÓN', startrow=current_row_writing , startcol = 0, index=False) + group_df.to_excel(self.writer, sheet_name='ACTIVOS DE DEPRECIACIÓN', startrow=current_row_writing , startcol = 4, index=True) + + current_row_writing = current_row_writing + 7 + + self.all_tables_dfs["capex"].rename(columns = {'USED_ACCOUNT_NAME':'Cuenta utilizada para calculo', 'PERIODS': 'Años de depreciación', 'METHOD':'Metodo de proyección'}, inplace = True) + self.all_tables_dfs["capex"].to_excel(self.writer, sheet_name='CAPEX', startrow=0 , startcol = 0, index=False) + + capex_dep_dates = self.all_tables_dfs["capex_dep"].pop('CALCULATED_DATE') + self.all_tables_dfs["capex_dep"].rename(columns = {'MANUAL_PERCENTAGE':'Procentaje manual', 'CAPEX_SUMMARY': 'CAPEX', 'CAPEX_ACUMULATED':'Depreciación de capex'}, inplace = True) + self.all_tables_dfs["capex_dep"] = self.all_tables_dfs["capex_dep"].T + self.all_tables_dfs["capex_dep"].columns = capex_dep_dates + self.all_tables_dfs["capex_dep"].to_excel(self.writer, sheet_name='CAPEX', startrow=4 , startcol=0) + + logger.info(f'[create_capex_table] Salida de nuevo capex:\nPropiedades\n{self.all_tables_dfs["capex"]}\n\nResultados:{self.all_tables_dfs["capex_dep"].to_string()}') + + + @handler_wrapper('Creando tabla final de flujo de caja', 'Tabla de flujo de caja creada con exito', 'Error creando tabla de flujo de caja', 'Error creando tabla de flujo de caja') + def create_cash_flow_table(self): + self.all_tables_dfs["cash_flow"].loc[self.all_tables_dfs["cash_flow"]['CASH_FLOW_ITEM_NAME'] == 'Check', 'VALUE']= 'Sí' + self.all_tables_dfs["cash_flow"].rename(columns = {'SUMMARY_DATE':'Fecha', 'CASH_FLOW_ITEM_NAME': 'Linea de flujo de caja', 'CAPEX_ACUMULATED':'Depreciación de capex'}, inplace = True) + self.all_tables_dfs["cash_flow"] = self.all_tables_dfs["cash_flow"].pivot(index='Linea de flujo de caja', columns='Fecha', values='VALUE') + self.all_tables_dfs['cash_flow']['order'] = self.all_tables_dfs['cash_flow'].index.map(self.cash_flow_directory_order) + self.all_tables_dfs['cash_flow'].sort_values(['order'], inplace = True) + self.all_tables_dfs['cash_flow'].drop(columns=['order'], errors = 'ignore', inplace = True) + logger.info(f'[create_cash_flow_table] Salida de flujo de caja:\n{self.all_tables_dfs["cash_flow"].to_string()}') + self.exit_dataframes['FLUJO DE CAJA'] = self.all_tables_dfs["cash_flow"] + + + @handler_wrapper('Creando tabla de deuda', 'Tabla de deuda creada con exito', 'Error creando tabla de deuda', 'Error creando tabla de deuda') + def create_debt_table(self): + self.all_tables_dfs["debt"].loc[self.all_tables_dfs["debt"]['ACCOUNT_NUMBER'] == '0', 'ACCOUNT_NUMBER'] = 'Deuda futura' + self.all_tables_dfs["debt"].drop(columns=['ORIGINAL_VALUE', 'PROJECTION_TYPE', 'START_YEAR', 'ENDING_YEAR', 'DEBT_COMMENT', 'RATE_COMMENT', 'SPREAD_COMMENT'], errors = 'ignore', inplace = True) + self.all_tables_dfs["debt"].rename(columns = {'ACCOUNT_NUMBER':'Numero de cuenta', 'ALIAS_NAME': 'Nombre de deuda', 'INITIAL_BALANCE':'Saldo inicial', 'AMORTIZATION':'Amortizacion', 'INTEREST_VALUE':'Valor de interes', 'ENDING_BALANCE_VARIATION':'Variación de saldo final', 'RATE_ATRIBUTE': 'Tasa de rates', 'SPREAD_ATRIBUTE':'Tasa de spreads'}, inplace = True) + account_alias_pairs = self.all_tables_dfs["debt"][['Numero de cuenta', 'Nombre de deuda']].drop_duplicates() + current_debt_df = pd.DataFrame() + future_debt_df = pd.DataFrame() + sheet_current_row = 0 + for account_alias_dict in account_alias_pairs.to_dict(orient="records"): + df_dict = {key:[value] for key, value in account_alias_dict.items()} + properties = pd.DataFrame(data=df_dict) + pair_debt_df = self.all_tables_dfs["debt"].loc[(self.all_tables_dfs["debt"]["Numero de cuenta"]==account_alias_dict['Numero de cuenta'])&(self.all_tables_dfs["debt"]["Nombre de deuda"]==account_alias_dict['Nombre de deuda'])] + pair_debt_df.drop(columns=['Numero de cuenta', 'Nombre de deuda'], errors = 'ignore', inplace = True) + pair_years = pair_debt_df.pop('YEAR') + pair_debt_df = pair_debt_df.T + pair_debt_df.columns = pair_years + properties.to_excel(self.writer, sheet_name='DEUDA', startrow=sheet_current_row , startcol=0, index = False) + pair_debt_df.to_excel(self.writer, sheet_name='DEUDA', startrow=sheet_current_row , startcol=5) + sheet_current_row = len(pair_debt_df.index) + 3 + + + @handler_wrapper('Creando tavla de capital de trabajo', 'Tabla de capital de trabajo creada con exito', 'Error creando tabla de capital de trabajo', 'Error creando tabla de capital de trabajo') + def create_modal_window_table(self, context, sheet_name): + contex_found_df = self.all_tables_dfs["modal_window"].loc[self.all_tables_dfs["modal_window"]['CONTEXT_WINDOW'] == context] + if contex_found_df.empty: + return + contex_found_df.rename(columns = {'ACCOUNT_NUMBER':'Numero de cuenta', 'ORIGINAL_VALUE': 'Valor original de cuenta', 'VS_ACCOUNT_NAME':'Depende de la cuenta', 'PROJECTION_TYPE':'Tipo de proyeccion', 'COMMENT':'Comentario', 'ATRIBUTE': 'Atributo'}, inplace = True) + all_properties_df = contex_found_df[['Numero de cuenta', 'Valor original de cuenta', 'Depende de la cuenta', 'Tipo de proyeccion', 'Comentario']].drop_duplicates() + logger.info(f'[mira aca] este es el all_properties_df: {all_properties_df.to_string()}') + sheet_current_row = 0 + for properties_dict in all_properties_df.to_dict(orient="records"): + df_dict = {key:[value] for key, value in properties_dict.items()} + properties = pd.DataFrame(data=df_dict).T + + projections_df = contex_found_df.loc[contex_found_df["Numero de cuenta"]==properties_dict['Numero de cuenta']] + projections_df = projections_df[['PROJECTED_DATE', 'Atributo', 'VALUE']] + account_years = projections_df.pop('PROJECTED_DATE') + projections_df = projections_df.T + projections_df.columns = account_years + properties.to_excel(self.writer, sheet_name = sheet_name, startrow=sheet_current_row , startcol=0, header = False) + projections_df.to_excel(self.writer, sheet_name = sheet_name, startrow=sheet_current_row , startcol=3) + sheet_current_row = sheet_current_row + len(projections_df.index) + 5 + + + @handler_wrapper('Creando archivo de excel', 'Archivo de excel creado con exito', 'Error creando archivo de excel', 'Error creando archivo de excel') + def create_excel_file(self): + for sheet, created_table in self.exit_dataframes.items(): + created_table.to_excel(self.writer, sheet_name=sheet, index=True) + + self.writer.close() + self.excel_data = self.output.getvalue() + + + @handler_wrapper('Cargando archivo de excel a s3', 'Archivo de excel cargado con exito', 'Error cargando archivo excel a s3', 'Error cargando archivo') + def save_to_s3(self): + self.bucket = os.environ['BUCKET'] + key_folder = os.environ['FOLDER_PATH'] + os.environ['SECRET_DB_REGION'] + s3_client = boto3.client('s3') + buffer = io.BytesIO(self.excel_data) + self.file_key = f"{key_folder}{self.nit}-{self.user}-{'-'.join(self.assessment_date_long.split('-')[:3])}.xlsx" + s3_client.upload_fileobj(buffer, self.bucket, self.file_key) + + + @handler_wrapper('Requiriendo url firmada', 'Url firmada obtenida con exito', 'Error construyendo url firmada', 'Error construyendo url para descarga de excel hacia front') + def generate_presigned_url(self): + s3_client = boto3.client('s3') + + self.signed_url = s3_client.generate_presigned_url('get_object', + Params={'Bucket': self.bucket, 'Key': self.file_key}, + ExpiresIn=3600) + + + @handler_wrapper('Construyendo respuesta a front', 'Respuesta construída con exito', 'Error construyendo respuesta a front', 'Error construyendo respuesta') + def create_response(self): + if self.signed_url: + self.partial_response = {'download_url':self.signed_url} + + + @debugger_wrapper('Error construyendo respuesta final', 'Error construyendo respuesta') + def response_maker(self, succesfull_run = False, error_str = str()): + if self.db_connection: + self.db_connection.close() + if succesfull_run: + self.final_response['statusCode'] = 200 + self.final_response['body'] = json.dumps(self.partial_response) + return self.final_response + + self.final_response['body'] = json.dumps(self.detailed_raise if self.detailed_raise else error_str) + return self.final_response + + + +def get_current_error_line(): + return str(sys.exc_info()[-1].tb_lineno) + \ No newline at end of file diff --git a/corporate_finances_back_py/assessment-report-update/utils.py b/corporate_finances_back_py/assessment-report-update/utils.py new file mode 100644 index 0000000..9efbdea --- /dev/null +++ b/corporate_finances_back_py/assessment-report-update/utils.py @@ -0,0 +1,33 @@ +#version 2023 - 05 - 04 +import base64 +import boto3 +import json +import logging + +from sqlalchemy import create_engine + +from decorators import handler_wrapper, debugger_wrapper + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + + +@debugger_wrapper('Error al obtener secreto','Error fatal de back conectando a base de datos') +def get_secret(secret_region, secret_name): + session = boto3.session.Session() + client_secrets_manager = session.client(service_name='secretsmanager', region_name=secret_region) + secret_data = client_secrets_manager.get_secret_value(SecretId=secret_name) + if 'SecretString' in secret_data: + secret_str = secret_data['SecretString'] + else: + secret_str = base64.b64decode(secret_data['SecretBinary']) + logger.info('[utils] (get_secret) Se obtuvo el secreto') + return json.loads(secret_str) + + +@debugger_wrapper('Error en la conexion a base de datos','Error fatal de back conectando a base de datos') +def connect_to_db(db_schema, db_secret): + conn_string = ('mysql+mysqlconnector://' + db_secret["username"] + ':' + db_secret["password"] + '@' + db_secret["host"] + ':' + str(db_secret["port"]) + '/' + db_schema) + sql_engine = create_engine(conn_string) + db_connection = sql_engine.connect() + return db_connection \ No newline at end of file diff --git a/corporate_finances_back_py/assessment-report-update/vars.py b/corporate_finances_back_py/assessment-report-update/vars.py new file mode 100644 index 0000000..337e088 --- /dev/null +++ b/corporate_finances_back_py/assessment-report-update/vars.py @@ -0,0 +1,121 @@ +queries = {'Classification_A': 'SELECT * FROM ORIGINAL_PUC A, ARCHIVE B, ASSESSMENT C WHERE A.ID_ARCHIVE = B.ID AND B.ID = C.ID_ARCHIVE AND C.ID = {}', + 'Classification_B': 'SELECT * FROM USER_CLASSIFICATION WHERE ID_ASSESSMENT = {}', + 'raw_classification': 'SELECT * FROM RAW_CLASSIFICATION', + 'raw_pyg': 'SELECT * FROM RAW_PYG', + 'pyg_base': 'SELECT * FROM PYG_RESULTS WHERE ID_ASSESSMENT = {}', + 'pyg_projections': 'SELECT B.*, A.PROJECTION_TYPE, A.COMMENT, A.ID_DEPENDENCE FROM PYG_ITEM A, PROJECTED_PYG B WHERE A.ID_ASSESSMENT = B.ID_ASSESSMENT AND A.ID_RAW_PYG = B.ID_RAW_PYG AND A.ID_ASSESSMENT = {}', + 'fixed_assets': """SELECT B.PROJECTED_DATE, A.ID_ITEMS_GROUP, A.PROJECTION_TYPE, A.ASSET_ACCOUNT, A.ACUMULATED_ACCOUNT, A.PERIOD_ACCOUNT, A.ASSET_ORIGINAL_VALUE, A.ACUMULATED_ORIGINAL_VALUE, A.PERIOD_ORIGINAL_VALUE, A.PROJECTED_YEARS, +B.ASSET_VALUE, B.ACUMULATED_VALUE, B.EXISTING_ASSET_VALUE, B.PERIOD_VALUE FROM FIXED_ASSETS A, PROJECTED_FIXED_ASSETS B WHERE A.ID_ASSESSMENT = B.ID_ASSESSMENT AND A.ID_ITEMS_GROUP = B.ID_ITEMS_GROUP AND A.ID_ASSESSMENT = {}""", + 'capex': 'SELECT METHOD, USED_ACCOUNT_NAME, PERIODS FROM CAPEX WHERE ID_ASSESSMENT = {}', + 'capex_dep': 'SELECT * FROM CAPEX_VALUES WHERE ID_ASSESSMENT = {}', + 'cash_flow': 'SELECT A.SUMMARY_DATE, A.VALUE, B.CASH_FLOW_ITEM_NAME FROM CASH_FLOW A, RAW_CASH_FLOW B WHERE A.ID_RAW_CASH_FLOW = B.ID AND A.ID_ASSESSMENT = {}', + 'debt': """SELECT B.`YEAR`, A.*, B.INITIAL_BALANCE, B.AMORTIZATION, B.INTEREST_VALUE, B.ENDING_BALANCE_VARIATION, B.RATE_ATRIBUTE, B.SPREAD_ATRIBUTE FROM DEBT A, PROJECTED_DEBT B +WHERE A.ID_ASSESSMENT = B.ID_ASSESSMENT AND A.ACCOUNT_NUMBER = B.ACCOUNT_NUMBER AND A.ALIAS_NAME = B.ALIAS_NAME AND A.ID_ASSESSMENT = {} ORDER BY A.ACCOUNT_NUMBER DESC, A.ALIAS_NAME, B.YEAR""", + 'modal_window':"""SELECT A.ACCOUNT_NUMBER, A.ORIGINAL_VALUE, A.VS_ACCOUNT_NAME, A.PROJECTION_TYPE, A.COMMENT, A.CONTEXT_WINDOW, B.PROJECTED_DATE, B.ATRIBUTE, B.VALUE +FROM MODAL_WINDOWS A, MODAL_WINDOWS_PROJECTED B WHERE A.ID_ASSESSMENT = B.ID_ASSESSMENT AND A.CONTEXT_WINDOW = B.CONTEXT_WINDOW AND A.ACCOUNT_NUMBER = B.ACCOUNT_NUMBER AND A.ID_ASSESSMENT = {}""" +} + +pyg_order = [ +'Ingresos operacionales 1', +'Ingresos operacionales 2', +'Ingresos operacionales 3', +'Ingresos operacionales 4', +'Ingresos operacionales 5', +'Ingresos operacionales 6', +'Ingresos operacionales 7', +'Ingresos operacionales 8', +'Ingresos operacionales 9', +'Ingresos operacionales 10', +'Ingresos operacionales 11', +'Ingresos operacionales 12', +'Ingresos operacionales 13', +'Ingresos operacionales 14', +'Ingresos operacionales 15', +'Ingresos operacionales 16', +'Ingresos operacionales 17', +'Ingresos operacionales 18', +'Ingresos operacionales 19', +'Ingresos operacionales 20', +'Ingresos operacionales', +'Costos (Sin depreciación)', +'Utilidad bruta', +'Gastos operacionales 1', +'Gastos operacionales 2', +'Gastos operacionales 3', +'Gastos operacionales 4', +'Gastos operacionales 5', +'Gastos operacionales 6', +'Gastos operacionales 7', +'Gastos operacionales 8', +'Gastos operacionales 9', +'Gastos operacionales 10', +'Gastos operacionales 11', +'Gastos operacionales 12', +'Gastos operacionales 13', +'Gastos operacionales 14', +'Gastos operacionales 15', +'Gastos operacionales 16', +'Gastos operacionales 17', +'Gastos operacionales 18', +'Gastos operacionales 19', +'Gastos operacionales 20', +'Gastos operacionales 21', +'Gastos operacionales 22', +'Gastos operacionales 23', +'Gastos operacionales 24', +'Gastos operacionales 25', +'Gastos operacionales 26', +'Gastos operacionales 27', +'Gastos operacionales 28', +'Gastos operacionales 29', +'Gastos operacionales 30', +'Gastos operacionales', +'Otros ingresos y egresos operativos', +'EBITDA', +'Depreciación del periodo', +'Depreciación Capex', +'Amortización del periodo', +'Deterioro', +'EBIT', +'Otros ingresos y egresos no operativos', +'Intereses/gasto financiero', +'Utilidad antes de impuestos', +'Impuestos de renta', +'Utilidad neta'] + + + + +cash_flow_order = [ +'Utilidad neta', +'Impuestos de renta', +'Intereses/gasto financiero', +'EBIT', +'Impuestos operacionales', +'UODI (NOPAT)', +'Depreciación del periodo', +'Deterioro', +'Amortización del periodo', +'Depreciación Capex', +'Otros movimientos que no son salida ni entrada de efectivo operativos', +'Flujo de caja bruto', +'Capital de trabajo', +'CAPEX', +'Otros movimientos netos de activos operativos que afecta el FCLO', +'Otros ingresos y egresos operativos', +'Flujo de caja Libre Operacional', +'Intereses/gasto financiero FC', +'Impuestos no operacionales', +'Variación de deuda', +'Deuda de tesorería del periodo', +'Deuda de tesorería acumulada', +'Otros movimientos netos de activos operativos que afecta el FCLA', +'Otros ingresos y egresos no operativos', +'Flujo de caja del accionista', +'Aportes de capital social u otros', +'Dividentos en efectivo', +'Flujo de caja del periodo', +'Saldo de caja inicial', +'Saldo de caja final', +'Check', +] \ No newline at end of file diff --git a/corporate_finances_back_py/assessment-retrieve/decorators.py b/corporate_finances_back_py/assessment-retrieve/decorators.py new file mode 100644 index 0000000..071760a --- /dev/null +++ b/corporate_finances_back_py/assessment-retrieve/decorators.py @@ -0,0 +1,63 @@ +#version 2023 - 05 - 04 +import logging +import sys +import traceback +from functools import wraps +from time import time + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + +def handler_wrapper(start, satisfactory_log, error_log, raise_error): + #esto se ejecuta en la inicializacion de primero + def decorator(func): + #print(message1) + #lo que yo ponga acá se ejecuta antes de hacer el llamado a la funcion + @wraps(func) + def wrapper(*args, **kwargs): + #esto sí se ejecuta solo cuando llama a la funcion decorada + #print(message2) + try: + logger.info(f'[{func.__name__}] {start}...') + resultado = func(*args, **kwargs) + logger.info(f'[{func.__name__}] {satisfactory_log}') + return resultado + except Exception as e: + logger.error(f"[{func.__name__}] {error_log}, linea: {get_especific_error_line(func.__name__)}, motivo: {str(e)}") + raise Exception(f"{raise_error}") + + return wrapper + return decorator + +def debugger_wrapper(error_log, raise_error): + def decorator(func): + @wraps(func) + def wrapper(*args, **kwargs): + try: + resultado = func(*args, **kwargs) + return resultado + except Exception as e: + logger.error(f"[{func.__name__}] {error_log}, linea: {get_especific_error_line(func.__name__)}, motivo: {str(e)}") + raise Exception(f"{raise_error}") + return wrapper + return decorator + + +def get_especific_error_line(func_name): + _, _, exc_tb = sys.exc_info() + for trace in traceback.extract_tb(exc_tb): + if func_name in trace: + return str(trace[1]) + +def timing(f): + @wraps(f) + def wrap(*args, **kw): + ts = time() + result = f(*args, **kw) + te = time() + taken_time_message = '[timing] La funcion {}, toma: {:.2f} sec en ejecutarse'.format(f.__name__, te-ts) + logger.info(taken_time_message) + return result + return wrap + + diff --git a/corporate_finances_back_py/assessment-retrieve/lambda_function.py b/corporate_finances_back_py/assessment-retrieve/lambda_function.py new file mode 100644 index 0000000..a4093b7 --- /dev/null +++ b/corporate_finances_back_py/assessment-retrieve/lambda_function.py @@ -0,0 +1,269 @@ +import json +import logging +import sys +import os +import pandas as pd +import datetime +import decimal +from sqlalchemy import text + +print(f'En principal{__name__}') +if __name__ in ['__main__', 'lambda_function']: + from decorators import handler_wrapper, timing, debugger_wrapper + from utils import get_secret, connect_to_db, connect_to_db_local_dev +else: + from .decorators import handler_wrapper, timing, debugger_wrapper + from .utils import get_secret, connect_to_db, connect_to_db_local_dev + +logging.basicConfig() +logging.basicConfig(format='%(asctime)s [%(levelname)s] [%(module)s] %(message)s', force=True, datefmt='%Y-%m-%d %H:%M:%S') +logger = logging.getLogger() +logger.setLevel(logging.INFO) + +def lambda_handler(event,context): + sc_obj = script_object(event) + lambda_response = sc_obj.starter() + logger.info(f'respuesta final de lambda: \n{lambda_response}') + return lambda_response + + +class script_object: + def __init__(self, event): + try: + self.failed_init = False + self.final_response = {'headers':{'Access-Control-Allow-Headers': '*', + 'Access-Control-Allow-Origin': '*', + 'Access-Control-Allow-Methods': '*'}, "statusCode": 500, 'body': {}} + self.db_connection = 0 + self.detailed_raise = '' + self.partial_response = list() + + logger.warning(f'event de entrada: {str(event)}') + + self.id_assessment = event['pathParameters']['id_assessment'] + + self.not_operational_accounts = list() + self.debt_accounts = list() + + self.cash_flow_dict = ['Flujo de caja Libre Operacional', 'Flujo de caja del accionista', 'Flujo de caja del periodo'] + self.assessment_directory = {'ASSESSMENT_DATE': 'dateAssessment', + 'INITIAL_DATE': 'dateInitial', + 'CURRENT_CLOSING_DATE': 'dateCurrentClosing', + 'FLOW_HALF_PERIOD': 'flowHalfPeriod', + 'NEXT_FLOW_HALF_YEAR': 'nextFlowHalfYear', + 'DATES_ADJUST_ATRIBUTE': 'adjust', + 'DATES_ADJUST_COMMENT': 'explicationDateAdjust', + 'CHOSEN_FLOW_NAME': 'cashFree', + 'NORMALIZED_CASH_FLOW': 'normalicedCashFlow', + 'DISCOUNT_RATE_ATRIBUTE': 'discountRateAtribute', + 'TERMINAL_VALUE': 'terminalValue', + 'DISCOUNT_FACTOR': 'discountFactor', + 'VP_TERMINAL_VALUE': 'vpTerminalValue', + 'ENTERPRISE_VALUE': 'enterpriseValue', + 'FINANCIAL_ADJUST': 'financialAdjust', + 'TOTAL_NOT_OPERATIONAL_ASSETS': 'activesNoOperational', + 'TOTAL_OPERATIONAL_PASIVES': 'pasiveOperational', + 'PATRIMONY_VALUE': 'patrimonial', + 'OUTSTANDING_SHARES': 'nActions', + 'ASSESSMENT_VALUE': 'valuePerValuation', + 'VP_FLOWS': 'vpFlows', + 'GRADIENT': 'gradient', + 'ADJUST_METHOD': 'method' + + } + self.fclo_directory = {'OPERATIVE_CASH_FLOW': 'operativeCashFlow', + 'DISCOUNT_PERIOD': 'discountPeriod', + 'DISCOUNT_RATE': 'discountRate', + 'DISCOUNT_FACTOR': 'discountFactor', + 'FCLO': 'fclo' + } + + self.historic_dates = list() # + self.projection_dates = list() # + self.cash_flow_response = list() + self.found_accounts = list() + self.assessment_atributes = dict() + self.flow_discount = list() + self.assessment = dict() + + + except Exception as e: + logger.error(f'[__init__] Error inicializando objeto lambda, linea: {get_current_error_line()}, motivo: {str(e)}') + self.failed_init = True + + def starter(self): + try: + if self.failed_init: + raise AttributeError('Error con los datos recibidos al servicio') + self.create_conection_to_db() + self.get_assessment_dates() + self.acquire_classification_values() + self.acquire_cash_flows() + self.check_assessment_atributes() + if self.assessment_atributes: + self.acquire_fclo_atributes() + self.consume_fclo_atributes() + self.consume_assessment_atributes() + + + self.organize_partial_response() + + + return self.response_maker(succesfull_run = True) + + except Exception as e: + logger.error(f'[starter] Hubieron problemas en el comando de la linea: {get_current_error_line()}') + return self.response_maker(succesfull_run = False, error_str = (str(e))) + + @handler_wrapper('Creando conexion a bd','Conexion a bd creada con exito','Error en la conexion a bd','Problemas creando la conexion a bd') + def create_conection_to_db(self): + if __name__ != 'lambda_function': + self.db_connection = connect_to_db_local_dev() + self.db_connection.begin() + return + + db_schema = os.environ['DB_SCHEMA'] + secret_db_region = os.environ['SECRET_DB_REGION'] + secret_db_name = os.environ['SECRET_DB_NAME'] + db_secret = get_secret(secret_db_region, secret_db_name) + self.db_connection = connect_to_db(db_schema, db_secret) + + + @handler_wrapper('Obteniendo las fechas del proceso de valoración', 'Fechas del proceso de valroación obtenidas con exito', 'Error obteniendo las fechas del proceso de valoración', 'Error obteniendo fechas del proceso de valoración') + def get_assessment_dates(self): + query = f"SELECT DATES, PROPERTY FROM ASSESSMENT_DATES WHERE ID_ASSESSMENT = {self.id_assessment} ORDER BY DATES" + logger.info(f"[get_assessment_dates] Query a base de datos para obtener las fechas utilizadas en el proces de valoración:\n {query}") + rds_data = self.db_connection.execute(text(query)) + directory = {'HISTORIC': self.historic_dates, 'PROJECTION': self.projection_dates} + found_dates = [row._asdict() for row in rds_data.fetchall()] + for date_item in found_dates: + directory.get(date_item['PROPERTY'], []).append(date_item['DATES'].strftime('%d-%m-%Y')) + self.projection_dates = [item.split('-')[-1] for item in self.projection_dates] + logger.info(f'[get_assessment_dates] Fechas del proceso de valoración:\nhistoricas: {self.historic_dates}\nproyecciones: {self.projection_dates}') + + + @handler_wrapper('Oteniendo las cuentas de valoración historica', 'Valores de cuentas obtenidos con exito', 'Error obteniendo valores de cuentas', 'Error obtenino valores de cuentas clasificadas') + def acquire_classification_values(self): + query = f"""SELECT B.CLASSIFICATION AS clasification, A.ACCOUNT_NAME AS name, A.ANNUALIZED AS value FROM ASSESSMENT_CHECKED A, RAW_CLASSIFICATION B, ASSESSMENT C +WHERE A.ID_ASSESSMENT = C.ID AND A.ID_RAW_CLASSIFICATION = B.ID AND A.ID_ARCHIVE = C.ID_ARCHIVE +AND B.CLASSIFICATION IN ('Efectivo y no operacionales', 'Caja', 'Deuda con costo financiero') AND A.ID_ASSESSMENT = {self.id_assessment}""" + logger.info(f"[acquire_classification_values] Query a base de datos para obtener los valores de cuentas con las clasificaciones requeridas:\n{query}") + rds_data = self.db_connection.execute(text(query)) + self.found_accounts = [row._asdict() for row in rds_data.fetchall()] + clasification_directory = {'Efectivo y no operacionales': self.not_operational_accounts, 'Deuda con costo financiero': self.debt_accounts} + for item in self.found_accounts: + item['value'] = float(item['value']) + clasification_directory.get(item['clasification'], []).append(item) + + + @handler_wrapper('Obteniendo cajas de flujo de caja', 'Cajas de flujo de caja obtenidas con exito', 'Error adquiriendo resultados de flujo de caja', 'Error adquiriendo resultados de flujo de caja') + def acquire_cash_flows(self): + query = f"""SELECT CASH_FLOW_ITEM_NAME, VALUE FROM CASH_FLOW A, RAW_CASH_FLOW B WHERE A.ID_RAW_CASH_FLOW = B.ID AND A.ID_ASSESSMENT = {self.id_assessment} +AND B.CASH_FLOW_ITEM_NAME IN ('Flujo de Caja Libre Operacional', 'Flujo de Caja del accionista', 'Flujo de Caja del periodo') ORDER BY A.SUMMARY_DATE""" + logger.info(f"[acquire_cash_flows] Query a base de datos para obtener los valores de flujos de caja requeridos:\n{query}") + rds_data = self.db_connection.execute(text(query)) + cash_flows = [row._asdict() for row in rds_data.fetchall()] + for item in cash_flows: + item['VALUE'] = float(item['VALUE']) + + for cash_flow in self.cash_flow_dict: + values_vector = [row['VALUE'] for row in cash_flows if row['CASH_FLOW_ITEM_NAME'] == cash_flow][-1-len(self.projection_dates):] + + values_vector[0] = values_vector[0] if '-12-' in self.historic_dates[-1] else values_vector[1] - values_vector.pop(0) + self.cash_flow_response.append({'name': cash_flow, 'values': values_vector}) + + + @handler_wrapper('Chequeando si existen atributos de pantalla de valoración', 'Chequeo terminado', 'Error chequeando si hay atributos de pantalla de valoración', 'Error chequeando atributos de pantalla de valoración') + def check_assessment_atributes(self): + query = f"""SELECT * FROM CALCULATED_ASSESSMENT WHERE ID_ASSESSMENT = {self.id_assessment}""" + logger.info(f"[check_assessment_atributes] Query a base de datos para obtener posibles atributos de pantalla de valoración:\n{query}") + rds_data = self.db_connection.execute(text(query)) + self.assessment_atributes = [row._asdict() for row in rds_data.fetchall()] + self.assessment_atributes = self.assessment_atributes[0] if self.assessment_atributes else False + + + @handler_wrapper('Se encontraron atributos de pantallla de valoración, adquiriendo atributos de FCLO', 'Atributos FCLO adquiridos', 'Error adquiriendo atributos FCLO', 'Error adquiriendo atributos fclo') + def acquire_fclo_atributes(self): + query = f"""SELECT * FROM FCLO_DISCOUNT WHERE ID_ASSESSMENT = {self.id_assessment} ORDER BY ITEM_DATE""" + logger.info(f"[acquire_fclo_atributes] Query a base de datos para obtener atributos de FCLO:\n{query}") + rds_data = self.db_connection.execute(text(query)) + self.fclo_atributes = [row._asdict() for row in rds_data.fetchall()] + + + @handler_wrapper('Consumiendo atributos de fclo', 'Atributos de fclo consumidos con exito', 'Error consumiendo atributos de fclo', 'Error consumiendo fclo') + def consume_fclo_atributes(self): + fclo_dict = {'dates': []} + if '-12-' in self.historic_dates[-1]: + fclo_dict['dates'] = [self.historic_dates[-1]] + self.projection_dates + + else: + self.projection_dates[0] = f'Diciembre {self.projection_dates[0]}' + fclo_dict['dates'] = self.projection_dates + + + logger.info(f'[fclo_dict] hasta aca {fclo_dict}') + for bd_key, front_key in self.fclo_directory.items(): + fclo_dict[front_key] = [float(item[bd_key]) for item in self.fclo_atributes] + logger.info(f'[fclo_dict] hasta aca {fclo_dict}') + self.flow_discount.append(fclo_dict) + + + + @handler_wrapper('Consumiendo atributos base de la pantalla de valoración', 'Atributos base consumidos correctamente', 'Error consumiendo atributos base de la pantalla de valoración', 'Error consumiendo atributos de la pantalla de valoración1') + def consume_assessment_atributes(self): + for bd_key, front_key in self.assessment_directory.items(): + self.assessment[front_key] = always_ok(self.assessment_atributes[bd_key]) + self.assessment['efectAndBox'] = self.not_operational_accounts + self.assessment['debtFinancialCost'] = self.debt_accounts + + + @handler_wrapper('Organizando respuesta final', 'Respuesta final organizada exitosamente', 'Error organizando respuesta final', 'Error organizando respuesta final') + def organize_partial_response(self): + if self.assessment_atributes: + self.assessment['flowDiscount'] = self.flow_discount + self.partial_response = {'cash_flows': self.cash_flow_response, 'classifications': self.found_accounts, 'assessment': self.assessment} + else: + self.partial_response = {'cash_flows': self.cash_flow_response, 'classifications': self.found_accounts} + + + @debugger_wrapper('Error construyendo respuesta final', 'Error construyendo respuesta') + def response_maker(self, succesfull_run = False, error_str = str()): + if succesfull_run: + self.final_response['statusCode'] = 200 + self.final_response['body'] = json.dumps(self.partial_response) + self.db_connection.commit() if __name__ != 'lambda_function' else None + + else: + self.final_response['body'] = json.dumps(self.detailed_raise if self.detailed_raise else error_str) + self.db_connection.rollback() if self.db_connection and __name__ != 'lambda_function' else None + + if self.db_connection: + self.db_connection.close() + return self.final_response + + +def always_ok(input_value): + logger.debug(f'leyendo {input_value} de tipo {type(input_value)}') + if type(input_value) is datetime.date: + return input_value.strftime('%Y-%m-%d') + + elif type(input_value) is decimal.Decimal: + return float(input_value) + + elif type(input_value) is int: + return input_value + + elif type(input_value) is str: + return input_value + else: + raise Exception('tipo no documentado') + + + +def get_current_error_line(): + return str(sys.exc_info()[-1].tb_lineno) + + +if __name__ == "__main__": + event = {"pathParameters": {"id_assessment": "51"}} + lambda_handler(event, '') \ No newline at end of file diff --git a/corporate_finances_back_py/assessment-retrieve/utils.py b/corporate_finances_back_py/assessment-retrieve/utils.py new file mode 100644 index 0000000..a38d9dd --- /dev/null +++ b/corporate_finances_back_py/assessment-retrieve/utils.py @@ -0,0 +1,60 @@ +#version 2023 - 05 - 04 +import base64 +import boto3 +import json +import logging +import os +from sqlalchemy import create_engine +print(f'En utils {__name__}') +if __name__ in ['utils']: + from decorators import handler_wrapper, timing, debugger_wrapper + +else: + from .decorators import handler_wrapper, timing, debugger_wrapper + + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + + +@debugger_wrapper('Error al obtener secreto','Error fatal de back conectando a base de datos') +def get_secret(secret_region, secret_name): + session = boto3.session.Session() + client_secrets_manager = session.client(service_name='secretsmanager', region_name=secret_region) + secret_data = client_secrets_manager.get_secret_value(SecretId=secret_name) + if 'SecretString' in secret_data: + secret_str = secret_data['SecretString'] + else: + secret_str = base64.b64decode(secret_data['SecretBinary']) + logger.info('[utils] (get_secret) Se obtuvo el secreto') + return json.loads(secret_str) + + +@debugger_wrapper('Error en la conexion a base de datos','Error fatal de back conectando a base de datos') +def connect_to_db(db_schema, db_secret): + conn_string = ('mysql+mysqlconnector://' + db_secret["username"] + ':' + db_secret["password"] + '@' + db_secret["host"] + ':' + str(db_secret["port"]) + '/' + db_schema) + sql_engine = create_engine(conn_string) + db_connection = sql_engine.connect() + return db_connection + + +@debugger_wrapper('Error en la conexion a base de datos','Error fatal de back conectando a base de datos') +def connect_to_db_local_dev(): + from dotenv import load_dotenv + load_dotenv() + conn_string = os.environ['local_dev_connector'] + sql_engine = create_engine(conn_string) + db_connection = sql_engine.connect() + return db_connection + + +@handler_wrapper('Invocando asincronamente a Engine de dinamismo', 'Invocación a Engine exitosa', 'Error invocando a Engine', 'Error invocando dinamismo') +def call_dynamic_engine(id_assessment): + lambda_engine = os.environ['LAMBDA_ENGINE'] + data = json.dumps({'id_assessment':id_assessment}).encode() + client = boto3.client('lambda') + response = client.invoke( + FunctionName=lambda_engine, + InvocationType='Event', + Payload= data +) \ No newline at end of file diff --git a/corporate_finances_back_py/assessment-summary-builder/decorators.py b/corporate_finances_back_py/assessment-summary-builder/decorators.py new file mode 100644 index 0000000..071760a --- /dev/null +++ b/corporate_finances_back_py/assessment-summary-builder/decorators.py @@ -0,0 +1,63 @@ +#version 2023 - 05 - 04 +import logging +import sys +import traceback +from functools import wraps +from time import time + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + +def handler_wrapper(start, satisfactory_log, error_log, raise_error): + #esto se ejecuta en la inicializacion de primero + def decorator(func): + #print(message1) + #lo que yo ponga acá se ejecuta antes de hacer el llamado a la funcion + @wraps(func) + def wrapper(*args, **kwargs): + #esto sí se ejecuta solo cuando llama a la funcion decorada + #print(message2) + try: + logger.info(f'[{func.__name__}] {start}...') + resultado = func(*args, **kwargs) + logger.info(f'[{func.__name__}] {satisfactory_log}') + return resultado + except Exception as e: + logger.error(f"[{func.__name__}] {error_log}, linea: {get_especific_error_line(func.__name__)}, motivo: {str(e)}") + raise Exception(f"{raise_error}") + + return wrapper + return decorator + +def debugger_wrapper(error_log, raise_error): + def decorator(func): + @wraps(func) + def wrapper(*args, **kwargs): + try: + resultado = func(*args, **kwargs) + return resultado + except Exception as e: + logger.error(f"[{func.__name__}] {error_log}, linea: {get_especific_error_line(func.__name__)}, motivo: {str(e)}") + raise Exception(f"{raise_error}") + return wrapper + return decorator + + +def get_especific_error_line(func_name): + _, _, exc_tb = sys.exc_info() + for trace in traceback.extract_tb(exc_tb): + if func_name in trace: + return str(trace[1]) + +def timing(f): + @wraps(f) + def wrap(*args, **kw): + ts = time() + result = f(*args, **kw) + te = time() + taken_time_message = '[timing] La funcion {}, toma: {:.2f} sec en ejecutarse'.format(f.__name__, te-ts) + logger.info(taken_time_message) + return result + return wrap + + diff --git a/corporate_finances_back_py/assessment-summary-builder/lambda_function.py b/corporate_finances_back_py/assessment-summary-builder/lambda_function.py new file mode 100644 index 0000000..615f4a7 --- /dev/null +++ b/corporate_finances_back_py/assessment-summary-builder/lambda_function.py @@ -0,0 +1,332 @@ +""": +capas: +capa-pandas-data-transfer + +variables de entorno: +ASSESSMENT_CHECKED_TABLE : ASSESSMENT_CHECKED +CLASSIFICATION_SUMMARY_TABLE : CLASSIFICATION_SUMMARY +DB_SCHEMA : src_corporate_finance +RAW_CLASSIFICATION_TABLE : RAW_CLASSIFICATION +SECRET_DB_NAME : precia/rds8/sources/finanzas_corporativas +SECRET_DB_REGION : us-east-1 + +RAM: 1024 MB + + +""" + +import json +import logging +import sys +import traceback +import time +import copy +from utils import * +import os +import pandas as pd +from decorators import handler_wrapper, timing + +#logging.basicConfig() #En lambdas borra este +logger = logging.getLogger() +logger.setLevel(logging.INFO) + + +def lambda_handler(event, context): + lo = lambda_object(event) + return lo.starter() + + +class lambda_object(): + + @handler_wrapper('Obteniendo valores clave de event', 'Valores de event obtenidos correctamente', + 'Error al obtener valores event', 'Fallo en la obtencion de valores clave de event') + def __init__(self, event) -> None: + logger.warning(f'event que llega a la lambda: {str(event)}') + + event_body_json = event["body"] + event_body_dict = json.loads(event_body_json) + self.assessment_id = event_body_dict['assessment_id'] + self.archive_id = event_body_dict['archive_id'] + self.full_records = event_body_dict['full_records'] + self.parent_accounts_items = {'Ingresos operacionales': ['Ingresos operacionales 1', 'Ingresos operacionales 2', 'Ingresos operacionales 3', 'Ingresos operacionales 4', 'Ingresos operacionales 5'], 'Gastos operacionales': ['Gastos operacionales 1', 'Gastos operacionales 2', 'Gastos operacionales 3', 'Otros ingresos/egresos operativos']} + self.special_classifications = ["Depreciación del periodo", "Depreciación acumulada", "Propiedad, planta y equipo", "Intangibles", "Amortización acumulada", "Amortización del periodo"] + self.raw_classification_data = list() + self.raw_classification_names = list() + + self.purged_items = list() + self.calculated_summaries = list() + + self.final_response = {'headers':{'Access-Control-Allow-Headers': '*', 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Methods': '*'}} + + + def starter(self): + try: + logger.info(f'[starter] Empezando starter de objeto lambda') + self.create_conection_to_resources() + self.get_classification_raw_info() + self.classification_shooter() + self.parent_accounts_shooter() + self.special_classifications_shooter() + self.annualize_information() + self.merge_classifications_ids() + self.create_uploable_dataframes() + self.fix_dataframes() + self.send_all_to_db() + self.db_connection.close() + return self.response_maker(succesfull = True) + + except Exception as e: + if self.db_connection: + self.db_connection.close() + logger.error(f'[starter] Error en el procesamieno del comando de la linea: {get_current_error_line()}, motivo: {e}') + return self.response_maker(succesfull = False, exception_str = str(e)) + + + @handler_wrapper('Creando conexion a bd','Conexion a bd creada con exito','Error en la conexion a bd','Problemas creando la conexion a bd') + def create_conection_to_resources(self): + db_schema = os.environ['DB_SCHEMA'] + secret_db_region = os.environ['SECRET_DB_REGION'] + secret_db_name = os.environ['SECRET_DB_NAME'] + db_secret = get_secret(secret_db_region, secret_db_name) + self.db_connection = connect_to_db(db_schema, db_secret) + + + @handler_wrapper('Trayendo todas las clasificaciones en raw_classifications','Clasificaciones obtenidas con exito', 'Error obteniendo clasificaciones raw', 'Error obteniendo clasificaciones raw') + def get_classification_raw_info(self): + query = f"SELECT * FROM RAW_CLASSIFICATION" + logger.info(f'[get_classification_raw_info] Query para obtener las clasificaciones raw: {query}') + query_result = self.db_connection.execute(query).mappings().all() + self.raw_classification_data = [dict(item) for item in query_result] + self.raw_classification_names = [item['CLASSIFICATION'] for item in self.raw_classification_data] + + + @handler_wrapper('Inicializando disparador de clasificaciones', 'Disparador de clasificaciones terminado con exito', 'Error en el disparador de clasificaciones', 'Error calculando clasificacion') + def classification_shooter(self): + #[self.basic_seeker(master_classification) for master_classification in self.raw_classification_names] #me tengo que saltar la clasificacion 'No aplica' + for master_classification in self.raw_classification_names: + self.basic_seeker(master_classification) + + + def basic_seeker(self, classification_to_find): + logger.info(f'[basic_seeker] Calculando la clasificacion: "{classification_to_find}"') + group_filter = lambda item: item['classification'] == classification_to_find + found_items = list(filter(group_filter, self.full_records)) + if not found_items or classification_to_find == 'No aplica': + logger.info(f'[basic_seeker] No se encontraron cuentas con clasificacion {classification_to_find}') + return + found_items = self.filter_items_to_min_level(found_items) + logger.warning(f"[basic_seeker] Los items con la clasificacion {classification_to_find} son: \n{found_items}") + found_items = copy.deepcopy(found_items) + self.individual_records_modifier(found_items) + self.classification_summary_calculator(classification_to_find) + + + @handler_wrapper('Inicializando disparador de clasificaciones padre', 'Disparador de cuentas padre terminado con exito', 'Error en el disparador cuentas padre', 'Error calculando cuentas padre de subs') + def parent_accounts_shooter(self): + [self.calculate_parents_accounts(parent_account, sub_classifications) for parent_account, sub_classifications in self.parent_accounts_items.items()] + + + def calculate_parents_accounts(self, parent_account, sub_classifications): + purged_items = list(filter(lambda item: item['classification'] in sub_classifications, self.purged_items)) + self.calculated_summaries.append({'classification': parent_account, **self.calculate_summary_groups(purged_items)}) + + + @handler_wrapper('Recalculando items de clasificaciones especiales', 'Clasificaciones especiales recalculadas con exito', 'Error al calcular cuentas especiales', 'Error calculando cuentas especiales') + def special_classifications_shooter(self): + logger.warning(f'purged_items antes de especiales: \n{self.purged_items}') + [self.special_seeker(master_classification) for master_classification in self.special_classifications] + logger.warning(f'purged_items despues de especiales: \n{self.purged_items}') + + + def special_seeker(self, classification_to_find): + logger.info(f'[special_seeker] Calculando la clasificacion: "{classification_to_find}"') + f = lambda item : item['classification'] == classification_to_find + found_items = list(filter(f, self.full_records)) + if found_items: + sorted_unique_found_levels = sorted(set(item['nivel'] for item in found_items)) + if len(sorted_unique_found_levels) > 1: + level_to_search = sorted_unique_found_levels[1] + self.special_purged_accounts_eraser(classification_to_find) + g = lambda item : item['nivel'] == level_to_search + found_items = list(filter(g, found_items)) + found_items = copy.deepcopy(found_items) + self.individual_records_modifier(found_items) + return + + logger.info(f'[special_seeker] Todos los items de la clasificacion {classification_to_find} tienen solo un nivel') + return + + logger.info(f'[special_seeker] No se encontraron cuentas con clasificacion {classification_to_find}') + + + def special_purged_accounts_eraser(self, classification_to_erase): + self.purged_items = list(filter(lambda item:item['classification'] != classification_to_erase , self.purged_items)) + + + def individual_records_modifier(self, found_items): + self.purged_items += list(map(self.purge_individual_item, found_items)) + + + def classification_summary_calculator(self, classification_to_find): + purged_items = list(filter(lambda item: item['classification'] == classification_to_find, self.purged_items)) + self.calculated_summaries.append({'classification': classification_to_find, **self.calculate_summary_groups(purged_items)}) + + + def purge_individual_item(self, master_account): + master_account['name'] = f"{master_account['name'].strip()} ({master_account['account']})" + master_account['hint'] = f"{master_account['account']} " + filter_machine = self.create_sub_accounts_filter(master_account) + self.sub_classifications_pool = list(filter(lambda item: all(f(item) for f in filter_machine), self.full_records)) + self.sub_classifications_pool.sort(key = lambda item: item['nivel'], reverse = False) #Con esto me aseguro que el set de subclasificaciones esté en orden de nivel y que no purgaré un nivel 10 antes de purgar un nivel 6 + sub_classifications = self.classifications_set_ordered(self.sub_classifications_pool) + logger.warning(f"[purge_individual_item] sub clasificaciones encontradas para la cuenta {master_account['account']}: \n{sub_classifications}") + + for classification in sub_classifications: + master_account['hint'] = master_account.get('hint', master_account['account']) #ver si esto lo puedo borrar + logger.warning(f"[purge_individual_item] Cuenta {master_account['account']} antes de modificacion por clasificacion {classification}: \nValor: {master_account['balance']}\nHint: {master_account['hint']}") + sub_classification_items = [item for item in self.sub_classifications_pool if item['classification'] == classification] + sub_classification_items = self.filter_items_to_min_level(sub_classification_items) + + for sub_item in sub_classification_items: + master_account = self.apply_sub_item_to_master(master_account, sub_item) + + logger.warning(f"[purge_individual_item] Cuenta {master_account['account']} post modificacion de clasificacion {classification}: \nvalor: {master_account['balance']}, hint: {master_account['hint']}") + return master_account + + + def create_sub_accounts_filter(self, master_account): + filters = [] + filters.append(lambda item: item['account'].startswith(master_account['account'])) + filters.append(lambda item: item['classification'] != master_account['classification']) + filters.append(lambda item: item['nivel'] > master_account['nivel']) + #filters.append(lambda item: item['classification'] != 'No aplica') + return filters + + + def filter_items_to_min_level(self, items): + nivels = sorted(set([item['nivel'] for item in items])) + + #usable_accounts = [ item['account'] for item in filter(lambda item: item['nivel'] == nivels[0], items)] + usable_accounts = [ item['account'] for item in items if item['nivel'] == nivels[0] ] + logger.info(f'[filter_items_to_min_level] usable_accounts original: \n{usable_accounts}') + + for nivel in nivels[1:]: + this_level_items = [item for item in items if item['nivel'] == nivel] + new_items = [item['account'] for item in this_level_items if not item['account'].startswith(tuple(usable_accounts))] + #Acá se están obteniendo las subcuentas que estén clasificadas igual que el subaccount del master pero que no sean subcuentas entre sí + #suponga: master account 11 efectivo, subcuenta 1105 ppe, subcuenta 131015 ppe; estas dos subcuentas no son subcuentas entre sí, por eso ambas + #deben restarse del master account + #si la subcuentas fueran 1110 ppe y 111020 ppe, debería tenerse en cuenta unicamente la 1110 + logger.info(f'[filter_items_to_min_level] se agregan las siguientes cuentas: \n{new_items}') + usable_accounts.extend(new_items) + return list(filter(lambda item: item['account'] in usable_accounts , items)) + + + def classifications_set_ordered(self, sub_classifications_pool): + return list(dict.fromkeys(item['classification'] for item in sub_classifications_pool)) #Esto es para hacer un SET + #de las clasificaciones pero sin perder el orden de las mismas, porque ya están organizadas por nivel, requiero + #sacar las clasificaciones sin repetirse pero sin desorganizarse, que es lo que haría un set() + + + def apply_sub_item_to_master(self, master_account, sub_item): + master_account['balance'] = master_account['balance'] - sub_item['balance'] + master_account['hint'] = master_account['hint'] + f"-{sub_item['account']} " + + self.sub_classifications_pool = list(filter(lambda item: not item['account'].startswith(sub_item['account']), self.sub_classifications_pool)) + #recordar que hay un sub_classification_items que son las sub cuentas con una clasificaciones, pero hay un sub_classifications_pool que contiene TODAS las subcuentas con + #multiples clasificaciones, las subcuentas con la misma clasificacion que se deban omitir ya se están omitiendo en filter_items_to_min_level, pero si hay sub clasificaciones + #con clasificaciones differentes en el pool, estas tambien se deben omitir, por eso es tan importante que la depuración se realice en niveles inferiores y luego a superiores + return master_account + + + #OJO esta definicion no se está usando + def calculate_sub_grouping(self, item): + value = 0 + accounts_used_log = '' + + #logger.warning(f"{item}") + if (item['nature'] == 'Debito' and item['account'][0] in ['1', '2', '3']) or (item['nature'] == 'Credito' and item['account'][0] in ['4', '5', '6']): + value = value + item['balance'] + accounts_used_log = accounts_used_log + f"+{item.get('hint', item.get('account'))} " + if (item['nature'] == 'Credito' and item['account'][0] in ['1', '2', '3']) or (item['nature'] == 'Debito' and item['account'][0] in ['4', '5', '6']): + value = value - item['balance'] + accounts_used_log = accounts_used_log + f"-{item.get('hint', item.get('account'))} " + return {'value': value, 'hint':accounts_used_log} + + + def calculate_summary_groups(self, found_purged_items): + #ya que no se está teniendo en cuenta naturaleza y capitulos para el df2, + #lo ideal es que al sumar estas cuentas purgadas, sí se tenga en cuenta estas cosas + #usar el algoritmo de calculate_sub_grouping + summary_value = sum(item['balance'] for item in found_purged_items) + summary_hint = ' + '.join(item['hint'] for item in found_purged_items) + return {'value': summary_value, 'hint':summary_hint} + + + def annualize_information(self): + pass #acá va todo el master de anualización, sea manual o automatica + + + @handler_wrapper('Emergiendo IDs de los nombres de clasificacion','Ids emergidos correctamente', 'Error emergiendo IDs de clasificacion', 'Error agrupando datos') + def merge_classifications_ids(self): + inverted_raw_classifications = {} + + for item in self.raw_classification_data: + inverted_raw_classifications[item['CLASSIFICATION']] = item['ID'] + + logger.warning(f'Este es mi elemento self.inverted_raw_classifications {inverted_raw_classifications}') + for item in self.calculated_summaries: + item['ID_RAW_CLASSIFICATION'] = inverted_raw_classifications[item['classification']] + for item in self.purged_items: + item['ID_RAW_CLASSIFICATION'] = inverted_raw_classifications[item['classification']] + + + def create_uploable_dataframes(self): + self.summaries_df = pd.DataFrame.from_records(self.calculated_summaries) + self.purged_items_df = pd.DataFrame.from_records(self.purged_items) + + + + + @handler_wrapper('Arreglando dataframes para subida a bd', 'Arreglo de dataframes terminado', 'Error arreglando dataframes', 'Error operando datos') + def fix_dataframes(self): + logger.warning(f"[fix_dataframes] summaries antes de fix: \n{self.summaries_df.to_string()}") + self.summaries_df['ID_ASSESSMENT'] = self.assessment_id + self.summaries_df['ID_ARCHIVE'] = self.archive_id + self.summaries_df['ANNUALIZED'] = self.summaries_df['value'] + self.summaries_df.rename(columns={'value': 'CALCULATED_BALANCE', 'hint': 'HINT'},inplace=True) + self.summaries_df.drop(['classification'], axis=1, inplace=True) + #De este me falta el merge con id_raw_classifications + + logger.warning(f"[fix_dataframes] purgeds antes de fix: \n{self.purged_items_df.to_string()}") + self.purged_items_df['ID_ASSESSMENT'] = self.assessment_id + self.purged_items_df['ID_ARCHIVE'] = self.archive_id + self.purged_items_df['ANNUALIZED'] = self.purged_items_df['balance'] + self.purged_items_df.rename(columns={'balance': 'CALCULATED_BALANCE', 'hint': 'HINT', 'nature': 'NATURE', 'account': 'ACCOUNT_NUMBER', 'name': 'ACCOUNT_NAME'},inplace=True) + self.purged_items_df.drop(['initial_date', 'nivel', 'classification', 'chapter', 'status'], axis=1, inplace=True) #este chapter es importante para despues, sería mejor no borrarlo + #De este me falta el merge con id_raw_classifications + + logger.warning(f"[fix_dataframes] summaries despues de fix: \n{self.summaries_df.to_string()}") + logger.warning(f"[fix_dataframes] purgeds despues de fix: \n{self.purged_items_df.to_string()}") + #TODO: Tengo que sí o sí arreglar los hints y revisar los casos + + + + @handler_wrapper('Enviando informacion a base de datos', 'Información cargada correctamente', 'Error al cargar información a la base de datos', 'Hubieron problemas al cargar datos a base de datos') + def send_all_to_db(self): + self.summaries_df.to_sql(name="CLASSIFICATION_SUMMARY", con=self.db_connection, if_exists='append', index=False) + + self.purged_items_df.to_sql(name="ASSESSMENT_CHECKED", con=self.db_connection, if_exists='append', index=False) + + + def response_maker(self, succesfull = False, exception_str = str): + if not succesfull: + self.final_response['body'] = json.dumps(exception_str) + return self.final_response + else: + self.final_response['body'] = json.dumps('ok') + return self.final_response + + +def get_current_error_line(): + return str(sys.exc_info()[-1].tb_lineno) \ No newline at end of file diff --git a/corporate_finances_back_py/assessment-summary-builder/utils.py b/corporate_finances_back_py/assessment-summary-builder/utils.py new file mode 100644 index 0000000..9efbdea --- /dev/null +++ b/corporate_finances_back_py/assessment-summary-builder/utils.py @@ -0,0 +1,33 @@ +#version 2023 - 05 - 04 +import base64 +import boto3 +import json +import logging + +from sqlalchemy import create_engine + +from decorators import handler_wrapper, debugger_wrapper + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + + +@debugger_wrapper('Error al obtener secreto','Error fatal de back conectando a base de datos') +def get_secret(secret_region, secret_name): + session = boto3.session.Session() + client_secrets_manager = session.client(service_name='secretsmanager', region_name=secret_region) + secret_data = client_secrets_manager.get_secret_value(SecretId=secret_name) + if 'SecretString' in secret_data: + secret_str = secret_data['SecretString'] + else: + secret_str = base64.b64decode(secret_data['SecretBinary']) + logger.info('[utils] (get_secret) Se obtuvo el secreto') + return json.loads(secret_str) + + +@debugger_wrapper('Error en la conexion a base de datos','Error fatal de back conectando a base de datos') +def connect_to_db(db_schema, db_secret): + conn_string = ('mysql+mysqlconnector://' + db_secret["username"] + ':' + db_secret["password"] + '@' + db_secret["host"] + ':' + str(db_secret["port"]) + '/' + db_schema) + sql_engine = create_engine(conn_string) + db_connection = sql_engine.connect() + return db_connection \ No newline at end of file diff --git a/corporate_finances_back_py/assessment-to-db/decorators.py b/corporate_finances_back_py/assessment-to-db/decorators.py new file mode 100644 index 0000000..071760a --- /dev/null +++ b/corporate_finances_back_py/assessment-to-db/decorators.py @@ -0,0 +1,63 @@ +#version 2023 - 05 - 04 +import logging +import sys +import traceback +from functools import wraps +from time import time + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + +def handler_wrapper(start, satisfactory_log, error_log, raise_error): + #esto se ejecuta en la inicializacion de primero + def decorator(func): + #print(message1) + #lo que yo ponga acá se ejecuta antes de hacer el llamado a la funcion + @wraps(func) + def wrapper(*args, **kwargs): + #esto sí se ejecuta solo cuando llama a la funcion decorada + #print(message2) + try: + logger.info(f'[{func.__name__}] {start}...') + resultado = func(*args, **kwargs) + logger.info(f'[{func.__name__}] {satisfactory_log}') + return resultado + except Exception as e: + logger.error(f"[{func.__name__}] {error_log}, linea: {get_especific_error_line(func.__name__)}, motivo: {str(e)}") + raise Exception(f"{raise_error}") + + return wrapper + return decorator + +def debugger_wrapper(error_log, raise_error): + def decorator(func): + @wraps(func) + def wrapper(*args, **kwargs): + try: + resultado = func(*args, **kwargs) + return resultado + except Exception as e: + logger.error(f"[{func.__name__}] {error_log}, linea: {get_especific_error_line(func.__name__)}, motivo: {str(e)}") + raise Exception(f"{raise_error}") + return wrapper + return decorator + + +def get_especific_error_line(func_name): + _, _, exc_tb = sys.exc_info() + for trace in traceback.extract_tb(exc_tb): + if func_name in trace: + return str(trace[1]) + +def timing(f): + @wraps(f) + def wrap(*args, **kw): + ts = time() + result = f(*args, **kw) + te = time() + taken_time_message = '[timing] La funcion {}, toma: {:.2f} sec en ejecutarse'.format(f.__name__, te-ts) + logger.info(taken_time_message) + return result + return wrap + + diff --git a/corporate_finances_back_py/assessment-to-db/lambda_function.py b/corporate_finances_back_py/assessment-to-db/lambda_function.py new file mode 100644 index 0000000..6241c85 --- /dev/null +++ b/corporate_finances_back_py/assessment-to-db/lambda_function.py @@ -0,0 +1,271 @@ +""": +capas: +capa-pandas-data-transfer + +variables de entorno: +ARCHIVES_TABLE : ARCHIVE +ASSESSMENT_TABLE : ASSESSMENT +CALCULATED_ASSESSMENT_TABLE : CALCULATED_ASSESSMENT +CASH_FLOW_TABLE : CASH_FLOW +COMPANIES_TABLE : COMPANY +DB_SCHEMA : src_corporate_finance +FCLO_DISCOUNT_TABLE : FCLO_DISCOUNT +RAW_CASH_FLOW_TABLE : RAW_CASH_FLOW +SECRET_DB_NAME : precia/rds8/sources/finanzas_corporativas +SECRET_DB_REGION : us-east-1 + +RAM: 1024 MB + +""" +import json +import logging +import sys +import traceback +import time +import datetime +import copy +import os +from utils import * +import pandas as pd +from decorators import handler_wrapper, timing + +#logging.basicConfig() #En lambdas borra este +logger = logging.getLogger() +logger.setLevel(logging.INFO) + + +def lambda_handler(event, context): + sc_obj = script_object(event) + lambda_response = sc_obj.starter() + logger.info(f'respuesta final de lambda: \n{lambda_response}') + return lambda_response + + +class script_object(): + + @handler_wrapper('Obteniendo valores clave de event', 'Valores de event obtenidos correctamente', + 'Error al obtener valores event', 'Fallo en la obtencion de valores clave de event') + def __init__(self, event) -> None: + self.final_response = {'headers':{'Access-Control-Allow-Headers': '*', + 'Access-Control-Allow-Origin': '*', + 'Access-Control-Allow-Methods': '*'}, "statusCode": 500, 'body': {}} + self.failed_init = False + try: + logger.warning(f'[__init__] event que llega a la lambda: {str(event)}') + + event_body_json = event["body"] + event_dict = json.loads(event_body_json) + + self.id_assessment = event_dict['id_assessment'] + self.close_assessment = event_dict['isFinal'] + self.fclo_data = event_dict['valuation']['flowDiscount'][0] + self.assessment_data = event_dict['valuation'] + + self.assessment_insert_str = f"INSERT INTO CALCULATED_ASSESSMENT VALUES (" + self.search_directory = {'ASSESSMENT_DATE-date' : 'dateAssessment', + 'INITIAL_DATE-date' : 'dateInitial', + 'CURRENT_CLOSING_DATE-date' : 'dateCurrentClosing', + 'FLOW_HALF_PERIOD-date' : 'flowHalfPeriod', + 'NEXT_FLOW_HALF_YEAR-date' : 'nextFlowHalfYear', + 'DATES_ADJUST_ATRIBUTE-varchar' : 'adjust', + 'DATES_ADJUST_COMMENT-varchar' : 'explicationDateAdjust', + 'CHOSEN_FLOW_NAME-varchar' : 'cashFree', + 'CHOSEN_FLOW_COMMENT-varchar' : 'force_False', #no existe en front + 'DISCOUNT_RATE_COMMENT-varchar' : 'force_False', #no existe en front + 'VP_FLOWS-decimal' : 'vpFlows', + 'GRADIENT-varchar' : 'gradient', + 'NORMALIZED_CASH_FLOW-decimal' : 'normalicedCashFlow', + 'DISCOUNT_RATE_ATRIBUTE-varchar' : 'discountRateAtribute', + 'TERMINAL_VALUE-decimal' : 'terminalValue', + 'DISCOUNT_FACTOR-varchar' : 'discountFactor', + 'VP_TERMINAL_VALUE-decimal' : 'vpTerminalValue', + 'ENTERPRISE_VALUE-decimal' : 'enterpriseValue', + 'FINANCIAL_ADJUST-decimal' : 'financialAdjust', #este falta que lo mande el front + 'TOTAL_NOT_OPERATIONAL_ASSETS-decimal' : 'activesNoOperational', + 'TOTAL_OPERATIONAL_PASIVES-decimal' : 'pasiveOperational', + 'ASSETS_COMMENT-varchar' : 'assestComment', #falta + 'PASIVES_COMMENT-varchar' : 'pasiveComment', #falta + 'PATRIMONY_VALUE-decimal' : 'patrimonial', + 'OUTSTANDING_SHARES-int' : 'nActions', + 'ASSESSMENT_VALUE-decimal' : 'valuePerValuation', + 'ADJUST_METHOD-varchar':'method' + } + + self.db_connection = 0 + self.historic_dates = list() + self.projection_dates = list() + + logger.warning(f'[__init__] Inicialización terminada') + + except Exception as e: + logger.error(f'[__init__] Error en la inicialicación, motivo: {str(e)}, linea: {get_current_error_line()}') + self.failed_init = True + + def starter(self): + try: + if self.failed_init: + raise AttributeError('Error de inicializacion') + + logger.info(f'[starter] Empezando starter de objeto lambda') + self.create_conection_to_resources() + self.get_assessment_dates() + self.check_existant_calculated_assessment_data() + self.assessment_data_organizer() + self.organize_fclo() + self.upload_data() + self.save_assessment_step() + if self.close_assessment: + self.close_assessment_process() + self.db_connection.close() + return self.response_maker(succesfull = True) + + except Exception as e: + if self.db_connection: + self.db_connection.close() + logger.error(f'[starter] Error en el procesamieno del comando de la linea: {get_current_error_line()}, motivo: {e}') + return self.response_maker(succesfull = False, exception_str = str(e)) + + + @handler_wrapper('Creando conexion a bd','Conexion a bd creada con exito','Error en la conexion a bd','Problemas creando la conexion a bd') + def create_conection_to_resources(self): + db_schema = os.environ['DB_SCHEMA'] + secret_db_region = os.environ['SECRET_DB_REGION'] + secret_db_name = os.environ['SECRET_DB_NAME'] + db_secret = get_secret(secret_db_region, secret_db_name) + self.db_connection = connect_to_db(db_schema, db_secret) + + + @handler_wrapper('Obteniendo las fechas del proceso de valoración', 'Fechas del proceso de valroación obtenidas con exito', 'Error obteniendo las fechas del proceso de valoración', 'Error obteniendo fechas del proceso de valoración') + def get_assessment_dates(self): + query = f"SELECT DATES, PROPERTY FROM ASSESSMENT_DATES WHERE ID_ASSESSMENT = {self.id_assessment} ORDER BY DATES" + logger.info(f"[get_assessment_dates] Query a base de datos para obtener las fechas utilizadas en el proces de valoración:\n {query}") + rds_data = self.db_connection.execute(query) + directory = {'HISTORIC': self.historic_dates, 'PROJECTION': self.projection_dates} + found_dates = [row._asdict() for row in rds_data.fetchall()] + for date_item in found_dates: + directory.get(date_item['PROPERTY'], []).append(date_item['DATES'].strftime('%Y-%m-%d %H:%M:%S')) + logger.info(f'[get_assessment_dates] Fechas del proceso de valoración:\nhistoricas: {self.historic_dates}\nproyecciones: {self.projection_dates}') + + + @handler_wrapper('Chequeando si hay datos para este proceso de valoracion','Chequeo de datos anteriores terminado','Error revisando existencia de datos anteriores en bd','Error revisando si hay datos anteriores') + def check_existant_calculated_assessment_data(self): + logger.info(f'Prueba para saber existencia de calculated_assessment:') + query = f"SELECT EXISTS (SELECT * FROM CALCULATED_ASSESSMENT WHERE ID_ASSESSMENT = {self.id_assessment} LIMIT 1)" + logger.info(f'este es el query: \n{query}') + respuesta_exists = self.db_connection.execute(query).scalar() #esto está en pruebas de concepto, revisar si se puede mandar directo al if + logger.warning(f'esta fue la respuesta: \n{respuesta_exists} de tipo {type(respuesta_exists)}') + + if respuesta_exists: + logger.error('El proceso de valoracion ya está publicado, no se puede reemplazar') + #raise AttributeError('El proceso de valoracion ya está publicado, no se debe reemplazar') + self.calculated_assessment_safe_delete() + + + #este deja de usarse porque el proceso de valoración va a qudar en status Issued automaticamente + @handler_wrapper('El proceso requirió la eliminacion de proyecciones anteriores','Borrado seguro realizado con exito','Error realizando el borrado seguro de proyecciones anteriores','Problemas eliminando proyecciones anteriores') + def calculated_assessment_safe_delete(self): + query = f"DELETE FROM CALCULATED_ASSESSMENT WHERE ID_ASSESSMENT = {self.id_assessment}" + logger.info(f'[calculated_assessment_safe_delete] Query para eliminar datos anteriores de tabla CALCULATED_ASSESSMENT: {query}') + self.db_connection.execute(query) + + query = f"DELETE FROM FCLO_DISCOUNT WHERE ID_ASSESSMENT = {self.id_assessment}" + logger.info(f'[calculated_assessment_safe_delete] Query para eliminar datos anteriores de tabla FCLO_DISCOUNT: {query}') + self.db_connection.execute(query) + + + @handler_wrapper('Acomodando informacion de valoración para enviar a db','String preparado para envir a bd','Error organizando información','Error procesando información de valoracion') + def assessment_data_organizer(self): + self.assessment_insert_str += str(self.id_assessment) + temp_dict = {} + logger.info(f'[mira aca]{self.search_directory}') + for key, value in self.search_directory.items(): + logger.warning(f'[assessment_data_organizer] buscando {value} en:\n{self.assessment_data}') + temp_value = self.assessment_data.get(value, False) + temp_dict[key] = temp_value + logger.info(f'{key} valor: {temp_value}') + if not temp_value and temp_value != 0: + self.assessment_insert_str += f', NULL ' + continue + if key.endswith('-date'): + temp_date_long_str = datetime.datetime.strptime(temp_value, '%Y-%m-%d').strftime('%Y-%m-%d %H:%M:%S') + self.assessment_insert_str += f', "{temp_date_long_str}"' + + elif key.endswith('-varchar'): + self.assessment_insert_str += f', "{temp_value}"' + + elif key.endswith('-decimal') or key.endswith('-int'): + self.assessment_insert_str += f', {temp_value}' + self.assessment_insert_str += ')' + logger.warning(temp_dict) + + + @handler_wrapper('Organizando tabla de FCLO', 'Tabla de FCLO organizada con exito', 'Error organizando tabla de FCLO', 'Error procesando datos de valoracion') + def organize_fclo(self): + temp_date = self.historic_dates[-1:] + self.projection_dates if '-12-' in self.historic_dates[-1] else self.projection_dates + + self.fclo_data['ITEM_DATE'] = temp_date + self.fclo_df = pd.DataFrame.from_dict(self.fclo_data) + self.fclo_df['ID_ASSESSMENT'] = self.id_assessment + self.fclo_df.astype({'operativeCashFlow': 'float', + 'discountPeriod': 'string', + 'discountRate': 'string', + 'discountFactor': 'string', + 'fclo': 'float', }) + self.fclo_df.drop(['dates'], axis=1, inplace = True) + + self.fclo_df.rename(columns = {'operativeCashFlow':'OPERATIVE_CASH_FLOW', + 'discountPeriod':'DISCOUNT_PERIOD', + 'discountRate':'DISCOUNT_RATE', + 'discountFactor':'DISCOUNT_FACTOR', + 'fclo':'FCLO'}, inplace = True) + + + @handler_wrapper('Subiendo datos a base de datos','Datos subidos a bd con exito','Error subiendo datos a bd','Error subiendo datos a bd') + def upload_data(self): + logger.warning(f'[upload_data] query de linea de valoracion:\n{self.assessment_insert_str}') + logger.warning(f'[upload_data] Dataframe a cargar a fclo: \n{self.fclo_df.to_string()}') + + self.db_connection.execute(self.assessment_insert_str) + logger.warning(f'[upload_data] Carga de linea de valoracion exitosa') + + #query = f"UPDATE ASSESSMENT SET `STATUS` = \"Issued\" WHERE ID = {self.id_assessment}" + #logger.info(f'[upload_data] Query para cabiar el status del proceso de valoración: {query}') + #self.db_connection.execute(query) + + self.fclo_df.to_sql(name='FCLO_DISCOUNT', con=self.db_connection, if_exists='append', index=False) + + + @handler_wrapper('Guardando el paso del proceso de valoracion','Paso guardado correctamente','Error guardando el paso del proceso de valoración', 'Error guardando informacion') + def save_assessment_step(self): + try: + query = f"INSERT INTO ASSESSMENT_STEPS VALUES ({self.id_assessment}, \"VALORATION\");" + logger.info(f"[save_assessment_step] Query a base de datos para guardar el paso del proceso de valoracion: \n{query}") + rds_data = self.db_connection.execute(query) + except Exception as e: + logger.warning(f'[save_assessment_step] Es posible que el step del proceso de valoracion ya haya sido guardado, sin embargo, este es el mensaje de error:\n{str(e)}') + + + @handler_wrapper('Cerrando proceso de valoración', 'Proceso de valroación cerrado correctamente', 'Error cambiando status del proceso de valoración', 'Error cambiando status del proceso de valoración, proceso no fue cerrado correctamente') + def close_assessment_process(self): + query = f"UPDATE ASSESSMENT SET STATUS = 'Published' WHERE ID = {self.id_assessment}" + logger.info(f'[close_assessment_process] Query para cerrar el proceso de valoración:\n{query}') + self.db_connection.execute(query) + + + def response_maker(self, succesfull = False, exception_str = str): + if not succesfull: + self.final_response['body'] = json.dumps(exception_str) + return self.final_response + else: + self.final_response['statusCode'] = 200 + self.final_response['body'] = json.dumps(f"Guardado en bd satisfactorio") + return self.final_response + + + +def get_current_error_line(): + return str(sys.exc_info()[-1].tb_lineno) + + + + \ No newline at end of file diff --git a/corporate_finances_back_py/assessment-to-db/utils.py b/corporate_finances_back_py/assessment-to-db/utils.py new file mode 100644 index 0000000..7516a9b --- /dev/null +++ b/corporate_finances_back_py/assessment-to-db/utils.py @@ -0,0 +1,32 @@ +#version 2023 - 05 - 04 +import base64 +import boto3 +import json +import logging + +from sqlalchemy import create_engine + +from decorators import handler_wrapper, debugger_wrapper + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + +@debugger_wrapper('Error al obtener secreto','Error fatal de back conectando a base de datos') +def get_secret(secret_region, secret_name): + session = boto3.session.Session() + client_secrets_manager = session.client(service_name='secretsmanager', region_name=secret_region) + secret_data = client_secrets_manager.get_secret_value(SecretId=secret_name) + if 'SecretString' in secret_data: + secret_str = secret_data['SecretString'] + else: + secret_str = base64.b64decode(secret_data['SecretBinary']) + logger.info('[utils] (get_secret) Se obtuvo el secreto') + return json.loads(secret_str) + + +@debugger_wrapper('Error en la conexion a base de datos','Error fatal de back conectando a base de datos') +def connect_to_db(db_schema, db_secret): + conn_string = ('mysql+mysqlconnector://' + db_secret["username"] + ':' + db_secret["password"] + '@' + db_secret["host"] + ':' + str(db_secret["port"]) + '/' + db_schema) + sql_engine = create_engine(conn_string) + db_connection = sql_engine.connect() + return db_connection \ No newline at end of file diff --git a/corporate_finances_back_py/capex-calculation-retrieve/decorators.py b/corporate_finances_back_py/capex-calculation-retrieve/decorators.py new file mode 100644 index 0000000..071760a --- /dev/null +++ b/corporate_finances_back_py/capex-calculation-retrieve/decorators.py @@ -0,0 +1,63 @@ +#version 2023 - 05 - 04 +import logging +import sys +import traceback +from functools import wraps +from time import time + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + +def handler_wrapper(start, satisfactory_log, error_log, raise_error): + #esto se ejecuta en la inicializacion de primero + def decorator(func): + #print(message1) + #lo que yo ponga acá se ejecuta antes de hacer el llamado a la funcion + @wraps(func) + def wrapper(*args, **kwargs): + #esto sí se ejecuta solo cuando llama a la funcion decorada + #print(message2) + try: + logger.info(f'[{func.__name__}] {start}...') + resultado = func(*args, **kwargs) + logger.info(f'[{func.__name__}] {satisfactory_log}') + return resultado + except Exception as e: + logger.error(f"[{func.__name__}] {error_log}, linea: {get_especific_error_line(func.__name__)}, motivo: {str(e)}") + raise Exception(f"{raise_error}") + + return wrapper + return decorator + +def debugger_wrapper(error_log, raise_error): + def decorator(func): + @wraps(func) + def wrapper(*args, **kwargs): + try: + resultado = func(*args, **kwargs) + return resultado + except Exception as e: + logger.error(f"[{func.__name__}] {error_log}, linea: {get_especific_error_line(func.__name__)}, motivo: {str(e)}") + raise Exception(f"{raise_error}") + return wrapper + return decorator + + +def get_especific_error_line(func_name): + _, _, exc_tb = sys.exc_info() + for trace in traceback.extract_tb(exc_tb): + if func_name in trace: + return str(trace[1]) + +def timing(f): + @wraps(f) + def wrap(*args, **kw): + ts = time() + result = f(*args, **kw) + te = time() + taken_time_message = '[timing] La funcion {}, toma: {:.2f} sec en ejecutarse'.format(f.__name__, te-ts) + logger.info(taken_time_message) + return result + return wrap + + diff --git a/corporate_finances_back_py/capex-calculation-retrieve/lambda_function.py b/corporate_finances_back_py/capex-calculation-retrieve/lambda_function.py new file mode 100644 index 0000000..c935da9 --- /dev/null +++ b/corporate_finances_back_py/capex-calculation-retrieve/lambda_function.py @@ -0,0 +1,149 @@ +import json +import logging +import sys +import os +from datetime import datetime +from sqlalchemy import text +from collections import defaultdict + +from decorators import handler_wrapper, timing, debugger_wrapper +from utils import get_secret, connect_to_db, connect_to_db_local_dev + +logging.basicConfig() +logging.basicConfig(format='%(asctime)s [%(levelname)s] [%(module)s] %(message)s', force=True, datefmt='%Y-%m-%d %H:%M:%S') +logger = logging.getLogger() +logger.setLevel(logging.INFO) + +def lambda_handler(event,context): + sc_obj = script_object(event) + lambda_response = sc_obj.starter() + logger.info(f'respuesta final de lambda: \n{lambda_response}') + return lambda_response + + +class script_object: + def __init__(self, event): + try: + self.failed_init = False + self.final_response = {'headers':{'Access-Control-Allow-Headers': '*', + 'Access-Control-Allow-Origin': '*', + 'Access-Control-Allow-Methods': '*'}, "statusCode": 500, 'body': {}} + self.db_connection = 0 + self.detailed_raise = '' + self.partial_response = list() + + logger.warning(f'event de entrada: {str(event)}') + + event_dict = event['pathParameters'] + self.id_assessment = event_dict['id_assessment'] + + self.capex_data_found = list() + self.grouped_capex_name = defaultdict(list) + + + except Exception as e: + logger.error(f'[__init__] Error inicializando objeto lambda, linea: {get_current_error_line()}, motivo: {str(e)}') + self.failed_init = True + + def starter(self): + try: + if self.failed_init: + raise AttributeError('Error con los datos recibidos al servicio') + self.create_conection_to_db() + self.get_capex_data() + if not self.capex_data_found: + return self.response_maker(succesfull_run = True) + self.organize_response_objects() + return self.response_maker(succesfull_run = True) + + except Exception as e: + logger.error(f'[starter] Hubieron problemas en el comando de la linea: {get_current_error_line()}') + return self.response_maker(succesfull_run = False, error_str = (str(e))) + + @handler_wrapper('Creando conexion a bd','Conexion a bd creada con exito','Error en la conexion a bd','Problemas creando la conexion a bd') + def create_conection_to_db(self): + if __name__ == "__main__": + self.db_connection = connect_to_db_local_dev() + return + db_schema = os.environ['DB_SCHEMA'] + secret_db_region = os.environ['SECRET_DB_REGION'] + secret_db_name = os.environ['SECRET_DB_NAME'] + db_secret = get_secret(secret_db_region, secret_db_name) + self.db_connection = connect_to_db(db_schema, db_secret) + + + @handler_wrapper('Buscando datos de capex en bd', 'Datos de capex adquiridos con exito', 'Error adquiriendo datos de capex','Error adquiriendo capex desde bd') + def get_capex_data(self): + query = f"""SELECT A.CAPEX_NAME, A.USED_ACCOUNT_NAME, B.MANUAL_PERCENTAGE, A.PERIODS, A.METHOD + FROM CAPEX A, CAPEX_VALUES B + WHERE A.ID_ASSESSMENT = B.ID_ASSESSMENT + AND A.CAPEX_NAME = B.CAPEX_NAME + AND A.ID_ASSESSMENT = {self.id_assessment} ORDER BY B.CALCULATED_DATE""" + + logger.info(f'[get_capex_data] Query para obtener caracteristicas de capex:\n{query}') + rds_data = self.db_connection.execute(text(query)) + self.capex_data_found = [item._asdict() for item in rds_data.fetchall()] + logger.info(f'[get_capex_data] Resultados del query de capex:\n{self.capex_data_found}') + + if self.capex_data_found: + for item in self.capex_data_found: + self.grouped_capex_name[item['CAPEX_NAME']].append(item) + + + @handler_wrapper('Capex antiguo encontrado, organizando respuesta', 'Respuesta de lambda construída', 'Error construyendo respuesta de lambda', 'Error construyendo respuesta') + def organize_response_objects(self): + + for capex in self.grouped_capex_name.values(): + manual_values=list() + for row in capex: + try: + manual_values.append(float(row['MANUAL_PERCENTAGE'])) + except: + continue + + self.partial_response.append({'name':capex[0]['CAPEX_NAME'], + 'method': capex[0]['METHOD'], + 'accountProjector': capex[0]['USED_ACCOUNT_NAME'], + 'year': capex[0]['PERIODS'], + 'manualValues': manual_values}) + + + @debugger_wrapper('Error construyendo respuesta final', 'Error construyendo respuesta') + def response_maker(self, succesfull_run = False, error_str = str()): + if self.db_connection: + self.db_connection.close() + if succesfull_run: + self.final_response['statusCode'] = 200 + self.final_response['body'] = json.dumps(self.partial_response) + return self.final_response + + self.final_response['body'] = json.dumps(self.detailed_raise if self.detailed_raise else error_str) + return self.final_response + + + +def get_current_error_line(): + return str(sys.exc_info()[-1].tb_lineno) + + +if __name__ == "__main__": + event = {"pathParameters": {"id_assessment": "2071"}} + lambda_handler(event, '') + +"""AL EJECUTAR, LA SALIDA DEBE TENER LA FORMA: +[ + { + "name": "capex tab 1", + "method": Manual", + "accountProjector": "Ingresos operacionales", + "year": 5, + "manualValues": [100000, 200000, 300000, 400000, 500000] + }, + { + "name": "capex tab 2", + "method": "Porcentaje de otra variable", + "accountProjector": "Ingresos operacionales", + "year": 5, + "manualValues": [10, 20, 30, 40, 50] + } +]""" \ No newline at end of file diff --git a/corporate_finances_back_py/capex-calculation-retrieve/utils.py b/corporate_finances_back_py/capex-calculation-retrieve/utils.py new file mode 100644 index 0000000..b37a486 --- /dev/null +++ b/corporate_finances_back_py/capex-calculation-retrieve/utils.py @@ -0,0 +1,44 @@ +#version 2023 - 05 - 04 +import base64 +import boto3 +import json +import logging +import os + +from sqlalchemy import create_engine + +from decorators import handler_wrapper, debugger_wrapper + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + + +@debugger_wrapper('Error al obtener secreto','Error fatal de back conectando a base de datos') +def get_secret(secret_region, secret_name): + session = boto3.session.Session() + client_secrets_manager = session.client(service_name='secretsmanager', region_name=secret_region) + secret_data = client_secrets_manager.get_secret_value(SecretId=secret_name) + if 'SecretString' in secret_data: + secret_str = secret_data['SecretString'] + else: + secret_str = base64.b64decode(secret_data['SecretBinary']) + logger.info('[utils] (get_secret) Se obtuvo el secreto') + return json.loads(secret_str) + + +@debugger_wrapper('Error en la conexion a base de datos','Error fatal de back conectando a base de datos') +def connect_to_db(db_schema, db_secret): + conn_string = ('mysql+mysqlconnector://' + db_secret["username"] + ':' + db_secret["password"] + '@' + db_secret["host"] + ':' + str(db_secret["port"]) + '/' + db_schema) + sql_engine = create_engine(conn_string) + db_connection = sql_engine.connect() + return db_connection + + +@debugger_wrapper('Error en la conexion a base de datos','Error fatal de back conectando a base de datos') +def connect_to_db_local_dev(): + from dotenv import load_dotenv + load_dotenv() + conn_string = os.environ['local_dev_connector'] + sql_engine = create_engine(conn_string) + db_connection = sql_engine.connect() + return db_connection diff --git a/corporate_finances_back_py/capex-calculation-to-db/decorators.py b/corporate_finances_back_py/capex-calculation-to-db/decorators.py new file mode 100644 index 0000000..071760a --- /dev/null +++ b/corporate_finances_back_py/capex-calculation-to-db/decorators.py @@ -0,0 +1,63 @@ +#version 2023 - 05 - 04 +import logging +import sys +import traceback +from functools import wraps +from time import time + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + +def handler_wrapper(start, satisfactory_log, error_log, raise_error): + #esto se ejecuta en la inicializacion de primero + def decorator(func): + #print(message1) + #lo que yo ponga acá se ejecuta antes de hacer el llamado a la funcion + @wraps(func) + def wrapper(*args, **kwargs): + #esto sí se ejecuta solo cuando llama a la funcion decorada + #print(message2) + try: + logger.info(f'[{func.__name__}] {start}...') + resultado = func(*args, **kwargs) + logger.info(f'[{func.__name__}] {satisfactory_log}') + return resultado + except Exception as e: + logger.error(f"[{func.__name__}] {error_log}, linea: {get_especific_error_line(func.__name__)}, motivo: {str(e)}") + raise Exception(f"{raise_error}") + + return wrapper + return decorator + +def debugger_wrapper(error_log, raise_error): + def decorator(func): + @wraps(func) + def wrapper(*args, **kwargs): + try: + resultado = func(*args, **kwargs) + return resultado + except Exception as e: + logger.error(f"[{func.__name__}] {error_log}, linea: {get_especific_error_line(func.__name__)}, motivo: {str(e)}") + raise Exception(f"{raise_error}") + return wrapper + return decorator + + +def get_especific_error_line(func_name): + _, _, exc_tb = sys.exc_info() + for trace in traceback.extract_tb(exc_tb): + if func_name in trace: + return str(trace[1]) + +def timing(f): + @wraps(f) + def wrap(*args, **kw): + ts = time() + result = f(*args, **kw) + te = time() + taken_time_message = '[timing] La funcion {}, toma: {:.2f} sec en ejecutarse'.format(f.__name__, te-ts) + logger.info(taken_time_message) + return result + return wrap + + diff --git a/corporate_finances_back_py/capex-calculation-to-db/lambda_function.py b/corporate_finances_back_py/capex-calculation-to-db/lambda_function.py new file mode 100644 index 0000000..ff6cd8e --- /dev/null +++ b/corporate_finances_back_py/capex-calculation-to-db/lambda_function.py @@ -0,0 +1,221 @@ +import json +import logging +import sys +import os +import pandas as pd +import datetime +import os + +from sqlalchemy import text + +if __name__ in ['__main__', 'lambda_function']: + from decorators import handler_wrapper, timing, debugger_wrapper + from utils import get_secret, connect_to_db, call_dynamic_engine, connect_to_db_local_dev +else: + from .decorators import handler_wrapper, timing, debugger_wrapper + from .utils import get_secret, connect_to_db, call_dynamic_engine, connect_to_db_local_dev + +logging.basicConfig() +logging.basicConfig(format='%(asctime)s [%(levelname)s] [%(module)s] %(message)s', force=True, datefmt='%Y-%m-%d %H:%M:%S') +logger = logging.getLogger() +logger.setLevel(logging.DEBUG) + +############################################ +############ EN DESARROLLO PARA LA HU 4096 +############################################ +def lambda_handler(event,context): + sc_obj = script_object(event) + lambda_response = sc_obj.starter() + logger.info(f'respuesta final de lambda: \n{lambda_response}') + return lambda_response + + +class script_object: + def __init__(self, event): + try: + self.failed_init = False + self.final_response = {'headers':{'Access-Control-Allow-Headers': '*', + 'Access-Control-Allow-Origin': '*', + 'Access-Control-Allow-Methods': '*'}, "statusCode": 500, 'body': {}} + self.db_connection = 0 + self.detailed_raise = '' + self.partial_response = list() + + logger.warning(f'event de entrada: {str(event)}') + + event_dict = json.loads(event['body']) + + self.id_assessment = event_dict['id_assessment'] + self.capex_properties = event_dict['capex'] + + self.historic_dates = list() + self.projection_dates = list() + self.capex_record = list() + self.proy_dates = list() + self.proy_records = list() + + + except Exception as e: + logger.error(f'[__init__] Error inicializando objeto lambda, linea: {get_current_error_line()}, motivo: {str(e)}') + self.failed_init = True + + def starter(self): + try: + if self.failed_init: + raise AttributeError('Error con los datos recibidos al servicio') + self.create_conection_to_db() + self.get_assessment_dates() + self.organize_capex_result() + self.organice_projection_result() + self.create_uploable_dataframe() + self.assets_safe_delete() + self.upload_dataframes_to_bd() + call_dynamic_engine(self.id_assessment, __name__) + + return self.response_maker(succesfull_run = True) + + except Exception as e: + logger.error(f'[starter] Hubieron problemas en el comando de la linea: {get_current_error_line()}') + return self.response_maker(succesfull_run = False, error_str = (str(e))) + + @handler_wrapper('Creando conexion a bd','Conexion a bd creada con exito','Error en la conexion a bd','Problemas creando la conexion a bd') + def create_conection_to_db(self): + if __name__ != 'lambda_function': + self.db_connection = connect_to_db_local_dev() + self.db_connection.begin() + return + db_schema = os.environ['DB_SCHEMA'] + secret_db_region = os.environ['SECRET_DB_REGION'] + secret_db_name = os.environ['SECRET_DB_NAME'] + db_secret = get_secret(secret_db_region, secret_db_name) + self.db_connection = connect_to_db(db_schema, db_secret) + + + @handler_wrapper('Obteniendo las fechas del proceso de valoración', 'Fechas del proceso de valoración obtenidas con exito', 'Error obteniendo las fechas del proceso de valoración', 'Error obteniendo fechas del proceso de valoración') + def get_assessment_dates(self): + query = f"SELECT DATES, PROPERTY FROM ASSESSMENT_DATES WHERE ID_ASSESSMENT = {self.id_assessment} ORDER BY DATES" + logger.info(f"[get_assessment_dates] Query a base de datos para obtener las fechas utilizadas en el proces de valoración:\n {query}") + rds_data = self.db_connection.execute(text(query)) + directory = {'HISTORIC': self.historic_dates, 'PROJECTION': self.projection_dates} + found_dates = [row._asdict() for row in rds_data.fetchall()] + for date_item in found_dates: + directory.get(date_item['PROPERTY'], []).append(date_item['DATES'].strftime('%Y-%m-%d %H:%M:%S')) + logger.info(f'[get_assessment_dates] Fechas del proceso de valoración:\nhistoricas: {self.historic_dates}\nproyecciones: {self.projection_dates}') + + + @handler_wrapper('Organizando resultados capex de front', 'Resultados de capex organizados con exito', 'Error organizando resultados de capex', 'Error organizando datos a bd') + def organize_capex_result(self): + self.capex_record =[{'ID_ASSESSMENT': self.id_assessment, + 'CAPEX_NAME':capex_partial['name'], + 'USED_ACCOUNT_NAME':capex_partial['accountProjector'], + 'METHOD': capex_partial['method'], + 'TIME_PERIOD':'ANUAL', + 'PERIODS': capex_partial['year'], + 'CALCULATION_COMMENT': ''} + for capex_partial in self.capex_properties] + + @handler_wrapper('Organizando tabla de proyeccion', 'Datos de proyeccion organizados con exito', 'Error organizando datos de proyeccion', 'Error organizando proyeccion capex') + def organice_projection_result(self): + + for capex_property in self.capex_properties: + for index, date in enumerate(self.historic_dates): + proy_object = { + 'ID_ASSESSMENT': self.id_assessment, + 'CAPEX_NAME':capex_property['name'], + 'CALCULATED_DATE': date, + 'MANUAL_PERCENTAGE': float('nan'), + 'CAPEX_SUMMARY': float('nan'), + 'CAPEX_ACUMULATED': float('nan') + } + + logger.info(f'[organize_capex_result] Objeto de capex historico a agregar:\n{proy_object}') + self.proy_records.append(proy_object) + + for index, proy_date in enumerate(self.projection_dates): + proy_object = {'ID_ASSESSMENT':self.id_assessment, + 'CAPEX_NAME':capex_property['name'], + 'CALCULATED_DATE': proy_date, + 'MANUAL_PERCENTAGE': capex_property['manualValues'][index], + 'CAPEX_SUMMARY': float('nan'), + 'CAPEX_ACUMULATED': float('nan') + } + + logger.info(f'[organize_capex_result] Objeto de capex proyectado a agregar:\n{proy_object}') + self.proy_records.append(proy_object) + + + @handler_wrapper('Creando dataframes de carga', 'Dataframes de carga creados con exito', 'Error creando dataframes de carga', 'Error creando objeto para carga') + def create_uploable_dataframe(self): + self.capex_record_df = pd.DataFrame.from_records(self.capex_record) + logger.info('[create_uploable_dataframe] df de capex a cargar:\n{self.capex_record_df.to_string()}') + self.projection_records_df = pd.DataFrame.from_records(self.proy_records) + logger.info('[create_uploable_dataframe] df de capex values a cargar:\n{self.projection_records_df.to_string()}') + + + @handler_wrapper('Se requirió borrado en base de datos de información previa', 'Borrado exitoso', 'Error intentando eliminar información previa en bd', 'Error borrando información previa en bd') + def assets_safe_delete(self): + query = 'DELETE FROM CAPEX WHERE ID_ASSESSMENT = :id_assessment' + logger.info(f'[assets_safe_delete] Query para ELIMINAR información previa en bd:\n{query}') + self.db_connection.execute(text(query), {'id_assessment': self.id_assessment}) + + query = 'DELETE FROM CAPEX_VALUES WHERE ID_ASSESSMENT = :id_assessment' + logger.info(f'[assets_safe_delete] Query para ELIMINAR información previa en bd:\n{query}') + self.db_connection.execute(text(query), {'id_assessment': self.id_assessment}) + + + @handler_wrapper('Cargando dataframes a bd', 'Carga de datos de capex exitosa', 'Error cargando datos de capex a bd', 'Error cargando datos a bd') + def upload_dataframes_to_bd(self): + self.capex_record_df.to_sql(name='CAPEX', con=self.db_connection, if_exists='append', index=False) + self.projection_records_df.to_sql(name='CAPEX_VALUES', con=self.db_connection, if_exists='append', index=False) + + + @debugger_wrapper('Error construyendo respuesta final', 'Error construyendo respuesta') + def response_maker(self, succesfull_run = False, error_str = str()): + if succesfull_run: + self.final_response['statusCode'] = 200 + self.final_response['body'] = json.dumps('ok') + self.db_connection.commit() if __name__ != 'lambda_function' else None + + else: + self.final_response['body'] = json.dumps(self.detailed_raise if self.detailed_raise else error_str) + self.db_connection.rollback() if self.db_connection and __name__ != 'lambda_function' else None + + if self.db_connection: + self.db_connection.close() + return self.final_response + + + +def get_current_error_line(): + return str(sys.exc_info()[-1].tb_lineno) + +if __name__ == '__main__': + event = {'body': '{\"id_assessment\": 2071, \"capex\": [{\"name\": \"capex tab 1\", \"method\": \"Porcentaje de otra variable\", \"accountProjector\": \"Ingresos operacionales\", \"year\": \"5\", \"manualValues\": [10, 20, 30, 40, 50]}, {\"name\": \"capex tab 2\", \"method\": \"Manual\", \"accountProjector\": \"\", \"year\": \"5\", \"manualValues\": [100000, 200000, 300000, 400000, 500000]}]}'} + lambda_handler(event, '') + + """ + EL OBJETO DE ENTRADA TIENE ESTA FORMA: + { + "id_assessment": 2071, + "capex": [ + { + "name": "capex tab 1", + "method": "Porcentaje de otra variable", + "accountProjector": "Ingresos operacionales", + "year": "5", + "manualValues": [10, 20, 30, 40, 50], + }, + { + "name": "capex tab 2", + "method": "Manual", + "accountProjector": "", + "year": "5", + "manualValues": [100000, 200000, 300000, 400000, 500000], + } + ] +} + + + + + """ \ No newline at end of file diff --git a/corporate_finances_back_py/capex-calculation-to-db/utils.py b/corporate_finances_back_py/capex-calculation-to-db/utils.py new file mode 100644 index 0000000..a14fdb0 --- /dev/null +++ b/corporate_finances_back_py/capex-calculation-to-db/utils.py @@ -0,0 +1,64 @@ +#version 2023 - 05 - 04 +import base64 +import boto3 +import json +import logging +import os + +from sqlalchemy import create_engine + +print(f'En utils {__name__}') +if __name__ in ['utils']: + from decorators import handler_wrapper, timing, debugger_wrapper + +else: + from .decorators import handler_wrapper, timing, debugger_wrapper + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + + +@debugger_wrapper('Error al obtener secreto','Error fatal de back conectando a base de datos') +def get_secret(secret_region, secret_name): + session = boto3.session.Session() + client_secrets_manager = session.client(service_name='secretsmanager', region_name=secret_region) + secret_data = client_secrets_manager.get_secret_value(SecretId=secret_name) + if 'SecretString' in secret_data: + secret_str = secret_data['SecretString'] + else: + secret_str = base64.b64decode(secret_data['SecretBinary']) + logger.info('[utils] (get_secret) Se obtuvo el secreto') + return json.loads(secret_str) + + +@debugger_wrapper('Error en la conexion a base de datos','Error fatal de back conectando a base de datos') +def connect_to_db(db_schema, db_secret): + conn_string = ('mysql+mysqlconnector://' + db_secret["username"] + ':' + db_secret["password"] + '@' + db_secret["host"] + ':' + str(db_secret["port"]) + '/' + db_schema) + sql_engine = create_engine(conn_string) + db_connection = sql_engine.connect() + return db_connection + + +@debugger_wrapper('Error en la conexion a base de datos','Error fatal de back conectando a base de datos') +def connect_to_db_local_dev(): + from dotenv import load_dotenv + load_dotenv() + conn_string = os.environ['local_dev_connector'] + sql_engine = create_engine(conn_string) + db_connection = sql_engine.connect() + return db_connection + + +@handler_wrapper('Invocando asincronamente a Engine de dinamismo', 'Invocación a Engine exitosa', 'Error invocando a Engine', 'Error invocando dinamismo') +def call_dynamic_engine(id_assessment, context): + if context == 'lambda_function': + lambda_engine = os.environ['LAMBDA_ENGINE'] + data = json.dumps({'id_assessment':id_assessment}).encode() + client = boto3.client('lambda') + response = client.invoke( + FunctionName=lambda_engine, + InvocationType='Event', + Payload= data + ) + else: + logger.warning('[call_dynamic_engine] no se ejecuta engine ya que el contexto es local') diff --git a/corporate_finances_back_py/capex-depreciation-items-retrieve/decorators.py b/corporate_finances_back_py/capex-depreciation-items-retrieve/decorators.py new file mode 100644 index 0000000..071760a --- /dev/null +++ b/corporate_finances_back_py/capex-depreciation-items-retrieve/decorators.py @@ -0,0 +1,63 @@ +#version 2023 - 05 - 04 +import logging +import sys +import traceback +from functools import wraps +from time import time + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + +def handler_wrapper(start, satisfactory_log, error_log, raise_error): + #esto se ejecuta en la inicializacion de primero + def decorator(func): + #print(message1) + #lo que yo ponga acá se ejecuta antes de hacer el llamado a la funcion + @wraps(func) + def wrapper(*args, **kwargs): + #esto sí se ejecuta solo cuando llama a la funcion decorada + #print(message2) + try: + logger.info(f'[{func.__name__}] {start}...') + resultado = func(*args, **kwargs) + logger.info(f'[{func.__name__}] {satisfactory_log}') + return resultado + except Exception as e: + logger.error(f"[{func.__name__}] {error_log}, linea: {get_especific_error_line(func.__name__)}, motivo: {str(e)}") + raise Exception(f"{raise_error}") + + return wrapper + return decorator + +def debugger_wrapper(error_log, raise_error): + def decorator(func): + @wraps(func) + def wrapper(*args, **kwargs): + try: + resultado = func(*args, **kwargs) + return resultado + except Exception as e: + logger.error(f"[{func.__name__}] {error_log}, linea: {get_especific_error_line(func.__name__)}, motivo: {str(e)}") + raise Exception(f"{raise_error}") + return wrapper + return decorator + + +def get_especific_error_line(func_name): + _, _, exc_tb = sys.exc_info() + for trace in traceback.extract_tb(exc_tb): + if func_name in trace: + return str(trace[1]) + +def timing(f): + @wraps(f) + def wrap(*args, **kw): + ts = time() + result = f(*args, **kw) + te = time() + taken_time_message = '[timing] La funcion {}, toma: {:.2f} sec en ejecutarse'.format(f.__name__, te-ts) + logger.info(taken_time_message) + return result + return wrap + + diff --git a/corporate_finances_back_py/capex-depreciation-items-retrieve/lambda_function.py b/corporate_finances_back_py/capex-depreciation-items-retrieve/lambda_function.py new file mode 100644 index 0000000..0a6313b --- /dev/null +++ b/corporate_finances_back_py/capex-depreciation-items-retrieve/lambda_function.py @@ -0,0 +1,246 @@ +import json +import logging +import sys +import os +from datetime import datetime +from sqlalchemy import text + +from decorators import handler_wrapper, timing, debugger_wrapper +from utils import get_secret, connect_to_db, connect_to_db_local_dev + +logging.basicConfig() +logging.basicConfig(format='%(asctime)s [%(levelname)s] %(message)s', force=True, datefmt='%Y-%m-%d %H:%M:%S') +logger = logging.getLogger() +logger.setLevel(logging.DEBUG) + + +def lambda_handler(event,context): + sc_obj = script_object(event) + lambda_response = sc_obj.starter() + logger.info(f'respuesta final de lambda: \n{lambda_response}') + return lambda_response + + +class script_object: + def __init__(self, event): + try: + self.failed_init = False + self.final_response = {'headers':{'Access-Control-Allow-Headers': '*', + 'Access-Control-Allow-Origin': '*', + 'Access-Control-Allow-Methods': '*'}, "statusCode": 500, 'body': {}} + self.db_connection = 0 + self.detailed_raise = '' + self.partial_response = list() + + logger.warning(f'event de entrada: {str(event)}') + + event_dict = event['pathParameters'] + self.id_assessment = event_dict['id_assessment'] + + self.dropdown_dict = {'fixedAssets': ['Activo Fijo', 'Activos intangibles'], #Este es para crear el pool + 'period': ['Depreciación del Periodo', 'Amortización del Periodo'], #Toca cambiar los vectores de los values por las clasificaciones que son + 'accumulated': ['Depreciación Acumulada', 'Amortización Acumulada']} + + self.retrieve_bd_dict = {'fixedAssets': 'ASSET_ACCOUNT', #Este es para las propiedades basicas de cada tab, directorio de tabla FIXED_ASSETS + 'period': 'PERIOD_ACCOUNT', + 'acumulated': 'ACUMULATED_ACCOUNT'} + + self.vectors_directory = {'grossAssets': 'ASSET_VALUE', #Este es para las llaves de salida y la llave en BD de las proyecciones PROJECTED_FIXED_ASSETS + 'depAcumulated': 'ACUMULATED_VALUE', + 'activeNeto': 'EXISTING_ASSET_VALUE', + 'depPeriod': 'PERIOD_VALUE'} + + self.historic_vector_directory = {'ASSET_VALUE': 'fixedAssets', #Este es para que según el vector a construir, saber la propiedad donde se ubica la clasificacion a buscar en los historicos + 'ACUMULATED_VALUE': 'acumulated', + 'PERIOD_VALUE': 'period'} + + self.projections_found = list() + self.accounts_found = set() + self.id_items_groups = set() + self.historic_dates = list() + self.projection_dates = list() + self.pool_result = list() + self.tabs_result = list() + + + except Exception as e: + logger.error(f'[__init__] Error inicializando objeto lambda, linea: {get_current_error_line()}, motivo: {str(e)}') + self.failed_init = True + + def starter(self): + try: + if self.failed_init: + raise AttributeError('Error con los datos recibidos al servicio') + self.create_conection_to_db() + self.get_raw_classification() + self.get_assessment_dates() + #Construir el pool + self.get_historic_summary_values() + self.build_pool_master() + + logger.debug(f'[mira aca] el objeto de pool:\n{self.pool_result}') + + #Construir el retrieve + self.get_assets_projections() + if self.projections_found: + self.organize_retrieve_tab_objects() + + self.organize_partial_response() + return self.response_maker(succesfull_run = True) + + except Exception as e: + logger.error(f'[starter] Hubieron problemas en el comando de la linea: {get_current_error_line()}') + return self.response_maker(succesfull_run = False, error_str = (str(e))) + + @handler_wrapper('Creando conexion a bd','Conexion a bd creada con exito','Error en la conexion a bd','Problemas creando la conexion a bd') + def create_conection_to_db(self): + if __name__ != 'lambda_function': + self.db_connection = connect_to_db_local_dev() + self.db_connection.begin() + return + db_schema = os.environ['DB_SCHEMA'] + secret_db_region = os.environ['SECRET_DB_REGION'] + secret_db_name = os.environ['SECRET_DB_NAME'] + db_secret = get_secret(secret_db_region, secret_db_name) + self.db_connection = connect_to_db(db_schema, db_secret) + + + @handler_wrapper('Adquiriendo raw de clasificaciones','Raw de clasificaciones adquirido con exito','Error adquiriendo raw de clasificaciones','Problemas adquiriendo clasificaciones') + def get_raw_classification(self): + query = """SELECT ID, CLASSIFICATION FROM RAW_CLASSIFICATION""" + logger.info(f"[get_raw_classification] Query a base de datos para obtener el raw de clasificaciones:\n {query}") + rds_data = self.db_connection.execute(text(query)) + self.id_classification_dict = {str(row.ID) : row.CLASSIFICATION for row in rds_data.fetchall()} + + + @handler_wrapper('Obteniendo las fechas del proceso de valoración', 'Fechas del proceso de valroación obtenidas con exito', 'Error obteniendo las fechas del proceso de valoración', 'Error obteniendo fechas del proceso de valoración') + def get_assessment_dates(self): + query = f"SELECT DATES, PROPERTY FROM ASSESSMENT_DATES WHERE ID_ASSESSMENT = {self.id_assessment} ORDER BY DATES" + logger.info(f"[get_assessment_dates] Query a base de datos para obtener las fechas utilizadas en el proces de valoración:\n {query}") + rds_data = self.db_connection.execute(text(query)) + directory = {'HISTORIC': self.historic_dates, 'PROJECTION': self.projection_dates} + for date_item in rds_data.fetchall(): + directory.get(date_item.PROPERTY, []).append(date_item.DATES.strftime('%d-%m-%Y')) #Las self.projection_dates no las estoy usando para nada + + logger.info(f'[get_assessment_dates] Fechas del proceso de valoración:\nhistoricas: {self.historic_dates}\nproyecciones: {self.projection_dates}') + + + @handler_wrapper('Obteniendo valores historicos', 'Valores historicos obtenidos con éxito', 'Error obteniendo los valores historicos', 'Error adquiriendo data historica') + def get_historic_summary_values(self): + query = f"""SELECT C.ID as id_archive, C.INITIAL_DATE, B.CLASSIFICATION, D.ACCOUNT_NAME, A.ANNUALIZED FROM CLASSIFICATION_SUMMARY A, RAW_CLASSIFICATION B, ARCHIVE C, ASSESSMENT_CHECKED D +WHERE A.ID_RAW_CLASSIFICATION = B.ID AND C.ID = A.ID_ARCHIVE AND D.ID_ARCHIVE = C.ID AND D.ID_ASSESSMENT = A.ID_ASSESSMENT AND D.ID_RAW_CLASSIFICATION = A.ID_RAW_CLASSIFICATION +AND A.ID_ASSESSMENT = :id_assessment ORDER BY C.INITIAL_DATE, B.CLASSIFICATION""" #TODO, creo que así pongo un tercer orden por D.ACCOUNT_NUMBER, los pool van a llegar con las cuentas organizadas tambien + + logger.info(f'[get_historic_summary_values] Query para obtener los valores historicos:\n{query}') + rds_data = self.db_connection.execute(text(query), {'id_assessment': self.id_assessment}) + self.historic_values = [item._asdict() for item in rds_data.fetchall()] + for row in self.historic_values: + row['ANNUALIZED'] = float(row['ANNUALIZED']) + + + @handler_wrapper('Construyendo objeto pool', 'Objeto pool construído con éxito', 'Error construyendo objeto pool', 'Error construyendo pool de cuentas') + def build_pool_master(self): + archive_date_dict = {row['id_archive']: row['INITIAL_DATE'] for row in self.historic_values} + for archive, date in archive_date_dict.items(): + archive_pool = {} + for key, searching_classifitcations in self.dropdown_dict.items(): + archive_pool[key] = self.micro_key_pool_builder(archive, searching_classifitcations) + + archive_pool['date'] = date.strftime('%d-%m-%Y') + self.pool_result.append(archive_pool) + + + @debugger_wrapper('Error construyendo una llave de pool', 'Error construyendo pool de cuentas') + def micro_key_pool_builder(self, archive, searching_classifitcations): + key_response = [] + this_key_found_classifications = sorted(set(row['CLASSIFICATION'] for row in self.historic_values if row['CLASSIFICATION'].startswith(tuple(searching_classifitcations)))) + for classificacion in this_key_found_classifications: + names = [row['ACCOUNT_NAME'] for row in self.historic_values if row['CLASSIFICATION'] == classificacion and row['id_archive'] == archive] + total = next(row['ANNUALIZED'] for row in self.historic_values if row['CLASSIFICATION'] == classificacion and row['id_archive'] == archive) + key_response.append({'groupName': classificacion, 'names': names, 'total': total}) + return key_response + + + + @handler_wrapper('Buscando Proyecciones de activos fijos', 'Proyecciones de activos fijos adquiridas con éxito', 'Error adquiriendo proyecciones de activos fijos','Error adquiriendo proyecciones de activos fijos') + def get_assets_projections(self): + query = f"""SELECT A.ID_ITEMS_GROUP, A.PROJECTION_TYPE, A.ASSET_ACCOUNT, A.ACUMULATED_ACCOUNT, A.PERIOD_ACCOUNT, +A.PROJECTED_YEARS, A.CALCULATION_COMMENT, B.PROJECTED_DATE, B.ASSET_VALUE, B.ACUMULATED_VALUE, B.EXISTING_ASSET_VALUE, B.PERIOD_VALUE +FROM FIXED_ASSETS A, PROJECTED_FIXED_ASSETS B WHERE A.ID_ASSESSMENT = :id_assessment +AND A.ID_ASSESSMENT = B.ID_ASSESSMENT AND A.ID_ITEMS_GROUP = B.ID_ITEMS_GROUP ORDER BY B.PROJECTED_DATE""" + + logger.info(f'[get_assets_projections] Query para obtener las caracteristicas de las proyecciones de activos a depreciar: {query}') + rds_data = self.db_connection.execute(text(query), {'id_assessment': self.id_assessment}) + self.projections_found = [item._asdict() for item in rds_data.fetchall()] + for item in self.projections_found: + possible_new_accounts = {item['ASSET_ACCOUNT'], item['ACUMULATED_ACCOUNT'], item['PERIOD_ACCOUNT']} + self.accounts_found.update(possible_new_accounts) #esto no sé para qué lo iba a usar + self.id_items_groups.add(item['ID_ITEMS_GROUP']) + item['PROJECTED_DATE'] = item['PROJECTED_DATE'].strftime('%Y') + item['ASSET_VALUE'] = float(item['ASSET_VALUE']) + item['ACUMULATED_VALUE'] = float(item['ACUMULATED_VALUE']) + item['EXISTING_ASSET_VALUE'] = float(item['EXISTING_ASSET_VALUE']) + item['PERIOD_VALUE'] = float(item['PERIOD_VALUE']) + + + @handler_wrapper('Tabs de proyecciones preconstruidos encontrado, organizando', 'tabs de proyecciones construídos con éxito', 'Error organizando tabs de proyecciones', 'Error organizando tabs de proyecciones') + def organize_retrieve_tab_objects(self): + self.id_items_groups = sorted(self.id_items_groups) + for tab_id in self.id_items_groups: + tab_object = {} + properties_object = next(row for row in self.projections_found if row['ID_ITEMS_GROUP'] == tab_id) + tab_object['dateHistorys'] = self.historic_dates + tab_object['dateProjections'] = [row['PROJECTED_DATE'] for row in self.projections_found if row['ID_ITEMS_GROUP'] == tab_id] + tab_object['dateProjections'][0] = f"Diciembre {tab_object['dateProjections'][0]}" if tab_object['dateProjections'][0] in self.historic_dates[-1] else tab_object['dateProjections'][0] + tab_object['years'] = properties_object['PROJECTED_YEARS'] + tab_object['method'] = properties_object['PROJECTION_TYPE'] + + for key, search_for in self.retrieve_bd_dict.items(): + tab_object[key] = self.id_classification_dict[properties_object[search_for]] + + for key, search_for in self.vectors_directory.items(): + tab_object[key] = self.create_tab_vectors(tab_id, search_for, tab_object) + + self.tabs_result.append(tab_object) + + @debugger_wrapper('Error creando tab', 'Error construyendo una de las pestañas de depreciacion') + def create_tab_vectors(self, tab_id, bd_key_search_for, tab_object): + if bd_key_search_for == 'EXISTING_ASSET_VALUE': + historic_assect_vector = self.create_tab_vectors(tab_id, 'ASSET_VALUE', tab_object)['history'] + historic_acum_vector = self.create_tab_vectors(tab_id, 'ACUMULATED_VALUE', tab_object)['history'] + historic_vector = [i-j for i,j in zip(historic_assect_vector, historic_acum_vector)] + else: + historic_classificacion = tab_object[self.historic_vector_directory[bd_key_search_for]] + historic_vector = {row['id_archive']: row['ANNUALIZED'] for row in self.historic_values if row['CLASSIFICATION'] == historic_classificacion} + historic_vector = list(historic_vector.values()) #Se hace un diccionario con los archives para que me traiga un valor único por archive + + proy_vector = [row[bd_key_search_for] for row in self.projections_found if row['ID_ITEMS_GROUP'] == tab_id] + return {'history': historic_vector, 'projection': proy_vector} + + + @handler_wrapper('Organizando body de respuesta', 'Body de respuesta organizado con éxito', 'Error organizando objeto de respuesta', 'Error organizando respuesta') + def organize_partial_response(self): + self.partial_response = {'data': self.pool_result, 'tabs': self.tabs_result} + + + @debugger_wrapper('Error construyendo respuesta final', 'Error construyendo respuesta') + def response_maker(self, succesfull_run = False, error_str = str()): + if succesfull_run: + self.final_response['statusCode'] = 200 + self.final_response['body'] = json.dumps(self.partial_response) + self.db_connection.commit() if __name__ != 'lambda_function' else None + else: + self.final_response['body'] = json.dumps(self.detailed_raise if self.detailed_raise else error_str) + self.db_connection.rollback() if self.db_connection and __name__ != 'lambda_function' else None + if self.db_connection: + self.db_connection.close() + return self.final_response + + + +def get_current_error_line(): + return str(sys.exc_info()[-1].tb_lineno) + +if __name__ == "__main__": + event = {"pathParameters": {"id_assessment": "2055"}} + lambda_handler(event, '') \ No newline at end of file diff --git a/corporate_finances_back_py/capex-depreciation-items-retrieve/utils.py b/corporate_finances_back_py/capex-depreciation-items-retrieve/utils.py new file mode 100644 index 0000000..3b9134f --- /dev/null +++ b/corporate_finances_back_py/capex-depreciation-items-retrieve/utils.py @@ -0,0 +1,43 @@ +#version 2023 - 05 - 04 +import base64 +import boto3 +import json +import logging +import os +from sqlalchemy import create_engine + +from decorators import handler_wrapper, debugger_wrapper + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + + +@debugger_wrapper('Error al obtener secreto','Error fatal de back conectando a base de datos') +def get_secret(secret_region, secret_name): + session = boto3.session.Session() + client_secrets_manager = session.client(service_name='secretsmanager', region_name=secret_region) + secret_data = client_secrets_manager.get_secret_value(SecretId=secret_name) + if 'SecretString' in secret_data: + secret_str = secret_data['SecretString'] + else: + secret_str = base64.b64decode(secret_data['SecretBinary']) + logger.info('[utils] (get_secret) Se obtuvo el secreto') + return json.loads(secret_str) + + +@debugger_wrapper('Error en la conexion a base de datos','Error fatal de back conectando a base de datos') +def connect_to_db(db_schema, db_secret): + conn_string = ('mysql+mysqlconnector://' + db_secret["username"] + ':' + db_secret["password"] + '@' + db_secret["host"] + ':' + str(db_secret["port"]) + '/' + db_schema) + sql_engine = create_engine(conn_string) + db_connection = sql_engine.connect() + return db_connection + + +@debugger_wrapper('Error en la conexion a base de datos','Error fatal de back conectando a base de datos') +def connect_to_db_local_dev(): + from dotenv import load_dotenv + load_dotenv() + conn_string = os.environ['local_dev_connector'] + sql_engine = create_engine(conn_string) + db_connection = sql_engine.connect() + return db_connection diff --git a/corporate_finances_back_py/capex-depreciation-items-to-db/decorators.py b/corporate_finances_back_py/capex-depreciation-items-to-db/decorators.py new file mode 100644 index 0000000..071760a --- /dev/null +++ b/corporate_finances_back_py/capex-depreciation-items-to-db/decorators.py @@ -0,0 +1,63 @@ +#version 2023 - 05 - 04 +import logging +import sys +import traceback +from functools import wraps +from time import time + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + +def handler_wrapper(start, satisfactory_log, error_log, raise_error): + #esto se ejecuta en la inicializacion de primero + def decorator(func): + #print(message1) + #lo que yo ponga acá se ejecuta antes de hacer el llamado a la funcion + @wraps(func) + def wrapper(*args, **kwargs): + #esto sí se ejecuta solo cuando llama a la funcion decorada + #print(message2) + try: + logger.info(f'[{func.__name__}] {start}...') + resultado = func(*args, **kwargs) + logger.info(f'[{func.__name__}] {satisfactory_log}') + return resultado + except Exception as e: + logger.error(f"[{func.__name__}] {error_log}, linea: {get_especific_error_line(func.__name__)}, motivo: {str(e)}") + raise Exception(f"{raise_error}") + + return wrapper + return decorator + +def debugger_wrapper(error_log, raise_error): + def decorator(func): + @wraps(func) + def wrapper(*args, **kwargs): + try: + resultado = func(*args, **kwargs) + return resultado + except Exception as e: + logger.error(f"[{func.__name__}] {error_log}, linea: {get_especific_error_line(func.__name__)}, motivo: {str(e)}") + raise Exception(f"{raise_error}") + return wrapper + return decorator + + +def get_especific_error_line(func_name): + _, _, exc_tb = sys.exc_info() + for trace in traceback.extract_tb(exc_tb): + if func_name in trace: + return str(trace[1]) + +def timing(f): + @wraps(f) + def wrap(*args, **kw): + ts = time() + result = f(*args, **kw) + te = time() + taken_time_message = '[timing] La funcion {}, toma: {:.2f} sec en ejecutarse'.format(f.__name__, te-ts) + logger.info(taken_time_message) + return result + return wrap + + diff --git a/corporate_finances_back_py/capex-depreciation-items-to-db/lambda_function.py b/corporate_finances_back_py/capex-depreciation-items-to-db/lambda_function.py new file mode 100644 index 0000000..a4ab866 --- /dev/null +++ b/corporate_finances_back_py/capex-depreciation-items-to-db/lambda_function.py @@ -0,0 +1,186 @@ +import json +import logging +import sys +import os +import datetime +import pandas as pd +from sqlalchemy import text + +from decorators import handler_wrapper, timing, debugger_wrapper +from utils import get_secret, connect_to_db, call_dynamic_engine, connect_to_db_local_dev + + +logging.basicConfig() +logging.basicConfig(format='%(asctime)s [%(levelname)s] %(message)s', force=True, datefmt='%Y-%m-%d %H:%M:%S') +logger = logging.getLogger() +logger.setLevel(logging.INFO) + + +def lambda_handler(event,context): + sc_obj = script_object(event) + lambda_response = sc_obj.starter() + logger.info(f'respuesta final de lambda: \n{lambda_response}') + return lambda_response + + +class script_object: + def __init__(self, event): + try: + self.failed_init = False + self.final_response = {'headers':{'Access-Control-Allow-Headers': '*', + 'Access-Control-Allow-Origin': '*', + 'Access-Control-Allow-Methods': '*'}, "statusCode": 500, 'body': {}} + self.db_connection = 0 + self.detailed_raise = '' + self.partial_response = list() + + logger.warning(f'event de entrada: {str(event)}') + + event_dict = json.loads(event['body']) + + self.id_assessment = event_dict['id_assessment'] + self.tabs = event_dict['tabs'] + + self.assets_records = list() + self.projection_records = list() + self.historic_dates = list() + self.projection_dates = list() + self.classification_id_dict = dict() + + + except Exception as e: + logger.error(f'[__init__] Error inicializando objeto lambda, linea: {get_current_error_line()}, motivo: {str(e)}') + self.failed_init = True + + def starter(self): + try: + if self.failed_init: + raise AttributeError('Error con los datos recibidos al servicio') + self.create_conection_to_db() + self.get_raw_classification() + self.get_assessment_dates() + self.assets_safe_delete() + self.organize_assets_tabs() + self.upload_dataframes_to_bd() + call_dynamic_engine(self.id_assessment, __name__) + return self.response_maker(succesfull_run = True) + + except Exception as e: + logger.error(f'[starter] Hubieron problemas en el comando de la linea: {get_current_error_line()}') + return self.response_maker(succesfull_run = False, error_str = (str(e))) + + @handler_wrapper('Creando conexion a bd','Conexion a bd creada con exito','Error en la conexion a bd','Problemas creando la conexion a bd') + def create_conection_to_db(self): + if __name__ != 'lambda_function': + self.db_connection = connect_to_db_local_dev() + self.db_connection.begin() + return + + db_schema = os.environ['DB_SCHEMA'] + secret_db_region = os.environ['SECRET_DB_REGION'] + secret_db_name = os.environ['SECRET_DB_NAME'] + db_secret = get_secret(secret_db_region, secret_db_name) + self.db_connection = connect_to_db(db_schema, db_secret) + + + @handler_wrapper('Adquiriendo raw de clasificaciones','Raw de clasificaciones adquirido con exito','Error adquiriendo raw de clasificaciones','Problemas adquiriendo clasificaciones') + def get_raw_classification(self): + query = """SELECT ID, CLASSIFICATION FROM RAW_CLASSIFICATION""" + logger.info(f"[get_raw_classification] Query a base de datos para obtener el raw de clasificaciones:\n {query}") + rds_data = self.db_connection.execute(text(query)) + self.classification_id_dict = {row.CLASSIFICATION: row.ID for row in rds_data.fetchall()} + + + @handler_wrapper('Obteniendo las fechas del proceso de valoración', 'Fechas del proceso de valroación obtenidas con exito', 'Error obteniendo las fechas del proceso de valoración', 'Error obteniendo fechas del proceso de valoración') + def get_assessment_dates(self): + query = f"SELECT DATES, PROPERTY FROM ASSESSMENT_DATES WHERE ID_ASSESSMENT = {self.id_assessment} ORDER BY DATES" + logger.info(f"[get_assessment_dates] Query a base de datos para obtener las fechas utilizadas en el proces de valoración:\n {query}") + rds_data = self.db_connection.execute(text(query)) + directory = {'HISTORIC': self.historic_dates, 'PROJECTION': self.projection_dates} + for date_item in rds_data.fetchall(): + directory.get(date_item.PROPERTY, []).append(date_item.DATES.strftime('%Y-%m-%d %H:%M:%S')) #Las self.projection_dates no las estoy usando para nada + + logger.info(f'[get_assessment_dates] Fechas del proceso de valoración:\nhistoricas: {self.historic_dates}\nproyecciones: {self.projection_dates}') + + + @handler_wrapper('Borrando información previa en base de datos', 'Borrado exitoso', 'Error intentando eliminar información previa en bd', 'Error borrando información previa en bd') + def assets_safe_delete(self): + query = f'DELETE FROM FIXED_ASSETS WHERE ID_ASSESSMENT = :id_assessment' + logger.info(f'[assets_safe_delete] Query para ELIMINAR información previa en bd:\n{query}') + self.db_connection.execute(text(query), {'id_assessment': self.id_assessment}) + + query = f'DELETE FROM PROJECTED_FIXED_ASSETS WHERE ID_ASSESSMENT = id_assessment' + logger.info(f'[assets_safe_delete] Query para ELIMINAR información previa en bd:\n{query}') + self.db_connection.execute(text(query), {'id_assessment': self.id_assessment}) + + + @handler_wrapper('Construyendo tablas a bd', 'Tablas a bd construídas con exito', 'Error construyendo tablas a bd','Error construyendo tablas a bd') + def organize_assets_tabs(self): + for id_items_group, tab_properties in enumerate(self.tabs): + tab_record = {'ID_ASSESSMENT': self.id_assessment, + 'ID_ITEMS_GROUP': id_items_group, + 'PROJECTION_TYPE': tab_properties['method'], + 'ASSET_ACCOUNT': self.classification_id_dict[tab_properties['fixedAssets']], + 'PERIOD_ACCOUNT': self.classification_id_dict[tab_properties['period']], + 'ACUMULATED_ACCOUNT': self.classification_id_dict[tab_properties['acumulated']], + 'PROJECTED_YEARS': tab_properties['years'], + } + self.assets_records.append(tab_record) + self.create_proyected_records(id_items_group, tab_properties) + + + @debugger_wrapper('Error construyendo records de proyeccion de activos fijos', 'Error construyendo records de guardado') + def create_proyected_records(self, id_items_group, tab_properties): + tab_dates = [self.projection_dates[0]] + first_projection_year = datetime.datetime.strptime(self.projection_dates[0], '%Y-%m-%d %H:%M:%S').replace(day = 1, month = 1) + tab_dates = tab_dates + [first_projection_year.replace(year = first_projection_year.year + year).strftime('%Y-%m-%d %H:%M:%S') for year in range(1, len(tab_properties['grossAssets']['projection']) + 1)] + + for index, proy_dates in enumerate(tab_dates): + try: + proy_record = { + 'ID_ASSESSMENT': self.id_assessment, + 'ID_ITEMS_GROUP': id_items_group, + 'PROJECTED_DATE': proy_dates, + 'ASSET_VALUE': tab_properties['grossAssets']['projection'][index], + 'ACUMULATED_VALUE': tab_properties['depAcumulated']['projection'][index], + 'EXISTING_ASSET_VALUE': tab_properties['activeNeto']['projection'][index], + 'PERIOD_VALUE': tab_properties['depPeriod']['projection'][index], + } + self.projection_records.append(proy_record) + except Exception as e: + logger.error(f'[mira aca] {get_current_error_line()} el objeto es {tab_properties}') + break + + + + @handler_wrapper('Cargando data a bd', 'Data carga a bd', 'Error en la carga de información a bd', 'Error cargando la información a bd') + def upload_dataframes_to_bd(self): + self.assets_records_df = pd.DataFrame.from_records(self.assets_records) + self.projection_records_df = pd.DataFrame.from_records(self.projection_records) + logger.info(f'a guardar en fixed:\n{self.assets_records_df.to_string()}') + logger.info(f'a guardar en projected:\n{self.projection_records_df.to_string()}') + self.assets_records_df.to_sql(name='FIXED_ASSETS', con=self.db_connection, if_exists='append', index=False) + self.projection_records_df.to_sql(name='PROJECTED_FIXED_ASSETS', con=self.db_connection, if_exists='append', index=False) + + + def response_maker(self, succesfull_run = False, error_str = str): + if succesfull_run: + self.final_response['statusCode'] = 200 + self.final_response['body'] = json.dumps('ok') + self.db_connection.commit() if __name__ != 'lambda_function' else None + else: + self.final_response['body'] = json.dumps(self.detailed_raise if self.detailed_raise else error_str) + self.db_connection.rollback() if self.db_connection and __name__ != 'lambda_function' else None + if self.db_connection: + self.db_connection.close() + return self.final_response + + +def get_current_error_line(): + return str(sys.exc_info()[-1].tb_lineno) + + + +if __name__ == "__main__": + event = {'body': '{"id_assessment": 2055, "data": [{"date": "30/03/2024", "fixedAssets": [{"groupName": "Activo Fijo 1", "names": ["Activo Cuenta 1", "Activo Cuenta 2", "Activo Cuenta 3"], "total": 30}], "period": [{"groupName": "Depreciacion del Periodo", "names": ["Depreciacion Periodo Cuenta 1", "Depreciacion Periodo Cuenta 2", "Depreciacion Periodo Cuenta 3"], "total": 30}], "accumulated": [{"groupName": "Depreciacion Acumulada", "names": ["Depreciacion Cuenta 1", "Depreciacion Cuenta 2", "Depreciacion Cuenta 3"], "total": 30}]}, {"date": "30/03/2023", "fixedAssets": [{"groupName": "Activo Fijo 1", "names": ["Daniel", "Hola", "Estas"], "total": 30}], "period": [{"groupName": "Depreciacion del Periodo", "names": ["Jeisson", "Hola", "Esta"], "total": 30}], "accumulated": [{"groupName": "Depreciacion Acumulada", "names": ["Fernando", "Hola", "Esta"], "total": 30}]}], "tabs": [{"fixedAssets": "Propiedad, planta y equipo", "period": "Ingresos operacionales 1", "acumulated": "Gastos operacionales 1", "grossAssets": {"history": [31951.43], "projection": [31951.43, 31951.43, 31951.43, 31951.43, 31951.43]}, "depAcumulated": {"history": [10118.08], "projection": [14484.75, 18851.42, 23218.09, 27584.76, 31951.43]}, "activeNeto": {"history": [21833.35], "projection": [17466.68, 13100.01, 8733.34, 4366.67, 0]}, "depPeriod": {"history": [6286.42], "projection": [4366.67, 4366.67, 4366.67, 4366.67, 4366.67]}, "dateHistorys": ["31-12-2022"], "dateProjections": ["2023", "2024", "2025", "2026", "2027"], "years": 5, "method": "D&A en línea recta"}, {"fixedAssets": "Intangibles", "period": "Ingresos operacionales 2", "acumulated": "Gastos operacionales 2", "grossAssets": {"history": [31951.43], "projection": [31951.43, 31951.43, 31951.43, 31951.43, 31951.43]}, "depAcumulated": {"history": [10118.08], "projection": [14484.75, 18851.42, 23218.09, 27584.76, 31951.43]}, "activeNeto": {"history": [21833.35], "projection": [17466.68, 13100.01, 8733.34, 4366.67, 0]}, "depPeriod": {"history": [6286.42], "projection": [4366.67, 4366.67, 4366.67, 4366.67, 4366.67]}, "dateHistorys": ["31-12-2022"], "dateProjections": ["2023", "2024", "2025", "2026", "2027"], "years": 5, "method": "D&A en línea recta"}]}'} + lambda_handler(event, '') \ No newline at end of file diff --git a/corporate_finances_back_py/capex-depreciation-items-to-db/utils.py b/corporate_finances_back_py/capex-depreciation-items-to-db/utils.py new file mode 100644 index 0000000..f54e168 --- /dev/null +++ b/corporate_finances_back_py/capex-depreciation-items-to-db/utils.py @@ -0,0 +1,60 @@ +#version 2023 - 05 - 04 +import base64 +import boto3 +import json +import logging +import os + +from sqlalchemy import create_engine + +from decorators import handler_wrapper, debugger_wrapper + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + + +@debugger_wrapper('Error al obtener secreto','Error fatal de back conectando a base de datos') +def get_secret(secret_region, secret_name): + session = boto3.session.Session() + client_secrets_manager = session.client(service_name='secretsmanager', region_name=secret_region) + secret_data = client_secrets_manager.get_secret_value(SecretId=secret_name) + if 'SecretString' in secret_data: + secret_str = secret_data['SecretString'] + else: + secret_str = base64.b64decode(secret_data['SecretBinary']) + logger.info('[utils] (get_secret) Se obtuvo el secreto') + return json.loads(secret_str) + + +@debugger_wrapper('Error en la conexion a base de datos','Error fatal de back conectando a base de datos') +def connect_to_db(db_schema, db_secret): + conn_string = ('mysql+mysqlconnector://' + db_secret["username"] + ':' + db_secret["password"] + '@' + db_secret["host"] + ':' + str(db_secret["port"]) + '/' + db_schema) + sql_engine = create_engine(conn_string) + db_connection = sql_engine.connect() + return db_connection + + + +@handler_wrapper('Invocando asincronamente a Engine de dinamismo', 'Invocación a Engine exitosa', 'Error invocando a Engine', 'Error invocando dinamismo') +def call_dynamic_engine(id_assessment, context): + if context == 'lambda_function': + lambda_engine = os.environ['LAMBDA_ENGINE'] + data = json.dumps({'id_assessment':id_assessment}).encode() + client = boto3.client('lambda') + response = client.invoke( + FunctionName=lambda_engine, + InvocationType='Event', + Payload= data + ) + else: + logger.warning('[call_dynamic_engine] no se ejecuta engine ya que el contexto es local') + + +@debugger_wrapper('Error en la conexion a base de datos','Error fatal de back conectando a base de datos') +def connect_to_db_local_dev(): + from dotenv import load_dotenv + load_dotenv() + conn_string = os.environ['local_dev_connector'] + sql_engine = create_engine(conn_string) + db_connection = sql_engine.connect() + return db_connection diff --git a/corporate_finances_back_py/capex-depreciation-items/decorators.py b/corporate_finances_back_py/capex-depreciation-items/decorators.py new file mode 100644 index 0000000..071760a --- /dev/null +++ b/corporate_finances_back_py/capex-depreciation-items/decorators.py @@ -0,0 +1,63 @@ +#version 2023 - 05 - 04 +import logging +import sys +import traceback +from functools import wraps +from time import time + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + +def handler_wrapper(start, satisfactory_log, error_log, raise_error): + #esto se ejecuta en la inicializacion de primero + def decorator(func): + #print(message1) + #lo que yo ponga acá se ejecuta antes de hacer el llamado a la funcion + @wraps(func) + def wrapper(*args, **kwargs): + #esto sí se ejecuta solo cuando llama a la funcion decorada + #print(message2) + try: + logger.info(f'[{func.__name__}] {start}...') + resultado = func(*args, **kwargs) + logger.info(f'[{func.__name__}] {satisfactory_log}') + return resultado + except Exception as e: + logger.error(f"[{func.__name__}] {error_log}, linea: {get_especific_error_line(func.__name__)}, motivo: {str(e)}") + raise Exception(f"{raise_error}") + + return wrapper + return decorator + +def debugger_wrapper(error_log, raise_error): + def decorator(func): + @wraps(func) + def wrapper(*args, **kwargs): + try: + resultado = func(*args, **kwargs) + return resultado + except Exception as e: + logger.error(f"[{func.__name__}] {error_log}, linea: {get_especific_error_line(func.__name__)}, motivo: {str(e)}") + raise Exception(f"{raise_error}") + return wrapper + return decorator + + +def get_especific_error_line(func_name): + _, _, exc_tb = sys.exc_info() + for trace in traceback.extract_tb(exc_tb): + if func_name in trace: + return str(trace[1]) + +def timing(f): + @wraps(f) + def wrap(*args, **kw): + ts = time() + result = f(*args, **kw) + te = time() + taken_time_message = '[timing] La funcion {}, toma: {:.2f} sec en ejecutarse'.format(f.__name__, te-ts) + logger.info(taken_time_message) + return result + return wrap + + diff --git a/corporate_finances_back_py/capex-depreciation-items/lambda_function.py b/corporate_finances_back_py/capex-depreciation-items/lambda_function.py new file mode 100644 index 0000000..4ef02a7 --- /dev/null +++ b/corporate_finances_back_py/capex-depreciation-items/lambda_function.py @@ -0,0 +1,145 @@ +import json +import logging +import sys +import os +from datetime import datetime + +from decorators import handler_wrapper, timing, debugger_wrapper +from utils import get_secret, connect_to_db + + +#logging.basicConfig() #En lambdas borra este + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + +############################################ +### CANDIDATO A DEPRECIACION POR HU 4095 ### +############################################ + +def lambda_handler(event,context): + sc_obj = script_object(event) + lambda_response = sc_obj.starter() + logger.info(f'respuesta final de lambda: \n{lambda_response}') + return lambda_response + + +class script_object: + def __init__(self, event): + try: + self.failed_init = False + self.final_response = {'headers':{'Access-Control-Allow-Headers': '*', + 'Access-Control-Allow-Origin': '*', + 'Access-Control-Allow-Methods': '*'}, "statusCode": 500, 'body': {}} + self.db_connection = 0 + self.detailed_raise = '' + self.partial_response = {} + + logger.warning(f'event de entrada: {str(event)}') + + event_dict = event['pathParameters'] + self.id_assessment = event_dict['id_assessment'] + + + self.drop_list_directory = {'gross_assestment_items': ["Propiedad, planta y equipo","Intangibles"], + 'period_depreciation_items':["Depreciación del periodo", "Amortización del periodo"], + 'acumulated_depreciation_items': ['Depreciación acumulada','Amortización acumulada']} + + self.drops_sets_list = dict() + + self.all_archives_ids = list() + self.items_pool = list() + self.historic_dates = list() + self.short_dates = list() + self.archives_ids = list() + self.cleaned_items_pool = list() + + + except Exception as e: + logger.error(f'[__init__] Error inicializando objeto lambda, linea: {get_current_error_line()}, motivo: {str(e)}') + self.failed_init = True + + def starter(self): + try: + if self.failed_init: + raise AttributeError('Error con los datos recibidos al servicio') + + self.create_conection_to_db() + self.get_user_classificated_data() + self.filter_drop_down_pools() + self.clearing_objects_pool() + self.organize_final_response() + return self.response_maker(succesfull_run = True) + + except Exception as e: + logger.error(f'[starter] Hubieron problemas en el comando de la linea: {get_current_error_line()}') + return self.response_maker(succesfull_run = False, error_str = (str(e))) + + @handler_wrapper('Creando conexion a bd','Conexion a bd creada con exito','Error en la conexion a bd','Problemas creando la conexion a bd') + def create_conection_to_db(self): + db_schema = os.environ['DB_SCHEMA'] + secret_db_region = os.environ['SECRET_DB_REGION'] + secret_db_name = os.environ['SECRET_DB_NAME'] + db_secret = get_secret(secret_db_region, secret_db_name) + self.db_connection = connect_to_db(db_schema, db_secret) + + + @handler_wrapper('Buscando clasificacion master manual', 'Master asignado correctamente', 'Error adquiriendo master de clasificacion','Error adquiriendo clasificacion de analista') + def get_user_classificated_data(self): + classifications_to_search_for = [] + list(map(lambda values: classifications_to_search_for.extend(values), self.drop_list_directory.values())) + + query = f"""SELECT C.INITIAL_DATE AS date, C.ID, B.CLASSIFICATION, A.ACCOUNT_NUMBER, A.ACCOUNT_NAME, A.ANNUALIZED, A.HINT +FROM ASSESSMENT_CHECKED A, RAW_CLASSIFICATION B, ARCHIVE C +WHERE A.ID_ARCHIVE = C.ID AND A.ID_RAW_CLASSIFICATION = B.ID +AND A.ID_ASSESSMENT = {self.id_assessment} AND B.CLASSIFICATION IN {tuple(classifications_to_search_for)} +ORDER BY C.INITIAL_DATE""" + + logger.info(f'[get_user_classificated_data] Query para obtener los pasos completados del proceso de valoracion:\n{query}') + rds_data = self.db_connection.execute(query) + self.items_pool = [item._asdict() for item in rds_data.fetchall()] + for item in self.items_pool: + item['ANNUALIZED'] = float(item['ANNUALIZED']) + if item['ID'] not in self.archives_ids: + self.archives_ids.append(item['ID']) + self.historic_dates.append(item['date']) + self.short_dates.append(item['date'].strftime('%d-%m-%Y')) + + logger.info(f'[get_user_classificated_data] Fechas historicas encontradas: {self.historic_dates}') + logger.info(f'[get_user_classificated_data] archives historicos encontrados: {self.archives_ids}') + + + @handler_wrapper('Creando pool filtrado de listas desplegazbles','filtrado completado','Error filtrando ','Error obteniendo Pucs') + def filter_drop_down_pools(self): + for drop_name, classifications in self.drop_list_directory.items(): + self.drops_sets_list[drop_name] = [{'name': item['ACCOUNT_NAME'], 'account':item['ACCOUNT_NUMBER']} for item in self.items_pool if (item['CLASSIFICATION'] in classifications) and (item['ID'] == self.archives_ids[-1])] + logger.info(f'[filter_drop_down_pools] Items encontrados para el drop down {drop_name}:\n{self.drops_sets_list[drop_name]}') + + @handler_wrapper('Organizando pool de items', 'Pool de items organizado con exito', 'Error organizando pool de items', 'Error organizando pool de items') + def clearing_objects_pool(self): + for item in self.items_pool: + this_item_date = item['date'].strftime('%d-%m-%Y') + self.cleaned_items_pool.append({'account': item['ACCOUNT_NUMBER'], 'date': this_item_date, 'value': item['ANNUALIZED'], 'classification': item['CLASSIFICATION']}) + + @handler_wrapper('Organizando respuesta final', 'Respuesta de lambda organizada con exito', 'Error organizando respuesta de lambda', 'Error organizando respuesta') + def organize_final_response(self): + self.partial_response = {'dates': self.short_dates, **self.drops_sets_list, 'pool': self.cleaned_items_pool} + + + @debugger_wrapper('Error construyendo respuesta final', 'Error construyendo respuesta') + def response_maker(self, succesfull_run = False, error_str = str()): + if self.db_connection: + self.db_connection.close() + if succesfull_run: + self.final_response['statusCode'] = 200 + self.final_response['body'] = json.dumps(self.partial_response) + return self.final_response + + self.final_response['body'] = json.dumps(self.detailed_raise if self.detailed_raise else error_str) + return self.final_response + + + +def get_current_error_line(): + return str(sys.exc_info()[-1].tb_lineno) + \ No newline at end of file diff --git a/corporate_finances_back_py/capex-depreciation-items/utils.py b/corporate_finances_back_py/capex-depreciation-items/utils.py new file mode 100644 index 0000000..9efbdea --- /dev/null +++ b/corporate_finances_back_py/capex-depreciation-items/utils.py @@ -0,0 +1,33 @@ +#version 2023 - 05 - 04 +import base64 +import boto3 +import json +import logging + +from sqlalchemy import create_engine + +from decorators import handler_wrapper, debugger_wrapper + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + + +@debugger_wrapper('Error al obtener secreto','Error fatal de back conectando a base de datos') +def get_secret(secret_region, secret_name): + session = boto3.session.Session() + client_secrets_manager = session.client(service_name='secretsmanager', region_name=secret_region) + secret_data = client_secrets_manager.get_secret_value(SecretId=secret_name) + if 'SecretString' in secret_data: + secret_str = secret_data['SecretString'] + else: + secret_str = base64.b64decode(secret_data['SecretBinary']) + logger.info('[utils] (get_secret) Se obtuvo el secreto') + return json.loads(secret_str) + + +@debugger_wrapper('Error en la conexion a base de datos','Error fatal de back conectando a base de datos') +def connect_to_db(db_schema, db_secret): + conn_string = ('mysql+mysqlconnector://' + db_secret["username"] + ':' + db_secret["password"] + '@' + db_secret["host"] + ':' + str(db_secret["port"]) + '/' + db_schema) + sql_engine = create_engine(conn_string) + db_connection = sql_engine.connect() + return db_connection \ No newline at end of file diff --git a/corporate_finances_back_py/capex-summary-retrieve/decorators.py b/corporate_finances_back_py/capex-summary-retrieve/decorators.py new file mode 100644 index 0000000..071760a --- /dev/null +++ b/corporate_finances_back_py/capex-summary-retrieve/decorators.py @@ -0,0 +1,63 @@ +#version 2023 - 05 - 04 +import logging +import sys +import traceback +from functools import wraps +from time import time + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + +def handler_wrapper(start, satisfactory_log, error_log, raise_error): + #esto se ejecuta en la inicializacion de primero + def decorator(func): + #print(message1) + #lo que yo ponga acá se ejecuta antes de hacer el llamado a la funcion + @wraps(func) + def wrapper(*args, **kwargs): + #esto sí se ejecuta solo cuando llama a la funcion decorada + #print(message2) + try: + logger.info(f'[{func.__name__}] {start}...') + resultado = func(*args, **kwargs) + logger.info(f'[{func.__name__}] {satisfactory_log}') + return resultado + except Exception as e: + logger.error(f"[{func.__name__}] {error_log}, linea: {get_especific_error_line(func.__name__)}, motivo: {str(e)}") + raise Exception(f"{raise_error}") + + return wrapper + return decorator + +def debugger_wrapper(error_log, raise_error): + def decorator(func): + @wraps(func) + def wrapper(*args, **kwargs): + try: + resultado = func(*args, **kwargs) + return resultado + except Exception as e: + logger.error(f"[{func.__name__}] {error_log}, linea: {get_especific_error_line(func.__name__)}, motivo: {str(e)}") + raise Exception(f"{raise_error}") + return wrapper + return decorator + + +def get_especific_error_line(func_name): + _, _, exc_tb = sys.exc_info() + for trace in traceback.extract_tb(exc_tb): + if func_name in trace: + return str(trace[1]) + +def timing(f): + @wraps(f) + def wrap(*args, **kw): + ts = time() + result = f(*args, **kw) + te = time() + taken_time_message = '[timing] La funcion {}, toma: {:.2f} sec en ejecutarse'.format(f.__name__, te-ts) + logger.info(taken_time_message) + return result + return wrap + + diff --git a/corporate_finances_back_py/capex-summary-retrieve/lambda_function.py b/corporate_finances_back_py/capex-summary-retrieve/lambda_function.py new file mode 100644 index 0000000..ec95330 --- /dev/null +++ b/corporate_finances_back_py/capex-summary-retrieve/lambda_function.py @@ -0,0 +1,358 @@ +import json +import logging +import sys +import os + +from sqlalchemy import text + +from decorators import handler_wrapper, timing, debugger_wrapper +from utils import get_secret, connect_to_db, connect_to_db_local_dev + +logging.basicConfig() +logging.basicConfig(format='%(asctime)s [%(levelname)s] [%(module)s] %(message)s', force=True, datefmt='%Y-%m-%d %H:%M:%S') +logger = logging.getLogger() +logger.setLevel(logging.INFO) + +def lambda_handler(event,context): + sc_obj = script_object(event) + lambda_response = sc_obj.starter() + logger.info(f'respuesta final de lambda: \n{lambda_response}') + return lambda_response + + +class script_object: + def __init__(self, event): + try: + self.failed_init = False + self.final_response = {'headers':{'Access-Control-Allow-Headers': '*', + 'Access-Control-Allow-Origin': '*', + 'Access-Control-Allow-Methods': '*'}, "statusCode": 500, 'body': {}} + self.db_connection = 0 + self.detailed_raise = '' + self.partial_response = list() + + logger.warning(f'event de entrada: {str(event)}') + + event_dict = event['pathParameters'] + self.id_assessment = event_dict['id_assessment'] + + self.organizer_directory = {'Ingresos operacionales':'OPERATIONAL_INCOME', + 'Activos existentes brutos':'EXISTING_ASSETS', + 'CAPEX':'CAPEX', + 'Depreciación Capex':'NEW_CAPEX', + 'Depreciación del periodo': 'PERIOD_DEPRECIATION', + 'Amortización del periodo':'PERIOD_AMORTIZATION', + 'Depreciación acumulada':'ACUMULATED_DEPRECIATION', + 'Amortización acumulada':'ACUMULATED_AMORTIZATION', + } + + ####################################### + self.summary_supplies = ['Ingresos operacionales', 'Propiedad, planta y equipo', 'Intangibles', 'Depreciación del periodo', 'Amortización del periodo', 'Depreciación acumulada', 'Amortización acumulada'] + + self.summary_order = {'Ingresos operacionales': self.organize_operational_income, + 'Activos existentes brutos': self.organize_assets, + 'CAPEX': self.organize_capex_line, + 'Depreciación Capex': self.organize_new_capex_line, + 'Depreciación del periodo': self.organize_dep_amrtz, + 'Amortización del periodo': self.organize_dep_amrtz, + 'Depreciación acumulada': self.organize_dep_amrtz, + 'Amortización acumulada': self.organize_dep_amrtz} + + self.period_classifications = ['Depreciación del periodo', 'Amortización del periodo'] + self.acumulated_classifications = ['Depreciación acumulada', 'Amortización acumulada'] + summary_classifications = self.period_classifications + self.acumulated_classifications + self.dep_amrtz_data = {item: [] for item in summary_classifications} + ######################################## + + + self.historic_dates = list() + self.projection_dates = list() + self.summary_results = list() + + + self.summary_data_found = list() + self.historic_dates = list() + self.operational_income_projections = list() + self.historic_data = dict() + self.proyection_dates = list() + self.existant_assets_proyections = list() + self.capex_summary_results = list() + self.response_data = list() + + self.found_tabs = bool() + self.found_new_capex = bool() + + except Exception as e: + logger.error(f'[__init__] Error inicializando objeto lambda, linea: {get_current_error_line()}, motivo: {str(e)}') + self.failed_init = True + + def starter(self): + try: + if self.failed_init: + raise AttributeError('Error con los datos recibidos al servicio') + self.create_conection_to_db() + self.get_assessment_dates() + self.get_summary_results() + self.organize_response_data() + if not self.summary_results: + self.get_historic_summary_data() + self.organize_historic_rows() + self.get_operational_income_projections() + self.get_dep_amrtz_projections() + self.organize_dep_amrtz_projections() + self.organize_assets_projections() + self.get_capex_results() + self.organize_summary() + + return self.response_maker(succesfull_run = True) + + except Exception as e: + logger.error(f'[starter] Hubieron problemas en el comando de la linea: {get_current_error_line()}') + return self.response_maker(succesfull_run = False, error_str = (str(e))) + + @handler_wrapper('Creando conexion a bd','Conexion a bd creada con exito','Error en la conexion a bd','Problemas creando la conexion a bd') + def create_conection_to_db(self): + if __name__ != 'lambda_function': + self.db_connection = connect_to_db_local_dev() + return + db_schema = os.environ['DB_SCHEMA'] + secret_db_region = os.environ['SECRET_DB_REGION'] + secret_db_name = os.environ['SECRET_DB_NAME'] + db_secret = get_secret(secret_db_region, secret_db_name) + self.db_connection = connect_to_db(db_schema, db_secret) + + + @handler_wrapper('Obteniendo las fechas del proceso de valoración', 'Fechas del proceso de valroación obtenidas con exito', 'Error obteniendo las fechas del proceso de valoración', 'Error obteniendo fechas del proceso de valoración') + def get_assessment_dates(self): + query = f"SELECT DATES, PROPERTY FROM ASSESSMENT_DATES WHERE ID_ASSESSMENT = {self.id_assessment} ORDER BY DATES" + logger.info(f"[get_assessment_dates] Query a base de datos para obtener las fechas utilizadas en el proces de valoración:\n {query}") + rds_data = self.db_connection.execute(text(query)) + directory = {'HISTORIC': {'vector': self.historic_dates, 'out_fmt': '%d-%m-%Y'}, 'PROJECTION': {'vector': self.projection_dates, 'out_fmt': '%Y'}} + for date_item in rds_data.fetchall(): + directory[date_item.PROPERTY]['vector'].append(date_item.DATES.strftime(directory[date_item.PROPERTY]['out_fmt'])) #Las self.projection_dates no las estoy usando para nada + + logger.info(f'[get_assessment_dates] Fechas del proceso de valoración:\nhistoricas: {self.historic_dates}\nproyecciones: {self.projection_dates}') + + + @handler_wrapper('Obteniendo los resultados de capex summary', 'Resultados de capex summary obtenidos con exito', 'Error obteniendo resultados de capex summary', 'Error obteniendo resultados de capex summary') + def get_summary_results(self): + query = """SELECT OPERATIONAL_INCOME, EXISTING_ASSETS, CAPEX, PERIOD_DEPRECIATION, PERIOD_AMORTIZATION, ACUMULATED_DEPRECIATION, +ACUMULATED_AMORTIZATION, NEW_CAPEX FROM CAPEX_SUMMARY WHERE ID_ASSESSMENT = :id_assessment ORDER BY SUMMARY_DATE""" + logger.info(f"[get_summary_results] Query a base de datos para obtener los resultados de summary:\n {query}") + rds_data = self.db_connection.execute(text(query), {'id_assessment': self.id_assessment}) + self.summary_results = [row._asdict() for row in rds_data.fetchall()] + for row in self.summary_results: + row['OPERATIONAL_INCOME'] = float(row['OPERATIONAL_INCOME']) + row['EXISTING_ASSETS'] = float(row['EXISTING_ASSETS']) + row['CAPEX'] = float(row['CAPEX']) + row['PERIOD_DEPRECIATION'] = float(row['PERIOD_DEPRECIATION']) + row['PERIOD_AMORTIZATION'] = float(row['PERIOD_AMORTIZATION']) + row['ACUMULATED_DEPRECIATION'] = float(row['ACUMULATED_DEPRECIATION']) + row['ACUMULATED_AMORTIZATION'] = float(row['ACUMULATED_AMORTIZATION']) + row['NEW_CAPEX'] = float(row['NEW_CAPEX']) + + logger.info(f'[summary_results] summary encontrado: {self.summary_results}') + + + @handler_wrapper('Construyendo objeto data de respuesta', 'Data de respesta construída con éxito', 'Error construyendo objeto data de respuesta', 'Error organizando data de summary') + def organize_response_data(self): + data_response = [] + for key, search_for in self.organizer_directory.items(): + row_data = {'name': key} + row_data['values'] = self.create_values_object(search_for) + data_response.append(row_data) + + self.projection_dates[0] = f'Diciembre {self.projection_dates[0]}' if self.projection_dates[0] in self.historic_dates[-1] else self.projection_dates[0] + self.partial_response = {'data': data_response, 'datesHistory': self.historic_dates, 'dateProjection': self.projection_dates} + + + debugger_wrapper('Error creando micro objeto de summary', 'Error acomodando lineas de capex summary') + def create_values_object(self, search_for): + full_vector = [row[search_for] for row in self.summary_results] + if len(full_vector) < (len(self.historic_dates) + len(self.projection_dates)): + return {'history' : full_vector[:len(self.historic_dates)]} + return {'history' : full_vector[:len(self.historic_dates)], 'projection': full_vector[len(self.historic_dates):]} + + + @debugger_wrapper('Error construyendo respuesta final', 'Error construyendo respuesta') + def response_maker(self, succesfull_run = False, error_str = str()): + if succesfull_run: + self.final_response['statusCode'] = 200 + self.final_response['body'] = json.dumps(self.partial_response) + else: + self.final_response['body'] = json.dumps(self.detailed_raise if self.detailed_raise else error_str) + if self.db_connection: + self.db_connection.close() + return self.final_response + + + + @handler_wrapper('Buscando caracteristicas de capex existente', 'Caracteristicas de capex encontradas', 'Error adquiriendo caracteristicas capex','Error adquiriendo capex') + def get_historic_summary_data(self): + query = f"""SELECT D.INITIAL_DATE AS date, B.CLASSIFICATION, A.ANNUALIZED +FROM CLASSIFICATION_SUMMARY A, RAW_CLASSIFICATION B, ARCHIVE D +WHERE A.ID_RAW_CLASSIFICATION = B.ID AND A.ID_ARCHIVE = D.ID +AND ID_ASSESSMENT = {self.id_assessment} AND B.CLASSIFICATION IN ({str(self.summary_supplies).replace('[','').replace(']','')}) +ORDER BY D.INITIAL_DATE""" + + logger.info(f'[get_capex_data] Query para obtener summaries de clasificacion:\n{query}') + rds_data = self.db_connection.execute(text(query)) + self.summary_data_found = [item._asdict() for item in rds_data.fetchall()] + + for row in self.summary_data_found: + row['ANNUALIZED'] = float(row['ANNUALIZED']) + row['date'] = row['date'].strftime('%d-%m-%Y') + if row['date'] not in self.historic_dates: + self.historic_dates.append(row['date']) + + logger.info(f'[get_historic_summary_data] Fechas historicas encontradas: {self.historic_dates}') + + + @handler_wrapper('Separando fechas historicas de proyecciones', 'Fechas separadas con exito', 'Error separando fechas historicas de proyecciones', 'Error acomodando datos') + def organize_historic_rows(self): + for classification in self.summary_order: + self.historic_data[classification] = [item['ANNUALIZED'] for item in self.summary_data_found if item['CLASSIFICATION'] == classification] + + items_ppe = [item['ANNUALIZED'] for item in self.summary_data_found if item['CLASSIFICATION'] == 'Propiedad, planta y equipo'] + items_itb = [item['ANNUALIZED'] for item in self.summary_data_found if item['CLASSIFICATION'] == 'Intangibles'] + + items_ppe = items_ppe if items_ppe else [0] * len(self.historic_dates) + items_itb = items_itb if items_itb else [0] * len(self.historic_dates) + + self.historic_data['Activos existentes brutos'] = [i+j for i,j in zip(items_ppe, items_itb)] + logger.info(f'[organize_historic_rows] Data historica lista para requerirse: \n{self.historic_data}') + + + @handler_wrapper('Buscando proyecciones de ingresos operacionales', 'Proyecciones encontradas con exito', 'Error adquiriendo proyecciones de ingresos operacionales', 'Error adquiriendo proyecciones de ingresos operacionales') + def get_operational_income_projections(self): + query = f"""SELECT A.PROJECTED_DATE AS proy_date, A.VALUE FROM PROJECTED_PYG A, RAW_PYG B WHERE A.ID_RAW_PYG = B.ID +AND A.ID_ASSESSMENT = {self.id_assessment} AND B.PYG_ITEM_NAME = "Ingresos operacionales" ORDER BY A.PROJECTED_DATE""" + + logger.info(f'[get_operational_income_projections] Query para obtener proyecciones de ingresos operacionales:\n{query}') + rds_data = self.db_connection.execute(text(query)) + operational_income_projections_data = [item._asdict() for item in rds_data.fetchall()] + self.operational_income_projections = [float(item['VALUE']) for item in operational_income_projections_data] + self.proyection_dates = [item['proy_date'].strftime('%d-%m-%Y') for item in operational_income_projections_data] + + logger.info(f'[get_operational_income_projections] proyecciones de ingresos operacionales encontradas: {self.operational_income_projections}') + + + @handler_wrapper('Capex antiguo encontrado, organizando respuesta', 'Respuesta de lambda construída', 'Error construyendo respuesta de lambda', 'Error construyendo respuesta') + def get_dep_amrtz_projections(self): + query = f"""SELECT A.ID_ITEMS_GROUP, A.PROJECTED_DATE AS proy_date, A.ASSET_VALUE, A.ACUMULATED_VALUE, A.EXISTING_ASSET_VALUE, A.PERIOD_VALUE, C.ACCOUNT_NUMBER, D.CLASSIFICATION +FROM PROJECTED_FIXED_ASSETS A, FIXED_ASSETS B, ASSESSMENT_CHECKED C, RAW_CLASSIFICATION D, ASSESSMENT E +WHERE A.ID_ASSESSMENT = B.ID_ASSESSMENT AND A.ID_ASSESSMENT = C.ID_ASSESSMENT AND A.ID_ASSESSMENT = E.ID +AND A.ID_ASSESSMENT = {self.id_assessment} +AND A.ID_ITEMS_GROUP = B.ID_ITEMS_GROUP AND E.ID_ARCHIVE = C.ID_ARCHIVE AND C.ID_RAW_CLASSIFICATION = D.ID +AND (B.ASSET_ACCOUNT = D.ID OR B.ACUMULATED_ACCOUNT = D.ID OR B.PERIOD_ACCOUNT = D.ID) +ORDER BY A.ID_ITEMS_GROUP, A.PROJECTED_DATE +""" + + logger.info(f'[get_dep_amrtz_projections] Query para obtener proyecciones de activos fijos:\n{query}') + rds_data = self.db_connection.execute(text(query)) + self.assets_projections = [item._asdict() for item in rds_data.fetchall()] + logger.info(f'[get_dep_amrtz_projections] proyecciones de activos fijos encontradas:\n{self.assets_projections}') + for row in self.assets_projections: + self.found_tabs = True + row['ASSET_VALUE'] = float(row['ASSET_VALUE']) + row['ACUMULATED_VALUE'] = float(row['ACUMULATED_VALUE']) + row['EXISTING_ASSET_VALUE'] = float(row['EXISTING_ASSET_VALUE']) + row['PERIOD_VALUE'] = float(row['PERIOD_VALUE']) + + row['proy_date'] = row['proy_date'].strftime('%d-%m-%Y') + + + @handler_wrapper('Organizando proyecciones de assets', 'Proyecciones de assets organizadas con exito', 'Error organizando proyecciones de assets', 'Error sumarizando proyecciones de activos fijos') + def organize_dep_amrtz_projections(self): + + for proy_date in self.proyection_dates: + for classification in self.period_classifications: + filtered_items = [item for item in self.assets_projections if (item['proy_date'] == proy_date and item['CLASSIFICATION'] == classification)] + total_period = sum(item['PERIOD_VALUE'] for item in filtered_items) + + logger.info(f"""[organize_dep_amrtz_projections] items Filtrados para la clasificacion: {classification} en la fecha {proy_date}:\n{filtered_items}\n\ + total amortizacion/depreciacion del periodo:{total_period}""") + + self.dep_amrtz_data[classification].append(total_period) + + for classification in self.acumulated_classifications: + filtered_items = [item for item in self.assets_projections if (item['proy_date'] == proy_date and item['CLASSIFICATION'] == classification)] + total_acumluated = sum(item['ACUMULATED_VALUE'] for item in filtered_items) + + logger.info(f"""[organize_dep_amrtz_projections] items Filtrados para la clasificacion: {classification} en la fecha {proy_date}:\n{filtered_items}\n\ + total amortizacion/depreciacion acumulada:{total_acumluated}""") + + self.dep_amrtz_data[classification].append(total_acumluated) + + logger.warning(f'[organize_dep_amrtz_projections] Objeto final de depreciacion y amortización proyectada por pestañas de activos fijos:\n{self.dep_amrtz_data}') + + @handler_wrapper('Organizando proyecciones de activos fijos', 'Proyecciones de activos fijos organizadas', 'Error organizando proyeccionesde activos fijos', 'Error organizando calculos de activos fijos') + def organize_assets_projections(self): + for proy_date in self.proyection_dates: + self.existant_assets_proyections.append(sum(set(item['ASSET_VALUE'] for item in self.assets_projections if item['proy_date'] == proy_date))) + logger.info(f'[organize_assets_projections] Proyecciones encontradas para los assets de las tarjetas de depreciacion: {self.existant_assets_proyections}') + + @handler_wrapper('Adquiriendo los resultados de capex', 'Resultados de capex obtenidos con exito', 'Error adquiriendo los resultados de capex', 'Error re adquiriendo capex') + def get_capex_results(self): + query = f"SELECT CAPEX_SUMMARY, CAPEX_ACUMULATED FROM CAPEX_VALUES WHERE ID_ASSESSMENT = {self.id_assessment} ORDER BY CALCULATED_DATE" + logger.info(f'[get_capex_results] Query para obtener los valores calculados de capex:\n{query}') + rds_data = self.db_connection.execute(text(query)) + capex_results = [item._asdict() for item in rds_data.fetchall()] + self.capex_summary_results = [float(item['CAPEX_SUMMARY']) for item in capex_results] + self.new_capex_summary_results = [float(item['CAPEX_ACUMULATED']) for item in capex_results] + logger.info(f'[get_capex_results] Valores calculados de capex encontrados:\n**Antiguo capex\n**{self.capex_summary_results}\n\n**Nuevo capex acumulado\n**{self.new_capex_summary_results}') + if self.capex_summary_results: + self.found_new_capex = True + + @handler_wrapper('Organizando summary para muestra en front', 'Summary organizado correctamente', 'Error organizando summary', 'Error organizando salida a front') + def organize_summary(self): + for row_summary, function in self.summary_order.items(): + created_row = function(row_summary) + if not created_row: + continue + self.response_data.append(created_row) + projection_dates_short = [date.split('-')[-1] for date in self.proyection_dates] + + projection_dates_short[0] = projection_dates_short[0] if '-12-' in self.historic_dates[-1] else f'Diciembre {projection_dates_short[0]}' #Se agrega esta linea para que llegue diciembre con formato de anualización a front + + self.partial_response = {'data': self.response_data, 'datesHistory': self.historic_dates, 'dateProjection': projection_dates_short} + if not self.found_tabs and not self.found_new_capex: + self.partial_response['dateProjection'] = [] + for item in self.partial_response['data']: + item['values']['projection'] = [] + + + @debugger_wrapper('Error organizando row de ingreso operacional', 'Error organizando summary de ingreso operacional') + def organize_operational_income(self, name): + return {'name': name, 'values': {'history': self.historic_data['Ingresos operacionales'], 'projection': self.operational_income_projections}} + + + @debugger_wrapper('Error organizando row de ingreso operacional', 'Error organizando summary de ingreso operacional') + def organize_assets(self, name): + return {'name': name, 'values': {'history': self.historic_data['Activos existentes brutos'], 'projection': self.existant_assets_proyections}} + + + @debugger_wrapper('Error organizando row de ingreso operacional', 'Error organizando summary de ingreso operacional') + def organize_capex_line(self, name): + if not self.capex_summary_results: + return None + return {'name': name, 'values': {'history': self.capex_summary_results[:len(self.historic_dates)], 'projection': self.capex_summary_results[len(self.historic_dates):]}} + + @debugger_wrapper('Error organizando row de ingreso operacional', 'Error organizando summary de ingreso operacional') + def organize_new_capex_line(self, name): + if not self.new_capex_summary_results: + return None + return {'name': name, 'values': {'history': self.new_capex_summary_results[:len(self.historic_dates)], 'projection': self.new_capex_summary_results[len(self.historic_dates):]}} + + @debugger_wrapper('Error organizando row de ingreso operacional', 'Error organizando summary de ingreso operacional') + def organize_dep_amrtz(self, name): + historic_array = self.historic_data[name] if self.historic_data[name] else [0] * len(self.historic_dates) + return {'name': name, 'values': {'history': historic_array, 'projection': self.dep_amrtz_data[name]}} + + +def get_current_error_line(): + return str(sys.exc_info()[-1].tb_lineno) + +if __name__ == "__main__": + event = {"pathParameters": {"id_assessment": "2065"}} + lambda_handler(event, '') \ No newline at end of file diff --git a/corporate_finances_back_py/capex-summary-retrieve/utils.py b/corporate_finances_back_py/capex-summary-retrieve/utils.py new file mode 100644 index 0000000..ea463fa --- /dev/null +++ b/corporate_finances_back_py/capex-summary-retrieve/utils.py @@ -0,0 +1,44 @@ +#version 2023 - 05 - 04 +import base64 +import boto3 +import json +import logging +import os + +from sqlalchemy import create_engine + +from decorators import handler_wrapper, debugger_wrapper + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + + +@debugger_wrapper('Error al obtener secreto','Error fatal de back conectando a base de datos') +def get_secret(secret_region, secret_name): + session = boto3.session.Session() + client_secrets_manager = session.client(service_name='secretsmanager', region_name=secret_region) + secret_data = client_secrets_manager.get_secret_value(SecretId=secret_name) + if 'SecretString' in secret_data: + secret_str = secret_data['SecretString'] + else: + secret_str = base64.b64decode(secret_data['SecretBinary']) + logger.info('[utils] (get_secret) Se obtuvo el secreto') + return json.loads(secret_str) + + +@debugger_wrapper('Error en la conexion a base de datos','Error fatal de back conectando a base de datos') +def connect_to_db(db_schema, db_secret): + conn_string = ('mysql+mysqlconnector://' + db_secret["username"] + ':' + db_secret["password"] + '@' + db_secret["host"] + ':' + str(db_secret["port"]) + '/' + db_schema) + sql_engine = create_engine(conn_string) + db_connection = sql_engine.connect() + return db_connection + + +@debugger_wrapper('Error en la conexion a base de datos','Error fatal de back conectando a base de datos') +def connect_to_db_local_dev(): + from dotenv import load_dotenv + load_dotenv() + conn_string = os.environ['local_dev_connector'] + sql_engine = create_engine(conn_string) + db_connection = sql_engine.connect() + return db_connection diff --git a/corporate_finances_back_py/cash-flow-modal-pool/decorators.py b/corporate_finances_back_py/cash-flow-modal-pool/decorators.py new file mode 100644 index 0000000..071760a --- /dev/null +++ b/corporate_finances_back_py/cash-flow-modal-pool/decorators.py @@ -0,0 +1,63 @@ +#version 2023 - 05 - 04 +import logging +import sys +import traceback +from functools import wraps +from time import time + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + +def handler_wrapper(start, satisfactory_log, error_log, raise_error): + #esto se ejecuta en la inicializacion de primero + def decorator(func): + #print(message1) + #lo que yo ponga acá se ejecuta antes de hacer el llamado a la funcion + @wraps(func) + def wrapper(*args, **kwargs): + #esto sí se ejecuta solo cuando llama a la funcion decorada + #print(message2) + try: + logger.info(f'[{func.__name__}] {start}...') + resultado = func(*args, **kwargs) + logger.info(f'[{func.__name__}] {satisfactory_log}') + return resultado + except Exception as e: + logger.error(f"[{func.__name__}] {error_log}, linea: {get_especific_error_line(func.__name__)}, motivo: {str(e)}") + raise Exception(f"{raise_error}") + + return wrapper + return decorator + +def debugger_wrapper(error_log, raise_error): + def decorator(func): + @wraps(func) + def wrapper(*args, **kwargs): + try: + resultado = func(*args, **kwargs) + return resultado + except Exception as e: + logger.error(f"[{func.__name__}] {error_log}, linea: {get_especific_error_line(func.__name__)}, motivo: {str(e)}") + raise Exception(f"{raise_error}") + return wrapper + return decorator + + +def get_especific_error_line(func_name): + _, _, exc_tb = sys.exc_info() + for trace in traceback.extract_tb(exc_tb): + if func_name in trace: + return str(trace[1]) + +def timing(f): + @wraps(f) + def wrap(*args, **kw): + ts = time() + result = f(*args, **kw) + te = time() + taken_time_message = '[timing] La funcion {}, toma: {:.2f} sec en ejecutarse'.format(f.__name__, te-ts) + logger.info(taken_time_message) + return result + return wrap + + diff --git a/corporate_finances_back_py/cash-flow-modal-pool/lambda_function.py b/corporate_finances_back_py/cash-flow-modal-pool/lambda_function.py new file mode 100644 index 0000000..ab0418b --- /dev/null +++ b/corporate_finances_back_py/cash-flow-modal-pool/lambda_function.py @@ -0,0 +1,141 @@ +import json +import logging +import sys +import os + +from datetime import datetime + +from decorators import handler_wrapper, timing, debugger_wrapper +from utils import get_secret, connect_to_db + + +#logging.basicConfig() #En lambdas borra este + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + + +def lambda_handler(event,context): + sc_obj = script_object(event) + lambda_response = sc_obj.starter() + logger.info(f'respuesta final de lambda: \n{lambda_response}') + return lambda_response + + +class script_object: + def __init__(self, event): + try: + self.failed_init = False + self.final_response = {'headers':{'Access-Control-Allow-Headers': '*', + 'Access-Control-Allow-Origin': '*', + 'Access-Control-Allow-Methods': '*'}, "statusCode": 500, 'body': {}} + self.db_connection = 0 + self.detailed_raise = '' + self.partial_response = list() + + logger.warning(f'event de entrada: {str(event)}') + self.id_assessment = event['queryStringParameters']['id_assessment'] + self.context = event['queryStringParameters']['context'] + + self.puc_chapters = {'1':'Activo', '2':'Pasivo', '3':'Patrimonio', '4':'Ingresos', '5':'Gastos', '6':'Costos de venta', '7':'Costos de producción o de operación', '8':'Cuentas de orden deudoras', '9':'Cuentas de orden acreedoras'} + + self.context_classifications = {'patrimony':['Aportes de capital social u otros','Cambios en el patrimonio'], + 'wk':['Capital de trabajo'], + 'other_projections':['Otros movimientos que no son salida ni entrada de efectivo no operativos','Otros movimientos que no son salida ni entrada de efectivo operativos','Otros movimientos netos de activos operativos que afecta el FCLO','Otros movimientos netos de activos operativos que afecta el FCLA'], + 'debt' : ['Deuda con costo financiero']} + + self.purged_items = list() + self.archives_ids = list() + self.history_dates = list() + self.key_items = list() + + + except Exception as e: + logger.error(f'[__init__] Error inicializando objeto lambda, linea: {get_current_error_line()}, motivo: {str(e)}') + self.failed_init = True + + def starter(self): + try: + if self.failed_init: + raise AttributeError('Error con los datos recibidos al servicio') + self.create_conection_to_db() + self.get_purged_items() + self.create_items_keys() + self.organize_pool_to_front() + self.organize_partial_response() + + return self.response_maker(succesfull_run = True) + + except Exception as e: + logger.error(f'[starter] Hubieron problemas en el comando de la linea: {get_current_error_line()}') + return self.response_maker(succesfull_run = False, error_str = (str(e))) + + @handler_wrapper('Creando conexion a bd','Conexion a bd creada con exito','Error en la conexion a bd','Problemas creando la conexion a bd') + def create_conection_to_db(self): + db_schema = os.environ['DB_SCHEMA'] + secret_db_region = os.environ['SECRET_DB_REGION'] + secret_db_name = os.environ['SECRET_DB_NAME'] + db_secret = get_secret(secret_db_region, secret_db_name) + self.db_connection = connect_to_db(db_schema, db_secret) + + + @handler_wrapper('Obteniendo datos de puc purgados','Datos de puc obtenidos','Error obteniendo datos de puc','Error al buscar datos de puc purgados') + def get_purged_items(self): + searching_classifications = self.context_classifications[self.context] + searching_classifications_str = str(searching_classifications).replace('[', '').replace(']','') + query = f"""SELECT C.ID AS archive_id, C.INITIAL_DATE AS date, A.ACCOUNT_NUMBER AS account, B.CLASSIFICATION AS classification, A.ANNUALIZED AS value, A.ACCOUNT_NAME AS name +FROM ASSESSMENT_CHECKED A, RAW_CLASSIFICATION B, ARCHIVE C +WHERE A.ID_RAW_CLASSIFICATION = B.ID AND A.ID_ARCHIVE = C.ID AND B.CLASSIFICATION IN ({searching_classifications_str}) +AND ID_ASSESSMENT = {self.id_assessment} ORDER BY C.INITIAL_DATE""" + + logger.info(f"[get_purged_items] Query a base de datos para obtener los datos de puc calculados:\n {query}") + rds_data = self.db_connection.execute(query) + + self.purged_items = [item._asdict() for item in rds_data.fetchall()] + logger.info(f'[get_purged_items] Datos de cuentas traídas desde bd:\n{self.purged_items}') + + for item in self.purged_items: + item['date'] = item['date'].strftime('%d-%m-%Y') + if item['archive_id'] not in self.archives_ids: + self.archives_ids.append(item['archive_id']) + self.history_dates.append(item['date']) + + item['value'] = float(item['value']) + #item['chapter'] = self.puc_chapters.get(item['account'][0], 'Capitulo no encontrado') + + logger.warning(f'[get_purged_items] datos de cuentyas post procesamiento inicial:\n{self.purged_items}') + + @handler_wrapper('Creando llaves para las listas desplegables', 'Listas desplegables creadas con exito', 'Error creando llaves de listas deplegables', 'Error creando listas desplegables') + def create_items_keys(self): + self.key_items = [{'name':item['name'], 'account':item['account']} for item in self.purged_items if item['archive_id'] == self.archives_ids[-1]] + + + @handler_wrapper('Eliminando datos innecesarios de los objetos en el pool', 'Objetos pool limpiados con exito', 'Error limpiando objetos del pool', 'Error creando pool') + def organize_pool_to_front(self): + for item in self.purged_items: + del item['name'] + del item['archive_id'] + + + @handler_wrapper('Organizando respuesta final', 'Respuesta final organizada con exito', 'Error organizando respeusta final', 'Error creando respesta final') + def organize_partial_response(self): + self.partial_response = {'dates': self.history_dates, 'items': self.key_items, 'pool': self.purged_items} + + + @debugger_wrapper('Error construyendo respuesta final', 'Error construyendo respuesta') + def response_maker(self, succesfull_run = False, error_str = str()): + if self.db_connection: + self.db_connection.close() + if succesfull_run: + self.final_response['statusCode'] = 200 + self.final_response['body'] = json.dumps(self.partial_response) + return self.final_response + + self.final_response['body'] = json.dumps(self.detailed_raise if self.detailed_raise else error_str) + return self.final_response + + + +def get_current_error_line(): + return str(sys.exc_info()[-1].tb_lineno) + \ No newline at end of file diff --git a/corporate_finances_back_py/cash-flow-modal-pool/utils.py b/corporate_finances_back_py/cash-flow-modal-pool/utils.py new file mode 100644 index 0000000..9efbdea --- /dev/null +++ b/corporate_finances_back_py/cash-flow-modal-pool/utils.py @@ -0,0 +1,33 @@ +#version 2023 - 05 - 04 +import base64 +import boto3 +import json +import logging + +from sqlalchemy import create_engine + +from decorators import handler_wrapper, debugger_wrapper + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + + +@debugger_wrapper('Error al obtener secreto','Error fatal de back conectando a base de datos') +def get_secret(secret_region, secret_name): + session = boto3.session.Session() + client_secrets_manager = session.client(service_name='secretsmanager', region_name=secret_region) + secret_data = client_secrets_manager.get_secret_value(SecretId=secret_name) + if 'SecretString' in secret_data: + secret_str = secret_data['SecretString'] + else: + secret_str = base64.b64decode(secret_data['SecretBinary']) + logger.info('[utils] (get_secret) Se obtuvo el secreto') + return json.loads(secret_str) + + +@debugger_wrapper('Error en la conexion a base de datos','Error fatal de back conectando a base de datos') +def connect_to_db(db_schema, db_secret): + conn_string = ('mysql+mysqlconnector://' + db_secret["username"] + ':' + db_secret["password"] + '@' + db_secret["host"] + ':' + str(db_secret["port"]) + '/' + db_schema) + sql_engine = create_engine(conn_string) + db_connection = sql_engine.connect() + return db_connection \ No newline at end of file diff --git a/corporate_finances_back_py/cash-flow-projection-calculator/decorators.py b/corporate_finances_back_py/cash-flow-projection-calculator/decorators.py new file mode 100644 index 0000000..1aba58c --- /dev/null +++ b/corporate_finances_back_py/cash-flow-projection-calculator/decorators.py @@ -0,0 +1,47 @@ +#version 2022 - 12 - 06 +import logging +import sys +import traceback +from functools import wraps +from time import time + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + +def handler_wrapper(start, satisfactory_log, error_log, raise_error): + #esto se ejecuta en la inicializacion de primero + def decorator(func): + #print(message1) + #lo que yo ponga acá se ejecuta antes de hacer el llamado a la funcion + def wrapper(*args, **kwargs): + #esto sí se ejecuta solo cuando llama a la funcion decorada + #print(message2) + try: + logger.info(f'[{func.__name__}] {start}...') + resultado = func(*args, **kwargs) + logger.info(f'[{func.__name__}] {satisfactory_log}') + return resultado + except Exception as e: + logger.error(f"[{func.__name__}] {error_log}, linea: {get_especific_error_line(func.__name__)}, motivo: {str(e)}") + raise Exception(f"{raise_error}") + + return wrapper + return decorator + + +def get_especific_error_line(func_name): + _, _, exc_tb = sys.exc_info() + for trace in traceback.extract_tb(exc_tb): + if func_name in trace: + return str(trace[1]) + +def timing(f): + @wraps(f) + def wrap(*args, **kw): + ts = time() + result = f(*args, **kw) + te = time() + taken_time_message = '[timing] La funcion {}, toma: {:.2f} sec en ejecutarse'.format(f.__name__, te-ts) + logger.info(taken_time_message) + return result + return wrap diff --git a/corporate_finances_back_py/cash-flow-projection-calculator/lambda_function.py b/corporate_finances_back_py/cash-flow-projection-calculator/lambda_function.py new file mode 100644 index 0000000..4e26e3a --- /dev/null +++ b/corporate_finances_back_py/cash-flow-projection-calculator/lambda_function.py @@ -0,0 +1,121 @@ +""": +capas: +ninguna + +variables de entorno: +ninguna + +RAM: 25 MB +""" + + +import json +import logging +import sys +import traceback + + + +from decorators import handler_wrapper, timing + + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + + +def lambda_handler(event, context): + lo = lambda_object(event) + return lo.starter() + + +class lambda_object(): + + @handler_wrapper('Obteniendo valores clave de event', 'Valores de event obtenidos correctamente', + 'Error al obtener valores event', 'Fallo en la obtencion de valores clave de event') + def __init__(self, event) -> None: + + logger.warning(f'event que llega a la lambda: {str(event)}') + event_body_json = event["body"] + self.received_object = json.loads(event_body_json) + self.functions_directory = { + "impositive": self.calculate_impositives, + "proportion": self.calculate_proportions, + "fixed": self.calculated_fixeds, + "constant": self.calculate_constants, + "input": self.calculate_inputs, + "zero": self.calculate_zeros + } + + self.calculated_projection = {'name':self.received_object['name']} + self.final_response = {'headers':{'Access-Control-Allow-Headers': '*', 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Methods': '*'}} + + + def starter(self): + try: + logger.info(f'[starter] Empezando starter de objeto lambda') + self.functions_directory[self.received_object['projection']]() + logger.info(f'[starter] Tareas de starter terminadas con exito') + return self.response_maker(succesfull = True) + + except Exception as e: + logger.error(f'[starter] Error en el procesamieno del comando de la linea: {get_current_error_line()}, motivo: {e}') + return self.response_maker(succesfull = False, exception_str = str(e)) + + + @handler_wrapper('Calculando tasa impositiva','Tasa impositiva calculada con exito','Error calculando tasa impositiva','No se pudieron procesar los datos recibidos') + def calculate_impositives(self): + proyected_values = [] + for index, vs_value in enumerate(self.received_object["vs_values"]): + proyected_values.append(vs_value * self.received_object['percentage'][index]/100) + self.calculated_projection['result'] = proyected_values + + + @handler_wrapper('Calculando proporcion','Proporcion calculada con exito','Error calculando proporcion','No se pudieron procesar los datos recibidos') + def calculate_proportions(self): + proyected_values = [self.received_object["value"] / self.received_object["vs_original_value"] * self.received_object["vs_values"][0]] + for index, vs_value in enumerate(self.received_object["vs_values"][1:]): + proyected_values.append(proyected_values[index] / self.received_object["vs_values"][index] * self.received_object["vs_values"][index+1] ) + self.calculated_projection['result'] = proyected_values + + + + @handler_wrapper('Calculando tasa fija','Tasa fija calculada con exito','Error calculando tasa fija','No se pudieron procesar los datos recibidos') + def calculated_fixeds(self): + proyected_values = [(1+self.received_object["percentage"][0]/100) * self.received_object["value"]] + for index, p in enumerate(self.received_object["percentage"][1:]): + proyected_values.append(proyected_values[index] * (1+p/100)) + self.calculated_projection['result'] = proyected_values + + + + @handler_wrapper('Calculando valor cte','Valor cte calculado con exito','Error calculando valor constante','No se pudieron procesar los datos recibidos') + def calculate_constants(self): + self.calculated_projection['result'] = [self.received_object["value"]] * self.received_object["years"] + + + @handler_wrapper('Calculando inputs','Inputs asignados con exito','Error asignando inputs','No se pudieron procesar los datos recibidos') + def calculate_inputs(self): + self.calculated_projection['result'] = self.received_object["inputs"] + + @handler_wrapper('Calculando zero','Zero asignado con exito','Error asignando zeros','No se pudieron procesar los datos recibidos') + def calculate_zeros(self): + self.calculated_projection['result'] = [0] * self.received_object["years"] + + + + def response_maker(self, succesfull = False, exception_str = str): + if not succesfull: + self.final_response['body'] = json.dumps(exception_str) + return self.final_response + self.final_response['body'] = json.dumps(self.calculated_projection) + return self.final_response + + +def get_current_error_line(): + return str(sys.exc_info()[-1].tb_lineno) + + +def get_especific_error_line(): + _, _, exc_tb = sys.exc_info() + return str(traceback.extract_tb(exc_tb)[-1][1]) + diff --git a/corporate_finances_back_py/cash-flow-retrieve/decorators.py b/corporate_finances_back_py/cash-flow-retrieve/decorators.py new file mode 100644 index 0000000..071760a --- /dev/null +++ b/corporate_finances_back_py/cash-flow-retrieve/decorators.py @@ -0,0 +1,63 @@ +#version 2023 - 05 - 04 +import logging +import sys +import traceback +from functools import wraps +from time import time + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + +def handler_wrapper(start, satisfactory_log, error_log, raise_error): + #esto se ejecuta en la inicializacion de primero + def decorator(func): + #print(message1) + #lo que yo ponga acá se ejecuta antes de hacer el llamado a la funcion + @wraps(func) + def wrapper(*args, **kwargs): + #esto sí se ejecuta solo cuando llama a la funcion decorada + #print(message2) + try: + logger.info(f'[{func.__name__}] {start}...') + resultado = func(*args, **kwargs) + logger.info(f'[{func.__name__}] {satisfactory_log}') + return resultado + except Exception as e: + logger.error(f"[{func.__name__}] {error_log}, linea: {get_especific_error_line(func.__name__)}, motivo: {str(e)}") + raise Exception(f"{raise_error}") + + return wrapper + return decorator + +def debugger_wrapper(error_log, raise_error): + def decorator(func): + @wraps(func) + def wrapper(*args, **kwargs): + try: + resultado = func(*args, **kwargs) + return resultado + except Exception as e: + logger.error(f"[{func.__name__}] {error_log}, linea: {get_especific_error_line(func.__name__)}, motivo: {str(e)}") + raise Exception(f"{raise_error}") + return wrapper + return decorator + + +def get_especific_error_line(func_name): + _, _, exc_tb = sys.exc_info() + for trace in traceback.extract_tb(exc_tb): + if func_name in trace: + return str(trace[1]) + +def timing(f): + @wraps(f) + def wrap(*args, **kw): + ts = time() + result = f(*args, **kw) + te = time() + taken_time_message = '[timing] La funcion {}, toma: {:.2f} sec en ejecutarse'.format(f.__name__, te-ts) + logger.info(taken_time_message) + return result + return wrap + + diff --git a/corporate_finances_back_py/cash-flow-retrieve/lambda_function.py b/corporate_finances_back_py/cash-flow-retrieve/lambda_function.py new file mode 100644 index 0000000..3771c80 --- /dev/null +++ b/corporate_finances_back_py/cash-flow-retrieve/lambda_function.py @@ -0,0 +1,182 @@ + + +import json +from sqlalchemy import text +import logging +import sys +import os +import math + +from decorators import handler_wrapper, timing, debugger_wrapper +from utils import get_secret, connect_to_db, connect_to_db_local_dev +from vars import cash_flow_all_items + +logging.basicConfig() +logging.basicConfig(format='%(asctime)s [%(levelname)s] [%(module)s] %(message)s', force=True, datefmt='%Y-%m-%d %H:%M:%S') +logger = logging.getLogger() +logger.setLevel(logging.INFO) + +def lambda_handler(event, context): + sc_obj = script_object(event) + lambda_response = sc_obj.starter() + logger.info(f'respuesta final de lambda: \n{lambda_response}') + return lambda_response + + +class script_object(): + + @handler_wrapper('Obteniendo valores clave de event', 'Valores de event obtenidos correctamente', + 'Error al obtener valores event', 'Fallo en la obtencion de valores clave de event') + def __init__(self, event) -> None: + try: + self.failed_init = False + self.final_response = {'headers':{'Access-Control-Allow-Headers': '*', + 'Access-Control-Allow-Origin': '*', + 'Access-Control-Allow-Methods': '*'}, "statusCode": 500, 'body': {}} + self.db_connection = 0 + self.detailed_raise = '' + self.partial_response = list() + + logger.warning(f'event de entrada: {str(event)}') + event_dict = event['pathParameters'] + self.id_assessment = event_dict['id_assessment'] + + self.historic_dates = list() + self.historic_dates_len = int() + self.projection_dates = list() + self.projection_dates_len = int() + self.total_asssessment_dates = int() + self.cash_flow_table = dict() + self.pyg_vector = dict() + self.debt_data = False + self.capex_exists = False + + except Exception as e: + logger.error(f'[__init__] Error inicializando objeto lambda, linea: {get_current_error_line()}, motivo: {str(e)}') + self.failed_init = True + + + def starter(self): + try: + logger.info('[starter] Empezando starter de objeto lambda') + self.create_conection_to_resources() + self.get_assessment_dates() + self.initialize_zero_vectors() + self.acquire_cash_flow_results() + self.consume_cash_flow() + self.organize_final_response() + + logger.info('[starter] Tareas de starter terminadas con exito') + return self.response_maker(succesfull_run = True) + + except Exception as e: + logger.error(f'[starter] Error en el procesamieno del comando de la linea: {get_current_error_line()}, motivo: {e}') + return self.response_maker(succesfull_run = False, error_str = str(e)) + + + + @handler_wrapper('Creando conexion a bd','Conexion a bd creada con exito','Error en la conexion a bd','Problemas creando la conexion a bd') + def create_conection_to_resources(self): + if __name__ == "__main__": + self.db_connection = connect_to_db_local_dev() + return + + db_schema = os.environ['DB_SCHEMA'] + secret_db_region = os.environ['SECRET_DB_REGION'] + secret_db_name = os.environ['SECRET_DB_NAME'] + db_secret = get_secret(secret_db_region, secret_db_name) + self.db_connection = connect_to_db(db_schema, db_secret) + + + @handler_wrapper('Obteniendo las fechas del proceso de valoración', 'Fechas del proceso de valroación obtenidas con exito', 'Error obteniendo las fechas del proceso de valoración', 'Error obteniendo fechas del proceso de valoración') + def get_assessment_dates(self): + query = "SELECT DATES, PROPERTY FROM ASSESSMENT_DATES WHERE ID_ASSESSMENT = :id_assessment ORDER BY DATES" + logger.info(f"[get_assessment_dates] Query a base de datos para obtener las fechas utilizadas en el proces de valoración:\n {query}") + rds_data = self.db_connection.execute(text(query), {"id_assessment": self.id_assessment}) + directory = {'HISTORIC': self.historic_dates, 'PROJECTION': self.projection_dates} + for date_item in rds_data.fetchall(): + directory.get(date_item.PROPERTY, []).append(date_item.DATES) + self.total_asssessment_dates = self.total_asssessment_dates +1 + + self.historic_dates = [date.strftime('%d-%m-%Y') for date in self.historic_dates] + self.projection_dates = [date.strftime('%Y') for date in self.projection_dates] + self.projection_dates[0] = self.projection_dates[0] if '-12-' in self.historic_dates[-1] else f'Diciembre {self.projection_dates[0]}' #Se agrega esta linea para que llegue diciembre con formato de anualización a front + + self.historic_dates_len = len(self.historic_dates) + self.projection_dates_len = len(self.projection_dates) + self.total_dates_len = self.historic_dates_len + self.projection_dates_len + + logger.info(f'[get_assessment_dates] Fechas del proceso de valoración:\nhistoricas: {self.historic_dates}\nproyecciones: {self.projection_dates}') + + + @handler_wrapper('Inicializando todos los vectores a zero', 'Vectores de flujo de caja inicializados', 'Error inicializando vectores de flujo de caja', 'Error iniciando sistema vectorial') + def initialize_zero_vectors(self): + for row in cash_flow_all_items: + self.cash_flow_table[row] = [0] * self.total_asssessment_dates + + + + @handler_wrapper('Adquiriendo resultados de tabla de flujo de caja', 'Datos de flujo de caja adquiridos con éxito', 'Error adquiriendo resultados de tabla de flujo de caja', 'Error adquiriendo resultados') + def acquire_cash_flow_results(self): + query = "SELECT A.SUMMARY_DATE, A.VALUE AS value, B.CASH_FLOW_ITEM_NAME FROM CASH_FLOW A, RAW_CASH_FLOW B WHERE A.ID_RAW_CASH_FLOW = B.ID AND A.ID_ASSESSMENT = :id_assessment ORDER BY A.SUMMARY_DATE" + logger.info(f"[acquire_cash_flow_results] Query a base de datos para obtener los resultados de engine para el flujo de caja:\n{query}") + rds_data = self.db_connection.execute(text(query), {'id_assessment':self.id_assessment}) + self.acquired_cash_flow_results = [row._asdict() for row in rds_data.fetchall()] + for row in self.acquired_cash_flow_results: + row['value'] = float(row['value']) + + + @handler_wrapper('Consumiendo datos adquiridos de flujo de caja', 'Datos adquiridos consumidos con éxito', 'Error consumiendo datos de flujo de caja', 'Error construyendo tabla de flujo de caja') + def consume_cash_flow(self): + for key in self.cash_flow_table: + key_found_vector = [row['value'] for row in self.acquired_cash_flow_results if row['CASH_FLOW_ITEM_NAME'] == key] + if len(key_found_vector) != self.total_dates_len: + logger.warning(f'[] El vector de {key} tiene longitud diferente a la cantidad de fechas\nFechas:{self.total_dates_len}\nVector: {key_found_vector}') + self.cash_flow_table[key] = key_found_vector + if key == 'Check': + self.cash_flow_table[key] = ['Sí'] * self.total_asssessment_dates + + + @handler_wrapper('Organizando respuesta final', 'Respuesta final organizada satisfactoriamente', 'Error organizando respuesta final', 'Error organizando respuesta de servicio') + def organize_final_response(self): + data = [] + + self.cash_flow_table['Otros ingresos y egresos no operativos CF'] = self.cash_flow_table['Otros ingresos y egresos no operativos'] + for key, vector in self.cash_flow_table.items(): + data.append({'name': key, 'values': {'history': vector[:len(self.historic_dates)], 'projection': vector[-1 * len(self.projection_dates):]}}) + + + self.partial_response = {'datesHistory': self.historic_dates, 'datesProjection': self.projection_dates, 'data': data} + + + def response_maker(self, succesfull_run = False, error_str = str()): + if self.db_connection: + self.db_connection.close() + if succesfull_run: + self.final_response['statusCode'] = 200 + self.final_response['body'] = json.dumps(self.partial_response) + return self.final_response + + self.final_response['body'] = json.dumps(self.detailed_raise if self.detailed_raise else error_str) + return self.final_response + + +def get_current_error_line(): + return str(sys.exc_info()[-1].tb_lineno) + + +def checker(a,b): + if math.isclose(a, b, rel_tol=0.001, abs_tol=0.1): + return 'Sí' + return 'No' + +def safe_exit(j): + try: + return float(j) + except: + return 0 + + +if __name__ == "__main__": + event = {"pathParameters": {"id_assessment": "51"}} + lambda_handler(event, '') \ No newline at end of file diff --git a/corporate_finances_back_py/cash-flow-retrieve/utils.py b/corporate_finances_back_py/cash-flow-retrieve/utils.py new file mode 100644 index 0000000..6a07af1 --- /dev/null +++ b/corporate_finances_back_py/cash-flow-retrieve/utils.py @@ -0,0 +1,41 @@ +#version 2023 - 05 - 04 +import base64 +import boto3 +import json +import logging + +from sqlalchemy import create_engine + +from decorators import handler_wrapper, debugger_wrapper + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + + +@debugger_wrapper('Error al obtener secreto','Error fatal de back conectando a base de datos') +def get_secret(secret_region, secret_name): + session = boto3.session.Session() + client_secrets_manager = session.client(service_name='secretsmanager', region_name=secret_region) + secret_data = client_secrets_manager.get_secret_value(SecretId=secret_name) + if 'SecretString' in secret_data: + secret_str = secret_data['SecretString'] + else: + secret_str = base64.b64decode(secret_data['SecretBinary']) + logger.info('[utils] (get_secret) Se obtuvo el secreto') + return json.loads(secret_str) + + +@debugger_wrapper('Error en la conexion a base de datos','Error fatal de back conectando a base de datos') +def connect_to_db(db_schema, db_secret): + conn_string = ('mysql+mysqlconnector://' + db_secret["username"] + ':' + db_secret["password"] + '@' + db_secret["host"] + ':' + str(db_secret["port"]) + '/' + db_schema) + sql_engine = create_engine(conn_string) + db_connection = sql_engine.connect() + return db_connection + + +@debugger_wrapper('Error en la conexion a base de datos','Error fatal de back conectando a base de datos') +def connect_to_db_local_dev(): + conn_string = open(r"C:\Users\JeissonBotache\.aws\aurora_sources8_dev.txt", "r").read() + sql_engine = create_engine(conn_string) + db_connection = sql_engine.connect() + return db_connection diff --git a/corporate_finances_back_py/cash-flow-retrieve/vars.py b/corporate_finances_back_py/cash-flow-retrieve/vars.py new file mode 100644 index 0000000..9745a24 --- /dev/null +++ b/corporate_finances_back_py/cash-flow-retrieve/vars.py @@ -0,0 +1,75 @@ + +cash_flow_all_items = ['Utilidad neta', + 'Impuestos de renta', + 'Intereses/gasto financiero', + 'Otros ingresos y egresos no operativos CF', + 'EBIT', + 'Impuestos operacionales', + 'UODI (NOPAT)', + 'Depreciación del Periodo', + 'Deterioro', + 'Amortización del Periodo', + 'Depreciación Capex', + 'Otros movimientos que no son salida ni entrada de efectivo operativos', + 'Flujo de caja bruto', + 'Capital de trabajo', + 'CAPEX', + 'Otros movimientos netos de activos operativos que afecta el FCLO', + 'Otros ingresos y egresos operativos', + 'Flujo de caja Libre Operacional', + 'Intereses/gasto financiero FC', + 'Impuestos no operacionales', + 'Variación de deuda', + 'Deuda de tesorería del periodo', + 'Deuda de tesorería acumulada', + 'Otros movimientos netos de activos operativos que afecta el FCLA', + 'Otros ingresos y egresos no operativos', + 'Flujo de caja del accionista', + 'Aportes de capital social u otros', + 'Dividentos en efectivo', + 'Flujo de caja del periodo', + 'Saldo de caja inicial', + 'Saldo de caja final', + 'Check'] + +pyg_items = ['Utilidad antes de impuestos', + 'Impuestos de renta', + 'Intereses/gasto financiero', + 'Deterioro', + 'Otros ingresos y egresos operativos', + 'Otros ingresos y egresos no operativos', + 'Utilidad neta', + 'EBIT'] + +capex_items = ['Depreciación del Periodo', 'Amortización del Periodo', 'CAPEX', 'Depreciación Capex'] + +patrimony_items = ['Aportes de capital social u otros', 'Dividentos en efectivo'] + +other_projections = ['Otros movimientos que no son salida ni entrada de efectivo operativos', 'Otros movimientos netos de activos operativos que afecta el FCLA', 'Otros movimientos netos de activos operativos que afecta el FCLO'] + +wk_items = ['Capital de trabajo'] + +debt_items = ['Variación de deuda'] #Este no sé si se pueda usar así o es un metodo con calculos propios + +""" +cash_flow_totals = {'Flujo de caja bruto':{'dependencies': ['UODI (NOPAT)','Depreciación','Deterioro','Amortización', 'Depreciación Capex','Otros movimientos que no son salida ni entrada de efectivo operativos'], + 'is_sum': [1,1,1,1,1,-1]}, + 'Flujo de caja Libre Operacional':{'dependencies':['Flujo de caja bruto', 'Capital de trabajo', 'CAPEX', 'Otros movimientos netos de activos operativos que afecta el FCLO', 'Otros ingresos y egresos operativos'], + 'is_sum':[1,-1,-1,-1,1]}, #revisar si FCLO suma o resta + 'Flujo de caja del accionista':{'dependencies':['Flujo de caja Libre Operacional', 'Intereses/gasto financiero FC', 'Impuestos no operacionales', 'Variación de deuda', 'Otros movimientos netos de activos operativos que afecta el FCLA', 'Otros ingresos y egresos no operativos'], + 'is_sum':[1,-1,-1,1,-1,1]}, + 'Flujo de caja del periodo':{'dependencies':['Flujo de caja del accionista','Aportes de capital social u otros', 'Dividentos en efectivo'], + 'is_sum':[1,1,-1]} + } +""" + +cash_flow_totals = {'Flujo de caja bruto':{'dependencies': ['UODI (NOPAT)','Depreciación del Periodo','Deterioro','Amortización del Periodo', 'Depreciación Capex','Otros movimientos que no son salida ni entrada de efectivo operativos'], + 'is_sum': [1,1,1,1,1,-1]}, + 'Flujo de caja Libre Operacional':{'dependencies':['Flujo de caja bruto', 'Capital de trabajo', 'CAPEX', 'Otros movimientos netos de activos operativos que afecta el FCLO', 'Otros ingresos y egresos operativos'], + 'is_sum':[1,-1,-1,-1,1]}, #revisar si FCLO suma o resta + 'Flujo de caja del accionista':{'dependencies':['Flujo de caja Libre Operacional', 'Intereses/gasto financiero FC', 'Impuestos no operacionales', 'Variación de deuda', 'Deuda de tesorería del periodo', 'Otros movimientos netos de activos operativos que afecta el FCLA', 'Otros ingresos y egresos no operativos'], + 'is_sum':[1,-1,-1,1,1,-1,1]}, + 'Flujo de caja del periodo':{'dependencies':['Flujo de caja del accionista','Aportes de capital social u otros', 'Dividentos en efectivo'], + 'is_sum':[1,1,-1]} + } + diff --git a/corporate_finances_back_py/checker-to-db/decorators.py b/corporate_finances_back_py/checker-to-db/decorators.py new file mode 100644 index 0000000..071760a --- /dev/null +++ b/corporate_finances_back_py/checker-to-db/decorators.py @@ -0,0 +1,63 @@ +#version 2023 - 05 - 04 +import logging +import sys +import traceback +from functools import wraps +from time import time + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + +def handler_wrapper(start, satisfactory_log, error_log, raise_error): + #esto se ejecuta en la inicializacion de primero + def decorator(func): + #print(message1) + #lo que yo ponga acá se ejecuta antes de hacer el llamado a la funcion + @wraps(func) + def wrapper(*args, **kwargs): + #esto sí se ejecuta solo cuando llama a la funcion decorada + #print(message2) + try: + logger.info(f'[{func.__name__}] {start}...') + resultado = func(*args, **kwargs) + logger.info(f'[{func.__name__}] {satisfactory_log}') + return resultado + except Exception as e: + logger.error(f"[{func.__name__}] {error_log}, linea: {get_especific_error_line(func.__name__)}, motivo: {str(e)}") + raise Exception(f"{raise_error}") + + return wrapper + return decorator + +def debugger_wrapper(error_log, raise_error): + def decorator(func): + @wraps(func) + def wrapper(*args, **kwargs): + try: + resultado = func(*args, **kwargs) + return resultado + except Exception as e: + logger.error(f"[{func.__name__}] {error_log}, linea: {get_especific_error_line(func.__name__)}, motivo: {str(e)}") + raise Exception(f"{raise_error}") + return wrapper + return decorator + + +def get_especific_error_line(func_name): + _, _, exc_tb = sys.exc_info() + for trace in traceback.extract_tb(exc_tb): + if func_name in trace: + return str(trace[1]) + +def timing(f): + @wraps(f) + def wrap(*args, **kw): + ts = time() + result = f(*args, **kw) + te = time() + taken_time_message = '[timing] La funcion {}, toma: {:.2f} sec en ejecutarse'.format(f.__name__, te-ts) + logger.info(taken_time_message) + return result + return wrap + + diff --git a/corporate_finances_back_py/checker-to-db/lambda_function.py b/corporate_finances_back_py/checker-to-db/lambda_function.py new file mode 100644 index 0000000..0497fc8 --- /dev/null +++ b/corporate_finances_back_py/checker-to-db/lambda_function.py @@ -0,0 +1,349 @@ + +import boto3 +import json +import logging +import sys +import time +import urllib +import traceback +from utils import * +import os + +import pandas as pd +import numpy as np + +from decorators import handler_wrapper, timing + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + + +def lambda_handler(event, context): + """: + Funcion lambda_handler que se activa automaticamente. La función llama los demás metodos de la lambda + que contienen la logica necesaria para obtener los resultados. Si en el procedimiento hay errores + se dispara un raise que ejecuta una respuesta base que debería servir para encontrar la ubicacion + del error. + :param event: Se puede interpretar como variables base que activan la lambda + :param context: contiene informacion relevante al ambiente de la lambda, raramente se usa + :returns: La funcion debe devolver un objeto con los encabezados y el body en la estructura esperada; + """ + #logger.info(f'event de entrada: {str(event)}') + sc_obj = script_object(event) + return sc_obj.starter() + + +class script_object: + + def __init__(self, event): + try: + + logger.info('[__INIT__] Inicializando objeto lambda ...') + logger.info(f'event de entrada: {str(event)}') + + logger.info('[__INIT__] Inicializando objeto lambda ...') + logger.info(f'event de entrada_ {str(event)}') + event_body_json = event["body"] + event_body_dict = json.loads(event_body_json) + self.raw_dataframe = pd.DataFrame.from_records(event_body_dict['dataframe']) + + try: + self.found_archive = event_body_dict['archive']['found_archive'] + self.create_archive_info = 0 + + except Exception: + self.found_archive = 0 + self.create_archive_info = event_body_dict['archive'] + self.sector = event_body_dict['archive']['sector'] + self.initial_date = event_body_dict['archive']['date'] + self.df_full_original = pd.core.frame.DataFrame() + self.cleaned_df = pd.core.frame.DataFrame() + self.ready_to_upload_df = pd.core.frame.DataFrame() + self.db_connection = 0 + self.final_response = {'headers':{'Access-Control-Allow-Headers': '*', 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Methods': '*'}, 'statusCode': 200} + self.failed_init = False + + logger.info('[__INIT__] Objeto lambda inicializada exitosamente') + + except Exception as e: + self.failed_init = True + logger.error(f"[__INIT__] error en inicializacion, linea: {get_especific_error_line()}, motivo: "+str(e)) + + + def starter(self): + try: + if self.failed_init: + raise Exception('Falla inicializacion, revisar logs') + self.df_cleaner() + self.puc_translator() + self.level_asign() + self.master_checker() + self.create_conection_to_db() + + if self.found_archive: + logger.warning('[starter] Se requiere hace un safe delete de los datos en la tabla de ORIGINAL_PUC') + self.safe_delete_on_bd() + + if self.create_archive_info: + logger.warning('[starter] Se requiere crear el archive en la tabla de ARCHIVES') + self.create_archive_on_bd() + + self.get_df_ready_to_db() + self.send_to_db() + self.db_connection.close() + return self.response_maker(succesfull = True) + + except Exception as e: + if self.db_connection: + self.db_connection.close() + logger.error(f'[starter] Error en el procesamieno del comando de la linea: {get_current_error_line()}, motivo: {e}') + return self.response_maker(succesfull = False, exception_str = e) + + @handler_wrapper('Iniciando alistamiento de dataframe','Dataframe alistado con exito','Error al alistar dataframe','Se presenta error con los datos recibidos') + def df_cleaner (self): + self.cleaned_df = self.raw_dataframe.copy() + self.cleaned_df.fillna('', inplace=True) + self.cleaned_df = self.cleaned_df.astype({"balance": "string","account":"string","name":"string"}, copy=True) + self.cleaned_df = self.cleaned_df[self.cleaned_df['account'].apply(lambda x: x.split('.')[0].isnumeric())] #esta linea sirve para que eliminar las filas donde 'account no tiene un valor numerico' o es un string vacio + self.cleaned_df['balance'] = pd.to_numeric(self.cleaned_df['balance'], errors='coerce') + self.cleaned_df['account'] = self.cleaned_df['account'].str.split('.').str[0] + self.cleaned_df.dropna(subset=['balance','account'],inplace=True) + self.cleaned_df.astype({"balance": "float"}, copy=False) + self.cleaned_df.sort_values(by=['account'], inplace=True) + self.cleaned_df.reset_index(drop=True, inplace=True) + + + @handler_wrapper('Chequeando si el puc es de cliente o super','Traduccion de puc completada','Error al traducir puc','Hubieron errores en el alistamiento de la informacion') + def puc_translator(self): + logger.info('[puc_translator] Revisando si el puc depurado es de tipo superfinanciera...') + if self.cleaned_df.iloc[0,0] == '100000': + temp_df = self.cleaned_df.copy() + logger.info('[puc_translator] El puc depurado es de tipo superFinanciera, traduciendo...') + for ending in ["00000", "0000", "00"]: + temp_df.loc[temp_df["account"].str.endswith(ending),"account"] = temp_df.loc[temp_df["account"].str.endswith(ending),"account"].str.slice(stop=(6-len(ending))) + self.cleaned_df = temp_df.copy() + else: + logger.info('[puc_translator] El puc ya es de tipo Default') + + + @handler_wrapper('Asignando niveles a dataframe alistado','Niveles asignados al dataframe','Error asignando los niveles al dataframe','Error revisando los datos recibidos') + def level_asign(self): + self.cleaned_df["checked"] = False + self.cleaned_df['nivel'] = self.cleaned_df['account'].astype(str).str.len() + self.cleaned_df['checked_balance'] = self.cleaned_df['balance'] + self.cleaned_df['created_data'] = 0 + + + @handler_wrapper('iniciando master checker','Master checker terminado con exito','Error calculando chequeos','Error revisando los datos recibidos') + def master_checker(self): + logger.warning(f"Dataframe con el que voy a hacer los chequeos:\n {str(self.cleaned_df.to_dict(orient = 'records'))}") + self.negative_accounts_check() + self.subchapter_check() + + if False in self.cleaned_df["checked"].unique(): ##revisar si puedo sacar este unique + logger.warning("Chequeo de subcapitulos no satisfactorio, agregando cuentas superiores...") + self.upper_accounts_checker() + + self.finance_account_fixer() + + self.cleaned_df.sort_values(by=['account'], inplace=True) + self.cleaned_df.reset_index(drop=True, inplace=True) + + + @handler_wrapper('Haciendo chequeo de cuentas negativas','Chequeo de cuentas negativas terminado con exito','Error en el chequeo de cuentas','Error revisando capitulos negativos') + def negative_accounts_check(self): + account_groups = ["2", "3", "4", "6"] + for group in account_groups: + try: + group_value = self.cleaned_df.loc[self.cleaned_df["account"] == group]["checked_balance"].values[0] + except Exception as e: + continue + + if group_value < 0: + self.cleaned_df.loc[self.cleaned_df['account'].str.startswith(group), 'checked_balance'] = self.cleaned_df.loc[self.cleaned_df['account'].str.startswith(group), 'checked_balance'] * -1 + logger.info(f'se realizó cambio de signo para las cuentas del capitulo {group}') + + + @handler_wrapper('Chequeando subcuentas','Chequeo de subcuentas terminado','Error en el chequeo de subcuentas','Error realizando chequeos preliminares a guardado') + def subchapter_check(self): + df = self.cleaned_df.copy() + niveles = list(df["nivel"].unique()) + niveles = sorted(niveles, reverse=True) + for nivel in niveles[1:]: + + #logger.info("Revisando las cuentas de nivel: "+str(nivel)) + df_nivel = df.loc[df["nivel"] == nivel] + for upper_cat in df_nivel["account"]: + lower_cat_df = df.loc[(df["nivel"] > nivel) & + (df["account"].str.startswith(upper_cat)) & + (df["checked"] == False)] + + if lower_cat_df.empty: + continue + + lower_cat_niveles = list(lower_cat_df["nivel"].unique()) + lower_cat_niveles = sorted(lower_cat_niveles) + if len(lower_cat_niveles) > 1: + lower_cat_df = lower_cat_df.loc[df["nivel"] == lower_cat_niveles[0]] + upper_cat_value = df.loc[df["account"] == upper_cat]["checked_balance"].values[0] + lower_cat_sum = lower_cat_df["checked_balance"].sum() + check_result = checker(upper_cat_value, lower_cat_sum) + + df.loc[df['account'].isin(lower_cat_df.account), 'checked'] = check_result + + if nivel == 1: + df.loc[df['nivel'] == 1, 'checked'] = True + + self.cleaned_df['checked'] = df['checked'] + + + @handler_wrapper('Entrando a creador de cuentas nuevas','Creador de cuentas nuevas terminado con exito','Error en creador de cuentas nuevas','Error chequeando valores recibidos') + def upper_accounts_checker(self): + niveles = list(self.cleaned_df["nivel"].unique()) + niveles = sorted(niveles, reverse=True) #Este va disminuyendo [6,4,2,1] + + for index, children_level in enumerate(niveles[:-1]): + df_to_append = self.new_accounts(children_level, niveles[index+1]) + + + @handler_wrapper('Buscando cuentas nuevas para un nivel dado','Cuentas creadas con exito para uno de los niveles','Error creando cuentas para uno de los niveles','Error procesando nuevas cuentas') + def new_accounts(self, children_accounts_level, parent_level): + + failed_accounts_df = self.cleaned_df.loc[self.cleaned_df["checked"] == False] # .tolist() + + new_accounts_df = pd.DataFrame(columns=["account", "name", "balance"]) + + for account in failed_accounts_df.loc[failed_accounts_df["nivel"] == children_accounts_level, "account"].unique(): + + if account[:parent_level] in self.cleaned_df["account"].unique(): + #print(f"la cuenta {account[:new_accounts_level]} ya existe, no es necesario crearla") + pass + else: + failed_accounts_sum = failed_accounts_df.loc[ + (failed_accounts_df["account"].str.startswith(account[:parent_level])) & + (failed_accounts_df["nivel"] == children_accounts_level), "balance"].sum() + + new_line_df = pd.DataFrame({"account": [account[:parent_level]], + "name": ["cuenta autogenerada para chequeo de capitulos"], + "balance": [failed_accounts_sum], + "checked_balance": [failed_accounts_sum], + "nivel":[parent_level], + "checked":[False], + "created_data":1 + }) + logger.warning(f'cuenta creada: {account[:parent_level]}, por valor de {failed_accounts_sum}') + self.cleaned_df = pd.concat([self.cleaned_df, new_line_df]) + #self.cleaned_df.sort_values(by=['account'], inplace=True) #este no importa si lo quito + self.cleaned_df.reset_index(drop=True, inplace=True) #este sí lo necesito o da error en el subchapter_check + + + @handler_wrapper('Revisando ecuacion financiera','Ecuacion financiera chequeada con exito','Error revisando los valores de ecuacion financiera','Error revisando valores de ecuacion financiera') + def finance_account_fixer(self): + activos = self.cleaned_df.loc[self.cleaned_df["account"] == "1", "checked_balance"].values[0] + pasivos = self.cleaned_df.loc[self.cleaned_df["account"] == "2", "checked_balance"].values[0] + patrimonio = self.cleaned_df.loc[self.cleaned_df["account"] == "3", "checked_balance"].values[0] + ingresos = self.cleaned_df.loc[self.cleaned_df["account"] == "4", "checked_balance"].values[0] + gastos = self.cleaned_df.loc[self.cleaned_df["account"] == "5", "checked_balance"].values[0] + + logger.warning(f'Los valores encontrados son: \nactivo: {activos}, \npasivo: {pasivos}, \npatrimonio: {patrimonio}, \ningresos: {ingresos}, \ngastos: {gastos}') + + if not checker(activos, pasivos + patrimonio): + delta_diferencia = activos - pasivos - patrimonio + logger.warning(f'La ecuacion financiera no chequeó, el delta de activos - pasivos - patrimonio es: {delta_diferencia}') + delta_diferencia = ingresos - gastos + logger.warning(f'Delta diferencia de ingresos - gastos: {delta_diferencia}') + + account_to_modify_directory = {'Real':'36','Financiero':'39'} + account_to_modify = account_to_modify_directory[self.sector] + + if self.cleaned_df.loc[self.cleaned_df['account'] == account_to_modify].empty: + #crear cuenta + new_row = pd.Series({'account':account_to_modify, + 'name':'Cuenta creada para chequeo de ecuacion financiera', + 'balance':0, + 'checked':True, + 'nivel':2, + 'checked_balance':delta_diferencia, + 'created_data':1}) + self.cleaned_df = pd.concat([self.cleaned_df, new_row.to_frame().T]) + self.cleaned_df = self.cleaned_df.astype({'name': 'object', 'balance': 'float64', 'checked': 'bool', 'nivel': 'int64', 'checked_balance': 'float64', 'created_data': 'int64'}) #Esto lo necesito porque la concatenación me caga la subida de los datos + else: + #modificar cuenta + logger.warning(f"Valor original de la cuenta a modificar: \n{self.cleaned_df.loc[self.cleaned_df['account'] == account_to_modify].to_string()}") + self.cleaned_df.loc[self.cleaned_df['account'] == account_to_modify, 'checked_balance'] = self.cleaned_df.loc[self.cleaned_df['account'] == account_to_modify, 'checked_balance'] + delta_diferencia + self.cleaned_df.loc[self.cleaned_df['account'] == account_to_modify, 'name'] = '[MODIFICADO POR ECUACION FINANCIERA] '+self.cleaned_df.loc[self.cleaned_df['account'] == account_to_modify, 'name'] + + logger.warning(f"Valor modificado de la cuenta a modificar: \n{self.cleaned_df.loc[self.cleaned_df['account'] == account_to_modify].to_string()}") + return + + logger.warning(f'La ecuacion financier chequeó, no fue necesario agregar o modificar cuentas') + + + @handler_wrapper('Creando conexion a bd','Conexion a bd creada con exito','Error en la conexion a bd','Problemas creando la conexion a bd') + def create_conection_to_db(self): + db_schema = os.environ['DB_SCHEMA'] + secret_db_region = os.environ['SECRET_DB_REGION'] + secret_db_name = os.environ['SECRET_DB_NAME'] + db_secret = get_secret(secret_db_region, secret_db_name) + self.db_connection = connect_to_db(db_schema, db_secret) + + + @handler_wrapper('Haciendo borrado seguro de puc a reemplazar','Borrado seguro completado','Error al realizar borrado seguro','Se presenta error reemplazando informacion en base de datos') + def safe_delete_on_bd(self): + query = f"DELETE FROM ORIGINAL_PUC WHERE ID_ARCHIVE = {self.found_archive}" + logger.warning(query) + self.db_connection.execute(query) + + @handler_wrapper('Creando archive para los datos recibidos','Archive creado y asignado con exito','Error en la creacion del archive requerido','Se presenta error creando informacion en base de datos') + def create_archive_on_bd(self): + query_create_archive = f"INSERT INTO ARCHIVE (ID_COMPANY, INITIAL_DATE, PERIODICITY) VALUES ({self.create_archive_info['company_id']}, \"{self.create_archive_info['date']}\", \"{self.create_archive_info['periodicity']}\")" + logger.info(f'[create_archive] Query de creacion archive: {query_create_archive}') + self.db_connection.execute(query_create_archive) + + query_get_id_created_archive = f"SELECT ID FROM ARCHIVE WHERE ID_COMPANY={self.create_archive_info['company_id']} AND INITIAL_DATE=\"{self.create_archive_info['date']}\" AND PERIODICITY=\"{self.create_archive_info['periodicity']}\" LIMIT 1" + logger.warning(f'query para encontrar el id con el que se guardó el archive: {query_get_id_created_archive}') + rds_data = self.db_connection.execute(query_get_id_created_archive) + self.found_archive = dict(rds_data.mappings().all()[0])['ID'] + + + @handler_wrapper('Alistando dataframe para enviar a bd','Dataframe alistado correctamente','Error al alistar dataframe','Error alistando datos para guardado en base de datos') + def get_df_ready_to_db(self): + logger.warning(f'[get_df_ready_to_db] todo está llegando correctamente a alistamiento a base de datos') + logger.warning(f'[get_df_ready_to_db] El dataframe a cargar es:') + logger.warning(f"\n{self.cleaned_df.to_string()}") + #logger.warning(self.cleaned_df.head(5).to_string()) + self.ready_to_upload_df = self.cleaned_df.copy() + self.ready_to_upload_df['ID_ARCHIVE'] = self.found_archive + self.ready_to_upload_df['ACCOUNT_ORDER'] = self.ready_to_upload_df.index + self.ready_to_upload_df.drop(['checked' , 'nivel'], axis=1, inplace = True) + self.ready_to_upload_df.rename(columns={'account': 'ACCOUNT_NUMBER','name': 'ACCOUNT_NAME', 'balance':'ORIGINAL_BALANCE', 'checked_balance':'CHECKED_BALANCE', 'created_data':'CREATED_DATA'}, inplace=True) + + + + @handler_wrapper('Empezando envío de datos a bd','Envio de datos a bd terminado con exito','Error al subir informacion a bd','Hubieron problemas en la carga de la información a base de datos') + def send_to_db(self): + query_insert = self.ready_to_upload_df.to_sql(name = 'ORIGINAL_PUC', con=self.db_connection, if_exists='append', index=False) + + + def response_maker(self, succesfull = False, exception_str = str()): + if not succesfull: + self.final_response['body'] = json.dumps({'succesfull':0,'message':exception_str, 'date': self.initial_date}) + return self.final_response + self.final_response['body'] = json.dumps({'succesfull':1,'message':'ok', 'date': self.initial_date}) + return self.final_response + + +def checker(a, b): + return np.isclose(a, b, atol=0.1, rtol=0.001) #DIFERENCIA RELATIVA PERMITIDA + +def get_error_line(): + return str(sys.exc_info()[-1].tb_lineno) + + +def get_especific_error_line(): + _, _, exc_tb = sys.exc_info() + return str(traceback.extract_tb(exc_tb)[-1][1]) + + + + \ No newline at end of file diff --git a/corporate_finances_back_py/checker-to-db/utils.py b/corporate_finances_back_py/checker-to-db/utils.py new file mode 100644 index 0000000..9efbdea --- /dev/null +++ b/corporate_finances_back_py/checker-to-db/utils.py @@ -0,0 +1,33 @@ +#version 2023 - 05 - 04 +import base64 +import boto3 +import json +import logging + +from sqlalchemy import create_engine + +from decorators import handler_wrapper, debugger_wrapper + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + + +@debugger_wrapper('Error al obtener secreto','Error fatal de back conectando a base de datos') +def get_secret(secret_region, secret_name): + session = boto3.session.Session() + client_secrets_manager = session.client(service_name='secretsmanager', region_name=secret_region) + secret_data = client_secrets_manager.get_secret_value(SecretId=secret_name) + if 'SecretString' in secret_data: + secret_str = secret_data['SecretString'] + else: + secret_str = base64.b64decode(secret_data['SecretBinary']) + logger.info('[utils] (get_secret) Se obtuvo el secreto') + return json.loads(secret_str) + + +@debugger_wrapper('Error en la conexion a base de datos','Error fatal de back conectando a base de datos') +def connect_to_db(db_schema, db_secret): + conn_string = ('mysql+mysqlconnector://' + db_secret["username"] + ':' + db_secret["password"] + '@' + db_secret["host"] + ':' + str(db_secret["port"]) + '/' + db_schema) + sql_engine = create_engine(conn_string) + db_connection = sql_engine.connect() + return db_connection \ No newline at end of file diff --git a/corporate_finances_back_py/classifications-retrieve/__init__.py b/corporate_finances_back_py/classifications-retrieve/__init__.py new file mode 100644 index 0000000..37b06ae --- /dev/null +++ b/corporate_finances_back_py/classifications-retrieve/__init__.py @@ -0,0 +1,8 @@ + +if __name__ == '__init__' : + from decorators import handler_wrapper, timing, debugger_wrapper + from utils import get_secret, connect_to_db, connect_to_db_local_dev + +else: + from .decorators import handler_wrapper, timing, debugger_wrapper + from .utils import get_secret, connect_to_db, connect_to_db_local_dev \ No newline at end of file diff --git a/corporate_finances_back_py/classifications-retrieve/decorators.py b/corporate_finances_back_py/classifications-retrieve/decorators.py new file mode 100644 index 0000000..071760a --- /dev/null +++ b/corporate_finances_back_py/classifications-retrieve/decorators.py @@ -0,0 +1,63 @@ +#version 2023 - 05 - 04 +import logging +import sys +import traceback +from functools import wraps +from time import time + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + +def handler_wrapper(start, satisfactory_log, error_log, raise_error): + #esto se ejecuta en la inicializacion de primero + def decorator(func): + #print(message1) + #lo que yo ponga acá se ejecuta antes de hacer el llamado a la funcion + @wraps(func) + def wrapper(*args, **kwargs): + #esto sí se ejecuta solo cuando llama a la funcion decorada + #print(message2) + try: + logger.info(f'[{func.__name__}] {start}...') + resultado = func(*args, **kwargs) + logger.info(f'[{func.__name__}] {satisfactory_log}') + return resultado + except Exception as e: + logger.error(f"[{func.__name__}] {error_log}, linea: {get_especific_error_line(func.__name__)}, motivo: {str(e)}") + raise Exception(f"{raise_error}") + + return wrapper + return decorator + +def debugger_wrapper(error_log, raise_error): + def decorator(func): + @wraps(func) + def wrapper(*args, **kwargs): + try: + resultado = func(*args, **kwargs) + return resultado + except Exception as e: + logger.error(f"[{func.__name__}] {error_log}, linea: {get_especific_error_line(func.__name__)}, motivo: {str(e)}") + raise Exception(f"{raise_error}") + return wrapper + return decorator + + +def get_especific_error_line(func_name): + _, _, exc_tb = sys.exc_info() + for trace in traceback.extract_tb(exc_tb): + if func_name in trace: + return str(trace[1]) + +def timing(f): + @wraps(f) + def wrap(*args, **kw): + ts = time() + result = f(*args, **kw) + te = time() + taken_time_message = '[timing] La funcion {}, toma: {:.2f} sec en ejecutarse'.format(f.__name__, te-ts) + logger.info(taken_time_message) + return result + return wrap + + diff --git a/corporate_finances_back_py/classifications-retrieve/lambda_function.py b/corporate_finances_back_py/classifications-retrieve/lambda_function.py new file mode 100644 index 0000000..60d2ea4 --- /dev/null +++ b/corporate_finances_back_py/classifications-retrieve/lambda_function.py @@ -0,0 +1,208 @@ +import json +import logging +import sys +import os +from sqlalchemy import text + +if __name__ in ['__main__', 'lambda_function']: + from __init__ import * +else: + from .__init__ import * + +logging.basicConfig() +logging.basicConfig(format='%(asctime)s [%(levelname)s] [%(module)s] %(message)s', force=True, datefmt='%Y-%m-%d %H:%M:%S') +logger = logging.getLogger() +logger.setLevel(logging.INFO) + +def lambda_handler(event,context): + sc_obj = script_object(event) + lambda_response = sc_obj.starter() + logger.info(f'respuesta final de lambda: \n{lambda_response}') + return lambda_response + + +class script_object: + def __init__(self, event): + try: + self.failed_init = False + self.final_response = {'headers':{'Access-Control-Allow-Headers': '*', + 'Access-Control-Allow-Origin': '*', + 'Access-Control-Allow-Methods': '*'}, "statusCode": 500, 'body': {}} + self.db_connection = 0 + self.detailed_raise = '' + self.partial_response = {} + + logger.warning(f'event de entrada: {str(event)}') + + self.puc_chapters = {'1':'Activo', '2':'Pasivo', '3':'Patrimonio', '4':'Ingresos', '5':'Gastos', '6':'Costos de venta', '7':'Costos de producción o de operación', '8':'Cuentas de orden deudoras', '9':'Cuentas de orden acreedoras'} + self.status_dict = {'No clasificado': False} + + + event_dict = event['pathParameters'] + self.id_assessment = event_dict['id_assessment'] + self.all_archives_ids = list() + self.classification_master = list() + self.full_accounts = list() + self.archives_dates = list() + self.full_merged = list() + + + except Exception as e: + logger.error(f'[__init__] Error inicializando objeto lambda, linea: {get_current_error_line()}, motivo: {str(e)}') + self.failed_init = True + + @timing + def starter(self): + try: + if self.failed_init: + raise AttributeError('Error con los datos recibidos al servicio') + + self.create_conection_to_db() + self.get_user_classification() + if not self.classification_master: + self.get_default_sector_classification() + + self.get_historic_archives_ids() + self.get_puc_original_data() + self.balance_pucs_accounts() + self.merge_information() + self.filter_data_by_archive_date() + + self.db_connection.close() + return self.response_maker(succesfull_run = True) + except Exception as e: + if self.db_connection: + self.db_connection.close() + logger.error(f'[starter] Hubieron problemas en el comando de la linea: {get_current_error_line()}') + return self.response_maker(succesfull_run = False, error_str = (str(e))) + + @handler_wrapper('Creando conexion a bd','Conexion a bd creada con exito','Error en la conexion a bd','Problemas creando la conexion a bd') + def create_conection_to_db(self): + if __name__ != 'lambda_function': + self.db_connection = connect_to_db_local_dev() + return + + db_schema = os.environ['DB_SCHEMA'] + secret_db_region = os.environ['SECRET_DB_REGION'] + secret_db_name = os.environ['SECRET_DB_NAME'] + db_secret = get_secret(secret_db_region, secret_db_name) + self.db_connection = connect_to_db(db_schema, db_secret) + + @handler_wrapper('Chequeando si el proceso de valoración posee clasificacion de usuario', 'Chequeo terminado', 'Error chequeando si el proceso de valoración posee clasificación de usuario', 'Error extrayendo clasificación de usuario') + def get_user_classification(self): + query = f"SELECT A.ACCOUNT_NUMBER AS account, B.CLASSIFICATION AS classification FROM USER_CLASSIFICATION A, RAW_CLASSIFICATION B WHERE A.ID_RAW_CLASSIFICATION = B.ID AND A.ID_ASSESSMENT = :id_assessment ORDER BY A.ACCOUNT_NUMBER" + logger.info(f'[get_user_classification] Query para obtener el modelo de clasificaciones del proceso de valoracion:\n{query}') + rds_data = self.db_connection.execute(text(query), {'id_assessment': self.id_assessment}) + self.classification_master = [row._asdict() for row in rds_data.fetchall()] + + + @handler_wrapper('Ya que no hay clasificación de usuario, se requirió usar las clasificaciones por modelo a partir del sector', 'Clasificación por defecto adquirida con éxito', 'Error clasificación por defecto', 'Error extrayendo clasificación por defecto') + def get_default_sector_classification(self): + query = f"""SELECT D.ACCOUNT_NUMBER AS account, E.CLASSIFICATION AS classification FROM COMPANY A, ARCHIVE B, ASSESSMENT C, DEFAULT_CLASSIFICATION D, RAW_CLASSIFICATION E +WHERE A.ID = B.ID_COMPANY AND B.ID = C.ID_ARCHIVE AND A.SECTOR = D.SECTOR AND D.ID_RAW_CLASSIFICATION = E.ID AND C.ID = :id_assessment ORDER BY D.ACCOUNT_NUMBER""" + logger.info(f'[get_default_sector_classification] Query para obtener el modelo de clasificaciones por defecto:\n{query}') + rds_data = self.db_connection.execute(text(query), {'id_assessment': self.id_assessment}) + self.classification_master = [row._asdict() for row in rds_data.fetchall()] + + + @handler_wrapper('Buscando clasificacion master manual', 'Master asignado correctamente', 'Error adquiriendo master de clasificacion','Error adquiriendo clasificacion de analista') + def get_historic_archives_ids(self): + query = f"""SELECT B.ID FROM ARCHIVE B WHERE INITIAL_DATE IN (SELECT D.DATES FROM ASSESSMENT C, ASSESSMENT_DATES D +WHERE C.ID = D.ID_ASSESSMENT AND C.ID = :id_assessment AND D.PROPERTY = "HISTORIC") +AND ID_COMPANY = (SELECT B.ID_COMPANY FROM ARCHIVE B, ASSESSMENT C WHERE B.ID = ID_ARCHIVE AND C.ID = :id_assessment) ORDER BY B.INITIAL_DATE""" + logger.info(f'[get_historic_archives_ids] Query para obtener los archives seleccionados del proceso de valoracion:\n{query}') + rds_data = self.db_connection.execute(text(query), {'id_assessment': self.id_assessment}) + + self.all_archives_ids = [row.ID for row in rds_data.fetchall()] + + + @handler_wrapper('Obteniendo datos de pucs originales','Datos adquiridos correctamente','Error obteniendo datos de PUC','Error obteniendo Pucs') + def get_puc_original_data(self): + if len(self.all_archives_ids) == 1: + query = f"SELECT A.INITIAL_DATE AS initial_date, B.ACCOUNT_NUMBER AS account, B.CHECKED_BALANCE AS balance, B.ACCOUNT_NAME AS name FROM ARCHIVE A, ORIGINAL_PUC B WHERE A.ID = B.ID_ARCHIVE AND A.ID IN ({self.all_archives_ids[0]})" + else: + query = f"SELECT A.INITIAL_DATE AS initial_date, B.ACCOUNT_NUMBER AS account, B.CHECKED_BALANCE AS balance, B.ACCOUNT_NAME AS name FROM ARCHIVE A, ORIGINAL_PUC B WHERE A.ID = B.ID_ARCHIVE AND A.ID IN {tuple(self.all_archives_ids)}" + logger.info(f'[get_puc_original_data] Query para obtener los pucs originales del proceso de valoracion: {query}') + rds_data = self.db_connection.execute(text(query)) + self.full_accounts = [item._asdict() for item in rds_data.fetchall()] + self.archives_dates = sorted(list(set(item['initial_date'] for item in self.full_accounts))) #aca puedo colocar el inversor de fechas de archives + + + @handler_wrapper('Balanceando numeros de cuentas entre pucs historicos', 'Balanceado de pucs historics exitoso', 'Error balanceando cuentas de pucs historicos', 'Error construyendo cuentas para balanceado de pucs historicos') + def balance_pucs_accounts(self): + archives_accounts_directory = {archive: list() for archive in self.archives_dates} + all_historic_account_numbers = set() + for row in self.full_accounts: + all_historic_account_numbers.add(row['account']) + archives_accounts_directory[row['initial_date']].append(row['account']) + + for archive_date, this_archive_accounts in archives_accounts_directory.items(): + this_archive_missing_accounts = [item for item in all_historic_account_numbers if item not in this_archive_accounts] + logger.warning(f'[mira aca] al puc de la fecha {archive_date} le hacen falta las cuentas {this_archive_missing_accounts}') + for account_number in this_archive_missing_accounts: + self.full_accounts.append({'account': account_number, 'name': 'Cuenta creada para balanceo de pucs historicos', 'balance': 0, 'ID_RAW_CLASSIFICATION':0, 'initial_date': archive_date}) + + + @handler_wrapper('Emergiendo informacion a cuentas', 'Información asignada con exito', 'Error emergiendo información a cuentas', 'Error asignando informacion a cuentas') + def merge_information(self): + full_accounts_basic_merge = [self.merge_single_account_information(item) for item in self.full_accounts] + full_accounts_classified = self.merge_classification(full_accounts_basic_merge) + self.full_merged = [ self.merge_status(item) for item in full_accounts_classified] + logger.warning(f'zero: {self.full_merged}') + + + @debugger_wrapper('Error asignando caracteristicas a cuenta', 'Error emergiendo informacion') + def merge_single_account_information(self, account_dict): + account_dict['chapter'] = self.puc_chapters.get(account_dict['account'][0]) + account_dict['nivel'] = len(account_dict['account']) + account_dict['classification'] = 'No aplica' + + account_dict['initial_date'] = account_dict['initial_date'].strftime('%Y-%m-%d') + account_dict['balance'] = float(account_dict['balance']) + return account_dict + + + @debugger_wrapper('Problemas asignando clasificaciones', 'Error asignando clasificaciones') + def merge_classification(self, accounts): + for master_account in self.classification_master: + for filtered_account in [account for account in accounts if account['account'].startswith(master_account['account'])]: + filtered_account['classification'] = master_account['classification'] + return accounts + + #@handler_wrapper('Emergiendo status para el pool de items emergido', 'Status declarado con exito', 'Error emergiendo status', 'Error asignando status con respecto a las clasificaciones') + @debugger_wrapper('Error emergiendo status para el pool de items emergido', 'Error asignando status con respecto a las clasificaciones') + def merge_status(self, item): + item['status'] = self.status_dict.get(item['classification'], True) + return item + + + + + @handler_wrapper('Filtrando las datas respectivas a las fechas de archives', 'Data preparada para front', 'Error preparando informacion a front, problemas filtrando DATA por fechas de archives', 'Error preparando data') + def filter_data_by_archive_date(self): + self.partial_response = [] + for date in self.archives_dates: + this_short_date = date.strftime('%Y-%m-%d') + partial_date_data = {'date': this_short_date, 'data': [item for item in self.full_merged if item['initial_date'] == this_short_date]} + self.partial_response.append(partial_date_data) + + + @debugger_wrapper('Error construyendo respuesta final', 'Error construyendo respuesta') + def response_maker(self, succesfull_run = False, error_str = str()): + if succesfull_run: + self.final_response['statusCode'] = 200 + self.final_response['body'] = json.dumps(self.partial_response) + return self.final_response + + self.final_response['body'] = json.dumps(self.detailed_raise if self.detailed_raise else error_str) + return self.final_response + + + +def get_current_error_line(): + return str(sys.exc_info()[-1].tb_lineno) + + +if __name__ == "__main__": + event = {"pathParameters": {"id_assessment": "2037"}} + lambda_handler(event, '') \ No newline at end of file diff --git a/corporate_finances_back_py/classifications-retrieve/utils.py b/corporate_finances_back_py/classifications-retrieve/utils.py new file mode 100644 index 0000000..2535076 --- /dev/null +++ b/corporate_finances_back_py/classifications-retrieve/utils.py @@ -0,0 +1,46 @@ +#version 2023 - 05 - 04 +import base64 +import boto3 +import json +import logging +import os +from sqlalchemy import create_engine + +if __name__ == 'utils': + from decorators import handler_wrapper, debugger_wrapper +else: + from .decorators import handler_wrapper, debugger_wrapper + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + + +@debugger_wrapper('Error al obtener secreto','Error fatal de back conectando a base de datos') +def get_secret(secret_region, secret_name): + session = boto3.session.Session() + client_secrets_manager = session.client(service_name='secretsmanager', region_name=secret_region) + secret_data = client_secrets_manager.get_secret_value(SecretId=secret_name) + if 'SecretString' in secret_data: + secret_str = secret_data['SecretString'] + else: + secret_str = base64.b64decode(secret_data['SecretBinary']) + logger.info('[utils] (get_secret) Se obtuvo el secreto') + return json.loads(secret_str) + + +@debugger_wrapper('Error en la conexion a base de datos','Error fatal de back conectando a base de datos') +def connect_to_db(db_schema, db_secret): + conn_string = ('mysql+mysqlconnector://' + db_secret["username"] + ':' + db_secret["password"] + '@' + db_secret["host"] + ':' + str(db_secret["port"]) + '/' + db_schema) + sql_engine = create_engine(conn_string) + db_connection = sql_engine.connect() + return db_connection + + +@debugger_wrapper('Error en la conexion a base de datos','Error fatal de back conectando a base de datos') +def connect_to_db_local_dev(): + from dotenv import load_dotenv + load_dotenv() + conn_string = os.environ['local_dev_connector'] + sql_engine = create_engine(conn_string) + db_connection = sql_engine.connect() + return db_connection diff --git a/corporate_finances_back_py/classifications/decorators.py b/corporate_finances_back_py/classifications/decorators.py new file mode 100644 index 0000000..db17c59 --- /dev/null +++ b/corporate_finances_back_py/classifications/decorators.py @@ -0,0 +1,84 @@ +#version 2024 - 02 - 20 +import logging +import sys +import traceback +from functools import wraps +from time import time + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + +def handler_wrapper(start, satisfactory_log, error_log, raise_error): + #esto se ejecuta en la inicializacion de primero + def decorator(func): + #print(message1) + #lo que yo ponga acá se ejecuta antes de hacer el llamado a la funcion + @wraps(func) + def wrapper(*args, **kwargs): + #esto sí se ejecuta solo cuando llama a la funcion decorada + #print(message2) + try: + logger.info(f'[{func.__name__}] {start}...') + resultado = func(*args, **kwargs) + logger.info(f'[{func.__name__}] {satisfactory_log}') + return resultado + except Exception as e: + logger.error(f"[{func.__name__}] {error_log}, linea: {get_especific_error_line(func.__name__)}, motivo: {str(e)}") + raise Exception(f"{raise_error}") + + return wrapper + return decorator + +def debugger_wrapper(error_log, raise_error): + def decorator(func): + @wraps(func) + def wrapper(*args, **kwargs): + try: + resultado = func(*args, **kwargs) + return resultado + except Exception as e: + logger.error(f"[{func.__name__}] {error_log}, linea: {get_especific_error_line(func.__name__)}, motivo: {str(e)}") + raise Exception(f"{raise_error}") + return wrapper + return decorator + +def try_pass_wrapper(error_log): + def decorator(func): + @wraps(func) + def wrapper(*args, **kwargs): + try: + resultado = func(*args, **kwargs) + return resultado + except Exception as e: + logger.debug(f"[{func.__name__}] {error_log}, linea: {get_especific_error_line(func.__name__)}, motivo: {str(e)}") + return wrapper + return decorator + +def runs_ok(func): + def wrapper_func(*args, **kwargs): + try: + func(*args, **kwargs) + return True + except Exception: + return False + return wrapper_func + + +def get_especific_error_line(func_name): + _, _, exc_tb = sys.exc_info() + for trace in traceback.extract_tb(exc_tb): + if func_name in trace: + return str(trace[1]) + +def timing(f): + @wraps(f) + def wrap(*args, **kw): + ts = time() + result = f(*args, **kw) + te = time() + taken_time_message = '[timing] La funcion {}, toma: {:.2f} sec en ejecutarse'.format(f.__name__, te-ts) + logger.info(taken_time_message) + return result + return wrap + + diff --git a/corporate_finances_back_py/classifications/lambda_function.py b/corporate_finances_back_py/classifications/lambda_function.py new file mode 100644 index 0000000..dcb8b4d --- /dev/null +++ b/corporate_finances_back_py/classifications/lambda_function.py @@ -0,0 +1,111 @@ +""": +capas +capa-pandas-data-transfer + +variables de entorno +DB_SCHEMA : src_corporate_finance +RAW_CLASSIFICATION_TABLE : RAW_CLASSIFICATION +SECRET_DB_NAME : precia/rds8/sources/finanzas_corporativas +SECRET_DB_REGION : us-east-1 + +RAM: 512 MB +""" + + +import boto3 +import datetime +import json +import logging +import sys +import traceback +import os +from sqlalchemy import text + + +from utils import * +from decorators import handler_wrapper, timing + + +def lambda_handler(event, context): + logger.info(f'[lambda_handler] Event de entrada: {event}\nContext de entrada: {context}') + sc_obj = script_object() + return sc_obj.starter() + + +class script_object: + def __init__(self): + try: + logger.info('[__INIT__] Inicializando objeto lambda ...') + self.final_response = {'headers':{'Access-Control-Allow-Headers': '*', 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Methods': '*'}, 'statusCode': 200} + self.db_connection = '' + + self.failed_init = False + logger.info('[__INIT__] Objeto lambda inicializada exitosamente') + + except Exception as e: + self.failed_init = True + logger.error(f"[__INIT__] error en inicializacion, linea: {get_especific_error_line()}, motivo: "+str(e)) + + + def starter(self): + try: + if self.failed_init: + raise AttributeError('Falla inicializacion, revisar logs') + self.create_clients() + self.get_classifications() + + self.db_connection.close() + return self.response_maker(succesfull = True) + + except Exception as e: + if self.db_connection: + self.db_connection.close() + logger.error(f'[starter] Error en el procesamieno del comando de la linea: {get_current_error_line()}, motivo: {e}') + return self.response_maker(succesfull = False, exception_str = str(e)) + + @handler_wrapper('Creando clientes a servicios externos','Clientes a servicios construidos','Error construyendo conexiones a recursos externos','Problemas requiriendo recursos externos') + def create_clients(self): + if __name__ != 'lambda_function': + self.db_connection = connect_to_db_local_dev() + print('print de debug') + self.db_connection.begin() + print('print de debug') + return + db_schema = os.environ['DB_SCHEMA'] + secret_db_region = os.environ['SECRET_DB_REGION'] + secret_db_name = os.environ['SECRET_DB_NAME'] + db_secret = get_secret(secret_db_region, secret_db_name) + self.db_connection = connect_to_db(db_schema, db_secret) + + + @handler_wrapper('Obteniendo listado de clasificaciones','Listado obtenido','Error obteniendo listado de clasificaciones','Error obteniendo listado de clasificaciones') + def get_classifications(self): + query = "SELECT CLASSIFICATION FROM RAW_CLASSIFICATION WHERE IS_PARENT = 0" + logger.info(f"Query a base de datos para obtener la data del puc:\n {query}") + rds_data = self.db_connection.execute(query) + self.classifications_array = list(map(lambda item: item['CLASSIFICATION'], rds_data.mappings().all() )) + logger.warning(f'array obtenido: {self.classifications_array} de tipo {type(self.classifications_array)}') + + + + def response_maker(self, succesfull = False, exception_str = str()): + if not succesfull: + self.final_response['body'] = json.dumps(exception_str) + return self.final_response + self.final_response['body'] = json.dumps(self.classifications_array) + return self.final_response + + + + +def get_current_error_line(): + return str(sys.exc_info()[-1].tb_lineno) + + +def get_especific_error_line(): + _, _, exc_tb = sys.exc_info() + return str(traceback.extract_tb(exc_tb)[-1][1]) + + +if __name__ == '__main__': + lambda_handler('','') \ No newline at end of file diff --git a/corporate_finances_back_py/classifications/utils.py b/corporate_finances_back_py/classifications/utils.py new file mode 100644 index 0000000..c4fc5b2 --- /dev/null +++ b/corporate_finances_back_py/classifications/utils.py @@ -0,0 +1,76 @@ +""" +variables de entorno: +DB_SCHEMA : src_corporate_finance +RAW_CLASSIFICATION_TABLE : RAW_CLASSIFICATION +SECRET_DB_NAME : precia/rds8/sources/finanzas_corporativas +SECRET_DB_REGION : us-east-1 +""" + + +import base64 +import boto3 +import json +import logging +import os +import sys + +from sqlalchemy import create_engine +from sqlalchemy.pool import NullPool + +from decorators import handler_wrapper, debugger_wrapper + + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + + +@handler_wrapper('Obteniendo secreto','secreto obtenido','Error al obtener secreto','error fatal de back') +def get_secret(secret_region, secret_name): + """ + Obtiene las credenciales que vienen del Secret Manager + :param secret_region: (string) Nombre de la region donde se encuentran las credenciales + :param secrete_name: (string) Nombre del secreto + :return: (dict) Diccionario con las credenciales + """ + session = boto3.session.Session() + client_secrets_manager = session.client(service_name='secretsmanager', region_name=secret_region) + secret_data = client_secrets_manager.get_secret_value(SecretId=secret_name) + if 'SecretString' in secret_data: + secret_str = secret_data['SecretString'] + else: + secret_str = base64.b64decode(secret_data['SecretBinary']) + logger.info('[utils] (get_secret) Se obtuvo el secreto') + return json.loads(secret_str) + + +@handler_wrapper('Conectando a base de datos {a}','Conectado correctamente a base de datos','Error en la conexion a base de datos','error fatal de back') +def connect_to_db(db_schema, db_secret): + """ + Se conecta a dos bases de datos por medio de las variables de entorno + :return: (tuple) Contiene los objetos sqlalchemy para ejecutar queries + """ + + conn_string = ('mysql+mysqlconnector://' + db_secret["username"] + ':' + db_secret["password"] + '@' + db_secret["host"] + ':' + str(db_secret["port"]) + '/' + db_schema) + sql_engine = create_engine(conn_string) + db_connection = sql_engine.connect() + return db_connection + + +@debugger_wrapper('Error en la conexion a base de datos','Error fatal de back conectando a base de datos') +def connect_to_db_local_dev(): + from dotenv import load_dotenv + load_dotenv() + conn_string = os.environ['local_dev_connector'] + sql_engine = create_engine(conn_string) + with sql_engine.connect() as db_connection: + db_connection = sql_engine.connect() + return db_connection + + +def get_current_error_line(): + return str(sys.exc_info()[-1].tb_lineno) + + +def get_especific_error_line(): + _, _, exc_tb = sys.exc_info() + return str(traceback.extract_tb(exc_tb)[-1][1]) diff --git a/corporate_finances_back_py/companies-create/decorators.py b/corporate_finances_back_py/companies-create/decorators.py new file mode 100644 index 0000000..1acc589 --- /dev/null +++ b/corporate_finances_back_py/companies-create/decorators.py @@ -0,0 +1,34 @@ +import logging +import sys +import traceback + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + +def handler_wrapper(start, satisfactory_log, error_log, raise_error): + #esto se ejecuta en la inicializacion de primero + def decorator(func): + #print(message1) + #lo que yo ponga acá se ejecuta antes de hacer el llamado a la funcion + def wrapper(*args, **kwargs): + #esto sí se ejecuta solo cuando llama a la funcion decorada + #print(message2) + try: + logger.info(f'[{func.__name__}] {start}...') + resultado = func(*args, **kwargs) + logger.info(f'[{func.__name__}] {satisfactory_log}') + return resultado + except Exception as e: + logger.error(f"[{func.__name__}] {error_log}, linea: {get_especific_error_line(func.__name__)}, motivo: {str(e)}") + raise Exception(f"[{func.__name__}] {raise_error}") + + return wrapper + return decorator + + + +def get_especific_error_line(func_name): + _, _, exc_tb = sys.exc_info() + for trace in traceback.extract_tb(exc_tb): + if func_name in trace: + return str(trace[1]) \ No newline at end of file diff --git a/corporate_finances_back_py/companies-create/lambda_function.py b/corporate_finances_back_py/companies-create/lambda_function.py new file mode 100644 index 0000000..4690c1b --- /dev/null +++ b/corporate_finances_back_py/companies-create/lambda_function.py @@ -0,0 +1,146 @@ +""": +============================================================= + +Nombre: lbd-dev-layer-fincor-companies-create-post +Tipo: Lambda AWS +Autor: Jeisson David Botache Yela +Tecnología - Precia + +Ultima modificación: 04/08/2022 + +Para el proyecto Delta de finanzas corporativas se requiere que se realice una clasificacion +'default' de las cuentas, esta clasificacion es dependiente del tipo de empresa que haya +elegido el analista, + + +Requerimientos: +capa-pandas-data-transfer v5 + + +variables de entorno: +DB_SCHEMA : src_corporate_finance +SECRET_DB_NAME : precia/rds8/sources/finanzas_corporativas +SECRET_DB_REGION : us-east-1 +TABLE_NAME : COMPANY +============================================================= +""" + +import boto3 +import json +import logging +import sys +import traceback + + +from utils import * +from sqlalchemy import create_engine +from decorators import handler_wrapper + +logger = logging.getLogger() +logger.setLevel(logging.INFO) +failed_init = False + +try: + logger.info('[__INIT__] Inicializando Lambda ...') + db_schema = os.environ['DB_SCHEMA'] + secret_db_name = os.environ['SECRET_DB_NAME'] + secret_db_region = os.environ['SECRET_DB_REGION'] + table_name = os.environ['TABLE_NAME'] + s3_client = boto3.client('s3') + + db_secret = get_secret(secret_db_region, secret_db_name) + + + logger.info('[__INIT__] Lambda inicializada exitosamente') + +except Exception as e: + failed_init = True + logger.error(f"[__INIT__] error en inicializacion, motivo: " + str(e)) + + +def lambda_handler(event, context): + logger.error(f"event de entrada: \n{str(event)}") + if failed_init: + return response_maker() + try: + key_values = process_event(event) + company_to_db(key_values) + + logger.info('[Lambda Handler] Tareas de la lambda terminadas satisfactoriamente, creando respuesta...') + return response_maker(succesfull=True, exception='') + + except Exception as e: + logger.error( + f'[Lambda Handler] Tareas de la lambda reportan errores fatales en el comando de la linea: {get_current_error_line()}, motivo: {str(e)}, creando respuesta...') + return response_maker(succesfull=False, exception=str(e)) + + +@handler_wrapper('Obteniendo valores clave de event', 'Valores de event obtenidos correctamente', + 'Error al obtener valores event', 'Fallo en la obtencion de valores clave de event') +def process_event(event): + event_body_json = event["body"] + event_body_dict = json.loads(event_body_json) + key_values = {} + key_values['Nit'] = event_body_dict["nit"].strip() + key_values['Name'] = event_body_dict["name"] + key_values['Sector'] = event_body_dict['sector'] + + return key_values + + +@handler_wrapper('Cargando empresa a base de datos', 'Empresa agregada a base de datos satisfactoriamente', + 'Error al cargar empresa a base de datos', 'Fallo en agregar la empresa a base de datos, es posible que la empresa ya exista') +def company_to_db(key_values): + + db_connection = connect_to_db(db_schema, db_secret) + + query = f"INSERT INTO {table_name} (NIT, SECTOR ,NAME) VALUES (\"{key_values['Nit']}\", \"{key_values['Sector']}\", \"{key_values['Name']}\")" + + logger.info(f"query a base de datos crear empresa {query} ") #TODO: borrar esto en paso a pruebas + db_connection.execute(query) + + +def response_maker(succesfull = False , exception = ''): + """: + Funcion que construye la respuesta general del lambda, para llegar se activa si todo salió bien en lambda handler + o si algo salió mal y se disparó el la excepcion general de esta. En caso de llegar a este metodo por medio de una excepcion + se trae un motivo de falla que no será mostrado al analista a menos que lo esté asesorando un desarrollador. + :succesfull: determina si el metodo se está ejecutando como excepcion o como salida correcta + :exception: motivo de error + :error_line: linea de falla + :returns: la funcion regresa el objeto alistado que lambda handler rergesará al disparador. status_code dependiente + si hubieron errores y mensajes acordes o una respuesta positiva con un message ok. En cualquier + caso se deben agregar tambien los encabezados 'Acces-Control' para que api gateway no corte la comunicacion back-front + """ + headers = {'headers': {'Access-Control-Allow-Headers': '*', 'Access-Control-Allow-Origin': '*','Access-Control-Allow-Methods': '*'}} + if not succesfull: + try: + error_response = {'statusCode': 500, + 'body' : json.dumps(f'error de ejecución interno, motivo: {exception}')} + error_response.update(headers) + return error_response + except Exception as e: + logger.error(f'[response_maker] Error al construir la respuesta de error, linea: {get_current_error_line()}, motivo: {str(e)}') + return 'Fatal error' + + + try: + + ok_response = {'statusCode': 200} + ok_response.update(headers) + body = {'message':'Empresa creada satisfactoriamente'} + ok_response["body"] = json.dumps(body) + return ok_response + + except Exception as e: + logger.error(f'[response_maker] Error al construir la respuesta de terminacion satisfactoria, linea: {get_current_error_line()}, motivo: {str(e)}') + return response_maker(succesfull = False, exception = str(e)) + + + +def get_current_error_line(): + return str(sys.exc_info()[-1].tb_lineno) + +def get_especific_error_line(): + _, _, exc_tb = sys.exc_info() + return str(traceback.extract_tb(exc_tb)[-1][1]) \ No newline at end of file diff --git a/corporate_finances_back_py/companies-create/utils.py b/corporate_finances_back_py/companies-create/utils.py new file mode 100644 index 0000000..738f74f --- /dev/null +++ b/corporate_finances_back_py/companies-create/utils.py @@ -0,0 +1,56 @@ +import base64 +import boto3 +import json +import logging +import os +import sys +import traceback + +from sqlalchemy import create_engine + +from decorators import handler_wrapper + + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + + +@handler_wrapper('Obteniendo secreto','secreto obtenido','Error al obtener secreto','error fatal de back') +def get_secret(secret_region, secret_name): + """ + Obtiene las credenciales que vienen del Secret Manager + :param secret_region: (string) Nombre de la region donde se encuentran las credenciales + :param secrete_name: (string) Nombre del secreto + :return: (dict) Diccionario con las credenciales + """ + session = boto3.session.Session() + client_secrets_manager = session.client(service_name='secretsmanager', region_name=secret_region) + secret_data = client_secrets_manager.get_secret_value(SecretId=secret_name) + if 'SecretString' in secret_data: + secret_str = secret_data['SecretString'] + else: + secret_str = base64.b64decode(secret_data['SecretBinary']) + logger.info('[utils] (get_secret) Se obtuvo el secreto') + return json.loads(secret_str) + + +@handler_wrapper('Conectando a base de datos {a}','Conectado correctamente a base de datos','Error en la conexion a base de datos','error fatal de back') +def connect_to_db(db_schema, db_secret): + """ + Se conecta a dos bases de datos por medio de las variables de entorno + :return: (tuple) Contiene los objetos sqlalchemy para ejecutar queries + """ + + conn_string = ('mysql+mysqlconnector://' + db_secret["username"] + ':' + db_secret["password"] + '@' + db_secret["host"] + ':' + str(db_secret["port"]) + '/' + db_schema) + sql_engine = create_engine(conn_string) + db_connection = sql_engine.connect() + return db_connection + + +def get_current_error_line(): + return str(sys.exc_info()[-1].tb_lineno) + + +def get_especific_error_line(): + _, _, exc_tb = sys.exc_info() + return str(traceback.extract_tb(exc_tb)[-1][1]) diff --git a/corporate_finances_back_py/companies-exists/decorators.py b/corporate_finances_back_py/companies-exists/decorators.py new file mode 100644 index 0000000..1aba58c --- /dev/null +++ b/corporate_finances_back_py/companies-exists/decorators.py @@ -0,0 +1,47 @@ +#version 2022 - 12 - 06 +import logging +import sys +import traceback +from functools import wraps +from time import time + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + +def handler_wrapper(start, satisfactory_log, error_log, raise_error): + #esto se ejecuta en la inicializacion de primero + def decorator(func): + #print(message1) + #lo que yo ponga acá se ejecuta antes de hacer el llamado a la funcion + def wrapper(*args, **kwargs): + #esto sí se ejecuta solo cuando llama a la funcion decorada + #print(message2) + try: + logger.info(f'[{func.__name__}] {start}...') + resultado = func(*args, **kwargs) + logger.info(f'[{func.__name__}] {satisfactory_log}') + return resultado + except Exception as e: + logger.error(f"[{func.__name__}] {error_log}, linea: {get_especific_error_line(func.__name__)}, motivo: {str(e)}") + raise Exception(f"{raise_error}") + + return wrapper + return decorator + + +def get_especific_error_line(func_name): + _, _, exc_tb = sys.exc_info() + for trace in traceback.extract_tb(exc_tb): + if func_name in trace: + return str(trace[1]) + +def timing(f): + @wraps(f) + def wrap(*args, **kw): + ts = time() + result = f(*args, **kw) + te = time() + taken_time_message = '[timing] La funcion {}, toma: {:.2f} sec en ejecutarse'.format(f.__name__, te-ts) + logger.info(taken_time_message) + return result + return wrap diff --git a/corporate_finances_back_py/companies-exists/lambda_function.py b/corporate_finances_back_py/companies-exists/lambda_function.py new file mode 100644 index 0000000..84aed07 --- /dev/null +++ b/corporate_finances_back_py/companies-exists/lambda_function.py @@ -0,0 +1,146 @@ +""": +============================================================= + +Nombre: lbd-dev-layer-fincor-companies-exists-get +Tipo: Lambda AWS +Autor: Jeisson David Botache Yela +Tecnología - Precia + +Ultima modificación: 03/08/2022 + +Para el proyecto Delta de finanzas corporativas se requiere que se realice una clasificacion +'default' de las cuentas + + +Requerimientos: +capa-pandas-data-transfer v.02 + + +variables de entorno: +DB_SCHEMA : src_corporate_finance +SECRET_DB_NAME : precia/rds8/sources/finanzas_corporativas +SECRET_DB_REGION : us-east-1 +TABLE_NAME : COMPANY + +RAM: 512 MB +============================================================= +""" + +import boto3 +import json +import logging +import sys +import traceback + +from utils import * + +from decorators import handler_wrapper, timing + +logger = logging.getLogger() +logger.setLevel(logging.INFO) +failed_init = False + +try: + logger.info('[__INIT__] Inicializando Lambda ...') + db_schema = os.environ['DB_SCHEMA'] + secret_db_name = os.environ['SECRET_DB_NAME'] + secret_db_region = os.environ['SECRET_DB_REGION'] + table_name = os.environ['TABLE_NAME'] + s3_client = boto3.client('s3') + + db_secret = get_secret(secret_db_region, secret_db_name) + logger.info('[__INIT__] Lambda inicializada exitosamente') + + +except Exception as e: + failed_init = True + logger.error(f"[__INIT__] error en inicializacion, motivo: " + str(e)) + + +def lambda_handler(event, context): + #TODO: documentar metodo + if failed_init: + return {'statusCode': 500, 'body': json.dumps('Error al inicializar lambda')} + + try: + db_connection = connect_to_db(db_schema, db_secret) + key_values = process_event(event) + companie_exists = search_existing(key_values, db_connection) + + logger.info('[Lambda Handler] Tareas de la lambda terminadas satisfactoriamente, creando respuesta...') + return response_maker(companie_exists, succesfull=True, exception='') + + except Exception as e: + logger.error( + f'[Lambda Handler] Tareas de la lambda reportan errores fatales en el comando de la linea: {get_current_error_line()}, motivo: {str(e)}, creando respuesta...') + response_maker(True,succesfull=False, exception=str(e)) + +@handler_wrapper('Buscando nit en event','Nit encontrado satisfactoriamente','Error al buscar nit en event','No se pudo encontrar el nit en la dirección requerida') +def process_event(event): + #TODO: documentar metodo + logger.info(f'{str(event)}') #TODO: borra esto en paso a pruebas + key_values = {} + key_values['Nit'] = event["pathParameters"]["nit"] + logger.info(f"nit encontrado: {key_values['Nit']}") + + return key_values + +@handler_wrapper('Buscando nit en base de datos','Busqueda terminada','Error al buscar nit en base de datos','Error al buscar, reporte al administrador del sistema') +def search_existing(key_values, db_connection): + #TODO: documentar metodo + query = f"SELECT * FROM {table_name} WHERE NIT=\"{key_values['Nit']}\" LIMIT 1" + logger.info(f'Query a base de datos: {query}') + rds_data = db_connection.execute(query) + + + if rds_data.rowcount != 0: + resultado = dict(rds_data.mappings().all()[0]) + + logger.info(f'{resultado}') #TODO: borra esto en paso a pruebas + logger.info(f'{type(resultado)}') #TODO: borra esto en paso a pruebas + return resultado + return {} + +def response_maker(companie_exists, succesfull = False , exception = ''): + """: + Funcion que construye la respuesta general del lambda, para llegar se activa si todo salió bien en lambda handler + o si algo salió mal y se disparó el la excepcion general de esta. En caso de llegar a este metodo por medio de una excepcion + se trae un motivo de falla que no será mostrado al analista a menos que lo esté asesorando un desarrollador. + :succesfull: determina si el metodo se está ejecutando como excepcion o como salida correcta + :exception: motivo de error + :error_line: linea de falla + :returns: la funcion regresa el objeto alistado que lambda handler rergesará al disparador. status_code dependiente + si hubieron errores y mensajes acordes o una respuesta positiva con un message ok. En cualquier + caso se deben agregar tambien los encabezados 'Acces-Control' para que api gateway no corte la comunicacion back-front + """ + headers = {'headers': {'Access-Control-Allow-Headers': '*', 'Access-Control-Allow-Origin': '*','Access-Control-Allow-Methods': '*'}} + if not succesfull: + try: + error_response = {'statusCode': 500, + 'body' : json.dumps(f'error de ejecución, motivo: {exception}')} + error_response.update(headers) + return error_response + except Exception as e: + logger.error(f'[response_maker] Error al construir la respuesta de error, linea: {get_current_error_line()}, motivo: {str(e)}') + return 'Fatal error' + + + try: + + ok_response = {'statusCode': 200} + ok_response.update(headers) + body = {} + ok_response["body"] = json.dumps(companie_exists) #TODO:revisar esto con Daniel, objeto o json + return ok_response + + except Exception as e: + logger.error(f'[response_maker] Error al construir la respuesta de terminacion satisfactoria, linea: {get_current_error_line()}, motivo: {str(e)}') + return response_maker({}, succesfull = False, exception = str(e)) + + +def get_current_error_line(): + return str(sys.exc_info()[-1].tb_lineno) + +def get_especific_error_line(): + _, _, exc_tb = sys.exc_info() + return str(traceback.extract_tb(exc_tb)[-1][1]) \ No newline at end of file diff --git a/corporate_finances_back_py/companies-exists/utils.py b/corporate_finances_back_py/companies-exists/utils.py new file mode 100644 index 0000000..5997971 --- /dev/null +++ b/corporate_finances_back_py/companies-exists/utils.py @@ -0,0 +1,56 @@ +import base64 +import boto3 +import json +import logging +import os +import sys +import traceback + +from sqlalchemy import create_engine + +from decorators import handler_wrapper + + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + + +@handler_wrapper('Obteniendo secreto','secreto obtenido','Error al obtener secreto','error fatal de back') +def get_secret(secret_region, secret_name): + """ + Obtiene las credenciales que vienen del Secret Manager + :param secret_region: (string) Nombre de la region donde se encuentran las credenciales + :param secrete_name: (string) Nombre del secreto + :return: (dict) Diccionario con las credenciales + """ + session = boto3.session.Session() + client_secrets_manager = session.client(service_name='secretsmanager', region_name=secret_region) + secret_data = client_secrets_manager.get_secret_value(SecretId=secret_name) + if 'SecretString' in secret_data: + secret_str = secret_data['SecretString'] + else: + secret_str = base64.b64decode(secret_data['SecretBinary']) + logger.info('[utils] (get_secret) Se obtuvo el secreto') + return json.loads(secret_str) + + +@handler_wrapper('Conectando a base de datos','Conectado correctamente a base de datos','Error en la conexion a base de datos','error fatal de back') +def connect_to_db(db_schema, db_secret): + """ + Se conecta a dos bases de datos por medio de las variables de entorno + :return: (tuple) Contiene los objetos sqlalchemy para ejecutar queries + """ + + conn_string = ('mysql+mysqlconnector://' + db_secret["username"] + ':' + db_secret["password"] + '@' + db_secret["host"] + ':' + str(db_secret["port"]) + '/' + db_schema) + sql_engine = create_engine(conn_string) + db_connection = sql_engine.connect() + return db_connection + + +def get_current_error_line(): + return str(sys.exc_info()[-1].tb_lineno) + + +def get_especific_error_line(): + _, _, exc_tb = sys.exc_info() + return str(traceback.extract_tb(exc_tb)[-1][1]) diff --git a/corporate_finances_back_py/companies-puc-archive-info/decorators.py b/corporate_finances_back_py/companies-puc-archive-info/decorators.py new file mode 100644 index 0000000..1aba58c --- /dev/null +++ b/corporate_finances_back_py/companies-puc-archive-info/decorators.py @@ -0,0 +1,47 @@ +#version 2022 - 12 - 06 +import logging +import sys +import traceback +from functools import wraps +from time import time + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + +def handler_wrapper(start, satisfactory_log, error_log, raise_error): + #esto se ejecuta en la inicializacion de primero + def decorator(func): + #print(message1) + #lo que yo ponga acá se ejecuta antes de hacer el llamado a la funcion + def wrapper(*args, **kwargs): + #esto sí se ejecuta solo cuando llama a la funcion decorada + #print(message2) + try: + logger.info(f'[{func.__name__}] {start}...') + resultado = func(*args, **kwargs) + logger.info(f'[{func.__name__}] {satisfactory_log}') + return resultado + except Exception as e: + logger.error(f"[{func.__name__}] {error_log}, linea: {get_especific_error_line(func.__name__)}, motivo: {str(e)}") + raise Exception(f"{raise_error}") + + return wrapper + return decorator + + +def get_especific_error_line(func_name): + _, _, exc_tb = sys.exc_info() + for trace in traceback.extract_tb(exc_tb): + if func_name in trace: + return str(trace[1]) + +def timing(f): + @wraps(f) + def wrap(*args, **kw): + ts = time() + result = f(*args, **kw) + te = time() + taken_time_message = '[timing] La funcion {}, toma: {:.2f} sec en ejecutarse'.format(f.__name__, te-ts) + logger.info(taken_time_message) + return result + return wrap diff --git a/corporate_finances_back_py/companies-puc-archive-info/lambda_function.py b/corporate_finances_back_py/companies-puc-archive-info/lambda_function.py new file mode 100644 index 0000000..5445375 --- /dev/null +++ b/corporate_finances_back_py/companies-puc-archive-info/lambda_function.py @@ -0,0 +1,179 @@ +""": +capas: +capa-pandas-data-transfer v.02 + +Variables de entorno +ARCHIVES_TABLE : ARCHIVE +COMPANIES_TABLE : COMPANY +DB_SCHEMA : src_corporate_finance +SECRET_DB_NAME : precia/rds8/sources/finanzas_corporativas +SECRET_DB_REGION : us-east-1 + +RAM: 512 MB + +""" + + +import boto3 +import datetime +import json +import logging +import os +import sys +import traceback + +from utils import * +import pandas as pd + +from decorators import handler_wrapper, timing + +################################################ +###LAMBDA CANDIDATA A DEPRECIACION POR HU 4530 +################################################ + +logger = logging.getLogger() +logger.setLevel(logging.INFO) +failed_init = False + +try: + logger.info('[__INIT__] Inicializando Lambda ...') + + db_schema = os.environ['DB_SCHEMA'] + secret_db_region = os.environ['SECRET_DB_REGION'] + secret_db_name = os.environ['SECRET_DB_NAME'] + companies_table = os.environ['COMPANIES_TABLE'] + archives_table = os.environ['ARCHIVES_TABLE'] + db_secret = get_secret(secret_db_region, secret_db_name) + logger.info('[__INIT__] Lambda inicializada exitosamente') + +except Exception as e: + failed_init = True + logger.error(f"[__INIT__] error en inicializacion, motivo: " + str(e)) + + +def lambda_handler(event, context): + if failed_init: + response_maker('respuesta de excepcion de lambda handler', succesfull=False, exception='Fallo en la inicializacion') + + try: + logger.info(f'[lambda_handler] el event que me está llegando es: {str(event)}') + db_connection = connect_to_db(db_schema, db_secret) + + nit = process_event(event) + company_info = get_nit_info(db_connection, nit) + companie_archives = get_company_archives(db_connection, company_info) + + object_response = companie_archives_cleaner(companie_archives) + + logger.info(f'[Lambda_handler] Tareas de lambda terminadas correctamente') + return response_maker(object_response , succesfull=True, exception='') + + except Exception as e: + logger.error(f'[Lambda_handler] Tareas de lambda terminadas con errores, linea: {get_current_error_line()} motivo: {str(e)}') + return response_maker({}, succesfull=False, exception=str(e)) + + + +@handler_wrapper('Procesando event para obtener el user','Nombre de usuario encontrado', 'Error al procesar event', 'Fallo fatal ') +def process_event(event): + """: + Funcion que toma el event que disparó la lambda en busqueda del filename envíado por el front. + En la transformación del filename se debe anotar: los espacios vacíos del filename se convierten + en '%20', se debe reemplazar; algunos archivos pueden tener varios puntos en el nombre, por lo + tanto se debe hacer un split por puntos para eliminar el ultimo y eliminar la extenxión del archivo. + Se vuelven a unir las partes separadas con puntos y se agrega la extensión json + :param event: Se puede interpretar como variables base que activan la lambda + :returns: La funcion debe devolver el filename necesario para la descarga + """ + + nit = event["pathParameters"]["nit"] + return nit + + +@handler_wrapper('Buscando id del nit recibido','El id del nit recibido fue encontrado','Error en la busqueda de los datos de la empresa','Error, problemas localizando la informacion de la empresa') +def get_nit_info(db_connection, nit): + query = f"SELECT * FROM {companies_table} WHERE NIT=\"{nit}\" LIMIT 1" + rds_data = db_connection.execute(query) + company_info = dict(rds_data.mappings().all()[0]) + return company_info + + +@handler_wrapper('Chequeando los archives del nit recibido','Archives encontrados', 'Error chequeando archives', 'error fatal, remitase al administrador') +def get_company_archives(db_connection, company_info): + query = f"SELECT * FROM {archives_table} WHERE ID_COMPANY={company_info['ID']}" + logger.info(f"Query a base de datos {query}") + + archives_df= pd.read_sql(query, db_connection); + + logger.warning(archives_df.head(3).to_string()) + return archives_df + + +@handler_wrapper('Organizando archives por fecha y periodicidad','Dataframe organizado correctamente','Error al hacer sort de los datos','Error fatal, remitase al admin') +def companie_archives_cleaner(archives_df): + + archives_df = archives_df.sort_values(['INITIAL_DATE', 'PERIODICITY']) + logger.warning(archives_df.head(3).to_string()) + + object_response = {} + for row in archives_df.itertuples(): + initial_date_str = row[3].strftime("%d-%m-%Y") + try: + object_response[initial_date_str].append(row[4]) + continue + except Exception: + object_response[initial_date_str] = [row[4]] + + return object_response + + +@handler_wrapper('Creando respuesta','Respuesta creada correctamente','Error al crear respuesta','Error fatal al crear respuesta') +def response_maker(object_response , succesfull=False, exception=''): + """: + Funcion que construye la respuesta general del lambda, para llegar se activa si todo salió bien en lambda handler + o si algo salió mal y se disparó el la excepcion general de esta. En caso de llegar a este metodo por medio de una excepcion + se trae un motivo de falla que no será mostrado al analista a menos que lo esté asesorando un desarrollador. + :succesfull: determina si el metodo se está ejecutando como excepcion o como salida correcta + :exception: motivo de error + :error_line: linea de falla + :returns: la funcion regresa el objeto alistado que lambda handler rergesará al disparador. status_code dependiente + si hubieron errores y mensajes acordes o una respuesta positiva con un message ok. En cualquier + caso se deben agregar tambien los encabezados 'Acces-Control' para que api gateway no corte la comunicacion back-front + """ + headers = {'headers': {'Access-Control-Allow-Headers': '*', 'Access-Control-Allow-Origin': '*', + 'Access-Control-Allow-Methods': '*'}} + if not succesfull: + try: + logger.warning('Creando respuesta de error') #cuando es comunicacion lambda a lambda se debe mandar un codigo 200 así haya habido error interno + error_response = {'statusCode': 200} + error_response.update(headers) + error_response['body'] = json.dumps(exception) + + logger.warning(f'[response_maker] Respuesta a retornar: {str(error_response)}') + return error_response + except Exception as e: + logger.error( + f'[response_maker] Error al construir la respuesta de error, linea: {get_current_error_line()}, motivo: {str(e)}') + return 'Fatal error' + + try: + logger.info('[response_maker] creando respuesta ') + ok_response = {'statusCode': 200} + ok_response.update(headers) + + ok_response["body"] = json.dumps(object_response) + return ok_response + + except Exception as e: + logger.error( + f'[response_maker] Error al construir la respuesta de aceptado, linea: {get_current_error_line()}, motivo: {str(e)}') + return response_maker({}, succesfull=False, exception=str(e)) + + +def get_current_error_line(): + return str(sys.exc_info()[-1].tb_lineno) + + +def get_especific_error_line(): + _, _, exc_tb = sys.exc_info() + return str(traceback.extract_tb(exc_tb)[-1][1]) \ No newline at end of file diff --git a/corporate_finances_back_py/companies-puc-archive-info/utils.py b/corporate_finances_back_py/companies-puc-archive-info/utils.py new file mode 100644 index 0000000..738f74f --- /dev/null +++ b/corporate_finances_back_py/companies-puc-archive-info/utils.py @@ -0,0 +1,56 @@ +import base64 +import boto3 +import json +import logging +import os +import sys +import traceback + +from sqlalchemy import create_engine + +from decorators import handler_wrapper + + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + + +@handler_wrapper('Obteniendo secreto','secreto obtenido','Error al obtener secreto','error fatal de back') +def get_secret(secret_region, secret_name): + """ + Obtiene las credenciales que vienen del Secret Manager + :param secret_region: (string) Nombre de la region donde se encuentran las credenciales + :param secrete_name: (string) Nombre del secreto + :return: (dict) Diccionario con las credenciales + """ + session = boto3.session.Session() + client_secrets_manager = session.client(service_name='secretsmanager', region_name=secret_region) + secret_data = client_secrets_manager.get_secret_value(SecretId=secret_name) + if 'SecretString' in secret_data: + secret_str = secret_data['SecretString'] + else: + secret_str = base64.b64decode(secret_data['SecretBinary']) + logger.info('[utils] (get_secret) Se obtuvo el secreto') + return json.loads(secret_str) + + +@handler_wrapper('Conectando a base de datos {a}','Conectado correctamente a base de datos','Error en la conexion a base de datos','error fatal de back') +def connect_to_db(db_schema, db_secret): + """ + Se conecta a dos bases de datos por medio de las variables de entorno + :return: (tuple) Contiene los objetos sqlalchemy para ejecutar queries + """ + + conn_string = ('mysql+mysqlconnector://' + db_secret["username"] + ':' + db_secret["password"] + '@' + db_secret["host"] + ':' + str(db_secret["port"]) + '/' + db_schema) + sql_engine = create_engine(conn_string) + db_connection = sql_engine.connect() + return db_connection + + +def get_current_error_line(): + return str(sys.exc_info()[-1].tb_lineno) + + +def get_especific_error_line(): + _, _, exc_tb = sys.exc_info() + return str(traceback.extract_tb(exc_tb)[-1][1]) diff --git a/corporate_finances_back_py/company-assessments-info/decorators.py b/corporate_finances_back_py/company-assessments-info/decorators.py new file mode 100644 index 0000000..071760a --- /dev/null +++ b/corporate_finances_back_py/company-assessments-info/decorators.py @@ -0,0 +1,63 @@ +#version 2023 - 05 - 04 +import logging +import sys +import traceback +from functools import wraps +from time import time + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + +def handler_wrapper(start, satisfactory_log, error_log, raise_error): + #esto se ejecuta en la inicializacion de primero + def decorator(func): + #print(message1) + #lo que yo ponga acá se ejecuta antes de hacer el llamado a la funcion + @wraps(func) + def wrapper(*args, **kwargs): + #esto sí se ejecuta solo cuando llama a la funcion decorada + #print(message2) + try: + logger.info(f'[{func.__name__}] {start}...') + resultado = func(*args, **kwargs) + logger.info(f'[{func.__name__}] {satisfactory_log}') + return resultado + except Exception as e: + logger.error(f"[{func.__name__}] {error_log}, linea: {get_especific_error_line(func.__name__)}, motivo: {str(e)}") + raise Exception(f"{raise_error}") + + return wrapper + return decorator + +def debugger_wrapper(error_log, raise_error): + def decorator(func): + @wraps(func) + def wrapper(*args, **kwargs): + try: + resultado = func(*args, **kwargs) + return resultado + except Exception as e: + logger.error(f"[{func.__name__}] {error_log}, linea: {get_especific_error_line(func.__name__)}, motivo: {str(e)}") + raise Exception(f"{raise_error}") + return wrapper + return decorator + + +def get_especific_error_line(func_name): + _, _, exc_tb = sys.exc_info() + for trace in traceback.extract_tb(exc_tb): + if func_name in trace: + return str(trace[1]) + +def timing(f): + @wraps(f) + def wrap(*args, **kw): + ts = time() + result = f(*args, **kw) + te = time() + taken_time_message = '[timing] La funcion {}, toma: {:.2f} sec en ejecutarse'.format(f.__name__, te-ts) + logger.info(taken_time_message) + return result + return wrap + + diff --git a/corporate_finances_back_py/company-assessments-info/lambda_function.py b/corporate_finances_back_py/company-assessments-info/lambda_function.py new file mode 100644 index 0000000..d235b61 --- /dev/null +++ b/corporate_finances_back_py/company-assessments-info/lambda_function.py @@ -0,0 +1,164 @@ +from sqlalchemy import text +import datetime +import json +import logging +import os +import sys +import sqlalchemy +import traceback + +if __name__ in ['__main__', 'lambda_function']: + from decorators import handler_wrapper, timing, debugger_wrapper + from utils import get_secret, connect_to_db, connect_to_db_local_dev + +else: + from .decorators import handler_wrapper, timing, debugger_wrapper + from .utils import get_secret, connect_to_db, connect_to_db_local_dev + +logging.basicConfig() +#logging.basicConfig(format='%(asctime)s [%(levelname)s] [%(module)s] %(message)s', force=True, datefmt='%Y-%m-%d %H:%M:%S') +logging.basicConfig(format='%(asctime)s [%(levelname)s] %(message)s', force=True, datefmt='%Y-%m-%d %H:%M:%S') +logger = logging.getLogger() +logger.setLevel(logging.INFO) + + +def lambda_handler(event, context): + sc_obj = script_object(event) + lambda_response = sc_obj.starter() + logger.info(f'respuesta final de lambda: \n{lambda_response}') + return lambda_response + + +class script_object(): + def __init__(self, event) -> None: + try: + self.failed_init = False + self.final_response = {'headers':{'Access-Control-Allow-Headers': '*', + 'Access-Control-Allow-Origin': '*', + 'Access-Control-Allow-Methods': '*'}, "statusCode": 500, 'body': {}} + self.db_connection = 0 + self.detailed_raise = '' + self.partial_response = {} + self.id_assessment = 0 + + logger.warning(f'event de entrada: {str(event)}') + event_dict = event.get('queryStringParameters', False) + self.nit = event_dict['nit'] + + except Exception as e: + logger.error(f'[__init__] Error inicializando objeto lambda, linea: {get_current_error_line()}, motivo: {str(e)}') + self.failed_init = True + + + def starter(self): + try: + if self.failed_init: + raise AttributeError('Error con los datos recibidos al servicio') + + logger.info('[starter] Empezando starter de objeto lambda') + self.create_conection_to_db() + self.adquire_company_info() + self.check_model_existance() + self.adquire_archives_info() + self.adquire_assessment_info() + self.merge_assessment_data() + + + return self.response_maker(succesfull_run = True) + except Exception as e: + logger.error(f'[starter] Hubieron problemas en el comando de la linea: {get_current_error_line()}') + return self.response_maker(succesfull_run = False, error_str = (str(e))) + + + + @handler_wrapper('Creando conexion a bd','Conexion a bd creada con exito','Error en la conexion a bd','Problemas creando la conexion a bd') + def create_conection_to_db(self): + if __name__ != 'lambda_function': + self.db_connection = connect_to_db_local_dev() + return + + db_schema = os.environ['DB_SCHEMA'] + secret_db_region = os.environ['SECRET_DB_REGION'] + secret_db_name = os.environ['SECRET_DB_NAME'] + db_secret = get_secret(secret_db_region, secret_db_name) + self.db_connection = connect_to_db(db_schema, db_secret) + + + @handler_wrapper('Adquiriendo información de la empresa', 'Información de empresa adquirida con exito', 'Error adquiriendo informacion de la empresa', 'Error adquiriendo información de la empresa') + def adquire_company_info(self): + query = f"SELECT * FROM COMPANY WHERE NIT = '{self.nit}'" + logger.info(f"[get_raw_pyg] Query a base de datos para obtener la información de la empresa:\n{query}") + rds_data = self.db_connection.execute(text(query)) + self.company_info = [row._asdict() for row in rds_data.fetchall()] + self.partial_response['company'] = {'name': self.company_info[0]['NAME'], 'sector': self.company_info[0]['SECTOR']} + + @handler_wrapper('Chqueando si la empresa tiene modelo', 'Chequeo de modelo terminado', 'Error chequeando si la empresa tiene modelo', 'Error chequeando modelo') + def check_model_existance(self): + query = f"SELECT EXISTS (SELECT * FROM MODEL_USER_CLASSIFICATION WHERE ID_COMPANY = {self.company_info[0]['ID']})" + logger.info(f"[check_model_existance] Query a base de datos para chequear si la empresa tiene modelo guardado :\n{query}") + rds_data = self.db_connection.execute(text(query)) + model_exists = rds_data.scalar() + logger.info(f'[check_model_existance] Bool de modelo existe:\n{model_exists}') + if model_exists: + self.partial_response['model'] = 'Sí' + + + @handler_wrapper('Adquiriendo infromación de los procesos de la empresa', 'Información de pucs adquirida con exito', 'Error adquiriendo informacion de los puc de la empresa', 'Error adquiriendo información de pucs|') + def adquire_archives_info(self): + query = f"SELECT ID, INITIAL_DATE, PERIODICITY AS periodicity FROM ARCHIVE WHERE ID_COMPANY = {self.company_info[0]['ID']} ORDER BY INITIAL_DATE" + logger.info(f"[adquire_archives_info] Query a base de datos para obtener la información de los pucs de la empresa:\n{query}") + rds_data = self.db_connection.execute(text(query)) + self.archives_info = [row._asdict() for row in rds_data.fetchall()] + for row in self.archives_info: + row['date'] = row['INITIAL_DATE'].strftime('%d-%m-%Y') + del row['INITIAL_DATE'] + logger.info(f'[adquire_archives_info] Archives de la empresa encontrados:\n{self.archives_info}') + + + @handler_wrapper('Adquiriendo información de assessments', 'Información de assessments adquirida con exito', 'Error adquiriendo informacion de assessments', 'Error adquiriendo información de procesos de valoracion') + def adquire_assessment_info(self): + found_archives = [archive['ID'] for archive in self.archives_info] + archives_str = str(found_archives).replace('[','').replace(']','') + query = f"SELECT * FROM ASSESSMENT WHERE ID_ARCHIVE in ({archives_str})" + logger.info(f"[adquire_assessment_info] Query a base de datos para obtener la información de los procesos de valoración creados para esta emrpesa:\n{query}") + rds_data = self.db_connection.execute(text(query)) + self.assessment_records = [row._asdict() for row in rds_data.fetchall()] + + + @handler_wrapper('Emergiendo los assessments encontrados con los archives de la empresa', 'Datos adquiridos unidos correctamente', 'Error emergiendo datos adquiridos', 'Error al relacionar procesos de valoración y archives de puc') + def merge_assessment_data(self): + response_data = [] + for row in self.archives_info: + assessments_created = [item for item in self.assessment_records if item['ID_ARCHIVE'] == row['ID']] + if not assessments_created: + response_data.append(row) + + for found_assessment in assessments_created: + row['user'] = found_assessment['USER'] + row['id_assessment'] = found_assessment['ID'] + response_data.append(row.copy()) + + + self.partial_response['data'] = response_data + + + + @debugger_wrapper('Error construyendo respuesta final', 'Error construyendo respuesta') + def response_maker(self, succesfull_run = False, error_str = str()): + if self.db_connection: + self.db_connection.close() + if succesfull_run: + self.final_response['statusCode'] = 200 + self.final_response['body'] = json.dumps(self.partial_response) + return self.final_response + + self.final_response['body'] = json.dumps(self.detailed_raise if self.detailed_raise else error_str) + return self.final_response + + +def get_current_error_line(): + return str(sys.exc_info()[-1].tb_lineno) + +if __name__ == "__main__": + event = {"queryStringParameters": {"nit":"949439939-1", 'periodicity': "Anual" , "user": "dmanchola@precia.co"}} + lambda_handler(event, '') diff --git a/corporate_finances_back_py/company-assessments-info/utils.py b/corporate_finances_back_py/company-assessments-info/utils.py new file mode 100644 index 0000000..eefd5b0 --- /dev/null +++ b/corporate_finances_back_py/company-assessments-info/utils.py @@ -0,0 +1,47 @@ +#version 2024 - 03 - 15 +import base64 +import boto3 +import json +import logging +import os +from sqlalchemy import create_engine + +if __name__ in ['utils']: + from decorators import handler_wrapper, timing, debugger_wrapper + +else: + from .decorators import handler_wrapper, timing, debugger_wrapper + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + + +@debugger_wrapper('Error al obtener secreto','Error fatal de back conectando a base de datos') +def get_secret(secret_region, secret_name): + session = boto3.session.Session() + client_secrets_manager = session.client(service_name='secretsmanager', region_name=secret_region) + secret_data = client_secrets_manager.get_secret_value(SecretId=secret_name) + if 'SecretString' in secret_data: + secret_str = secret_data['SecretString'] + else: + secret_str = base64.b64decode(secret_data['SecretBinary']) + logger.info('[utils] (get_secret) Se obtuvo el secreto') + return json.loads(secret_str) + + +@debugger_wrapper('Error en la conexion a base de datos','Error fatal de back conectando a base de datos') +def connect_to_db(db_schema, db_secret): + conn_string = ('mysql+mysqlconnector://' + db_secret["username"] + ':' + db_secret["password"] + '@' + db_secret["host"] + ':' + str(db_secret["port"]) + '/' + db_schema) + sql_engine = create_engine(conn_string) + db_connection = sql_engine.connect() + return db_connection + + +@debugger_wrapper('Error en la conexion a base de datos','Error fatal de back conectando a base de datos') +def connect_to_db_local_dev(): + from dotenv import load_dotenv + load_dotenv() + conn_string = os.environ['local_dev_connector'] + sql_engine = create_engine(conn_string) + db_connection = sql_engine.connect() + return db_connection diff --git a/corporate_finances_back_py/debt-amortize/decorators.py b/corporate_finances_back_py/debt-amortize/decorators.py new file mode 100644 index 0000000..071760a --- /dev/null +++ b/corporate_finances_back_py/debt-amortize/decorators.py @@ -0,0 +1,63 @@ +#version 2023 - 05 - 04 +import logging +import sys +import traceback +from functools import wraps +from time import time + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + +def handler_wrapper(start, satisfactory_log, error_log, raise_error): + #esto se ejecuta en la inicializacion de primero + def decorator(func): + #print(message1) + #lo que yo ponga acá se ejecuta antes de hacer el llamado a la funcion + @wraps(func) + def wrapper(*args, **kwargs): + #esto sí se ejecuta solo cuando llama a la funcion decorada + #print(message2) + try: + logger.info(f'[{func.__name__}] {start}...') + resultado = func(*args, **kwargs) + logger.info(f'[{func.__name__}] {satisfactory_log}') + return resultado + except Exception as e: + logger.error(f"[{func.__name__}] {error_log}, linea: {get_especific_error_line(func.__name__)}, motivo: {str(e)}") + raise Exception(f"{raise_error}") + + return wrapper + return decorator + +def debugger_wrapper(error_log, raise_error): + def decorator(func): + @wraps(func) + def wrapper(*args, **kwargs): + try: + resultado = func(*args, **kwargs) + return resultado + except Exception as e: + logger.error(f"[{func.__name__}] {error_log}, linea: {get_especific_error_line(func.__name__)}, motivo: {str(e)}") + raise Exception(f"{raise_error}") + return wrapper + return decorator + + +def get_especific_error_line(func_name): + _, _, exc_tb = sys.exc_info() + for trace in traceback.extract_tb(exc_tb): + if func_name in trace: + return str(trace[1]) + +def timing(f): + @wraps(f) + def wrap(*args, **kw): + ts = time() + result = f(*args, **kw) + te = time() + taken_time_message = '[timing] La funcion {}, toma: {:.2f} sec en ejecutarse'.format(f.__name__, te-ts) + logger.info(taken_time_message) + return result + return wrap + + diff --git a/corporate_finances_back_py/debt-amortize/lambda_function.py b/corporate_finances_back_py/debt-amortize/lambda_function.py new file mode 100644 index 0000000..5f285d7 --- /dev/null +++ b/corporate_finances_back_py/debt-amortize/lambda_function.py @@ -0,0 +1,221 @@ +import json +import logging +import sys +import os +import pandas as pd +from datetime import datetime +from sqlalchemy import text + +from decorators import handler_wrapper, timing, debugger_wrapper +from utils import get_secret, connect_to_db, connect_to_db_local_dev + +logging.basicConfig() +logging.basicConfig(format='%(asctime)s [%(levelname)s] [%(module)s] %(message)s', force=True, datefmt='%Y-%m-%d %H:%M:%S') +logger = logging.getLogger() +logger.setLevel(logging.INFO) + +def lambda_handler(event,context): + sc_obj = script_object(event) + lambda_response = sc_obj.starter() + logger.info(f'respuesta final de lambda: \n{lambda_response}') + return lambda_response + +###################################### +#Candidato para depreciación +###################################### +class script_object: + def __init__(self, event): + try: + self.failed_init = False + self.final_response = {'headers':{'Access-Control-Allow-Headers': '*', + 'Access-Control-Allow-Origin': '*', + 'Access-Control-Allow-Methods': '*'}, "statusCode": 500, 'body': {}} + self.db_connection = 0 + self.detailed_raise = '' + self.partial_response = list() + + logger.warning(f'event de entrada: {str(event)}') + + self.id_assessment = event['pathParameters']['id_assessment'] + + self.vectors = ['ITEM_DATE','INITIAL_BALANCE', 'DISBURSEMENT', 'AMORTIZATION', 'ENDING_BALANCE', 'INTEREST_VALUE', 'ENDING_BALANCE_VARIATION'] + + self.current_debt_items = list() + self.future_debt_items = list() + + self.db_debt_records = dict() + + self.current_debt_array = list() + self.future_debt_array = list() + self.total_assessment_dates = list() + + self.historic_dates = list() # + self.projection_dates = list() # + + + except Exception as e: + logger.error(f'[__init__] Error inicializando objeto lambda, linea: {get_current_error_line()}, motivo: {str(e)}') + self.failed_init = True + + def starter(self): + try: + if self.failed_init: + raise AttributeError('Error con los datos recibidos al servicio') + self.create_conection_to_db() + self.get_assessment_dates() #TODO: ver si Dani necesita el maxYear + self.get_debt_data() + if self.current_debt_items: + self.organize_current_debt_items() + + if self.future_debt_items: + self.organize_future_debt_items() + #self.delete_previous_results() + #self.upload_debt_records() + self.organize_partial_response() + + + return self.response_maker(succesfull_run = True) + + except Exception as e: + logger.error(f'[starter] Hubieron problemas en el comando de la linea: {get_current_error_line()}') + return self.response_maker(succesfull_run = False, error_str = (str(e))) + + @handler_wrapper('Creando conexion a bd','Conexion a bd creada con exito','Error en la conexion a bd','Problemas creando la conexion a bd') + def create_conection_to_db(self): + if __name__ == "__main__": + self.db_connection = connect_to_db_local_dev() + return + + db_schema = os.environ['DB_SCHEMA'] + secret_db_region = os.environ['SECRET_DB_REGION'] + secret_db_name = os.environ['SECRET_DB_NAME'] + db_secret = get_secret(secret_db_region, secret_db_name) + self.db_connection = connect_to_db(db_schema, db_secret) + + + @handler_wrapper('Obteniendo las fechas del proceso de valoración', 'Fechas del proceso de valroación obtenidas con exito', 'Error obteniendo las fechas del proceso de valoración', 'Error obteniendo fechas del proceso de valoración') + def get_assessment_dates(self): + query = f"SELECT DATES, PROPERTY FROM ASSESSMENT_DATES WHERE ID_ASSESSMENT = {self.id_assessment} ORDER BY DATES" + logger.info(f"[get_assessment_dates] Query a base de datos para obtener las fechas utilizadas en el proces de valoración:\n {query}") + rds_data = self.db_connection.execute(text(query)) + directory = {'HISTORIC': self.historic_dates, 'PROJECTION': self.projection_dates} + found_dates = [row._asdict() for row in rds_data.fetchall()] + for date_item in found_dates: + #logger.info(f'[mira aca]{date_item}') + self.db_debt_records[date_item['DATES'].strftime('%Y')] = {'DISBURSEMENT': 0, 'INTEREST_VALUE': 0} + directory.get(date_item['PROPERTY'], []).append(date_item['DATES'].strftime('%Y-%m-%d')) + logger.info(f'[get_assessment_dates] Fechas del proceso de valoración:\nhistoricas: {self.historic_dates}\nproyecciones: {self.projection_dates}') + + + @handler_wrapper('Adquiriendo datos guardados de deuda', 'Datos de deuda adquiridos con exito', 'Error adquiriendo datos de deuda', 'Error adquiriendo datos') + def get_debt_data(self): + query = f"""SELECT ACCOUNT_NUMBER AS account, ALIAS_NAME, ITEM_DATE, INITIAL_BALANCE, DISBURSEMENT, AMORTIZATION, ENDING_BALANCE, INTEREST_VALUE, ENDING_BALANCE_VARIATION +FROM PROJECTED_DEBT WHERE ID_ASSESSMENT = {self.id_assessment} ORDER BY ITEM_DATE""" + + logger.info(f"[get_debt_data] Query a base de datos para obtener los datos que existan de deuda:\n {query}") + rds_data = self.db_connection.execute(text(query)) + directory = {'0': self.future_debt_items} + for row in [row._asdict() for row in rds_data.fetchall()]: + logger.info(f'[mira aca]{row}') + row['INITIAL_BALANCE'] = float(row['INITIAL_BALANCE']) + row['DISBURSEMENT'] = float(row['DISBURSEMENT']) + row['AMORTIZATION'] = float(row['AMORTIZATION']) + row['ENDING_BALANCE'] = float(row['ENDING_BALANCE']) + row['INTEREST_VALUE'] = float(row['INTEREST_VALUE']) + row['ENDING_BALANCE_VARIATION'] = float(row['ENDING_BALANCE_VARIATION']) + #self.integrate_row_to_records(row) #toca sacarlo porque esto es logica de negocio + + directory.get(row['account'], self.current_debt_items).append(row) + + self.future_debt_items = [item for item in self.future_debt_items if item['ALIAS_NAME'] != 'Deuda de Tesoreria'] + logger.info(f'[get_debt_data] Deudas re organizadas, resultados:\nDeudas actuales: {self.current_debt_items}\nDeudas futuras: {self.future_debt_items}') + logger.info(f'[get_debt_data] Records de deudas organizados, resultados:\n{self.db_debt_records}') + + + @handler_wrapper('Organizando objetos de deuda actual', 'Objetos de deuda actual organizados con exito','Error organizando objetos de deuda actual', 'Error organizando objeto de deuda actual') + def organize_current_debt_items(self): + found_accounts = sorted(set(row['account'] for row in self.current_debt_items)) + + for account in found_accounts: + base_properties = next(item for item in self.current_debt_items if item['account'] == account) + vector_values = {} + for vec in self.vectors: + vector_values[vec] = [item[vec] for item in self.current_debt_items if item['account'] == account][len(self.historic_dates):] + + vector_values['ITEM_DATE'] = [date.strftime('%Y') for date in vector_values['ITEM_DATE']] + vector_values['ITEM_DATE'][0] = vector_values['ITEM_DATE'][0] if '-12-' in self.historic_dates[-1] else f"Diciembre {vector_values['ITEM_DATE'][0]}" + + self.current_debt_array.append({'name': base_properties['ALIAS_NAME'], + 'years':vector_values['ITEM_DATE'], + 'initialBalance':vector_values['INITIAL_BALANCE'], + 'disbursement': [0] * len(vector_values['ITEM_DATE']), + 'amortization':vector_values['AMORTIZATION'], + 'finalbalance':vector_values['ENDING_BALANCE'], + 'interest':vector_values['INTEREST_VALUE'], + 'finalBalanceVariation':vector_values['ENDING_BALANCE_VARIATION']}) + + + @handler_wrapper('Organizando objetos de deuda futura', 'Objetos de deuda futura organizados con exito','Error organizando objetos de deuda futura', 'Error organizando objeto de deuda futura') + def organize_future_debt_items(self): + found_aliases = sorted(set(row['ALIAS_NAME'] for row in self.future_debt_items)) + + for alias in found_aliases: + base_properties = next(item for item in self.future_debt_items if item['ALIAS_NAME'] == alias) + vector_values = {} + for vec in self.vectors: + vector_values[vec] = [item[vec] for item in self.future_debt_items if item['ALIAS_NAME'] == alias] + vector_values['ITEM_DATE'] = [date.strftime('%Y') for date in vector_values['ITEM_DATE']] + self.future_debt_array.append({'name': base_properties['ALIAS_NAME'], + 'years':vector_values['ITEM_DATE'], + 'initialBalance':vector_values['INITIAL_BALANCE'], + 'disbursement':vector_values['DISBURSEMENT'], + 'amortization':vector_values['AMORTIZATION'], + 'finalbalance':vector_values['ENDING_BALANCE'], + 'interest':vector_values['INTEREST_VALUE'], + 'finalBalanceVariation':vector_values['ENDING_BALANCE_VARIATION']}) + + @debugger_wrapper('Error integrando proyeccion de deuda a records de bd', 'Error integrando deuda a records de bd') + def integrate_row_to_records(self, row): + try: + logger.warning(f'[mira aca] Integrando:{row} a:\n{self.db_debt_records}') + if row['YEAR'] in self.historic_dates: + self.db_debt_records[row['YEAR']]['DISBURSEMENT'] = 0 + self.db_debt_records[row['YEAR']]['INTEREST_VALUE'] = 0 + logger.info(f'row {row} ha sido omitido') + return + self.db_debt_records[row['YEAR']]['DISBURSEMENT'] = self.db_debt_records[row['YEAR']]['DISBURSEMENT'] + row['ENDING_BALANCE_VARIATION'] + self.db_debt_records[row['YEAR']]['INTEREST_VALUE'] = self.db_debt_records[row['YEAR']]['INTEREST_VALUE'] + row['INTEREST_VALUE'] + + for date in self.projection_dates: + if date not in self.db_debt_records: + self.db_debt_records[date] = {'DISBURSEMENT': 0, 'INTEREST_VALUE': 0} + + except Exception as e: + logger.error(f'[integrate_row_to_records] Este error no se debió haber activado, pero por si acaso, se estaba intentando integrar el row \n{row}\ncon los records:\n{self.db_debt_records}\nY lanzó el error {str(e)}') + + + @handler_wrapper('Organizando Respuesta final', 'Respuesta final organizada con exito', 'Error organizando respuesta final', 'Error organizando respuesta final') + def organize_partial_response(self): + self.partial_response = {'existingDebt': self.current_debt_array, 'futureDebt': self.future_debt_array} + + + @debugger_wrapper('Error construyendo respuesta final', 'Error construyendo respuesta') + def response_maker(self, succesfull_run = False, error_str = str()): + if self.db_connection: + self.db_connection.close() + if succesfull_run: + self.final_response['statusCode'] = 200 + self.final_response['body'] = json.dumps(self.partial_response) + return self.final_response + + self.final_response['body'] = json.dumps(self.detailed_raise if self.detailed_raise else error_str) + return self.final_response + + +def get_current_error_line(): + return str(sys.exc_info()[-1].tb_lineno) + + +if __name__ == "__main__": + event = {"pathParameters": {"id_assessment": "2013"}} + lambda_handler(event, '') \ No newline at end of file diff --git a/corporate_finances_back_py/debt-amortize/utils.py b/corporate_finances_back_py/debt-amortize/utils.py new file mode 100644 index 0000000..52264c3 --- /dev/null +++ b/corporate_finances_back_py/debt-amortize/utils.py @@ -0,0 +1,41 @@ +#version 2023 - 05 - 04 +import base64 +import boto3 +import json +import logging + +from sqlalchemy import create_engine + +from decorators import handler_wrapper, debugger_wrapper + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + + +@debugger_wrapper('Error al obtener secreto','Error fatal de back conectando a base de datos') +def get_secret(secret_region, secret_name): + session = boto3.session.Session() + client_secrets_manager = session.client(service_name='secretsmanager', region_name=secret_region) + secret_data = client_secrets_manager.get_secret_value(SecretId=secret_name) + if 'SecretString' in secret_data: + secret_str = secret_data['SecretString'] + else: + secret_str = base64.b64decode(secret_data['SecretBinary']) + logger.info('[utils] (get_secret) Se obtuvo el secreto') + return json.loads(secret_str) + + +@debugger_wrapper('Error en la conexion a base de datos','Error fatal de back conectando a base de datos') +def connect_to_db(db_schema, db_secret): + conn_string = ('mysql+mysqlconnector://' + db_secret["username"] + ':' + db_secret["password"] + '@' + db_secret["host"] + ':' + str(db_secret["port"]) + '/' + db_schema) + sql_engine = create_engine(conn_string) + db_connection = sql_engine.connect() + return db_connection + + +@debugger_wrapper('Error en la conexion a base de datos','Error fatal de back conectando a base de datos') +def connect_to_db_local_dev(): + conn_string = open(r"C:\Users\JeissonBotache\.aws\aurora_sources8_dev.txt", "r").read() + sql_engine = create_engine(conn_string) + db_connection = sql_engine.connect() + return db_connection \ No newline at end of file diff --git a/corporate_finances_back_py/debt-retrieve/decorators.py b/corporate_finances_back_py/debt-retrieve/decorators.py new file mode 100644 index 0000000..071760a --- /dev/null +++ b/corporate_finances_back_py/debt-retrieve/decorators.py @@ -0,0 +1,63 @@ +#version 2023 - 05 - 04 +import logging +import sys +import traceback +from functools import wraps +from time import time + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + +def handler_wrapper(start, satisfactory_log, error_log, raise_error): + #esto se ejecuta en la inicializacion de primero + def decorator(func): + #print(message1) + #lo que yo ponga acá se ejecuta antes de hacer el llamado a la funcion + @wraps(func) + def wrapper(*args, **kwargs): + #esto sí se ejecuta solo cuando llama a la funcion decorada + #print(message2) + try: + logger.info(f'[{func.__name__}] {start}...') + resultado = func(*args, **kwargs) + logger.info(f'[{func.__name__}] {satisfactory_log}') + return resultado + except Exception as e: + logger.error(f"[{func.__name__}] {error_log}, linea: {get_especific_error_line(func.__name__)}, motivo: {str(e)}") + raise Exception(f"{raise_error}") + + return wrapper + return decorator + +def debugger_wrapper(error_log, raise_error): + def decorator(func): + @wraps(func) + def wrapper(*args, **kwargs): + try: + resultado = func(*args, **kwargs) + return resultado + except Exception as e: + logger.error(f"[{func.__name__}] {error_log}, linea: {get_especific_error_line(func.__name__)}, motivo: {str(e)}") + raise Exception(f"{raise_error}") + return wrapper + return decorator + + +def get_especific_error_line(func_name): + _, _, exc_tb = sys.exc_info() + for trace in traceback.extract_tb(exc_tb): + if func_name in trace: + return str(trace[1]) + +def timing(f): + @wraps(f) + def wrap(*args, **kw): + ts = time() + result = f(*args, **kw) + te = time() + taken_time_message = '[timing] La funcion {}, toma: {:.2f} sec en ejecutarse'.format(f.__name__, te-ts) + logger.info(taken_time_message) + return result + return wrap + + diff --git a/corporate_finances_back_py/debt-retrieve/lambda_function.py b/corporate_finances_back_py/debt-retrieve/lambda_function.py new file mode 100644 index 0000000..eb77947 --- /dev/null +++ b/corporate_finances_back_py/debt-retrieve/lambda_function.py @@ -0,0 +1,220 @@ +import json +import logging +import sys +import os + +from datetime import datetime +from sqlalchemy import text +from decorators import handler_wrapper, timing, debugger_wrapper +from utils import get_secret, connect_to_db, connect_to_db_local_dev + +logging.basicConfig() +logging.basicConfig(format='%(asctime)s [%(levelname)s] [%(module)s] %(message)s', force=True, datefmt='%Y-%m-%d %H:%M:%S') +#logging.basicConfig(format='%(asctime)s [%(levelname)s] %(message)s', force=True, datefmt='%Y-%m-%d %H:%M:%S') +logger = logging.getLogger() +logger.setLevel(logging.INFO) +logger.setLevel(logging.INFO) + +def lambda_handler(event,context): + sc_obj = script_object(event) + lambda_response = sc_obj.starter() + logger.info(f'respuesta final de lambda: \n{lambda_response}') + return lambda_response + + +class script_object: + def __init__(self, event): + try: + self.failed_init = False + self.final_response = {'headers':{'Access-Control-Allow-Headers': '*', + 'Access-Control-Allow-Origin': '*', + 'Access-Control-Allow-Methods': '*'}, "statusCode": 500, 'body': {}} + self.db_connection = 0 + self.detailed_raise = '' + self.partial_response = list() + + logger.warning(f'event de entrada: {str(event)}') + + self.id_assessment = event['pathParameters']['id_assessment'] + self.current_debt_items = list() + self.future_debt_items = list() + self.treasure_debt_items = list() + + self.current_debt_array = list() + self.future_debt_array = list() + + self.historic_dates = list() # + self.projection_dates = list() # + + + except Exception as e: + logger.error(f'[__init__] Error inicializando objeto lambda, linea: {get_current_error_line()}, motivo: {str(e)}') + self.failed_init = True + + def starter(self): + try: + if self.failed_init: + raise AttributeError('Error con los datos recibidos al servicio') + self.create_conection_to_db() + self.get_assessment_dates() + self.get_debt_data() + if self.current_debt_items: + self.organize_current_debt_items() + + if self.future_debt_items: + self.organize_future_debt_items() + + if self.treasure_debt_items: + self.organize_treasure_debt_items() + + self.organize_partial_response() + + + return self.response_maker(succesfull_run = True) + + except Exception as e: + logger.error(f'[starter] Hubieron problemas en el comando de la linea: {get_current_error_line()}') + return self.response_maker(succesfull_run = False, error_str = (str(e))) + + @handler_wrapper('Creando conexion a bd','Conexion a bd creada con exito','Error en la conexion a bd','Problemas creando la conexion a bd') + def create_conection_to_db(self): + if __name__ == "__main__": + self.db_connection = connect_to_db_local_dev() + return + db_schema = os.environ['DB_SCHEMA'] + secret_db_region = os.environ['SECRET_DB_REGION'] + secret_db_name = os.environ['SECRET_DB_NAME'] + db_secret = get_secret(secret_db_region, secret_db_name) + self.db_connection = connect_to_db(db_schema, db_secret) + + + @handler_wrapper('Obteniendo las fechas del proceso de valoración', 'Fechas del proceso de valroación obtenidas con exito', 'Error obteniendo las fechas del proceso de valoración', 'Error obteniendo fechas del proceso de valoración') + def get_assessment_dates(self): + query = f"SELECT DATES, PROPERTY FROM ASSESSMENT_DATES WHERE ID_ASSESSMENT = {self.id_assessment} ORDER BY DATES" + logger.info(f"[get_assessment_dates] Query a base de datos para obtener las fechas utilizadas en el proces de valoración:\n {query}") + rds_data = self.db_connection.execute(text(query)) + directory = {'HISTORIC': self.historic_dates, 'PROJECTION': self.projection_dates} + for date_item in rds_data.fetchall(): + directory.get(date_item.PROPERTY, []).append(date_item.DATES.strftime('%Y-%m-%d')) + + logger.info(f'[get_assessment_dates] Fechas del proceso de valoración:\nhistoricas: {self.historic_dates}\nproyecciones: {self.projection_dates}') + + + @handler_wrapper('Adquiriendo datos guardados de deuda', 'Datos de deuda adquiridos con exito', 'Error adquiriendo datos de deuda', 'Error adquiriendo datos') + def get_debt_data(self): + query = """SELECT A.ACCOUNT_NUMBER AS account, A.ALIAS_NAME, A.PROJECTION_TYPE, A.START_YEAR, A.ENDING_YEAR, A.DEBT_COMMENT, A.RATE_COMMENT, A.SPREAD_COMMENT, +B.RATE_ATRIBUTE, B.SPREAD_ATRIBUTE, B.ITEM_DATE, D.ACCOUNT_NAME FROM DEBT A, PROJECTED_DEBT B, ASSESSMENT C, ASSESSMENT_CHECKED D WHERE A.ID_ASSESSMENT = :id_assessment +AND C.ID = A.ID_ASSESSMENT AND C.ID = B.ID_ASSESSMENT AND C.ID = D.ID_ASSESSMENT AND C.ID_ARCHIVE = D.ID_ARCHIVE AND D.ACCOUNT_NUMBER = A.ACCOUNT_NUMBER +AND A.ACCOUNT_NUMBER = B.ACCOUNT_NUMBER AND A.ALIAS_NAME = B.ALIAS_NAME AND A.ACCOUNT_NUMBER = B.ACCOUNT_NUMBER ORDER BY B.ITEM_DATE""" + logger.info(f"[get_debt_data] Query a base de datos para obtener los datos de deuda existente:\n {query}") + rds_data = self.db_connection.execute(text(query), {'id_assessment':self.id_assessment}) + self.current_debt_items = [row._asdict() for row in rds_data.fetchall()] + + query = """SELECT A.ACCOUNT_NUMBER AS account, A.ALIAS_NAME, A.PROJECTION_TYPE, A.ORIGINAL_VALUE, A.START_YEAR, A.ENDING_YEAR, A.DEBT_COMMENT, A.RATE_COMMENT, A.SPREAD_COMMENT, +B.RATE_ATRIBUTE, B.SPREAD_ATRIBUTE, B.ITEM_DATE FROM DEBT A, PROJECTED_DEBT B WHERE A.ID_ASSESSMENT = B.ID_ASSESSMENT AND A.ACCOUNT_NUMBER = B.ACCOUNT_NUMBER AND A.ALIAS_NAME = B.ALIAS_NAME +AND A.ACCOUNT_NUMBER = B.ACCOUNT_NUMBER AND A.ID_ASSESSMENT = :id_assessment AND A.ACCOUNT_NUMBER = 0 ORDER BY B.ITEM_DATE""" + logger.info(f"[get_debt_data] Query a base de datos para obtener los datos de deuda futura:\n {query}") + rds_data = self.db_connection.execute(text(query), {'id_assessment':self.id_assessment}) + self.future_debt_items = [row._asdict() for row in rds_data.fetchall()] + + self.treasure_debt_items = [item for item in self.future_debt_items if item['ALIAS_NAME'] == 'Deuda de Tesoreria'] + self.future_debt_items = [item for item in self.future_debt_items if item['ALIAS_NAME'] != 'Deuda de Tesoreria'] + logger.info(f'[get_debt_data] Deudas re organizadas, resultados:\nDeudas actuales: {self.current_debt_items}\nDeudas futuras: {self.future_debt_items}\nDeudas de tesorería:{self.treasure_debt_items}') + + + @handler_wrapper('Organizando objetos de deuda actual', 'Objetos de deuda actual organizados con exito','Error organizando objetos de deuda actual', 'Error organizando objeto de deuda actual') + def organize_current_debt_items(self): + found_accounts = sorted(set(row['account'] for row in self.current_debt_items)) + for account in found_accounts: + base_properties = next(item for item in self.current_debt_items if item['account'] == account) + rate_atributtes = [float(item['RATE_ATRIBUTE']) for item in self.current_debt_items if item['account'] == account][len(self.historic_dates):] + spread_atributtes = [float(item['SPREAD_ATRIBUTE']) for item in self.current_debt_items if item['account'] == account][len(self.historic_dates):] + years_vector = [item['ITEM_DATE'].strftime('%Y') for item in self.current_debt_items if item['account'] == account][len(self.historic_dates):] + years_vector[0] = years_vector[0] if '-12-' in self.historic_dates[-1] else f"Diciembre {years_vector[0]}" + + self.current_debt_array.append({'accountNumber':account, + 'expiration':base_properties['ENDING_YEAR'], + 'accountName':base_properties['ACCOUNT_NAME'], + 'name':base_properties['ALIAS_NAME'], + 'method':base_properties['PROJECTION_TYPE'], + 'explication':base_properties['DEBT_COMMENT'], + 'years':years_vector, + 'rates':{'values':rate_atributtes, 'explication':base_properties['RATE_COMMENT']}, + 'spread':{'values':spread_atributtes, 'explication':base_properties['SPREAD_COMMENT']} + }) + + + @handler_wrapper('Organizando objetos de deuda futura', 'Objetos de deuda futura organizados con exito','Error organizando objetos de deuda futura', 'Error organizando objeto de deuda futura') + def organize_future_debt_items(self): + found_aliases = sorted(set(row['ALIAS_NAME'] for row in self.future_debt_items)) + for alias in found_aliases: + base_properties = next(item for item in self.future_debt_items if item['ALIAS_NAME'] == alias) + rate_atributtes = [float(item['RATE_ATRIBUTE']) for item in self.future_debt_items if item['ALIAS_NAME'] == alias] + spread_atributtes = [float(item['SPREAD_ATRIBUTE']) for item in self.future_debt_items if item['ALIAS_NAME'] == alias] + years_vector = [item['ITEM_DATE'].strftime('%Y') for item in self.future_debt_items if item['ALIAS_NAME'] == alias] + + self.future_debt_array.append({'newAmount': float(base_properties['ORIGINAL_VALUE']), + 'disburmentYear':base_properties['START_YEAR'], + 'finalYear':base_properties['ENDING_YEAR'], + 'name':base_properties['ALIAS_NAME'], + 'method':base_properties['PROJECTION_TYPE'], + 'explication':base_properties['DEBT_COMMENT'], + 'years':years_vector, + 'rates':{'values':rate_atributtes, 'explication':base_properties['RATE_COMMENT']}, + 'spread':{'values':spread_atributtes, 'explication':base_properties['SPREAD_COMMENT']} + }) + + @handler_wrapper('Se encontraron tasas de deuda de tesorería, organizando', 'Deuda de tesorería organizada con exito', 'Error organizando deuda de tesorería', 'Error organizando tasas de tesorería') + def organize_treasure_debt_items(self): + base_properties = self.treasure_debt_items[0] + self.treasure_debt_record = {'disburmentYear':base_properties['START_YEAR'], + 'finalYear': base_properties['ENDING_YEAR'], + 'name': 'Deuda de Tesoreria', + 'method': 'Amortización lineal', + 'explication': base_properties['DEBT_COMMENT'], + 'years':[], + 'rates':{'values':[],'explication':base_properties['RATE_COMMENT']}, + 'spread':{'values':[],'explication':base_properties['SPREAD_COMMENT']}} + + for item in self.treasure_debt_items: + self.treasure_debt_record['years'].append(item['ITEM_DATE'].strftime('%Y')) + self.treasure_debt_record['rates']['values'].append(safe_exit(item['RATE_ATRIBUTE'])) + self.treasure_debt_record['spread']['values'].append(safe_exit(item['SPREAD_ATRIBUTE'])) + + + + @handler_wrapper('Organizando Respuesta final', 'Respuesta final organizada con exito', 'Error organizando respuesta final', 'Error organizando respuesta final') + def organize_partial_response(self): + min_year = int(self.projection_dates[1].split('-')[0]) if '-12-' in self.projection_dates[0] else int(self.projection_dates[0].split('-')[0]) + self.partial_response = {'minYear':min_year, 'maxYear':int(self.projection_dates[-1].split('-')[0]), 'financialDebt': self.current_debt_array, 'futureDebt': self.future_debt_array, 'treasureDebt': []} + if self.treasure_debt_items: + self.partial_response['treasureDebt'] = [self.treasure_debt_record] + + + @debugger_wrapper('Error construyendo respuesta final', 'Error construyendo respuesta') + def response_maker(self, succesfull_run = False, error_str = str()): + if self.db_connection: + self.db_connection.close() + if succesfull_run: + self.final_response['statusCode'] = 200 + self.final_response['body'] = json.dumps(self.partial_response) + return self.final_response + + self.final_response['body'] = json.dumps(self.detailed_raise if self.detailed_raise else error_str) + return self.final_response + + + +def get_current_error_line(): + return str(sys.exc_info()[-1].tb_lineno) + +def safe_exit(j): + try: + return float(j) + except: + return 0 + + +if __name__ == "__main__": + event = {"pathParameters": {"id_assessment": "47"}} + lambda_handler(event, '') \ No newline at end of file diff --git a/corporate_finances_back_py/debt-retrieve/utils.py b/corporate_finances_back_py/debt-retrieve/utils.py new file mode 100644 index 0000000..6a07af1 --- /dev/null +++ b/corporate_finances_back_py/debt-retrieve/utils.py @@ -0,0 +1,41 @@ +#version 2023 - 05 - 04 +import base64 +import boto3 +import json +import logging + +from sqlalchemy import create_engine + +from decorators import handler_wrapper, debugger_wrapper + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + + +@debugger_wrapper('Error al obtener secreto','Error fatal de back conectando a base de datos') +def get_secret(secret_region, secret_name): + session = boto3.session.Session() + client_secrets_manager = session.client(service_name='secretsmanager', region_name=secret_region) + secret_data = client_secrets_manager.get_secret_value(SecretId=secret_name) + if 'SecretString' in secret_data: + secret_str = secret_data['SecretString'] + else: + secret_str = base64.b64decode(secret_data['SecretBinary']) + logger.info('[utils] (get_secret) Se obtuvo el secreto') + return json.loads(secret_str) + + +@debugger_wrapper('Error en la conexion a base de datos','Error fatal de back conectando a base de datos') +def connect_to_db(db_schema, db_secret): + conn_string = ('mysql+mysqlconnector://' + db_secret["username"] + ':' + db_secret["password"] + '@' + db_secret["host"] + ':' + str(db_secret["port"]) + '/' + db_schema) + sql_engine = create_engine(conn_string) + db_connection = sql_engine.connect() + return db_connection + + +@debugger_wrapper('Error en la conexion a base de datos','Error fatal de back conectando a base de datos') +def connect_to_db_local_dev(): + conn_string = open(r"C:\Users\JeissonBotache\.aws\aurora_sources8_dev.txt", "r").read() + sql_engine = create_engine(conn_string) + db_connection = sql_engine.connect() + return db_connection diff --git a/corporate_finances_back_py/debt-saver/decorators.py b/corporate_finances_back_py/debt-saver/decorators.py new file mode 100644 index 0000000..071760a --- /dev/null +++ b/corporate_finances_back_py/debt-saver/decorators.py @@ -0,0 +1,63 @@ +#version 2023 - 05 - 04 +import logging +import sys +import traceback +from functools import wraps +from time import time + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + +def handler_wrapper(start, satisfactory_log, error_log, raise_error): + #esto se ejecuta en la inicializacion de primero + def decorator(func): + #print(message1) + #lo que yo ponga acá se ejecuta antes de hacer el llamado a la funcion + @wraps(func) + def wrapper(*args, **kwargs): + #esto sí se ejecuta solo cuando llama a la funcion decorada + #print(message2) + try: + logger.info(f'[{func.__name__}] {start}...') + resultado = func(*args, **kwargs) + logger.info(f'[{func.__name__}] {satisfactory_log}') + return resultado + except Exception as e: + logger.error(f"[{func.__name__}] {error_log}, linea: {get_especific_error_line(func.__name__)}, motivo: {str(e)}") + raise Exception(f"{raise_error}") + + return wrapper + return decorator + +def debugger_wrapper(error_log, raise_error): + def decorator(func): + @wraps(func) + def wrapper(*args, **kwargs): + try: + resultado = func(*args, **kwargs) + return resultado + except Exception as e: + logger.error(f"[{func.__name__}] {error_log}, linea: {get_especific_error_line(func.__name__)}, motivo: {str(e)}") + raise Exception(f"{raise_error}") + return wrapper + return decorator + + +def get_especific_error_line(func_name): + _, _, exc_tb = sys.exc_info() + for trace in traceback.extract_tb(exc_tb): + if func_name in trace: + return str(trace[1]) + +def timing(f): + @wraps(f) + def wrap(*args, **kw): + ts = time() + result = f(*args, **kw) + te = time() + taken_time_message = '[timing] La funcion {}, toma: {:.2f} sec en ejecutarse'.format(f.__name__, te-ts) + logger.info(taken_time_message) + return result + return wrap + + diff --git a/corporate_finances_back_py/debt-saver/lambda_function.py b/corporate_finances_back_py/debt-saver/lambda_function.py new file mode 100644 index 0000000..11e7189 --- /dev/null +++ b/corporate_finances_back_py/debt-saver/lambda_function.py @@ -0,0 +1,330 @@ +import json +import logging +import sys +import os +import pandas as pd +from datetime import datetime +from sqlalchemy import text + +from decorators import handler_wrapper, timing, debugger_wrapper +from utils import get_secret, connect_to_db, call_dynamic_engine, connect_to_db_local_dev + +logging.basicConfig() +logging.basicConfig(format='%(asctime)s [%(levelname)s] [%(module)s] %(message)s', force=True, datefmt='%Y-%m-%d %H:%M:%S') +logger = logging.getLogger() +logger.setLevel(logging.INFO) + +def lambda_handler(event,context): + sc_obj = script_object(event) + lambda_response = sc_obj.starter() + logger.info(f'respuesta final de lambda: \n{lambda_response}') + return lambda_response + + +class script_object: + def __init__(self, event): + try: + self.failed_init = False + self.final_response = {'headers':{'Access-Control-Allow-Headers': '*', + 'Access-Control-Allow-Origin': '*', + 'Access-Control-Allow-Methods': '*'}, "statusCode": 500, 'body': {}} + self.db_connection = 0 + self.detailed_raise = '' + self.partial_response = list() + + logger.warning(f'event de entrada: {str(event)}') + + event_dict = json.loads(event['body']) + self.id_assessment = event_dict['id_assessment'] + self.current_debt_items = event_dict['financialDebt'] + self.future_debt_items = event_dict['futureDebt'] + future_debt = event_dict.get('treasureDebt', False) + if future_debt: + future_debt = future_debt[0] + future_debt['newAmount'] = 0 + logger.info('Se está capturando deuda de tesorería') + self.future_debt_items.append(future_debt) + + self.historic_dates = list() + self.debt_account_value_dict = dict() + self.projection_dates = list() + self.debt_directory = list() + self.projections_directory = list() + self.future_debt_directory = list() + self.future_deb_projections_directory = list() + + except Exception as e: + logger.error(f'[__init__] Error inicializando objeto lambda, linea: {get_current_error_line()}, motivo: {str(e)}') + self.failed_init = True + + def starter(self): + try: + if self.failed_init: + raise AttributeError('Error con los datos recibidos al servicio') + self.create_conection_to_db() + #self.db_connection.begin() + self.get_assessment_dates() + if self.current_debt_items: + self.get_original_values() + self.organize_debt_items() + self.calculate_debt_projections() + + if self.future_debt_items: + self.organize_future_items() + self.calculate_future_debt_projections() + + self.delete_previous_bd_data() + self.create_uploable_dataframes() + self.upload_dataframes_to_bd() + #self.db_connection.commit() + call_dynamic_engine(self.id_assessment) + + return self.response_maker(succesfull_run = True) + + except Exception as e: + logger.error(f'[starter] Hubieron problemas en el comando de la linea: {get_current_error_line()}') + return self.response_maker(succesfull_run = False, error_str = (str(e))) + + @handler_wrapper('Creando conexion a bd','Conexion a bd creada con exito','Error en la conexion a bd','Problemas creando la conexion a bd') + def create_conection_to_db(self): + if __name__ == "__main__": + self.db_connection = connect_to_db_local_dev() + return + db_schema = os.environ['DB_SCHEMA'] + secret_db_region = os.environ['SECRET_DB_REGION'] + secret_db_name = os.environ['SECRET_DB_NAME'] + db_secret = get_secret(secret_db_region, secret_db_name) + self.db_connection = connect_to_db(db_schema, db_secret) + + + @handler_wrapper('Obteniendo las fechas del proceso de valoración', 'Fechas del proceso de valroación obtenidas con exito', 'Error obteniendo las fechas del proceso de valoración', 'Error obteniendo fechas del proceso de valoración') + def get_assessment_dates(self): + query = f"SELECT DATES, PROPERTY FROM ASSESSMENT_DATES WHERE ID_ASSESSMENT = {self.id_assessment} ORDER BY DATES" + logger.info(f"[get_assessment_dates] Query a base de datos para obtener las fechas utilizadas en el proces de valoración:\n {query}") + rds_data = self.db_connection.execute(text(query)) + directory = {'HISTORIC': self.historic_dates, 'PROJECTION': self.projection_dates} + for date_item in rds_data.fetchall(): + directory.get(date_item.PROPERTY, []).append(date_item.DATES.strftime('%Y-%m-%d %H:%M:%S')) #Las self.projection_dates no las estoy usando para nada + + logger.info(f'[get_assessment_dates] Fechas del proceso de valoración:\nhistoricas: {self.historic_dates}\nproyecciones: {self.projection_dates}') + + + @handler_wrapper('Obteniendo valores originales de las deudas', 'Valores originales obtenidos con exito', 'Error adquiriendo valores originales de deudas', 'Error adquiriendo valores originales') + def get_original_values(self): + historic_debt_accounts = [item['accountNumber'] for item in self.current_debt_items] + historic_debt_accounts_str = str(historic_debt_accounts).replace('[','').replace(']','') + query = f"""SELECT A.ACCOUNT_NUMBER AS account, A.ANNUALIZED AS value FROM ASSESSMENT_CHECKED A, ASSESSMENT B WHERE A.ID_ASSESSMENT = B.ID + AND A.ID_ARCHIVE = B.ID_ARCHIVE AND A.ID_ASSESSMENT = {self.id_assessment} AND A.ACCOUNT_NUMBER IN ({historic_debt_accounts_str}) ORDER BY account""" + + logger.info(f"[get_original_values] Query a base de datos para obtener lo valores originales de deuda:\n {query}") + rds_data = self.db_connection.execute(text(query)) + + self.debt_account_value_dict = {row.account:float(row.value) for row in rds_data.fetchall()} + logger.info(f'[get_original_values] Valores originales de las cuentas de deudas:\n{self.debt_account_value_dict}') + + + @handler_wrapper('Calculando proyecciones de deudas historicas', 'Proyecciones de deudas historicas calculados con exito', 'Error proyectando deuda historica', 'Error proyectando deuda historica') + def organize_debt_items(self): + for debt in self.current_debt_items: + debt_caracteristics = {'ID_ASSESSMENT':self.id_assessment, + 'ACCOUNT_NUMBER': debt['accountNumber'], + 'ORIGINAL_VALUE':self.debt_account_value_dict[debt['accountNumber']], + 'ALIAS_NAME': debt['name'], + 'PROJECTION_TYPE': debt['method'], + 'START_YEAR': self.projection_dates[0].split('-')[0], + 'ENDING_YEAR': debt['expiration'], + 'DEBT_COMMENT': debt['explication'], + 'RATE_COMMENT': debt['rates']['explication'], + 'SPREAD_COMMENT': debt['spread']['explication']} + self.debt_directory.append(debt_caracteristics) + + + @handler_wrapper('Calculando proyecciones de deuda', 'Proyecciones de deuda calculadas con éxito', 'Error calculando proyecciones de deuda', 'Error calculando proyecciones de deuda') + def calculate_debt_projections(self): + for debt in self.current_debt_items: + self.calculate_current_debt_projections(debt) + logger.warning(f'[calculate_debt_projections] Directorio final de proyecciones de deuda historica:\n{self.projections_directory}') + + + @debugger_wrapper('Error calculando proyeccion de deuda actual', 'Error calculando proyecciones de deuda actual') + def calculate_current_debt_projections(self, debt): + original_value = self.debt_account_value_dict[debt['accountNumber']] + interest_vector = [float(i)+float(j) for i,j in zip(debt['rates']['values'], debt['spread']['values'])] + + #projection_years = int(debt['expiration']) - int(self.historic_dates[-1].split('-')[0]) #+ 1 # con esto corrijo la división de amortización + projection_years = len(debt['years']) + amortization_vector = [original_value / projection_years] * projection_years + disbursement_vector = [0] * projection_years + + initial_balance_vector = [original_value - amortization_value * proy_year for proy_year, amortization_value in enumerate(amortization_vector)] + final_balance_vector = initial_balance_vector[1:] + + final_balance_vector.append(0) + interest_vector_balance = [i * j / 100 for i, j in zip(initial_balance_vector, interest_vector)] + + final_balance_variance_vector = [final_balance_vector[0]- initial_balance_vector[0]] + for index, value in enumerate(final_balance_vector[1:], start = 1): + final_balance_variance_vector.append(value - final_balance_vector[index-1]) + + logger.info(f'[mira aca] \nvector de interés: {interest_vector_balance}\nanios de proyeccion: {projection_years}') + + projections_long_dates = [datetime.strptime(str(int(self.historic_dates[-1].split('-')[0]) + year), '%Y').strftime('%Y-%m-%d %H:%M:%S') for year in range(1, projection_years + 1)] + + for i in range(1, projection_years + 1): + projection_item = {'ID_ASSESSMENT':self.id_assessment, + 'ACCOUNT_NUMBER':debt['accountNumber'], + 'ALIAS_NAME':debt['name'], + 'ITEM_DATE': projections_long_dates[i-1], + 'INITIAL_BALANCE':initial_balance_vector[i-1], + 'DISBURSEMENT':disbursement_vector[i-1], + 'AMORTIZATION':amortization_vector[i-1], + 'ENDING_BALANCE':final_balance_vector[i-1], + 'INTEREST_VALUE':interest_vector_balance[i-1], + 'ENDING_BALANCE_VARIATION':final_balance_variance_vector[i-1], + 'RATE_ATRIBUTE':debt['rates']['values'][i-1], + 'SPREAD_ATRIBUTE':debt['spread']['values'][i-1]} + self.projections_directory.append(projection_item) + + for date in self.historic_dates: + projection_item = {'ID_ASSESSMENT':self.id_assessment, + 'ACCOUNT_NUMBER':debt['accountNumber'], + 'ALIAS_NAME':debt['name'], + 'ITEM_DATE': date, + 'INITIAL_BALANCE':0, + 'DISBURSEMENT':0, + 'AMORTIZATION':0, + 'ENDING_BALANCE':0, + 'INTEREST_VALUE':0, + 'ENDING_BALANCE_VARIATION':0, + 'RATE_ATRIBUTE':0, + 'SPREAD_ATRIBUTE':0} + self.projections_directory.append(projection_item) + + + + @handler_wrapper('Organizando items de deuda futura', 'Items de deuda futura organizados con exito', 'Error organizando items de deuda futura', 'Error organizando items de deuda futura') + def organize_future_items(self): + for debt in self.future_debt_items: + debt_caracteristics = {'ID_ASSESSMENT':self.id_assessment, + 'ACCOUNT_NUMBER': 0, + 'ORIGINAL_VALUE':debt['newAmount'], + 'ALIAS_NAME': debt['name'], + 'PROJECTION_TYPE': debt['method'], + 'START_YEAR': debt['disburmentYear'], + 'ENDING_YEAR': debt['finalYear'], + 'DEBT_COMMENT': debt['explication'], + 'RATE_COMMENT': debt['rates']['explication'], + 'SPREAD_COMMENT': debt['spread']['explication']} + self.future_debt_directory.append(debt_caracteristics) + + @handler_wrapper('Calculando proyecciones de deuda futura', 'Proyecciones de deuda futura calculadas con exito', 'Error calculando proyecciones de deuda futura', 'Error calculando proyecciones de deuda futura') + def calculate_future_debt_projections(self): + for debt in self.future_debt_items: + self.calculate_single_future_debt_projection(debt) + logger.warning(f'[calculate_future_debt_projections] Directorio construído de deuda futura:\n{self.projections_directory}') + + + @debugger_wrapper('Error calculando proyeccion de deuda futura', 'Error calculando proyeccion de deuda futura') + def calculate_single_future_debt_projection(self, debt): + original_value = debt['newAmount'] + + interest_vector = [i+j for i,j in zip(debt['rates']['values'], debt['spread']['values'])] + + projection_years = int(debt['finalYear']) - int(debt['disburmentYear']) + 1 + amortization_vector = [original_value / projection_years] * projection_years + disbursement_vector = [0] * projection_years + disbursement_vector[0] = original_value + + initial_balance_vector = [original_value - amortization_value * proy_year for proy_year, amortization_value in enumerate(amortization_vector)] + final_balance_vector = initial_balance_vector[1:] #esto está bien, mi saldo final va a ser el inicial del siguiente periodo + + final_balance_vector.append(0) #esto está bien, mi saldo final en el ultimo año debería ser cero + logger.info(f' mira aca {initial_balance_vector} y {interest_vector}') + interest_vector_balance = [i * safe_exit(j) / 100 for i, j in zip(initial_balance_vector, interest_vector)] #Al quitar la linea 238, el interés debería tener valores desde el primer año + + final_balance_variance_vector = [final_balance_vector[0]] + for index, value in enumerate(final_balance_vector[1:], start = 1): + final_balance_variance_vector.append(value - final_balance_vector[index-1]) + + projections_long_dates = [datetime.strptime(str(int(debt['disburmentYear']) + year), '%Y').strftime('%Y-%m-%d %H:%M:%S') for year in range(projection_years)] + + for i in range(projection_years): + projection_item = {'ID_ASSESSMENT':self.id_assessment, + 'ACCOUNT_NUMBER':0, + 'ALIAS_NAME':debt['name'], + 'ITEM_DATE': projections_long_dates[i], + 'INITIAL_BALANCE':initial_balance_vector[i], + 'DISBURSEMENT':disbursement_vector[i], + 'AMORTIZATION':amortization_vector[i], + 'ENDING_BALANCE':final_balance_vector[i], + 'INTEREST_VALUE':interest_vector_balance[i], + 'ENDING_BALANCE_VARIATION':final_balance_variance_vector[i], + 'RATE_ATRIBUTE':debt['rates']['values'][i], + 'SPREAD_ATRIBUTE':debt['spread']['values'][i]} + self.future_deb_projections_directory.append(projection_item) + + + @handler_wrapper('Eliminando posible data de deuda anterior', 'Posible data de deuda en bd eliminada correctamente', 'Error eliminando posible data de deuda en bd', 'Error sobreescribiendo data en bd') + def delete_previous_bd_data(self): + query = f"DELETE FROM DEBT WHERE ID_ASSESSMENT = {self.id_assessment}" + logger.info(f'[delete_previous_bd_data] Query para eliminado de data en tabla DEBT:\n{query}') + self.db_connection.execute(text(query)) + + query = f"DELETE FROM PROJECTED_DEBT WHERE ID_ASSESSMENT = {self.id_assessment}" + logger.info(f'[delete_previous_bd_data] Query para eliminado de data en tabla PROJECTED_DEBT:\n{query}') + self.db_connection.execute(text(query)) + + + @handler_wrapper('Creando Dataframes para carga en bd', 'Dataframes creados con exito', 'Error creando dataframes para carga en bd', 'Error creando tablas para carga en bd') + def create_uploable_dataframes(self): + if self.current_debt_items: + self.debt_df = pd.DataFrame.from_records(self.debt_directory) + self.debt_projections_df = pd.DataFrame.from_records(self.projections_directory) + + if self.future_debt_items: + self.future_debt_df = pd.DataFrame.from_records(self.future_debt_directory) + self.future_debt_projections_df = pd.DataFrame.from_records(self.future_deb_projections_directory) + + + @handler_wrapper('Cargando data a bd', 'Data cargada a bd', 'Error en la carga de información a bd', 'Error cargando la información a bd') + def upload_dataframes_to_bd(self): + if self.current_debt_items: + logger.info(f'[upload_dataframes_to_bd] Dataframe que se cargará a DEBT:\n{self.debt_df.to_string()}') + logger.info(f'[upload_dataframes_to_bd] Dataframe que se cargará a PROJECTED_DEBT:\n{self.debt_projections_df.to_string()}') + self.debt_df.to_sql(name='DEBT', con=self.db_connection, if_exists='append', index=False) + self.debt_projections_df.to_sql(name='PROJECTED_DEBT', con=self.db_connection, if_exists='append', index=False) + + if self.future_debt_items: + logger.info(f'[upload_dataframes_to_bd] Dataframe que se cargará a DEBT:\n{self.future_debt_df.to_string()}') + logger.info(f'[upload_dataframes_to_bd] Dataframe que se cargará a PROJECTED_DEBT:\n{self.future_debt_projections_df.to_string()}') + self.future_debt_df.to_sql(name='DEBT', con=self.db_connection, if_exists='append', index=False) + self.future_debt_projections_df.to_sql(name='PROJECTED_DEBT', con=self.db_connection, if_exists='append', index=False) + + + @debugger_wrapper('Error construyendo respuesta final', 'Error construyendo respuesta') + def response_maker(self, succesfull_run = False, error_str = str()): + if self.db_connection: + self.db_connection.close() + if succesfull_run: + self.final_response['statusCode'] = 200 + self.final_response['body'] = json.dumps('ok') + return self.final_response + + self.final_response['body'] = json.dumps(self.detailed_raise if self.detailed_raise else error_str) + return self.final_response + + + +def get_current_error_line(): + return str(sys.exc_info()[-1].tb_lineno) + +def safe_exit(j): + try: + return float(j) + except: + return 0 + + +if __name__ == "__main__": + event = {"body": "{\"id_assessment\":2028,\"financialDebt\":[{\"accountName\":\"Pasivos financieras (21)\",\"accountNumber\":\"21\",\"expiration\":\"2022\",\"name\":\"Prueba1\",\"method\":\"Amortización lineal\",\"explication\":\"1\",\"years\":[\"Diciembre 2020\",2021,2022],\"rates\":{\"values\":[1,1,1],\"explication\":\"Hola\"},\"spread\":{\"values\":[1,1,1],\"explication\":\"Hola1\"}},{\"accountName\":\"Pasivos de operaciones corrientes (22)\",\"accountNumber\":\"22\",\"expiration\":\"2023\",\"name\":\"Prueba\",\"method\":\"Amortización lineal\",\"explication\":\"Purbea\",\"years\":[\"Diciembre 2020\",2021,2022,2023],\"rates\":{\"values\":[1,1,1,1],\"explication\":\"1\"},\"spread\":{\"values\":[1,1,1,1],\"explication\":\"1\"}},{\"accountName\":\"Cuentas por pagar (23)\",\"accountNumber\":\"23\",\"expiration\":\"2023\",\"name\":\"A\",\"method\":\"Amortización lineal\",\"explication\":\"1\",\"years\":[\"Diciembre 2020\",2021,2022,2023],\"rates\":{\"values\":[1,1,1,1],\"explication\":\"1\"},\"spread\":{\"values\":[1,1,1,-2],\"explication\":\"1\"}},{\"accountName\":\"Pasivos por impuestos corrientes (24)\",\"accountNumber\":\"24\",\"expiration\":\"2021\",\"name\":\"a\",\"method\":\"Amortización lineal\",\"explication\":\"1\",\"years\":[\"Diciembre 2020\",2021],\"rates\":{\"values\":[1,1],\"explication\":\"A\"},\"spread\":{\"values\":[1,-1],\"explication\":\"A\"}}],\"futureDebt\":[],\"treasureDebt\":[{\"disburmentYear\":2020,\"finalYear\":2023,\"name\":\"Deuda de Tesoreria\",\"method\":\"Amortización lineal\",\"explication\":\"\",\"years\":[\"2020\",\"2021\",\"2022\",\"2023\"],\"rates\":{\"values\":[0,0,0,0],\"explication\":\"\"},\"spread\":{\"values\":[0,0,0,0],\"explication\":\"\"}}]}"} + lambda_handler(event, '') \ No newline at end of file diff --git a/corporate_finances_back_py/debt-saver/utils.py b/corporate_finances_back_py/debt-saver/utils.py new file mode 100644 index 0000000..1ba35cd --- /dev/null +++ b/corporate_finances_back_py/debt-saver/utils.py @@ -0,0 +1,51 @@ +#version 2023 - 05 - 04 +import base64 +import boto3 +import json +import logging +import os +from sqlalchemy import create_engine + +from decorators import handler_wrapper, debugger_wrapper + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + + +@debugger_wrapper('Error al obtener secreto','Error fatal de back conectando a base de datos') +def get_secret(secret_region, secret_name): + session = boto3.session.Session() + client_secrets_manager = session.client(service_name='secretsmanager', region_name=secret_region) + secret_data = client_secrets_manager.get_secret_value(SecretId=secret_name) + if 'SecretString' in secret_data: + secret_str = secret_data['SecretString'] + else: + secret_str = base64.b64decode(secret_data['SecretBinary']) + logger.info('[utils] (get_secret) Se obtuvo el secreto') + return json.loads(secret_str) + + +@debugger_wrapper('Error en la conexion a base de datos','Error fatal de back conectando a base de datos') +def connect_to_db(db_schema, db_secret): + conn_string = ('mysql+mysqlconnector://' + db_secret["username"] + ':' + db_secret["password"] + '@' + db_secret["host"] + ':' + str(db_secret["port"]) + '/' + db_schema) + sql_engine = create_engine(conn_string) + db_connection = sql_engine.connect() + return db_connection + + +@handler_wrapper('Invocando asincronamente a Engine de dinamismo', 'Invocación a Engine exitosa', 'Error invocando a Engine', 'Error invocando dinamismo') +def call_dynamic_engine(id_assessment): + data = json.dumps({'id_assessment':id_assessment}).encode() + client = boto3.client('lambda') + client.invoke( + FunctionName = os.environ['LAMBDA_ENGINE'], + InvocationType='Event', + Payload= data +) + +@debugger_wrapper('Error en la conexion a base de datos','Error fatal de back conectando a base de datos') +def connect_to_db_local_dev(): + conn_string = open(r"C:\Users\JeissonBotache\.aws\aurora_sources8_dev.txt", "r").read() + sql_engine = create_engine(conn_string) + db_connection = sql_engine.connect() + return db_connection diff --git a/corporate_finances_back_py/extractor.py b/corporate_finances_back_py/extractor.py new file mode 100644 index 0000000..5f7ca4f --- /dev/null +++ b/corporate_finances_back_py/extractor.py @@ -0,0 +1,20 @@ +import zipfile +import os + +this_path = os.getcwd() +lambdas_zip_list = [item for item in os.listdir() if item.endswith('.zip')] +print(f'Loz zips encontrados son: {len(lambdas_zip_list)}\n{lambdas_zip_list}') +print(this_path) + + + +def extractor(zip_name): + full_path = f'{this_path}\{zip_name}' + print(f'extrayendo: {full_path}') + ZipFile = zipfile.ZipFile(full_path) + #extracted_folder_name = '-'.join(zip_name.replace('.zip','').split('-')[3:]) #esto es cuando el nombre de la lambda incluye lbd dev finanzas + extracted_folder_name = zip_name.replace('.zip','') + ZipFile.extractall(path = f"{this_path}\extracted\\{extracted_folder_name}") + +for zip_file_name in lambdas_zip_list: + extractor(zip_file_name) \ No newline at end of file diff --git a/corporate_finances_back_py/folder_names.py b/corporate_finances_back_py/folder_names.py new file mode 100644 index 0000000..7569841 --- /dev/null +++ b/corporate_finances_back_py/folder_names.py @@ -0,0 +1,27 @@ + +import os + +cwd = os.getcwd() + +found_folders = os.listdir(cwd) + +to_ = str.maketrans("-", "_") +from_ = str.maketrans("_", "-") +options = {'-': from_, '_': to_} + +while True: + choice = input('¿Hacia qué formato desea transformar las carpetas? -/_: ') + if choice in ("-", "_"): + use_translator = options[choice] + break + print('Opción incorrecta\n') + + +for folder_name in found_folders: + + if '.' in folder_name: + continue + try: + os.rename(f'{cwd}\{folder_name}', f'{cwd}\{folder_name.translate(use_translator)}') + except: + continue \ No newline at end of file diff --git a/corporate_finances_back_py/full-model-saver/decorators.py b/corporate_finances_back_py/full-model-saver/decorators.py new file mode 100644 index 0000000..071760a --- /dev/null +++ b/corporate_finances_back_py/full-model-saver/decorators.py @@ -0,0 +1,63 @@ +#version 2023 - 05 - 04 +import logging +import sys +import traceback +from functools import wraps +from time import time + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + +def handler_wrapper(start, satisfactory_log, error_log, raise_error): + #esto se ejecuta en la inicializacion de primero + def decorator(func): + #print(message1) + #lo que yo ponga acá se ejecuta antes de hacer el llamado a la funcion + @wraps(func) + def wrapper(*args, **kwargs): + #esto sí se ejecuta solo cuando llama a la funcion decorada + #print(message2) + try: + logger.info(f'[{func.__name__}] {start}...') + resultado = func(*args, **kwargs) + logger.info(f'[{func.__name__}] {satisfactory_log}') + return resultado + except Exception as e: + logger.error(f"[{func.__name__}] {error_log}, linea: {get_especific_error_line(func.__name__)}, motivo: {str(e)}") + raise Exception(f"{raise_error}") + + return wrapper + return decorator + +def debugger_wrapper(error_log, raise_error): + def decorator(func): + @wraps(func) + def wrapper(*args, **kwargs): + try: + resultado = func(*args, **kwargs) + return resultado + except Exception as e: + logger.error(f"[{func.__name__}] {error_log}, linea: {get_especific_error_line(func.__name__)}, motivo: {str(e)}") + raise Exception(f"{raise_error}") + return wrapper + return decorator + + +def get_especific_error_line(func_name): + _, _, exc_tb = sys.exc_info() + for trace in traceback.extract_tb(exc_tb): + if func_name in trace: + return str(trace[1]) + +def timing(f): + @wraps(f) + def wrap(*args, **kw): + ts = time() + result = f(*args, **kw) + te = time() + taken_time_message = '[timing] La funcion {}, toma: {:.2f} sec en ejecutarse'.format(f.__name__, te-ts) + logger.info(taken_time_message) + return result + return wrap + + diff --git a/corporate_finances_back_py/full-model-saver/lambda_function.py b/corporate_finances_back_py/full-model-saver/lambda_function.py new file mode 100644 index 0000000..7cece3e --- /dev/null +++ b/corporate_finances_back_py/full-model-saver/lambda_function.py @@ -0,0 +1,198 @@ +import datetime +import json +import logging +import os +import sys +import traceback + +import pandas as pd +from sqlalchemy import text +from decorators import debugger_wrapper, handler_wrapper +from utils import connect_to_db, get_secret, local_connect_to_db + +logging.basicConfig() +logging.basicConfig(format='%(asctime)s [%(levelname)s] [%(module)s] %(message)s', force=True, datefmt='%Y-%m-%d %H:%M:%S') +logger = logging.getLogger() +logger.setLevel(logging.DEBUG) + + +def lambda_handler(event, context): + sc_obj = script_object(event) + lambda_response = sc_obj.starter() + logger.info(f'respuesta final de lambda: \n{lambda_response}') + return lambda_response + + +class script_object(): + + @handler_wrapper('Obteniendo valores clave de event', 'Valores de event obtenidos correctamente', + 'Error al obtener valores event', 'Fallo en la obtencion de valores clave de event') + def __init__(self, event) -> None: + try: + self.failed_init = False + self.final_response = {'headers':{'Access-Control-Allow-Headers': '*', + 'Access-Control-Allow-Origin': '*', + 'Access-Control-Allow-Methods': '*'}, "statusCode": 500, 'body': {}} + self.db_connection = 0 + self.detailed_raise = '' + self.partial_response = {} + + logger.warning(f'event de entrada: {str(event)}') + self.id_assessment = json.loads(event['body'])['id_assessment'] + + + self.simple_atributes_tables = {'CAPEX': ['USED_ACCOUNT_NAME', 'METHOD', 'TIME_PERIOD', 'PERIODS', 'CALCULATION_COMMENT'], + 'DEBT': ['ORIGINAL_VALUE', 'ACCOUNT_NUMBER', 'ALIAS_NAME', 'PROJECTION_TYPE', 'START_YEAR', 'ENDING_YEAR', 'DEBT_COMMENT', 'RATE_COMMENT', 'SPREAD_COMMENT'], + 'FIXED_ASSETS': ['ID_ITEMS_GROUP', 'PROJECTION_TYPE', 'ASSET_ACCOUNT', 'ACUMULATED_ACCOUNT', 'PERIOD_ACCOUNT', 'PROJECTED_YEARS', 'CALCULATION_COMMENT'], + 'MODAL_WINDOWS': ['ACCOUNT_NUMBER', 'CONTEXT_WINDOW', 'VS_ACCOUNT_NAME', 'PROJECTION_TYPE', 'COMMENT'], + 'PYG_ITEM': ['ID_RAW_PYG', 'ID_DEPENDENCE', 'PROJECTION_TYPE', 'COMMENT'], + 'USER_CLASSIFICATION': ['ACCOUNT_NUMBER', 'ID_RAW_CLASSIFICATION'], + 'CALCULATED_ASSESSMENT': ['ASSESSMENT_DATE', 'INITIAL_DATE', 'DATES_ADJUST_ATRIBUTE', 'DATES_ADJUST_COMMENT', 'CHOSEN_FLOW_NAME', 'GRADIENT', 'TERMINAL_VALUE', 'TOTAL_NOT_OPERATIONAL_ASSETS', 'TOTAL_OPERATIONAL_PASIVES', 'OUTSTANDING_SHARES', 'ADJUST_METHOD']} + + + self.ordered_atributes_tables = {'CAPEX_VALUES': {'columns': ['CALCULATED_DATE', 'MANUAL_PERCENTAGE', 'CAPEX_SUMMARY', 'CAPEX_ACUMULATED'], 'order':'CALCULATED_DATE'}, + 'PROJECTED_DEBT': {'columns': ['ITEM_DATE', 'ACCOUNT_NUMBER', 'ALIAS_NAME', 'INITIAL_BALANCE', 'DISBURSEMENT', 'AMORTIZATION', 'ENDING_BALANCE', 'INTEREST_VALUE','ENDING_BALANCE_VARIATION', 'RATE_ATRIBUTE', 'SPREAD_ATRIBUTE'], 'order':'ITEM_DATE'}, + 'FCLO_DISCOUNT': {'columns': ['ITEM_DATE', 'DISCOUNT_PERIOD', 'DISCOUNT_RATE', 'DISCOUNT_FACTOR'], 'order':'ITEM_DATE'}, + 'PROJECTED_FIXED_ASSETS': {'columns': ['PROJECTED_DATE', 'ID_ITEMS_GROUP', 'ASSET_VALUE', 'ACUMULATED_VALUE', 'EXISTING_ASSET_VALUE', 'PERIOD_VALUE'], 'order':'PROJECTED_DATE'}, + 'MODAL_WINDOWS_PROJECTED': {'columns': ['PROJECTED_DATE', 'ACCOUNT_NUMBER', 'CONTEXT_WINDOW', 'ATRIBUTE', 'VALUE'], 'order': 'PROJECTED_DATE'}, + 'PROJECTED_PYG': {'columns': ['PROJECTED_DATE', 'ID_RAW_PYG', 'ATRIBUTE', 'VALUE'], 'order':'PROJECTED_DATE'}} + + self.columns_dropper = {} + + self.historic_dates = list() + self.projection_dates = list() + self.total_asssessment_dates = 0 + self.table_atributes = dict() + self.table_dfs = dict() + + except Exception as e: + logger.error(f'[__init__] Error inicializando objeto lambda, linea: {get_current_error_line()}, motivo: {str(e)}') + self.failed_init = True + + + def starter(self): + try: + if self.failed_init: + raise AttributeError('Error con los datos recibidos al servicio') + + logger.info('[starter] Empezando starter de objeto lambda') + self.create_conection_to_db() + self.get_company_id() + self.get_assessment_dates() + self.acquire_assessment_simple_attributes() + self.acquire_assessment_ordered_attributes() + self.reduce_model_dates() + self.create_uploable_dataframes() + self.delete_previous_models() + self.upload_models() + #self.db_connection.commit() + return self.response_maker(succesfull_run = True) + except Exception as e: + logger.error(f'[starter] Hubieron problemas en el comando de la linea: {get_current_error_line()}') + return self.response_maker(succesfull_run = False, error_str = (str(e))) + + + @handler_wrapper('Creando conexion a bd','Conexion a bd creada con exito','Error en la conexion a bd','Problemas creando la conexion a bd') + def create_conection_to_db(self): + if __name__ == "__main__": + self.db_connection = local_connect_to_db() + else: + db_schema = os.environ['DB_SCHEMA'] + secret_db_region = os.environ['SECRET_DB_REGION'] + secret_db_name = os.environ['SECRET_DB_NAME'] + db_secret = get_secret(secret_db_region, secret_db_name) + self.db_connection = connect_to_db(db_schema, db_secret) + + + @handler_wrapper('Obteniendo el ID de la empresa', 'ID de la empresa obtenido con exito', 'Error obteniendo ID de la empresa', 'Error obteniendo identificador de empresa') + def get_company_id(self): + query = 'SELECT A.ID FROM COMPANY A, ARCHIVE B, ASSESSMENT C WHERE A.ID = B.ID_COMPANY AND B.ID = C.ID_ARCHIVE AND C.ID = :id_assessment' + logger.info(f'[get_company_id] Query para obtener el ID de la empresa que se está valorando: {query}') + rds_data = self.db_connection.execute(text(query), {'id_assessment': self.id_assessment}) + self.id_company = int(rds_data.scalar()) + + + @handler_wrapper('Obteniendo las fechas del proceso de valoración', 'Fechas del proceso de valroación obtenidas con exito', 'Error obteniendo las fechas del proceso de valoración', 'Error obteniendo fechas del proceso de valoración') + def get_assessment_dates(self): + query = "SELECT DATES, PROPERTY FROM ASSESSMENT_DATES WHERE ID_ASSESSMENT = :id_assessment ORDER BY DATES" + logger.info(f"[get_assessment_dates] Query a base de datos para obtener las fechas utilizadas en el proces de valoración:\n {query}") + rds_data = self.db_connection.execute(text(query), {'id_assessment': self.id_assessment}) + directory = {'HISTORIC': self.historic_dates, 'PROJECTION': self.projection_dates} + for date_item in rds_data.fetchall(): + directory.get(date_item.PROPERTY, []).append(date_item.DATES) + self.total_asssessment_dates = self.total_asssessment_dates +1 + + self.historic_dates = [date.strftime('%Y-%m-%d %H:%M:%S') for date in self.historic_dates] + self.projection_dates = [date.strftime('%Y-%m-%d %H:%M:%S') for date in self.projection_dates] + logger.info(f'[get_assessment_dates] Fechas del proceso de valoración:\nhistoricas: {self.historic_dates}\nproyecciones: {self.projection_dates}') + + + @handler_wrapper('Obteniendo Atributos simples del proceso de valoración', 'Atributos simples del proceso de valoración obtenidos con exito', 'Error obteniendo los atributos simples del proceso de valoración', 'Error obteniendo atributos del proceso de valoración') + def acquire_assessment_simple_attributes(self): + for table, columns in self.simple_atributes_tables.items(): + cleaned_colums = str(columns).replace('[','').replace(']','').replace("'", '') + query = f"SELECT {cleaned_colums} FROM {table} WHERE ID_ASSESSMENT = {self.id_assessment}" + logger.info(f"[acquire_assessment_simple_attributes] Query a base de datos para obtener los atributos de la tabla {table}:\n{query}") + rds_data = self.db_connection.execute(text(query)) + self.table_atributes[table] = [row._asdict() for row in rds_data.fetchall()] + logger.info(f'[acquire_assessment_simple_attributes] Datos encontrados para la tabla {table}:\n{self.table_atributes[table]}') + + + @handler_wrapper('Obteniendo Atributos del proceso de valoración', 'Atributos del proceso de valoración obtenidos con exito', 'Error obteniendo atributos del proceso de valoración', 'Error obteniendo atributos del proceso de valoración') + def acquire_assessment_ordered_attributes(self): + for table, cols_order in self.ordered_atributes_tables.items(): + cleaned_colums = str(cols_order['columns']).replace('[','').replace(']','').replace("'", '') + query = f"SELECT {cleaned_colums} FROM {table} WHERE ID_ASSESSMENT = {self.id_assessment} ORDER BY {cols_order['order']}" + logger.info(f"[acquire_assessment_ordered_attributes] Query a base de datos para obtener los atributos de la tabla {table}:\n{query}") + rds_data = self.db_connection.execute(text(query)) + self.table_atributes[table] = [row._asdict() for row in rds_data.fetchall()] + logger.info(f'[acquire_assessment_ordered_attributes] Datos encontrados para la tabla {table}:\n{self.table_atributes[table]}') + + + @handler_wrapper('Reduciendo cantidad de fechas historicas y proyectadas', 'Reduccion de fechas exitosa', 'Error reduciendo cantidad de fechas', 'Error Revisando fechas del proceso de valoración') + def reduce_model_dates(self): + assessment_has_annual_attributes = 1 if self.historic_dates[-1].split('-')[1] != '12' else 0 + self.table_atributes['ASSESSMENT_YEARS'] = [{'HISTORIC_YEARS':len(self.historic_dates), 'PROJECTION_YEARS': len(self.projection_dates), 'ANNUAL_ATTRIBUTE': assessment_has_annual_attributes}] + #self.table_atributes['ASSESSMENT_YEARS'] = [{'HISTORIC_YEARS':len(self.historic_dates), 'PROJECTION_YEARS': len(self.projection_dates)}] + + @handler_wrapper('Creando dataframes de carga a bd', 'Dataframes de carga creados con exito', 'Error creando dataframes de carga a bd', 'Error creando tablas modelo') + def create_uploable_dataframes(self): + for table, atribute_list in self.table_atributes.items(): + self.table_dfs[table] = pd.DataFrame.from_records(atribute_list) + + + @handler_wrapper('Eliminando posibles modelos anteriores', 'Eliminación de modelos anteriores exitosa', 'Error eliminando posibles modelos anteriores', 'Error sobreescribiendo data') + def delete_previous_models(self): + for table in self.table_dfs: + query = f"DELETE FROM MODEL_{table} WHERE ID_COMPANY = {self.id_company}" + logger.info(f"[delete_previous_models] Query a base de datos para eliminar el modelo de la tabla {table}:\n{query}") + self.db_connection.execute(text(query)) + + + @handler_wrapper('Cargando modelos a bd', 'Modelos cargados a bd con exito', 'Error cargando modelos a bd', 'Error cargando modelos a base de datos') + def upload_models(self): + for table, df in self.table_dfs.items(): + df['ID_COMPANY'] = self.id_company + logger.info(f'[upload_models] Cargando el siguiente dataframe en la tabla MODEL_{table}:\n{df.to_string()}') + df.to_sql(name= f'MODEL_{table}', con=self.db_connection, if_exists='append', index=False) + + + @debugger_wrapper('Error construyendo respuesta final', 'Error construyendo respuesta') + def response_maker(self, succesfull_run = False, error_str = str()): + if self.db_connection: + self.db_connection.close() + if succesfull_run: + self.final_response['statusCode'] = 200 + self.final_response['body'] = json.dumps('ok') + return self.final_response + + self.final_response['body'] = json.dumps(self.detailed_raise if self.detailed_raise else error_str) + return self.final_response + + +def get_current_error_line(): + return str(sys.exc_info()[-1].tb_lineno) + +if __name__ == "__main__": + event = {'body': '{"id_assessment": 30}'} + lambda_handler(event, '') \ No newline at end of file diff --git a/corporate_finances_back_py/full-model-saver/utils.py b/corporate_finances_back_py/full-model-saver/utils.py new file mode 100644 index 0000000..cb5a67f --- /dev/null +++ b/corporate_finances_back_py/full-model-saver/utils.py @@ -0,0 +1,43 @@ +#version 2023 - 05 - 04 +import base64 +import boto3 +import json +import logging + +from sqlalchemy import create_engine + +from decorators import handler_wrapper, debugger_wrapper + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + + +@debugger_wrapper('Error al obtener secreto','Error fatal de back conectando a base de datos') +def get_secret(secret_region, secret_name): + session = boto3.session.Session() + client_secrets_manager = session.client(service_name='secretsmanager', region_name=secret_region) + secret_data = client_secrets_manager.get_secret_value(SecretId=secret_name) + if 'SecretString' in secret_data: + secret_str = secret_data['SecretString'] + else: + secret_str = base64.b64decode(secret_data['SecretBinary']) + logger.info('[utils] (get_secret) Se obtuvo el secreto') + return json.loads(secret_str) + + +@debugger_wrapper('Error en la conexion a base de datos','Error fatal de back conectando a base de datos') +def connect_to_db(db_schema, db_secret): + conn_string = ('mysql+mysqlconnector://' + db_secret["username"] + ':' + db_secret["password"] + '@' + db_secret["host"] + ':' + str(db_secret["port"]) + '/' + db_schema) + sql_engine = create_engine(conn_string) + db_connection = sql_engine.connect() + return db_connection + + +@debugger_wrapper('Error en la conexion local a base de datos','Error fatal conectando a base de datos desde el local') +def local_connect_to_db(): + f = open(r"C:\Users\JeissonBotache\.aws\aurora_sources8_dev.txt", "r") + conn_string = f.read() + logger.warning(f'El string de conexion es:\n{conn_string}') + sql_engine = create_engine(conn_string) + db_connection = sql_engine.connect() + return db_connection \ No newline at end of file diff --git a/corporate_finances_back_py/implicit-growing/decorators.py b/corporate_finances_back_py/implicit-growing/decorators.py new file mode 100644 index 0000000..469f484 --- /dev/null +++ b/corporate_finances_back_py/implicit-growing/decorators.py @@ -0,0 +1,47 @@ +#version 2022 - 12 - 06 +import logging +import sys +import traceback +from functools import wraps +from time import time + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + +def handler_wrapper(start, satisfactory_log, error_log, raise_error): + #esto se ejecuta en la inicializacion de primero + def decorator(func): + #print(message1) + #lo que yo ponga acá se ejecuta antes de hacer el llamado a la funcion + def wrapper(*args, **kwargs): + #esto sí se ejecuta solo cuando llama a la funcion decorada + #print(message2) + try: + logger.info(f'[{func.__name__}] {start}...') + resultado = func(*args, **kwargs) + logger.info(f'[{func.__name__}] {satisfactory_log}') + return resultado + except Exception as e: + logger.error(f"[{func.__name__}] {error_log}, linea: {get_especific_error_line(func.__name__)}, motivo: {str(e)}") + raise Exception(f"{raise_error}") + + return wrapper + return decorator + + +def get_especific_error_line(func_name): + _, _, exc_tb = sys.exc_info() + for trace in traceback.extract_tb(exc_tb): + if func_name in trace: + return str(trace[1]) + +def timing(f): + @wraps(f) + def wrap(*args, **kw): + ts = time() + result = f(*args, **kw) + te = time() + taken_time_message = '[timing] La funcion {}, toma: {:.2f} sec en ejecutarse'.format(f.__name__, te-ts) + logger.info(taken_time_message) + return result + return wrap diff --git a/corporate_finances_back_py/implicit-growing/lambda_function.py b/corporate_finances_back_py/implicit-growing/lambda_function.py new file mode 100644 index 0000000..4efc63b --- /dev/null +++ b/corporate_finances_back_py/implicit-growing/lambda_function.py @@ -0,0 +1,244 @@ +""": +capas: +ninguna + +variables de entorno: +ninguna + +RAM: 256 MB +""" + +import boto3 +from datetime import datetime +import json +import logging +from statistics import mean, stdev, median # linear_regression, +import sys +import traceback + +from decorators import handler_wrapper, timing + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + + +def lambda_handler(event, context): + lo = lambda_object(event) + return lo.starter() + + +class lambda_object(): + accountPyg = list + accountProportion = list + + accountPyg_name = str + accountProportion_name = str + + retrieved_long_dates= list + retrieved_short_dates = list + + implicit_growing_results = dict() + + final_response = {'headers':{'Access-Control-Allow-Headers': '*', 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Methods': '*'}} + + @handler_wrapper('Obteniendo valores clave de event', 'Valores de event obtenidos correctamente', + 'Error al obtener valores event', 'Fallo en la obtencion de valores clave de event') + def __init__(self, event) -> None: + + event_body_json = event["body"] + event_body_dict = json.loads(event_body_json) + logger.info(f'Objeto de entrada event: {str(event)}') + self.accountPyg = event_body_dict['accountPyg'] + self.accountPyg_name = self.accountPyg[0]['account'] + self.accountProportion = event_body_dict["accountProportion"] + self.accountProportion_name = self.accountProportion[0]['account'] + + + def starter(self): + try: + logger.info(f'[starter] Empezando starter de objeto lambda') + self.get_all_dates() + self.organize_values_by_date() + self.calculate_implicit_growing() + self.calculate_proportions() + self.get_statistics() + self.prepare_values_as_strings() + logger.info(f'[starter] Tareas de starter terminadas con exito') + return self.response_maker(succesfull = True) + except Exception as e: + logger.error(f'[starter] Error en el procesamieno del comando de la linea: {get_current_error_line()}, motivo: {e}') + return self.response_maker(succesfull = False, exception_str = e) + + @handler_wrapper('Organizando fechas','Fechas organizadas correctamente','Error al organizar fechas','Error en los datos recibidos') + def get_all_dates(self): + dates_AccountPyg = {datetime.strptime(item['date'], '%d-%m-%Y') for item in self.accountPyg} + self.retrieved_long_dates = sorted(dates_AccountPyg, reverse = False) #Este le da orden ascendente o descendente a todas las fechas a revisar + + short_dates = [] + for date in self.retrieved_long_dates: + short_dates.append(date.strftime('%d-%m-%Y')) + + self.retrieved_short_dates = short_dates + + handler_wrapper('Organizando valores por fechas','Valores organizados correctamente','Error en la oganizacion de valores','Error en los datos recibidos') + def organize_values_by_date(self): + #logger.warning(f'[mira aca fechas cortas] {str(self.retrieved_short_dates)}') + new_accountPyg = [] + new_accountProportion = [] + for date in self.retrieved_short_dates: + for item in self.accountPyg: + if item['date'] == date: + item['value'] = abs(item['value']) + new_accountPyg.append(item) + for item in self.accountProportion: + if item['date'] == date: + item['value'] = abs(item['value']) + new_accountProportion.append(item) + + self.accountPyg = new_accountPyg + self.accountProportion = new_accountProportion + + + @handler_wrapper('Calculando tabla de variacion','Tabla de variacion calculada con exito','Error en el calculo de tabla de variacion','Error en el calculo de datos') + def calculate_implicit_growing(self): + accounts = [self.accountPyg, self.accountProportion] + variations = [] + index = 0 + + + for account in accounts: + variations.append({'name':'Variación absoluta '+account[0]['account'],'value':['No aplica']}) + variations.append({'name':'Variación relativa '+account[0]['account'],'value':['No aplica']}) + for j, item in enumerate(account): + current_value = item['value'] + try: + next_value = account[j+1]['value'] + except Exception: + break + variations[index]['value'].append(next_value-current_value) + if current_value ==0: + variations[index+1]['value'].append(0) + continue + variations[index+1]['value'].append(next_value/current_value - 1) + index = index + 2 + + #logger.warning(f'resultado de variations : {variations}') + self.implicit_growing_results['variations'] = variations + self.accountPyg_rates = variations[1]['value'][1:] + self.accountProportion_rates = variations[3]['value'][1:] + + + def calculate_proportions(self): + proportions = {'name':f"{self.accountPyg[0]['account']} / {self.accountProportion[0]['account']}", 'value':[]} + for i in range(len(self.accountPyg)): + if self.accountProportion[i]['value'] ==0: + proportions['value'].append('No aplica') + continue + proportions['value'].append(self.accountPyg[i]['value'] / self.accountProportion[i]['value']) + + self.implicit_growing_results['proportions'] = [proportions] + + @handler_wrapper('Calculando valores estadisticos','Valores estadisticos obtenidos','Error calculando valores estadisticos','Problemas en los calculos') + def get_statistics(self): + + account_rates = [self.accountPyg_rates, self.accountProportion_rates] + account_names = [self.accountPyg_name, self.accountProportion_name] + statistics = [] + i=0 + + + for account in account_rates: + logger.warning(f'Valor de account: {account}') + temp_object = {'account' : account_names[i]} + try: + temp_object['average'] = mean(account) + except Exception: + temp_object['average'] = 'No aplica' + + try: + temp_object['median'] = median(account) + temp_object['min'] = min(account) + temp_object['max'] = max(account) + except Exception: + temp_object['median'] = 'No aplica' + temp_object['min'] = 'No aplica' + temp_object['max'] = 'No aplica' + try: + temp_object['deviation'] = stdev(account) + temp_object['beta'] = self.calculate_linear_regression() + except Exception: + temp_object['deviation'] = 'No aplica' + temp_object['beta'] = 'No aplica' + + statistics.append(temp_object) + i = i+1 + + self.implicit_growing_results['statistics'] = statistics + ## + + def calculate_linear_regression(self): + x = self.accountPyg_rates + y = self.accountProportion_rates + + n = len(x) + ex = sum(x) + ey = sum(y) + + ex2 = sum([item*item for item in x]) + exy = sum([x[i]*y[i] for i in range(n)]) + + slope = (n*exy-(ex*ey)) / (n*ex2 - (ex**2)) + return slope + + @handler_wrapper('Alistando strings para front','Strings para front alistados correctamente','Error al modificar resultados como strings','Error en el postprocesamiento de informacion') + def prepare_values_as_strings(self): + for index, item in enumerate(self.implicit_growing_results['variations']): + if index %2 == 0: + self.implicit_growing_results['variations'][index]['value'] = self.prepare_list_as_string(self.implicit_growing_results['variations'][index]['value'], 'coin') + else: + self.implicit_growing_results['variations'][index]['value'] = self.prepare_list_as_string(self.implicit_growing_results['variations'][index]['value'], 'percentage') + + self.implicit_growing_results['proportions'][0]['value'] = self.prepare_list_as_string(self.implicit_growing_results['proportions'][0]['value'], 'percentage') + + for index, statistics_object in enumerate(self.implicit_growing_results['statistics']): + for key, value in statistics_object.items(): + self.implicit_growing_results['statistics'][index][key] = self.prepare_item_as_string(value,'percentage') + + + def prepare_list_as_string(self,array,percentage_coin): + temp_item = [] + for item in array: + temp_item.append(self.prepare_item_as_string(item,percentage_coin)) + return temp_item + + + def prepare_item_as_string(self,item,percentage_coin): + if percentage_coin == 'coin': + try: + return f'$ {item:,.2f}'.replace('.',';').replace(',','.').replace(';',',') + except Exception: + return str(item) + + elif percentage_coin == 'percentage': + try: + return f'{item*100:.2f} %' + except Exception: + return str(item) + + + def response_maker(self, succesfull = False, exception_str = str): + if not succesfull: + self.final_response['body'] = json.dumps(exception_str) + else: + self.final_response['body'] = json.dumps(self.implicit_growing_results) + return self.final_response + + + +def get_current_error_line(): + return str(sys.exc_info()[-1].tb_lineno) + + +def get_especific_error_line(): + _, _, exc_tb = sys.exc_info() + return str(traceback.extract_tb(exc_tb)[-1][1]) \ No newline at end of file diff --git a/corporate_finances_back_py/initial-account-classification/decorators.py b/corporate_finances_back_py/initial-account-classification/decorators.py new file mode 100644 index 0000000..071760a --- /dev/null +++ b/corporate_finances_back_py/initial-account-classification/decorators.py @@ -0,0 +1,63 @@ +#version 2023 - 05 - 04 +import logging +import sys +import traceback +from functools import wraps +from time import time + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + +def handler_wrapper(start, satisfactory_log, error_log, raise_error): + #esto se ejecuta en la inicializacion de primero + def decorator(func): + #print(message1) + #lo que yo ponga acá se ejecuta antes de hacer el llamado a la funcion + @wraps(func) + def wrapper(*args, **kwargs): + #esto sí se ejecuta solo cuando llama a la funcion decorada + #print(message2) + try: + logger.info(f'[{func.__name__}] {start}...') + resultado = func(*args, **kwargs) + logger.info(f'[{func.__name__}] {satisfactory_log}') + return resultado + except Exception as e: + logger.error(f"[{func.__name__}] {error_log}, linea: {get_especific_error_line(func.__name__)}, motivo: {str(e)}") + raise Exception(f"{raise_error}") + + return wrapper + return decorator + +def debugger_wrapper(error_log, raise_error): + def decorator(func): + @wraps(func) + def wrapper(*args, **kwargs): + try: + resultado = func(*args, **kwargs) + return resultado + except Exception as e: + logger.error(f"[{func.__name__}] {error_log}, linea: {get_especific_error_line(func.__name__)}, motivo: {str(e)}") + raise Exception(f"{raise_error}") + return wrapper + return decorator + + +def get_especific_error_line(func_name): + _, _, exc_tb = sys.exc_info() + for trace in traceback.extract_tb(exc_tb): + if func_name in trace: + return str(trace[1]) + +def timing(f): + @wraps(f) + def wrap(*args, **kw): + ts = time() + result = f(*args, **kw) + te = time() + taken_time_message = '[timing] La funcion {}, toma: {:.2f} sec en ejecutarse'.format(f.__name__, te-ts) + logger.info(taken_time_message) + return result + return wrap + + diff --git a/corporate_finances_back_py/initial-account-classification/lambda_function.py b/corporate_finances_back_py/initial-account-classification/lambda_function.py new file mode 100644 index 0000000..38d64cf --- /dev/null +++ b/corporate_finances_back_py/initial-account-classification/lambda_function.py @@ -0,0 +1,229 @@ +#{"body": "{\"nit\":\"800149923-8\",\"date\":\"30-11-2022\",\"periodicity\":\"Trimestral\"}"} + + +import boto3 +import datetime +import json +import logging +import sys +import traceback +import os + +import pandas as pd + +from utils import * +from decorators import handler_wrapper, timing + + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + + +def lambda_handler(event, context): + sc_obj = script_object(event) + lambda_response = sc_obj.starter() + logger.info(f'respuesta final de lambda: \n{lambda_response}') + return lambda_response + + +class script_object: + def __init__(self, event): + try: + self.failed_init = False + + logger.info('[__INIT__] Inicializando objeto lambda ...') + logger.info(f'event de entrada_ {str(event)}') + + + logger.warning(f'event de entrada: {str(event)}') + + self.puc_chapters = {'1':'Activo', '2':'Pasivo', '3':'Patrimonio', '4':'Ingresos', '5':'Gastos', '6':'Costos de venta', '7':'Costos de producción o de operación', '8':'Cuentas de orden deudoras', '9':'Cuentas de orden acreedoras'} + self.status_dict = {'No clasificado': False} + + + event_dict = event['pathParameters'] + + self.id_assessment = event_dict['id_assessment'] + + self.id_archive = event_dict.get('id_archive', False) + + self.db_connection = 0 + self.s3_client = 0 + + self.puc_chapters = {'1':'Activo', '2':'Pasivo', '3':'Patrimonio', '4':'Ingresos', '5':'Gastos', '6':'Costos de venta', '7':'Costos de producción o de operación', '8':'Cuentas de orden deudoras', '9':'Cuentas de orden acreedoras'} + + self.company_info = dict() + self.archive_data = dict() + self.company_has_model = False + + self.puc_data_on_db = pd.core.frame.DataFrame() + self.puc_data = pd.core.frame.DataFrame() + self.classified_df = pd.core.frame.DataFrame() + + self.df_classified_dict = dict() #este es el que viaja al front + + self.final_response = {'headers':{'Access-Control-Allow-Headers': '*', 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Methods': '*'}, 'statusCode': 200} + logger.info('[__INIT__] Objeto lambda inicializada exitosamente') + + except Exception as e: + + self.failed_init = True + logger.error(f"[__INIT__] error en inicializacion, linea: {get_especific_error_line()}, motivo: "+str(e)) + + + def starter(self): + try: + if self.failed_init: + raise AttributeError('Falla inicializacion, revisar logs') + self.create_clients() + self.get_company_info() + #self.get_archive_info() + self.get_puc_data() + self.setting_up_df() + self.check_company_model() + if not self.company_has_model: + self.get_classification_dict() + + self.classify_dataframe() + self.clean_df_to_front() + return self.response_maker(succesfull = True) + + except Exception as e: + logger.error(f'[starter] Error en el procesamieno del comando de la linea: {get_current_error_line()}, motivo: {e}') + return self.response_maker(succesfull = False, exception_str = str(e)) + + + @handler_wrapper('Creando clientes a servicios externos','Clientes a servicios construidos','Error construyendo conexiones a recursos externos','Problemas requiriendo recursos externos') + def create_clients(self): + db_schema = os.environ['DB_SCHEMA'] + secret_db_region = os.environ['SECRET_DB_REGION'] + secret_db_name = os.environ['SECRET_DB_NAME'] + db_secret = get_secret(secret_db_region, secret_db_name) + self.db_connection = connect_to_db(db_schema, db_secret) + self.s3_client = boto3.client('s3') + + + @handler_wrapper('Buscando id del nit recibido','El id del nit recibido fue encontrado','Error en la busqueda de los datos de la empresa','Error, problemas localizando la informacion de la empresa') + def get_company_info(self): + query = f"SELECT A.ID, A.NIT, A.SECTOR, C.ID_ARCHIVE, B.INITIAL_DATE FROM COMPANY A, ARCHIVE B, ASSESSMENT C WHERE A.ID = B.ID_COMPANY AND B.ID = C.ID_ARCHIVE AND C.ID = {self.id_assessment} LIMIT 1" + logger.info(f"Query a base de datos para obtener la informacion de la empresa: {query}") + rds_data = self.db_connection.execute(query) + self.assessment_info = [row._asdict() for row in rds_data.fetchall()][0] + self.initial_date_short = self.assessment_info['INITIAL_DATE'].strftime('%d-%m-%Y') + + + @handler_wrapper('Obteniendo la informacion chequeada del puc','Informacion de puc encontrada', 'Error al hacer query de los datos chequeados','Error al buscar los datos de puc') + def get_puc_data(self): + if self.id_archive: + query = f"SELECT ACCOUNT_NUMBER, CHECKED_BALANCE, ACCOUNT_NAME FROM ORIGINAL_PUC WHERE ID_ARCHIVE = {self.id_archive} ORDER BY ACCOUNT_NUMBER" + else: + query = f"SELECT ACCOUNT_NUMBER, CHECKED_BALANCE, ACCOUNT_NAME FROM ORIGINAL_PUC WHERE ID_ARCHIVE = {self.assessment_info['ID_ARCHIVE']} ORDER BY ACCOUNT_NUMBER" + logger.info(f"Query a base de datos para obtener la data del puc {query}") + self.puc_data_on_db = pd.read_sql(query, self.db_connection) + + + @handler_wrapper('Cambiando tipos de datos en las columnas','Configuracion de dataframe completado','Error en la preparación del dataframe','Error en la preparación del dataframe') + def setting_up_df(self): + self.puc_data = self.puc_data_on_db.copy() + self.puc_data.rename(columns={'ACCOUNT_NUMBER': 'account', 'ACCOUNT_NAME': 'name', 'CHECKED_BALANCE':'balance'}, inplace=True) + self.puc_data['nivel'] = self.puc_data['account'].str.len() + self.puc_data['initial_date'] = self.initial_date_short + self.puc_data = self.puc_data.astype({"account": "string", "name": "string", "balance": "float", "nivel":"int"}, copy=True) + + + @handler_wrapper('Chequeando si la empresa tiene un modelo de clasificación construído', 'Chequeo de modelo de clasificación previa terminado','Error chequeando si la empresa tiene un model de clasificación construído', 'Error chequeando si existe modelo de clasificación previo') + def check_company_model(self): + query = f"SELECT A.ACCOUNT_NUMBER, B.CLASSIFICATION FROM MODEL_USER_CLASSIFICATION A, RAW_CLASSIFICATION B WHERE A.ID_RAW_CLASSIFICATION = B.ID AND A.ID_COMPANY = {self.assessment_info['ID']} ORDER BY A.ACCOUNT_NUMBER" + logger.info(f"[check_company_model] Query a base de datos para obtener la data del puc {query}") + rds_data = self.db_connection.execute(query) + self.classification_list = rds_data.mappings().all() + logger.info(f'[check_company_model] Este fue el model encontrado para la empresa que se está valorando:\n{self.classification_list}') + if self.classification_list: + self.company_has_model = True + + + @handler_wrapper('Leyendo archivo de clasificacion','Archivo de clasificacion leído satisfactoriamente','No se pudo leer el archivo de clasificacion','Error en la generacion de archivo de clasificacion') + def get_classification_dict(self): + query = f"SELECT A.CLASSIFICATION, B.ACCOUNT_NUMBER FROM RAW_CLASSIFICATION A, DEFAULT_CLASSIFICATION B WHERE A.ID = B.ID_RAW_CLASSIFICATION AND SECTOR = \"{self.assessment_info['SECTOR']}\" ORDER BY 2" + logger.info(f"Query a base de datos para obtener la data del puc {query}") + rds_data = self.db_connection.execute(query) + self.classification_list = rds_data.mappings().all() + #logger.warning(f'Data obtenida del pedido de clasificaciones: {self.classification_list}') + + + @handler_wrapper('Empieza clasificacion','Dataframe clasificado satisfactoriamente','Error en la clasificacion del dataframe','No se pudo realizar la clasificacion') + def classify_dataframe(self): + self.classified_df = self.puc_data.copy() + for default_row in self.classification_list: + self.classified_df.loc[self.classified_df['account'].str.startswith(default_row['ACCOUNT_NUMBER']), 'classification'] = default_row['CLASSIFICATION'] + + + @handler_wrapper('Organizando dataframe para muestra en front','Dataframe organizado correctamente','Error organizando datos para muestra en front','Hubieron problemas preparando la informacion clasificada') + def clean_df_to_front(self): + #self.classified_df.fillna('No aplica', inplace=True) + self.classified_df.loc[self.classified_df['nivel'] == 1, 'classification' ] = 'No aplica' + self.classified_df.fillna(value={'classification': 'No clasificado'}, inplace = True) + #self.classified_df['status'] = + self.classified_df.loc[self.classified_df['classification'] == 'No clasificado', 'status' ] = False + self.classified_df.loc[self.classified_df['classification'] != 'No clasificado', 'status' ] = True + + self.classified_df.sort_values(by=['account'], inplace=True) + + self.classified_df['chapter'] = [self.puc_chapters[account_number[0]] for account_number in self.classified_df['account'].values.tolist() ] + + #self.classified_df.set_index('account', inplace=True) + self.df_classified_dict = self.classified_df.to_dict('records') + + + def response_maker(self, succesfull = False, exception_str = str()): + if self.db_connection: + self.db_connection.close() + if not succesfull: + self.final_response['body'] = json.dumps(exception_str) + return self.final_response + self.final_response['body'] = json.dumps([{'date': self.initial_date_short, 'data': self.df_classified_dict, 'sector':self.assessment_info['SECTOR'], 'archive_id': self.assessment_info['ID_ARCHIVE']}]) + return self.final_response + + +def get_current_error_line(): + return str(sys.exc_info()[-1].tb_lineno) + + +def get_especific_error_line(): + _, _, exc_tb = sys.exc_info() + return str(traceback.extract_tb(exc_tb)[-1][1]) + + + + + + +@handler_wrapper('Creando directorio','Directorio creado satisfactoriamente','Error en la creacion del directorio','No se pudo crear el directorio') +def create_directory(df_ready): + df_ready['nivel'] = df_ready['account'].map(len) + directory = {} + for cuenta in df_ready.loc[df_ready['nivel'] == 1, 'account']: + sons = get_sons_of(df_ready,cuenta) + directory[cuenta] = sons + + for son in sons: + grand_sons = get_sons_of(df_ready, son) + directory[son] = grand_sons + + return directory + + +def get_sons_of(df, cuenta): + current_level = len(cuenta) + lower_cat_df = df.loc[(df["nivel"] > current_level) & + (df["account"].str.startswith(cuenta))] + + if lower_cat_df.empty: + return {} + + lower_cat_niveles = list(lower_cat_df["nivel"].unique()) + lower_cat_niveles = sorted(lower_cat_niveles) + if len(lower_cat_niveles) > 1 and current_level ==1: #este es un bloqueador, como voy a poder abrir solo los ojos de nivel 1 y 2, al abrir el de 2 tiene que mostrarme todas las cuentas que sean hijas de esa cuenta de nivel 2 + lower_cat_df = lower_cat_df.loc[df["nivel"] == lower_cat_niveles[0]] + return sorted(lower_cat_df['account'].values) + \ No newline at end of file diff --git a/corporate_finances_back_py/initial-account-classification/utils.py b/corporate_finances_back_py/initial-account-classification/utils.py new file mode 100644 index 0000000..9efbdea --- /dev/null +++ b/corporate_finances_back_py/initial-account-classification/utils.py @@ -0,0 +1,33 @@ +#version 2023 - 05 - 04 +import base64 +import boto3 +import json +import logging + +from sqlalchemy import create_engine + +from decorators import handler_wrapper, debugger_wrapper + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + + +@debugger_wrapper('Error al obtener secreto','Error fatal de back conectando a base de datos') +def get_secret(secret_region, secret_name): + session = boto3.session.Session() + client_secrets_manager = session.client(service_name='secretsmanager', region_name=secret_region) + secret_data = client_secrets_manager.get_secret_value(SecretId=secret_name) + if 'SecretString' in secret_data: + secret_str = secret_data['SecretString'] + else: + secret_str = base64.b64decode(secret_data['SecretBinary']) + logger.info('[utils] (get_secret) Se obtuvo el secreto') + return json.loads(secret_str) + + +@debugger_wrapper('Error en la conexion a base de datos','Error fatal de back conectando a base de datos') +def connect_to_db(db_schema, db_secret): + conn_string = ('mysql+mysqlconnector://' + db_secret["username"] + ':' + db_secret["password"] + '@' + db_secret["host"] + ':' + str(db_secret["port"]) + '/' + db_schema) + sql_engine = create_engine(conn_string) + db_connection = sql_engine.connect() + return db_connection \ No newline at end of file diff --git a/corporate_finances_back_py/modal-projections-retrieve/decorators.py b/corporate_finances_back_py/modal-projections-retrieve/decorators.py new file mode 100644 index 0000000..071760a --- /dev/null +++ b/corporate_finances_back_py/modal-projections-retrieve/decorators.py @@ -0,0 +1,63 @@ +#version 2023 - 05 - 04 +import logging +import sys +import traceback +from functools import wraps +from time import time + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + +def handler_wrapper(start, satisfactory_log, error_log, raise_error): + #esto se ejecuta en la inicializacion de primero + def decorator(func): + #print(message1) + #lo que yo ponga acá se ejecuta antes de hacer el llamado a la funcion + @wraps(func) + def wrapper(*args, **kwargs): + #esto sí se ejecuta solo cuando llama a la funcion decorada + #print(message2) + try: + logger.info(f'[{func.__name__}] {start}...') + resultado = func(*args, **kwargs) + logger.info(f'[{func.__name__}] {satisfactory_log}') + return resultado + except Exception as e: + logger.error(f"[{func.__name__}] {error_log}, linea: {get_especific_error_line(func.__name__)}, motivo: {str(e)}") + raise Exception(f"{raise_error}") + + return wrapper + return decorator + +def debugger_wrapper(error_log, raise_error): + def decorator(func): + @wraps(func) + def wrapper(*args, **kwargs): + try: + resultado = func(*args, **kwargs) + return resultado + except Exception as e: + logger.error(f"[{func.__name__}] {error_log}, linea: {get_especific_error_line(func.__name__)}, motivo: {str(e)}") + raise Exception(f"{raise_error}") + return wrapper + return decorator + + +def get_especific_error_line(func_name): + _, _, exc_tb = sys.exc_info() + for trace in traceback.extract_tb(exc_tb): + if func_name in trace: + return str(trace[1]) + +def timing(f): + @wraps(f) + def wrap(*args, **kw): + ts = time() + result = f(*args, **kw) + te = time() + taken_time_message = '[timing] La funcion {}, toma: {:.2f} sec en ejecutarse'.format(f.__name__, te-ts) + logger.info(taken_time_message) + return result + return wrap + + diff --git a/corporate_finances_back_py/modal-projections-retrieve/lambda_function.py b/corporate_finances_back_py/modal-projections-retrieve/lambda_function.py new file mode 100644 index 0000000..86233d2 --- /dev/null +++ b/corporate_finances_back_py/modal-projections-retrieve/lambda_function.py @@ -0,0 +1,190 @@ +import json +import logging +import sys +import os + +from datetime import datetime +from sqlalchemy import text + +from decorators import handler_wrapper, timing, debugger_wrapper +from utils import get_secret, connect_to_db, connect_to_db_local_dev + +logging.basicConfig() +logging.basicConfig(format='%(asctime)s [%(levelname)s] [%(module)s] %(message)s', force=True, datefmt='%Y-%m-%d %H:%M:%S') +logger = logging.getLogger() +logger.setLevel(logging.INFO) + +def lambda_handler(event,context): + sc_obj = script_object(event) + lambda_response = sc_obj.starter() + logger.info(f'respuesta final de lambda: \n{lambda_response}') + return lambda_response + + +class script_object: + def __init__(self, event): + try: + self.failed_init = False + self.final_response = {'headers':{'Access-Control-Allow-Headers': '*', + 'Access-Control-Allow-Origin': '*', + 'Access-Control-Allow-Methods': '*'}, "statusCode": 500, 'body': {}} + self.db_connection = 0 + self.detailed_raise = '' + self.partial_response = list() + + logger.warning(f'event de entrada: {str(event)}') + self.id_assessment = event['queryStringParameters']['id_assessment'] + self.context = event['queryStringParameters']['context'] + + self.context_classifications = {'patrimony':['Aportes de capital social u otros','Cambios en el patrimonio'], + 'wk':['Capital de trabajo'], + 'other_projections':['Otros movimientos que no son salida ni entrada de efectivo no operativos','Otros movimientos que no son salida ni entrada de efectivo operativos','Otros movimientos netos de activos operativos que afecta el FCLO','Otros movimientos netos de activos operativos que afecta el FCLA'], + 'debt' : ['Deuda con costo financiero']} + + self.first_time_projecting_object = {'VS_ACCOUNT_NAME': 'Seleccione', 'PROJECTION_TYPE': 'Seleccione', 'COMMENT': ''} + + self.historic_dates = list() + self.projection_dates = list() + self.proy_years = int() + self.projected_items = list() + self.organized_projected_items = list() + + + except Exception as e: + logger.error(f'[__init__] Error inicializando objeto lambda, linea: {get_current_error_line()}, motivo: {str(e)}') + self.failed_init = True + + def starter(self): + try: + if self.failed_init: + raise AttributeError('Error con los datos recibidos al servicio') + self.create_conection_to_db() + self.get_assessment_dates() + self.get_historic_data() + self.get_projection_data() + self.organize_atributes() + self.organize_projected_items() + self.organize_partial_response() + return self.response_maker(succesfull = True) + + except Exception as e: + logger.error(f'[starter] Hubieron problemas en el comando de la linea: {get_current_error_line()}') + return self.response_maker(succesfull = False, error_str = (str(e))) + + @handler_wrapper('Creando conexion a bd','Conexion a bd creada con exito','Error en la conexion a bd','Problemas creando la conexion a bd') + def create_conection_to_db(self): + if __name__ != 'lambda_function': + self.db_connection = connect_to_db_local_dev() + self.db_connection.begin() + return + db_schema = os.environ['DB_SCHEMA'] + secret_db_region = os.environ['SECRET_DB_REGION'] + secret_db_name = os.environ['SECRET_DB_NAME'] + db_secret = get_secret(secret_db_region, secret_db_name) + self.db_connection = connect_to_db(db_schema, db_secret) + + + @handler_wrapper('Obteniendo fechas de proyeccion del proceso de valoración', 'Fechas de proyeccion del proceso de valoración obtenidas con exito','Error adquiriendo fechas de proyeccion del proceso de valoración', 'Error adquiriendo fechas de proyeccion') + def get_assessment_dates(self): + query = f"SELECT DATES, PROPERTY FROM ASSESSMENT_DATES WHERE ID_ASSESSMENT = {self.id_assessment} ORDER BY DATES" + logger.info(f"[get_projection_dates] Query a base de datos para obtener las fechas utilizadas en el proceso de valoración:\n {query}") + rds_data = self.db_connection.execute(text(query)) + directory = {'HISTORIC': self.historic_dates, 'PROJECTION': self.projection_dates} + for date_item in rds_data.fetchall(): + directory.get(date_item.PROPERTY, []).append(date_item.DATES) + + self.historic_dates = [date.strftime('%d-%m-%Y') for date in self.historic_dates] + self.projection_dates = [date.strftime('%Y') for date in self.projection_dates] #'%Y-%m-%d %H:%M:%S' + + self.projection_dates[0] = f'Diciembre {self.projection_dates[0]}' if self.projection_dates[0] in self.historic_dates[-1] else self.projection_dates[0] + self.proy_years = len(self.projection_dates) # if '-12-' in self.historic_dates[-1] else len(self.projection_dates) - 1 #quitar el comentario si no llegan los years que son a front + + logger.info(f'[get_assessment_dates] Fechas del proceso de valoración:\nhistoricas: {self.historic_dates}\nproyecciones: {self.projection_dates}') + + + @handler_wrapper('Obteniendo datos de puc purgados','Datos de puc obtenidos','Error obteniendo datos de puc','Error al buscar datos de puc purgados') + def get_historic_data(self): + query = f"""SELECT A.ACCOUNT_NUMBER, A.ANNUALIZED, C.CLASSIFICATION, A.ACCOUNT_NAME FROM ASSESSMENT_CHECKED A, ARCHIVE B, RAW_CLASSIFICATION C +WHERE A.ID_ARCHIVE = B.ID AND A.ID_RAW_CLASSIFICATION = C.ID AND A.ID_ASSESSMENT = :id_assessment ORDER BY B.INITIAL_DATE, A.ACCOUNT_NUMBER;""" + + logger.info(f"[get_historic_data] Query a base de datos para obtener los datos proyectados:\n {query}") + rds_data = self.db_connection.execute(text(query), {'id_assessment': self.id_assessment}) + self.historic_data = [item._asdict() for item in rds_data.fetchall()] + for row in self.historic_data: + row['ANNUALIZED'] = float(row['ANNUALIZED']) + + logger.info(f'[get_historic_data] Datos historicos de cuentas:\n{self.historic_data}') + + + @handler_wrapper('Obteniendo datos de puc purgados','Datos de puc obtenidos','Error obteniendo datos de puc','Error al buscar datos de puc purgados') + def get_projection_data(self): + query = f"""SELECT A.ACCOUNT_NUMBER, A.VS_ACCOUNT_NAME, A.PROJECTION_TYPE, A.`COMMENT`, B.ATRIBUTE +FROM MODAL_WINDOWS A, MODAL_WINDOWS_PROJECTED B WHERE A.CONTEXT_WINDOW = B.CONTEXT_WINDOW +AND A.ACCOUNT_NUMBER = B.ACCOUNT_NUMBER AND A.ID_ASSESSMENT = B.ID_ASSESSMENT +AND A.ID_ASSESSMENT = :id_assessment AND A.CONTEXT_WINDOW = :context ORDER BY B.PROJECTED_DATE, A.ACCOUNT_NUMBER""" + + logger.info(f"[get_projection_data] Query a base de datos para obtener los datos proyectados:\n {query}") + rds_data = self.db_connection.execute(text(query), {'id_assessment': self.id_assessment, 'context':self.context}) + self.projected_items = [item._asdict() for item in rds_data.fetchall()] + logger.info(f'[get_projection_data] Datos de proyeccion:\n{self.projected_items}') + + + @handler_wrapper('Organizando atributos de cuentas', 'Atributos de cuentas organizados con exito', 'Error organizando atributos de cuentas', 'Error organizando atributos') + def organize_atributes(self): + current_context_clasifications = self.context_classifications[self.context] + self.context_accounts = sorted(set(row['ACCOUNT_NUMBER'] for row in self.historic_data if row['CLASSIFICATION'] in current_context_clasifications)) #con este tengo mi array de cuentas + self.atributes_dict = {account: {'history': list(), 'projection': list()} for account in self.context_accounts} + for account in self.context_accounts: + self.atributes_dict[account]['history'] = [row['ANNUALIZED'] for row in self.historic_data if row['ACCOUNT_NUMBER'] == account] + projection_vector = [row['ATRIBUTE'] for row in self.projected_items if row['ACCOUNT_NUMBER'] == account] + if not projection_vector: + projection_vector = [''] * self.proy_years + self.atributes_dict[account]['projection'] = projection_vector + + + @handler_wrapper('Eliminando datos innecesarios de los objetos en el pool', 'Objetos pool limpiados con exito', 'Error limpiando objetos del pool', 'Error creando pool') + def organize_projected_items(self): + for account in self.context_accounts: + account_name = next(item for item in self.historic_data if item['ACCOUNT_NUMBER'] == account)['ACCOUNT_NAME'] + proy_info = next((item for item in self.projected_items if item['ACCOUNT_NUMBER'] == account), self.first_time_projecting_object) + self.organized_projected_items.append({'name': account_name, + 'account': account, + 'accountProjector': proy_info['VS_ACCOUNT_NAME'], + 'atributes': self.atributes_dict[account], + 'explication': proy_info['COMMENT'], + 'method': proy_info['PROJECTION_TYPE']}) + + + + + @handler_wrapper('Organizando respuesta final', 'Respuesta final organizada con exito', 'Error organizando respeusta final', 'Error creando respesta final') + def organize_partial_response(self): + self.partial_response = {'datesProjections': self.projection_dates, + 'datesHistory': self.historic_dates, + 'year': self.proy_years, + 'projection_data': self.organized_projected_items, + 'context': self.context, + 'id_assessment': self.id_assessment + } + + + def response_maker(self, succesfull=False, error_str=""): + if self.db_connection: + self.db_connection.close() + if not succesfull: + self.final_response["body"] = json.dumps(self.detailed_raise if self.detailed_raise else error_str) + else: + self.final_response["statusCode"] = 200 + self.final_response["body"] = json.dumps(self.partial_response) + return self.final_response + + +def get_current_error_line(): + return str(sys.exc_info()[-1].tb_lineno) + +if __name__ == "__main__": + event = {"queryStringParameters": {"id_assessment": "2064", "context": "wk"}} + lambda_handler(event, '') + + + \ No newline at end of file diff --git a/corporate_finances_back_py/modal-projections-retrieve/utils.py b/corporate_finances_back_py/modal-projections-retrieve/utils.py new file mode 100644 index 0000000..36d6abe --- /dev/null +++ b/corporate_finances_back_py/modal-projections-retrieve/utils.py @@ -0,0 +1,43 @@ +#version 2023 - 05 - 04 +import base64 +import boto3 +import json +import logging +import os + +from sqlalchemy import create_engine +from decorators import handler_wrapper, debugger_wrapper + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + + +@debugger_wrapper('Error al obtener secreto','Error fatal de back conectando a base de datos') +def get_secret(secret_region, secret_name): + session = boto3.session.Session() + client_secrets_manager = session.client(service_name='secretsmanager', region_name=secret_region) + secret_data = client_secrets_manager.get_secret_value(SecretId=secret_name) + if 'SecretString' in secret_data: + secret_str = secret_data['SecretString'] + else: + secret_str = base64.b64decode(secret_data['SecretBinary']) + logger.info('[utils] (get_secret) Se obtuvo el secreto') + return json.loads(secret_str) + + +@debugger_wrapper('Error en la conexion a base de datos','Error fatal de back conectando a base de datos') +def connect_to_db(db_schema, db_secret): + conn_string = ('mysql+mysqlconnector://' + db_secret["username"] + ':' + db_secret["password"] + '@' + db_secret["host"] + ':' + str(db_secret["port"]) + '/' + db_schema) + sql_engine = create_engine(conn_string) + db_connection = sql_engine.connect() + return db_connection + + +@debugger_wrapper('Error en la conexion a base de datos','Error fatal de back conectando a base de datos') +def connect_to_db_local_dev(): + from dotenv import load_dotenv + load_dotenv() + conn_string = os.environ['local_dev_connector'] + sql_engine = create_engine(conn_string) + db_connection = sql_engine.connect() + return db_connection diff --git a/corporate_finances_back_py/modal-summary/decorators.py b/corporate_finances_back_py/modal-summary/decorators.py new file mode 100644 index 0000000..071760a --- /dev/null +++ b/corporate_finances_back_py/modal-summary/decorators.py @@ -0,0 +1,63 @@ +#version 2023 - 05 - 04 +import logging +import sys +import traceback +from functools import wraps +from time import time + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + +def handler_wrapper(start, satisfactory_log, error_log, raise_error): + #esto se ejecuta en la inicializacion de primero + def decorator(func): + #print(message1) + #lo que yo ponga acá se ejecuta antes de hacer el llamado a la funcion + @wraps(func) + def wrapper(*args, **kwargs): + #esto sí se ejecuta solo cuando llama a la funcion decorada + #print(message2) + try: + logger.info(f'[{func.__name__}] {start}...') + resultado = func(*args, **kwargs) + logger.info(f'[{func.__name__}] {satisfactory_log}') + return resultado + except Exception as e: + logger.error(f"[{func.__name__}] {error_log}, linea: {get_especific_error_line(func.__name__)}, motivo: {str(e)}") + raise Exception(f"{raise_error}") + + return wrapper + return decorator + +def debugger_wrapper(error_log, raise_error): + def decorator(func): + @wraps(func) + def wrapper(*args, **kwargs): + try: + resultado = func(*args, **kwargs) + return resultado + except Exception as e: + logger.error(f"[{func.__name__}] {error_log}, linea: {get_especific_error_line(func.__name__)}, motivo: {str(e)}") + raise Exception(f"{raise_error}") + return wrapper + return decorator + + +def get_especific_error_line(func_name): + _, _, exc_tb = sys.exc_info() + for trace in traceback.extract_tb(exc_tb): + if func_name in trace: + return str(trace[1]) + +def timing(f): + @wraps(f) + def wrap(*args, **kw): + ts = time() + result = f(*args, **kw) + te = time() + taken_time_message = '[timing] La funcion {}, toma: {:.2f} sec en ejecutarse'.format(f.__name__, te-ts) + logger.info(taken_time_message) + return result + return wrap + + diff --git a/corporate_finances_back_py/modal-summary/lambda_function.py b/corporate_finances_back_py/modal-summary/lambda_function.py new file mode 100644 index 0000000..6e9a55d --- /dev/null +++ b/corporate_finances_back_py/modal-summary/lambda_function.py @@ -0,0 +1,410 @@ +#Este servicio debo cambiarlo de nombre + +import json +import logging +import sys +import os +import boto3 +import pandas as pd +from datetime import datetime + +from decorators import handler_wrapper, timing, debugger_wrapper +from utils import get_secret, connect_to_db, call_dynamic_engine + + +#logging.basicConfig() #En lambdas borra este + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + + +def lambda_handler(event,context): + sc_obj = script_object(event) + lambda_response = sc_obj.starter() + logger.info(f'respuesta final de lambda: \n{lambda_response}') + return lambda_response + + +class script_object: + def __init__(self, event): + try: + self.failed_init = False + self.final_response = {'headers':{'Access-Control-Allow-Headers': '*', + 'Access-Control-Allow-Origin': '*', + 'Access-Control-Allow-Methods': '*'}, "statusCode": 500, 'body': {}} + self.db_connection = 0 + self.detailed_raise = '' + self.partial_response = list() + + logger.warning(f'event de entrada: {str(event)}') + self.id_assessment = event['queryStringParameters']['id_assessment'] + self.context = event['queryStringParameters']['context'] + + self.puc_chapters = {'1':'Activo', '2':'Pasivo', '3':'Patrimonio', '4':'Ingresos', '5':'Gastos', '6':'Costos de venta', '7':'Costos de producción o de operación', '8':'Cuentas de orden deudoras', '9':'Cuentas de orden acreedoras'} + self.context_table_dict = {'patrimony': 'PATRIMONY_RESULTS', 'other_projections': 'OTHER_MODAL_RESULTS', 'wk': 'WK_RESULTS'} + + self.historic_dates = list() + self.projection_dates = list() + self.assessment_dates_long = list() + self.total_asssessment_dates = 0 + self.accounts_projected = list() + self.account_numbers = list() + self.found_classifications = list() + + self.classification_vector = dict() + + #wk: + self.total_actives = list() + self.total_pasives = list() + self.total_directory = {'1': self.total_actives, '2': self.total_pasives} + self.data_items = list() + self.wk_results = list() + self.wk_variation = list() + + #pat + self.social_capital_items = list() + self.pat_changes_items = list() + self.classification_summary_vector = dict() + self.social_capital_contributions = list() + self.cash_dividends = list() + self.net_utility_values = list() + + #op + self.total_directory = {'1': self.total_actives, '2': self.total_pasives} + + + + + except Exception as e: + logger.error(f'[__init__] Error inicializando objeto lambda, linea: {get_current_error_line()}, motivo: {str(e)}') + self.failed_init = True + + def starter(self): + try: + if self.failed_init: + raise AttributeError('Error con los datos recibidos al servicio') + self.create_conection_to_db() + self.get_assessment_dates() + self.get_historic_values() + self.get_projection_values() + self.organize_data_items() + self.organize_classifications_summary() + if self.context == "wk": + self.wk_calculate_yearly_totals() + self.wk_organize_partial_response() + self.wk_organize_to_db() + + if self.context == "patrimony": + self.pat_classification_summary_builder() + self.pat_call_pyg_service() + self.pat_calculate_totals() + self.pat_organize_partial_response() + self.pat_organize_to_db() + + if self.context == "other_projections": + self.op_calculate_yearly_totals() + self.op_organize_partial_response() + self.op_organize_to_db() + self.delete_previous_results() + self.send_summary_to_bd() + + call_dynamic_engine(self.id_assessment) + + return self.response_maker(succesfull_run = True) + + except Exception as e: + logger.error(f'[starter] Hubieron problemas en el comando de la linea: {get_current_error_line()}') + return self.response_maker(succesfull_run = False, error_str = (str(e))) + + @handler_wrapper('Creando conexion a bd','Conexion a bd creada con exito','Error en la conexion a bd','Problemas creando la conexion a bd') + def create_conection_to_db(self): + db_schema = os.environ['DB_SCHEMA'] + secret_db_region = os.environ['SECRET_DB_REGION'] + secret_db_name = os.environ['SECRET_DB_NAME'] + db_secret = get_secret(secret_db_region, secret_db_name) + self.db_connection = connect_to_db(db_schema, db_secret) + + @handler_wrapper('Obteniendo las fechas del proceso de valoración', 'Fechas del proceso de valroación obtenidas con exito', 'Error obteniendo las fechas del proceso de valoración', 'Error obteniendo fechas del proceso de valoración') + def get_assessment_dates(self): + query = f"SELECT DATES, PROPERTY FROM ASSESSMENT_DATES WHERE ID_ASSESSMENT = {self.id_assessment} ORDER BY DATES" + logger.info(f"[get_assessment_dates] Query a base de datos para obtener las fechas utilizadas en el proces de valoración:\n {query}") + rds_data = self.db_connection.execute(query) + directory = {'HISTORIC': self.historic_dates, 'PROJECTION': self.projection_dates} + for date_item in rds_data.fetchall(): + self.assessment_dates_long.append(date_item.DATES.strftime('%Y-%m-%d %H:%M:%S')) + directory.get(date_item.PROPERTY, []).append(date_item.DATES) + self.total_asssessment_dates = self.total_asssessment_dates +1 + + logger.info(f'[get_assessment_dates] Fechas del proceso de valoración:\nhistoricas: {self.historic_dates}\nproyecciones: {self.projection_dates}') + + + @handler_wrapper('Obteniendo datos de puc purgados','Datos de puc obtenidos','Error obteniendo datos de puc','Error al buscar datos de puc purgados') + def get_historic_values(self): + + query = f"""SELECT A.ACCOUNT_NUMBER AS account, B.ANNUALIZED AS value, D.CLASSIFICATION, B.ACCOUNT_NAME +FROM MODAL_WINDOWS A, ASSESSMENT_CHECKED B, ARCHIVE C, RAW_CLASSIFICATION D +WHERE A.ID_ASSESSMENT = B.ID_ASSESSMENT AND A.ACCOUNT_NUMBER = B.ACCOUNT_NUMBER AND B.ID_ARCHIVE = C.ID AND B.ID_RAW_CLASSIFICATION = D.ID +AND A.CONTEXT_WINDOW = "{self.context}" AND A.ID_ASSESSMENT = {self.id_assessment} ORDER BY C.INITIAL_DATE, account""" + + logger.info(f"[get_historic_values] Query a base de datos para obtener los datos de puc historicos calculados:\n{query}") + rds_data = self.db_connection.execute(query) + + self.historic_values = [item._asdict() for item in rds_data.fetchall()] + logger.info(f'[get_historic_values] Datos historicos de las cuentas usadas en la ventana modal:\n{self.historic_values}') + + for item in self.historic_values: + item['value'] = float(item['value']) + item['chapter'] = self.puc_chapters.get(item['account'][0], 'Capitulo no encontrado') + if item['account'] not in self.accounts_projected: + self.accounts_projected.append(item['account']) + if item['CLASSIFICATION'] not in self.found_classifications: + self.found_classifications.append(item['CLASSIFICATION']) + + logger.warning(f'[get_historic_values] datos de cuentas post procesamiento inicial:\n{self.historic_values}') + + + @handler_wrapper('Obteniendo proyecciones de la ventana modal', 'Proyecciones de la ventana modal obtenidas con exito', 'Error obteniendo proyecciones de la ventana modal', 'Error obteniendo proyecciones') + def get_projection_values(self): + query = f"""SELECT A.PROJECTED_DATE, A.ACCOUNT_NUMBER AS account, C.CLASSIFICATION, A.VALUE AS value +FROM MODAL_WINDOWS_PROJECTED A, ASSESSMENT_CHECKED B, RAW_CLASSIFICATION C, ASSESSMENT D +WHERE A.ACCOUNT_NUMBER = B.ACCOUNT_NUMBER AND B.ID_RAW_CLASSIFICATION = C.ID AND B.ID_ARCHIVE = D.ID_ARCHIVE +AND A.ID_ASSESSMENT = B.ID_ASSESSMENT AND A.ID_ASSESSMENT = D.ID +AND A.ID_ASSESSMENT = {self.id_assessment} AND CONTEXT_WINDOW = "{self.context}" ORDER BY PROJECTED_DATE""" + + logger.info(f"[get_projection_values] Query a base de datos para obtener los datos de proyectados de la ventana modal:\n{query}") + rds_data = self.db_connection.execute(query) + + self.projection_values = [item._asdict() for item in rds_data.fetchall()] + logger.info(f'[get_projection_values] Datos proyectados de las cuentas usadas en la ventana modal:\n{self.projection_values}') + + for item in self.projection_values: + item['value'] = float(item['value']) + item['chapter'] = self.puc_chapters.get(item['account'][0], 'Capitulo no encontrado') + + logger.warning(f'[get_projection_values] datos de cuentas post procesamiento inicial:\n{self.projection_values}') + + + @handler_wrapper('Organizando array de items proyectados', 'Array de items proyectado organizado con exito', 'Error organizando array de items proyectado', 'Error organizando pool de items proyectados') + def organize_data_items(self): + for account in self.accounts_projected: + #logger.info(f'[mira aca] buscando {account} en {self.historic_values}') + account_name = [item['ACCOUNT_NAME'] for item in self.historic_values if item['account'] == account][-1] + historic_values = [item['value'] for item in self.historic_values if item['account'] == account] + projection_values = [item['value'] for item in self.projection_values if item['account'] == account] + this_account_values_list = historic_values + projection_values + self.total_directory.get(account[0], []).append(this_account_values_list) + self.data_items.append({'name': account_name, 'values': {'history': historic_values, 'projections': projection_values}}) + + + @handler_wrapper('Calculando vectores de totales por clasificación', 'Vectores de totales calculados con exito', 'Error calculando vectores de totales por clasificacion', 'Error calculando summaries de clasificaciones') + def organize_classifications_summary(self): + for classification in self.found_classifications: + classifications_account_len = len(set(item['account'] for item in self.historic_values if item['CLASSIFICATION'] == classification)) + historic_classification_items = [item['value'] for item in self.historic_values if item['CLASSIFICATION'] == classification] + projection_classification_items = [item['value'] for item in self.projection_values if item['CLASSIFICATION'] == classification] + logger.warning(f'[mira aca] estos deberían ser vectores completos:\nhistoricos:{historic_classification_items}\nproyecciones{projection_classification_items}') + self.classification_vector[classification] = [sum(historic_classification_items[i:i + classifications_account_len]) for i in range(0, len(historic_classification_items), classifications_account_len) ] + + logger.info(f'[organize_classifications_summary] vector de summary de la clasificacion {classification} antes de meter proyecciones:\n{self.classification_vector[classification]}') + + self.classification_vector[classification].extend([sum(projection_classification_items[i:i + classifications_account_len]) for i in range(0, len(projection_classification_items), classifications_account_len) ]) + logger.info(f'[organize_classifications_summary] vector de summary de la clasificacion {classification} despues de meter proyecciones:\n{self.classification_vector[classification]}') + logger.info(f'[organize_classifications_summary] vector de summary de la clasificacion {classification}{self.classification_vector[classification]}\nDesde los datos historicos:\n{self.historic_values}\nY los datos de proyeccion:\n{self.projection_values} ') + + + #working capital + @handler_wrapper('Realizando los totales de activos y pasivos para cada año', 'Totales de activos y pasivos realizado con exito', 'Error calculando totales de cada año', 'Error calculando totales de resumen') + def wk_calculate_yearly_totals(self): + logger.info(f'[mira acaA]: activos: {len(self.total_actives)} pasivos: {len(self.total_pasives)}') + if not self.total_actives: + self.total_actives = [[0]* self.total_asssessment_dates] + #estos dos es por si acaso no hay cuentas de capitulos 1 o 2 + if not self.total_pasives: + self.total_pasives = [[0]* self.total_asssessment_dates] + + logger.info(f'[mira acaB]: {self.total_actives}') + self.total_actives = [sum(year_data) for year_data in zip(*self.total_actives)] + self.total_pasives = [sum(year_data) for year_data in zip(*self.total_pasives)] + + self.wk_results = [i-j for i,j in zip(self.total_actives, self.total_pasives)] + self.wk_variation.append(0) + + for previous_index, year_result in enumerate(self.wk_results[1:]): + self.wk_variation.append(year_result - self.wk_results[previous_index]) + + + @handler_wrapper('Organizando respuesta final', 'Respuesta final organizada con exito', 'Error organizando respeusta final', 'Error creando respesta final') + def wk_organize_partial_response(self): + self.historic_dates_short = [date.strftime('%d-%m-%Y') for date in self.historic_dates] + self.projection_dates_short = [date.strftime('%Y') for date in self.projection_dates] + self.projection_dates_short[0] = self.projection_dates_short[0] if '-12-' in self.historic_dates_short[-1] else f'Diciembre {self.projection_dates_short[0]}' + self.partial_response = {'datesHistory': self.historic_dates_short, + 'datesProjections': self.projection_dates_short, + 'data': self.data_items, + 'actives': self.total_actives, + 'pasives': self.total_pasives, + 'workingCapital': self.wk_results, + 'variationWorkingCapital': self.wk_variation} + + @handler_wrapper(f'Organizando los records de capital de trabajo que se llevarán a flujo de caja', 'Records de capital de trabajo organizados', 'Error creando los Records de capital de trabajo', 'Error creando resultados a bd') + def wk_organize_to_db(self): + self.records_to_bd = [{'SUMMARY_DATE': i, 'WK_VARIATION': j} for i,j in zip(self.assessment_dates_long, self.wk_variation)] + + #working capital + + #patrimony + @handler_wrapper('Separando clasificaciones de patrimonio', 'Separado de clasificaciones de patrimonio terminada', 'Error separando clasificaciones de patrimonio', 'Error procesando patrimonio') + def pat_classification_summary_builder(self): + + for classification in ['Aportes de capital social u otros', 'Cambios en el patrimonio']: + historic_items = [item for item in self.historic_values if item['CLASSIFICATION'] == classification] + accounts = set(item['account'] for item in historic_items) + if accounts: + historic_values = [item['value'] for item in historic_items] + self.classification_summary_vector[classification] = [sum(historic_values[i:i + len(accounts)]) for i in range(0, len(historic_values),len(accounts)) ] + self.add_proyections_results(accounts, classification) + else: + self.classification_summary_vector[classification] = [0] * (len(self.historic_dates) + len(self.projection_dates)) + logger.info(f'[pat_classification_summary_builder] los items:\n{historic_items}\nSumados año a año resultaron en:\n{self.classification_summary_vector[classification]}') + logger.warning(f'[pat_classification_summary_builder]Resultados de las clasificaciones sumadas año a año:\n{self.classification_summary_vector}') + + + @debugger_wrapper('Error agregando proyecciones a una clasificación', 'Error agregando proyecciones de clasificacion') + def add_proyections_results(self, accounts, classification): + logger.info(f'[add_proyections_results] de este listado voy a buscar los accounts:\n{self.projection_values}') + projection_items = [item for item in self.projection_values if item['account'] in accounts] + projection_values = [item['value'] for item in projection_items] + projections_sum_values = [sum(projection_values[i:i + len(accounts)]) for i in range(0, len(projection_values),len(accounts)) ] + self.classification_summary_vector[classification].extend(projections_sum_values) + + + @handler_wrapper('Iniciando llamada al servicio calculador de pyg', 'Llamada a calculador de pyg terminada', 'Error llamando al servicio calculador de pyg', 'Error recalculando pyg') + def pat_call_pyg_service(self): + data_obj = {"pathParameters": {"id_assessment": self.id_assessment}} + logger.info(f'[pat_call_pyg_service] Data_obj que se le dispara al pyg retrieve') + data = json.dumps(data_obj).encode() + #session = boto3.session.Session() + #lambda_client = session.client('lambda') + lambda_client = boto3.client('lambda') + lambda_slave_pyg_retrieve = os.environ['LAMBDA_SLAVE_FINANZAS_PYG_RETRIEVE'] + + invoke_response = lambda_client.invoke(FunctionName=lambda_slave_pyg_retrieve, Payload = data) + + response_object = json.loads(json.loads(invoke_response['Payload'].read().decode())['body']) + logger.info(f'[pat_call_pyg_service] objeto de respuesta de la lambda slave:\n{response_object}') + net_utility_item = next(item for item in response_object['data'] if item['name'] == 'Utilidad neta') + #self.net_utility_historic_values = [item['value'] for item in net_utility_item['values']['history']] + #self.net_utility_projected_values = [item['value'] for item in net_utility_item['values']['projection']] + net_utility_vector = net_utility_item['values']['history'] + net_utility_item['values']['projection'] + self.net_utility_values = [item['value'] for item in net_utility_vector] + + + @handler_wrapper('Calculando totales de patrimonio', 'Totales de patrimonio calculados con exito', 'Error calculando totales de patrimonio', 'Error calculando totales de patrimonio') + def pat_calculate_totals(self): + self.social_capital_contributions.append(0) + for index, value in enumerate(self.classification_summary_vector['Aportes de capital social u otros'][1:], start = 1): + self.social_capital_contributions.append(value- self.classification_summary_vector['Aportes de capital social u otros'][index-1]) + + self.cash_dividends.append(self.classification_summary_vector['Cambios en el patrimonio'][0] * -1) + for index, value in enumerate(self.classification_summary_vector['Cambios en el patrimonio'][1:], start = 1): + self.cash_dividends.append(self.net_utility_values[index-1] - value + self.classification_summary_vector['Cambios en el patrimonio'][index-1]) + + + @handler_wrapper('Organizando objeto final de patrimonio', 'Objeto final de patrimonio organizado con exito', 'Error organizando objeto final de patrimonio', 'Error organizando respuesta final de patrimonio') + def pat_organize_partial_response(self): + self.historic_dates_short = [date.strftime('%d-%m-%Y') for date in self.historic_dates] + self.projection_dates_short = [date.strftime('%Y') for date in self.projection_dates] + self.projection_dates_short[0] = self.projection_dates_short[0] if '-12-' in self.historic_dates_short[-1] else f'Diciembre {self.projection_dates_short[0]}' + self.partial_response = {'datesHistory': self.historic_dates_short, + 'datesProjections': self.projection_dates_short, + 'data': self.data_items, + 'socialCapitalContributions': self.social_capital_contributions, + 'cashDividends': self.cash_dividends} + + @handler_wrapper(f'Organizando los records de patrimonio que se llevarán a flujo de caja', 'Records de patrimonio organizados', 'Error creando los Records de patrimonio', 'Error creando resultados a bd') + def pat_organize_to_db(self): + logger.info(f'[mira aca] SUMMARY_DATE: {self.assessment_dates_long}, SOCIAL_CONTRIBUTIONS: {self.social_capital_contributions}, CASH_DIVIDENDS: {self.cash_dividends} ') + self.records_to_bd = [{'SUMMARY_DATE': i, 'SOCIAL_CONTRIBUTIONS': j, 'CASH_DIVIDENDS': k} for i,j,k in zip(self.assessment_dates_long, self.social_capital_contributions, self.cash_dividends)] + + + + #patrimonio + + #otras proyecciones + @handler_wrapper('Calculando totales de otras proyecciones', 'Totales calculados con exito', 'Error calculando totales de otras proyecciones', 'Error calculando totales') + def op_calculate_yearly_totals(self): + #TODO: QUEDÉ ACA: debo sacar el total para la ventana modal de ortas proyecciones + logger.info(f'[op_calculate_yearly_totals]Summaries de proyecciones encontrados:\n{self.classification_vector}') + self.operating_cash = self.classification_vector.get('Otros movimientos que no son salida ni entrada de efectivo operativos', [0]*self.total_asssessment_dates) + self.operating_cash_variation = [item - self.operating_cash[index -1] for index, item in enumerate(self.operating_cash[1:], start = 1)] + self.operating_cash_variation.insert(0, 0) + + self.fclo = self.classification_vector.get('Otros movimientos netos de activos operativos que afecta el FCLO', [0]*self.total_asssessment_dates) + self.fclo_variation = [item - self.fclo[index -1] for index, item in enumerate(self.fclo[1:], start = 1)] + self.fclo_variation.insert(0, 0) + + self.fcla = self.classification_vector.get('Otros movimientos netos de activos operativos que afecta el FCLA', [0]*self.total_asssessment_dates) + self.fcla_variation = [item - self.fcla[index -1] for index, item in enumerate(self.fcla[1:], start = 1)] + self.fcla_variation.insert(0, 0) + + logger.info(f'[mira aca]\n{self.operating_cash}\ncon variacion:\n{self.operating_cash_variation}') + + + @handler_wrapper('Organizando objeto final de otras proyecciones', 'Objeto final de otras proyecciones organizado con exito', 'Error organizando objeto final de otras proyecciones', 'Error organizando respuesta final de otras proyecciones') + def op_organize_partial_response(self): + self.historic_dates_short = [date.strftime('%d-%m-%Y') for date in self.historic_dates] + self.projection_dates_short = [date.strftime('%Y') for date in self.projection_dates] + self.projection_dates_short[0] = self.projection_dates_short[0] if '-12-' in self.historic_dates_short[-1] else f'Diciembre {self.projection_dates_short[0]}' + self.partial_response = {'datesHistory': self.historic_dates_short, + 'datesProjections': self.projection_dates_short, + 'data': self.data_items, + 'operatingCashInflow': self.operating_cash, + 'variationOperatingCashInflow': self.operating_cash_variation, + 'fclo' : self.fclo, + 'variationFclo' : self.fclo_variation, + 'fcla' : self.fcla, + 'variationFcla' : self.fcla_variation} + + + @handler_wrapper(f'Organizando los records de otras proyecciones que se llevarán a flujo de caja', 'Records de otras proyecciones organizados', 'Error creando los Records de otras proyecciones', 'Error creando resultados a bd') + def op_organize_to_db(self): + self.records_to_bd = [{'SUMMARY_DATE': i, 'OTHER_OPERATIVE_MOVEMENTS': j, 'FCLO': k, 'FCLA': l} for i,j,k,l in zip(self.assessment_dates_long, self.operating_cash_variation, self.fclo_variation, self.fcla_variation)] + + #otras proyecciones + + @handler_wrapper('Eliminando anteriores resultados de la ventana modal', 'Borrado de datos anteriores exitosos', 'Error intentando borrar datos anteriores de ventana modal', 'Error sobreescribiendo datos en bd') + def delete_previous_results(self): + query = f"DELETE FROM {self.context_table_dict[self.context]} WHERE ID_ASSESSMENT = {self.id_assessment}" + logger.warning(f'[delete_previous_results] Query para eliminar datos anteriores de la tabla {self.context_table_dict[self.context]}:\n{query}') + self.db_connection.execute(query) + + + @handler_wrapper('Enviando resultados a bd', 'Envío de resultados a bd exitoso', 'Problemas enviando resultados a bd', 'Error enviando resultados a bd') + def send_summary_to_bd(self): + try: #TODO: quitar este try cuando haya guardado working capital y otras proyecciones + dataframe_to_bd = pd.DataFrame.from_records(self.records_to_bd) + dataframe_to_bd['ID_ASSESSMENT'] = self.id_assessment + logger.warning(f'[send_summary_to_bd] Se cargará la sgte información a la tabla {self.context_table_dict[self.context]}:\n{dataframe_to_bd.to_string()}') + dataframe_to_bd.to_sql(name = self.context_table_dict[self.context], con=self.db_connection, if_exists='append', index=False) + except Exception as e: + logger.error(f'[send_summary_to_bd] Error enviando a bd: {str(e)}') + pass + + + @debugger_wrapper('Error construyendo respuesta final', 'Error construyendo respuesta') + def response_maker(self, succesfull_run = False, error_str = str()): + if self.db_connection: + self.db_connection.close() + if succesfull_run: + self.final_response['statusCode'] = 200 + self.final_response['body'] = json.dumps(self.partial_response) + return self.final_response + + self.final_response['body'] = json.dumps(self.detailed_raise if self.detailed_raise else error_str) + return self.final_response + + + +def get_current_error_line(): + return str(sys.exc_info()[-1].tb_lineno) + \ No newline at end of file diff --git a/corporate_finances_back_py/modal-summary/utils.py b/corporate_finances_back_py/modal-summary/utils.py new file mode 100644 index 0000000..26fcea7 --- /dev/null +++ b/corporate_finances_back_py/modal-summary/utils.py @@ -0,0 +1,46 @@ +#version 2023 - 05 - 04 +import base64 +import boto3 +import json +import logging +import os + +from sqlalchemy import create_engine + +from decorators import handler_wrapper, debugger_wrapper + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + + +@debugger_wrapper('Error al obtener secreto','Error fatal de back conectando a base de datos') +def get_secret(secret_region, secret_name): + session = boto3.session.Session() + client_secrets_manager = session.client(service_name='secretsmanager', region_name=secret_region) + secret_data = client_secrets_manager.get_secret_value(SecretId=secret_name) + if 'SecretString' in secret_data: + secret_str = secret_data['SecretString'] + else: + secret_str = base64.b64decode(secret_data['SecretBinary']) + logger.info('[utils] (get_secret) Se obtuvo el secreto') + return json.loads(secret_str) + + +@debugger_wrapper('Error en la conexion a base de datos','Error fatal de back conectando a base de datos') +def connect_to_db(db_schema, db_secret): + conn_string = ('mysql+mysqlconnector://' + db_secret["username"] + ':' + db_secret["password"] + '@' + db_secret["host"] + ':' + str(db_secret["port"]) + '/' + db_schema) + sql_engine = create_engine(conn_string) + db_connection = sql_engine.connect() + return db_connection + + +@handler_wrapper('Invocando asincronamente a Engine de dinamismo', 'Invocación a Engine exitosa', 'Error invocando a Engine', 'Error invocando dinamismo') +def call_dynamic_engine(id_assessment): + lambda_engine = os.environ['LAMBDA_ENGINE'] + data = json.dumps({'id_assessment':id_assessment}).encode() + client = boto3.client('lambda') + response = client.invoke( + FunctionName=lambda_engine, + InvocationType='Event', + Payload= data +) diff --git a/corporate_finances_back_py/modal_window_saver/decorators.py b/corporate_finances_back_py/modal_window_saver/decorators.py new file mode 100644 index 0000000..071760a --- /dev/null +++ b/corporate_finances_back_py/modal_window_saver/decorators.py @@ -0,0 +1,63 @@ +#version 2023 - 05 - 04 +import logging +import sys +import traceback +from functools import wraps +from time import time + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + +def handler_wrapper(start, satisfactory_log, error_log, raise_error): + #esto se ejecuta en la inicializacion de primero + def decorator(func): + #print(message1) + #lo que yo ponga acá se ejecuta antes de hacer el llamado a la funcion + @wraps(func) + def wrapper(*args, **kwargs): + #esto sí se ejecuta solo cuando llama a la funcion decorada + #print(message2) + try: + logger.info(f'[{func.__name__}] {start}...') + resultado = func(*args, **kwargs) + logger.info(f'[{func.__name__}] {satisfactory_log}') + return resultado + except Exception as e: + logger.error(f"[{func.__name__}] {error_log}, linea: {get_especific_error_line(func.__name__)}, motivo: {str(e)}") + raise Exception(f"{raise_error}") + + return wrapper + return decorator + +def debugger_wrapper(error_log, raise_error): + def decorator(func): + @wraps(func) + def wrapper(*args, **kwargs): + try: + resultado = func(*args, **kwargs) + return resultado + except Exception as e: + logger.error(f"[{func.__name__}] {error_log}, linea: {get_especific_error_line(func.__name__)}, motivo: {str(e)}") + raise Exception(f"{raise_error}") + return wrapper + return decorator + + +def get_especific_error_line(func_name): + _, _, exc_tb = sys.exc_info() + for trace in traceback.extract_tb(exc_tb): + if func_name in trace: + return str(trace[1]) + +def timing(f): + @wraps(f) + def wrap(*args, **kw): + ts = time() + result = f(*args, **kw) + te = time() + taken_time_message = '[timing] La funcion {}, toma: {:.2f} sec en ejecutarse'.format(f.__name__, te-ts) + logger.info(taken_time_message) + return result + return wrap + + diff --git a/corporate_finances_back_py/modal_window_saver/lambda_function.py b/corporate_finances_back_py/modal_window_saver/lambda_function.py new file mode 100644 index 0000000..71d1cda --- /dev/null +++ b/corporate_finances_back_py/modal_window_saver/lambda_function.py @@ -0,0 +1,158 @@ +#a esta lambda debo ponerle el sombrero de -to-db +import json +import logging +import sys +import os +import pandas as pd +from sqlalchemy import text +from datetime import datetime + +from decorators import handler_wrapper, timing, debugger_wrapper +from utils import get_secret, connect_to_db, connect_to_db_local_dev, call_dynamic_engine + +logging.basicConfig() +logging.basicConfig(format='%(asctime)s [%(levelname)s] [%(module)s] %(message)s', force=True, datefmt='%Y-%m-%d %H:%M:%S') +logger = logging.getLogger() +logger.setLevel(logging.INFO) + + +def lambda_handler(event,context): + sc_obj = script_object(event) + lambda_response = sc_obj.starter() + logger.info(f'respuesta final de lambda: \n{lambda_response}') + return lambda_response + + +class script_object: + def __init__(self, event): + try: + self.failed_init = False + self.final_response = {'headers':{'Access-Control-Allow-Headers': '*', + 'Access-Control-Allow-Origin': '*', + 'Access-Control-Allow-Methods': '*'}, "statusCode": 500, 'body': {}} + self.db_connection = 0 + self.detailed_raise = '' + self.partial_response = list() + + logger.warning(f'event de entrada: {str(event)}') + event_dict = json.loads(event['body']) + self.id_assessment = event_dict['id_assessment'] + self.context = event_dict['context'] + self.projecting_items = event_dict['projection_data'] + + self.historic_dates = list() + self.projection_dates = list() + self.years = int() + self.accounts_original_values = dict() + self.modal_window_records = [] + self.modal_projected_records = [] + + + except Exception as e: + logger.error(f'[__init__] Error inicializando objeto lambda, linea: {get_current_error_line()}, motivo: {str(e)}') + self.failed_init = True + + def starter(self): + try: + if self.failed_init: + raise AttributeError('Error con los datos recibidos al servicio') + self.create_conection_to_db() + self.early_modal_windows_safe_delete() + self.get_assessment_dates() + self.create_db_records() + self.upload_dataframes_to_bd() + call_dynamic_engine(self.id_assessment, __name__) + return self.response_maker(succesfull_run = True) + + except Exception as e: + logger.error(f'[starter] Hubieron problemas en el comando de la linea: {get_current_error_line()}') + return self.response_maker(succesfull_run = False, error_str = (str(e))) + + @handler_wrapper('Creando conexion a bd','Conexion a bd creada con exito','Error en la conexion a bd','Problemas creando la conexion a bd') + def create_conection_to_db(self): + if __name__ != 'lambda_function': + self.db_connection = connect_to_db_local_dev() + self.db_connection.begin() + return + + db_schema = os.environ['DB_SCHEMA'] + secret_db_region = os.environ['SECRET_DB_REGION'] + secret_db_name = os.environ['SECRET_DB_NAME'] + db_secret = get_secret(secret_db_region, secret_db_name) + self.db_connection = connect_to_db(db_schema, db_secret) + + + @handler_wrapper('Obteniendo las fechas del proceso de valoración', 'Fechas del proceso de valroación obtenidas con exito', 'Error obteniendo las fechas del proceso de valoración', 'Error obteniendo fechas del proceso de valoración') + def get_assessment_dates(self): + query = f"SELECT DATES, PROPERTY FROM ASSESSMENT_DATES WHERE ID_ASSESSMENT = {self.id_assessment} ORDER BY DATES" + logger.info(f"[get_assessment_dates] Query a base de datos para obtener las fechas utilizadas en el proces de valoración:\n {query}") + rds_data = self.db_connection.execute(text(query)) + directory = {'HISTORIC': self.historic_dates, 'PROJECTION': self.projection_dates} + for date_item in rds_data.fetchall(): + directory.get(date_item.PROPERTY, []).append(date_item.DATES.strftime('%Y-%m-%d %H:%M:%S')) + + logger.info(f'[get_assessment_dates] Fechas del proceso de valoración:\nhistoricas: {self.historic_dates}\nproyecciones: {self.projection_dates}') + + + @handler_wrapper('Fue necesaria la eliminacion de proyecciones en BD', 'Eliminación exitosa', 'Error eliminado proyecciones de BD', 'Error sobreescribiendo proyecciones en bd') + def early_modal_windows_safe_delete(self): + query = f'DELETE FROM MODAL_WINDOWS WHERE ID_ASSESSMENT = {self.id_assessment} AND CONTEXT_WINDOW = "{self.context}"' + logger.warning(f'[early_modal_windows_safe_delete] Query para eliminacion de datos anteriores para el contexto {self.context}: \n{query}') + self.db_connection.execute(text(query)) + + query = f'DELETE FROM MODAL_WINDOWS_PROJECTED WHERE ID_ASSESSMENT = {self.id_assessment} AND CONTEXT_WINDOW = "{self.context}"' + logger.warning(f'[early_modal_windows_safe_delete] Query para eliminacion de datos anteriores para el contexto {self.context}: \n{query}') + self.db_connection.execute(text(query)) + + + @handler_wrapper('Organizando records para envio a bd', 'Records alistados con exito', 'Error areglando records para envío a bd', 'Error manejando datos para envío a bd') + def create_db_records(self): + logger.info(f'[create_db_records] array de objetos a organizar para bd:\n{self.projecting_items}') + for item in self.projecting_items: + self.modal_window_records.append({'ID_ASSESSMENT': self.id_assessment, + 'ORIGINAL_VALUE': 0, + 'ACCOUNT_NUMBER': item['account'], + 'CONTEXT_WINDOW': self.context, + 'VS_ACCOUNT_NAME': item['accountProjector'], + 'PROJECTION_TYPE': item['method'], + 'COMMENT':item['explication']}) + + projection_records = [{'ID_ASSESSMENT': self.id_assessment, + 'VALUE': 0, + 'ACCOUNT_NUMBER': item['account'], + 'CONTEXT_WINDOW': self.context, + 'PROJECTED_DATE': year, + 'ATRIBUTE': item['atributes']['projection'][i] + } for i, year in enumerate(self.projection_dates)] + self.modal_projected_records.extend(projection_records) + + + @handler_wrapper('Cargando data a bd', 'Data carga a bd', 'Error en la carga de información a bd', 'Error cargando la información a bd') + def upload_dataframes_to_bd(self): + self.modal_window_df = pd.DataFrame.from_records(self.modal_window_records) + self.modal_projected_df = pd.DataFrame.from_records(self.modal_projected_records) + logger.info(f'[upload_dataframes_to_bd] Dataframe que se cargará a MODAL_WINDOWS:\n{self.modal_window_df.to_string()}') + logger.info(f'[upload_dataframes_to_bd] Dataframe que se cargará a MODAL_WINDOWS_PROJECTED:\n{self.modal_projected_df.to_string()}') + self.modal_window_df.to_sql(name='MODAL_WINDOWS', con=self.db_connection, if_exists='append', index=False) + self.modal_projected_df.to_sql(name='MODAL_WINDOWS_PROJECTED', con=self.db_connection, if_exists='append', index=False) + + + def response_maker(self, succesfull_run=False, error_str=""): + if self.db_connection: + self.db_connection.close() + if not succesfull_run: + self.final_response["body"] = json.dumps(self.detailed_raise if self.detailed_raise else error_str) + else: + self.final_response["statusCode"] = 200 + self.final_response["body"] = json.dumps("Ok") + return self.final_response + + + +def get_current_error_line(): + return str(sys.exc_info()[-1].tb_lineno) + + +if __name__ == '__main__': + event = {'body': '{"context": "patrimony", "datesHistory": ["2023-12-31", "2024-12-31"], "dates_projections": ["2025", "2026", "2027"], "id_assessment": "2064", "projection_data": [{"account": "23", "name": "patrimonio (23)", "accountProjector": "No aplica", "atributes": {"history": [64099.94, 32049.97], "projection": [10.0, 20.0, 30.0]}, "explication": "Hola", "method": "Tasa de crecimiento fija"}, {"account": "11", "name": "caja (11)", "accountProjector": "No aplica", "atributes": {"history": [64099.94, 32049.97], "projection": ["", "", ""]}, "explication": "Proyecci\\u00f3n primera vez, debug", "method": "Cero"}], "year": 3}'} + lambda_handler(event, '') \ No newline at end of file diff --git a/corporate_finances_back_py/modal_window_saver/utils.py b/corporate_finances_back_py/modal_window_saver/utils.py new file mode 100644 index 0000000..07bb5e5 --- /dev/null +++ b/corporate_finances_back_py/modal_window_saver/utils.py @@ -0,0 +1,58 @@ +#version 2023 - 05 - 04 +import base64 +import boto3 +import json +import logging +import os +from sqlalchemy import create_engine + +from decorators import handler_wrapper, debugger_wrapper + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + + +@debugger_wrapper('Error al obtener secreto','Error fatal de back conectando a base de datos') +def get_secret(secret_region, secret_name): + session = boto3.session.Session() + client_secrets_manager = session.client(service_name='secretsmanager', region_name=secret_region) + secret_data = client_secrets_manager.get_secret_value(SecretId=secret_name) + if 'SecretString' in secret_data: + secret_str = secret_data['SecretString'] + else: + secret_str = base64.b64decode(secret_data['SecretBinary']) + logger.info('[utils] (get_secret) Se obtuvo el secreto') + return json.loads(secret_str) + + +@debugger_wrapper('Error en la conexion a base de datos','Error fatal de back conectando a base de datos') +def connect_to_db(db_schema, db_secret): + conn_string = ('mysql+mysqlconnector://' + db_secret["username"] + ':' + db_secret["password"] + '@' + db_secret["host"] + ':' + str(db_secret["port"]) + '/' + db_schema) + sql_engine = create_engine(conn_string) + db_connection = sql_engine.connect() + return db_connection + + +@debugger_wrapper('Error en la conexion a base de datos','Error fatal de back conectando a base de datos') +def connect_to_db_local_dev(): + from dotenv import load_dotenv + load_dotenv() + conn_string = os.environ['local_dev_connector'] + sql_engine = create_engine(conn_string) + db_connection = sql_engine.connect() + return db_connection + + +@handler_wrapper('Invocando asincronamente a Engine de dinamismo', 'Invocación a Engine exitosa', 'Error invocando a Engine', 'Error invocando dinamismo') +def call_dynamic_engine(id_assessment, context): + if context == 'lambda_function': + lambda_engine = os.environ['LAMBDA_ENGINE'] + data = json.dumps({'id_assessment':id_assessment}).encode() + client = boto3.client('lambda') + response = client.invoke( + FunctionName=lambda_engine, + InvocationType='Event', + Payload= data + ) + else: + logger.warning('[call_dynamic_engine] no se ejecuta engine ya que el contexto es local') diff --git a/corporate_finances_back_py/multi-account-classification/builder.py b/corporate_finances_back_py/multi-account-classification/builder.py new file mode 100644 index 0000000..0dc2fbb --- /dev/null +++ b/corporate_finances_back_py/multi-account-classification/builder.py @@ -0,0 +1,240 @@ + +from decorators import handler_wrapper, timing, debugger_wrapper +import logging +from datetime import datetime, timedelta +import sys +import math +import copy +import pandas as pd +from sqlalchemy import text + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + +class builder_class(): + + @handler_wrapper('Ejecutando builder', 'Builder ejecutado con exito', 'Error ejecutando builder de puc historico', 'Error ejecutando builder de puc historico') + def historic_pucs_builder(self): + self.parent_accounts_items = {'Ingresos operacionales': ['Ingresos operacionales 1', 'Ingresos operacionales 2', 'Ingresos operacionales 3', 'Ingresos operacionales 4', 'Ingresos operacionales 5'], 'Gastos operacionales': ['Gastos operacionales 1', 'Gastos operacionales 2', 'Gastos operacionales 3', 'Otros ingresos/egresos operativos']} + self.special_classifications = ["Depreciación del periodo", "Depreciación acumulada", "Propiedad, planta y equipo", "Intangibles", "Amortización acumulada", "Amortización del periodo"] + + self.purged_items = list() + self.calculated_summaries = list() + + assessment_archives = set(row['ID_ARCHIVE'] for row in self.full_historic_data) + for archive in assessment_archives: + self.id_archive_processing = archive + self.full_records = [row for row in self.full_historic_data if row['ID_ARCHIVE'] == archive] + + self.classification_shooter() + self.parent_accounts_shooter() + self.special_classifications_shooter() + + self.merge_classifications_ids() + self.fix_data_to_bd() + self.upload_results_to_bd() + + + @handler_wrapper('Inicializando disparador de clasificaciones', 'Disparador de clasificaciones terminado con exito', 'Error en el disparador de clasificaciones', 'Error calculando clasificacion') + def classification_shooter(self): + for master_classification in self.classification_id_dict: + self.basic_seeker(master_classification) + + + @debugger_wrapper('Error filtrando las clasificaciones requeridas', 'Error filtrando clasificaciones') + def basic_seeker(self, classification_to_find): + logger.info(f'[basic_seeker] Calculando la clasificacion: "{classification_to_find}"') + group_filter = lambda item: item.get('classification', 'No aplica') == classification_to_find + found_items = list(filter(group_filter, self.full_records)) + if not found_items or classification_to_find == 'No aplica': + logger.info(f'[basic_seeker] No se encontraron cuentas con clasificacion {classification_to_find}') + return + found_items = self.filter_items_to_min_level(found_items) + logger.warning(f"[basic_seeker] Los items con la clasificacion {classification_to_find} son: \n{found_items}") + found_items = copy.deepcopy(found_items) + self.individual_records_modifier(found_items) + self.classification_summary_calculator(classification_to_find) + + + @handler_wrapper('Inicializando disparador de clasificaciones padre', 'Disparador de cuentas padre terminado con exito', 'Error en el disparador cuentas padre', 'Error calculando cuentas padre de subs') + def parent_accounts_shooter(self): + [self.calculate_parents_accounts(parent_account, sub_classifications) for parent_account, sub_classifications in self.parent_accounts_items.items()] + + + def calculate_parents_accounts(self, parent_account, sub_classifications): + purged_items = list(filter(lambda item: item['classification'] in sub_classifications, self.purged_items)) + self.calculated_summaries.append({'classification': parent_account, **self.calculate_summary_groups(purged_items), 'ID_ARCHIVE': self.id_archive_processing}) + + + @handler_wrapper('Recalculando items de clasificaciones especiales', 'Clasificaciones especiales recalculadas con exito', 'Error al calcular cuentas especiales', 'Error calculando cuentas especiales') + def special_classifications_shooter(self): + logger.warning(f'purged_items antes de especiales: \n{self.purged_items}') + [self.special_seeker(master_classification) for master_classification in self.special_classifications] + logger.warning(f'purged_items despues de especiales: \n{self.purged_items}') + + + @debugger_wrapper('Fallo calculando clasificaciones especiales', 'Error calculando clasificaciones de tipo especial') + def special_seeker(self, classification_to_find): + logger.info(f'[special_seeker] Calculando la clasificacion: "{classification_to_find}"') + f = lambda item : item.get('classification', 'No aplica') == classification_to_find + found_items = list(filter(f, self.full_records)) + if found_items: + sorted_unique_found_levels = sorted(set(item['nivel'] for item in found_items)) + if len(sorted_unique_found_levels) > 1: + level_to_search = sorted_unique_found_levels[1] + self.special_purged_accounts_eraser(classification_to_find) + g = lambda item : item['nivel'] == level_to_search + found_items = list(filter(g, found_items)) + found_items = copy.deepcopy(found_items) + self.individual_records_modifier(found_items) + return + + logger.info(f'[special_seeker] Todos los items de la clasificacion {classification_to_find} tienen solo un nivel') + return + + logger.info(f'[special_seeker] No se encontraron cuentas con clasificacion {classification_to_find}') + + + def special_purged_accounts_eraser(self, classification_to_erase): + self.purged_items = list(filter(lambda item:item['classification'] != classification_to_erase or item['ID_ARCHIVE'] != self.id_archive_processing, self.purged_items)) + + + def individual_records_modifier(self, found_items): + self.purged_items += list(map(self.purge_individual_item, found_items)) + + + def classification_summary_calculator(self, classification_to_find): + purged_items = list(filter(lambda item: item['classification'] == classification_to_find and item['ID_ARCHIVE'] == self.id_archive_processing, self.purged_items)) + self.calculated_summaries.append({'classification': classification_to_find, **self.calculate_summary_groups(purged_items), 'ID_ARCHIVE': self.id_archive_processing}) + + + @debugger_wrapper('Error purgando cuentas individuales', 'Error purgando cuentas de puc') + def purge_individual_item(self, master_account): + master_account['ACCOUNT_NAME'] = f"{master_account['ACCOUNT_NAME'].strip()} ({master_account['ACCOUNT_NUMBER']})" + master_account['hint'] = f"{master_account['ACCOUNT_NUMBER']} " + master_account['ID_ARCHIVE'] = self.id_archive_processing + filter_machine = self.create_sub_accounts_filter(master_account) + self.sub_classifications_pool = list(filter(lambda item: all(f(item) for f in filter_machine), self.full_records)) + self.sub_classifications_pool.sort(key = lambda item: item['nivel'], reverse = False) #Con esto me aseguro que el set de subclasificaciones esté en orden de nivel y que no purgaré un nivel 10 antes de purgar un nivel 6 + sub_classifications = self.classifications_set_ordered(self.sub_classifications_pool) + logger.warning(f"[purge_individual_item] sub clasificaciones encontradas para la cuenta {master_account['ACCOUNT_NUMBER']}: \n{sub_classifications}") + + for classification in sub_classifications: + master_account['hint'] = master_account.get('hint', master_account['ACCOUNT_NUMBER']) #ver si esto lo puedo borrar + logger.warning(f"[purge_individual_item] Cuenta {master_account['ACCOUNT_NUMBER']} antes de modificacion por clasificacion {classification}: \nValor: {master_account['value']}\nHint: {master_account['hint']}") + sub_classification_items = [item for item in self.sub_classifications_pool if item['classification'] == classification] + sub_classification_items = self.filter_items_to_min_level(sub_classification_items) + + for sub_item in sub_classification_items: + master_account = self.apply_sub_item_to_master(master_account, sub_item) + + logger.warning(f"[purge_individual_item] Cuenta {master_account['ACCOUNT_NUMBER']} post modificacion de clasificacion {classification}: \nvalor: {master_account['value']}, hint: {master_account['hint']}") + return master_account + + + def create_sub_accounts_filter(self, master_account): + filters = [] + filters.append(lambda item: item['ACCOUNT_NUMBER'].startswith(master_account['ACCOUNT_NUMBER'])) + filters.append(lambda item: item['classification'] != master_account['classification']) + filters.append(lambda item: item['nivel'] > master_account['nivel']) + #filters.append(lambda item: item['classification'] != 'No aplica') + return filters + + + @debugger_wrapper('Error filtrando cuentas a minimo nivel', 'Error procesando data') + def filter_items_to_min_level(self, items): + nivels = sorted(set([item['nivel'] for item in items])) + usable_accounts = [ item['ACCOUNT_NUMBER'] for item in items if item['nivel'] == nivels[0] ] + logger.info(f'[filter_items_to_min_level] usable_accounts original: \n{usable_accounts}') + + for nivel in nivels[1:]: + this_level_items = [item for item in items if item['nivel'] == nivel] + new_items = [item['ACCOUNT_NUMBER'] for item in this_level_items if not item['ACCOUNT_NUMBER'].startswith(tuple(usable_accounts))] + #Acá se están obteniendo las subcuentas que estén clasificadas igual que el subaccount del master pero que no sean subcuentas entre sí + #suponga: master account 11 efectivo, subcuenta 1105 ppe, subcuenta 131015 ppe; estas dos subcuentas no son subcuentas entre sí, por eso ambas + #deben restarse del master account + #si la subcuentas fueran 1110 ppe y 111020 ppe, debería tenerse en cuenta unicamente la 1110 + logger.info(f'[filter_items_to_min_level] se agregan las siguientes cuentas: \n{new_items}') + usable_accounts.extend(new_items) + return list(filter(lambda item: item['ACCOUNT_NUMBER'] in usable_accounts , items)) + + + + def classifications_set_ordered(self, sub_classifications_pool): + return list(dict.fromkeys(item['classification'] for item in sub_classifications_pool)) #Esto es para hacer un SET + #de las clasificaciones pero sin perder el orden de las mismas, porque ya están organizadas por nivel, requiero + #sacar las clasificaciones sin repetirse pero sin desorganizarse, que es lo que haría un set() + + + def apply_sub_item_to_master(self, master_account, sub_item): + master_account['value'] = master_account['value'] - sub_item['value'] + master_account['hint'] = master_account['hint'] + f"-{sub_item['ACCOUNT_NUMBER']} " + + self.sub_classifications_pool = list(filter(lambda item: not item['ACCOUNT_NUMBER'].startswith(sub_item['ACCOUNT_NUMBER']), self.sub_classifications_pool)) + #recordar que hay un sub_classification_items que son las sub cuentas con una clasificaciones, pero hay un sub_classifications_pool que contiene TODAS las subcuentas con + #multiples clasificaciones, las subcuentas con la misma clasificacion que se deban omitir ya se están omitiendo en filter_items_to_min_level, pero si hay sub clasificaciones + #con clasificaciones differentes en el pool, estas tambien se deben omitir, por eso es tan importante que la depuración se realice en niveles inferiores y luego a superiores + return master_account + + + #OJO esta definicion no se está usando + def calculate_sub_grouping(self, item): + value = 0 + accounts_used_log = '' + + #logger.warning(f"{item}") + if (item['nature'] == 'Debito' and item['ACCOUNT_NUMBER'][0] in ['1', '2', '3']) or (item['nature'] == 'Credito' and item['ACCOUNT_NUMBER'][0] in ['4', '5', '6']): + value = value + item['value'] + accounts_used_log = accounts_used_log + f"+{item.get('hint', item.get('ACCOUNT_NUMBER'))} " + if (item['nature'] == 'Credito' and item['ACCOUNT_NUMBER'][0] in ['1', '2', '3']) or (item['nature'] == 'Debito' and item['ACCOUNT_NUMBER'][0] in ['4', '5', '6']): + value = value - item['value'] + accounts_used_log = accounts_used_log + f"-{item.get('hint', item.get('ACCOUNT_NUMBER'))} " + return {'value': value, 'hint':accounts_used_log} + + + def calculate_summary_groups(self, found_purged_items): + #ya que no se está teniendo en cuenta naturaleza y capitulos para el df2, + #lo ideal es que al sumar estas cuentas purgadas, sí se tenga en cuenta estas cosas + #usar el algoritmo de calculate_sub_grouping + summary_value = sum(item['value'] for item in found_purged_items) + summary_hint = ' + '.join(item['hint'] for item in found_purged_items) + return {'value': summary_value, 'hint':summary_hint} + + + @handler_wrapper('Emergiendo IDs de los nombres de clasificacion','Ids emergidos correctamente', 'Error emergiendo IDs de clasificacion', 'Error agrupando datos') + def merge_classifications_ids(self): + logger.warning(f'Este es mi elemento self.inverted_raw_classifications {self.classification_id_dict}') + for item in self.calculated_summaries: + item['ID_RAW_CLASSIFICATION'] = self.classification_id_dict[item['classification']] + for item in self.purged_items: + item['ID_RAW_CLASSIFICATION'] = self.classification_id_dict[item['classification']] + + + @handler_wrapper('Arreglando dataframes para subida a bd', 'Arreglo de dataframes terminado', 'Error arreglando dataframes', 'Error operando datos') + def fix_data_to_bd(self): + self.summaries_df = pd.DataFrame.from_records(self.calculated_summaries) + self.purged_items_df = pd.DataFrame.from_records(self.purged_items) + + logger.warning(f"[fix_dataframes] summaries antes de fix: \n{self.summaries_df.to_string()}") + self.summaries_df['ID_ASSESSMENT'] = self.id_assessment + self.summaries_df['ANNUALIZED'] = self.summaries_df['value'] + self.summaries_df.rename(columns={'value': 'CALCULATED_BALANCE', 'hint': 'HINT'},inplace=True) + self.summaries_df.drop(['classification'], axis=1, inplace=True) + #De este me falta el merge con id_raw_classifications + + logger.warning(f"[fix_dataframes] purgeds antes de fix: \n{self.purged_items_df.to_string()}") + self.purged_items_df['ID_ASSESSMENT'] = self.id_assessment + self.purged_items_df['ANNUALIZED'] = self.purged_items_df['value'] + self.purged_items_df.rename(columns={'value': 'CALCULATED_BALANCE', 'hint': 'HINT', 'nature': 'NATURE', 'name': 'ACCOUNT_NAME'},inplace=True) + self.purged_items_df.drop(['nivel', 'classification'], axis=1, inplace=True) #este chapter es importante para despues, sería mejor no borrarlo + #De este me falta el merge con id_raw_classifications + + logger.warning(f"[fix_dataframes] summaries despues de fix: \n{self.summaries_df.to_string()}") + logger.warning(f"[fix_dataframes] purgeds despues de fix: \n{self.purged_items_df.to_string()}") + #TODO: Tengo que sí o sí arreglar los hints y revisar los casos + + + @handler_wrapper('Cargando datos a bd', 'Datos cargados a bd satisfactoriamente', 'Error cargando datos a bd', 'Error cargando resultados a base de datos') + def upload_results_to_bd(self): + self.summaries_df.to_sql(name='CLASSIFICATION_SUMMARY', con=self.db_connection, if_exists='append', index=False) + self.purged_items_df.to_sql(name='ASSESSMENT_CHECKED', con=self.db_connection, if_exists='append', index=False) \ No newline at end of file diff --git a/corporate_finances_back_py/multi-account-classification/decorators.py b/corporate_finances_back_py/multi-account-classification/decorators.py new file mode 100644 index 0000000..db17c59 --- /dev/null +++ b/corporate_finances_back_py/multi-account-classification/decorators.py @@ -0,0 +1,84 @@ +#version 2024 - 02 - 20 +import logging +import sys +import traceback +from functools import wraps +from time import time + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + +def handler_wrapper(start, satisfactory_log, error_log, raise_error): + #esto se ejecuta en la inicializacion de primero + def decorator(func): + #print(message1) + #lo que yo ponga acá se ejecuta antes de hacer el llamado a la funcion + @wraps(func) + def wrapper(*args, **kwargs): + #esto sí se ejecuta solo cuando llama a la funcion decorada + #print(message2) + try: + logger.info(f'[{func.__name__}] {start}...') + resultado = func(*args, **kwargs) + logger.info(f'[{func.__name__}] {satisfactory_log}') + return resultado + except Exception as e: + logger.error(f"[{func.__name__}] {error_log}, linea: {get_especific_error_line(func.__name__)}, motivo: {str(e)}") + raise Exception(f"{raise_error}") + + return wrapper + return decorator + +def debugger_wrapper(error_log, raise_error): + def decorator(func): + @wraps(func) + def wrapper(*args, **kwargs): + try: + resultado = func(*args, **kwargs) + return resultado + except Exception as e: + logger.error(f"[{func.__name__}] {error_log}, linea: {get_especific_error_line(func.__name__)}, motivo: {str(e)}") + raise Exception(f"{raise_error}") + return wrapper + return decorator + +def try_pass_wrapper(error_log): + def decorator(func): + @wraps(func) + def wrapper(*args, **kwargs): + try: + resultado = func(*args, **kwargs) + return resultado + except Exception as e: + logger.debug(f"[{func.__name__}] {error_log}, linea: {get_especific_error_line(func.__name__)}, motivo: {str(e)}") + return wrapper + return decorator + +def runs_ok(func): + def wrapper_func(*args, **kwargs): + try: + func(*args, **kwargs) + return True + except Exception: + return False + return wrapper_func + + +def get_especific_error_line(func_name): + _, _, exc_tb = sys.exc_info() + for trace in traceback.extract_tb(exc_tb): + if func_name in trace: + return str(trace[1]) + +def timing(f): + @wraps(f) + def wrap(*args, **kw): + ts = time() + result = f(*args, **kw) + te = time() + taken_time_message = '[timing] La funcion {}, toma: {:.2f} sec en ejecutarse'.format(f.__name__, te-ts) + logger.info(taken_time_message) + return result + return wrap + + diff --git a/corporate_finances_back_py/multi-account-classification/lambda_function.py b/corporate_finances_back_py/multi-account-classification/lambda_function.py new file mode 100644 index 0000000..0194551 --- /dev/null +++ b/corporate_finances_back_py/multi-account-classification/lambda_function.py @@ -0,0 +1,276 @@ +from sqlalchemy import text +import datetime +import json +import logging +from queue import Queue +from threading import Thread +import sys +import boto3 +import os +import sqlalchemy +import traceback +import pandas as pd + +from builder import builder_class + +from decorators import handler_wrapper, timing, debugger_wrapper, try_pass_wrapper +from utils import get_secret, connect_to_db, call_dynamic_engine, connect_to_db_local_dev + +logging.basicConfig() +logging.basicConfig(format='%(asctime)s [%(levelname)s] %(message)s', force=True, datefmt='%Y-%m-%d %H:%M:%S') +logger = logging.getLogger() +logger.setLevel(logging.INFO) + + +def lambda_handler(event, context): + sc_obj = script_object(event) + lambda_response = sc_obj.starter() + logger.info(f'respuesta final de lambda: \n{lambda_response}') + return lambda_response + + +class script_object(builder_class): + def __init__(self, event): + + try: + self.failed_init = False + self.final_response = {'headers':{'Access-Control-Allow-Headers': '*', + 'Access-Control-Allow-Origin': '*', + 'Access-Control-Allow-Methods': '*'}, "statusCode": 500, 'body': {}} + self.db_connection = 0 + self.detailed_raise = '' + self.partial_response = {} + + logger.info('[__INIT__] Inicializando Lambda ...') + logger.warning(f'event de entrada: {str(event)}') + + event_body_json = event["body"] + self.event_body_dict = json.loads(event_body_json) + + self.id_assessment = self.event_body_dict['id_assessment'] + self.first_time_classification = True if 'selected_dates' in self.event_body_dict else False + + self.classification_dates = set(item['date'] for item in self.event_body_dict['data']) + + self.company_data = dict() + self.current_archive_data = dict() + self.archives_dates = list() + self.full_historic_data = list() + + self.raw_classification_data = pd.core.frame.DataFrame() + self.reduced_classified_df = pd.core.frame.DataFrame() + self.merged_df = pd.core.frame.DataFrame() + self.selected_archives_to_db_df = pd.core.frame.DataFrame() + + + logger.info('[__INIT__] Objeto lambda inicializada exitosamente') + + except Exception as e: + self.failed_init = True + logger.error(f"[__INIT__] error en inicializacion, linea: {get_current_error_line()}, motivo: "+str(e)) + + @timing + def starter(self): + try: + if self.failed_init: + raise AttributeError('Error con los datos recibidos al servicio') + + self.create_conection_to_db() + #self.db_connection.begin() + self.get_company_archive_info() + self.user_classification_data_safe_delete() + + self.choose_clasification_data() + + self.get_classification_raw_info() + + ##Manejo de clasificaciones actuales + self.reduce_classified() + self.merge_classifications() + self.depurate_classifies_to_bd() + self.user_classified_to_bd() + + #Clasificando los pucs actuales + self.get_original_puc_data() + self.balance_pucs_accounts() + self.re_classify_all_historic_pucs() + self.historic_pucs_builder() + + self.save_assessment_step() + call_dynamic_engine(self.id_assessment) + #self.db_connection.commit() + return self.response_maker(succesfull_run = True) + except Exception as e: + if self.db_connection: + self.db_connection.close() + logger.error(f'[starter] Hubieron problemas en el comando de la linea: {get_current_error_line()}') + return self.response_maker(succesfull_run = False, error_str = (str(e))) + + + @handler_wrapper('Creando conexion a bd','Conexion a bd creada con exito','Error en la conexion a bd','Problemas creando la conexion a bd') + def create_conection_to_db(self): + if __name__ != 'lambda_function': + self.db_connection = connect_to_db_local_dev() + self.db_connection.begin() + return + db_schema = os.environ['DB_SCHEMA'] + secret_db_region = os.environ['SECRET_DB_REGION'] + secret_db_name = os.environ['SECRET_DB_NAME'] + db_secret = get_secret(secret_db_region, secret_db_name) + self.db_connection = connect_to_db(db_schema, db_secret) + + @handler_wrapper('El proceso requirió la eliminacion de una clasificacion anterior','Borrado seguro realizado con exito','Error realizando el borrado seguro de clasificacion de usuario anterior','Problemas sobre escribiendo una clasificacion anterior') + def user_classification_data_safe_delete(self): + query = f"DELETE FROM USER_CLASSIFICATION WHERE ID_ASSESSMENT = {self.id_assessment}" + logger.info(f'[user_classification_data_safe_delete] Query para eliminar datos anteriores de clasificacion personal: {query}') + self.db_connection.execute(text(query)) + + query = f"DELETE FROM CLASSIFICATION_SUMMARY WHERE ID_ASSESSMENT = {self.id_assessment}" + logger.info(f'[user_classification_data_safe_delete] Query para eliminar datos anteriores de resultados por clasificacion: {query}') + self.db_connection.execute(text(query)) + + query = f"DELETE FROM ASSESSMENT_CHECKED WHERE ID_ASSESSMENT = {self.id_assessment}" + logger.info(f'[user_classification_data_safe_delete] Query para eliminar datos anteriores de items purgados: {query}') + self.db_connection.execute(text(query)) + + + @handler_wrapper('Buscando info de empresa y archive a valorar', 'Información de empresa y archive obtenida', 'Error obteniendo información de empresa y archive', 'Error adquiriendo información del proceso de información') + def get_company_archive_info(self): + query = f"""SELECT A.ID, B.INITIAL_DATE FROM COMPANY A, ARCHIVE B, ASSESSMENT C WHERE A.ID = B.ID_COMPANY AND B.ID = C.ID_ARCHIVE AND C.ID = {self.id_assessment}""" + logger.info(f'[get_company_archive_info] Query para pedir la información del assessment:\n{query}') + rds_data = self.db_connection.execute(text(query)) + assessment_data = rds_data.one()._asdict() + self.id_company = assessment_data['ID'] + self.classification_dates.add(assessment_data['INITIAL_DATE'].strftime('%Y-%m-%d')) + + + @handler_wrapper('Decidiendo el array de clasificaciones', 'Array de clasificaciones legido con exito', 'Error escogiendo array de clasificaciones', 'Porblemas procesando multiples fechas d clasificaciones') + def choose_clasification_data(self): + all_got_dates = [datetime.datetime.strptime(date, '%Y-%m-%d') for date in self.classification_dates] + max_date_str = max(all_got_dates).strftime('%Y-%m-%d') + last_date_data = next(item['data'] for item in self.event_body_dict['data'] if item['date'] == max_date_str) + self.raw_classified_df = pd.DataFrame.from_records( last_date_data ) + + + @handler_wrapper('Buscando datos de clasificacion raw para realizar el merge de los datos clasificados','Datos de clasificaciones raw obtenidos con exito','Error buscando clasificaciones raw','Error emergiendo la data recibida de clasificaciones') + def get_classification_raw_info(self): + query = "SELECT ID, CLASSIFICATION FROM RAW_CLASSIFICATION" + logger.info(f'[get_classification_raw_info] Query para obtener las clasificaciones raw: {query}') + self.raw_classification_data = pd.read_sql(query, self.db_connection) + self.classification_id_dict = dict(zip(self.raw_classification_data.CLASSIFICATION, self.raw_classification_data.ID)) + self.id_classification_dict = dict(zip(self.raw_classification_data.ID, self.raw_classification_data.CLASSIFICATION)) + + + @handler_wrapper('Recortando clasificaciones innecesarias','Clasificaciones innecesarias depuradas con exito','Error al depurar df clasificado','Error fatal en la revision de la clasificacion') + def reduce_classified(self): + logger.warning(f'[reduce_classified] DF que voy a depurar: \n{self.raw_classified_df.head(5).to_string()}') + self.raw_classified_df.drop(['chapter', 'initial_date'], axis=1, inplace=True) #'index', + self.levels = sorted(self.raw_classified_df['nivel'].unique().tolist()) #este va aumentando 1,2,4,6 + self.reduced_classified_df = self.raw_classified_df.loc[self.raw_classified_df['nivel'] == self.levels[1]] + for level in self.levels[2:]: + [self.account_depurator_chooser(account) for account in self.raw_classified_df.loc[self.raw_classified_df['nivel']==level].to_dict(orient='records')] + + logger.warning(f"[reduce_classified] resultado de depurador:\n {self.reduced_classified_df.to_dict(orient='records')}") + logger.warning(f"[reduce_classified] con una longitud de:\n {self.reduced_classified_df.shape[0]}") + + + @debugger_wrapper('Error reduciendo datafram', 'Error reduciendo cuentas') + def account_depurator_chooser(self,account): + account_classification = account["classification"] + account_parents_list = [account['account'][:nivel] for nivel in self.levels] + temp_parent_classification = self.reduced_classified_df.loc[self.reduced_classified_df['account'].isin(account_parents_list)] + parent_classification = temp_parent_classification.loc[temp_parent_classification['nivel'] == temp_parent_classification['nivel'].max(), 'classification'].values[0] + + if account_classification != parent_classification: + self.reduced_classified_df = pd.concat([self.reduced_classified_df, self.raw_classified_df.loc[self.raw_classified_df['account'].str.fullmatch(account['account'])]]) + + + @handler_wrapper('Realizando merge de clasificacion para obtener los ids de clasificacion','Merge realizado con exito','Error realizando merge de clasificacion default con la tabla de nombre raw de clasificacion','Hubieron problemas con los datos recibidos') + def merge_classifications(self): + """Acá se está asignando los ids de clasificacion al dataframe clasificado reducido + """ + self.merged_df = self.reduced_classified_df.merge(self.raw_classification_data, how='inner',left_on = ['classification'], right_on = ['CLASSIFICATION']) + + + @handler_wrapper('Depurando dataframe para envio a base de datos','Depurado a base de datos terminado con exito','Error en la depuracion a base de datos','Error arreglando datos para guardar en base de datos') + def depurate_classifies_to_bd(self): + #acá llega con estas columnas nivel, classification, account, ID, CLASSIFICATION + logger.warning(f'informacion que llega a depuracion:\n{self.merged_df.head(5).to_string()}') + self.merged_to_db_df = self.merged_df.copy() + self.merged_to_db_df.drop(['nivel', 'classification', 'CLASSIFICATION', 'status', 'ID_RAW_CLASSIFICATION', 'balance', 'name'], axis=1, inplace = True, errors= 'ignore') + self.merged_to_db_df['ID_ASSESSMENT'] = self.id_assessment + self.merged_to_db_df.rename(columns={"account": "ACCOUNT_NUMBER", 'ID': 'ID_RAW_CLASSIFICATION'}, inplace = True) + self.merged_to_db_df.sort_values(by=['ACCOUNT_NUMBER'], inplace = True, ignore_index = True) + + + @handler_wrapper('Cargando clasificacion del analista a base de datos', 'Clasificacion del analista guardada con exito','Error al guardar clasificacion del analista en bd','Hubieron errores al guardar clasificacion del analista en base de datos') + def user_classified_to_bd(self): + logger.info(f'[user_classified_to_bd] Datos que se van a guardar en bd:\n{self.merged_to_db_df.to_string()}') + self.merged_to_db_df.to_sql(name='USER_CLASSIFICATION', con=self.db_connection, if_exists='append', index=False) + + + @try_pass_wrapper('Puede que el paso del proceso ed valoración ya exista') + def save_assessment_step(self): + query = f"INSERT INTO ASSESSMENT_STEPS VALUES ({self.id_assessment}, \"CLASSIFICATION\");" + logger.info(f"[save_assessment_step] Query a base de datos para guardar el paso del proceso de valoracion: \n{query}") + self.db_connection.execute(text(query)) + + + @handler_wrapper('Obteniendo datos de puc historicos originales', 'Datos de puc originales obtenidos con exito', 'Error obteniendo datos de puc historicos', 'Error obteniendo datos de pucs historicos') + def get_original_puc_data(self): + classification_dates_str = str(self.classification_dates).replace('{','').replace('}','') + query = f"""SELECT C.ID_ARCHIVE, C.ACCOUNT_NUMBER, C.CHECKED_BALANCE AS value, C.ACCOUNT_NAME FROM COMPANY A, ARCHIVE B, ORIGINAL_PUC C WHERE A.ID = B.ID_COMPANY AND B.ID = C.ID_ARCHIVE AND B.INITIAL_DATE IN ({classification_dates_str}) AND A.ID = {self.id_company}""" + logger.info(f'[get_company_archive_info] Query para pedir la información del assessment:\n{query}') + rds_data = self.db_connection.execute(text(query)) + self.full_historic_data = [row._asdict() for row in rds_data.fetchall()] + for row in self.full_historic_data: + row['value'] = float(row['value']) + row['nivel'] = len(row['ACCOUNT_NUMBER']) + + + @handler_wrapper('Balanceando numeros de cuentas entre pucs historicos', 'Balanceado de pucs historics exitoso', 'Error balanceando cuentas de pucs historicos', 'Error construyendo cuentas para balanceado de pucs historicos') + def balance_pucs_accounts(self): + assessment_id_archives = set(row['ID_ARCHIVE'] for row in self.full_historic_data) + archives_accounts_directory = {archive: list() for archive in assessment_id_archives} + all_historic_account_numbers = set() + for row in self.full_historic_data: + all_historic_account_numbers.add(row['ACCOUNT_NUMBER']) + archives_accounts_directory[row['ID_ARCHIVE']].append(row['ACCOUNT_NUMBER']) + for archive, this_archive_accounts in archives_accounts_directory.items(): + this_archive_missing_accounts = [item for item in all_historic_account_numbers if item not in this_archive_accounts] + logger.warning(f'[balance_pucs_accounts] al archive {archive} le hacen falta las cuentas {this_archive_missing_accounts}') + for account_number in this_archive_missing_accounts: + self.full_historic_data.append({'ACCOUNT_NUMBER': account_number, 'ACCOUNT_NAME': 'Cuenta creada para balanceo de pucs historicos', 'value': 0, 'ID_ARCHIVE': archive, 'nivel': len(account_number)}) + #Estas cuentas que se van a crear para equilibrio, no requieren estar clasificadas, porque serán clasificadas por el merge de clasificacion de todas formas + + @handler_wrapper('Clasificando los pucs historicos totales', 'Pucs historicos clasificados con exito', 'Error clasificando pucs historicos', 'Error clasificando historicos con clasificaciones de usuario') + def re_classify_all_historic_pucs(self): + for merged_item in self.merged_to_db_df.to_dict(orient = 'records'): + filtered_items = [row for row in self.full_historic_data if row['ACCOUNT_NUMBER'].startswith(merged_item['ACCOUNT_NUMBER'])] + for row in filtered_items: + row['classification'] = self.id_classification_dict[merged_item['ID_RAW_CLASSIFICATION']] + + + + def response_maker(self, succesfull_run = False, error_str = str): + if succesfull_run: + self.final_response['statusCode'] = 200 + self.final_response['body'] = json.dumps('ok') + self.db_connection.commit() if __name__ != 'lambda_function' else None + + else: + self.final_response['body'] = json.dumps(self.detailed_raise if self.detailed_raise else error_str) + self.db_connection.rollback() if self.db_connection and __name__ != 'lambda_function' else None + + if self.db_connection: + self.db_connection.close() + return self.final_response + + +def get_current_error_line(): + return str(sys.exc_info()[-1].tb_lineno) + + +if __name__ == "__main__": + event = {'body': '{"id_assessment":2013,"data":[{"date":"2023-12-31","data":[{"initial_date":"2023-12-31","account":"1","balance":371542.84,"name":"ACTIVO","chapter":"Activo","nivel":1,"classification":"No aplica","status":true},{"initial_date":"2023-12-31","account":"11","balance":207084.24,"name":"Disponible","chapter":"Activo","nivel":2,"classification":"No aplica","status":true},{"initial_date":"2023-12-31","account":"1105","balance":6.97,"name":"Caja","chapter":"Activo","nivel":4,"classification":"Efectivo y no operacionales","status":true},{"initial_date":"2023-12-31","account":"110505","balance":6.97,"name":"Efectivo","chapter":"Activo","nivel":6,"classification":"Efectivo y no operacionales","status":true},{"initial_date":"2023-12-31","account":"1105050001","balance":3.19,"name":"Efectivo USD","chapter":"Activo","nivel":10,"classification":"Efectivo y no operacionales","status":true},{"initial_date":"2023-12-31","account":"1105053001","balance":2.3,"name":"Administracion Caja Menor","chapter":"Activo","nivel":10,"classification":"Efectivo y no operacionales","status":true},{"initial_date":"2023-12-31","account":"1105059501","balance":1.48,"name":"Vales Entregados Sodexo","chapter":"Activo","nivel":10,"classification":"Efectivo y no operacionales","status":true},{"initial_date":"2023-12-31","account":"110510","balance":0,"name":"Cheques","chapter":"Activo","nivel":6,"classification":"Efectivo y no operacionales","status":true},{"initial_date":"2023-12-31","account":"1105100001","balance":0,"name":"Caja Principal","chapter":"Activo","nivel":10,"classification":"Efectivo y no operacionales","status":true},{"initial_date":"2023-12-31","account":"1110","balance":166319.94,"name":"Banco De La Republica","chapter":"Activo","nivel":4,"classification":"No aplica","status":true},{"initial_date":"2023-12-31","account":"111005","balance":166319.94,"name":"Cuenta Corriente Bancaria","chapter":"Activo","nivel":6,"classification":"No aplica","status":true},{"initial_date":"2023-12-31","account":"1110050005","balance":0,"name":"Banco de La Republica Compen","chapter":"Activo","nivel":10,"classification":"No aplica","status":true},{"initial_date":"2023-12-31","account":"1110050006","balance":166304.46,"name":"Banco de La Republica Compen","chapter":"Activo","nivel":10,"classification":"No aplica","status":true},{"initial_date":"2023-12-31","account":"1110050010","balance":15.48,"name":"Banco Republica - Administraci","chapter":"Activo","nivel":10,"classification":"No aplica","status":true},{"initial_date":"2023-12-31","account":"1115","balance":40757.33,"name":"Bancos y Otras Entidades Fi","chapter":"Activo","nivel":4,"classification":"No aplica","status":true},{"initial_date":"2023-12-31","account":"111505","balance":40757.33,"name":"Bancos","chapter":"Activo","nivel":6,"classification":"No aplica","status":true},{"initial_date":"2023-12-31","account":"1115050001","balance":15745.67,"name":"Bancos Cuenta Corriente","chapter":"Activo","nivel":10,"classification":"No aplica","status":true},{"initial_date":"2023-12-31","account":"1115050002","balance":25011.66,"name":"Bancos Cuenta de Ahorros","chapter":"Activo","nivel":10,"classification":"No aplica","status":true},{"initial_date":"2023-12-31","account":"13","balance":53436.79,"name":"Inversiones","chapter":"Activo","nivel":2,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1301","balance":0,"name":"Inversiones Valor Razonable","chapter":"Activo","nivel":4,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"130115","balance":0,"name":"Otros Emisores Nacionales","chapter":"Activo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1301150005","balance":0,"name":"CDT Moneda Nacional","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1302","balance":53436.79,"name":"Inver Negociables Titu Partici","chapter":"Activo","nivel":4,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"130205","balance":53436.79,"name":"Particip en Fondos Comunes Ord","chapter":"Activo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1302050001","balance":45548.2,"name":"Carteras Colectivas Abiertas","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1302050002","balance":7888.58,"name":"Carteras Colectivas Pacto Perm","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1306","balance":0,"name":"Inver Negociables Titu Partici","chapter":"Activo","nivel":4,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"130605","balance":0,"name":"Particip En Fondos Comunes Ord","chapter":"Activo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1306050001","balance":0,"name":"Carteras Colectivas Abiertas","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"130606","balance":0,"name":"Particip En Fondos Comunes Esp","chapter":"Activo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1306060006","balance":0,"name":"Carteras Colectivas Pacto Perm","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1308","balance":0,"name":"Inversiones Para Mantener Hast","chapter":"Activo","nivel":4,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"130811","balance":0,"name":"Titulos Emitidos, Avalados, Ac","chapter":"Activo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1308110005","balance":0,"name":"CDT Moneda Nacional","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"16","balance":73345.28,"name":"Cuentas Por Cobrar","chapter":"Activo","nivel":2,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1614","balance":41979.67,"name":"Venta de bienes y servicios","chapter":"Activo","nivel":4,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"161405","balance":0,"name":"Bienes","chapter":"Activo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1614050001","balance":0,"name":"Venta de Bienes","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"161410","balance":41979.67,"name":"Servicios","chapter":"Activo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1614100001","balance":41979.67,"name":"Servicios PSE,SOI, ACH, SWIFT","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1614100002","balance":0,"name":"Ingresos Patrocinio Seminarios","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1614100003","balance":0,"name":"Clientes Extranjeros","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1614100004","balance":0,"name":"Clientes pendientes de factura","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"161415","balance":0,"name":"Transferencia de fondos de com","chapter":"Activo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1614151510","balance":0,"name":"Transferencia Fondos Compensac","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1630","balance":29390.01,"name":"Venta De Bienes Y Servicios","chapter":"Activo","nivel":4,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"163005","balance":14504.08,"name":"BIENES","chapter":"Activo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1630050005","balance":14504.08,"name":"Anticipo de Impto Renta y Comp","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1630050006","balance":0,"name":"Anticipo Sobretasa Renta y Com","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1630051215","balance":0,"name":"Sobrante en Liquidacion Renta","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"163010","balance":4.64,"name":"Servicios","chapter":"Activo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1630100001","balance":0,"name":"Servicios PSE,SOI, ACH, SWIFT","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1630100002","balance":0,"name":"Ingresos Patrocinio Seminarios","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1630100003","balance":0,"name":"Clientes Exterior_Serv_SWIFT","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1630103505","balance":4.64,"name":"ICA Retenido","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"163015","balance":14881.29,"name":"Transferencia De Fondos","chapter":"Activo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1630150010","balance":0,"name":"Transferencia Fondos Compensac","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1630151005","balance":0,"name":"otros Ing. trib 2.5%","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1630151006","balance":0,"name":"Servicios Generales","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1630151008","balance":0,"name":"Compras generales 2.5%","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1630151009","balance":543.87,"name":"Retefuente Rendim Financier 7%","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1630151036","balance":0,"name":"Autoretención CREE 0.8%","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1630151045","balance":0,"name":"Autorretención CREE Rend Finan","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1630151047","balance":107.04,"name":"Autorretención RENTA Rend Fina","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1630151048","balance":2957.57,"name":"Autoretención RENTA 0.8%","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1630151049","balance":11272.81,"name":"Autoretención Servicios 4%","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"163040","balance":0,"name":"Impuesto a las ventas","chapter":"Activo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1630401220","balance":0,"name":"Saldo a Favor IVA","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"163045","balance":0,"name":"Impuesto sobre la renta para l","chapter":"Activo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1630451225","balance":0,"name":"ANTICIPO SOBRETASA CREE","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1632","balance":0,"name":"Anticipos a contratos y provee","chapter":"Activo","nivel":4,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"163205","balance":0,"name":"Anticipos a contratos y provee","chapter":"Activo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1632050001","balance":0,"name":"Anticipos Contratos","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"163210","balance":0,"name":"Anticipos a contratos y provee","chapter":"Activo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1632100001","balance":0,"name":"Anticipos Proveedores","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1634","balance":1.22,"name":"A empleados","chapter":"Activo","nivel":4,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"163495","balance":1.22,"name":"Otros","chapter":"Activo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1634950005","balance":0.53,"name":"Anticipo para Gastos Viaje","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1634950006","balance":0.68,"name":"Anticipos Laborales","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1635","balance":0,"name":"PAGOS POR CUENTA DE CLIENTE","chapter":"Activo","nivel":4,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"163595","balance":0,"name":"OTROS","chapter":"Activo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1645","balance":0,"name":"Anticipos De Contratos Y Pr","chapter":"Activo","nivel":4,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"164505","balance":0,"name":"Anticipos De Contratos","chapter":"Activo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1645050001","balance":0,"name":"Anticipos Contratos","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"164510","balance":0,"name":"Anticipo De Proveedores","chapter":"Activo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1645100001","balance":0,"name":"Anticipos Proveedores","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1655","balance":0,"name":"Adelantos Al Personal","chapter":"Activo","nivel":4,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"165505","balance":0,"name":"Anticipos A Empleados","chapter":"Activo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1655050005","balance":0,"name":"Anticipos Laborales","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"165510","balance":0,"name":"Anticipo De Gastos De Viaje","chapter":"Activo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1655100005","balance":0,"name":"Anticipo para Gastos Viaje","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1687","balance":0,"name":"Diversas","chapter":"Activo","nivel":4,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"168795","balance":0,"name":"Otras","chapter":"Activo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1687950005","balance":0,"name":"Deudores Sancion Interinstituc","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1687950006","balance":0,"name":"Deudores empleados_Med prepag","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1687950007","balance":0,"name":"Deudores empleados_Movistar","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1687950008","balance":0,"name":"Deudores empleados_Libranzas","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1687950009","balance":0,"name":"Deudores empleados_Otros Concp","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1687950013","balance":0,"name":"Deudores por Incapacidad EPS","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1687950090","balance":0,"name":"Cuenta por cobrar a terceros","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1687950095","balance":0,"name":"Otros","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1690","balance":1976.91,"name":"Diversas","chapter":"Activo","nivel":4,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"169095","balance":1976.91,"name":"Otras","chapter":"Activo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1690950005","balance":65.93,"name":"Deudores Sancion Interinstituc","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1690950006","balance":1.04,"name":"Deudores empleados_Med prepag","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1690950007","balance":0.23,"name":"Deudores empleados_Movistar","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1690950008","balance":0,"name":"Deudores empleados_Libranzas","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1690950009","balance":0,"name":"Deudores empleados_Otros Concp","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1690950090","balance":1911.79,"name":"Cuenta por cobrar a terceros","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1690950095","balance":0,"name":"Otros","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1694","balance":2.53,"name":"Provisión Cuentas Por Cobrar","chapter":"Activo","nivel":4,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"169430","balance":2.53,"name":"Venta De Bienes Y Servicios","chapter":"Activo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1694300005","balance":2.53,"name":"Servic por Traferencia Electro","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"18","balance":3423.44,"name":"Propiedades Y Equipo","chapter":"Activo","nivel":2,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2023-12-31","account":"1801","balance":2901.1,"name":"Propiedad, planta y equipo","chapter":"Activo","nivel":4,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2023-12-31","account":"180104","balance":0,"name":"Edificios","chapter":"Activo","nivel":6,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2023-12-31","account":"1801040005","balance":0,"name":"Activo por desmantelamiento of","chapter":"Activo","nivel":10,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2023-12-31","account":"180112","balance":411.09,"name":"Vehículos","chapter":"Activo","nivel":6,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2023-12-31","account":"1801120510","balance":411.09,"name":"Vehiculos/Leasing Financiero","chapter":"Activo","nivel":10,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2023-12-31","account":"180120","balance":1999.47,"name":"Enseres","chapter":"Activo","nivel":6,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2023-12-31","account":"1801200505","balance":1999.47,"name":"Muebles y Enseres","chapter":"Activo","nivel":10,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2023-12-31","account":"180122","balance":89.74,"name":"Equipo","chapter":"Activo","nivel":6,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2023-12-31","account":"1801220510","balance":89.74,"name":"Equipos de Oficina","chapter":"Activo","nivel":10,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2023-12-31","account":"180124","balance":20316.58,"name":"Equipo Informático","chapter":"Activo","nivel":6,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2023-12-31","account":"1801240505","balance":2783.01,"name":"Equipos de Computo","chapter":"Activo","nivel":10,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2023-12-31","account":"1801240510","balance":14649.06,"name":"Leasing Equipos de Computo","chapter":"Activo","nivel":10,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2023-12-31","account":"1801240515","balance":2884.51,"name":"Equipos de Seguridad Informati","chapter":"Activo","nivel":10,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2023-12-31","account":"180126","balance":2515.31,"name":"Equipo de Redes y Comunicación","chapter":"Activo","nivel":6,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2023-12-31","account":"1801261005","balance":2515.31,"name":"Equipos de Telecomunicaciones","chapter":"Activo","nivel":10,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2023-12-31","account":"180160","balance":0,"name":"Revaluación Propiedad, Planta","chapter":"Activo","nivel":6,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2023-12-31","account":"1801602410","balance":0,"name":"Leasing Equipos de Computo","chapter":"Activo","nivel":10,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2023-12-31","account":"180162","balance":22431.09,"name":"Depreciación y Agotamiento pro","chapter":"Activo","nivel":6,"classification":"Depreciación acumulada","status":true},{"initial_date":"2023-12-31","account":"1801620405","balance":0,"name":"Activo por desmantelamiento of","chapter":"Activo","nivel":10,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2023-12-31","account":"1801621005","balance":1647.25,"name":"Muebles y Enseres","chapter":"Activo","nivel":10,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2023-12-31","account":"1801621505","balance":2054.22,"name":"Equipos de Computo","chapter":"Activo","nivel":10,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2023-12-31","account":"1801621506","balance":2845.8,"name":"Equipos de Seguridad Inform","chapter":"Activo","nivel":10,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2023-12-31","account":"1801621507","balance":1630.59,"name":"Equipo de telecomunicaciones","chapter":"Activo","nivel":10,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2023-12-31","account":"1801621510","balance":14077.76,"name":"Leasing Equipos de Computo","chapter":"Activo","nivel":10,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2023-12-31","account":"1801622010","balance":130.78,"name":"Vehiculos/Leasing Financiero","chapter":"Activo","nivel":10,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2023-12-31","account":"1801622210","balance":44.69,"name":"Equipos de Oficina","chapter":"Activo","nivel":10,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2023-12-31","account":"1801622215","balance":0,"name":"Leasing Equipos de Oficina","chapter":"Activo","nivel":10,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2023-12-31","account":"180195","balance":0,"name":"Otros Equipos Máquina Montaje","chapter":"Activo","nivel":6,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2023-12-31","account":"1801950001","balance":0,"name":"Otros Equipos/Máquinas en Mont","chapter":"Activo","nivel":10,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2023-12-31","account":"1818","balance":522.34,"name":"Mejoras propiedad Ajena","chapter":"Activo","nivel":4,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2023-12-31","account":"181805","balance":1751.57,"name":"Mejora en Propiedad planta y","chapter":"Activo","nivel":6,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2023-12-31","account":"1818050501","balance":1751.57,"name":"Mejoras en propiedades Ajenas","chapter":"Activo","nivel":10,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2023-12-31","account":"181897","balance":1229.23,"name":"DEPRECIACION DE ACTIVOS MEJORA","chapter":"Activo","nivel":6,"classification":"Depreciación acumulada","status":true},{"initial_date":"2023-12-31","account":"1818970501","balance":1229.23,"name":"DEPRECIACION Y/O AMORTIZACION","chapter":"Activo","nivel":10,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2023-12-31","account":"1820","balance":0,"name":"Equipo, Muebles Y Enseres D","chapter":"Activo","nivel":4,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2023-12-31","account":"182005","balance":0,"name":"Muebles Y Enseres","chapter":"Activo","nivel":6,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2023-12-31","account":"1820050005","balance":0,"name":"Muebles y Enseres","chapter":"Activo","nivel":10,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2023-12-31","account":"1820050010","balance":0,"name":"Equipos de Oficina","chapter":"Activo","nivel":10,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2023-12-31","account":"1825","balance":0,"name":"Equipo De Computación","chapter":"Activo","nivel":4,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2023-12-31","account":"182505","balance":0,"name":"Equipos De Procesamiento De","chapter":"Activo","nivel":6,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2023-12-31","account":"1825050005","balance":0,"name":"Equipos de Computo","chapter":"Activo","nivel":10,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2023-12-31","account":"1825050015","balance":0,"name":"Equipos de Seguridad Informati","chapter":"Activo","nivel":10,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2023-12-31","account":"182510","balance":0,"name":"Equipos De Telecomunicación","chapter":"Activo","nivel":6,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2023-12-31","account":"1825100005","balance":0,"name":"Equipos de Telecomunicaciones","chapter":"Activo","nivel":10,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2023-12-31","account":"1830","balance":0,"name":"Vehículos","chapter":"Activo","nivel":4,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2023-12-31","account":"183005","balance":0,"name":"Vehiculos","chapter":"Activo","nivel":6,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2023-12-31","account":"1830050010","balance":0,"name":"Vehiculos/Leasing Financiero","chapter":"Activo","nivel":10,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2023-12-31","account":"1895","balance":0,"name":"Depreciación y Amortización","chapter":"Activo","nivel":4,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2023-12-31","account":"189510","balance":0,"name":"Equipo, Muebles Y Enseres D","chapter":"Activo","nivel":6,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2023-12-31","account":"1895100005","balance":0,"name":"Muebles y Enseres Equip Ofic","chapter":"Activo","nivel":10,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2023-12-31","account":"189515","balance":0,"name":"Equipo De Computación","chapter":"Activo","nivel":6,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2023-12-31","account":"1895150005","balance":0,"name":"Equipos de Computo","chapter":"Activo","nivel":10,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2023-12-31","account":"1895150006","balance":0,"name":"Equipos de Seguridad Inform","chapter":"Activo","nivel":10,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2023-12-31","account":"1895150007","balance":0,"name":"Equipo de telecomunicaciones","chapter":"Activo","nivel":10,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2023-12-31","account":"189520","balance":0,"name":"Vehiculos - Leasing Financiero","chapter":"Activo","nivel":6,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2023-12-31","account":"1895200010","balance":0,"name":"Vehículos Leasing Financiero","chapter":"Activo","nivel":10,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2023-12-31","account":"1899","balance":0,"name":"Provisión Propiedades y Equipo","chapter":"Activo","nivel":4,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2023-12-31","account":"189905","balance":0,"name":"Provisión Propiedades y Equipo","chapter":"Activo","nivel":6,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2023-12-31","account":"1899050005","balance":0,"name":"Provision Propiedades y Equipo","chapter":"Activo","nivel":10,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2023-12-31","account":"19","balance":34253.11,"name":"Otros Activos","chapter":"Activo","nivel":2,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1910","balance":8721.31,"name":"Impuesto Diferido NIIF","chapter":"Activo","nivel":4,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"191005","balance":8721.31,"name":"Impuesto Diferido Activo","chapter":"Activo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1910050005","balance":8721.31,"name":"IMPUESTO_ DIFERIDO_ ACTIVO","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1911","balance":17230.67,"name":"Activos Intangibles","chapter":"Activo","nivel":4,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"191135","balance":61031.95,"name":"Programas y aplicaciones infor","chapter":"Activo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1911350005","balance":61031.95,"name":"Software Administracion","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"191160","balance":7167.54,"name":"Otros activos intangibles","chapter":"Activo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1911600005","balance":419.49,"name":"Proyectos Area","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1911600010","balance":6713.8,"name":"Proyectos Compañía","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1911600015","balance":34.25,"name":"Proyectos Mandatorio","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"191165","balance":50968.83,"name":"AMORTIZACION ACUMULADA","chapter":"Activo","nivel":6,"classification":"Amortización acumulada","status":true},{"initial_date":"2023-12-31","account":"1911650505","balance":47704.27,"name":"Amortización - Software Admini","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1911651005","balance":399.51,"name":"Amortización - Proyectos Área","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1911651010","balance":2830.8,"name":"Amortización - Proyectos Compa","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1911651015","balance":34.25,"name":"Software/licencia operación Am","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1912","balance":0,"name":"Aportes Permanentes","chapter":"Activo","nivel":4,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"191210","balance":0,"name":"Clubes Sociales","chapter":"Activo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1912100005","balance":0,"name":"Club Social","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1915","balance":0,"name":"Gastos Anticipados","chapter":"Activo","nivel":4,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"191510","balance":0,"name":"Seguros","chapter":"Activo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1915100001","balance":0,"name":"Seguros","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"191515","balance":0,"name":"ARRENDAMIENTOS","chapter":"Activo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"191535","balance":0,"name":"Mantenimiento Equipos","chapter":"Activo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1915350001","balance":0,"name":"Mantenimiento de equipos","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1915350002","balance":0,"name":"Mantenimiento de programas","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1915350005","balance":0,"name":"Servicios","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"191595","balance":0,"name":"Otros","chapter":"Activo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1915950010","balance":0,"name":"OTROS GASTOS ANTICIPADOS","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1920","balance":0,"name":"Cargos Diferidos","chapter":"Activo","nivel":4,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"192015","balance":0,"name":"Estudios Y Proyectos","chapter":"Activo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1920150005","balance":0,"name":"Proyectos Area","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1920150010","balance":0,"name":"Proyectos Compañía","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1920150015","balance":0,"name":"Proyectos Mandatorio","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"192020","balance":0,"name":"Programas Para Computador","chapter":"Activo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1920200005","balance":0,"name":"Software Administracion","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"192040","balance":0,"name":"Impuesto De Renta Diferido","chapter":"Activo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1920400005","balance":0,"name":"Impuesto de Renta Diferido","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1920400006","balance":0,"name":"Impuesto Renta Diferido CREE","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"192055","balance":0,"name":"Contribuciones y Afiliaciones","chapter":"Activo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1920550005","balance":0,"name":"Contribuciones y Afiliaciones","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1925","balance":8301.13,"name":"Gastos pagados por anticipado","chapter":"Activo","nivel":4,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"192505","balance":1202.5,"name":"Seguros","chapter":"Activo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1925050001","balance":1202.5,"name":"Seguros","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"192595","balance":7098.63,"name":"Otros","chapter":"Activo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1925950010","balance":752.17,"name":"OTROS GASTOS ANTICIPADOS","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1925953501","balance":249.89,"name":"Mantenimiento de equipos","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1925953502","balance":1155.36,"name":"Mantenimiento de programas","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1925953505","balance":1909.52,"name":"Servicios","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1925955005","balance":3031.69,"name":"Contribuciones y Afiliaciones","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1990","balance":0,"name":"Diversos","chapter":"Activo","nivel":4,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"199005","balance":0,"name":"ANTICIPOS IMPORRENTA","chapter":"Activo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"199010","balance":0,"name":"Retención En La Fuente","chapter":"Activo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1990100006","balance":0,"name":"Servicios Generales","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1990100008","balance":0,"name":"Compras generales 2.5%","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1990100009","balance":0,"name":"Retefuente Rendim Financier 7%","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1990100036","balance":0,"name":"Autoretención CREE 0.8%","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1990100045","balance":0,"name":"Autorretención CREE Rend Finan","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"199012","balance":0,"name":"Sobrantes De Anticipos Y Re","chapter":"Activo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1990120015","balance":0,"name":"Sobrante en Liquidacion Renta","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1990120020","balance":0,"name":"Saldo a Favor IVA","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1990120025","balance":0,"name":"ANTICIPO SOBRETASA CREE","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"199030","balance":0,"name":"Caja Menor","chapter":"Activo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1990300001","balance":0,"name":"Administracion Caja Menor","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"199035","balance":0,"name":"Anticipo Impuesto De Industria","chapter":"Activo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1990350005","balance":0,"name":"ICA Retenido","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"199095","balance":0,"name":"Otros","chapter":"Activo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1990950001","balance":0,"name":"Vales Entregados Sodexo","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1995","balance":0,"name":"Valorizaciones","chapter":"Activo","nivel":4,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"199510","balance":0,"name":"Propiedades Y Equipo","chapter":"Activo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"1995100005","balance":0,"name":"Propiedad Planta y Equipo","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2","balance":261718.02,"name":"PASIVO","chapter":"Pasivo","nivel":1,"classification":"No aplica","status":true},{"initial_date":"2023-12-31","account":"24","balance":1000,"name":"Créditos De Bancos y Otras","chapter":"Pasivo","nivel":2,"classification":"Deuda con costo financiero","status":true},{"initial_date":"2023-12-31","account":"2404","balance":0,"name":"Dividendos Por Pagar","chapter":"Pasivo","nivel":4,"classification":"Deuda con costo financiero","status":true},{"initial_date":"2023-12-31","account":"240405","balance":0,"name":"Dividendos Por Pagar","chapter":"Pasivo","nivel":6,"classification":"Deuda con costo financiero","status":true},{"initial_date":"2023-12-31","account":"2404050505","balance":0,"name":"Dividendos por Pagar","chapter":"Pasivo","nivel":10,"classification":"Deuda con costo financiero","status":true},{"initial_date":"2023-12-31","account":"2430","balance":0,"name":"Otros Bancos Y Entidades Fi","chapter":"Pasivo","nivel":4,"classification":"Deuda con costo financiero","status":true},{"initial_date":"2023-12-31","account":"243005","balance":0,"name":"Créditos","chapter":"Pasivo","nivel":6,"classification":"Deuda con costo financiero","status":true},{"initial_date":"2023-12-31","account":"2430050005","balance":0,"name":"Bancolombia Tarjeta de Credito","chapter":"Pasivo","nivel":10,"classification":"Deuda con costo financiero","status":true},{"initial_date":"2023-12-31","account":"2435","balance":1000,"name":"Otros bancos y entidades finan","chapter":"Pasivo","nivel":4,"classification":"Deuda con costo financiero","status":true},{"initial_date":"2023-12-31","account":"243505","balance":3.36,"name":"Créditos","chapter":"Pasivo","nivel":6,"classification":"Deuda con costo financiero","status":true},{"initial_date":"2023-12-31","account":"2435050005","balance":3.36,"name":"Bancolombia Tarjeta de Credito","chapter":"Pasivo","nivel":10,"classification":"Deuda con costo financiero","status":true},{"initial_date":"2023-12-31","account":"243560","balance":996.65,"name":"Contratos de arrendamiento fin","chapter":"Pasivo","nivel":6,"classification":"Deuda con costo financiero","status":true},{"initial_date":"2023-12-31","account":"2435600001","balance":110.82,"name":"Arrendamientos Leasing","chapter":"Pasivo","nivel":10,"classification":"Deuda con costo financiero","status":true},{"initial_date":"2023-12-31","account":"2435600002","balance":838.74,"name":"Obligacion Financiera Leasing","chapter":"Pasivo","nivel":10,"classification":"Deuda con costo financiero","status":true},{"initial_date":"2023-12-31","account":"2435600004","balance":45.87,"name":"Obligacion Financiera Leasing","chapter":"Pasivo","nivel":10,"classification":"Deuda con costo financiero","status":true},{"initial_date":"2023-12-31","account":"2435600006","balance":1.22,"name":"Obligacion Financiera Leasing","chapter":"Pasivo","nivel":10,"classification":"Deuda con costo financiero","status":true},{"initial_date":"2023-12-31","account":"2435600008","balance":0,"name":"Obligacion Financiera Leasing","chapter":"Pasivo","nivel":10,"classification":"Deuda con costo financiero","status":true},{"initial_date":"2023-12-31","account":"2435600009","balance":0,"name":"Obligacion Financiera Leasing","chapter":"Pasivo","nivel":10,"classification":"Deuda con costo financiero","status":true},{"initial_date":"2023-12-31","account":"2435600010","balance":0,"name":"Obligación Financiera Leasing","chapter":"Pasivo","nivel":10,"classification":"Deuda con costo financiero","status":true},{"initial_date":"2023-12-31","account":"2435600011","balance":0,"name":"Leasing 180-119248","chapter":"Pasivo","nivel":10,"classification":"Deuda con costo financiero","status":true},{"initial_date":"2023-12-31","account":"2435600012","balance":0,"name":"Obligacion Financiera Renting","chapter":"Pasivo","nivel":10,"classification":"Deuda con costo financiero","status":true},{"initial_date":"2023-12-31","account":"2495","balance":0,"name":"Otras Obligaciones Financieras","chapter":"Pasivo","nivel":4,"classification":"Deuda con costo financiero","status":true},{"initial_date":"2023-12-31","account":"249595","balance":0,"name":"Otras","chapter":"Pasivo","nivel":6,"classification":"Deuda con costo financiero","status":true},{"initial_date":"2023-12-31","account":"2495950010","balance":0,"name":"Otras Obligaciones Financieras","chapter":"Pasivo","nivel":10,"classification":"Deuda con costo financiero","status":true},{"initial_date":"2023-12-31","account":"25","balance":252240.38,"name":"Cuentas Por Pagar","chapter":"Pasivo","nivel":2,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2501","balance":2720.02,"name":"Comisiones","chapter":"Pasivo","nivel":4,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"250105","balance":2720.02,"name":"Honorarios","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2501050005","balance":1384.02,"name":"Honorarios Profesionales","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2501050006","balance":0,"name":"Honorarios Profesionales Extra","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2501050010","balance":1336,"name":"Honorarios Profesionales Prov.","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2502","balance":3332.92,"name":"Costos y gastos por pagar","chapter":"Pasivo","nivel":4,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"250205","balance":3332.92,"name":"Servicios","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2502059510","balance":17.22,"name":"Servicios Publicos","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2502059530","balance":0,"name":"Servicios en General","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2502059535","balance":3315.7,"name":"Servicios en General Prov.","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"250220","balance":0,"name":"Gastos de viaje","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2502209512","balance":0,"name":"Gastos de Viajes","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2502209515","balance":0,"name":"Gastos de Viajes","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2503","balance":61169.24,"name":"Impuestos","chapter":"Pasivo","nivel":4,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"250305","balance":56488.32,"name":"Renta y complementarios","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2503050501","balance":56488.32,"name":"De Renta y Complementarios","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"250310","balance":1147.05,"name":"Industria y comercio","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2503100001","balance":0.21,"name":"Retencion ICA 0.414%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2503100002","balance":24.67,"name":"Retencion ICA 0.69%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2503100003","balance":30.68,"name":"Retencion ICA 0.966%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2503100004","balance":1.43,"name":"Retencion ICA 1.104%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2503100006","balance":1.64,"name":"Retencion ICA 1.38%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2503100007","balance":0,"name":"Retencion ICA Retencion ICA-0,712%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2503100008","balance":0.62,"name":"Retencion ICA 0,766%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2503100009","balance":1.88,"name":"Retencion ICA 0,866%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2503101005","balance":1085.92,"name":"Industria y Comercio","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"250330","balance":0,"name":"CREE","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"250339","balance":0,"name":"cuenta autogenerada para chequeo de capitulos","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2503395001","balance":0,"name":"Impuesto a la Equidad CREE","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2503395002","balance":0,"name":"Sobretasa_CREE","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"250340","balance":3533.88,"name":"Sobre las ventas por pagar","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2503400005","balance":11.7,"name":"Iva Generado 16 %","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2503400006","balance":0,"name":"IVA Descontable Compras 16%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2503400007","balance":4788.1,"name":"Iva Generado 19%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2503400012","balance":5.13,"name":"IVA Descontable Compras 19%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2503400013","balance":0.02,"name":"IVA Descontable 5% - Compras","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2503400014","balance":0,"name":"IVA Descontable 5% - Servicios","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2503400021","balance":0,"name":"IVA Desc.Reg.Simplific.(2.4%)","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2503400024","balance":1226.94,"name":"IVA Descontable Servicios 19%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2503400025","balance":0,"name":"IVA Descontable Servicios 16%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2503400026","balance":33.83,"name":"IVA_Asumido_Compras_Exterior","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2504","balance":110.04,"name":"Dividendos y excedentes","chapter":"Pasivo","nivel":4,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"250405","balance":110.04,"name":"Dividendos","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2504050505","balance":110.04,"name":"Dividendos por Pagar","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2505","balance":87.69,"name":"Arrendamientos","chapter":"Pasivo","nivel":4,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"250540","balance":87.69,"name":"Arrendamientos","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2505400005","balance":87.69,"name":"Arrendamientos Administrativos","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2510","balance":0,"name":"Comisiones Y Honorarios","chapter":"Pasivo","nivel":4,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"251010","balance":0,"name":"Honorarios","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2510100005","balance":0,"name":"Honorarios Profesionales","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2515","balance":0,"name":"Impuestos","chapter":"Pasivo","nivel":4,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"251505","balance":0,"name":"RENTA Y COMPLEMENTARIOS","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"251510","balance":0,"name":"Industria Y Comercio","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2515100001","balance":0,"name":"Retencion ICA 0.414%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2515100002","balance":0,"name":"Retencion ICA 0.69%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2515100003","balance":0,"name":"Retencion ICA 0.966%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2515100004","balance":0,"name":"Retencion ICA 1.104%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2515100005","balance":0,"name":"Vigencia Fiscal Corriente","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2515100006","balance":0,"name":"Retencion ICA 1.38%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"251595","balance":0,"name":"Sobretasas Y Otros","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2515950011","balance":0,"name":"Impuesto al Patrimonio","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2515950012","balance":0,"name":"Impuesto a La Equidad CREE","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2519","balance":2734.09,"name":"Retenciones y aportes laborale","chapter":"Pasivo","nivel":4,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"251910","balance":0,"name":"Judiciales","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2519100001","balance":0,"name":"Embargos Judiciales a empleado","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"251945","balance":2734.09,"name":"Retenciones y aportes de nomin","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2519450005","balance":181.38,"name":"Retención fuente por Salarios","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2519450009","balance":0.16,"name":"Retención fuente Servicios 2%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2519450010","balance":103.01,"name":"Honorarios 11 % Declarantes","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2519450015","balance":0,"name":"Honorarios 10 % No Declarantes","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2519450017","balance":0.02,"name":"Retención en la Fuente Honorar","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2519450020","balance":0.15,"name":"Retención fuente Servicios 1%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2519450025","balance":0,"name":"Retención Fuente Serv Temp 2%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2519450030","balance":32.16,"name":"Ret Fte Serv 4% Declarantes","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2519450036","balance":0,"name":"RetFte Contrato Ing Proy 6%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2519450038","balance":93.86,"name":"Retefuente 3.5% Serv Informati","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2519450040","balance":0,"name":"Refte Ser Hot/Rest No Dec 3,5%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2519450043","balance":3.45,"name":"RteFte Serv Hoteles rest 3,5%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2519450044","balance":4.98,"name":"RteFte Arriendo inmuebles 3,5%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2519450047","balance":0,"name":"Rtefte serv transp pasaje 3.5%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2519450050","balance":2.9,"name":"Ret Fte Arriend Bns Mueb 4%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2519450054","balance":0,"name":"Re Fte Pagos al Exterior 15%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2519450055","balance":0,"name":"Ret Fte Compras No Decl 3.5%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2519450057","balance":1.34,"name":"Rete Fte Compras Declaran 2.5%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2519450058","balance":9.14,"name":"Ret Fte Pagos al Exterior 10%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2519450059","balance":0,"name":"Ret Fte Pagos al Exter 26.4%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2519450060","balance":0,"name":"Ret Fte Pagos al Exterior 33 %","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2519450061","balance":33.83,"name":"Ret Fte por IVA Pago Ext 100%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2519450062","balance":16.86,"name":"retención del Exterior por Exp","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2519450064","balance":0,"name":"Ret IVA Reg Simplif 15% (2.4%)","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2519450067","balance":134.97,"name":"Rte IVA Reg Comun 15% (2.4%)","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2519450068","balance":0,"name":"Rte Fte. Dividendos 33%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2519450069","balance":0,"name":"Rte Fte. Dividendos 7.5%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2519450071","balance":0,"name":"Rte Fte Dividendos 35%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2519450073","balance":0,"name":"Rte Fte Dividendos 10%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2519450076","balance":0,"name":"Retención en la Fuente por Com","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2519450078","balance":12.94,"name":"Autorretención RENTA Rend Fina","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2519450079","balance":279.37,"name":"Autorretención RENTA 0,8%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2519450085","balance":0,"name":"Autorretención CREE Rend Finan","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2519450086","balance":0.38,"name":"Retención en la Fuente Consult","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2519450087","balance":0,"name":"Retención en la Fuente Consult","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2519450089","balance":0,"name":"Retención en la Fuente Transpo","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2519450090","balance":0,"name":"Retención en la Fuente Dividen","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2519450092","balance":0,"name":"Rte Fte Comisiones P Jurid 11%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2519450097","balance":0,"name":"Autorretención CREE 0,8%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2519450098","balance":0,"name":"Rte Fte Otros Ing Tribut 4,5%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2519450099","balance":1013.87,"name":"Autoretención Servicios 4%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2519453005","balance":0,"name":"Fondo de Empleados","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2519453505","balance":0,"name":"Aportes a EPS","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2519453506","balance":175.26,"name":"Aportes a EPS Pago","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2519453515","balance":33.82,"name":"Medicina Prepagada Colsanitas","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2519453516","balance":0,"name":"Medicina Prepagada Compensar","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2519453517","balance":1.63,"name":"Medicina Prepagada Medisanitas","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2519453518","balance":0.62,"name":"Medicina prepagada Emermedica","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2519453520","balance":13.02,"name":"Aportes A R L","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2519454005","balance":144.65,"name":"Aport Caja Comp ICBF SENA","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2519459510","balance":0,"name":"Aportes a Fondo de Pension","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2519459511","balance":440.33,"name":"Aportes Fondo de Pensión Pago","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2519459515","balance":0,"name":"Aportes a Fdos Pens Volunt","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2519459520","balance":0,"name":"Aportes a Cuentas AFC","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2520","balance":0,"name":"DIVIDENDOS Y EXCEDENTES","chapter":"Pasivo","nivel":4,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"252005","balance":0,"name":"DIVIDENDOS DECRETADOS","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2525","balance":0,"name":"Arrendamientos","chapter":"Pasivo","nivel":4,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"252540","balance":0,"name":"Arrendamientos","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2525400005","balance":0,"name":"Arrendamientos Administrativos","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2535","balance":0,"name":"Impuesto A Las Ventas Por P","chapter":"Pasivo","nivel":4,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"253505","balance":0,"name":"Iva Generado 16 %","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2535050005","balance":0,"name":"IVA Generado 16%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"253510","balance":0,"name":"Iva Descontable","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2535100005","balance":0,"name":"IVA Descontable Compras 16%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2535100013","balance":0,"name":"IVA Descontable 5% - Compras","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2535100014","balance":0,"name":"IVA Descontable 5% - Servicios","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2535100021","balance":0,"name":"IVA Desc.Reg.Simplific.(2.4%)","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2535100025","balance":0,"name":"IVA Descontable Servicios 16%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2555","balance":0,"name":"Retenciones Y Aportes Laborale","chapter":"Pasivo","nivel":4,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"255505","balance":0,"name":"Retenciones En La Fuente","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2555050005","balance":0,"name":"Retención fuente por Salarios","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2555050009","balance":0,"name":"Retención fuente Servicios 2%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2555050010","balance":0,"name":"Honorarios 11 % Declarantes","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2555050015","balance":0,"name":"Honorarios 10 % No Declarantes","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2555050017","balance":0,"name":"Honorarios IMAN 19% 96 150 UVT","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2555050018","balance":0,"name":"Honorari IMAN 28% 151 360 UVT","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2555050020","balance":0,"name":"Retención fuente Servicios 1%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2555050030","balance":0,"name":"Ret Fte Serv 4% Declarantes","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2555050035","balance":0,"name":"Ret Fte Serv 6 % No Declarante","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2555050038","balance":0,"name":"Retefuente 3.5% Serv Informati","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2555050040","balance":0,"name":"Refte Ser Hot/Rest No Dec 3,5%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2555050043","balance":0,"name":"RteFte Serv Hoteles rest 3,5%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2555050044","balance":0,"name":"RteFte Arriendo inmuebles 3,5%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2555050050","balance":0,"name":"Ret Fte Arriend Bns Mueb 4%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2555050055","balance":0,"name":"Ret Fte Compras No Decl 3.5%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2555050057","balance":0,"name":"Rete Fte Compras Declaran 2.5%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2555050058","balance":0,"name":"Ret Fte Pagos al Exterior 10%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2555050059","balance":0,"name":"Ret Fte Pagos al Exter 26.4%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2555050060","balance":0,"name":"Ret Fte Pagos al Exterior 33 %","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2555050061","balance":0,"name":"Ret Fte por IVA Pago Ext 100%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2555050064","balance":0,"name":"Ret IVA Reg Simplif 15% (2.4%)","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2555050067","balance":0,"name":"Rte IVA Reg Comun 15% (2.4%)","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2555050085","balance":0,"name":"Autorretención CREE Rend Finan","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2555050092","balance":0,"name":"Rte Fte Comisiones P Jurid 11%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2555050097","balance":0,"name":"Autorretención CREE 0,8%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"255525","balance":0,"name":"COOPERATIVAS","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"255530","balance":0,"name":"Fondo De Empleados","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2555300005","balance":0,"name":"Fondo de Empleados","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"255535","balance":0,"name":"Aportes Salud","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2555350005","balance":0,"name":"Aportes a EPS","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2555350006","balance":0,"name":"Aportes a EPS Pago","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2555350015","balance":0,"name":"Medicina Prepagada Colsanitas","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2555350016","balance":0,"name":"Medicina Prepagada Compensar","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2555350017","balance":0,"name":"Medicina Prepagada Medisanitas","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2555350018","balance":0,"name":"Medicina prepagada Emermedica","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2555350020","balance":0,"name":"Aportes A R L","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"255540","balance":0,"name":"Aportes Caja Comp.,SENA,ICBF","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2555400005","balance":0,"name":"Aport Caja Comp ICBF SENA","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"255595","balance":0,"name":"Otros","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2555950010","balance":0,"name":"Aportes a Fondo de Pension","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2555950011","balance":0,"name":"Aportes Fondo de Pensión Pago","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2555950015","balance":0,"name":"Aportes a Fdos Pens Volunt","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2555950020","balance":0,"name":"Aportes a Cuentas AFC","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2590","balance":182086.37,"name":"Diversas","chapter":"Pasivo","nivel":4,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"259095","balance":182086.37,"name":"Otras","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2590951001","balance":19.37,"name":"Salarios por Pagar","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2590959501","balance":8765.46,"name":"Otras Cuentas por Pagar","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2590959502","balance":0,"name":"Banco de La Republica","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2590959503","balance":6996.74,"name":"Otras Cuentas por Pagar Extran","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2590959525","balance":0.14,"name":"Reembolsos Caja Menor","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2590959540","balance":0.2,"name":"Descuentos a Empleados","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2590959597","balance":166304.46,"name":"Cuenta por Pagar Puente TransfiYa","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2590959598","balance":0,"name":"Cuenta Bancaria Compensaci PSE","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2590959599","balance":0,"name":"CXP Pte Compensación BanRepubl","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2590959997","balance":0,"name":"Cta Puente Moduloo AP-AR","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2590959999","balance":0,"name":"Cuenta Puente Autorret ACH","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2595","balance":0,"name":"Diversas","chapter":"Pasivo","nivel":4,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"259510","balance":0,"name":"Nomina","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2595100001","balance":0,"name":"Salarios por Pagar","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"259595","balance":0,"name":"Otras","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2595950001","balance":0,"name":"Otras Cuentas por Pagar","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2595950002","balance":0,"name":"Banco de La Republica","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2595950010","balance":0,"name":"Servicios Publicos","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2595950012","balance":0,"name":"Gastos de Viajes","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2595950025","balance":0,"name":"Reembolsos Caja Menor","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2595950030","balance":0,"name":"Servicios en General","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2595950035","balance":0,"name":"Compras","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2595950040","balance":0,"name":"Descuentos a Empleados","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2595950099","balance":0,"name":"CXP Pte Compensación BanRepubl","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2595959998","balance":0,"name":"Cuenta Bancaria Compensaci PSE","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2595959999","balance":0,"name":"Cuenta Puente Autorret ACH","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"27","balance":7867.09,"name":"Otros Pasivos","chapter":"Pasivo","nivel":2,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2710","balance":1878.61,"name":"Obligaciones Laborales Cons","chapter":"Pasivo","nivel":4,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"271005","balance":1878.61,"name":"Cesantías Consolidadas","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2710050001","balance":1878.61,"name":"Ley 50 De 1990 y Normas Poster","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"271010","balance":0,"name":"Intereses Sobre Cesantías","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2710100001","balance":0,"name":"Intereses Sobre Cesantias","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"271015","balance":0,"name":"Vacaciones Consolidadas","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2710150001","balance":0,"name":"Vacaciones Consolidas","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"271095","balance":0,"name":"OTRAS PRESTACIONES SOCIALES","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2715","balance":200.41,"name":"Ingresos Anticipados","chapter":"Pasivo","nivel":4,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"271505","balance":200.41,"name":"Intereses sobre cesantías","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2715051005","balance":200.41,"name":"Intereses Sobre Cesantias","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"271595","balance":0,"name":"Otros","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2715950010","balance":0,"name":"Ingreos Serv PSE- HOS","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2715950015","balance":0,"name":"Ingreso Servicio SWIFT","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2715950016","balance":0,"name":"Ingresos Rec Exportación Swift","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2720","balance":1731.66,"name":"Vacaciones","chapter":"Pasivo","nivel":4,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"272005","balance":1731.66,"name":"Vacaciones","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2720051501","balance":1731.66,"name":"Vacaciones Consolidas","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2725","balance":914.23,"name":"Prima Legal","chapter":"Pasivo","nivel":4,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"272505","balance":914.23,"name":"Prima Legal","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2725052001","balance":914.23,"name":"Prima Legal de Servicios","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2735","balance":3142.18,"name":"Bonificaciones","chapter":"Pasivo","nivel":4,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"273505","balance":3142.18,"name":"Bonificaciones","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2735053007","balance":503.32,"name":"Bonificacion Vacaciones","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2735053508","balance":2638.86,"name":"Paga Variable por Gestion Admi","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2735053509","balance":0,"name":"Provision Seg. social Paga Vbl","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2760","balance":0,"name":"Indemnizaciones Laborales","chapter":"Pasivo","nivel":4,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"276075","balance":0,"name":"Indemnizaciones Laborales","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2760750001","balance":0,"name":"Indemnizaciones","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2795","balance":0,"name":"Otros Beneficios","chapter":"Pasivo","nivel":4,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"279505","balance":0,"name":"Otros Beneficios","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2795050001","balance":0,"name":"Otros Beneficio Bono por retir","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"28","balance":610.55,"name":"Pasivos Estimados Y Provisione","chapter":"Pasivo","nivel":2,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2810","balance":0,"name":"Obligaciones Laborales","chapter":"Pasivo","nivel":4,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"281005","balance":0,"name":"Cesantías","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2810050001","balance":0,"name":"Cesantias","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"281010","balance":0,"name":"Intereses Sobre Cesantías","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2810100001","balance":0,"name":"Intereses Sobre Cesantias","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"281015","balance":0,"name":"Vacaciones","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2810150001","balance":0,"name":"Vacaciones","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"281020","balance":0,"name":"Prima Legal","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2810200001","balance":0,"name":"Prima Legal de Servicios","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"281030","balance":0,"name":"Prima De Vacaciones","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2810300007","balance":0,"name":"Bonificacion Vacaciones","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"281035","balance":0,"name":"Bonificaciones","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2810350008","balance":0,"name":"Paga Variable por Gestion Admi","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2810350009","balance":0,"name":"Provision Seg. social Paga Vbl","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"281040","balance":0,"name":"Obligaciones Legales","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2810400001","balance":0,"name":"Obligaciones Legales","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2815","balance":0,"name":"Impuestos","chapter":"Pasivo","nivel":4,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"281505","balance":0,"name":"Renta Y Complementarios","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2815050001","balance":0,"name":"De Renta y Complementarios","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2815050002","balance":0,"name":"Impto de Renta Cree","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2815050003","balance":0,"name":"Sobretasa Impuesto de CREE","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"281510","balance":0,"name":"Industria Y Comercio","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2815100005","balance":0,"name":"Industria y Comercio","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2823","balance":610.55,"name":"Otras provisiones","chapter":"Pasivo","nivel":4,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"282315","balance":610.55,"name":"Otras provisiones","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2823150001","balance":0,"name":"Honorarios","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2823150003","balance":0,"name":"Servicios","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2823150004","balance":610.55,"name":"Otros","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2823159505","balance":0,"name":"Servicio Telefono Call Center","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2890","balance":0,"name":"Otros Pasivos Estimados","chapter":"Pasivo","nivel":4,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"289015","balance":0,"name":"Otros Pasivos","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2890150001","balance":0,"name":"Honorarios","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2890150003","balance":0,"name":"Servicios","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"289095","balance":0,"name":"Otros","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2890950001","balance":0,"name":"Otros","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2895","balance":0,"name":"Diversos","chapter":"Pasivo","nivel":4,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"289595","balance":0,"name":"Otros","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2895950005","balance":0,"name":"Servicio Telefono Call Center","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"29","balance":0,"name":"Otros Pasivos","chapter":"Pasivo","nivel":2,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2907","balance":0,"name":"Ingresos Anticipados","chapter":"Pasivo","nivel":4,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"290795","balance":0,"name":"Otros","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2907959505","balance":0,"name":"Otros","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2907959510","balance":0,"name":"Ingreos Serv PSE- HOS","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2907959511","balance":0,"name":"Impuesto_Diferido_Pasivo","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"2907959520","balance":0,"name":"Ingresos x anticipo SOIDATA","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2023-12-31","account":"3","balance":101877.99,"name":"PATRIMONIO","chapter":"Patrimonio","nivel":1,"classification":"No aplica","status":true},{"initial_date":"2023-12-31","account":"31","balance":6594.81,"name":"Capital Social","chapter":"Patrimonio","nivel":2,"classification":"Aportes de capital social u otros","status":true},{"initial_date":"2023-12-31","account":"3105","balance":6594.81,"name":"Capital Suscrito Y Pagado","chapter":"Patrimonio","nivel":4,"classification":"Aportes de capital social u otros","status":true},{"initial_date":"2023-12-31","account":"310505","balance":6613.22,"name":"Capital Autorizado","chapter":"Patrimonio","nivel":6,"classification":"Aportes de capital social u otros","status":true},{"initial_date":"2023-12-31","account":"3105050005","balance":6613.22,"name":"Capital Autorizado","chapter":"Patrimonio","nivel":10,"classification":"Aportes de capital social u otros","status":true},{"initial_date":"2023-12-31","account":"310510","balance":18.41,"name":"Capital Por Suscribir (-)","chapter":"Patrimonio","nivel":6,"classification":"Aportes de capital social u otros","status":true},{"initial_date":"2023-12-31","account":"3105100005","balance":18.41,"name":"Capital Por Suscribir","chapter":"Patrimonio","nivel":10,"classification":"Aportes de capital social u otros","status":true},{"initial_date":"2023-12-31","account":"32","balance":3413.1,"name":"Reservas","chapter":"Patrimonio","nivel":2,"classification":"Cambios en el patrimonio","status":true},{"initial_date":"2023-12-31","account":"3205","balance":3413.1,"name":"Reserva Legal","chapter":"Patrimonio","nivel":4,"classification":"Cambios en el patrimonio","status":true},{"initial_date":"2023-12-31","account":"320505","balance":3281.52,"name":"Apropiación De Utilidades Liqu","chapter":"Patrimonio","nivel":6,"classification":"Cambios en el patrimonio","status":true},{"initial_date":"2023-12-31","account":"3205050005","balance":2768.98,"name":"Reserva Legal","chapter":"Patrimonio","nivel":10,"classification":"Cambios en el patrimonio","status":true},{"initial_date":"2023-12-31","account":"3205050006","balance":512.53,"name":"Reserva Legal Gravada","chapter":"Patrimonio","nivel":10,"classification":"Cambios en el patrimonio","status":true},{"initial_date":"2023-12-31","account":"320510","balance":131.59,"name":"Prima En Colocación De Accione","chapter":"Patrimonio","nivel":6,"classification":"Cambios en el patrimonio","status":true},{"initial_date":"2023-12-31","account":"3205100005","balance":131.59,"name":"Prima en Colocacion de Accione","chapter":"Patrimonio","nivel":10,"classification":"Cambios en el patrimonio","status":true},{"initial_date":"2023-12-31","account":"3215","balance":0,"name":"Reservas Ocasionales","chapter":"Patrimonio","nivel":4,"classification":"Cambios en el patrimonio","status":true},{"initial_date":"2023-12-31","account":"321595","balance":0,"name":"Otras","chapter":"Patrimonio","nivel":6,"classification":"Cambios en el patrimonio","status":true},{"initial_date":"2023-12-31","account":"3215950010","balance":0,"name":"Para Futuras Inversiones","chapter":"Patrimonio","nivel":10,"classification":"Cambios en el patrimonio","status":true},{"initial_date":"2023-12-31","account":"34","balance":0,"name":"Superávit o Déficit","chapter":"Patrimonio","nivel":2,"classification":"Cambios en el patrimonio","status":true},{"initial_date":"2023-12-31","account":"3415","balance":0,"name":"Valorizaciones","chapter":"Patrimonio","nivel":4,"classification":"Cambios en el patrimonio","status":true},{"initial_date":"2023-12-31","account":"341510","balance":0,"name":"Propiedades Y Equipo","chapter":"Patrimonio","nivel":6,"classification":"Cambios en el patrimonio","status":true},{"initial_date":"2023-12-31","account":"3415100005","balance":0,"name":"Propiedad Planta y Equipo","chapter":"Patrimonio","nivel":10,"classification":"Cambios en el patrimonio","status":true},{"initial_date":"2023-12-31","account":"3417","balance":0,"name":"Revalorización Del Patrimonio","chapter":"Patrimonio","nivel":4,"classification":"Cambios en el patrimonio","status":true},{"initial_date":"2023-12-31","account":"341710","balance":0,"name":"Ajustes Al Patrimonio","chapter":"Patrimonio","nivel":6,"classification":"Cambios en el patrimonio","status":true},{"initial_date":"2023-12-31","account":"3417100005","balance":0,"name":"De Capital Social","chapter":"Patrimonio","nivel":10,"classification":"Cambios en el patrimonio","status":true},{"initial_date":"2023-12-31","account":"3417100015","balance":0,"name":"De Reservas","chapter":"Patrimonio","nivel":10,"classification":"Cambios en el patrimonio","status":true},{"initial_date":"2023-12-31","account":"3417100020","balance":0,"name":"De Resultados de Ejercicios An","chapter":"Patrimonio","nivel":10,"classification":"Cambios en el patrimonio","status":true},{"initial_date":"2023-12-31","account":"3417100035","balance":0,"name":"De Ajutes","chapter":"Patrimonio","nivel":10,"classification":"Cambios en el patrimonio","status":true},{"initial_date":"2023-12-31","account":"35","balance":0,"name":"RESULTADOS DE EJERCICIOS AN","chapter":"Patrimonio","nivel":2,"classification":"Cambios en el patrimonio","status":true},{"initial_date":"2023-12-31","account":"3505","balance":0,"name":"UTILIDADES O EXCEDENTES ACU","chapter":"Patrimonio","nivel":4,"classification":"Cambios en el patrimonio","status":true},{"initial_date":"2023-12-31","account":"350501","balance":0,"name":"UTILIDADES O EXCEDENTES ACU","chapter":"Patrimonio","nivel":6,"classification":"Cambios en el patrimonio","status":true},{"initial_date":"2023-12-31","account":"36","balance":0,"name":"Resultados Del Ejercicio","chapter":"Patrimonio","nivel":2,"classification":"Cambios en el patrimonio","status":true},{"initial_date":"2023-12-31","account":"3605","balance":0,"name":"Resultados Del Ejercicio","chapter":"Patrimonio","nivel":4,"classification":"Cambios en el patrimonio","status":true},{"initial_date":"2023-12-31","account":"360501","balance":0,"name":"Resultados Del Ejercicio","chapter":"Patrimonio","nivel":6,"classification":"Cambios en el patrimonio","status":true},{"initial_date":"2023-12-31","account":"3605010001","balance":0,"name":"Utilidad del Ejercicio","chapter":"Patrimonio","nivel":10,"classification":"Cambios en el patrimonio","status":true},{"initial_date":"2023-12-31","account":"39","balance":99816.91,"name":"[MODIFICADO POR ECUACION FINANCIERA] Ganancias o Pérdidas","chapter":"Patrimonio","nivel":2,"classification":"Utilidad del ejercicio periodo","status":true},{"initial_date":"2023-12-31","account":"3905","balance":0,"name":"Ganancias Acumuladas Ejercicio","chapter":"Patrimonio","nivel":4,"classification":"Utilidad del ejercicio periodo","status":true},{"initial_date":"2023-12-31","account":"390501","balance":0,"name":"Ganancias Acumuladas Ejercicio","chapter":"Patrimonio","nivel":6,"classification":"Utilidad del ejercicio periodo","status":true},{"initial_date":"2023-12-31","account":"3905010005","balance":0,"name":"Utilidades de Ejercicios Anter","chapter":"Patrimonio","nivel":10,"classification":"Utilidad del ejercicio periodo","status":true},{"initial_date":"2023-12-31","account":"3905010010","balance":0,"name":"Utilidades No Gravadas","chapter":"Patrimonio","nivel":10,"classification":"Utilidad del ejercicio periodo","status":true},{"initial_date":"2023-12-31","account":"3915","balance":91870.08,"name":"Ganancia del Ejercicio","chapter":"Patrimonio","nivel":4,"classification":"Utilidad del ejercicio periodo","status":true},{"initial_date":"2023-12-31","account":"391501","balance":91870.08,"name":"Ganancia del Ejercicio","chapter":"Patrimonio","nivel":6,"classification":"Utilidad del ejercicio periodo","status":true},{"initial_date":"2023-12-31","account":"3915010001","balance":91870.08,"name":"Utilidad del ejercicio","chapter":"Patrimonio","nivel":10,"classification":"Utilidad del ejercicio periodo","status":true},{"initial_date":"2023-12-31","account":"3930","balance":0,"name":"Resultados Acumulados Proceso","chapter":"Patrimonio","nivel":4,"classification":"Utilidad del ejercicio periodo","status":true},{"initial_date":"2023-12-31","account":"393010","balance":0,"name":"Pérdida","chapter":"Patrimonio","nivel":6,"classification":"Utilidad del ejercicio periodo","status":true},{"initial_date":"2023-12-31","account":"3930100001","balance":0,"name":"RESULTADOS ACUMULADOS PROCESO","chapter":"Patrimonio","nivel":10,"classification":"Utilidad del ejercicio periodo","status":true},{"initial_date":"2023-12-31","account":"4","balance":292592.28,"name":"INGRESOS","chapter":"Ingresos","nivel":1,"classification":"No aplica","status":true},{"initial_date":"2023-12-31","account":"41","balance":292592.28,"name":"Operacionales","chapter":"Ingresos","nivel":2,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"4103","balance":3000.33,"name":"Ingresos Financieros Operacion","chapter":"Ingresos","nivel":4,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"410305","balance":3000.33,"name":"Depósitos a la Vista","chapter":"Ingresos","nivel":6,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"4103052010","balance":3000.33,"name":"Rendimientos Ctas Ahorro","chapter":"Ingresos","nivel":10,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"4104","balance":0,"name":"Otros Intereses","chapter":"Ingresos","nivel":4,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"410402","balance":0,"name":"Depósitos a la Vista","chapter":"Ingresos","nivel":6,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"4104020010","balance":0,"name":"Rendimientos Ctas Ahorro","chapter":"Ingresos","nivel":10,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"410430","balance":0,"name":"Rendimientos Otras Especies","chapter":"Ingresos","nivel":6,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"4104300005","balance":0,"name":"CDT En Pesos","chapter":"Ingresos","nivel":10,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"4106","balance":7412.5,"name":"Valoración por Transferencia t","chapter":"Ingresos","nivel":4,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"410610","balance":7412.5,"name":"En títulos Participativos","chapter":"Ingresos","nivel":6,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"4106106005","balance":7412.5,"name":"Rendimientos Fiduciarias","chapter":"Ingresos","nivel":10,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"4108","balance":0,"name":"Utilidad en Valoración de Inve","chapter":"Ingresos","nivel":4,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"410806","balance":0,"name":"Por Incremento En El Valor","chapter":"Ingresos","nivel":6,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"4108060005","balance":0,"name":"Rendimientos Fiduciarias","chapter":"Ingresos","nivel":10,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"4111","balance":0,"name":"Utilidad En Valoración Inversi","chapter":"Ingresos","nivel":4,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"411106","balance":0,"name":"Por Incremento En El Valor Pre","chapter":"Ingresos","nivel":6,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"4111060005","balance":0,"name":"CDT En Pesos","chapter":"Ingresos","nivel":10,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"4115","balance":281264.14,"name":"Comisiones Y/o Honorarios","chapter":"Ingresos","nivel":4,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"411516","balance":281264.14,"name":"Uso Medios de Pago Diferentes","chapter":"Ingresos","nivel":6,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"4115164010","balance":62463.84,"name":"Servicio Soporte Sitio Central","chapter":"Ingresos","nivel":10,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"4115164020","balance":183214.29,"name":"Pagos Seguros en Linea PSE","chapter":"Ingresos","nivel":10,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"4115164025","balance":0,"name":"Seg. programa prevenc Fraude","chapter":"Ingresos","nivel":10,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"4115164035","balance":261.5,"name":"Acceso a la Red","chapter":"Ingresos","nivel":10,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"4115164045","balance":0,"name":"AMPLIACION DE SERVICIOS","chapter":"Ingresos","nivel":10,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"4115164050","balance":31170.35,"name":"Servicio Oper. de Información","chapter":"Ingresos","nivel":10,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"4115164055","balance":0,"name":"Soluciones SWIFT Colombia","chapter":"Ingresos","nivel":10,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"4115164060","balance":0,"name":"SOI DATA","chapter":"Ingresos","nivel":10,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"4115164065","balance":4154.17,"name":"Transferencia ACH YA","chapter":"Ingresos","nivel":10,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"411540","balance":0,"name":"Uso Medios De Pago Diferent","chapter":"Ingresos","nivel":6,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"4115400005","balance":0,"name":"Red de Valor Agregado","chapter":"Ingresos","nivel":10,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"4115400010","balance":0,"name":"Servicio Soporte Sitio Central","chapter":"Ingresos","nivel":10,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"4115400020","balance":0,"name":"Pagos Seguros en Linea PSE","chapter":"Ingresos","nivel":10,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"4115400025","balance":0,"name":"Seg. programa prevenc Fraude","chapter":"Ingresos","nivel":10,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"4115400035","balance":0,"name":"Acceso a la Red","chapter":"Ingresos","nivel":10,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"4115400040","balance":0,"name":"Exportación de Servicios_SWIFT","chapter":"Ingresos","nivel":10,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"4115400045","balance":0,"name":"AMPLIACION DE SERVICIOS","chapter":"Ingresos","nivel":10,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"4115400050","balance":0,"name":"Servicio Oper. de Información","chapter":"Ingresos","nivel":10,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"4115400055","balance":0,"name":"Soluciones SWIFT Colombia","chapter":"Ingresos","nivel":10,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"4131","balance":5.4,"name":"Por Venta de Propiedades y Equ","chapter":"Ingresos","nivel":4,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"413110","balance":0,"name":"Edificios","chapter":"Ingresos","nivel":6,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"4131100005","balance":0,"name":"Venta Equipo de Computacion","chapter":"Ingresos","nivel":10,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"413115","balance":5.4,"name":"Equipo,Muebles y Enseres de Of","chapter":"Ingresos","nivel":6,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"4131150005","balance":5.4,"name":"Venta Muebles y Enseres","chapter":"Ingresos","nivel":10,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"4190","balance":0,"name":"Recuperaciones Riesgo Operativ","chapter":"Ingresos","nivel":4,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"419010","balance":0,"name":"Recuperaciones Diferen a Segur","chapter":"Ingresos","nivel":6,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"4190100005","balance":0,"name":"Recuperaciones Riesgo Operativ","chapter":"Ingresos","nivel":10,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"4191","balance":3.56,"name":"Recuperaciones Riesgo Operativ","chapter":"Ingresos","nivel":4,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"419110","balance":3.56,"name":"Recuperaciones Diferentes a Se","chapter":"Ingresos","nivel":6,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"4191100005","balance":3.56,"name":"RECUPERACION RIESGO OPERATIVO","chapter":"Ingresos","nivel":10,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"4193","balance":0,"name":"subvenciones del gobierno","chapter":"Ingresos","nivel":4,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"419305","balance":0,"name":"subvenciones del gobierno","chapter":"Ingresos","nivel":6,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"4193050005","balance":0,"name":"INGRESOS SUBVENCIONES G","chapter":"Ingresos","nivel":10,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"4195","balance":902.58,"name":"Diversos","chapter":"Ingresos","nivel":4,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"419595","balance":902.58,"name":"Otros","chapter":"Ingresos","nivel":6,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"4195950005","balance":27.11,"name":"Otros Ingresos","chapter":"Ingresos","nivel":10,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"4195950031","balance":308.73,"name":"Diferencia de Cambio Realizada","chapter":"Ingresos","nivel":10,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"4195950035","balance":42.73,"name":"Diferencia en Cambio No Realiz","chapter":"Ingresos","nivel":10,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"4195950050","balance":0,"name":"Por Incapacidades","chapter":"Ingresos","nivel":10,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"4195950055","balance":0.32,"name":"Aprovechamientos","chapter":"Ingresos","nivel":10,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"4195950060","balance":523.67,"name":"Sancion Interinstitucional","chapter":"Ingresos","nivel":10,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"4195950065","balance":0.01,"name":"Ajuste al Peso","chapter":"Ingresos","nivel":10,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"4195950070","balance":0,"name":"Tokens","chapter":"Ingresos","nivel":10,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"4195950085","balance":0,"name":"Descuentos condicionados","chapter":"Ingresos","nivel":10,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"4198","balance":3.77,"name":"Recuperaciones Deterioro (Prov","chapter":"Ingresos","nivel":4,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"419805","balance":3.77,"name":"Reintegro Provisiones Cuentas","chapter":"Ingresos","nivel":6,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"4198053010","balance":0,"name":"Reintegro de Otras Provisiones","chapter":"Ingresos","nivel":10,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"4198055010","balance":3.77,"name":"Recuperacion anos anteriores","chapter":"Ingresos","nivel":10,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"42","balance":0,"name":"No Operacionales","chapter":"Ingresos","nivel":2,"classification":"Otros ingresos no operativos","status":true},{"initial_date":"2023-12-31","account":"4210","balance":0,"name":"Utilidad En Venta De Propie","chapter":"Ingresos","nivel":4,"classification":"Otros ingresos no operativos","status":true},{"initial_date":"2023-12-31","account":"421015","balance":0,"name":"Equipo, Muebles Y Enseres De O","chapter":"Ingresos","nivel":6,"classification":"Otros ingresos no operativos","status":true},{"initial_date":"2023-12-31","account":"4210150005","balance":0,"name":"Venta de Muebles y Enseres","chapter":"Ingresos","nivel":10,"classification":"Otros ingresos no operativos","status":true},{"initial_date":"2023-12-31","account":"421020","balance":0,"name":"Equipo De Computación","chapter":"Ingresos","nivel":6,"classification":"Otros ingresos no operativos","status":true},{"initial_date":"2023-12-31","account":"4210200005","balance":0,"name":"Venta Equipo de Computacion","chapter":"Ingresos","nivel":10,"classification":"Otros ingresos no operativos","status":true},{"initial_date":"2023-12-31","account":"4225","balance":0,"name":"Recuperaciones","chapter":"Ingresos","nivel":4,"classification":"Otros ingresos no operativos","status":true},{"initial_date":"2023-12-31","account":"422513","balance":0,"name":"Reintegro Otras Provisiones","chapter":"Ingresos","nivel":6,"classification":"Otros ingresos no operativos","status":true},{"initial_date":"2023-12-31","account":"4225130005","balance":0,"name":"Reintegro provisión de Renta","chapter":"Ingresos","nivel":10,"classification":"Otros ingresos no operativos","status":true},{"initial_date":"2023-12-31","account":"4225130010","balance":0,"name":"Reintegro de Otras Provisiones","chapter":"Ingresos","nivel":10,"classification":"Otros ingresos no operativos","status":true},{"initial_date":"2023-12-31","account":"422595","balance":0,"name":"Otras Recuperaciones","chapter":"Ingresos","nivel":6,"classification":"Otros ingresos no operativos","status":true},{"initial_date":"2023-12-31","account":"4225950005","balance":0,"name":"Recuperacion en Contratos","chapter":"Ingresos","nivel":10,"classification":"Otros ingresos no operativos","status":true},{"initial_date":"2023-12-31","account":"4225950010","balance":0,"name":"Recuperacion anos anteriores","chapter":"Ingresos","nivel":10,"classification":"Otros ingresos no operativos","status":true},{"initial_date":"2023-12-31","account":"4295","balance":0,"name":"Diversos","chapter":"Ingresos","nivel":4,"classification":"Otros ingresos no operativos","status":true},{"initial_date":"2023-12-31","account":"429595","balance":0,"name":"Otros","chapter":"Ingresos","nivel":6,"classification":"Otros ingresos no operativos","status":true},{"initial_date":"2023-12-31","account":"4295950031","balance":0,"name":"Diferencia de Cambio Realizada","chapter":"Ingresos","nivel":10,"classification":"Otros ingresos no operativos","status":true},{"initial_date":"2023-12-31","account":"4295950035","balance":0,"name":"Diferencia en Cambio No Realiz","chapter":"Ingresos","nivel":10,"classification":"Otros ingresos no operativos","status":true},{"initial_date":"2023-12-31","account":"4295950040","balance":0,"name":"Diferencia en Cambio en servi","chapter":"Ingresos","nivel":10,"classification":"Otros ingresos no operativos","status":true},{"initial_date":"2023-12-31","account":"4295950050","balance":0,"name":"Por Incapacidades","chapter":"Ingresos","nivel":10,"classification":"Otros ingresos no operativos","status":true},{"initial_date":"2023-12-31","account":"4295950055","balance":0,"name":"Aprovechamientos","chapter":"Ingresos","nivel":10,"classification":"Otros ingresos no operativos","status":true},{"initial_date":"2023-12-31","account":"4295950060","balance":0,"name":"Sancion Interinstitucional","chapter":"Ingresos","nivel":10,"classification":"Otros ingresos no operativos","status":true},{"initial_date":"2023-12-31","account":"4295950065","balance":0,"name":"Ajuste al Peso","chapter":"Ingresos","nivel":10,"classification":"Otros ingresos no operativos","status":true},{"initial_date":"2023-12-31","account":"4295950070","balance":0,"name":"Tokens","chapter":"Ingresos","nivel":10,"classification":"Otros ingresos no operativos","status":true},{"initial_date":"2023-12-31","account":"4295950080","balance":0,"name":"Descto por pronto pago","chapter":"Ingresos","nivel":10,"classification":"Otros ingresos no operativos","status":true},{"initial_date":"2023-12-31","account":"4295950085","balance":0,"name":"Descuentos condicionados","chapter":"Ingresos","nivel":10,"classification":"Otros ingresos no operativos","status":true},{"initial_date":"2023-12-31","account":"5","balance":284645.44,"name":"GASTOS Y COSTOS","chapter":"Gastos","nivel":1,"classification":"No aplica","status":true},{"initial_date":"2023-12-31","account":"51","balance":193113.14,"name":"Operacionales","chapter":"Gastos","nivel":2,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5104","balance":151.32,"name":"Otros Intereses, Prima Amor","chapter":"Gastos","nivel":4,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"510495","balance":151.32,"name":"Otros Intereses","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5104950010","balance":0,"name":"Intereses Corrientes","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5104950015","balance":0,"name":"Intereses Corrientes Leasing","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5104950016","balance":57.52,"name":"Intereses Corrientes Leasing","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5104950017","balance":0,"name":"Intereses Corrientes Leasing","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5104950019","balance":13.45,"name":"Intereses Corrientes Leasing","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5104950021","balance":0,"name":"Intereses Corrientes Leasing","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5104950022","balance":93.79,"name":"Intereses Corrientes Leasing","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5104950023","balance":0,"name":"Intereses leasing 180-119248","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"510497","balance":0.17,"name":"Riesgo Operativo","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5104970001","balance":0.17,"name":"RIESGO FINANCIERO POR OPERACIO","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5108","balance":0,"name":"PERDIDA EN VALORACION DE IN","chapter":"Gastos","nivel":4,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"510805","balance":0,"name":"PERDIDA EN VALORACION DE IN","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5115","balance":408.51,"name":"Comisiones","chapter":"Gastos","nivel":4,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"511512","balance":408.51,"name":"Servicios Bancarios","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5115122015","balance":408.51,"name":"Gastos Bancarios","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"511520","balance":0,"name":"Servicios Bancarios","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5115200015","balance":0,"name":"Gastos Bancarios","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"511595","balance":0,"name":"Otros Servicios","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5115950005","balance":0,"name":"Otros Servicios","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"511597","balance":0,"name":"Riesgo Operativo","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5115970001","balance":0,"name":"Riesgo Comisiones","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120","balance":60910.54,"name":"Gastos De Personal","chapter":"Gastos","nivel":4,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"512001","balance":5491.36,"name":"Salario Integral","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120010503","balance":5491.36,"name":"Salario Integral","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"512002","balance":21308.48,"name":"Sueldos","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120020505","balance":21308.48,"name":"Sueldos","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"512003","balance":676.77,"name":"Horas Extras","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120031005","balance":676.77,"name":"Horas Extras","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"512004","balance":0.8,"name":"Auxilio de Transporte","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120041505","balance":0.8,"name":"Auxilio de Transporte","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"512005","balance":0,"name":"Salarios","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120050003","balance":0,"name":"Salario Integral","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120050005","balance":0,"name":"Sueldos","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"512006","balance":1961.45,"name":"Cesantias","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120062505","balance":1961.45,"name":"Cesantias","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"512007","balance":206.48,"name":"Intereses Sobre Cesantias","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120073005","balance":206.48,"name":"Intereses Sobre Cesantias","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"512008","balance":1949.84,"name":"Prima Legal","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120083505","balance":1949.84,"name":"Prima Legal","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"512010","balance":1668.52,"name":"Horas Extras","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120100005","balance":0,"name":"Horas Extras","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120104505","balance":1668.52,"name":"Vacaciones","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"512011","balance":472.43,"name":"Prima de Vacaciones","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120115005","balance":472.43,"name":"Prima de Vacaciones","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"512013","balance":3226.56,"name":"Pensiones de Jubilacion","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120136005","balance":3226.56,"name":"Pensiones de Jubilacion","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"512015","balance":2703.08,"name":"Auxilio De Transporte","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120150005","balance":0,"name":"Auxilio de Transporte","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120156505","balance":2361.1,"name":"Paga Variab por Gest Administr","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120157005","balance":69.63,"name":"Bonificaciones","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120157006","balance":0,"name":"Bonificaciones Mera Liberalida","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120157007","balance":272.35,"name":"Bonificacion por Encargatura","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"512016","balance":64.79,"name":"Indemnizaciones","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120167505","balance":64.79,"name":"Indemnizaciones Terminacion Co","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"512019","balance":1697.36,"name":"Aportes Caja Compensacion Fami","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120199005","balance":1560.91,"name":"Aportes Caja Compensacion Fami","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120199205","balance":136.45,"name":"Aportes ARL","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"512025","balance":0,"name":"Cesantías","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120250005","balance":0,"name":"Cesantias","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"512030","balance":899.53,"name":"Intereses Sobre Cesantías","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120300005","balance":0,"name":"Intereses Sobre Cesantias","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120308505","balance":899.53,"name":"Aportes EPS","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"512035","balance":0,"name":"Prima Legal","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120350005","balance":0,"name":"Prima Legal","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"512040","balance":0,"name":"PRIMA EXTRALEGAL","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"512043","balance":60910.54,"name":"Otros Beneficios a Empleados","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120430001","balance":0,"name":"Otros Beneficios a Empleados","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120430010","balance":0,"name":"De Personal Teletrabajo","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120439501","balance":0,"name":"Capacitacion Direccion Segurid","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120439505","balance":492.04,"name":"Capacitacion/Transversal","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120439513","balance":0,"name":"Salud ocupaci/ Element protecc","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120439515","balance":82.93,"name":"Salud Ocupacional","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120439516","balance":0,"name":"Salud ocupaci/ semana de salud","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120439517","balance":0,"name":"Salud ocupaci/ recar extintor","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120439518","balance":0,"name":"Salud ocupaci/ Area Protegida","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120439519","balance":0,"name":"Salud ocupaci/ Fumigación","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120439520","balance":1037.96,"name":"Recreacion","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120439521","balance":0,"name":"Recreac/Nacimiento bebes","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120439523","balance":0,"name":"Recreac/ Reconocimientos","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120439524","balance":0,"name":"Recreac/ Tortas cumpleaños","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120439526","balance":0,"name":"Recreac/ Celebrac Aniversarios","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120439528","balance":0,"name":"Recreac/ Patrocinio deportes","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120439530","balance":0,"name":"Refrigerios","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120439531","balance":0,"name":"Recreac/ Desayuno Bienvenida","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120439534","balance":0,"name":"Recreac/ Patrocinio Fondo","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120439536","balance":0,"name":"Recreac/ Olimpiadas","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120439537","balance":0,"name":"Recreac/ Día Mujer","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120439538","balance":0,"name":"Recreac/ Día Padre y Madre","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120439539","balance":0,"name":"Recreac/ Día Vendedor","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120439540","balance":0,"name":"Recreac/ Novena funcionarios","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120439541","balance":0,"name":"Recreac/ Fiesta Fin de año","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120439542","balance":0,"name":"Recreac/ Día del soltero","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120439543","balance":0,"name":"Recreac/ Día de la Familia","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120439544","balance":0,"name":"Recreac/ Vacaciones Recreativa","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120439546","balance":0,"name":"Recreac/ Regalos Navidad Niños","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120439547","balance":0,"name":"Recreac/ Novena Familia","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120439548","balance":0,"name":"Recreac/ Papeleria Apoyo","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120439549","balance":0,"name":"Recreac/ Aniversario SOI","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120439550","balance":0,"name":"Recreacion/Quinquenios","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120439554","balance":63.24,"name":"Bienestar_Compañía","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120439555","balance":0,"name":"Beneficios funcionarios ACH","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120439605","balance":59234.37,"name":"Auxilios al Personal","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120439606","balance":0,"name":"DOTACIONES AL PERSONAL","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"512045","balance":0,"name":"Vacaciones","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120450005","balance":0,"name":"Vacaciones","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"512050","balance":0,"name":"Prima De Vacaciones","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120500005","balance":0,"name":"Prima de Vacaciones","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"512060","balance":0,"name":"Pensiones De Jubilación","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120600005","balance":0,"name":"Pensiones de Jubilacion","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"512065","balance":0,"name":"Otras Prestaciones Sociales","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120650005","balance":0,"name":"Paga Variab por Gest Administr","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"512070","balance":0,"name":"Bonificaciones","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120700005","balance":0,"name":"Bonificaciones","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120700006","balance":0,"name":"Bonificación por Retiro Defini","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120700007","balance":0,"name":"Bonificacion por Encargatura","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"512075","balance":0,"name":"Indemnizaciones","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120750005","balance":0,"name":"Indemnizaciones Terminacion Co","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"512085","balance":0,"name":"Aportes Eps","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120850005","balance":0,"name":"Aportes EPS","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"512090","balance":0,"name":"Aportes Caja de Compensación","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120900005","balance":0,"name":"Aportes Caja Compensacion Fami","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"512092","balance":0,"name":"Aportes Cajas Compen Sala I","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120920005","balance":0,"name":"Aportes ARL","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"512095","balance":0,"name":"Otros","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120950000","balance":0,"name":"Capacitación Auditoria Interna","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120950001","balance":0,"name":"Capacitacion Direccion Segurid","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120950002","balance":0,"name":"Capacitacion Direccion Tecnolo","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120950003","balance":0,"name":"Capacitacion Direccion Planeac","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120950004","balance":0,"name":"Capacitacion Direccion Product","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120950005","balance":0,"name":"Capacitacion/Transversal","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120950006","balance":0,"name":"Capacitacion /Equipo Directivo","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120950007","balance":0,"name":"Capacitacion /Equipo Tactico","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120950008","balance":0,"name":"Capacitacion /Dir TH y Admon","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120950009","balance":0,"name":"Capacitacion /Presidencia","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120950010","balance":0,"name":"Capacitación/Dir Comercial","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120950011","balance":0,"name":"Capacitacion /Subdi Serv Clien","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120950013","balance":0,"name":"Salud ocupaci/ Element protecc","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120950016","balance":0,"name":"Salud ocupaci/ semana de salud","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120950017","balance":0,"name":"Salud ocupaci/ recar extintor","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120950018","balance":0,"name":"Salud ocupaci/ Area Protegida","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120950019","balance":0,"name":"Salud ocupaci/ Fumigación","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120950020","balance":0,"name":"Recreacion","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120950021","balance":0,"name":"Recreac/Nacimiento bebes","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120950022","balance":0,"name":"Recreac/Incentiv Comerciales","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120950023","balance":0,"name":"Recreac/ Reconocimientos","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120950024","balance":0,"name":"Recreac/ Tortas cumpleaños","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120950025","balance":0,"name":"Recreac/ Galleta Aniversarios","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120950026","balance":0,"name":"Recreac/ Celebrac Aniversarios","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120950027","balance":0,"name":"Recreac/ Celebrac Cumpleaños","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120950028","balance":0,"name":"Recreac/ Patrocinio deportes","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120950029","balance":0,"name":"Recreac/ Kit Bienvenida","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120950030","balance":0,"name":"Refrigerios","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120950031","balance":0,"name":"Recreac/ Desayuno Bienvenida","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120950032","balance":0,"name":"Recreac/ Charlas Familia","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120950033","balance":0,"name":"Recreac/ Fotografias familia","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120950034","balance":0,"name":"Recreac/ Patrocinio Fondo","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120950036","balance":0,"name":"Recreac/ Olimpiadas","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120950037","balance":0,"name":"Recreac/ Día Mujer","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120950038","balance":0,"name":"Recreac/ Día Padre y Madre","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120950039","balance":0,"name":"Recreac/ Día Vendedor","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120950040","balance":0,"name":"Recreac/ Novena funcionarios","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120950041","balance":0,"name":"Recreac/ Fiesta Fin de año","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120950042","balance":0,"name":"Recreac/ Día del soltero","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120950043","balance":0,"name":"Recreac/ Día de la Familia","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120950044","balance":0,"name":"Recreac/ Vacaciones Recreativa","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120950046","balance":0,"name":"Recreac/ Regalos Navidad Niños","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120950047","balance":0,"name":"Recreac/ Novena Familia","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120950048","balance":0,"name":"Recreac/ Papeleria Apoyo","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120950049","balance":0,"name":"Recreac/ Aniversario SOI","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120950050","balance":0,"name":"Recreacion/Quinquenios","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120950051","balance":0,"name":"Capacitación/ Dirección Jurídi","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"512096","balance":0,"name":"Auxilios Al Personal","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120960005","balance":0,"name":"Auxilios al Personal","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120960006","balance":0,"name":"DOTACIONES AL PERSONAL","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"512097","balance":1.33,"name":"Riesgo Operativo","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5120970005","balance":1.33,"name":"Riesgo Operativo Personal","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5130","balance":22063.09,"name":"Honorarios","chapter":"Gastos","nivel":4,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"513005","balance":0,"name":"Junta Directiva","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5130050005","balance":0,"name":"Junta Directiva","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"513010","balance":429.09,"name":"Revisoría Fiscal y Auditoria","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5130100010","balance":0,"name":"Revisoria Fiscal","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5130100505","balance":429.09,"name":"Junta Directiva","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"513015","balance":123.04,"name":"Revisoria Fiscal y Auditoria E","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5130151010","balance":123.04,"name":"Revisoria Fiscal","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"513020","balance":0,"name":"ASESORIAS JURIDICAS","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"513025","balance":23.55,"name":"Asesorías Juridicas","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5130259511","balance":23.55,"name":"Otros Honor/ Asesoría Laboral","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5130259517","balance":0,"name":"Otros Honor/ Honorarios Legale","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"513030","balance":530.22,"name":"Asesorias Financieras","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5130309505","balance":457.4,"name":"Servicio Contable","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5130309506","balance":72.83,"name":"Tributarios","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"513095","balance":20957.18,"name":"Otros","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5130950005","balance":0,"name":"Servicio Contable","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5130950006","balance":0,"name":"Tributarios","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5130950010","balance":2403.77,"name":"Otros Honorarios","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5130950011","balance":0,"name":"Otros Honor/ Asesoría Laboral","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5130950012","balance":178.09,"name":"Otros Honor/ Proceso selección","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5130950013","balance":0,"name":"Otros Honor/ E-Learning","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5130950015","balance":1751.46,"name":"Consultorias","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5130950016","balance":0,"name":"Otros Honor/ Formu Mantenimien","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5130950017","balance":0,"name":"Otros Honor/ Honorarios Legale","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5130950018","balance":0,"name":"Otros Honor/ Planeaci Estrateg","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5130950020","balance":43.92,"name":"Otros Honor/ Encuestas","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5130950021","balance":0,"name":"Otros Honor/ Otros","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5130950022","balance":0,"name":"Consultoria/Soport Projec Serv","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5130950023","balance":29.51,"name":"Consultoria/Endeuda funcionari","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5130950024","balance":0,"name":"Consultoria/ GPTW","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5130950025","balance":326.74,"name":"Consultoria/Temas Legales","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5130950026","balance":2011.71,"name":"Consultoria/ Implementación","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5130950027","balance":30.1,"name":"Consultoria/Certificac Calidad","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5130950028","balance":0.8,"name":"Consultoria/sensibiliz Interna","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5130950029","balance":3492.93,"name":"Otros Honorarios/ Venta SOI","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5130950030","balance":0,"name":"Otros Honorarios/ Investig de","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5130950035","balance":1191.3,"name":"Asesoria Tecnica","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5130950036","balance":0,"name":"Ases Técn/ Recurs Pruebas","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5130950037","balance":0,"name":"Ases Técn/ Mesa de Servicio","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5130950038","balance":0,"name":"Ases Técn/ Recurso ITSTK","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5130950039","balance":0,"name":"Ases Técn/ Sop eq comp y comun","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5130950040","balance":278,"name":"Ases Técn/ Soporte Premier","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5130950041","balance":0,"name":"Ases Técn/ Prbas Ethical Hacki","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5130950042","balance":9119.64,"name":"Ases Técn/ AT+ horas desarroll","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5130950043","balance":0,"name":"Ases Técn/ Desarrollo PSE","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5130950045","balance":100,"name":"Ases Técn/ Desarrollo Portales","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5130950046","balance":0,"name":"Ases Técn/ Licenciamiento","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5130950047","balance":0,"name":"Ases Técn/ Vinculación Certifi","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"513097","balance":0,"name":"Riesgo Operativo","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5130970001","balance":0,"name":"Riesgo Honorarios","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5130970005","balance":0,"name":"Riesgo Honorarios","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5140","balance":5064.53,"name":"Impuestos","chapter":"Gastos","nivel":4,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"514005","balance":5064.53,"name":"Registro Y Anotación","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5140051005","balance":4127.63,"name":"Industria y Comercio","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5140053505","balance":927.5,"name":"Gravamen a los Movim Financie","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5140053510","balance":0,"name":"Sobretasa de Renta","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5140059540","balance":1.55,"name":"Impto Nacional al Consumo","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5140059545","balance":9.4,"name":"Tasa Aeroportuaria","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5140059546","balance":0,"name":"Impuesto a la Riqueza","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"514010","balance":0,"name":"Industria Y Comercio","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5140100005","balance":0,"name":"Industria y Comercio","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"514035","balance":0,"name":"GMF","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5140350005","balance":0,"name":"Gravamen a los Movim Financie","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"514095","balance":0,"name":"Sobretasas Y Otros","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5140950020","balance":0,"name":"Derechos Sobre Instrumentos Pu","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5140950035","balance":0,"name":"Contribución CRC","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5140950040","balance":0,"name":"Impto Nacional al Consumo","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5140950045","balance":0,"name":"Tasa Aeroportuaria","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5140950046","balance":0,"name":"Impuesto a la Riqueza","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"514097","balance":0,"name":"Riesgo Operativo","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5140970001","balance":0,"name":"Contribución CRC. rubro defini","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5140970005","balance":0,"name":"Riesgo Impuestos","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5145","balance":4079.45,"name":"Arrendamientos","chapter":"Gastos","nivel":4,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"514505","balance":1667.13,"name":"Equipo De Computación","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5145050001","balance":0,"name":"Leasing vehiculo / VOT","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5145050002","balance":0,"name":"Leasing vehículo / VMP","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5145050003","balance":0,"name":"Leasing vehículo / Presidencia","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5145050021","balance":0,"name":"Leasing Equipos de Computo","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5145050023","balance":0,"name":"Leasing Storage","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5145050024","balance":0,"name":"Leasing servidores","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5145050025","balance":671.13,"name":"Equipo de Computacion y Comuni","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5145050026","balance":996.01,"name":"Arrendamiento Datacenter","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5145050027","balance":0,"name":"Arrendamiento Kioskos","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"514510","balance":1930.94,"name":"Locales Y Oficinas","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5145100006","balance":0,"name":"Arrendam sede / Sitio Alterno","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5145100007","balance":1930.94,"name":"Arrendam sede/ Sede Principal","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5145100008","balance":0,"name":"Arrendam sede/ Otras Sedes","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"514515","balance":0,"name":"PARQUEADEROS","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"514535","balance":0,"name":"MAQUINARIA Y EQUIPO","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"514595","balance":481.38,"name":"Otros","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5145950005","balance":0,"name":"Arrendamiento Muebles","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5145950015","balance":70.17,"name":"Salon de Eventos con Equipos","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5145950016","balance":411.21,"name":"Arrend. Infraest en la nube","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"514597","balance":2.09,"name":"Riesgo Operativo","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5145970001","balance":2.09,"name":"Riesgo Arrendamientos","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5150","balance":0,"name":"Contribuciones Y Afiliaciones","chapter":"Gastos","nivel":4,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"515095","balance":0,"name":"Otras","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5150950005","balance":0,"name":"Otras Contrib y Afiliaciones","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"515097","balance":0,"name":"Riesgo Operativo","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5150970005","balance":0,"name":"Riesgo Contribuciones y Afilia","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5155","balance":3398.91,"name":"Seguros","chapter":"Gastos","nivel":4,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"515510","balance":3398.91,"name":"Cumplimiento","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5155100005","balance":5,"name":"Cumplimiento","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5155100006","balance":59.85,"name":"Seguros/ Todo Riesgo","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5155100007","balance":219.96,"name":"Seguros/ Direct y Administrado","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5155100008","balance":2209.95,"name":"Seguros/ Infidelidad y riesgos","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5155100009","balance":46.18,"name":"Seguros/ Arrendamiento","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5155100010","balance":846.86,"name":"Seguros/ Riesgos Cibernéticos","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5155100016","balance":0,"name":"Seguros/ Riesgos Cibernéticos","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5155100019","balance":11.1,"name":"Seguros/Arrendamientos Leasing","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5155100021","balance":0,"name":"Seguros/Arrendamientos Leasing","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5155100022","balance":0,"name":"Seguros/Arrendamientos Leasing","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5160","balance":13526.17,"name":"Mantenimiento Y Reparaciónes","chapter":"Gastos","nivel":4,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"516005","balance":2813.53,"name":"Equipo De Computación","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5160050005","balance":342.37,"name":"Mantenimiento Hardware","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5160050010","balance":2471.17,"name":"Mantenimiento Software","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5160050012","balance":0,"name":"Mto Software/Sopor y Mto SWIFT","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5160050015","balance":0,"name":"Mto Software/Sop y Mto Z Virtu","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5160050016","balance":0,"name":"Mto Software/Certifi Digitales","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5160050017","balance":0,"name":"Mto Software/ Mantenimient HCM","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5160050018","balance":0,"name":"Mto Software/ Mantenimient ERP","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5160050019","balance":0,"name":"Mto Software/ Mto Balanc-enrut","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5160050020","balance":0,"name":"Mto Software/ Telefonía IP","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5160050021","balance":0,"name":"Mto Software/ Aranda","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5160050022","balance":0,"name":"Mto Software/ Liferay","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5160050023","balance":0,"name":"Mto Software/ Antivirus","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5160050024","balance":0,"name":"Mto Software/ VMWare","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5160050025","balance":0,"name":"Mto Software/ Entrust","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5160050026","balance":0,"name":"Mto Software/ Whatsup","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5160050027","balance":0,"name":"Mto Software/ Manager y BAC","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5160050028","balance":0,"name":"Mto Software/ Licencias Oracle","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5160050029","balance":0,"name":"Mto Software/ Red Hat","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5160050030","balance":0,"name":"Mto Software/Licencias Microso","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5160050031","balance":0,"name":"Mto Software/Licencias Symante","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5160050032","balance":0,"name":"Mto Software/ Isolucion","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5160050033","balance":0,"name":"Mto Software/ SPA","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5160050036","balance":0,"name":"Mto Software/Mto VIGIA","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5160050038","balance":0,"name":"Mto Software/Mto Portales","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5160050039","balance":0,"name":"Mto Software/ACHNNET, ACH SSS","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5160050040","balance":0,"name":"Mto Software/ PSE, TEL","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5160050041","balance":0,"name":"Mto Software/ Nuevo SOI","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5160050042","balance":0,"name":"Mto Software/ otros","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5160050043","balance":0,"name":"Mto Software/ Pantalla y comun","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"516010","balance":171.55,"name":"Equipo De Oficina","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5160100005","balance":28.07,"name":"Mantenimien Equipos de Oficina","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5160100006","balance":0,"name":"Mantenimien Equipo de Computo","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5160100007","balance":38.96,"name":"Mto eq ofic/ Mto equ seguridad","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5160100008","balance":2.85,"name":"Mto eq ofic/ Periféricos","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5160100009","balance":0,"name":"Equipos de Oficina de Administ","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5160100010","balance":27.95,"name":"Mto eq ofic/ UPS","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5160100011","balance":0,"name":"Mto eq ofic/ balanc-enrutadore","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5160100012","balance":0,"name":"Mto eq ofic/ Hardware","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5160100013","balance":53.35,"name":"Mto eq ofic/ Recableado","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5160100014","balance":13.11,"name":"Mto eq ofic/ Soporte Mto SWIFT","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5160100015","balance":1.77,"name":"Mto eq ofic/ Sistema deteccion","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5160100016","balance":0,"name":"Mto eq ofic/ equipo cafeteria","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5160100017","balance":0,"name":"Mto eq ofic/ equipo oficina","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5160100018","balance":5.48,"name":"Mantenimiento Equ ofici/Tokens","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5160109505","balance":0,"name":"Mantenimiento Oficina","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"516015","balance":3.82,"name":"Muebles Y Enseres","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5160150005","balance":3.82,"name":"Mantenimien Muebles y Enseres","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"516095","balance":10537.28,"name":"Otros","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5160950005","balance":0,"name":"Mantenimiento Oficina","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5160950516","balance":245.68,"name":"Mto Software/Certifi Digitales","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5160950517","balance":0,"name":"Mto Software/ Mantenimient HCM","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5160950518","balance":0,"name":"Mto Software/ Mantenimient ERP","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5160950519","balance":0,"name":"Mto Software/ Mto Balanc-enrut","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5160950520","balance":0,"name":"Mto Software/ Telefonía IP","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5160950521","balance":0,"name":"Mto Software/ Aranda","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5160950522","balance":0,"name":"Mto Software/ Liferay","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5160950523","balance":0,"name":"Mto Software/ Antivirus","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5160950526","balance":0,"name":"Mto Software/ Whatsup","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5160950527","balance":128.93,"name":"Mto Software/ Manager y BAC","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5160950528","balance":197.98,"name":"Mto Software/ Licencias Oracle","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5160950529","balance":306.18,"name":"Mto Software/ Red Hat","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5160950530","balance":0,"name":"Mto Software/Licencias Microso","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5160950531","balance":228.29,"name":"Mto Software/Licencias Symante","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5160950533","balance":0,"name":"Mto Software/ SPA","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5160950538","balance":226.82,"name":"Mto Software/Mto Portales","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5160950539","balance":295.8,"name":"Mto Software/ACHNNET, ACH SSS","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5160950540","balance":670.64,"name":"Mto Software/ PSE, TEL","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5160950541","balance":1479.76,"name":"Mto Software/ Nuevo SOI","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5160950542","balance":4109.09,"name":"Mto Software/ otros","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5160950543","balance":0,"name":"Mto Software/ Pantalla y comun","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5160950544","balance":2648.12,"name":"Pruebas Servicios Tecnológicos","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5165","balance":196.2,"name":"Adecuación e Instalación De Of","chapter":"Gastos","nivel":4,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"516515","balance":196.2,"name":"Reparaciones Locativas","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5165150005","balance":196.2,"name":"Reparaciones Locativas Oficina","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"516595","balance":0,"name":"Otros","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5165950005","balance":0,"name":"Otros","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5170","balance":13.15,"name":"Provisiónes","chapter":"Gastos","nivel":4,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"517015","balance":0,"name":"Cuentas Por Cobrar","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5170150005","balance":0,"name":"Provision Ctas Por Cobrar","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"517020","balance":13.15,"name":"Cuentas por Cobrar","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5170201505","balance":13.15,"name":"Provision Ctas Por Cobrar","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5172","balance":3.03,"name":"Multas y Sanciones, Litigios,","chapter":"Gastos","nivel":4,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"517225","balance":3.03,"name":"Multas y Sanciones Otras Autor","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5172251005","balance":3.03,"name":"Multas y Sanciones Otras Autor","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5175","balance":3687.77,"name":"Depreciaciones","chapter":"Gastos","nivel":4,"classification":"Depreciación del periodo","status":true},{"initial_date":"2023-12-31","account":"517506","balance":140.36,"name":"Vehículos","chapter":"Gastos","nivel":6,"classification":"Depreciación del periodo","status":true},{"initial_date":"2023-12-31","account":"5175065005","balance":140.36,"name":"Vehículos en Leasing","chapter":"Gastos","nivel":10,"classification":"Depreciación del periodo","status":true},{"initial_date":"2023-12-31","account":"517507","balance":285.84,"name":"Edificios","chapter":"Gastos","nivel":6,"classification":"Depreciación del periodo","status":true},{"initial_date":"2023-12-31","account":"5175074005","balance":0,"name":"Activo por desmantelamiento of","chapter":"Gastos","nivel":10,"classification":"Depreciación del periodo","status":true},{"initial_date":"2023-12-31","account":"5175074010","balance":285.84,"name":"Mejoras en Propiedad Ajena","chapter":"Gastos","nivel":10,"classification":"Depreciación del periodo","status":true},{"initial_date":"2023-12-31","account":"517508","balance":74.06,"name":"Enseres y Accesorios","chapter":"Gastos","nivel":6,"classification":"Depreciación del periodo","status":true},{"initial_date":"2023-12-31","account":"5175081010","balance":74.06,"name":"Muebles y Enseres","chapter":"Gastos","nivel":10,"classification":"Depreciación del periodo","status":true},{"initial_date":"2023-12-31","account":"5175081011","balance":0,"name":"Muebles y Enseres/otros","chapter":"Gastos","nivel":10,"classification":"Depreciación del periodo","status":true},{"initial_date":"2023-12-31","account":"517510","balance":866.02,"name":"Equipo, Muebles y Enseres de O","chapter":"Gastos","nivel":6,"classification":"Depreciación del periodo","status":true},{"initial_date":"2023-12-31","account":"5175100010","balance":0,"name":"Muebles y Enseres","chapter":"Gastos","nivel":10,"classification":"Depreciación del periodo","status":true},{"initial_date":"2023-12-31","account":"5175101510","balance":195.52,"name":"Equipos de Oficina","chapter":"Gastos","nivel":10,"classification":"Depreciación del periodo","status":true},{"initial_date":"2023-12-31","account":"5175101515","balance":670.5,"name":"Leasing Equipos de Oficina","chapter":"Gastos","nivel":10,"classification":"Depreciación del periodo","status":true},{"initial_date":"2023-12-31","account":"517512","balance":1919.03,"name":"Equipo Informático","chapter":"Gastos","nivel":6,"classification":"Depreciación del periodo","status":true},{"initial_date":"2023-12-31","account":"5175121505","balance":742.82,"name":"Equip de Computo Admon","chapter":"Gastos","nivel":10,"classification":"Depreciación del periodo","status":true},{"initial_date":"2023-12-31","account":"5175121510","balance":374.97,"name":"Equip de Segurid de la Info","chapter":"Gastos","nivel":10,"classification":"Depreciación del periodo","status":true},{"initial_date":"2023-12-31","account":"5175121515","balance":801.24,"name":"Leasing Equipos de Computo","chapter":"Gastos","nivel":10,"classification":"Depreciación del periodo","status":true},{"initial_date":"2023-12-31","account":"517514","balance":402.46,"name":"Equipo de Redes y Comunicación","chapter":"Gastos","nivel":6,"classification":"Depreciación del periodo","status":true},{"initial_date":"2023-12-31","account":"5175141507","balance":0,"name":"Equipos de Telecomunicaciones","chapter":"Gastos","nivel":10,"classification":"Depreciación del periodo","status":true},{"initial_date":"2023-12-31","account":"5175142605","balance":0,"name":"Leasing Equipos de Telecomunic","chapter":"Gastos","nivel":10,"classification":"Depreciación del periodo","status":true},{"initial_date":"2023-12-31","account":"5175142606","balance":402.46,"name":"Equipos de Telecomunicaciones","chapter":"Gastos","nivel":10,"classification":"Depreciación del periodo","status":true},{"initial_date":"2023-12-31","account":"517515","balance":0,"name":"Equipo De Computación","chapter":"Gastos","nivel":6,"classification":"Depreciación del periodo","status":true},{"initial_date":"2023-12-31","account":"5175150005","balance":0,"name":"Equip de Computo Admon","chapter":"Gastos","nivel":10,"classification":"Depreciación del periodo","status":true},{"initial_date":"2023-12-31","account":"5175150010","balance":0,"name":"Equip de Segurid de la Info","chapter":"Gastos","nivel":10,"classification":"Depreciación del periodo","status":true},{"initial_date":"2023-12-31","account":"517550","balance":0,"name":"Vehículos","chapter":"Gastos","nivel":6,"classification":"Depreciación del periodo","status":true},{"initial_date":"2023-12-31","account":"5175500005","balance":0,"name":"Vehículos en Leasing","chapter":"Gastos","nivel":10,"classification":"Depreciación del periodo","status":true},{"initial_date":"2023-12-31","account":"5180","balance":24443.18,"name":"Amortizaciones","chapter":"Gastos","nivel":4,"classification":"Amortización del periodo","status":true},{"initial_date":"2023-12-31","account":"518015","balance":0,"name":"Estudios y Proyectos","chapter":"Gastos","nivel":6,"classification":"Amortización del periodo","status":true},{"initial_date":"2023-12-31","account":"5180150005","balance":0,"name":"Estudio Investigaciones y Pro","chapter":"Gastos","nivel":10,"classification":"Amortización del periodo","status":true},{"initial_date":"2023-12-31","account":"5180150006","balance":0,"name":"PROGRAMAS DE ADMINISTRACION","chapter":"Gastos","nivel":10,"classification":"Amortización del periodo","status":true},{"initial_date":"2023-12-31","account":"518020","balance":24443.18,"name":"Programas y Aplicaciones Infor","chapter":"Gastos","nivel":6,"classification":"Amortización del periodo","status":true},{"initial_date":"2023-12-31","account":"5180201505","balance":21006.44,"name":"Estudio Investigaciones y Pro","chapter":"Gastos","nivel":10,"classification":"Amortización del periodo","status":true},{"initial_date":"2023-12-31","account":"5180201506","balance":3436.74,"name":"PROGRAMAS DE ADMINISTRACION","chapter":"Gastos","nivel":10,"classification":"Amortización del periodo","status":true},{"initial_date":"2023-12-31","account":"518095","balance":0,"name":"OTRAS","chapter":"Gastos","nivel":6,"classification":"Amortización del periodo","status":true},{"initial_date":"2023-12-31","account":"5190","balance":55170.32,"name":"Diversos","chapter":"Gastos","nivel":4,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"519005","balance":3079.28,"name":"Servicio de Aseo y Vigilancia","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190050010","balance":104.05,"name":"Aseo Oficinas","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190050015","balance":0,"name":"Vigilancia","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190050016","balance":294.76,"name":"Custodia Archivo Físico","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190050020","balance":2680.47,"name":"Vigilancia Seguridad Informati","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"519010","balance":0,"name":"Servicios Temporales","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190100005","balance":0,"name":"Sumin Personal Temporal","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"519015","balance":5322.07,"name":"Publicidad y Propaganda","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190150005","balance":5116.91,"name":"Publicidad","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190150006","balance":0,"name":"Publicidad/ Regalos de Navidad","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190150007","balance":0,"name":"Publicidad/Concursos","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190150008","balance":0,"name":"Publicidad/Piezas","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190150009","balance":0,"name":"Publicidad/Promocionales","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190150010","balance":27.45,"name":"Publicidad/Campañas","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190150011","balance":0,"name":"Publicidad/Imagen","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190150012","balance":177.72,"name":"Publicidad/Ferias y Eventos","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"519020","balance":161.86,"name":"Relaciones Públicas","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190200018","balance":161.86,"name":"Relaciones Públicas","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"519025","balance":913.9,"name":"Servicios Públicos","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190250005","balance":9.08,"name":"Acueducto y Alcantarillado","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190250010","balance":108.3,"name":"Serv Energia Electrica","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190250015","balance":153.82,"name":"Servicio Telefonico","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190250016","balance":217.09,"name":"Serv Teléfono/ Línea 018000","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190250017","balance":0,"name":"Serv Teléfono/ Telefono fijo","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190250035","balance":0,"name":"Servicio Celulares","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190250036","balance":22.05,"name":"Celulares/preliquidacion P.A","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190250037","balance":18.75,"name":"Celulares/Consumo Compañía","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190250038","balance":0,"name":"Equ Telecomunicaciones_Celular","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190250041","balance":370.83,"name":"Intenet/ Internet","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190250042","balance":2.58,"name":"Intenet/ IP","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190250043","balance":11.39,"name":"Intenet/ Dominios","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190250044","balance":0,"name":"Intenet/ Webex","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190250045","balance":0,"name":"Intenet/ Modems","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"519030","balance":576.32,"name":"Procesamiento Electrónico de D","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190300013","balance":0,"name":"Comunicaciones Canales Dedicad","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190300016","balance":15.09,"name":"Canal dedicado/ Telmex","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190300017","balance":15.97,"name":"Canal dedicado/ Banc República","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190300018","balance":123.68,"name":"Canal dedicado/ Sincronización","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190300019","balance":0,"name":"Canal dedicado/ Canal Interno","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190300020","balance":128.97,"name":"Canal dedicado/ LAN to LAN","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190300021","balance":292.61,"name":"Canal dedicado/ Replicac datos","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190300022","balance":0,"name":"Canal dedicado/ SWIFT","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"519035","balance":260.24,"name":"Gastos De Viaje","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190350005","balance":65.7,"name":"Alojamiento y Manutencion","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190350015","balance":194.54,"name":"Pasajes Aereos","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190350020","balance":0,"name":"Alimentacion","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190350030","balance":0,"name":"Pasajes Terrestres","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"519040","balance":88.89,"name":"Transporte","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190400005","balance":37.92,"name":"Servicio de Taxi","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190400010","balance":50.97,"name":"Mensajeria","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190400015","balance":0.05,"name":"Servicio de Correo","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190400020","balance":0,"name":"Transporte Proveedores","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"519045","balance":19.19,"name":"Útiles Y Papelería","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190450005","balance":19.19,"name":"Papeleria","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190450006","balance":0,"name":"Papelería/ Carnets","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190450010","balance":0,"name":"Servicio de Impresion","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"519060","balance":0,"name":"DONACIONES","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"519065","balance":4105.8,"name":"Suscripciones","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190650005","balance":4105.8,"name":"Suscripciones","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"519095","balance":40454.08,"name":"Otros","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190950005","balance":357.96,"name":"Servicio Administracion Edific","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190950006","balance":0,"name":"Administracion - Otras sedes","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190950010","balance":3.9,"name":"Autenticaciones","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190950020","balance":0,"name":"Gastos Legales","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190950025","balance":4.57,"name":"Renovacion Matricula Mercantil","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190950035","balance":28.04,"name":"Elementos de Aseo","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190950036","balance":0,"name":"Elementos Cafeteria","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190950037","balance":43.68,"name":"Elem Cafeteria/ Maquina Café","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190950038","balance":6.59,"name":"Elem Cafeteria/ Consumo Sodexo","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190950039","balance":43.6,"name":"Elem Cafeteria/ Almrz Trabajo","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190950040","balance":0,"name":"Elementos Cafeteria Reuniones","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190950045","balance":18145.91,"name":"Afiliciones y Suscripciones","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190950046","balance":0,"name":"Lavanderia","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190950047","balance":4.56,"name":"Afiliación / ISACA","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190950048","balance":0,"name":"Afiliación / DRII","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190950049","balance":2.77,"name":"Afiliación / ACRIP","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190950050","balance":34.59,"name":"Junta Directiva","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190950051","balance":67.46,"name":"Suscripción / El Empleo","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190950052","balance":76.85,"name":"Afiliación / Superfinanciera","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190950053","balance":0,"name":"Suscripción / Códigos Legis","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190950054","balance":3.97,"name":"Suscripción / Notinet","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190950055","balance":0.31,"name":"Almuerzos de Trabajo","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190950056","balance":135.38,"name":"Afiliación / Informa","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190950057","balance":0,"name":"Suscripción / Seguridad CSI","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190950059","balance":0,"name":"Suscripción / Publicar","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190950061","balance":0,"name":"Suscripción / DirectTV","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190950062","balance":0.46,"name":"Suscripción / Revista Dinero","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190950063","balance":0.43,"name":"Suscripción / Diario República","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190950065","balance":0.06,"name":"Parqueadero Mensajeria","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190950066","balance":0,"name":"Suscripción / Club Banqueros","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190950067","balance":0,"name":"Afiliación / ICPFA","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190950070","balance":14.38,"name":"Gastos Varios Personal","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190950080","balance":0,"name":"Responsabilidad Social Empresa","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190950085","balance":12519.25,"name":"Otros Diversos","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190950097","balance":0,"name":"Call Center/ Asesores PA+PCSS","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190950098","balance":0,"name":"Call Center/ Asesores PE+CORP","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190950099","balance":0,"name":"Call Center/ Asesores BO+CHAT","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190950100","balance":0,"name":"Call Center/ Asesores Mto","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190950101","balance":0,"name":"Call Center/ Asesores PSE","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190950102","balance":338.82,"name":"Call Center/ IVR","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190950103","balance":0,"name":"Call Center/Tarific MTO","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190950104","balance":0,"name":"Call Center/Tarific PA-PE","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190950105","balance":0,"name":"Call Center/Tarific PSE","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190950106","balance":0,"name":"Call Center/Tarific SGS","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190950107","balance":0,"name":"Call Center/Licencia CMS","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190950108","balance":0,"name":"Call center/Registros Mantenim","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190950109","balance":8508.56,"name":"Call Center/Asesores PE/BO/PSE","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190950110","balance":0,"name":"BPO Campañas/Retroactivos","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190950505","balance":0.14,"name":"Intereses por Multas y Sancion","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190959505","balance":2.6,"name":"Activos Dados de Baja","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190959535","balance":3.28,"name":"Impuestos Asumidos","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190959536","balance":0.11,"name":"Impuestos Asumidos","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190959537","balance":0.49,"name":"Impuestos Asumidos","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190959538","balance":0.39,"name":"Impuestos Asumidos","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190959540","balance":105.64,"name":"Intereses de Mora","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190959541","balance":1.5,"name":"Intereses de Mora Leasing","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190959543","balance":0,"name":"Intereses de Mora Leasing","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190959545","balance":1.79,"name":"Otros Gastos no deducibles Fis","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190959549","balance":0,"name":"Intereses de Mora Leasing","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190959550","balance":0.57,"name":"Ajuste al Mil","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190959560","balance":1.03,"name":"Diferencia en Cambio Realizada","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190959566","balance":109.8,"name":"Diferencia en cambio no Realiz","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190959570","balance":0,"name":"Pruebas en proyectos","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190959581","balance":0,"name":"Penalidades","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190959705","balance":0,"name":"Riesgo Intereses de Mora","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190959710","balance":0,"name":"Riesgo Sanciones","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"519097","balance":188.68,"name":"Riesgo Operativo","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190970001","balance":188.68,"name":"RIESGO OPERATIVO DIVERSOS","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"5190970005","balance":0,"name":"Riesgo Diversos","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2023-12-31","account":"52","balance":0,"name":"No Operacionales","chapter":"Gastos","nivel":2,"classification":"No aplica","status":true},{"initial_date":"2023-12-31","account":"5215","balance":0,"name":"PERDIDA EN VENTA DE OTROS A","chapter":"Gastos","nivel":4,"classification":"No aplica","status":true},{"initial_date":"2023-12-31","account":"521597","balance":0,"name":"RIESGO OPERATIVO","chapter":"Gastos","nivel":6,"classification":"No aplica","status":true},{"initial_date":"2023-12-31","account":"5230","balance":0,"name":"Multas Y Sanciones, Litigio","chapter":"Gastos","nivel":4,"classification":"No aplica","status":true},{"initial_date":"2023-12-31","account":"523010","balance":0,"name":"Multas y Sanciones Otras Autor","chapter":"Gastos","nivel":6,"classification":"No aplica","status":true},{"initial_date":"2023-12-31","account":"5230100005","balance":0,"name":"Multas y Sanciones Otras Autor","chapter":"Gastos","nivel":10,"classification":"No aplica","status":true},{"initial_date":"2023-12-31","account":"5295","balance":0,"name":"Diversos","chapter":"Gastos","nivel":4,"classification":"No aplica","status":true},{"initial_date":"2023-12-31","account":"529505","balance":0,"name":"Intereses por Multas y Sanc","chapter":"Gastos","nivel":6,"classification":"No aplica","status":true},{"initial_date":"2023-12-31","account":"5295050005","balance":0,"name":"Intereses por Multas y Sancion","chapter":"Gastos","nivel":10,"classification":"No aplica","status":true},{"initial_date":"2023-12-31","account":"529595","balance":0,"name":"Otros","chapter":"Gastos","nivel":6,"classification":"No aplica","status":true},{"initial_date":"2023-12-31","account":"5295950005","balance":0,"name":"Activos Dados de Baja","chapter":"Gastos","nivel":10,"classification":"No aplica","status":true},{"initial_date":"2023-12-31","account":"5295950035","balance":0,"name":"Retenciones de Fuente Asumidas","chapter":"Gastos","nivel":10,"classification":"No aplica","status":true},{"initial_date":"2023-12-31","account":"5295950036","balance":0,"name":"Retenciones Asumidas por ICA","chapter":"Gastos","nivel":10,"classification":"No aplica","status":true},{"initial_date":"2023-12-31","account":"5295950037","balance":0,"name":"Retenciones Asumidas por IVA","chapter":"Gastos","nivel":10,"classification":"No aplica","status":true},{"initial_date":"2023-12-31","account":"5295950038","balance":0,"name":"Impo por operacion exterior","chapter":"Gastos","nivel":10,"classification":"No aplica","status":true},{"initial_date":"2023-12-31","account":"5295950040","balance":0,"name":"Intereses de Mora","chapter":"Gastos","nivel":10,"classification":"No aplica","status":true},{"initial_date":"2023-12-31","account":"5295950045","balance":0,"name":"Gasto No Deducible","chapter":"Gastos","nivel":10,"classification":"No aplica","status":true},{"initial_date":"2023-12-31","account":"5295950050","balance":0,"name":"Ajuste al Mil","chapter":"Gastos","nivel":10,"classification":"No aplica","status":true},{"initial_date":"2023-12-31","account":"5295950060","balance":0,"name":"Diferencia en Cambio Realizada","chapter":"Gastos","nivel":10,"classification":"No aplica","status":true},{"initial_date":"2023-12-31","account":"5295950065","balance":0,"name":"Diferenc en Cambio por Servic","chapter":"Gastos","nivel":10,"classification":"No aplica","status":true},{"initial_date":"2023-12-31","account":"5295950066","balance":0,"name":"Diferencia en cambio no Realiz","chapter":"Gastos","nivel":10,"classification":"No aplica","status":true},{"initial_date":"2023-12-31","account":"5295950080","balance":0,"name":"Gto No Deducible Ejerc Anterio","chapter":"Gastos","nivel":10,"classification":"No aplica","status":true},{"initial_date":"2023-12-31","account":"5295950081","balance":0,"name":"Penalidades","chapter":"Gastos","nivel":10,"classification":"No aplica","status":true},{"initial_date":"2023-12-31","account":"529597","balance":0,"name":"Riesgo Operativo","chapter":"Gastos","nivel":6,"classification":"No aplica","status":true},{"initial_date":"2023-12-31","account":"5295970010","balance":0,"name":"Riesgo Sanciones","chapter":"Gastos","nivel":10,"classification":"No aplica","status":true},{"initial_date":"2023-12-31","account":"54","balance":0,"name":"Impuesto De Renta y Complement","chapter":"Gastos","nivel":2,"classification":"No aplica","status":true},{"initial_date":"2023-12-31","account":"5405","balance":0,"name":"Impuesto De Renta y Complement","chapter":"Gastos","nivel":4,"classification":"No aplica","status":true},{"initial_date":"2023-12-31","account":"540505","balance":0,"name":"Renta","chapter":"Gastos","nivel":6,"classification":"No aplica","status":true},{"initial_date":"2023-12-31","account":"5405050005","balance":0,"name":"Impuesto de Renta y Complement","chapter":"Gastos","nivel":10,"classification":"No aplica","status":true},{"initial_date":"2023-12-31","account":"5405050010","balance":0,"name":"Impuesto de Renta Diferido","chapter":"Gastos","nivel":10,"classification":"No aplica","status":true},{"initial_date":"2023-12-31","account":"5405050011","balance":0,"name":"Impuesto Renta Diferido CREe","chapter":"Gastos","nivel":10,"classification":"No aplica","status":true},{"initial_date":"2023-12-31","account":"5405050015","balance":0,"name":"Impuesto Renta Period Anterior","chapter":"Gastos","nivel":10,"classification":"No aplica","status":true},{"initial_date":"2023-12-31","account":"5405050020","balance":0,"name":"Impuesto para Equidad CREE","chapter":"Gastos","nivel":10,"classification":"No aplica","status":true},{"initial_date":"2023-12-31","account":"5405050021","balance":0,"name":"Sobretasa Impuesto de CREE","chapter":"Gastos","nivel":10,"classification":"No aplica","status":true},{"initial_date":"2023-12-31","account":"57","balance":55264.36,"name":"Impuesto de Renta y Complement","chapter":"Gastos","nivel":2,"classification":"Impuestos de renta","status":true},{"initial_date":"2023-12-31","account":"5705","balance":55264.36,"name":"Impuesto de Renta y Complement","chapter":"Gastos","nivel":4,"classification":"Impuestos de renta","status":true},{"initial_date":"2023-12-31","account":"570505","balance":55264.36,"name":"Impuesto de Renta y Complement","chapter":"Gastos","nivel":6,"classification":"Impuestos de renta","status":true},{"initial_date":"2023-12-31","account":"5705050001","balance":0,"name":"Impuesto de Renta y Complement","chapter":"Gastos","nivel":10,"classification":"Impuestos de renta","status":true},{"initial_date":"2023-12-31","account":"5705050005","balance":55264.36,"name":"Impuesto de Renta y Complement","chapter":"Gastos","nivel":10,"classification":"Impuestos de renta","status":true},{"initial_date":"2023-12-31","account":"5705050010","balance":0,"name":"Impuesto de Renta Diferido","chapter":"Gastos","nivel":10,"classification":"Impuestos de renta","status":true},{"initial_date":"2023-12-31","account":"5705050015","balance":0,"name":"Impuesto Renta Periodo Anterio","chapter":"Gastos","nivel":10,"classification":"Impuestos de renta","status":true},{"initial_date":"2023-12-31","account":"5705050020","balance":0,"name":"Impuesto para Equidad CREE","chapter":"Gastos","nivel":10,"classification":"Impuestos de renta","status":true},{"initial_date":"2023-12-31","account":"5705050021","balance":0,"name":"Sobretasa Impuesto de CREE","chapter":"Gastos","nivel":10,"classification":"Impuestos de renta","status":true},{"initial_date":"2023-12-31","account":"59","balance":0,"name":"Ganancias (excedentes) Y Perdi","chapter":"Gastos","nivel":2,"classification":"Utilidad del ejercicio","status":true},{"initial_date":"2023-12-31","account":"5905","balance":0,"name":"Ganancias (excedentes) Y Perdi","chapter":"Gastos","nivel":4,"classification":"Utilidad del ejercicio","status":true},{"initial_date":"2023-12-31","account":"590501","balance":0,"name":"Ganancias (excedentes) Y Perdi","chapter":"Gastos","nivel":6,"classification":"Utilidad del ejercicio","status":true},{"initial_date":"2023-12-31","account":"590505","balance":0,"name":"Ganancias (Excedentes) y Perdi","chapter":"Gastos","nivel":6,"classification":"Utilidad del ejercicio","status":true},{"initial_date":"2023-12-31","account":"5905050005","balance":0,"name":"Resultado del Ejercicio","chapter":"Gastos","nivel":10,"classification":"Utilidad del ejercicio","status":true},{"initial_date":"2023-12-31","account":"8","balance":0,"name":"CUENTAS DE ORDEN DEUDORAS","chapter":"Cuentas de orden deudoras","nivel":1,"classification":"No aplica","status":true},{"initial_date":"2023-12-31","account":"81","balance":0,"name":"Deudoras","chapter":"Cuentas de orden deudoras","nivel":2,"classification":"No clasificado","status":false},{"initial_date":"2023-12-31","account":"8112","balance":0,"name":"BIENES INMUEBLES DESTINADOS","chapter":"Cuentas de orden deudoras","nivel":4,"classification":"No clasificado","status":false},{"initial_date":"2023-12-31","account":"811210","balance":0,"name":"CANON DE ARRENDAMIENTO","chapter":"Cuentas de orden deudoras","nivel":6,"classification":"No clasificado","status":false},{"initial_date":"2023-12-31","account":"8170","balance":0,"name":"Propiedades Y Equipo Totalment","chapter":"Cuentas de orden deudoras","nivel":4,"classification":"No clasificado","status":false},{"initial_date":"2023-12-31","account":"817010","balance":0,"name":"Equipo Muebles y Enseres De Of","chapter":"Cuentas de orden deudoras","nivel":6,"classification":"No clasificado","status":false},{"initial_date":"2023-12-31","account":"8170100099","balance":0,"name":"Muebles y Enseres","chapter":"Cuentas de orden deudoras","nivel":10,"classification":"No clasificado","status":false},{"initial_date":"2023-12-31","account":"817015","balance":0,"name":"Equipo De Computación","chapter":"Cuentas de orden deudoras","nivel":6,"classification":"No clasificado","status":false},{"initial_date":"2023-12-31","account":"8170150005","balance":0,"name":"Administracion","chapter":"Cuentas de orden deudoras","nivel":10,"classification":"No clasificado","status":false},{"initial_date":"2023-12-31","account":"8171","balance":0,"name":"Valor Fiscal De Los Activos","chapter":"Cuentas de orden deudoras","nivel":4,"classification":"No clasificado","status":false},{"initial_date":"2023-12-31","account":"817105","balance":0,"name":"Valor Fiscal De Los Activos","chapter":"Cuentas de orden deudoras","nivel":6,"classification":"No clasificado","status":false},{"initial_date":"2023-12-31","account":"8171050005","balance":0,"name":"Valor Fiscal de Los Activos","chapter":"Cuentas de orden deudoras","nivel":10,"classification":"No clasificado","status":false},{"initial_date":"2023-12-31","account":"82","balance":0,"name":"Acreedoras","chapter":"Cuentas de orden deudoras","nivel":2,"classification":"No clasificado","status":false},{"initial_date":"2023-12-31","account":"8246","balance":0,"name":"Ajustes por Inflación Patrimon","chapter":"Cuentas de orden deudoras","nivel":4,"classification":"No clasificado","status":false},{"initial_date":"2023-12-31","account":"824631","balance":0,"name":"Capital Social","chapter":"Cuentas de orden deudoras","nivel":6,"classification":"No clasificado","status":false},{"initial_date":"2023-12-31","account":"8246310005","balance":0,"name":"Capital Social","chapter":"Cuentas de orden deudoras","nivel":10,"classification":"No clasificado","status":false},{"initial_date":"2023-12-31","account":"824632","balance":0,"name":"Reservas","chapter":"Cuentas de orden deudoras","nivel":6,"classification":"No clasificado","status":false},{"initial_date":"2023-12-31","account":"8246320005","balance":0,"name":"Reservas","chapter":"Cuentas de orden deudoras","nivel":10,"classification":"No clasificado","status":false},{"initial_date":"2023-12-31","account":"824635","balance":0,"name":"Resultados de Ejercicios Anter","chapter":"Cuentas de orden deudoras","nivel":6,"classification":"No clasificado","status":false},{"initial_date":"2023-12-31","account":"8246350005","balance":0,"name":"Resultados de Ejercicios Anter","chapter":"Cuentas de orden deudoras","nivel":10,"classification":"No clasificado","status":false},{"initial_date":"2023-12-31","account":"8271","balance":0,"name":"Valor Fiscal del Patrimonio","chapter":"Cuentas de orden deudoras","nivel":4,"classification":"No clasificado","status":false},{"initial_date":"2023-12-31","account":"827105","balance":0,"name":"Diferen Fiscal Vs Contabilidad","chapter":"Cuentas de orden deudoras","nivel":6,"classification":"No clasificado","status":false},{"initial_date":"2023-12-31","account":"8271050005","balance":0,"name":"Valor Fiscal del Patrimonio","chapter":"Cuentas de orden deudoras","nivel":10,"classification":"No clasificado","status":false},{"initial_date":"2023-12-31","account":"83","balance":0,"name":"Deudoras Por Contra","chapter":"Cuentas de orden deudoras","nivel":2,"classification":"No clasificado","status":false},{"initial_date":"2023-12-31","account":"8305","balance":0,"name":"Deudoras Por Contra (CR)","chapter":"Cuentas de orden deudoras","nivel":4,"classification":"No clasificado","status":false},{"initial_date":"2023-12-31","account":"830505","balance":0,"name":"BIENES MUEBLES","chapter":"Cuentas de orden deudoras","nivel":6,"classification":"No clasificado","status":false},{"initial_date":"2023-12-31","account":"830515","balance":0,"name":"Deudoras De Control Por Contra","chapter":"Cuentas de orden deudoras","nivel":6,"classification":"No clasificado","status":false},{"initial_date":"2023-12-31","account":"8305150015","balance":0,"name":"Administracion","chapter":"Cuentas de orden deudoras","nivel":10,"classification":"No clasificado","status":false},{"initial_date":"2023-12-31","account":"8305150090","balance":0,"name":"Muebles y Eneres","chapter":"Cuentas de orden deudoras","nivel":10,"classification":"No clasificado","status":false},{"initial_date":"2023-12-31","account":"830571","balance":0,"name":"Valor Fiscal De Los Activos","chapter":"Cuentas de orden deudoras","nivel":6,"classification":"No clasificado","status":false},{"initial_date":"2023-12-31","account":"8305710005","balance":0,"name":"Valor Fiscal de los Activos Cr","chapter":"Cuentas de orden deudoras","nivel":10,"classification":"No clasificado","status":false},{"initial_date":"2023-12-31","account":"84","balance":0,"name":"Acreedoras Por Contra","chapter":"Cuentas de orden deudoras","nivel":2,"classification":"No clasificado","status":false},{"initial_date":"2023-12-31","account":"8405","balance":0,"name":"Acreedoras Por Contra (DB)","chapter":"Cuentas de orden deudoras","nivel":4,"classification":"No clasificado","status":false},{"initial_date":"2023-12-31","account":"840505","balance":0,"name":"Acreedoras Por Contra (DB)","chapter":"Cuentas de orden deudoras","nivel":6,"classification":"No clasificado","status":false},{"initial_date":"2023-12-31","account":"8405050005","balance":0,"name":"Capital Social","chapter":"Cuentas de orden deudoras","nivel":10,"classification":"No clasificado","status":false},{"initial_date":"2023-12-31","account":"8405050010","balance":0,"name":"Reservas","chapter":"Cuentas de orden deudoras","nivel":10,"classification":"No clasificado","status":false},{"initial_date":"2023-12-31","account":"8405050015","balance":0,"name":"Resultados de Ejercicios Anter","chapter":"Cuentas de orden deudoras","nivel":10,"classification":"No clasificado","status":false},{"initial_date":"2023-12-31","account":"8405050020","balance":0,"name":"Ajuste Inflacion","chapter":"Cuentas de orden deudoras","nivel":10,"classification":"No clasificado","status":false},{"initial_date":"2023-12-31","account":"840571","balance":0,"name":"Valor Fiscal Del Patrim DB","chapter":"Cuentas de orden deudoras","nivel":6,"classification":"No clasificado","status":false},{"initial_date":"2023-12-31","account":"8405710005","balance":0,"name":"Valor Fiscal Patrimnio Db","chapter":"Cuentas de orden deudoras","nivel":10,"classification":"No clasificado","status":false}]},{"date":"2024-12-31","data":[{"initial_date":"2024-12-31","account":"1","balance":371542.84,"name":"ACTIVO","chapter":"Activo","nivel":1,"classification":"No aplica","status":true},{"initial_date":"2024-12-31","account":"11","balance":207084.24,"name":"Disponible","chapter":"Activo","nivel":2,"classification":"No aplica","status":true},{"initial_date":"2024-12-31","account":"1105","balance":6.97,"name":"Caja","chapter":"Activo","nivel":4,"classification":"Efectivo y no operacionales","status":true},{"initial_date":"2024-12-31","account":"110505","balance":6.97,"name":"Efectivo","chapter":"Activo","nivel":6,"classification":"Efectivo y no operacionales","status":true},{"initial_date":"2024-12-31","account":"1105050001","balance":3.19,"name":"Efectivo USD","chapter":"Activo","nivel":10,"classification":"Efectivo y no operacionales","status":true},{"initial_date":"2024-12-31","account":"1105053001","balance":2.3,"name":"Administracion Caja Menor","chapter":"Activo","nivel":10,"classification":"Efectivo y no operacionales","status":true},{"initial_date":"2024-12-31","account":"1105059501","balance":1.48,"name":"Vales Entregados Sodexo","chapter":"Activo","nivel":10,"classification":"Efectivo y no operacionales","status":true},{"initial_date":"2024-12-31","account":"110510","balance":0,"name":"Cheques","chapter":"Activo","nivel":6,"classification":"Efectivo y no operacionales","status":true},{"initial_date":"2024-12-31","account":"1105100001","balance":0,"name":"Caja Principal","chapter":"Activo","nivel":10,"classification":"Efectivo y no operacionales","status":true},{"initial_date":"2024-12-31","account":"1110","balance":166319.94,"name":"Banco De La Republica","chapter":"Activo","nivel":4,"classification":"No aplica","status":true},{"initial_date":"2024-12-31","account":"111005","balance":166319.94,"name":"Cuenta Corriente Bancaria","chapter":"Activo","nivel":6,"classification":"No aplica","status":true},{"initial_date":"2024-12-31","account":"1110050005","balance":0,"name":"Banco de La Republica Compen","chapter":"Activo","nivel":10,"classification":"No aplica","status":true},{"initial_date":"2024-12-31","account":"1110050006","balance":166304.46,"name":"Banco de La Republica Compen","chapter":"Activo","nivel":10,"classification":"No aplica","status":true},{"initial_date":"2024-12-31","account":"1110050010","balance":15.48,"name":"Banco Republica - Administraci","chapter":"Activo","nivel":10,"classification":"No aplica","status":true},{"initial_date":"2024-12-31","account":"1115","balance":40757.33,"name":"Bancos y Otras Entidades Fi","chapter":"Activo","nivel":4,"classification":"No aplica","status":true},{"initial_date":"2024-12-31","account":"111505","balance":40757.33,"name":"Bancos","chapter":"Activo","nivel":6,"classification":"No aplica","status":true},{"initial_date":"2024-12-31","account":"1115050001","balance":15745.67,"name":"Bancos Cuenta Corriente","chapter":"Activo","nivel":10,"classification":"No aplica","status":true},{"initial_date":"2024-12-31","account":"1115050002","balance":25011.66,"name":"Bancos Cuenta de Ahorros","chapter":"Activo","nivel":10,"classification":"No aplica","status":true},{"initial_date":"2024-12-31","account":"13","balance":53436.79,"name":"Inversiones","chapter":"Activo","nivel":2,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1301","balance":0,"name":"Inversiones Valor Razonable","chapter":"Activo","nivel":4,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"130115","balance":0,"name":"Otros Emisores Nacionales","chapter":"Activo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1301150005","balance":0,"name":"CDT Moneda Nacional","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1302","balance":53436.79,"name":"Inver Negociables Titu Partici","chapter":"Activo","nivel":4,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"130205","balance":53436.79,"name":"Particip en Fondos Comunes Ord","chapter":"Activo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1302050001","balance":45548.2,"name":"Carteras Colectivas Abiertas","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1302050002","balance":7888.58,"name":"Carteras Colectivas Pacto Perm","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1306","balance":0,"name":"Inver Negociables Titu Partici","chapter":"Activo","nivel":4,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"130605","balance":0,"name":"Particip En Fondos Comunes Ord","chapter":"Activo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1306050001","balance":0,"name":"Carteras Colectivas Abiertas","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"130606","balance":0,"name":"Particip En Fondos Comunes Esp","chapter":"Activo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1306060006","balance":0,"name":"Carteras Colectivas Pacto Perm","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1308","balance":0,"name":"Inversiones Para Mantener Hast","chapter":"Activo","nivel":4,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"130811","balance":0,"name":"Titulos Emitidos, Avalados, Ac","chapter":"Activo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1308110005","balance":0,"name":"CDT Moneda Nacional","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"16","balance":73345.28,"name":"Cuentas Por Cobrar","chapter":"Activo","nivel":2,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1614","balance":41979.67,"name":"Venta de bienes y servicios","chapter":"Activo","nivel":4,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"161405","balance":0,"name":"Bienes","chapter":"Activo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1614050001","balance":0,"name":"Venta de Bienes","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"161410","balance":41979.67,"name":"Servicios","chapter":"Activo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1614100001","balance":41979.67,"name":"Servicios PSE,SOI, ACH, SWIFT","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1614100002","balance":0,"name":"Ingresos Patrocinio Seminarios","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1614100003","balance":0,"name":"Clientes Extranjeros","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1614100004","balance":0,"name":"Clientes pendientes de factura","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"161415","balance":0,"name":"Transferencia de fondos de com","chapter":"Activo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1614151510","balance":0,"name":"Transferencia Fondos Compensac","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1630","balance":29390.01,"name":"Venta De Bienes Y Servicios","chapter":"Activo","nivel":4,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"163005","balance":14504.08,"name":"BIENES","chapter":"Activo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1630050005","balance":14504.08,"name":"Anticipo de Impto Renta y Comp","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1630050006","balance":0,"name":"Anticipo Sobretasa Renta y Com","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1630051215","balance":0,"name":"Sobrante en Liquidacion Renta","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"163010","balance":4.64,"name":"Servicios","chapter":"Activo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1630100001","balance":0,"name":"Servicios PSE,SOI, ACH, SWIFT","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1630100002","balance":0,"name":"Ingresos Patrocinio Seminarios","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1630100003","balance":0,"name":"Clientes Exterior_Serv_SWIFT","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1630103505","balance":4.64,"name":"ICA Retenido","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"163015","balance":14881.29,"name":"Transferencia De Fondos","chapter":"Activo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1630150010","balance":0,"name":"Transferencia Fondos Compensac","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1630151005","balance":0,"name":"otros Ing. trib 2.5%","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1630151006","balance":0,"name":"Servicios Generales","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1630151008","balance":0,"name":"Compras generales 2.5%","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1630151009","balance":543.87,"name":"Retefuente Rendim Financier 7%","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1630151036","balance":0,"name":"Autoretención CREE 0.8%","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1630151045","balance":0,"name":"Autorretención CREE Rend Finan","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1630151047","balance":107.04,"name":"Autorretención RENTA Rend Fina","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1630151048","balance":2957.57,"name":"Autoretención RENTA 0.8%","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1630151049","balance":11272.81,"name":"Autoretención Servicios 4%","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"163040","balance":0,"name":"Impuesto a las ventas","chapter":"Activo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1630401220","balance":0,"name":"Saldo a Favor IVA","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"163045","balance":0,"name":"Impuesto sobre la renta para l","chapter":"Activo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1630451225","balance":0,"name":"ANTICIPO SOBRETASA CREE","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1632","balance":0,"name":"Anticipos a contratos y provee","chapter":"Activo","nivel":4,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"163205","balance":0,"name":"Anticipos a contratos y provee","chapter":"Activo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1632050001","balance":0,"name":"Anticipos Contratos","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"163210","balance":0,"name":"Anticipos a contratos y provee","chapter":"Activo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1632100001","balance":0,"name":"Anticipos Proveedores","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1634","balance":1.22,"name":"A empleados","chapter":"Activo","nivel":4,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"163495","balance":1.22,"name":"Otros","chapter":"Activo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1634950005","balance":0.53,"name":"Anticipo para Gastos Viaje","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1634950006","balance":0.68,"name":"Anticipos Laborales","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1635","balance":0,"name":"PAGOS POR CUENTA DE CLIENTE","chapter":"Activo","nivel":4,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"163595","balance":0,"name":"OTROS","chapter":"Activo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1645","balance":0,"name":"Anticipos De Contratos Y Pr","chapter":"Activo","nivel":4,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"164505","balance":0,"name":"Anticipos De Contratos","chapter":"Activo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1645050001","balance":0,"name":"Anticipos Contratos","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"164510","balance":0,"name":"Anticipo De Proveedores","chapter":"Activo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1645100001","balance":0,"name":"Anticipos Proveedores","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1655","balance":0,"name":"Adelantos Al Personal","chapter":"Activo","nivel":4,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"165505","balance":0,"name":"Anticipos A Empleados","chapter":"Activo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1655050005","balance":0,"name":"Anticipos Laborales","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"165510","balance":0,"name":"Anticipo De Gastos De Viaje","chapter":"Activo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1655100005","balance":0,"name":"Anticipo para Gastos Viaje","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1687","balance":0,"name":"Diversas","chapter":"Activo","nivel":4,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"168795","balance":0,"name":"Otras","chapter":"Activo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1687950005","balance":0,"name":"Deudores Sancion Interinstituc","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1687950006","balance":0,"name":"Deudores empleados_Med prepag","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1687950007","balance":0,"name":"Deudores empleados_Movistar","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1687950008","balance":0,"name":"Deudores empleados_Libranzas","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1687950009","balance":0,"name":"Deudores empleados_Otros Concp","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1687950013","balance":0,"name":"Deudores por Incapacidad EPS","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1687950090","balance":0,"name":"Cuenta por cobrar a terceros","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1687950095","balance":0,"name":"Otros","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1690","balance":1976.91,"name":"Diversas","chapter":"Activo","nivel":4,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"169095","balance":1976.91,"name":"Otras","chapter":"Activo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1690950005","balance":65.93,"name":"Deudores Sancion Interinstituc","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1690950006","balance":1.04,"name":"Deudores empleados_Med prepag","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1690950007","balance":0.23,"name":"Deudores empleados_Movistar","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1690950008","balance":0,"name":"Deudores empleados_Libranzas","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1690950009","balance":0,"name":"Deudores empleados_Otros Concp","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1690950090","balance":1911.79,"name":"Cuenta por cobrar a terceros","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1690950095","balance":0,"name":"Otros","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1694","balance":2.53,"name":"Provisión Cuentas Por Cobrar","chapter":"Activo","nivel":4,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"169430","balance":2.53,"name":"Venta De Bienes Y Servicios","chapter":"Activo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1694300005","balance":2.53,"name":"Servic por Traferencia Electro","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"18","balance":3423.44,"name":"Propiedades Y Equipo","chapter":"Activo","nivel":2,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2024-12-31","account":"1801","balance":2901.1,"name":"Propiedad, planta y equipo","chapter":"Activo","nivel":4,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2024-12-31","account":"180104","balance":0,"name":"Edificios","chapter":"Activo","nivel":6,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2024-12-31","account":"1801040005","balance":0,"name":"Activo por desmantelamiento of","chapter":"Activo","nivel":10,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2024-12-31","account":"180112","balance":411.09,"name":"Vehículos","chapter":"Activo","nivel":6,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2024-12-31","account":"1801120510","balance":411.09,"name":"Vehiculos/Leasing Financiero","chapter":"Activo","nivel":10,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2024-12-31","account":"180120","balance":1999.47,"name":"Enseres","chapter":"Activo","nivel":6,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2024-12-31","account":"1801200505","balance":1999.47,"name":"Muebles y Enseres","chapter":"Activo","nivel":10,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2024-12-31","account":"180122","balance":89.74,"name":"Equipo","chapter":"Activo","nivel":6,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2024-12-31","account":"1801220510","balance":89.74,"name":"Equipos de Oficina","chapter":"Activo","nivel":10,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2024-12-31","account":"180124","balance":20316.58,"name":"Equipo Informático","chapter":"Activo","nivel":6,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2024-12-31","account":"1801240505","balance":2783.01,"name":"Equipos de Computo","chapter":"Activo","nivel":10,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2024-12-31","account":"1801240510","balance":14649.06,"name":"Leasing Equipos de Computo","chapter":"Activo","nivel":10,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2024-12-31","account":"1801240515","balance":2884.51,"name":"Equipos de Seguridad Informati","chapter":"Activo","nivel":10,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2024-12-31","account":"180126","balance":2515.31,"name":"Equipo de Redes y Comunicación","chapter":"Activo","nivel":6,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2024-12-31","account":"1801261005","balance":2515.31,"name":"Equipos de Telecomunicaciones","chapter":"Activo","nivel":10,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2024-12-31","account":"180160","balance":0,"name":"Revaluación Propiedad, Planta","chapter":"Activo","nivel":6,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2024-12-31","account":"1801602410","balance":0,"name":"Leasing Equipos de Computo","chapter":"Activo","nivel":10,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2024-12-31","account":"180162","balance":22431.09,"name":"Depreciación y Agotamiento pro","chapter":"Activo","nivel":6,"classification":"Depreciación acumulada","status":true},{"initial_date":"2024-12-31","account":"1801620405","balance":0,"name":"Activo por desmantelamiento of","chapter":"Activo","nivel":10,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2024-12-31","account":"1801621005","balance":1647.25,"name":"Muebles y Enseres","chapter":"Activo","nivel":10,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2024-12-31","account":"1801621505","balance":2054.22,"name":"Equipos de Computo","chapter":"Activo","nivel":10,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2024-12-31","account":"1801621506","balance":2845.8,"name":"Equipos de Seguridad Inform","chapter":"Activo","nivel":10,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2024-12-31","account":"1801621507","balance":1630.59,"name":"Equipo de telecomunicaciones","chapter":"Activo","nivel":10,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2024-12-31","account":"1801621510","balance":14077.76,"name":"Leasing Equipos de Computo","chapter":"Activo","nivel":10,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2024-12-31","account":"1801622010","balance":130.78,"name":"Vehiculos/Leasing Financiero","chapter":"Activo","nivel":10,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2024-12-31","account":"1801622210","balance":44.69,"name":"Equipos de Oficina","chapter":"Activo","nivel":10,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2024-12-31","account":"1801622215","balance":0,"name":"Leasing Equipos de Oficina","chapter":"Activo","nivel":10,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2024-12-31","account":"180195","balance":0,"name":"Otros Equipos Máquina Montaje","chapter":"Activo","nivel":6,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2024-12-31","account":"1801950001","balance":0,"name":"Otros Equipos/Máquinas en Mont","chapter":"Activo","nivel":10,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2024-12-31","account":"1818","balance":522.34,"name":"Mejoras propiedad Ajena","chapter":"Activo","nivel":4,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2024-12-31","account":"181805","balance":1751.57,"name":"Mejora en Propiedad planta y","chapter":"Activo","nivel":6,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2024-12-31","account":"1818050501","balance":1751.57,"name":"Mejoras en propiedades Ajenas","chapter":"Activo","nivel":10,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2024-12-31","account":"181897","balance":1229.23,"name":"DEPRECIACION DE ACTIVOS MEJORA","chapter":"Activo","nivel":6,"classification":"Depreciación acumulada","status":true},{"initial_date":"2024-12-31","account":"1818970501","balance":1229.23,"name":"DEPRECIACION Y/O AMORTIZACION","chapter":"Activo","nivel":10,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2024-12-31","account":"1820","balance":0,"name":"Equipo, Muebles Y Enseres D","chapter":"Activo","nivel":4,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2024-12-31","account":"182005","balance":0,"name":"Muebles Y Enseres","chapter":"Activo","nivel":6,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2024-12-31","account":"1820050005","balance":0,"name":"Muebles y Enseres","chapter":"Activo","nivel":10,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2024-12-31","account":"1820050010","balance":0,"name":"Equipos de Oficina","chapter":"Activo","nivel":10,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2024-12-31","account":"1825","balance":0,"name":"Equipo De Computación","chapter":"Activo","nivel":4,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2024-12-31","account":"182505","balance":0,"name":"Equipos De Procesamiento De","chapter":"Activo","nivel":6,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2024-12-31","account":"1825050005","balance":0,"name":"Equipos de Computo","chapter":"Activo","nivel":10,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2024-12-31","account":"1825050015","balance":0,"name":"Equipos de Seguridad Informati","chapter":"Activo","nivel":10,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2024-12-31","account":"182510","balance":0,"name":"Equipos De Telecomunicación","chapter":"Activo","nivel":6,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2024-12-31","account":"1825100005","balance":0,"name":"Equipos de Telecomunicaciones","chapter":"Activo","nivel":10,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2024-12-31","account":"1830","balance":0,"name":"Vehículos","chapter":"Activo","nivel":4,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2024-12-31","account":"183005","balance":0,"name":"Vehiculos","chapter":"Activo","nivel":6,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2024-12-31","account":"1830050010","balance":0,"name":"Vehiculos/Leasing Financiero","chapter":"Activo","nivel":10,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2024-12-31","account":"1895","balance":0,"name":"Depreciación y Amortización","chapter":"Activo","nivel":4,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2024-12-31","account":"189510","balance":0,"name":"Equipo, Muebles Y Enseres D","chapter":"Activo","nivel":6,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2024-12-31","account":"1895100005","balance":0,"name":"Muebles y Enseres Equip Ofic","chapter":"Activo","nivel":10,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2024-12-31","account":"189515","balance":0,"name":"Equipo De Computación","chapter":"Activo","nivel":6,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2024-12-31","account":"1895150005","balance":0,"name":"Equipos de Computo","chapter":"Activo","nivel":10,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2024-12-31","account":"1895150006","balance":0,"name":"Equipos de Seguridad Inform","chapter":"Activo","nivel":10,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2024-12-31","account":"1895150007","balance":0,"name":"Equipo de telecomunicaciones","chapter":"Activo","nivel":10,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2024-12-31","account":"189520","balance":0,"name":"Vehiculos - Leasing Financiero","chapter":"Activo","nivel":6,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2024-12-31","account":"1895200010","balance":0,"name":"Vehículos Leasing Financiero","chapter":"Activo","nivel":10,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2024-12-31","account":"1899","balance":0,"name":"Provisión Propiedades y Equipo","chapter":"Activo","nivel":4,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2024-12-31","account":"189905","balance":0,"name":"Provisión Propiedades y Equipo","chapter":"Activo","nivel":6,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2024-12-31","account":"1899050005","balance":0,"name":"Provision Propiedades y Equipo","chapter":"Activo","nivel":10,"classification":"Propiedad, planta y equipo","status":true},{"initial_date":"2024-12-31","account":"19","balance":34253.11,"name":"Otros Activos","chapter":"Activo","nivel":2,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1910","balance":8721.31,"name":"Impuesto Diferido NIIF","chapter":"Activo","nivel":4,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"191005","balance":8721.31,"name":"Impuesto Diferido Activo","chapter":"Activo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1910050005","balance":8721.31,"name":"IMPUESTO_ DIFERIDO_ ACTIVO","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1911","balance":17230.67,"name":"Activos Intangibles","chapter":"Activo","nivel":4,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"191135","balance":61031.95,"name":"Programas y aplicaciones infor","chapter":"Activo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1911350005","balance":61031.95,"name":"Software Administracion","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"191160","balance":7167.54,"name":"Otros activos intangibles","chapter":"Activo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1911600005","balance":419.49,"name":"Proyectos Area","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1911600010","balance":6713.8,"name":"Proyectos Compañía","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1911600015","balance":34.25,"name":"Proyectos Mandatorio","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"191165","balance":50968.83,"name":"AMORTIZACION ACUMULADA","chapter":"Activo","nivel":6,"classification":"Amortización acumulada","status":true},{"initial_date":"2024-12-31","account":"1911650505","balance":47704.27,"name":"Amortización - Software Admini","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1911651005","balance":399.51,"name":"Amortización - Proyectos Área","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1911651010","balance":2830.8,"name":"Amortización - Proyectos Compa","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1911651015","balance":34.25,"name":"Software/licencia operación Am","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1912","balance":0,"name":"Aportes Permanentes","chapter":"Activo","nivel":4,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"191210","balance":0,"name":"Clubes Sociales","chapter":"Activo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1912100005","balance":0,"name":"Club Social","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1915","balance":0,"name":"Gastos Anticipados","chapter":"Activo","nivel":4,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"191510","balance":0,"name":"Seguros","chapter":"Activo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1915100001","balance":0,"name":"Seguros","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"191515","balance":0,"name":"ARRENDAMIENTOS","chapter":"Activo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"191535","balance":0,"name":"Mantenimiento Equipos","chapter":"Activo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1915350001","balance":0,"name":"Mantenimiento de equipos","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1915350002","balance":0,"name":"Mantenimiento de programas","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1915350005","balance":0,"name":"Servicios","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"191595","balance":0,"name":"Otros","chapter":"Activo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1915950010","balance":0,"name":"OTROS GASTOS ANTICIPADOS","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1920","balance":0,"name":"Cargos Diferidos","chapter":"Activo","nivel":4,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"192015","balance":0,"name":"Estudios Y Proyectos","chapter":"Activo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1920150005","balance":0,"name":"Proyectos Area","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1920150010","balance":0,"name":"Proyectos Compañía","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1920150015","balance":0,"name":"Proyectos Mandatorio","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"192020","balance":0,"name":"Programas Para Computador","chapter":"Activo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1920200005","balance":0,"name":"Software Administracion","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"192040","balance":0,"name":"Impuesto De Renta Diferido","chapter":"Activo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1920400005","balance":0,"name":"Impuesto de Renta Diferido","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1920400006","balance":0,"name":"Impuesto Renta Diferido CREE","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"192055","balance":0,"name":"Contribuciones y Afiliaciones","chapter":"Activo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1920550005","balance":0,"name":"Contribuciones y Afiliaciones","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1925","balance":8301.13,"name":"Gastos pagados por anticipado","chapter":"Activo","nivel":4,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"192505","balance":1202.5,"name":"Seguros","chapter":"Activo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1925050001","balance":1202.5,"name":"Seguros","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"192595","balance":7098.63,"name":"Otros","chapter":"Activo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1925950010","balance":752.17,"name":"OTROS GASTOS ANTICIPADOS","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1925953501","balance":249.89,"name":"Mantenimiento de equipos","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1925953502","balance":1155.36,"name":"Mantenimiento de programas","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1925953505","balance":1909.52,"name":"Servicios","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1925955005","balance":3031.69,"name":"Contribuciones y Afiliaciones","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1990","balance":0,"name":"Diversos","chapter":"Activo","nivel":4,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"199005","balance":0,"name":"ANTICIPOS IMPORRENTA","chapter":"Activo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"199010","balance":0,"name":"Retención En La Fuente","chapter":"Activo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1990100006","balance":0,"name":"Servicios Generales","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1990100008","balance":0,"name":"Compras generales 2.5%","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1990100009","balance":0,"name":"Retefuente Rendim Financier 7%","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1990100036","balance":0,"name":"Autoretención CREE 0.8%","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1990100045","balance":0,"name":"Autorretención CREE Rend Finan","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"199012","balance":0,"name":"Sobrantes De Anticipos Y Re","chapter":"Activo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1990120015","balance":0,"name":"Sobrante en Liquidacion Renta","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1990120020","balance":0,"name":"Saldo a Favor IVA","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1990120025","balance":0,"name":"ANTICIPO SOBRETASA CREE","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"199030","balance":0,"name":"Caja Menor","chapter":"Activo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1990300001","balance":0,"name":"Administracion Caja Menor","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"199035","balance":0,"name":"Anticipo Impuesto De Industria","chapter":"Activo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1990350005","balance":0,"name":"ICA Retenido","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"199095","balance":0,"name":"Otros","chapter":"Activo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1990950001","balance":0,"name":"Vales Entregados Sodexo","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1995","balance":0,"name":"Valorizaciones","chapter":"Activo","nivel":4,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"199510","balance":0,"name":"Propiedades Y Equipo","chapter":"Activo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"1995100005","balance":0,"name":"Propiedad Planta y Equipo","chapter":"Activo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2","balance":261718.02,"name":"PASIVO","chapter":"Pasivo","nivel":1,"classification":"No aplica","status":true},{"initial_date":"2024-12-31","account":"24","balance":1000,"name":"Créditos De Bancos y Otras","chapter":"Pasivo","nivel":2,"classification":"Deuda con costo financiero","status":true},{"initial_date":"2024-12-31","account":"2404","balance":0,"name":"Dividendos Por Pagar","chapter":"Pasivo","nivel":4,"classification":"Deuda con costo financiero","status":true},{"initial_date":"2024-12-31","account":"240405","balance":0,"name":"Dividendos Por Pagar","chapter":"Pasivo","nivel":6,"classification":"Deuda con costo financiero","status":true},{"initial_date":"2024-12-31","account":"2404050505","balance":0,"name":"Dividendos por Pagar","chapter":"Pasivo","nivel":10,"classification":"Deuda con costo financiero","status":true},{"initial_date":"2024-12-31","account":"2430","balance":0,"name":"Otros Bancos Y Entidades Fi","chapter":"Pasivo","nivel":4,"classification":"Deuda con costo financiero","status":true},{"initial_date":"2024-12-31","account":"243005","balance":0,"name":"Créditos","chapter":"Pasivo","nivel":6,"classification":"Deuda con costo financiero","status":true},{"initial_date":"2024-12-31","account":"2430050005","balance":0,"name":"Bancolombia Tarjeta de Credito","chapter":"Pasivo","nivel":10,"classification":"Deuda con costo financiero","status":true},{"initial_date":"2024-12-31","account":"2435","balance":1000,"name":"Otros bancos y entidades finan","chapter":"Pasivo","nivel":4,"classification":"Deuda con costo financiero","status":true},{"initial_date":"2024-12-31","account":"243505","balance":3.36,"name":"Créditos","chapter":"Pasivo","nivel":6,"classification":"Deuda con costo financiero","status":true},{"initial_date":"2024-12-31","account":"2435050005","balance":3.36,"name":"Bancolombia Tarjeta de Credito","chapter":"Pasivo","nivel":10,"classification":"Deuda con costo financiero","status":true},{"initial_date":"2024-12-31","account":"243560","balance":996.65,"name":"Contratos de arrendamiento fin","chapter":"Pasivo","nivel":6,"classification":"Deuda con costo financiero","status":true},{"initial_date":"2024-12-31","account":"2435600001","balance":110.82,"name":"Arrendamientos Leasing","chapter":"Pasivo","nivel":10,"classification":"Deuda con costo financiero","status":true},{"initial_date":"2024-12-31","account":"2435600002","balance":838.74,"name":"Obligacion Financiera Leasing","chapter":"Pasivo","nivel":10,"classification":"Deuda con costo financiero","status":true},{"initial_date":"2024-12-31","account":"2435600004","balance":45.87,"name":"Obligacion Financiera Leasing","chapter":"Pasivo","nivel":10,"classification":"Deuda con costo financiero","status":true},{"initial_date":"2024-12-31","account":"2435600006","balance":1.22,"name":"Obligacion Financiera Leasing","chapter":"Pasivo","nivel":10,"classification":"Deuda con costo financiero","status":true},{"initial_date":"2024-12-31","account":"2435600008","balance":0,"name":"Obligacion Financiera Leasing","chapter":"Pasivo","nivel":10,"classification":"Deuda con costo financiero","status":true},{"initial_date":"2024-12-31","account":"2435600009","balance":0,"name":"Obligacion Financiera Leasing","chapter":"Pasivo","nivel":10,"classification":"Deuda con costo financiero","status":true},{"initial_date":"2024-12-31","account":"2435600010","balance":0,"name":"Obligación Financiera Leasing","chapter":"Pasivo","nivel":10,"classification":"Deuda con costo financiero","status":true},{"initial_date":"2024-12-31","account":"2435600011","balance":0,"name":"Leasing 180-119248","chapter":"Pasivo","nivel":10,"classification":"Deuda con costo financiero","status":true},{"initial_date":"2024-12-31","account":"2435600012","balance":0,"name":"Obligacion Financiera Renting","chapter":"Pasivo","nivel":10,"classification":"Deuda con costo financiero","status":true},{"initial_date":"2024-12-31","account":"2495","balance":0,"name":"Otras Obligaciones Financieras","chapter":"Pasivo","nivel":4,"classification":"Deuda con costo financiero","status":true},{"initial_date":"2024-12-31","account":"249595","balance":0,"name":"Otras","chapter":"Pasivo","nivel":6,"classification":"Deuda con costo financiero","status":true},{"initial_date":"2024-12-31","account":"2495950010","balance":0,"name":"Otras Obligaciones Financieras","chapter":"Pasivo","nivel":10,"classification":"Deuda con costo financiero","status":true},{"initial_date":"2024-12-31","account":"25","balance":252240.38,"name":"Cuentas Por Pagar","chapter":"Pasivo","nivel":2,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2501","balance":2720.02,"name":"Comisiones","chapter":"Pasivo","nivel":4,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"250105","balance":2720.02,"name":"Honorarios","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2501050005","balance":1384.02,"name":"Honorarios Profesionales","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2501050006","balance":0,"name":"Honorarios Profesionales Extra","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2501050010","balance":1336,"name":"Honorarios Profesionales Prov.","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2502","balance":3332.92,"name":"Costos y gastos por pagar","chapter":"Pasivo","nivel":4,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"250205","balance":3332.92,"name":"Servicios","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2502059510","balance":17.22,"name":"Servicios Publicos","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2502059530","balance":0,"name":"Servicios en General","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2502059535","balance":3315.7,"name":"Servicios en General Prov.","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"250220","balance":0,"name":"Gastos de viaje","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2502209512","balance":0,"name":"Gastos de Viajes","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2502209515","balance":0,"name":"Gastos de Viajes","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2503","balance":61169.24,"name":"Impuestos","chapter":"Pasivo","nivel":4,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"250305","balance":56488.32,"name":"Renta y complementarios","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2503050501","balance":56488.32,"name":"De Renta y Complementarios","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"250310","balance":1147.05,"name":"Industria y comercio","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2503100001","balance":0.21,"name":"Retencion ICA 0.414%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2503100002","balance":24.67,"name":"Retencion ICA 0.69%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2503100003","balance":30.68,"name":"Retencion ICA 0.966%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2503100004","balance":1.43,"name":"Retencion ICA 1.104%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2503100006","balance":1.64,"name":"Retencion ICA 1.38%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2503100007","balance":0,"name":"Retencion ICA Retencion ICA-0,712%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2503100008","balance":0.62,"name":"Retencion ICA 0,766%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2503100009","balance":1.88,"name":"Retencion ICA 0,866%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2503101005","balance":1085.92,"name":"Industria y Comercio","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"250330","balance":0,"name":"CREE","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"250339","balance":0,"name":"cuenta autogenerada para chequeo de capitulos","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2503395001","balance":0,"name":"Impuesto a la Equidad CREE","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2503395002","balance":0,"name":"Sobretasa_CREE","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"250340","balance":3533.88,"name":"Sobre las ventas por pagar","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2503400005","balance":11.7,"name":"Iva Generado 16 %","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2503400006","balance":0,"name":"IVA Descontable Compras 16%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2503400007","balance":4788.1,"name":"Iva Generado 19%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2503400012","balance":5.13,"name":"IVA Descontable Compras 19%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2503400013","balance":0.02,"name":"IVA Descontable 5% - Compras","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2503400014","balance":0,"name":"IVA Descontable 5% - Servicios","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2503400021","balance":0,"name":"IVA Desc.Reg.Simplific.(2.4%)","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2503400024","balance":1226.94,"name":"IVA Descontable Servicios 19%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2503400025","balance":0,"name":"IVA Descontable Servicios 16%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2503400026","balance":33.83,"name":"IVA_Asumido_Compras_Exterior","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2504","balance":110.04,"name":"Dividendos y excedentes","chapter":"Pasivo","nivel":4,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"250405","balance":110.04,"name":"Dividendos","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2504050505","balance":110.04,"name":"Dividendos por Pagar","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2505","balance":87.69,"name":"Arrendamientos","chapter":"Pasivo","nivel":4,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"250540","balance":87.69,"name":"Arrendamientos","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2505400005","balance":87.69,"name":"Arrendamientos Administrativos","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2510","balance":0,"name":"Comisiones Y Honorarios","chapter":"Pasivo","nivel":4,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"251010","balance":0,"name":"Honorarios","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2510100005","balance":0,"name":"Honorarios Profesionales","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2515","balance":0,"name":"Impuestos","chapter":"Pasivo","nivel":4,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"251505","balance":0,"name":"RENTA Y COMPLEMENTARIOS","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"251510","balance":0,"name":"Industria Y Comercio","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2515100001","balance":0,"name":"Retencion ICA 0.414%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2515100002","balance":0,"name":"Retencion ICA 0.69%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2515100003","balance":0,"name":"Retencion ICA 0.966%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2515100004","balance":0,"name":"Retencion ICA 1.104%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2515100005","balance":0,"name":"Vigencia Fiscal Corriente","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2515100006","balance":0,"name":"Retencion ICA 1.38%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"251595","balance":0,"name":"Sobretasas Y Otros","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2515950011","balance":0,"name":"Impuesto al Patrimonio","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2515950012","balance":0,"name":"Impuesto a La Equidad CREE","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2519","balance":2734.09,"name":"Retenciones y aportes laborale","chapter":"Pasivo","nivel":4,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"251910","balance":0,"name":"Judiciales","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2519100001","balance":0,"name":"Embargos Judiciales a empleado","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"251945","balance":2734.09,"name":"Retenciones y aportes de nomin","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2519450005","balance":181.38,"name":"Retención fuente por Salarios","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2519450009","balance":0.16,"name":"Retención fuente Servicios 2%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2519450010","balance":103.01,"name":"Honorarios 11 % Declarantes","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2519450015","balance":0,"name":"Honorarios 10 % No Declarantes","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2519450017","balance":0.02,"name":"Retención en la Fuente Honorar","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2519450020","balance":0.15,"name":"Retención fuente Servicios 1%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2519450025","balance":0,"name":"Retención Fuente Serv Temp 2%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2519450030","balance":32.16,"name":"Ret Fte Serv 4% Declarantes","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2519450036","balance":0,"name":"RetFte Contrato Ing Proy 6%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2519450038","balance":93.86,"name":"Retefuente 3.5% Serv Informati","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2519450040","balance":0,"name":"Refte Ser Hot/Rest No Dec 3,5%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2519450043","balance":3.45,"name":"RteFte Serv Hoteles rest 3,5%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2519450044","balance":4.98,"name":"RteFte Arriendo inmuebles 3,5%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2519450047","balance":0,"name":"Rtefte serv transp pasaje 3.5%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2519450050","balance":2.9,"name":"Ret Fte Arriend Bns Mueb 4%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2519450054","balance":0,"name":"Re Fte Pagos al Exterior 15%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2519450055","balance":0,"name":"Ret Fte Compras No Decl 3.5%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2519450057","balance":1.34,"name":"Rete Fte Compras Declaran 2.5%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2519450058","balance":9.14,"name":"Ret Fte Pagos al Exterior 10%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2519450059","balance":0,"name":"Ret Fte Pagos al Exter 26.4%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2519450060","balance":0,"name":"Ret Fte Pagos al Exterior 33 %","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2519450061","balance":33.83,"name":"Ret Fte por IVA Pago Ext 100%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2519450062","balance":16.86,"name":"retención del Exterior por Exp","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2519450064","balance":0,"name":"Ret IVA Reg Simplif 15% (2.4%)","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2519450067","balance":134.97,"name":"Rte IVA Reg Comun 15% (2.4%)","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2519450068","balance":0,"name":"Rte Fte. Dividendos 33%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2519450069","balance":0,"name":"Rte Fte. Dividendos 7.5%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2519450071","balance":0,"name":"Rte Fte Dividendos 35%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2519450073","balance":0,"name":"Rte Fte Dividendos 10%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2519450076","balance":0,"name":"Retención en la Fuente por Com","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2519450078","balance":12.94,"name":"Autorretención RENTA Rend Fina","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2519450079","balance":279.37,"name":"Autorretención RENTA 0,8%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2519450085","balance":0,"name":"Autorretención CREE Rend Finan","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2519450086","balance":0.38,"name":"Retención en la Fuente Consult","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2519450087","balance":0,"name":"Retención en la Fuente Consult","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2519450089","balance":0,"name":"Retención en la Fuente Transpo","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2519450090","balance":0,"name":"Retención en la Fuente Dividen","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2519450092","balance":0,"name":"Rte Fte Comisiones P Jurid 11%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2519450097","balance":0,"name":"Autorretención CREE 0,8%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2519450098","balance":0,"name":"Rte Fte Otros Ing Tribut 4,5%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2519450099","balance":1013.87,"name":"Autoretención Servicios 4%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2519453005","balance":0,"name":"Fondo de Empleados","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2519453505","balance":0,"name":"Aportes a EPS","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2519453506","balance":175.26,"name":"Aportes a EPS Pago","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2519453515","balance":33.82,"name":"Medicina Prepagada Colsanitas","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2519453516","balance":0,"name":"Medicina Prepagada Compensar","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2519453517","balance":1.63,"name":"Medicina Prepagada Medisanitas","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2519453518","balance":0.62,"name":"Medicina prepagada Emermedica","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2519453520","balance":13.02,"name":"Aportes A R L","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2519454005","balance":144.65,"name":"Aport Caja Comp ICBF SENA","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2519459510","balance":0,"name":"Aportes a Fondo de Pension","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2519459511","balance":440.33,"name":"Aportes Fondo de Pensión Pago","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2519459515","balance":0,"name":"Aportes a Fdos Pens Volunt","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2519459520","balance":0,"name":"Aportes a Cuentas AFC","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2520","balance":0,"name":"DIVIDENDOS Y EXCEDENTES","chapter":"Pasivo","nivel":4,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"252005","balance":0,"name":"DIVIDENDOS DECRETADOS","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2525","balance":0,"name":"Arrendamientos","chapter":"Pasivo","nivel":4,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"252540","balance":0,"name":"Arrendamientos","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2525400005","balance":0,"name":"Arrendamientos Administrativos","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2535","balance":0,"name":"Impuesto A Las Ventas Por P","chapter":"Pasivo","nivel":4,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"253505","balance":0,"name":"Iva Generado 16 %","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2535050005","balance":0,"name":"IVA Generado 16%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"253510","balance":0,"name":"Iva Descontable","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2535100005","balance":0,"name":"IVA Descontable Compras 16%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2535100013","balance":0,"name":"IVA Descontable 5% - Compras","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2535100014","balance":0,"name":"IVA Descontable 5% - Servicios","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2535100021","balance":0,"name":"IVA Desc.Reg.Simplific.(2.4%)","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2535100025","balance":0,"name":"IVA Descontable Servicios 16%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2555","balance":0,"name":"Retenciones Y Aportes Laborale","chapter":"Pasivo","nivel":4,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"255505","balance":0,"name":"Retenciones En La Fuente","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2555050005","balance":0,"name":"Retención fuente por Salarios","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2555050009","balance":0,"name":"Retención fuente Servicios 2%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2555050010","balance":0,"name":"Honorarios 11 % Declarantes","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2555050015","balance":0,"name":"Honorarios 10 % No Declarantes","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2555050017","balance":0,"name":"Honorarios IMAN 19% 96 150 UVT","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2555050018","balance":0,"name":"Honorari IMAN 28% 151 360 UVT","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2555050020","balance":0,"name":"Retención fuente Servicios 1%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2555050030","balance":0,"name":"Ret Fte Serv 4% Declarantes","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2555050035","balance":0,"name":"Ret Fte Serv 6 % No Declarante","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2555050038","balance":0,"name":"Retefuente 3.5% Serv Informati","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2555050040","balance":0,"name":"Refte Ser Hot/Rest No Dec 3,5%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2555050043","balance":0,"name":"RteFte Serv Hoteles rest 3,5%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2555050044","balance":0,"name":"RteFte Arriendo inmuebles 3,5%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2555050050","balance":0,"name":"Ret Fte Arriend Bns Mueb 4%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2555050055","balance":0,"name":"Ret Fte Compras No Decl 3.5%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2555050057","balance":0,"name":"Rete Fte Compras Declaran 2.5%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2555050058","balance":0,"name":"Ret Fte Pagos al Exterior 10%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2555050059","balance":0,"name":"Ret Fte Pagos al Exter 26.4%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2555050060","balance":0,"name":"Ret Fte Pagos al Exterior 33 %","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2555050061","balance":0,"name":"Ret Fte por IVA Pago Ext 100%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2555050064","balance":0,"name":"Ret IVA Reg Simplif 15% (2.4%)","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2555050067","balance":0,"name":"Rte IVA Reg Comun 15% (2.4%)","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2555050085","balance":0,"name":"Autorretención CREE Rend Finan","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2555050092","balance":0,"name":"Rte Fte Comisiones P Jurid 11%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2555050097","balance":0,"name":"Autorretención CREE 0,8%","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"255525","balance":0,"name":"COOPERATIVAS","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"255530","balance":0,"name":"Fondo De Empleados","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2555300005","balance":0,"name":"Fondo de Empleados","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"255535","balance":0,"name":"Aportes Salud","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2555350005","balance":0,"name":"Aportes a EPS","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2555350006","balance":0,"name":"Aportes a EPS Pago","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2555350015","balance":0,"name":"Medicina Prepagada Colsanitas","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2555350016","balance":0,"name":"Medicina Prepagada Compensar","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2555350017","balance":0,"name":"Medicina Prepagada Medisanitas","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2555350018","balance":0,"name":"Medicina prepagada Emermedica","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2555350020","balance":0,"name":"Aportes A R L","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"255540","balance":0,"name":"Aportes Caja Comp.,SENA,ICBF","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2555400005","balance":0,"name":"Aport Caja Comp ICBF SENA","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"255595","balance":0,"name":"Otros","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2555950010","balance":0,"name":"Aportes a Fondo de Pension","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2555950011","balance":0,"name":"Aportes Fondo de Pensión Pago","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2555950015","balance":0,"name":"Aportes a Fdos Pens Volunt","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2555950020","balance":0,"name":"Aportes a Cuentas AFC","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2590","balance":182086.37,"name":"Diversas","chapter":"Pasivo","nivel":4,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"259095","balance":182086.37,"name":"Otras","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2590951001","balance":19.37,"name":"Salarios por Pagar","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2590959501","balance":8765.46,"name":"Otras Cuentas por Pagar","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2590959502","balance":0,"name":"Banco de La Republica","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2590959503","balance":6996.74,"name":"Otras Cuentas por Pagar Extran","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2590959525","balance":0.14,"name":"Reembolsos Caja Menor","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2590959540","balance":0.2,"name":"Descuentos a Empleados","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2590959597","balance":166304.46,"name":"Cuenta por Pagar Puente TransfiYa","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2590959598","balance":0,"name":"Cuenta Bancaria Compensaci PSE","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2590959599","balance":0,"name":"CXP Pte Compensación BanRepubl","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2590959997","balance":0,"name":"Cta Puente Moduloo AP-AR","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2590959999","balance":0,"name":"Cuenta Puente Autorret ACH","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2595","balance":0,"name":"Diversas","chapter":"Pasivo","nivel":4,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"259510","balance":0,"name":"Nomina","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2595100001","balance":0,"name":"Salarios por Pagar","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"259595","balance":0,"name":"Otras","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2595950001","balance":0,"name":"Otras Cuentas por Pagar","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2595950002","balance":0,"name":"Banco de La Republica","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2595950010","balance":0,"name":"Servicios Publicos","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2595950012","balance":0,"name":"Gastos de Viajes","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2595950025","balance":0,"name":"Reembolsos Caja Menor","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2595950030","balance":0,"name":"Servicios en General","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2595950035","balance":0,"name":"Compras","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2595950040","balance":0,"name":"Descuentos a Empleados","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2595950099","balance":0,"name":"CXP Pte Compensación BanRepubl","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2595959998","balance":0,"name":"Cuenta Bancaria Compensaci PSE","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2595959999","balance":0,"name":"Cuenta Puente Autorret ACH","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"27","balance":7867.09,"name":"Otros Pasivos","chapter":"Pasivo","nivel":2,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2710","balance":1878.61,"name":"Obligaciones Laborales Cons","chapter":"Pasivo","nivel":4,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"271005","balance":1878.61,"name":"Cesantías Consolidadas","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2710050001","balance":1878.61,"name":"Ley 50 De 1990 y Normas Poster","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"271010","balance":0,"name":"Intereses Sobre Cesantías","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2710100001","balance":0,"name":"Intereses Sobre Cesantias","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"271015","balance":0,"name":"Vacaciones Consolidadas","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2710150001","balance":0,"name":"Vacaciones Consolidas","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"271095","balance":0,"name":"OTRAS PRESTACIONES SOCIALES","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2715","balance":200.41,"name":"Ingresos Anticipados","chapter":"Pasivo","nivel":4,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"271505","balance":200.41,"name":"Intereses sobre cesantías","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2715051005","balance":200.41,"name":"Intereses Sobre Cesantias","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"271595","balance":0,"name":"Otros","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2715950010","balance":0,"name":"Ingreos Serv PSE- HOS","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2715950015","balance":0,"name":"Ingreso Servicio SWIFT","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2715950016","balance":0,"name":"Ingresos Rec Exportación Swift","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2720","balance":1731.66,"name":"Vacaciones","chapter":"Pasivo","nivel":4,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"272005","balance":1731.66,"name":"Vacaciones","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2720051501","balance":1731.66,"name":"Vacaciones Consolidas","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2725","balance":914.23,"name":"Prima Legal","chapter":"Pasivo","nivel":4,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"272505","balance":914.23,"name":"Prima Legal","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2725052001","balance":914.23,"name":"Prima Legal de Servicios","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2735","balance":3142.18,"name":"Bonificaciones","chapter":"Pasivo","nivel":4,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"273505","balance":3142.18,"name":"Bonificaciones","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2735053007","balance":503.32,"name":"Bonificacion Vacaciones","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2735053508","balance":2638.86,"name":"Paga Variable por Gestion Admi","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2735053509","balance":0,"name":"Provision Seg. social Paga Vbl","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2760","balance":0,"name":"Indemnizaciones Laborales","chapter":"Pasivo","nivel":4,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"276075","balance":0,"name":"Indemnizaciones Laborales","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2760750001","balance":0,"name":"Indemnizaciones","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2795","balance":0,"name":"Otros Beneficios","chapter":"Pasivo","nivel":4,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"279505","balance":0,"name":"Otros Beneficios","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2795050001","balance":0,"name":"Otros Beneficio Bono por retir","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"28","balance":610.55,"name":"Pasivos Estimados Y Provisione","chapter":"Pasivo","nivel":2,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2810","balance":0,"name":"Obligaciones Laborales","chapter":"Pasivo","nivel":4,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"281005","balance":0,"name":"Cesantías","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2810050001","balance":0,"name":"Cesantias","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"281010","balance":0,"name":"Intereses Sobre Cesantías","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2810100001","balance":0,"name":"Intereses Sobre Cesantias","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"281015","balance":0,"name":"Vacaciones","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2810150001","balance":0,"name":"Vacaciones","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"281020","balance":0,"name":"Prima Legal","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2810200001","balance":0,"name":"Prima Legal de Servicios","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"281030","balance":0,"name":"Prima De Vacaciones","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2810300007","balance":0,"name":"Bonificacion Vacaciones","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"281035","balance":0,"name":"Bonificaciones","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2810350008","balance":0,"name":"Paga Variable por Gestion Admi","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2810350009","balance":0,"name":"Provision Seg. social Paga Vbl","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"281040","balance":0,"name":"Obligaciones Legales","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2810400001","balance":0,"name":"Obligaciones Legales","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2815","balance":0,"name":"Impuestos","chapter":"Pasivo","nivel":4,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"281505","balance":0,"name":"Renta Y Complementarios","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2815050001","balance":0,"name":"De Renta y Complementarios","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2815050002","balance":0,"name":"Impto de Renta Cree","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2815050003","balance":0,"name":"Sobretasa Impuesto de CREE","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"281510","balance":0,"name":"Industria Y Comercio","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2815100005","balance":0,"name":"Industria y Comercio","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2823","balance":610.55,"name":"Otras provisiones","chapter":"Pasivo","nivel":4,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"282315","balance":610.55,"name":"Otras provisiones","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2823150001","balance":0,"name":"Honorarios","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2823150003","balance":0,"name":"Servicios","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2823150004","balance":610.55,"name":"Otros","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2823159505","balance":0,"name":"Servicio Telefono Call Center","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2890","balance":0,"name":"Otros Pasivos Estimados","chapter":"Pasivo","nivel":4,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"289015","balance":0,"name":"Otros Pasivos","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2890150001","balance":0,"name":"Honorarios","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2890150003","balance":0,"name":"Servicios","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"289095","balance":0,"name":"Otros","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2890950001","balance":0,"name":"Otros","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2895","balance":0,"name":"Diversos","chapter":"Pasivo","nivel":4,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"289595","balance":0,"name":"Otros","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2895950005","balance":0,"name":"Servicio Telefono Call Center","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"29","balance":0,"name":"Otros Pasivos","chapter":"Pasivo","nivel":2,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2907","balance":0,"name":"Ingresos Anticipados","chapter":"Pasivo","nivel":4,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"290795","balance":0,"name":"Otros","chapter":"Pasivo","nivel":6,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2907959505","balance":0,"name":"Otros","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2907959510","balance":0,"name":"Ingreos Serv PSE- HOS","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2907959511","balance":0,"name":"Impuesto_Diferido_Pasivo","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"2907959520","balance":0,"name":"Ingresos x anticipo SOIDATA","chapter":"Pasivo","nivel":10,"classification":"Capital de trabajo","status":true},{"initial_date":"2024-12-31","account":"3","balance":101877.99,"name":"PATRIMONIO","chapter":"Patrimonio","nivel":1,"classification":"No aplica","status":true},{"initial_date":"2024-12-31","account":"31","balance":6594.81,"name":"Capital Social","chapter":"Patrimonio","nivel":2,"classification":"Aportes de capital social u otros","status":true},{"initial_date":"2024-12-31","account":"3105","balance":6594.81,"name":"Capital Suscrito Y Pagado","chapter":"Patrimonio","nivel":4,"classification":"Aportes de capital social u otros","status":true},{"initial_date":"2024-12-31","account":"310505","balance":6613.22,"name":"Capital Autorizado","chapter":"Patrimonio","nivel":6,"classification":"Aportes de capital social u otros","status":true},{"initial_date":"2024-12-31","account":"3105050005","balance":6613.22,"name":"Capital Autorizado","chapter":"Patrimonio","nivel":10,"classification":"Aportes de capital social u otros","status":true},{"initial_date":"2024-12-31","account":"310510","balance":18.41,"name":"Capital Por Suscribir (-)","chapter":"Patrimonio","nivel":6,"classification":"Aportes de capital social u otros","status":true},{"initial_date":"2024-12-31","account":"3105100005","balance":18.41,"name":"Capital Por Suscribir","chapter":"Patrimonio","nivel":10,"classification":"Aportes de capital social u otros","status":true},{"initial_date":"2024-12-31","account":"32","balance":3413.1,"name":"Reservas","chapter":"Patrimonio","nivel":2,"classification":"Cambios en el patrimonio","status":true},{"initial_date":"2024-12-31","account":"3205","balance":3413.1,"name":"Reserva Legal","chapter":"Patrimonio","nivel":4,"classification":"Cambios en el patrimonio","status":true},{"initial_date":"2024-12-31","account":"320505","balance":3281.52,"name":"Apropiación De Utilidades Liqu","chapter":"Patrimonio","nivel":6,"classification":"Cambios en el patrimonio","status":true},{"initial_date":"2024-12-31","account":"3205050005","balance":2768.98,"name":"Reserva Legal","chapter":"Patrimonio","nivel":10,"classification":"Cambios en el patrimonio","status":true},{"initial_date":"2024-12-31","account":"3205050006","balance":512.53,"name":"Reserva Legal Gravada","chapter":"Patrimonio","nivel":10,"classification":"Cambios en el patrimonio","status":true},{"initial_date":"2024-12-31","account":"320510","balance":131.59,"name":"Prima En Colocación De Accione","chapter":"Patrimonio","nivel":6,"classification":"Cambios en el patrimonio","status":true},{"initial_date":"2024-12-31","account":"3205100005","balance":131.59,"name":"Prima en Colocacion de Accione","chapter":"Patrimonio","nivel":10,"classification":"Cambios en el patrimonio","status":true},{"initial_date":"2024-12-31","account":"3215","balance":0,"name":"Reservas Ocasionales","chapter":"Patrimonio","nivel":4,"classification":"Cambios en el patrimonio","status":true},{"initial_date":"2024-12-31","account":"321595","balance":0,"name":"Otras","chapter":"Patrimonio","nivel":6,"classification":"Cambios en el patrimonio","status":true},{"initial_date":"2024-12-31","account":"3215950010","balance":0,"name":"Para Futuras Inversiones","chapter":"Patrimonio","nivel":10,"classification":"Cambios en el patrimonio","status":true},{"initial_date":"2024-12-31","account":"34","balance":0,"name":"Superávit o Déficit","chapter":"Patrimonio","nivel":2,"classification":"Cambios en el patrimonio","status":true},{"initial_date":"2024-12-31","account":"3415","balance":0,"name":"Valorizaciones","chapter":"Patrimonio","nivel":4,"classification":"Cambios en el patrimonio","status":true},{"initial_date":"2024-12-31","account":"341510","balance":0,"name":"Propiedades Y Equipo","chapter":"Patrimonio","nivel":6,"classification":"Cambios en el patrimonio","status":true},{"initial_date":"2024-12-31","account":"3415100005","balance":0,"name":"Propiedad Planta y Equipo","chapter":"Patrimonio","nivel":10,"classification":"Cambios en el patrimonio","status":true},{"initial_date":"2024-12-31","account":"3417","balance":0,"name":"Revalorización Del Patrimonio","chapter":"Patrimonio","nivel":4,"classification":"Cambios en el patrimonio","status":true},{"initial_date":"2024-12-31","account":"341710","balance":0,"name":"Ajustes Al Patrimonio","chapter":"Patrimonio","nivel":6,"classification":"Cambios en el patrimonio","status":true},{"initial_date":"2024-12-31","account":"3417100005","balance":0,"name":"De Capital Social","chapter":"Patrimonio","nivel":10,"classification":"Cambios en el patrimonio","status":true},{"initial_date":"2024-12-31","account":"3417100015","balance":0,"name":"De Reservas","chapter":"Patrimonio","nivel":10,"classification":"Cambios en el patrimonio","status":true},{"initial_date":"2024-12-31","account":"3417100020","balance":0,"name":"De Resultados de Ejercicios An","chapter":"Patrimonio","nivel":10,"classification":"Cambios en el patrimonio","status":true},{"initial_date":"2024-12-31","account":"3417100035","balance":0,"name":"De Ajutes","chapter":"Patrimonio","nivel":10,"classification":"Cambios en el patrimonio","status":true},{"initial_date":"2024-12-31","account":"35","balance":0,"name":"RESULTADOS DE EJERCICIOS AN","chapter":"Patrimonio","nivel":2,"classification":"Cambios en el patrimonio","status":true},{"initial_date":"2024-12-31","account":"3505","balance":0,"name":"UTILIDADES O EXCEDENTES ACU","chapter":"Patrimonio","nivel":4,"classification":"Cambios en el patrimonio","status":true},{"initial_date":"2024-12-31","account":"350501","balance":0,"name":"UTILIDADES O EXCEDENTES ACU","chapter":"Patrimonio","nivel":6,"classification":"Cambios en el patrimonio","status":true},{"initial_date":"2024-12-31","account":"36","balance":0,"name":"Resultados Del Ejercicio","chapter":"Patrimonio","nivel":2,"classification":"Cambios en el patrimonio","status":true},{"initial_date":"2024-12-31","account":"3605","balance":0,"name":"Resultados Del Ejercicio","chapter":"Patrimonio","nivel":4,"classification":"Cambios en el patrimonio","status":true},{"initial_date":"2024-12-31","account":"360501","balance":0,"name":"Resultados Del Ejercicio","chapter":"Patrimonio","nivel":6,"classification":"Cambios en el patrimonio","status":true},{"initial_date":"2024-12-31","account":"3605010001","balance":0,"name":"Utilidad del Ejercicio","chapter":"Patrimonio","nivel":10,"classification":"Cambios en el patrimonio","status":true},{"initial_date":"2024-12-31","account":"39","balance":99816.91,"name":"[MODIFICADO POR ECUACION FINANCIERA] Ganancias o Pérdidas","chapter":"Patrimonio","nivel":2,"classification":"Utilidad del ejercicio periodo","status":true},{"initial_date":"2024-12-31","account":"3905","balance":0,"name":"Ganancias Acumuladas Ejercicio","chapter":"Patrimonio","nivel":4,"classification":"Utilidad del ejercicio periodo","status":true},{"initial_date":"2024-12-31","account":"390501","balance":0,"name":"Ganancias Acumuladas Ejercicio","chapter":"Patrimonio","nivel":6,"classification":"Utilidad del ejercicio periodo","status":true},{"initial_date":"2024-12-31","account":"3905010005","balance":0,"name":"Utilidades de Ejercicios Anter","chapter":"Patrimonio","nivel":10,"classification":"Utilidad del ejercicio periodo","status":true},{"initial_date":"2024-12-31","account":"3905010010","balance":0,"name":"Utilidades No Gravadas","chapter":"Patrimonio","nivel":10,"classification":"Utilidad del ejercicio periodo","status":true},{"initial_date":"2024-12-31","account":"3915","balance":91870.08,"name":"Ganancia del Ejercicio","chapter":"Patrimonio","nivel":4,"classification":"Utilidad del ejercicio periodo","status":true},{"initial_date":"2024-12-31","account":"391501","balance":91870.08,"name":"Ganancia del Ejercicio","chapter":"Patrimonio","nivel":6,"classification":"Utilidad del ejercicio periodo","status":true},{"initial_date":"2024-12-31","account":"3915010001","balance":91870.08,"name":"Utilidad del ejercicio","chapter":"Patrimonio","nivel":10,"classification":"Utilidad del ejercicio periodo","status":true},{"initial_date":"2024-12-31","account":"3930","balance":0,"name":"Resultados Acumulados Proceso","chapter":"Patrimonio","nivel":4,"classification":"Utilidad del ejercicio periodo","status":true},{"initial_date":"2024-12-31","account":"393010","balance":0,"name":"Pérdida","chapter":"Patrimonio","nivel":6,"classification":"Utilidad del ejercicio periodo","status":true},{"initial_date":"2024-12-31","account":"3930100001","balance":0,"name":"RESULTADOS ACUMULADOS PROCESO","chapter":"Patrimonio","nivel":10,"classification":"Utilidad del ejercicio periodo","status":true},{"initial_date":"2024-12-31","account":"4","balance":292592.28,"name":"INGRESOS","chapter":"Ingresos","nivel":1,"classification":"No aplica","status":true},{"initial_date":"2024-12-31","account":"41","balance":292592.28,"name":"Operacionales","chapter":"Ingresos","nivel":2,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"4103","balance":3000.33,"name":"Ingresos Financieros Operacion","chapter":"Ingresos","nivel":4,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"410305","balance":3000.33,"name":"Depósitos a la Vista","chapter":"Ingresos","nivel":6,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"4103052010","balance":3000.33,"name":"Rendimientos Ctas Ahorro","chapter":"Ingresos","nivel":10,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"4104","balance":0,"name":"Otros Intereses","chapter":"Ingresos","nivel":4,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"410402","balance":0,"name":"Depósitos a la Vista","chapter":"Ingresos","nivel":6,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"4104020010","balance":0,"name":"Rendimientos Ctas Ahorro","chapter":"Ingresos","nivel":10,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"410430","balance":0,"name":"Rendimientos Otras Especies","chapter":"Ingresos","nivel":6,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"4104300005","balance":0,"name":"CDT En Pesos","chapter":"Ingresos","nivel":10,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"4106","balance":7412.5,"name":"Valoración por Transferencia t","chapter":"Ingresos","nivel":4,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"410610","balance":7412.5,"name":"En títulos Participativos","chapter":"Ingresos","nivel":6,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"4106106005","balance":7412.5,"name":"Rendimientos Fiduciarias","chapter":"Ingresos","nivel":10,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"4108","balance":0,"name":"Utilidad en Valoración de Inve","chapter":"Ingresos","nivel":4,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"410806","balance":0,"name":"Por Incremento En El Valor","chapter":"Ingresos","nivel":6,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"4108060005","balance":0,"name":"Rendimientos Fiduciarias","chapter":"Ingresos","nivel":10,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"4111","balance":0,"name":"Utilidad En Valoración Inversi","chapter":"Ingresos","nivel":4,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"411106","balance":0,"name":"Por Incremento En El Valor Pre","chapter":"Ingresos","nivel":6,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"4111060005","balance":0,"name":"CDT En Pesos","chapter":"Ingresos","nivel":10,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"4115","balance":281264.14,"name":"Comisiones Y/o Honorarios","chapter":"Ingresos","nivel":4,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"411516","balance":281264.14,"name":"Uso Medios de Pago Diferentes","chapter":"Ingresos","nivel":6,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"4115164010","balance":62463.84,"name":"Servicio Soporte Sitio Central","chapter":"Ingresos","nivel":10,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"4115164020","balance":183214.29,"name":"Pagos Seguros en Linea PSE","chapter":"Ingresos","nivel":10,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"4115164025","balance":0,"name":"Seg. programa prevenc Fraude","chapter":"Ingresos","nivel":10,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"4115164035","balance":261.5,"name":"Acceso a la Red","chapter":"Ingresos","nivel":10,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"4115164045","balance":0,"name":"AMPLIACION DE SERVICIOS","chapter":"Ingresos","nivel":10,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"4115164050","balance":31170.35,"name":"Servicio Oper. de Información","chapter":"Ingresos","nivel":10,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"4115164055","balance":0,"name":"Soluciones SWIFT Colombia","chapter":"Ingresos","nivel":10,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"4115164060","balance":0,"name":"SOI DATA","chapter":"Ingresos","nivel":10,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"4115164065","balance":4154.17,"name":"Transferencia ACH YA","chapter":"Ingresos","nivel":10,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"411540","balance":0,"name":"Uso Medios De Pago Diferent","chapter":"Ingresos","nivel":6,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"4115400005","balance":0,"name":"Red de Valor Agregado","chapter":"Ingresos","nivel":10,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"4115400010","balance":0,"name":"Servicio Soporte Sitio Central","chapter":"Ingresos","nivel":10,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"4115400020","balance":0,"name":"Pagos Seguros en Linea PSE","chapter":"Ingresos","nivel":10,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"4115400025","balance":0,"name":"Seg. programa prevenc Fraude","chapter":"Ingresos","nivel":10,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"4115400035","balance":0,"name":"Acceso a la Red","chapter":"Ingresos","nivel":10,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"4115400040","balance":0,"name":"Exportación de Servicios_SWIFT","chapter":"Ingresos","nivel":10,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"4115400045","balance":0,"name":"AMPLIACION DE SERVICIOS","chapter":"Ingresos","nivel":10,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"4115400050","balance":0,"name":"Servicio Oper. de Información","chapter":"Ingresos","nivel":10,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"4115400055","balance":0,"name":"Soluciones SWIFT Colombia","chapter":"Ingresos","nivel":10,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"4131","balance":5.4,"name":"Por Venta de Propiedades y Equ","chapter":"Ingresos","nivel":4,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"413110","balance":0,"name":"Edificios","chapter":"Ingresos","nivel":6,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"4131100005","balance":0,"name":"Venta Equipo de Computacion","chapter":"Ingresos","nivel":10,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"413115","balance":5.4,"name":"Equipo,Muebles y Enseres de Of","chapter":"Ingresos","nivel":6,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"4131150005","balance":5.4,"name":"Venta Muebles y Enseres","chapter":"Ingresos","nivel":10,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"4190","balance":0,"name":"Recuperaciones Riesgo Operativ","chapter":"Ingresos","nivel":4,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"419010","balance":0,"name":"Recuperaciones Diferen a Segur","chapter":"Ingresos","nivel":6,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"4190100005","balance":0,"name":"Recuperaciones Riesgo Operativ","chapter":"Ingresos","nivel":10,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"4191","balance":3.56,"name":"Recuperaciones Riesgo Operativ","chapter":"Ingresos","nivel":4,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"419110","balance":3.56,"name":"Recuperaciones Diferentes a Se","chapter":"Ingresos","nivel":6,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"4191100005","balance":3.56,"name":"RECUPERACION RIESGO OPERATIVO","chapter":"Ingresos","nivel":10,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"4193","balance":0,"name":"subvenciones del gobierno","chapter":"Ingresos","nivel":4,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"419305","balance":0,"name":"subvenciones del gobierno","chapter":"Ingresos","nivel":6,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"4193050005","balance":0,"name":"INGRESOS SUBVENCIONES G","chapter":"Ingresos","nivel":10,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"4195","balance":902.58,"name":"Diversos","chapter":"Ingresos","nivel":4,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"419595","balance":902.58,"name":"Otros","chapter":"Ingresos","nivel":6,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"4195950005","balance":27.11,"name":"Otros Ingresos","chapter":"Ingresos","nivel":10,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"4195950031","balance":308.73,"name":"Diferencia de Cambio Realizada","chapter":"Ingresos","nivel":10,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"4195950035","balance":42.73,"name":"Diferencia en Cambio No Realiz","chapter":"Ingresos","nivel":10,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"4195950050","balance":0,"name":"Por Incapacidades","chapter":"Ingresos","nivel":10,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"4195950055","balance":0.32,"name":"Aprovechamientos","chapter":"Ingresos","nivel":10,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"4195950060","balance":523.67,"name":"Sancion Interinstitucional","chapter":"Ingresos","nivel":10,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"4195950065","balance":0.01,"name":"Ajuste al Peso","chapter":"Ingresos","nivel":10,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"4195950070","balance":0,"name":"Tokens","chapter":"Ingresos","nivel":10,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"4195950085","balance":0,"name":"Descuentos condicionados","chapter":"Ingresos","nivel":10,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"4198","balance":3.77,"name":"Recuperaciones Deterioro (Prov","chapter":"Ingresos","nivel":4,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"419805","balance":3.77,"name":"Reintegro Provisiones Cuentas","chapter":"Ingresos","nivel":6,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"4198053010","balance":0,"name":"Reintegro de Otras Provisiones","chapter":"Ingresos","nivel":10,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"4198055010","balance":3.77,"name":"Recuperacion anos anteriores","chapter":"Ingresos","nivel":10,"classification":"Ingresos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5","balance":284645.44,"name":"GASTOS Y COSTOS","chapter":"Gastos","nivel":1,"classification":"No aplica","status":true},{"initial_date":"2024-12-31","account":"51","balance":193113.14,"name":"Operacionales","chapter":"Gastos","nivel":2,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5104","balance":151.32,"name":"Otros Intereses, Prima Amor","chapter":"Gastos","nivel":4,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"510495","balance":151.32,"name":"Otros Intereses","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5104950010","balance":0,"name":"Intereses Corrientes","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5104950015","balance":0,"name":"Intereses Corrientes Leasing","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5104950016","balance":57.52,"name":"Intereses Corrientes Leasing","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5104950017","balance":0,"name":"Intereses Corrientes Leasing","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5104950019","balance":13.45,"name":"Intereses Corrientes Leasing","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5104950021","balance":0,"name":"Intereses Corrientes Leasing","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5104950022","balance":93.79,"name":"Intereses Corrientes Leasing","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5104950023","balance":0,"name":"Intereses leasing 180-119248","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"510497","balance":0.17,"name":"Riesgo Operativo","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5104970001","balance":0.17,"name":"RIESGO FINANCIERO POR OPERACIO","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5108","balance":0,"name":"PERDIDA EN VALORACION DE IN","chapter":"Gastos","nivel":4,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"510805","balance":0,"name":"PERDIDA EN VALORACION DE IN","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5115","balance":408.51,"name":"Comisiones","chapter":"Gastos","nivel":4,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"511512","balance":408.51,"name":"Servicios Bancarios","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5115122015","balance":408.51,"name":"Gastos Bancarios","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"511520","balance":0,"name":"Servicios Bancarios","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5115200015","balance":0,"name":"Gastos Bancarios","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"511595","balance":0,"name":"Otros Servicios","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5115950005","balance":0,"name":"Otros Servicios","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"511597","balance":0,"name":"Riesgo Operativo","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5115970001","balance":0,"name":"Riesgo Comisiones","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120","balance":60910.54,"name":"Gastos De Personal","chapter":"Gastos","nivel":4,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"512001","balance":5491.36,"name":"Salario Integral","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120010503","balance":5491.36,"name":"Salario Integral","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"512002","balance":21308.48,"name":"Sueldos","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120020505","balance":21308.48,"name":"Sueldos","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"512003","balance":676.77,"name":"Horas Extras","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120031005","balance":676.77,"name":"Horas Extras","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"512004","balance":0.8,"name":"Auxilio de Transporte","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120041505","balance":0.8,"name":"Auxilio de Transporte","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"512005","balance":0,"name":"Salarios","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120050003","balance":0,"name":"Salario Integral","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120050005","balance":0,"name":"Sueldos","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"512006","balance":1961.45,"name":"Cesantias","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120062505","balance":1961.45,"name":"Cesantias","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"512007","balance":206.48,"name":"Intereses Sobre Cesantias","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120073005","balance":206.48,"name":"Intereses Sobre Cesantias","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"512008","balance":1949.84,"name":"Prima Legal","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120083505","balance":1949.84,"name":"Prima Legal","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"512010","balance":1668.52,"name":"Horas Extras","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120100005","balance":0,"name":"Horas Extras","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120104505","balance":1668.52,"name":"Vacaciones","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"512011","balance":472.43,"name":"Prima de Vacaciones","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120115005","balance":472.43,"name":"Prima de Vacaciones","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"512013","balance":3226.56,"name":"Pensiones de Jubilacion","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120136005","balance":3226.56,"name":"Pensiones de Jubilacion","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"512015","balance":2703.08,"name":"Auxilio De Transporte","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120150005","balance":0,"name":"Auxilio de Transporte","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120156505","balance":2361.1,"name":"Paga Variab por Gest Administr","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120157005","balance":69.63,"name":"Bonificaciones","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120157006","balance":0,"name":"Bonificaciones Mera Liberalida","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120157007","balance":272.35,"name":"Bonificacion por Encargatura","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"512016","balance":64.79,"name":"Indemnizaciones","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120167505","balance":64.79,"name":"Indemnizaciones Terminacion Co","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"512019","balance":1697.36,"name":"Aportes Caja Compensacion Fami","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120199005","balance":1560.91,"name":"Aportes Caja Compensacion Fami","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120199205","balance":136.45,"name":"Aportes ARL","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"512025","balance":0,"name":"Cesantías","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120250005","balance":0,"name":"Cesantias","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"512030","balance":899.53,"name":"Intereses Sobre Cesantías","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120300005","balance":0,"name":"Intereses Sobre Cesantias","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120308505","balance":899.53,"name":"Aportes EPS","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"512035","balance":0,"name":"Prima Legal","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120350005","balance":0,"name":"Prima Legal","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"512040","balance":0,"name":"PRIMA EXTRALEGAL","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"512043","balance":60910.54,"name":"Otros Beneficios a Empleados","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120430001","balance":0,"name":"Otros Beneficios a Empleados","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120430010","balance":0,"name":"De Personal Teletrabajo","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120439501","balance":0,"name":"Capacitacion Direccion Segurid","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120439505","balance":492.04,"name":"Capacitacion/Transversal","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120439513","balance":0,"name":"Salud ocupaci/ Element protecc","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120439515","balance":82.93,"name":"Salud Ocupacional","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120439516","balance":0,"name":"Salud ocupaci/ semana de salud","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120439517","balance":0,"name":"Salud ocupaci/ recar extintor","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120439518","balance":0,"name":"Salud ocupaci/ Area Protegida","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120439519","balance":0,"name":"Salud ocupaci/ Fumigación","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120439520","balance":1037.96,"name":"Recreacion","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120439521","balance":0,"name":"Recreac/Nacimiento bebes","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120439523","balance":0,"name":"Recreac/ Reconocimientos","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120439524","balance":0,"name":"Recreac/ Tortas cumpleaños","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120439526","balance":0,"name":"Recreac/ Celebrac Aniversarios","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120439528","balance":0,"name":"Recreac/ Patrocinio deportes","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120439530","balance":0,"name":"Refrigerios","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120439531","balance":0,"name":"Recreac/ Desayuno Bienvenida","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120439534","balance":0,"name":"Recreac/ Patrocinio Fondo","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120439536","balance":0,"name":"Recreac/ Olimpiadas","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120439537","balance":0,"name":"Recreac/ Día Mujer","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120439538","balance":0,"name":"Recreac/ Día Padre y Madre","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120439539","balance":0,"name":"Recreac/ Día Vendedor","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120439540","balance":0,"name":"Recreac/ Novena funcionarios","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120439541","balance":0,"name":"Recreac/ Fiesta Fin de año","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120439542","balance":0,"name":"Recreac/ Día del soltero","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120439543","balance":0,"name":"Recreac/ Día de la Familia","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120439544","balance":0,"name":"Recreac/ Vacaciones Recreativa","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120439546","balance":0,"name":"Recreac/ Regalos Navidad Niños","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120439547","balance":0,"name":"Recreac/ Novena Familia","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120439548","balance":0,"name":"Recreac/ Papeleria Apoyo","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120439549","balance":0,"name":"Recreac/ Aniversario SOI","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120439550","balance":0,"name":"Recreacion/Quinquenios","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120439554","balance":63.24,"name":"Bienestar_Compañía","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120439555","balance":0,"name":"Beneficios funcionarios ACH","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120439605","balance":59234.37,"name":"Auxilios al Personal","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120439606","balance":0,"name":"DOTACIONES AL PERSONAL","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"512045","balance":0,"name":"Vacaciones","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120450005","balance":0,"name":"Vacaciones","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"512050","balance":0,"name":"Prima De Vacaciones","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120500005","balance":0,"name":"Prima de Vacaciones","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"512060","balance":0,"name":"Pensiones De Jubilación","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120600005","balance":0,"name":"Pensiones de Jubilacion","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"512065","balance":0,"name":"Otras Prestaciones Sociales","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120650005","balance":0,"name":"Paga Variab por Gest Administr","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"512070","balance":0,"name":"Bonificaciones","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120700005","balance":0,"name":"Bonificaciones","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120700006","balance":0,"name":"Bonificación por Retiro Defini","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120700007","balance":0,"name":"Bonificacion por Encargatura","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"512075","balance":0,"name":"Indemnizaciones","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120750005","balance":0,"name":"Indemnizaciones Terminacion Co","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"512085","balance":0,"name":"Aportes Eps","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120850005","balance":0,"name":"Aportes EPS","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"512090","balance":0,"name":"Aportes Caja de Compensación","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120900005","balance":0,"name":"Aportes Caja Compensacion Fami","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"512092","balance":0,"name":"Aportes Cajas Compen Sala I","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120920005","balance":0,"name":"Aportes ARL","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"512095","balance":0,"name":"Otros","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120950000","balance":0,"name":"Capacitación Auditoria Interna","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120950001","balance":0,"name":"Capacitacion Direccion Segurid","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120950002","balance":0,"name":"Capacitacion Direccion Tecnolo","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120950003","balance":0,"name":"Capacitacion Direccion Planeac","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120950004","balance":0,"name":"Capacitacion Direccion Product","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120950005","balance":0,"name":"Capacitacion/Transversal","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120950006","balance":0,"name":"Capacitacion /Equipo Directivo","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120950007","balance":0,"name":"Capacitacion /Equipo Tactico","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120950008","balance":0,"name":"Capacitacion /Dir TH y Admon","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120950009","balance":0,"name":"Capacitacion /Presidencia","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120950010","balance":0,"name":"Capacitación/Dir Comercial","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120950011","balance":0,"name":"Capacitacion /Subdi Serv Clien","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120950013","balance":0,"name":"Salud ocupaci/ Element protecc","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120950016","balance":0,"name":"Salud ocupaci/ semana de salud","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120950017","balance":0,"name":"Salud ocupaci/ recar extintor","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120950018","balance":0,"name":"Salud ocupaci/ Area Protegida","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120950019","balance":0,"name":"Salud ocupaci/ Fumigación","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120950020","balance":0,"name":"Recreacion","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120950021","balance":0,"name":"Recreac/Nacimiento bebes","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120950022","balance":0,"name":"Recreac/Incentiv Comerciales","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120950023","balance":0,"name":"Recreac/ Reconocimientos","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120950024","balance":0,"name":"Recreac/ Tortas cumpleaños","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120950025","balance":0,"name":"Recreac/ Galleta Aniversarios","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120950026","balance":0,"name":"Recreac/ Celebrac Aniversarios","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120950027","balance":0,"name":"Recreac/ Celebrac Cumpleaños","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120950028","balance":0,"name":"Recreac/ Patrocinio deportes","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120950029","balance":0,"name":"Recreac/ Kit Bienvenida","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120950030","balance":0,"name":"Refrigerios","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120950031","balance":0,"name":"Recreac/ Desayuno Bienvenida","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120950032","balance":0,"name":"Recreac/ Charlas Familia","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120950033","balance":0,"name":"Recreac/ Fotografias familia","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120950034","balance":0,"name":"Recreac/ Patrocinio Fondo","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120950036","balance":0,"name":"Recreac/ Olimpiadas","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120950037","balance":0,"name":"Recreac/ Día Mujer","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120950038","balance":0,"name":"Recreac/ Día Padre y Madre","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120950039","balance":0,"name":"Recreac/ Día Vendedor","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120950040","balance":0,"name":"Recreac/ Novena funcionarios","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120950041","balance":0,"name":"Recreac/ Fiesta Fin de año","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120950042","balance":0,"name":"Recreac/ Día del soltero","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120950043","balance":0,"name":"Recreac/ Día de la Familia","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120950044","balance":0,"name":"Recreac/ Vacaciones Recreativa","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120950046","balance":0,"name":"Recreac/ Regalos Navidad Niños","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120950047","balance":0,"name":"Recreac/ Novena Familia","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120950048","balance":0,"name":"Recreac/ Papeleria Apoyo","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120950049","balance":0,"name":"Recreac/ Aniversario SOI","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120950050","balance":0,"name":"Recreacion/Quinquenios","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120950051","balance":0,"name":"Capacitación/ Dirección Jurídi","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"512096","balance":0,"name":"Auxilios Al Personal","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120960005","balance":0,"name":"Auxilios al Personal","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120960006","balance":0,"name":"DOTACIONES AL PERSONAL","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"512097","balance":1.33,"name":"Riesgo Operativo","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5120970005","balance":1.33,"name":"Riesgo Operativo Personal","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5130","balance":22063.09,"name":"Honorarios","chapter":"Gastos","nivel":4,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"513005","balance":0,"name":"Junta Directiva","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5130050005","balance":0,"name":"Junta Directiva","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"513010","balance":429.09,"name":"Revisoría Fiscal y Auditoria","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5130100010","balance":0,"name":"Revisoria Fiscal","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5130100505","balance":429.09,"name":"Junta Directiva","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"513015","balance":123.04,"name":"Revisoria Fiscal y Auditoria E","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5130151010","balance":123.04,"name":"Revisoria Fiscal","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"513020","balance":0,"name":"ASESORIAS JURIDICAS","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"513025","balance":23.55,"name":"Asesorías Juridicas","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5130259511","balance":23.55,"name":"Otros Honor/ Asesoría Laboral","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5130259517","balance":0,"name":"Otros Honor/ Honorarios Legale","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"513030","balance":530.22,"name":"Asesorias Financieras","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5130309505","balance":457.4,"name":"Servicio Contable","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5130309506","balance":72.83,"name":"Tributarios","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"513095","balance":20957.18,"name":"Otros","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5130950005","balance":0,"name":"Servicio Contable","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5130950006","balance":0,"name":"Tributarios","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5130950010","balance":2403.77,"name":"Otros Honorarios","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5130950011","balance":0,"name":"Otros Honor/ Asesoría Laboral","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5130950012","balance":178.09,"name":"Otros Honor/ Proceso selección","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5130950013","balance":0,"name":"Otros Honor/ E-Learning","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5130950015","balance":1751.46,"name":"Consultorias","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5130950016","balance":0,"name":"Otros Honor/ Formu Mantenimien","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5130950017","balance":0,"name":"Otros Honor/ Honorarios Legale","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5130950018","balance":0,"name":"Otros Honor/ Planeaci Estrateg","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5130950020","balance":43.92,"name":"Otros Honor/ Encuestas","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5130950021","balance":0,"name":"Otros Honor/ Otros","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5130950022","balance":0,"name":"Consultoria/Soport Projec Serv","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5130950023","balance":29.51,"name":"Consultoria/Endeuda funcionari","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5130950024","balance":0,"name":"Consultoria/ GPTW","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5130950025","balance":326.74,"name":"Consultoria/Temas Legales","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5130950026","balance":2011.71,"name":"Consultoria/ Implementación","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5130950027","balance":30.1,"name":"Consultoria/Certificac Calidad","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5130950028","balance":0.8,"name":"Consultoria/sensibiliz Interna","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5130950029","balance":3492.93,"name":"Otros Honorarios/ Venta SOI","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5130950030","balance":0,"name":"Otros Honorarios/ Investig de","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5130950035","balance":1191.3,"name":"Asesoria Tecnica","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5130950036","balance":0,"name":"Ases Técn/ Recurs Pruebas","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5130950037","balance":0,"name":"Ases Técn/ Mesa de Servicio","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5130950038","balance":0,"name":"Ases Técn/ Recurso ITSTK","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5130950039","balance":0,"name":"Ases Técn/ Sop eq comp y comun","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5130950040","balance":278,"name":"Ases Técn/ Soporte Premier","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5130950041","balance":0,"name":"Ases Técn/ Prbas Ethical Hacki","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5130950042","balance":9119.64,"name":"Ases Técn/ AT+ horas desarroll","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5130950043","balance":0,"name":"Ases Técn/ Desarrollo PSE","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5130950045","balance":100,"name":"Ases Técn/ Desarrollo Portales","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5130950046","balance":0,"name":"Ases Técn/ Licenciamiento","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5130950047","balance":0,"name":"Ases Técn/ Vinculación Certifi","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"513097","balance":0,"name":"Riesgo Operativo","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5130970001","balance":0,"name":"Riesgo Honorarios","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5130970005","balance":0,"name":"Riesgo Honorarios","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5140","balance":5064.53,"name":"Impuestos","chapter":"Gastos","nivel":4,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"514005","balance":5064.53,"name":"Registro Y Anotación","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5140051005","balance":4127.63,"name":"Industria y Comercio","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5140053505","balance":927.5,"name":"Gravamen a los Movim Financie","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5140053510","balance":0,"name":"Sobretasa de Renta","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5140059540","balance":1.55,"name":"Impto Nacional al Consumo","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5140059545","balance":9.4,"name":"Tasa Aeroportuaria","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5140059546","balance":0,"name":"Impuesto a la Riqueza","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"514010","balance":0,"name":"Industria Y Comercio","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5140100005","balance":0,"name":"Industria y Comercio","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"514035","balance":0,"name":"GMF","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5140350005","balance":0,"name":"Gravamen a los Movim Financie","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"514095","balance":0,"name":"Sobretasas Y Otros","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5140950020","balance":0,"name":"Derechos Sobre Instrumentos Pu","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5140950035","balance":0,"name":"Contribución CRC","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5140950040","balance":0,"name":"Impto Nacional al Consumo","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5140950045","balance":0,"name":"Tasa Aeroportuaria","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5140950046","balance":0,"name":"Impuesto a la Riqueza","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"514097","balance":0,"name":"Riesgo Operativo","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5140970001","balance":0,"name":"Contribución CRC. rubro defini","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5140970005","balance":0,"name":"Riesgo Impuestos","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5145","balance":4079.45,"name":"Arrendamientos","chapter":"Gastos","nivel":4,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"514505","balance":1667.13,"name":"Equipo De Computación","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5145050001","balance":0,"name":"Leasing vehiculo / VOT","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5145050002","balance":0,"name":"Leasing vehículo / VMP","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5145050003","balance":0,"name":"Leasing vehículo / Presidencia","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5145050021","balance":0,"name":"Leasing Equipos de Computo","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5145050023","balance":0,"name":"Leasing Storage","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5145050024","balance":0,"name":"Leasing servidores","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5145050025","balance":671.13,"name":"Equipo de Computacion y Comuni","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5145050026","balance":996.01,"name":"Arrendamiento Datacenter","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5145050027","balance":0,"name":"Arrendamiento Kioskos","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"514510","balance":1930.94,"name":"Locales Y Oficinas","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5145100006","balance":0,"name":"Arrendam sede / Sitio Alterno","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5145100007","balance":1930.94,"name":"Arrendam sede/ Sede Principal","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5145100008","balance":0,"name":"Arrendam sede/ Otras Sedes","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"514515","balance":0,"name":"PARQUEADEROS","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"514535","balance":0,"name":"MAQUINARIA Y EQUIPO","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"514595","balance":481.38,"name":"Otros","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5145950005","balance":0,"name":"Arrendamiento Muebles","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5145950015","balance":70.17,"name":"Salon de Eventos con Equipos","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5145950016","balance":411.21,"name":"Arrend. Infraest en la nube","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"514597","balance":2.09,"name":"Riesgo Operativo","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5145970001","balance":2.09,"name":"Riesgo Arrendamientos","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5150","balance":0,"name":"Contribuciones Y Afiliaciones","chapter":"Gastos","nivel":4,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"515095","balance":0,"name":"Otras","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5150950005","balance":0,"name":"Otras Contrib y Afiliaciones","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"515097","balance":0,"name":"Riesgo Operativo","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5150970005","balance":0,"name":"Riesgo Contribuciones y Afilia","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5155","balance":3398.91,"name":"Seguros","chapter":"Gastos","nivel":4,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"515510","balance":3398.91,"name":"Cumplimiento","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5155100005","balance":5,"name":"Cumplimiento","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5155100006","balance":59.85,"name":"Seguros/ Todo Riesgo","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5155100007","balance":219.96,"name":"Seguros/ Direct y Administrado","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5155100008","balance":2209.95,"name":"Seguros/ Infidelidad y riesgos","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5155100009","balance":46.18,"name":"Seguros/ Arrendamiento","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5155100010","balance":846.86,"name":"Seguros/ Riesgos Cibernéticos","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5155100016","balance":0,"name":"Seguros/ Riesgos Cibernéticos","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5155100019","balance":11.1,"name":"Seguros/Arrendamientos Leasing","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5155100021","balance":0,"name":"Seguros/Arrendamientos Leasing","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5155100022","balance":0,"name":"Seguros/Arrendamientos Leasing","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5160","balance":13526.17,"name":"Mantenimiento Y Reparaciónes","chapter":"Gastos","nivel":4,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"516005","balance":2813.53,"name":"Equipo De Computación","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5160050005","balance":342.37,"name":"Mantenimiento Hardware","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5160050010","balance":2471.17,"name":"Mantenimiento Software","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5160050012","balance":0,"name":"Mto Software/Sopor y Mto SWIFT","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5160050015","balance":0,"name":"Mto Software/Sop y Mto Z Virtu","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5160050016","balance":0,"name":"Mto Software/Certifi Digitales","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5160050017","balance":0,"name":"Mto Software/ Mantenimient HCM","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5160050018","balance":0,"name":"Mto Software/ Mantenimient ERP","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5160050019","balance":0,"name":"Mto Software/ Mto Balanc-enrut","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5160050020","balance":0,"name":"Mto Software/ Telefonía IP","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5160050021","balance":0,"name":"Mto Software/ Aranda","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5160050022","balance":0,"name":"Mto Software/ Liferay","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5160050023","balance":0,"name":"Mto Software/ Antivirus","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5160050024","balance":0,"name":"Mto Software/ VMWare","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5160050025","balance":0,"name":"Mto Software/ Entrust","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5160050026","balance":0,"name":"Mto Software/ Whatsup","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5160050027","balance":0,"name":"Mto Software/ Manager y BAC","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5160050028","balance":0,"name":"Mto Software/ Licencias Oracle","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5160050029","balance":0,"name":"Mto Software/ Red Hat","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5160050030","balance":0,"name":"Mto Software/Licencias Microso","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5160050031","balance":0,"name":"Mto Software/Licencias Symante","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5160050032","balance":0,"name":"Mto Software/ Isolucion","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5160050033","balance":0,"name":"Mto Software/ SPA","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5160050036","balance":0,"name":"Mto Software/Mto VIGIA","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5160050038","balance":0,"name":"Mto Software/Mto Portales","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5160050039","balance":0,"name":"Mto Software/ACHNNET, ACH SSS","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5160050040","balance":0,"name":"Mto Software/ PSE, TEL","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5160050041","balance":0,"name":"Mto Software/ Nuevo SOI","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5160050042","balance":0,"name":"Mto Software/ otros","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5160050043","balance":0,"name":"Mto Software/ Pantalla y comun","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"516010","balance":171.55,"name":"Equipo De Oficina","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5160100005","balance":28.07,"name":"Mantenimien Equipos de Oficina","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5160100006","balance":0,"name":"Mantenimien Equipo de Computo","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5160100007","balance":38.96,"name":"Mto eq ofic/ Mto equ seguridad","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5160100008","balance":2.85,"name":"Mto eq ofic/ Periféricos","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5160100009","balance":0,"name":"Equipos de Oficina de Administ","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5160100010","balance":27.95,"name":"Mto eq ofic/ UPS","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5160100011","balance":0,"name":"Mto eq ofic/ balanc-enrutadore","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5160100012","balance":0,"name":"Mto eq ofic/ Hardware","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5160100013","balance":53.35,"name":"Mto eq ofic/ Recableado","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5160100014","balance":13.11,"name":"Mto eq ofic/ Soporte Mto SWIFT","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5160100015","balance":1.77,"name":"Mto eq ofic/ Sistema deteccion","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5160100016","balance":0,"name":"Mto eq ofic/ equipo cafeteria","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5160100017","balance":0,"name":"Mto eq ofic/ equipo oficina","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5160100018","balance":5.48,"name":"Mantenimiento Equ ofici/Tokens","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5160109505","balance":0,"name":"Mantenimiento Oficina","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"516015","balance":3.82,"name":"Muebles Y Enseres","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5160150005","balance":3.82,"name":"Mantenimien Muebles y Enseres","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"516095","balance":10537.28,"name":"Otros","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5160950005","balance":0,"name":"Mantenimiento Oficina","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5160950516","balance":245.68,"name":"Mto Software/Certifi Digitales","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5160950517","balance":0,"name":"Mto Software/ Mantenimient HCM","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5160950518","balance":0,"name":"Mto Software/ Mantenimient ERP","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5160950519","balance":0,"name":"Mto Software/ Mto Balanc-enrut","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5160950520","balance":0,"name":"Mto Software/ Telefonía IP","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5160950521","balance":0,"name":"Mto Software/ Aranda","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5160950522","balance":0,"name":"Mto Software/ Liferay","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5160950523","balance":0,"name":"Mto Software/ Antivirus","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5160950526","balance":0,"name":"Mto Software/ Whatsup","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5160950527","balance":128.93,"name":"Mto Software/ Manager y BAC","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5160950528","balance":197.98,"name":"Mto Software/ Licencias Oracle","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5160950529","balance":306.18,"name":"Mto Software/ Red Hat","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5160950530","balance":0,"name":"Mto Software/Licencias Microso","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5160950531","balance":228.29,"name":"Mto Software/Licencias Symante","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5160950533","balance":0,"name":"Mto Software/ SPA","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5160950538","balance":226.82,"name":"Mto Software/Mto Portales","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5160950539","balance":295.8,"name":"Mto Software/ACHNNET, ACH SSS","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5160950540","balance":670.64,"name":"Mto Software/ PSE, TEL","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5160950541","balance":1479.76,"name":"Mto Software/ Nuevo SOI","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5160950542","balance":4109.09,"name":"Mto Software/ otros","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5160950543","balance":0,"name":"Mto Software/ Pantalla y comun","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5160950544","balance":2648.12,"name":"Pruebas Servicios Tecnológicos","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5165","balance":196.2,"name":"Adecuación e Instalación De Of","chapter":"Gastos","nivel":4,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"516515","balance":196.2,"name":"Reparaciones Locativas","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5165150005","balance":196.2,"name":"Reparaciones Locativas Oficina","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"516595","balance":0,"name":"Otros","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5165950005","balance":0,"name":"Otros","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5170","balance":13.15,"name":"Provisiónes","chapter":"Gastos","nivel":4,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"517015","balance":0,"name":"Cuentas Por Cobrar","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5170150005","balance":0,"name":"Provision Ctas Por Cobrar","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"517020","balance":13.15,"name":"Cuentas por Cobrar","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5170201505","balance":13.15,"name":"Provision Ctas Por Cobrar","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5172","balance":3.03,"name":"Multas y Sanciones, Litigios,","chapter":"Gastos","nivel":4,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"517225","balance":3.03,"name":"Multas y Sanciones Otras Autor","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5172251005","balance":3.03,"name":"Multas y Sanciones Otras Autor","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5175","balance":3687.77,"name":"Depreciaciones","chapter":"Gastos","nivel":4,"classification":"Depreciación del periodo","status":true},{"initial_date":"2024-12-31","account":"517506","balance":140.36,"name":"Vehículos","chapter":"Gastos","nivel":6,"classification":"Depreciación del periodo","status":true},{"initial_date":"2024-12-31","account":"5175065005","balance":140.36,"name":"Vehículos en Leasing","chapter":"Gastos","nivel":10,"classification":"Depreciación del periodo","status":true},{"initial_date":"2024-12-31","account":"517507","balance":285.84,"name":"Edificios","chapter":"Gastos","nivel":6,"classification":"Depreciación del periodo","status":true},{"initial_date":"2024-12-31","account":"5175074005","balance":0,"name":"Activo por desmantelamiento of","chapter":"Gastos","nivel":10,"classification":"Depreciación del periodo","status":true},{"initial_date":"2024-12-31","account":"5175074010","balance":285.84,"name":"Mejoras en Propiedad Ajena","chapter":"Gastos","nivel":10,"classification":"Depreciación del periodo","status":true},{"initial_date":"2024-12-31","account":"517508","balance":74.06,"name":"Enseres y Accesorios","chapter":"Gastos","nivel":6,"classification":"Depreciación del periodo","status":true},{"initial_date":"2024-12-31","account":"5175081010","balance":74.06,"name":"Muebles y Enseres","chapter":"Gastos","nivel":10,"classification":"Depreciación del periodo","status":true},{"initial_date":"2024-12-31","account":"5175081011","balance":0,"name":"Muebles y Enseres/otros","chapter":"Gastos","nivel":10,"classification":"Depreciación del periodo","status":true},{"initial_date":"2024-12-31","account":"517510","balance":866.02,"name":"Equipo, Muebles y Enseres de O","chapter":"Gastos","nivel":6,"classification":"Depreciación del periodo","status":true},{"initial_date":"2024-12-31","account":"5175100010","balance":0,"name":"Muebles y Enseres","chapter":"Gastos","nivel":10,"classification":"Depreciación del periodo","status":true},{"initial_date":"2024-12-31","account":"5175101510","balance":195.52,"name":"Equipos de Oficina","chapter":"Gastos","nivel":10,"classification":"Depreciación del periodo","status":true},{"initial_date":"2024-12-31","account":"5175101515","balance":670.5,"name":"Leasing Equipos de Oficina","chapter":"Gastos","nivel":10,"classification":"Depreciación del periodo","status":true},{"initial_date":"2024-12-31","account":"517512","balance":1919.03,"name":"Equipo Informático","chapter":"Gastos","nivel":6,"classification":"Depreciación del periodo","status":true},{"initial_date":"2024-12-31","account":"5175121505","balance":742.82,"name":"Equip de Computo Admon","chapter":"Gastos","nivel":10,"classification":"Depreciación del periodo","status":true},{"initial_date":"2024-12-31","account":"5175121510","balance":374.97,"name":"Equip de Segurid de la Info","chapter":"Gastos","nivel":10,"classification":"Depreciación del periodo","status":true},{"initial_date":"2024-12-31","account":"5175121515","balance":801.24,"name":"Leasing Equipos de Computo","chapter":"Gastos","nivel":10,"classification":"Depreciación del periodo","status":true},{"initial_date":"2024-12-31","account":"517514","balance":402.46,"name":"Equipo de Redes y Comunicación","chapter":"Gastos","nivel":6,"classification":"Depreciación del periodo","status":true},{"initial_date":"2024-12-31","account":"5175141507","balance":0,"name":"Equipos de Telecomunicaciones","chapter":"Gastos","nivel":10,"classification":"Depreciación del periodo","status":true},{"initial_date":"2024-12-31","account":"5175142605","balance":0,"name":"Leasing Equipos de Telecomunic","chapter":"Gastos","nivel":10,"classification":"Depreciación del periodo","status":true},{"initial_date":"2024-12-31","account":"5175142606","balance":402.46,"name":"Equipos de Telecomunicaciones","chapter":"Gastos","nivel":10,"classification":"Depreciación del periodo","status":true},{"initial_date":"2024-12-31","account":"517515","balance":0,"name":"Equipo De Computación","chapter":"Gastos","nivel":6,"classification":"Depreciación del periodo","status":true},{"initial_date":"2024-12-31","account":"5175150005","balance":0,"name":"Equip de Computo Admon","chapter":"Gastos","nivel":10,"classification":"Depreciación del periodo","status":true},{"initial_date":"2024-12-31","account":"5175150010","balance":0,"name":"Equip de Segurid de la Info","chapter":"Gastos","nivel":10,"classification":"Depreciación del periodo","status":true},{"initial_date":"2024-12-31","account":"517550","balance":0,"name":"Vehículos","chapter":"Gastos","nivel":6,"classification":"Depreciación del periodo","status":true},{"initial_date":"2024-12-31","account":"5175500005","balance":0,"name":"Vehículos en Leasing","chapter":"Gastos","nivel":10,"classification":"Depreciación del periodo","status":true},{"initial_date":"2024-12-31","account":"5180","balance":24443.18,"name":"Amortizaciones","chapter":"Gastos","nivel":4,"classification":"Amortización del periodo","status":true},{"initial_date":"2024-12-31","account":"518015","balance":0,"name":"Estudios y Proyectos","chapter":"Gastos","nivel":6,"classification":"Amortización del periodo","status":true},{"initial_date":"2024-12-31","account":"5180150005","balance":0,"name":"Estudio Investigaciones y Pro","chapter":"Gastos","nivel":10,"classification":"Amortización del periodo","status":true},{"initial_date":"2024-12-31","account":"5180150006","balance":0,"name":"PROGRAMAS DE ADMINISTRACION","chapter":"Gastos","nivel":10,"classification":"Amortización del periodo","status":true},{"initial_date":"2024-12-31","account":"518020","balance":24443.18,"name":"Programas y Aplicaciones Infor","chapter":"Gastos","nivel":6,"classification":"Amortización del periodo","status":true},{"initial_date":"2024-12-31","account":"5180201505","balance":21006.44,"name":"Estudio Investigaciones y Pro","chapter":"Gastos","nivel":10,"classification":"Amortización del periodo","status":true},{"initial_date":"2024-12-31","account":"5180201506","balance":3436.74,"name":"PROGRAMAS DE ADMINISTRACION","chapter":"Gastos","nivel":10,"classification":"Amortización del periodo","status":true},{"initial_date":"2024-12-31","account":"518095","balance":0,"name":"OTRAS","chapter":"Gastos","nivel":6,"classification":"Amortización del periodo","status":true},{"initial_date":"2024-12-31","account":"5190","balance":55170.32,"name":"Diversos","chapter":"Gastos","nivel":4,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"519005","balance":3079.28,"name":"Servicio de Aseo y Vigilancia","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190050010","balance":104.05,"name":"Aseo Oficinas","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190050015","balance":0,"name":"Vigilancia","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190050016","balance":294.76,"name":"Custodia Archivo Físico","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190050020","balance":2680.47,"name":"Vigilancia Seguridad Informati","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"519010","balance":0,"name":"Servicios Temporales","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190100005","balance":0,"name":"Sumin Personal Temporal","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"519015","balance":5322.07,"name":"Publicidad y Propaganda","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190150005","balance":5116.91,"name":"Publicidad","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190150006","balance":0,"name":"Publicidad/ Regalos de Navidad","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190150007","balance":0,"name":"Publicidad/Concursos","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190150008","balance":0,"name":"Publicidad/Piezas","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190150009","balance":0,"name":"Publicidad/Promocionales","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190150010","balance":27.45,"name":"Publicidad/Campañas","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190150011","balance":0,"name":"Publicidad/Imagen","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190150012","balance":177.72,"name":"Publicidad/Ferias y Eventos","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"519020","balance":161.86,"name":"Relaciones Públicas","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190200018","balance":161.86,"name":"Relaciones Públicas","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"519025","balance":913.9,"name":"Servicios Públicos","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190250005","balance":9.08,"name":"Acueducto y Alcantarillado","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190250010","balance":108.3,"name":"Serv Energia Electrica","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190250015","balance":153.82,"name":"Servicio Telefonico","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190250016","balance":217.09,"name":"Serv Teléfono/ Línea 018000","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190250017","balance":0,"name":"Serv Teléfono/ Telefono fijo","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190250035","balance":0,"name":"Servicio Celulares","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190250036","balance":22.05,"name":"Celulares/preliquidacion P.A","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190250037","balance":18.75,"name":"Celulares/Consumo Compañía","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190250038","balance":0,"name":"Equ Telecomunicaciones_Celular","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190250041","balance":370.83,"name":"Intenet/ Internet","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190250042","balance":2.58,"name":"Intenet/ IP","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190250043","balance":11.39,"name":"Intenet/ Dominios","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190250044","balance":0,"name":"Intenet/ Webex","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190250045","balance":0,"name":"Intenet/ Modems","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"519030","balance":576.32,"name":"Procesamiento Electrónico de D","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190300013","balance":0,"name":"Comunicaciones Canales Dedicad","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190300016","balance":15.09,"name":"Canal dedicado/ Telmex","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190300017","balance":15.97,"name":"Canal dedicado/ Banc República","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190300018","balance":123.68,"name":"Canal dedicado/ Sincronización","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190300019","balance":0,"name":"Canal dedicado/ Canal Interno","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190300020","balance":128.97,"name":"Canal dedicado/ LAN to LAN","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190300021","balance":292.61,"name":"Canal dedicado/ Replicac datos","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190300022","balance":0,"name":"Canal dedicado/ SWIFT","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"519035","balance":260.24,"name":"Gastos De Viaje","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190350005","balance":65.7,"name":"Alojamiento y Manutencion","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190350015","balance":194.54,"name":"Pasajes Aereos","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190350020","balance":0,"name":"Alimentacion","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190350030","balance":0,"name":"Pasajes Terrestres","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"519040","balance":88.89,"name":"Transporte","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190400005","balance":37.92,"name":"Servicio de Taxi","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190400010","balance":50.97,"name":"Mensajeria","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190400015","balance":0.05,"name":"Servicio de Correo","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190400020","balance":0,"name":"Transporte Proveedores","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"519045","balance":19.19,"name":"Útiles Y Papelería","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190450005","balance":19.19,"name":"Papeleria","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190450006","balance":0,"name":"Papelería/ Carnets","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190450010","balance":0,"name":"Servicio de Impresion","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"519060","balance":0,"name":"DONACIONES","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"519065","balance":4105.8,"name":"Suscripciones","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190650005","balance":4105.8,"name":"Suscripciones","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"519095","balance":40454.08,"name":"Otros","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190950005","balance":357.96,"name":"Servicio Administracion Edific","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190950006","balance":0,"name":"Administracion - Otras sedes","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190950010","balance":3.9,"name":"Autenticaciones","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190950020","balance":0,"name":"Gastos Legales","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190950025","balance":4.57,"name":"Renovacion Matricula Mercantil","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190950035","balance":28.04,"name":"Elementos de Aseo","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190950036","balance":0,"name":"Elementos Cafeteria","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190950037","balance":43.68,"name":"Elem Cafeteria/ Maquina Café","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190950038","balance":6.59,"name":"Elem Cafeteria/ Consumo Sodexo","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190950039","balance":43.6,"name":"Elem Cafeteria/ Almrz Trabajo","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190950040","balance":0,"name":"Elementos Cafeteria Reuniones","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190950045","balance":18145.91,"name":"Afiliciones y Suscripciones","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190950046","balance":0,"name":"Lavanderia","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190950047","balance":4.56,"name":"Afiliación / ISACA","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190950048","balance":0,"name":"Afiliación / DRII","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190950049","balance":2.77,"name":"Afiliación / ACRIP","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190950050","balance":34.59,"name":"Junta Directiva","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190950051","balance":67.46,"name":"Suscripción / El Empleo","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190950052","balance":76.85,"name":"Afiliación / Superfinanciera","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190950053","balance":0,"name":"Suscripción / Códigos Legis","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190950054","balance":3.97,"name":"Suscripción / Notinet","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190950055","balance":0.31,"name":"Almuerzos de Trabajo","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190950056","balance":135.38,"name":"Afiliación / Informa","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190950057","balance":0,"name":"Suscripción / Seguridad CSI","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190950059","balance":0,"name":"Suscripción / Publicar","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190950061","balance":0,"name":"Suscripción / DirectTV","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190950062","balance":0.46,"name":"Suscripción / Revista Dinero","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190950063","balance":0.43,"name":"Suscripción / Diario República","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190950065","balance":0.06,"name":"Parqueadero Mensajeria","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190950066","balance":0,"name":"Suscripción / Club Banqueros","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190950067","balance":0,"name":"Afiliación / ICPFA","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190950070","balance":14.38,"name":"Gastos Varios Personal","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190950080","balance":0,"name":"Responsabilidad Social Empresa","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190950085","balance":12519.25,"name":"Otros Diversos","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190950097","balance":0,"name":"Call Center/ Asesores PA+PCSS","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190950098","balance":0,"name":"Call Center/ Asesores PE+CORP","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190950099","balance":0,"name":"Call Center/ Asesores BO+CHAT","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190950100","balance":0,"name":"Call Center/ Asesores Mto","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190950101","balance":0,"name":"Call Center/ Asesores PSE","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190950102","balance":338.82,"name":"Call Center/ IVR","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190950103","balance":0,"name":"Call Center/Tarific MTO","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190950104","balance":0,"name":"Call Center/Tarific PA-PE","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190950105","balance":0,"name":"Call Center/Tarific PSE","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190950106","balance":0,"name":"Call Center/Tarific SGS","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190950107","balance":0,"name":"Call Center/Licencia CMS","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190950108","balance":0,"name":"Call center/Registros Mantenim","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190950109","balance":8508.56,"name":"Call Center/Asesores PE/BO/PSE","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190950110","balance":0,"name":"BPO Campañas/Retroactivos","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190950505","balance":0.14,"name":"Intereses por Multas y Sancion","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190959505","balance":2.6,"name":"Activos Dados de Baja","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190959535","balance":3.28,"name":"Impuestos Asumidos","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190959536","balance":0.11,"name":"Impuestos Asumidos","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190959537","balance":0.49,"name":"Impuestos Asumidos","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190959538","balance":0.39,"name":"Impuestos Asumidos","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190959540","balance":105.64,"name":"Intereses de Mora","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190959541","balance":1.5,"name":"Intereses de Mora Leasing","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190959543","balance":0,"name":"Intereses de Mora Leasing","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190959545","balance":1.79,"name":"Otros Gastos no deducibles Fis","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190959549","balance":0,"name":"Intereses de Mora Leasing","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190959550","balance":0.57,"name":"Ajuste al Mil","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190959560","balance":1.03,"name":"Diferencia en Cambio Realizada","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190959566","balance":109.8,"name":"Diferencia en cambio no Realiz","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190959570","balance":0,"name":"Pruebas en proyectos","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190959581","balance":0,"name":"Penalidades","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190959705","balance":0,"name":"Riesgo Intereses de Mora","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190959710","balance":0,"name":"Riesgo Sanciones","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"519097","balance":188.68,"name":"Riesgo Operativo","chapter":"Gastos","nivel":6,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190970001","balance":188.68,"name":"RIESGO OPERATIVO DIVERSOS","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"5190970005","balance":0,"name":"Riesgo Diversos","chapter":"Gastos","nivel":10,"classification":"Gastos operacionales 1","status":true},{"initial_date":"2024-12-31","account":"52","balance":0,"name":"No Operacionales","chapter":"Gastos","nivel":2,"classification":"No aplica","status":true},{"initial_date":"2024-12-31","account":"5215","balance":0,"name":"PERDIDA EN VENTA DE OTROS A","chapter":"Gastos","nivel":4,"classification":"No aplica","status":true},{"initial_date":"2024-12-31","account":"521597","balance":0,"name":"RIESGO OPERATIVO","chapter":"Gastos","nivel":6,"classification":"No aplica","status":true},{"initial_date":"2024-12-31","account":"5230","balance":0,"name":"Multas Y Sanciones, Litigio","chapter":"Gastos","nivel":4,"classification":"No aplica","status":true},{"initial_date":"2024-12-31","account":"523010","balance":0,"name":"Multas y Sanciones Otras Autor","chapter":"Gastos","nivel":6,"classification":"No aplica","status":true},{"initial_date":"2024-12-31","account":"5230100005","balance":0,"name":"Multas y Sanciones Otras Autor","chapter":"Gastos","nivel":10,"classification":"No aplica","status":true},{"initial_date":"2024-12-31","account":"5295","balance":0,"name":"Diversos","chapter":"Gastos","nivel":4,"classification":"No aplica","status":true},{"initial_date":"2024-12-31","account":"529505","balance":0,"name":"Intereses por Multas y Sanc","chapter":"Gastos","nivel":6,"classification":"No aplica","status":true},{"initial_date":"2024-12-31","account":"5295050005","balance":0,"name":"Intereses por Multas y Sancion","chapter":"Gastos","nivel":10,"classification":"No aplica","status":true},{"initial_date":"2024-12-31","account":"529595","balance":0,"name":"Otros","chapter":"Gastos","nivel":6,"classification":"No aplica","status":true},{"initial_date":"2024-12-31","account":"5295950005","balance":0,"name":"Activos Dados de Baja","chapter":"Gastos","nivel":10,"classification":"No aplica","status":true},{"initial_date":"2024-12-31","account":"5295950035","balance":0,"name":"Retenciones de Fuente Asumidas","chapter":"Gastos","nivel":10,"classification":"No aplica","status":true},{"initial_date":"2024-12-31","account":"5295950036","balance":0,"name":"Retenciones Asumidas por ICA","chapter":"Gastos","nivel":10,"classification":"No aplica","status":true},{"initial_date":"2024-12-31","account":"5295950037","balance":0,"name":"Retenciones Asumidas por IVA","chapter":"Gastos","nivel":10,"classification":"No aplica","status":true},{"initial_date":"2024-12-31","account":"5295950038","balance":0,"name":"Impo por operacion exterior","chapter":"Gastos","nivel":10,"classification":"No aplica","status":true},{"initial_date":"2024-12-31","account":"5295950040","balance":0,"name":"Intereses de Mora","chapter":"Gastos","nivel":10,"classification":"No aplica","status":true},{"initial_date":"2024-12-31","account":"5295950045","balance":0,"name":"Gasto No Deducible","chapter":"Gastos","nivel":10,"classification":"No aplica","status":true},{"initial_date":"2024-12-31","account":"5295950050","balance":0,"name":"Ajuste al Mil","chapter":"Gastos","nivel":10,"classification":"No aplica","status":true},{"initial_date":"2024-12-31","account":"5295950060","balance":0,"name":"Diferencia en Cambio Realizada","chapter":"Gastos","nivel":10,"classification":"No aplica","status":true},{"initial_date":"2024-12-31","account":"5295950065","balance":0,"name":"Diferenc en Cambio por Servic","chapter":"Gastos","nivel":10,"classification":"No aplica","status":true},{"initial_date":"2024-12-31","account":"5295950066","balance":0,"name":"Diferencia en cambio no Realiz","chapter":"Gastos","nivel":10,"classification":"No aplica","status":true},{"initial_date":"2024-12-31","account":"5295950080","balance":0,"name":"Gto No Deducible Ejerc Anterio","chapter":"Gastos","nivel":10,"classification":"No aplica","status":true},{"initial_date":"2024-12-31","account":"5295950081","balance":0,"name":"Penalidades","chapter":"Gastos","nivel":10,"classification":"No aplica","status":true},{"initial_date":"2024-12-31","account":"529597","balance":0,"name":"Riesgo Operativo","chapter":"Gastos","nivel":6,"classification":"No aplica","status":true},{"initial_date":"2024-12-31","account":"5295970010","balance":0,"name":"Riesgo Sanciones","chapter":"Gastos","nivel":10,"classification":"No aplica","status":true},{"initial_date":"2024-12-31","account":"54","balance":0,"name":"Impuesto De Renta y Complement","chapter":"Gastos","nivel":2,"classification":"No aplica","status":true},{"initial_date":"2024-12-31","account":"5405","balance":0,"name":"Impuesto De Renta y Complement","chapter":"Gastos","nivel":4,"classification":"No aplica","status":true},{"initial_date":"2024-12-31","account":"540505","balance":0,"name":"Renta","chapter":"Gastos","nivel":6,"classification":"No aplica","status":true},{"initial_date":"2024-12-31","account":"5405050005","balance":0,"name":"Impuesto de Renta y Complement","chapter":"Gastos","nivel":10,"classification":"No aplica","status":true},{"initial_date":"2024-12-31","account":"5405050010","balance":0,"name":"Impuesto de Renta Diferido","chapter":"Gastos","nivel":10,"classification":"No aplica","status":true},{"initial_date":"2024-12-31","account":"5405050011","balance":0,"name":"Impuesto Renta Diferido CREe","chapter":"Gastos","nivel":10,"classification":"No aplica","status":true},{"initial_date":"2024-12-31","account":"5405050015","balance":0,"name":"Impuesto Renta Period Anterior","chapter":"Gastos","nivel":10,"classification":"No aplica","status":true},{"initial_date":"2024-12-31","account":"5405050020","balance":0,"name":"Impuesto para Equidad CREE","chapter":"Gastos","nivel":10,"classification":"No aplica","status":true},{"initial_date":"2024-12-31","account":"5405050021","balance":0,"name":"Sobretasa Impuesto de CREE","chapter":"Gastos","nivel":10,"classification":"No aplica","status":true},{"initial_date":"2024-12-31","account":"57","balance":55264.36,"name":"Impuesto de Renta y Complement","chapter":"Gastos","nivel":2,"classification":"Impuestos de renta","status":true},{"initial_date":"2024-12-31","account":"5705","balance":55264.36,"name":"Impuesto de Renta y Complement","chapter":"Gastos","nivel":4,"classification":"Impuestos de renta","status":true},{"initial_date":"2024-12-31","account":"570505","balance":55264.36,"name":"Impuesto de Renta y Complement","chapter":"Gastos","nivel":6,"classification":"Impuestos de renta","status":true},{"initial_date":"2024-12-31","account":"5705050001","balance":0,"name":"Impuesto de Renta y Complement","chapter":"Gastos","nivel":10,"classification":"Impuestos de renta","status":true},{"initial_date":"2024-12-31","account":"5705050005","balance":55264.36,"name":"Impuesto de Renta y Complement","chapter":"Gastos","nivel":10,"classification":"Impuestos de renta","status":true},{"initial_date":"2024-12-31","account":"5705050010","balance":0,"name":"Impuesto de Renta Diferido","chapter":"Gastos","nivel":10,"classification":"Impuestos de renta","status":true},{"initial_date":"2024-12-31","account":"5705050015","balance":0,"name":"Impuesto Renta Periodo Anterio","chapter":"Gastos","nivel":10,"classification":"Impuestos de renta","status":true},{"initial_date":"2024-12-31","account":"5705050020","balance":0,"name":"Impuesto para Equidad CREE","chapter":"Gastos","nivel":10,"classification":"Impuestos de renta","status":true},{"initial_date":"2024-12-31","account":"5705050021","balance":0,"name":"Sobretasa Impuesto de CREE","chapter":"Gastos","nivel":10,"classification":"Impuestos de renta","status":true},{"initial_date":"2024-12-31","account":"59","balance":0,"name":"Ganancias (excedentes) Y Perdi","chapter":"Gastos","nivel":2,"classification":"Utilidad del ejercicio","status":true},{"initial_date":"2024-12-31","account":"5905","balance":0,"name":"Ganancias (excedentes) Y Perdi","chapter":"Gastos","nivel":4,"classification":"Utilidad del ejercicio","status":true},{"initial_date":"2024-12-31","account":"590501","balance":0,"name":"Ganancias (excedentes) Y Perdi","chapter":"Gastos","nivel":6,"classification":"Utilidad del ejercicio","status":true},{"initial_date":"2024-12-31","account":"590505","balance":0,"name":"Ganancias (Excedentes) y Perdi","chapter":"Gastos","nivel":6,"classification":"Utilidad del ejercicio","status":true},{"initial_date":"2024-12-31","account":"5905050005","balance":0,"name":"Resultado del Ejercicio","chapter":"Gastos","nivel":10,"classification":"Utilidad del ejercicio","status":true},{"initial_date":"2024-12-31","account":"8","balance":0,"name":"CUENTAS DE ORDEN DEUDORAS","chapter":"Cuentas de orden deudoras","nivel":1,"classification":"No aplica","status":true},{"initial_date":"2024-12-31","account":"81","balance":0,"name":"Deudoras","chapter":"Cuentas de orden deudoras","nivel":2,"classification":"No clasificado","status":false},{"initial_date":"2024-12-31","account":"8112","balance":0,"name":"BIENES INMUEBLES DESTINADOS","chapter":"Cuentas de orden deudoras","nivel":4,"classification":"No clasificado","status":false},{"initial_date":"2024-12-31","account":"811210","balance":0,"name":"CANON DE ARRENDAMIENTO","chapter":"Cuentas de orden deudoras","nivel":6,"classification":"No clasificado","status":false},{"initial_date":"2024-12-31","account":"8170","balance":0,"name":"Propiedades Y Equipo Totalment","chapter":"Cuentas de orden deudoras","nivel":4,"classification":"No clasificado","status":false},{"initial_date":"2024-12-31","account":"817010","balance":0,"name":"Equipo Muebles y Enseres De Of","chapter":"Cuentas de orden deudoras","nivel":6,"classification":"No clasificado","status":false},{"initial_date":"2024-12-31","account":"8170100099","balance":0,"name":"Muebles y Enseres","chapter":"Cuentas de orden deudoras","nivel":10,"classification":"No clasificado","status":false},{"initial_date":"2024-12-31","account":"817015","balance":0,"name":"Equipo De Computación","chapter":"Cuentas de orden deudoras","nivel":6,"classification":"No clasificado","status":false},{"initial_date":"2024-12-31","account":"8170150005","balance":0,"name":"Administracion","chapter":"Cuentas de orden deudoras","nivel":10,"classification":"No clasificado","status":false},{"initial_date":"2024-12-31","account":"8171","balance":0,"name":"Valor Fiscal De Los Activos","chapter":"Cuentas de orden deudoras","nivel":4,"classification":"No clasificado","status":false},{"initial_date":"2024-12-31","account":"817105","balance":0,"name":"Valor Fiscal De Los Activos","chapter":"Cuentas de orden deudoras","nivel":6,"classification":"No clasificado","status":false},{"initial_date":"2024-12-31","account":"8171050005","balance":0,"name":"Valor Fiscal de Los Activos","chapter":"Cuentas de orden deudoras","nivel":10,"classification":"No clasificado","status":false},{"initial_date":"2024-12-31","account":"82","balance":0,"name":"Acreedoras","chapter":"Cuentas de orden deudoras","nivel":2,"classification":"No clasificado","status":false},{"initial_date":"2024-12-31","account":"8246","balance":0,"name":"Ajustes por Inflación Patrimon","chapter":"Cuentas de orden deudoras","nivel":4,"classification":"No clasificado","status":false},{"initial_date":"2024-12-31","account":"824631","balance":0,"name":"Capital Social","chapter":"Cuentas de orden deudoras","nivel":6,"classification":"No clasificado","status":false},{"initial_date":"2024-12-31","account":"8246310005","balance":0,"name":"Capital Social","chapter":"Cuentas de orden deudoras","nivel":10,"classification":"No clasificado","status":false},{"initial_date":"2024-12-31","account":"824632","balance":0,"name":"Reservas","chapter":"Cuentas de orden deudoras","nivel":6,"classification":"No clasificado","status":false},{"initial_date":"2024-12-31","account":"8246320005","balance":0,"name":"Reservas","chapter":"Cuentas de orden deudoras","nivel":10,"classification":"No clasificado","status":false},{"initial_date":"2024-12-31","account":"824635","balance":0,"name":"Resultados de Ejercicios Anter","chapter":"Cuentas de orden deudoras","nivel":6,"classification":"No clasificado","status":false},{"initial_date":"2024-12-31","account":"8246350005","balance":0,"name":"Resultados de Ejercicios Anter","chapter":"Cuentas de orden deudoras","nivel":10,"classification":"No clasificado","status":false},{"initial_date":"2024-12-31","account":"8271","balance":0,"name":"Valor Fiscal del Patrimonio","chapter":"Cuentas de orden deudoras","nivel":4,"classification":"No clasificado","status":false},{"initial_date":"2024-12-31","account":"827105","balance":0,"name":"Diferen Fiscal Vs Contabilidad","chapter":"Cuentas de orden deudoras","nivel":6,"classification":"No clasificado","status":false},{"initial_date":"2024-12-31","account":"8271050005","balance":0,"name":"Valor Fiscal del Patrimonio","chapter":"Cuentas de orden deudoras","nivel":10,"classification":"No clasificado","status":false},{"initial_date":"2024-12-31","account":"83","balance":0,"name":"Deudoras Por Contra","chapter":"Cuentas de orden deudoras","nivel":2,"classification":"No clasificado","status":false},{"initial_date":"2024-12-31","account":"8305","balance":0,"name":"Deudoras Por Contra (CR)","chapter":"Cuentas de orden deudoras","nivel":4,"classification":"No clasificado","status":false},{"initial_date":"2024-12-31","account":"830505","balance":0,"name":"BIENES MUEBLES","chapter":"Cuentas de orden deudoras","nivel":6,"classification":"No clasificado","status":false},{"initial_date":"2024-12-31","account":"830515","balance":0,"name":"Deudoras De Control Por Contra","chapter":"Cuentas de orden deudoras","nivel":6,"classification":"No clasificado","status":false},{"initial_date":"2024-12-31","account":"8305150015","balance":0,"name":"Administracion","chapter":"Cuentas de orden deudoras","nivel":10,"classification":"No clasificado","status":false},{"initial_date":"2024-12-31","account":"8305150090","balance":0,"name":"Muebles y Eneres","chapter":"Cuentas de orden deudoras","nivel":10,"classification":"No clasificado","status":false},{"initial_date":"2024-12-31","account":"830571","balance":0,"name":"Valor Fiscal De Los Activos","chapter":"Cuentas de orden deudoras","nivel":6,"classification":"No clasificado","status":false},{"initial_date":"2024-12-31","account":"8305710005","balance":0,"name":"Valor Fiscal de los Activos Cr","chapter":"Cuentas de orden deudoras","nivel":10,"classification":"No clasificado","status":false},{"initial_date":"2024-12-31","account":"84","balance":0,"name":"Acreedoras Por Contra","chapter":"Cuentas de orden deudoras","nivel":2,"classification":"No clasificado","status":false},{"initial_date":"2024-12-31","account":"8405","balance":0,"name":"Acreedoras Por Contra (DB)","chapter":"Cuentas de orden deudoras","nivel":4,"classification":"No clasificado","status":false},{"initial_date":"2024-12-31","account":"840505","balance":0,"name":"Acreedoras Por Contra (DB)","chapter":"Cuentas de orden deudoras","nivel":6,"classification":"No clasificado","status":false},{"initial_date":"2024-12-31","account":"8405050005","balance":0,"name":"Capital Social","chapter":"Cuentas de orden deudoras","nivel":10,"classification":"No clasificado","status":false},{"initial_date":"2024-12-31","account":"8405050010","balance":0,"name":"Reservas","chapter":"Cuentas de orden deudoras","nivel":10,"classification":"No clasificado","status":false},{"initial_date":"2024-12-31","account":"8405050015","balance":0,"name":"Resultados de Ejercicios Anter","chapter":"Cuentas de orden deudoras","nivel":10,"classification":"No clasificado","status":false},{"initial_date":"2024-12-31","account":"8405050020","balance":0,"name":"Ajuste Inflacion","chapter":"Cuentas de orden deudoras","nivel":10,"classification":"No clasificado","status":false},{"initial_date":"2024-12-31","account":"840571","balance":0,"name":"Valor Fiscal Del Patrim DB","chapter":"Cuentas de orden deudoras","nivel":6,"classification":"No clasificado","status":false},{"initial_date":"2024-12-31","account":"8405710005","balance":0,"name":"Valor Fiscal Patrimnio Db","chapter":"Cuentas de orden deudoras","nivel":10,"classification":"No clasificado","status":false},{"account":"4210150005","name":"Cuenta creada para balanceo de pucs historicos","balance":0,"ID_RAW_CLASSIFICATION":0,"initial_date":"2024-12-31","chapter":"Ingresos","nivel":10,"classification":"Otros ingresos no operativos","status":true},{"account":"4295","name":"Cuenta creada para balanceo de pucs historicos","balance":0,"ID_RAW_CLASSIFICATION":0,"initial_date":"2024-12-31","chapter":"Ingresos","nivel":4,"classification":"Otros ingresos no operativos","status":true},{"account":"4295950055","name":"Cuenta creada para balanceo de pucs historicos","balance":0,"ID_RAW_CLASSIFICATION":0,"initial_date":"2024-12-31","chapter":"Ingresos","nivel":10,"classification":"Otros ingresos no operativos","status":true},{"account":"4295950050","name":"Cuenta creada para balanceo de pucs historicos","balance":0,"ID_RAW_CLASSIFICATION":0,"initial_date":"2024-12-31","chapter":"Ingresos","nivel":10,"classification":"Otros ingresos no operativos","status":true},{"account":"42","name":"Cuenta creada para balanceo de pucs historicos","balance":0,"ID_RAW_CLASSIFICATION":0,"initial_date":"2024-12-31","chapter":"Ingresos","nivel":2,"classification":"Otros ingresos no operativos","status":true},{"account":"4295950040","name":"Cuenta creada para balanceo de pucs historicos","balance":0,"ID_RAW_CLASSIFICATION":0,"initial_date":"2024-12-31","chapter":"Ingresos","nivel":10,"classification":"Otros ingresos no operativos","status":true},{"account":"4295950065","name":"Cuenta creada para balanceo de pucs historicos","balance":0,"ID_RAW_CLASSIFICATION":0,"initial_date":"2024-12-31","chapter":"Ingresos","nivel":10,"classification":"Otros ingresos no operativos","status":true},{"account":"422513","name":"Cuenta creada para balanceo de pucs historicos","balance":0,"ID_RAW_CLASSIFICATION":0,"initial_date":"2024-12-31","chapter":"Ingresos","nivel":6,"classification":"Otros ingresos no operativos","status":true},{"account":"4225950010","name":"Cuenta creada para balanceo de pucs historicos","balance":0,"ID_RAW_CLASSIFICATION":0,"initial_date":"2024-12-31","chapter":"Ingresos","nivel":10,"classification":"Otros ingresos no operativos","status":true},{"account":"4225130005","name":"Cuenta creada para balanceo de pucs historicos","balance":0,"ID_RAW_CLASSIFICATION":0,"initial_date":"2024-12-31","chapter":"Ingresos","nivel":10,"classification":"Otros ingresos no operativos","status":true},{"account":"422595","name":"Cuenta creada para balanceo de pucs historicos","balance":0,"ID_RAW_CLASSIFICATION":0,"initial_date":"2024-12-31","chapter":"Ingresos","nivel":6,"classification":"Otros ingresos no operativos","status":true},{"account":"4295950060","name":"Cuenta creada para balanceo de pucs historicos","balance":0,"ID_RAW_CLASSIFICATION":0,"initial_date":"2024-12-31","chapter":"Ingresos","nivel":10,"classification":"Otros ingresos no operativos","status":true},{"account":"4295950080","name":"Cuenta creada para balanceo de pucs historicos","balance":0,"ID_RAW_CLASSIFICATION":0,"initial_date":"2024-12-31","chapter":"Ingresos","nivel":10,"classification":"Otros ingresos no operativos","status":true},{"account":"4295950070","name":"Cuenta creada para balanceo de pucs historicos","balance":0,"ID_RAW_CLASSIFICATION":0,"initial_date":"2024-12-31","chapter":"Ingresos","nivel":10,"classification":"Otros ingresos no operativos","status":true},{"account":"421015","name":"Cuenta creada para balanceo de pucs historicos","balance":0,"ID_RAW_CLASSIFICATION":0,"initial_date":"2024-12-31","chapter":"Ingresos","nivel":6,"classification":"Otros ingresos no operativos","status":true},{"account":"4210200005","name":"Cuenta creada para balanceo de pucs historicos","balance":0,"ID_RAW_CLASSIFICATION":0,"initial_date":"2024-12-31","chapter":"Ingresos","nivel":10,"classification":"Otros ingresos no operativos","status":true},{"account":"4210","name":"Cuenta creada para balanceo de pucs historicos","balance":0,"ID_RAW_CLASSIFICATION":0,"initial_date":"2024-12-31","chapter":"Ingresos","nivel":4,"classification":"Otros ingresos no operativos","status":true},{"account":"4225950005","name":"Cuenta creada para balanceo de pucs historicos","balance":0,"ID_RAW_CLASSIFICATION":0,"initial_date":"2024-12-31","chapter":"Ingresos","nivel":10,"classification":"Otros ingresos no operativos","status":true},{"account":"4295950031","name":"Cuenta creada para balanceo de pucs historicos","balance":0,"ID_RAW_CLASSIFICATION":0,"initial_date":"2024-12-31","chapter":"Ingresos","nivel":10,"classification":"Otros ingresos no operativos","status":true},{"account":"4295950085","name":"Cuenta creada para balanceo de pucs historicos","balance":0,"ID_RAW_CLASSIFICATION":0,"initial_date":"2024-12-31","chapter":"Ingresos","nivel":10,"classification":"Otros ingresos no operativos","status":true},{"account":"4225130010","name":"Cuenta creada para balanceo de pucs historicos","balance":0,"ID_RAW_CLASSIFICATION":0,"initial_date":"2024-12-31","chapter":"Ingresos","nivel":10,"classification":"Otros ingresos no operativos","status":true},{"account":"4295950035","name":"Cuenta creada para balanceo de pucs historicos","balance":0,"ID_RAW_CLASSIFICATION":0,"initial_date":"2024-12-31","chapter":"Ingresos","nivel":10,"classification":"Otros ingresos no operativos","status":true},{"account":"421020","name":"Cuenta creada para balanceo de pucs historicos","balance":0,"ID_RAW_CLASSIFICATION":0,"initial_date":"2024-12-31","chapter":"Ingresos","nivel":6,"classification":"Otros ingresos no operativos","status":true},{"account":"4225","name":"Cuenta creada para balanceo de pucs historicos","balance":0,"ID_RAW_CLASSIFICATION":0,"initial_date":"2024-12-31","chapter":"Ingresos","nivel":4,"classification":"Otros ingresos no operativos","status":true},{"account":"429595","name":"Cuenta creada para balanceo de pucs historicos","balance":0,"ID_RAW_CLASSIFICATION":0,"initial_date":"2024-12-31","chapter":"Ingresos","nivel":6,"classification":"Otros ingresos no operativos","status":true}]}]}'} + lambda_handler(event, '') \ No newline at end of file diff --git a/corporate_finances_back_py/multi-account-classification/utils.py b/corporate_finances_back_py/multi-account-classification/utils.py new file mode 100644 index 0000000..85b57e1 --- /dev/null +++ b/corporate_finances_back_py/multi-account-classification/utils.py @@ -0,0 +1,56 @@ +#version 2023 - 05 - 04 +import base64 +import boto3 +import json +import logging +import os + +from sqlalchemy import create_engine + +from decorators import handler_wrapper, debugger_wrapper, try_pass_wrapper + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + + +@debugger_wrapper('Error al obtener secreto','Error fatal de back conectando a base de datos') +def get_secret(secret_region, secret_name): + session = boto3.session.Session() + client_secrets_manager = session.client(service_name='secretsmanager', region_name=secret_region) + secret_data = client_secrets_manager.get_secret_value(SecretId=secret_name) + if 'SecretString' in secret_data: + secret_str = secret_data['SecretString'] + else: + secret_str = base64.b64decode(secret_data['SecretBinary']) + logger.info('[utils] (get_secret) Se obtuvo el secreto') + return json.loads(secret_str) + + +@debugger_wrapper('Error en la conexion a base de datos','Error fatal de back conectando a base de datos') +def connect_to_db(db_schema, db_secret): + conn_string = ('mysql+mysqlconnector://' + db_secret["username"] + ':' + db_secret["password"] + '@' + db_secret["host"] + ':' + str(db_secret["port"]) + '/' + db_schema) + sql_engine = create_engine(conn_string) + db_connection = sql_engine.connect() + return db_connection + + +#@handler_wrapper('Invocando asincronamente a Engine de dinamismo', 'Invocación a Engine exitosa', 'Error invocando a Engine', 'Error invocando dinamismo') +@try_pass_wrapper('Error llamando a Core Engine') +def call_dynamic_engine(id_assessment): + lambda_engine = os.environ['LAMBDA_ENGINE'] + data = json.dumps({'id_assessment':id_assessment}).encode() + client = boto3.client('lambda') + client.invoke( + FunctionName=lambda_engine, + InvocationType='Event', + Payload= data +) + +@debugger_wrapper('Error en la conexion a base de datos','Error fatal de back conectando a base de datos') +def connect_to_db_local_dev(): + from dotenv import load_dotenv + load_dotenv() + conn_string = os.environ['local_dev_connector'] + sql_engine = create_engine(conn_string) + db_connection = sql_engine.connect() + return db_connection diff --git a/corporate_finances_back_py/multi-puc-depurate/decorators.py b/corporate_finances_back_py/multi-puc-depurate/decorators.py new file mode 100644 index 0000000..1aba58c --- /dev/null +++ b/corporate_finances_back_py/multi-puc-depurate/decorators.py @@ -0,0 +1,47 @@ +#version 2022 - 12 - 06 +import logging +import sys +import traceback +from functools import wraps +from time import time + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + +def handler_wrapper(start, satisfactory_log, error_log, raise_error): + #esto se ejecuta en la inicializacion de primero + def decorator(func): + #print(message1) + #lo que yo ponga acá se ejecuta antes de hacer el llamado a la funcion + def wrapper(*args, **kwargs): + #esto sí se ejecuta solo cuando llama a la funcion decorada + #print(message2) + try: + logger.info(f'[{func.__name__}] {start}...') + resultado = func(*args, **kwargs) + logger.info(f'[{func.__name__}] {satisfactory_log}') + return resultado + except Exception as e: + logger.error(f"[{func.__name__}] {error_log}, linea: {get_especific_error_line(func.__name__)}, motivo: {str(e)}") + raise Exception(f"{raise_error}") + + return wrapper + return decorator + + +def get_especific_error_line(func_name): + _, _, exc_tb = sys.exc_info() + for trace in traceback.extract_tb(exc_tb): + if func_name in trace: + return str(trace[1]) + +def timing(f): + @wraps(f) + def wrap(*args, **kw): + ts = time() + result = f(*args, **kw) + te = time() + taken_time_message = '[timing] La funcion {}, toma: {:.2f} sec en ejecutarse'.format(f.__name__, te-ts) + logger.info(taken_time_message) + return result + return wrap diff --git a/corporate_finances_back_py/multi-puc-depurate/lambda_function.py b/corporate_finances_back_py/multi-puc-depurate/lambda_function.py new file mode 100644 index 0000000..17172df --- /dev/null +++ b/corporate_finances_back_py/multi-puc-depurate/lambda_function.py @@ -0,0 +1,327 @@ +""": +============================================================= + +Nombre: lbd-dev-etl-fincor-puc-columns-depurate-post +Tipo: Lambda AWS +Autor: Jeisson David Botache Yela +Tecnología - Precia + +Ultima modificación: 11/07/2022 + +Para el proyecto Delta de finanzas corporativas se construyó la lambda +lbd-dev-layer-fincor-puc-columns-name-get, que sirve para encontrar los encabezados +de columnas de puc, el analista escoge entre estos encabezados cuáles desea utilizar +como columna de nombres de cuenta y columna de saldos. Para evitar problemas por +columnas con el mismo nombre, la información debe llegar a este depurador en una +estructura especifica. +Requerimientos: +capas +capa-pandas-data-transfer + +variables de entorno: +ARCHIVES_TABLE : ARCHIVE +BUCKET_NAME : s3-dev-datalake-sources +COMPANIES_TABLE : COMPANY +DB_SCHEMA : src_corporate_finance +PUC_BUCKET_PATH : corporate_finances/pucs/client/ +SECRET_DB_NAME : precia/rds8/sources/finanzas_corporativas +SECRET_DB_REGION : us-east-1 + +RAM: 1024 MB + +============================== +""" +import boto3 +import boto3 +import datetime +import json +import logging +import urllib +from queue import Queue +from threading import Thread +import sys +import sqlalchemy +import traceback +import pandas as pd + +from decorators import handler_wrapper, timing +from utils import * + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + + +def lambda_handler(event, context): + """: + Funcion lambda_handler que se activa automaticamente. La función llama los demás metodos de la lambda + que contienen la logica necesaria para obtener los resultados. Si en el procedimiento hay errores + se dispara un raise que ejecuta una respuesta base que debería servir para encontrar la ubicacion + del error. + :param event: Se puede interpretar como variables base que activan la lambda + :param context: contiene informacion relevante al ambiente de la lambda, raramente se usa + :returns: La funcion debe devolver un objeto con los encabezados y el body en la estructura esperada; + """ + logger.info(f'event de entrada: \n{str(event)}') + sc_obj = script_object(event) + return sc_obj.starter() + + +class script_object: + + def __init__(self, event): + try: + logger.info('[__INIT__] Inicializando objeto lambda ...') + self.failed_init = False + logger.info(f'event de entrada: {str(event)}') + self.bucket_name = os.environ['BUCKET_NAME'] + self.puc_bucket_path = os.environ['PUC_BUCKET_PATH'] + self.companies_table = os.environ['COMPANIES_TABLE'] + self.archives_table = os.environ['ARCHIVES_TABLE'] + db_schema = os.environ['DB_SCHEMA'] + secret_db_region = os.environ['SECRET_DB_REGION'] + secret_db_name = os.environ['SECRET_DB_NAME'] + db_secret = get_secret(secret_db_region, secret_db_name) + self.db_connection = connect_to_db(db_schema, db_secret) + + event_body_json = event["body"] + event_body_dict = json.loads(event_body_json) + self.row = event_body_dict['row'] + self.accounts_column = event_body_dict['accounts_column'] + self.nit = event_body_dict['nit'] + self.replace = event_body_dict['replace'] + self.filename = '.'.join(urllib.parse.unquote(event_body_dict['filename'].encode('utf8')).split('.')[:-1]) + '.json' + self.selected_columns = event_body_dict['selected_columns'] + logger.warning(f'selected columns encontrados: {self.selected_columns}') + self.s3_client = boto3.client('s3') + self.company_info = dict() + self.found_archives = [] + self.repeated_dates = [] + self.depurated_dfs_list = [] + self.queue_inputs = Queue() + self.queue_outputs = Queue() + + self.df_full_original = pd.core.frame.DataFrame() + + self.final_response = {'headers':{'Access-Control-Allow-Headers': '*', 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Methods': '*'}} #,'statusCode': 200 + logger.info('[__INIT__] Objeto lambda inicializada exitosamente') + + except Exception as e: + self.failed_init = True + logger.error(f"[__INIT__] error en inicializacion, linea: {get_especific_error_line()}, motivo: "+str(e)) + + + def starter(self): + try: + if self.failed_init: + raise AttributeError('Falla inicializacion, revisar logs') + self.get_company_info() + repeated_data = self.check_archives_info() + is_able_to_continue = self.check_values_to_continue(repeated_data) + if not is_able_to_continue: + return self.response_maker(succesfull=True) + + self.download_file() + self.read_json_as_dataframe() + self.depurate_dataframe() + self.multi_uploader() + logger.info('Tareas de lambda terminadas con exito') + self.db_connection.close() + return self.response_maker(succesfull = True) + + except Exception as e: + if self.db_connection: + self.db_connection.close() + logger.error(f'[starter] Error en el procesamieno del comando de la linea: {get_current_error_line()}, motivo: {e}') + return self.response_maker(succesfull = False, exception_str = e) + + + @handler_wrapper('Buscando id del nit recibido','El id del nit recibido fue encontrado','Error en la busqueda de los datos de la empresa','Error, problemas localizando la informacion de la empresa') + def get_company_info(self): + query = f"SELECT * FROM {self.companies_table} WHERE NIT=\"{self.nit}\" LIMIT 1" + logger.info(f'[get_company_info] Query para obtener datos de la empresa: {query}') + rds_data = self.db_connection.execute(query) + self.company_info = dict(rds_data.mappings().all()[0]) + + + @handler_wrapper('Chequeando si alguno de los archive ya existe','existencia de Archives completada', 'Error chequeando existencia de archives', 'Error fatal, no se pudo confirmar existencia de archives') + def check_archives_info(self): + repeated_data = False + for column_info in self.selected_columns[1:]: + initial_date = datetime.datetime.strptime(column_info['date'], "%d-%m-%Y").strftime('%Y-%m-%d %H:%M:%S') + query = f"SELECT ID FROM {self.archives_table} WHERE ID_COMPANY={self.company_info['ID']} AND INITIAL_DATE=\"{initial_date}\" AND PERIODICITY=\"{column_info['periodicity']}\" LIMIT 1" + logger.warning(f'query para mirar si existe el archive: {query}') + rds_data = self.db_connection.execute(query) + if rds_data.rowcount != 0: + self.repeated_dates.append(column_info['date']) + repeated_data = True + found_archive = dict(rds_data.mappings().all()[0])['ID'] + logger.warning(f'Archive encontrado: {found_archive}') + self.found_archives.append({'found_archive':found_archive, 'date' : initial_date, 'sector':self.company_info['SECTOR']}) + continue + self.found_archives.append({'company_id':self.company_info['ID'],'date':initial_date,'periodicity':column_info['periodicity'], 'sector':self.company_info['SECTOR']}) + + logger.info(f'[check_archives_info] Repeated_dates: {self.repeated_dates}') + return repeated_data + + + @handler_wrapper('Chequeando si se puede seguir ejecutando la lamba con datos repetidos','Chequeo terminado','Error al chequear valores para continuar','Error interno') + def check_values_to_continue(self, repeated_data): + """: + Este metodo asume algo importante: unicamente el perfil de 'Especialista' va a poder aceptar un reemplazo en el front, + entonces, si hay data repetida se va a cancelar la lambda siempre, a menos que el front haya enviado un replace, lo + cual, unicamente va a poder hacerlo un 'especialista'. hice un metodo completo para chequear esto en caso de que esta + comprobacion tenga más dificultad en un futuro + :key_values: De acá necesito ver si hay o no un replace + :repeated_data: Necesito ver si se encontró el mismo archive en uso, en caso de que no, la lambda va a continuar + para cualquier usuario + """ + if repeated_data and not self.replace: + return False + return True + + @handler_wrapper('Descargando archivo desde s3','Descarga exitosa','Error en la descarga del archivo','Hubieron problemas descargando el archivo cargado') + def download_file(self): + """: + Funcion que toma el filename para descargar el archivo de mismo nombre al /tmp del lambda; + importante: una lambda automatica lee el archivo que se sube a s3 y hace una copia a json. + :bucket_name: variable de entorno indicando el bucket donde se encuentra el archivo + :puc_bucket_path: variable de entorno indicando el key path donde se encuentra el archivo + :filename: nombre del archivo a buscar + :returns: La funcion no regresa nada + """ + logger.info(f'[download_file] Descargando archivo: {self.filename} desde {self.puc_bucket_path}...') + self.s3_client.download_file(self.bucket_name, self.puc_bucket_path+self.filename,'/tmp/'+self.filename) + + + @handler_wrapper('Leyendo archivo','Archivo convertido exitosamente','Error en la lectura del json a DataFrame','Error fatal en la lectura del archivo') + def read_json_as_dataframe(self): + """: + Funcion que toma el filename para hacer la lectura del archivo json descargado como DataFrame + :filename: nombre del archivo a buscar + :returns: La funcion regresa el dataframe del json. ya que el excel no sufrió cambios al + reformatearse a json lo nombro df_full_original + """ + + self.df_full_original = pd.read_json('/tmp/'+self.filename, orient="table") + + + @handler_wrapper('Depurando dataframe','Dataframe depurado con exito','Error al depurar Dataframe','Erro fatal en la depuracion') + def depurate_dataframe(self): + """: + Funcion que toma el dataFrame con los datos originales y lo depura por medio de los siguientes key values: + las variables headers_row y accounts_column se calcularon en la lambda 'lbd-dev-layer-fincor-puc-columns-name-get' + pero como la comunicacion entre lammbdas debe hacerse entre servicios como RDS, se decidió que el front guardara + estas variables para entregarlas en esta lambda. El DataFrame se depura y pasa por una acomodación extra: + se generalizan los nombres de coilumna a 'account', 'name', 'balance' + los tipos de datos son todos string excepto el de balance, que es float + los codigos pasan por un strip en caso de que hayan espacios + cambio celdas vacias (NaN) por espacios vacios '' + reviso que las celdas en account sean de tipo numerico, y me quedo con las que cumplen + organizo el dataframe por account (no olvidar que son numeros pero lo leo como string) + :headers_row: numero de fila donde se encontró que empieza el puc + :account_column: numero de columna donde se encontraron los codigos cuenta + :selected_columns: array de columnas seleccionadas por el analista en el front + :returns: La funcion regresa el dataframe depurado y con indexes recalculados + """ + + columnsIndexes = [] + columnsIndexes.append(self.accounts_column) + columnsIndexes.append(self.selected_columns.pop(0)['column']) + + base_df = self.df_full_original[self.row:].iloc[:, columnsIndexes] + + base_df.rename(columns={base_df.columns[0]: 'account', base_df.columns[1]: 'name'}, inplace=True) + base_df = base_df.astype({"account": "string", "name": "string"}, copy=True) + base_df['account'] = base_df['account'].str.strip() #hago strip de toda la columna account + + for column_info in self.selected_columns: + logger.info(f"[depurate_dataframe] depurando la columna: {column_info['column']}, con fecha: {column_info['date']}") + temp_df = base_df.copy() + temp_df.fillna('No aplica', inplace=True) + + temp_df['balance'] = self.df_full_original[self.row:].iloc[:, column_info['column']] + #logger.info(f"esto es lo que voy a meter a depurated_dfs_list: {str({'dataframe':temp_df,'archive':self.found_archives.pop(0)})}") + self.depurated_dfs_list.append({'dataframe':temp_df.to_dict('records'),'archive':self.found_archives.pop(0)}) + + + @handler_wrapper('Iniciando multi uploader','Multi uploader terminado con exito','Error en la carga de archivos, por favor revise su base de datos con la data que se intentó subir','Error en la carga a base de datos') + def multi_uploader(self): + """: + Funcion que toma el dataFrame depurado para guardarlo en + :filename: cómo se va a nombrear el archivo guardado + :depurated_file_df: DataFrame depurado + :returns: La funcion no regresa nada + """ + for item in self.depurated_dfs_list: + self.queue_inputs.put(item) + logger.warning('items guardados en q inputs') + + for t in range(len(self.depurated_dfs_list)): + worker = Thread(target=self.to_db_call) + worker.daemon = True + worker.start() + logger.warning('[multi_uploader] Empiezan a ejecutarse los hilos') + + self.queue_inputs.join() + + self.final_response['body'] = 'Carga y chequeo de datos exitoso' #,'statusCode': 200} + results = [] + + for t in range(len(self.depurated_dfs_list)): + + current_result =self.queue_outputs.get() + results.append(current_result) + if not current_result['succesfull']: + self.final_response['body'] = 'Hubieron problemas en la carga de algunos datos, porfa comuniquese con un administrador de tecnologia' + + self.queue_inputs = '' + self.queue_outputs = '' + + print(f'Estos fueron los resultados: {results}') + + + @handler_wrapper('iniciando hilo de carga de dataframe depurado','hilo terminado','error en el hilo','Error en la carga, confirme la carga en bd') + def to_db_call(self): + input_item = self.queue_inputs.get() + + data = json.dumps({'body': json.dumps(input_item)}).encode() + session = boto3.session.Session() + lambda_client = session.client('lambda') + + slave_lambda_checker = os.environ['SLAVE_LAMBDA_CHECKER'] + invoke_response = lambda_client.invoke(FunctionName = slave_lambda_checker, + #InvocationType='Event', + #InvocationType="RequestResponse", + Payload = data) + + response_object = json.loads(json.loads(invoke_response['Payload'].read().decode())['body']) + self.queue_outputs.put(response_object) + self.queue_inputs.task_done() + + + def response_maker(self, succesfull = False, exception_str = str): + if not succesfull: + self.final_response['body'] = json.dumps(exception_str) + return self.final_response + elif self.found_archives: + self.final_response['body'] = json.dumps(self.found_archives) + return self.final_response + else: + self.final_response['body'] = json.dumps(self.final_response['body']) + return self.final_response + + + +def get_error_line(): + """: + Funcion que busca la linea del ultimo error, en caso de usarse en cadena (como un except que recive el raise de + una funcion) se vuelve medianamente innecesario, ya que señalaría a la evocación de la función que falló, no a + la linea interna de la funcion que falló + :returns: La funcion regresa un string con la linea donde hubo la excepcion, sea por error o un raise + """ + return str(sys.exc_info()[-1].tb_lineno) + + +def get_especific_error_line(): + _, _, exc_tb = sys.exc_info() + return str(traceback.extract_tb(exc_tb)[-1][1]) diff --git a/corporate_finances_back_py/multi-puc-depurate/utils.py b/corporate_finances_back_py/multi-puc-depurate/utils.py new file mode 100644 index 0000000..f8be200 --- /dev/null +++ b/corporate_finances_back_py/multi-puc-depurate/utils.py @@ -0,0 +1,55 @@ +import base64 +import boto3 +import json +import logging +import os +import sys + +from sqlalchemy import create_engine + +from decorators import handler_wrapper + + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + + +@handler_wrapper('Obteniendo secreto','secreto obtenido','Error al obtener secreto','error fatal de back') +def get_secret(secret_region, secret_name): + """ + Obtiene las credenciales que vienen del Secret Manager + :param secret_region: (string) Nombre de la region donde se encuentran las credenciales + :param secrete_name: (string) Nombre del secreto + :return: (dict) Diccionario con las credenciales + """ + session = boto3.session.Session() + client_secrets_manager = session.client(service_name='secretsmanager', region_name=secret_region) + secret_data = client_secrets_manager.get_secret_value(SecretId=secret_name) + if 'SecretString' in secret_data: + secret_str = secret_data['SecretString'] + else: + secret_str = base64.b64decode(secret_data['SecretBinary']) + logger.info('[utils] (get_secret) Se obtuvo el secreto') + return json.loads(secret_str) + + +@handler_wrapper('Conectando a base de datos {a}','Conectado correctamente a base de datos','Error en la conexion a base de datos','error fatal de back') +def connect_to_db(db_schema, db_secret): + """ + Se conecta a dos bases de datos por medio de las variables de entorno + :return: (tuple) Contiene los objetos sqlalchemy para ejecutar queries + """ + + conn_string = ('mysql+mysqlconnector://' + db_secret["username"] + ':' + db_secret["password"] + '@' + db_secret["host"] + ':' + str(db_secret["port"]) + '/' + db_schema) + sql_engine = create_engine(conn_string) + db_connection = sql_engine.connect() + return db_connection + + +def get_current_error_line(): + return str(sys.exc_info()[-1].tb_lineno) + + +def get_especific_error_line(): + _, _, exc_tb = sys.exc_info() + return str(traceback.extract_tb(exc_tb)[-1][1]) diff --git a/corporate_finances_back_py/orchestrator/decorators.py b/corporate_finances_back_py/orchestrator/decorators.py new file mode 100644 index 0000000..668c6ce --- /dev/null +++ b/corporate_finances_back_py/orchestrator/decorators.py @@ -0,0 +1,63 @@ +#version 2023 - 05 - 04 +import logging +import sys +import traceback +from functools import wraps +from time import time + +logger = logging.getLogger() +logger.setLevel(logging.DEBUG) + +def handler_wrapper(start, satisfactory_log, error_log, raise_error): + #esto se ejecuta en la inicializacion de primero + def decorator(func): + #print(message1) + #lo que yo ponga acá se ejecuta antes de hacer el llamado a la funcion + @wraps(func) + def wrapper(*args, **kwargs): + #esto sí se ejecuta solo cuando llama a la funcion decorada + #print(message2) + try: + logger.info(f'[{func.__name__}] {start}...') + resultado = func(*args, **kwargs) + logger.info(f'[{func.__name__}] {satisfactory_log}') + return resultado + except Exception as e: + logger.error(f"[{func.__name__}] {error_log}, linea: {get_especific_error_line(func.__name__)}, motivo: {str(e)}") + raise Exception(f"{raise_error}") + + return wrapper + return decorator + +def debugger_wrapper(error_log, raise_error): + def decorator(func): + @wraps(func) + def wrapper(*args, **kwargs): + try: + resultado = func(*args, **kwargs) + return resultado + except Exception as e: + logger.error(f"[{func.__name__}] {error_log}, linea: {get_especific_error_line(func.__name__)}, motivo: {str(e)}") + raise Exception(f"{raise_error}") + return wrapper + return decorator + + +def get_especific_error_line(func_name): + _, _, exc_tb = sys.exc_info() + for trace in traceback.extract_tb(exc_tb): + if func_name in trace: + return str(trace[1]) + +def timing(f): + @wraps(f) + def wrap(*args, **kw): + ts = time() + result = f(*args, **kw) + te = time() + taken_time_message = '[timing] La funcion {}, toma: {:.2f} sec en ejecutarse'.format(f.__name__, te-ts) + logger.info(taken_time_message) + return result + return wrap + + diff --git a/corporate_finances_back_py/orchestrator/lambda_function.py b/corporate_finances_back_py/orchestrator/lambda_function.py new file mode 100644 index 0000000..63b3769 --- /dev/null +++ b/corporate_finances_back_py/orchestrator/lambda_function.py @@ -0,0 +1,123 @@ +import json +import logging +import sys +import os +import datetime + +from decorators import handler_wrapper, timing, debugger_wrapper +from utils import get_secret, connect_to_db + + +#logging.basicConfig() #En lambdas borra este + +logger = logging.getLogger() +logger.setLevel(logging.DEBUG) + + +def lambda_handler(event, context): + sc_obj = script_object(event) + lambda_response = sc_obj.starter() + logger.info(f'respuesta final de lambda: \n{lambda_response}') + return lambda_response + + +class script_object: + def __init__(self, event): + try: + self.failed_init = False + self.final_response = {'headers':{'Access-Control-Allow-Headers': '*', + 'Access-Control-Allow-Origin': '*', + 'Access-Control-Allow-Methods': '*'}, "statusCode": 500} + self.db_connection = 0 + self.detailed_raise = '' + self.partial_response = {} + self.empty_good_response = False + + logger.warning(f'event de entrada: {str(event)}') + + self.company_table = os.environ['COMPANY_TABLE'] + self.archive_table = os.environ['ARCHIVE_TABLE'] + self.assessment_table = os.environ['ASSESSMENT_TABLE'] + self.assessment_steps_table = os.environ['ASSESSMENT_STEPS_TABLE'] + + event_dict = event['queryStringParameters'] + self.nit = event_dict['nit'] + self.current_short_date = event_dict['date'] + self.current_long_date = datetime.datetime.strptime(self.current_short_date, "%d-%m-%Y").strftime('%Y-%m-%d %H:%M:%S') + self.current_periodicity = event_dict['periodicity'] + self.user = event_dict['user'] + self.assessment_data = {} + + except Exception as e: + logger.error(f'[__init__] Error inicializando objeto lambda, linea: {get_current_error_line()}, motivo: {str(e)}') + self.failed_init = True + + def starter(self): + try: + if self.failed_init: + raise AttributeError('Error con los datos recibidos al servicio') + + self.create_conection_to_db() + self.get_assessment_data() + self.get_assessment_completed_steps() + + self.db_connection.close() + return self.response_maker(succesfull_run = True) + except Exception as e: + if self.db_connection: + self.db_connection.close() + logger.error(f'[starter] Hubieron problemas en el comando de la linea: {get_current_error_line()}') + return self.response_maker(succesfull_run = False, error_str = (str(e))) + + @handler_wrapper('Creando conexion a bd','Conexion a bd creada con exito','Error en la conexion a bd','Problemas creando la conexion a bd') + def create_conection_to_db(self): + db_schema = os.environ['DB_SCHEMA'] + secret_db_region = os.environ['SECRET_DB_REGION'] + secret_db_name = os.environ['SECRET_DB_NAME'] + db_secret = get_secret(secret_db_region, secret_db_name) + self.db_connection = connect_to_db(db_schema, db_secret) + + + @handler_wrapper('Obteniendo ID de proceso de valoracion','Id de proceso de valoracion obtenido exitosamente','Error al encontrar ID de proceso de valoracion','Se encontraron problemas relacionados con el ID del proceso de valoracion') + def get_assessment_data(self): + query = f"SELECT * FROM {self.company_table} A, {self.archive_table} B, {self.assessment_table} C WHERE A.ID = B.ID_COMPANY AND C.ID_ARCHIVE = B.ID AND A.NIT = \"{self.nit}\" AND B.INITIAL_DATE = \"{self.current_long_date}\" AND B.PERIODICITY = \"{self.current_periodicity}\" AND C.USER = \"{self.user}\"" + logger.info(f'[get_company_info] Query para obtener datos del proceso de valoracion: {query}') + rds_data = self.db_connection.execute(query) + try: + self.assessment_data = dict(rds_data.one()) + + except Exception as e: + self.empty_good_response = True + self.partial_response = {'data_to_get': [], 'id_assessment': 0} + logger.warning(f'[mira aca] {str(e)}') + self.detailed_raise = 'El proceso de valoracion no existe' + + + @handler_wrapper('Revisando los pasos que se han realizado para el proceso de valoracion', 'Pasos hallados correctamente', 'Error adquiriendo los pasos del proceso de valoracion','Error adquiriendo datos del proceso de valoracion') + def get_assessment_completed_steps(self): + query = f"SELECT SERVICE FROM {self.assessment_steps_table} WHERE ID_ASSESSMENT = {self.assessment_data['ID']}" + logger.info(f'[get_assessment_completed_steps] Query para obtener los pasos completados del proceso de valoracion: {query}') + rds_data = self.db_connection.execute(query) + self.found_steps = [item['SERVICE'] for item in rds_data.all()] + self.partial_response['data_to_get'] = self.found_steps + if self.found_steps: + self.partial_response['id_assessment'] = self.assessment_data['ID'] + + + @debugger_wrapper('Error construyendo respuesta final', 'Error construyendo respuesta') + def response_maker(self, succesfull_run = False, error_str = str()): + if self.empty_good_response: + self.empty_good_response = False + return self.response_maker(succesfull_run = True) + + if succesfull_run: + self.final_response['statusCode'] = 200 + self.final_response['body'] = json.dumps(self.partial_response) + return self.final_response + + self.final_response['body'] = json.dumps(self.detailed_raise if self.detailed_raise else error_str) + return self.final_response + + +def get_current_error_line(): + return str(sys.exc_info()[-1].tb_lineno) \ No newline at end of file diff --git a/corporate_finances_back_py/orchestrator/utils.py b/corporate_finances_back_py/orchestrator/utils.py new file mode 100644 index 0000000..5606c37 --- /dev/null +++ b/corporate_finances_back_py/orchestrator/utils.py @@ -0,0 +1,35 @@ +#version 2023 - 05 - 04 +import base64 +import boto3 +import json +import logging + +from sqlalchemy import create_engine + +from decorators import handler_wrapper, debugger_wrapper + +logger = logging.getLogger() +logger.setLevel(logging.DEBUG) + + +@debugger_wrapper('Error al obtener secreto','Error fatal de back conectando a base de datos') +def get_secret(secret_region, secret_name): + session = boto3.session.Session() + client_secrets_manager = session.client(service_name='secretsmanager', region_name=secret_region) + logger.info(f'[buscando el secreto]{secret_name}') + secret_data = client_secrets_manager.get_secret_value(SecretId=secret_name) + logger.info(f'[valor del secreto obtenido]') + if 'SecretString' in secret_data: + secret_str = secret_data['SecretString'] + else: + secret_str = base64.b64decode(secret_data['SecretBinary']) + logger.info('[utils] (get_secret) Se obtuvo el secreto') + return json.loads(secret_str) + + +@debugger_wrapper('Error en la conexion a base de datos','Error fatal de back conectando a base de datos') +def connect_to_db(db_schema, db_secret): + conn_string = ('mysql+mysqlconnector://' + db_secret["username"] + ':' + db_secret["password"] + '@' + db_secret["host"] + ':' + str(db_secret["port"]) + '/' + db_schema) + sql_engine = create_engine(conn_string) + db_connection = sql_engine.connect() + return db_connection \ No newline at end of file diff --git a/corporate_finances_back_py/puc-checks/decorators.py b/corporate_finances_back_py/puc-checks/decorators.py new file mode 100644 index 0000000..1aba58c --- /dev/null +++ b/corporate_finances_back_py/puc-checks/decorators.py @@ -0,0 +1,47 @@ +#version 2022 - 12 - 06 +import logging +import sys +import traceback +from functools import wraps +from time import time + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + +def handler_wrapper(start, satisfactory_log, error_log, raise_error): + #esto se ejecuta en la inicializacion de primero + def decorator(func): + #print(message1) + #lo que yo ponga acá se ejecuta antes de hacer el llamado a la funcion + def wrapper(*args, **kwargs): + #esto sí se ejecuta solo cuando llama a la funcion decorada + #print(message2) + try: + logger.info(f'[{func.__name__}] {start}...') + resultado = func(*args, **kwargs) + logger.info(f'[{func.__name__}] {satisfactory_log}') + return resultado + except Exception as e: + logger.error(f"[{func.__name__}] {error_log}, linea: {get_especific_error_line(func.__name__)}, motivo: {str(e)}") + raise Exception(f"{raise_error}") + + return wrapper + return decorator + + +def get_especific_error_line(func_name): + _, _, exc_tb = sys.exc_info() + for trace in traceback.extract_tb(exc_tb): + if func_name in trace: + return str(trace[1]) + +def timing(f): + @wraps(f) + def wrap(*args, **kw): + ts = time() + result = f(*args, **kw) + te = time() + taken_time_message = '[timing] La funcion {}, toma: {:.2f} sec en ejecutarse'.format(f.__name__, te-ts) + logger.info(taken_time_message) + return result + return wrap diff --git a/corporate_finances_back_py/puc-checks/lambda_function.py b/corporate_finances_back_py/puc-checks/lambda_function.py new file mode 100644 index 0000000..f00e970 --- /dev/null +++ b/corporate_finances_back_py/puc-checks/lambda_function.py @@ -0,0 +1,273 @@ +""": +capas: +capa-pandas-data-transfer + +variables de entorno +ARCHIVES_TABLE : ARCHIVE +COMPANIES_TABLE : COMPANY +DB_SCHEMA : src_corporate_finance +PUCS_TABLE : ORIGINAL_PUC +SECRET_DB_NAME : precia/rds8/sources/finanzas_corporativas +SECRET_DB_REGION : us-east-1 + +RAM: 1024 +""" + +import json +import logging +import sys +import datetime + +import pandas as pd +import numpy as np +import os +from decorators import handler_wrapper, timing +from utils import * + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + + +def lambda_handler(event, context): + logger.info(f'[lambda_handler] event de entrada:\n{event}') + sc_obj = script_object(event) + return sc_obj.starter() + +class script_object(): + + def __init__(self, event) -> None: + try: + logger.info('[__INIT__] Inicializando Lambda ...') + + self.companies_table = os.environ['COMPANIES_TABLE'] + self.archives_table = os.environ['ARCHIVES_TABLE'] + self.puc_table = os.environ['PUCS_TABLE'] + + event_body_dict = json.loads(event["body"]) + self.nit = event_body_dict["nit"] + self.initial_date_short = event_body_dict["date"] + self.initial_date_long = datetime.datetime.strptime(self.initial_date_short, "%d-%m-%Y").strftime('%Y-%m-%d %H:%M:%S') + self.periodicity = event_body_dict['periodicity'] + + self.db_connection = 0 + + self.company_info = dict() + self.archive_info = dict() + + self.raw_puc_df = pd.core.frame.DataFrame() + self.df_ready = pd.core.frame.DataFrame() + + self.results_response = {} + + self.failed_init = False + self.final_response = {'headers':{'Access-Control-Allow-Headers': '*', 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Methods': '*'}} + logger.info('[__INIT__] Lambda inicializada exitosamente') + + except Exception as e: + self.failed_init = True + logger.error(f"[__INIT__] error en inicializacion, motivo: " + str(e)) + + + def starter(self): + try: + if self.failed_init: + raise AttributeError('Falla inicializacion, revisar logs') + + self.create_db_conection() + self.get_company_info() + self.get_archive_info() + self.get_puc_data() + self.setting_up_df() + self.master_checker() + + return self.response_maker(succesfull = True) + except Exception as e: + logger.error(f'[starter] Falla en el objeto lambda, linea: {get_error_line()}, \nmotivo: {str(e)}') + return self.response_maker(succesfull = False, exception_str = str(e)) + + + @handler_wrapper('Creando conexion a base de datos','Conexion a base de datos creada con exito','Error creando conexion a base de datos','Problemas al conectarse a bse de datos') + def create_db_conection(self): + db_schema = os.environ['DB_SCHEMA'] + secret_db_region = os.environ['SECRET_DB_REGION'] + secret_db_name = os.environ['SECRET_DB_NAME'] + db_secret = get_secret(secret_db_region, secret_db_name) + self.db_connection = connect_to_db(db_schema, db_secret) + #self.db_connection = connect_to_db_local_dev() + + + @handler_wrapper('Buscando informacion del nit recibido','La información de la empresa fue encontrada','Error en la busqueda de los datos de la empresa','Error, problemas localizando la informacion de la empresa') + def get_company_info(self): + query = f"SELECT * FROM {self.companies_table} WHERE NIT=\"{self.nit}\" LIMIT 1" + logger.info(f'[get_company_info] query para obtener la informacion de la empresa: {query}') + rds_data = self.db_connection.execute(query) + self.company_info = dict(rds_data.mappings().all()[0]) + + + @handler_wrapper('Buscando información del archive solicitado','Información encontrada con exito', 'Error buscando información del archive', 'Error fatal, no se encontró la información solicitada') + def get_archive_info(self): + query = f"SELECT * FROM {self.archives_table} WHERE ID_COMPANY={self.company_info['ID']} AND INITIAL_DATE = \"{self.initial_date_long}\" AND PERIODICITY=\"{self.periodicity}\" LIMIT 1" + logger.info(f"[get_archive_info] Query a base de datos {query}") + rds_data = self.db_connection.execute(query) + self.archive_info = dict(rds_data.mappings().all()[0]) + + + @handler_wrapper('Obteniendo la informacion chequeada del puc','Informacion de puc encontrada', 'Error al hacer query de los datos chequeados','Error al buscar los datos de puc') + def get_puc_data(self): + query = f"SELECT ACCOUNT_NUMBER, ORIGINAL_BALANCE, CHECKED_BALANCE, ACCOUNT_NAME, CREATED_DATA FROM {self.puc_table} WHERE ID_ARCHIVE = {self.archive_info['ID']} ORDER BY ACCOUNT_NUMBER" + logger.info(f"[get_checked_data_info] Query a base de datos {query}") + self.raw_puc_df = pd.read_sql(query, self.db_connection); + + + @handler_wrapper('Cambiando tipos de datos de dataframe','Dataframe listo para chequeos','Error al alistar Dataframe','Error fatal, comuniquese con Tecnologia') + def setting_up_df(self): + logger.info(f'[setting_up_df] columnas que llegan a alistamiento: {self.raw_puc_df.columns}') + self.raw_puc_df.rename(columns={'ACCOUNT_NUMBER': 'account', 'ACCOUNT_NAME': 'name', 'ORIGINAL_BALANCE':"balance"}, inplace=True) + self.df_ready = self.raw_puc_df.astype({"account": "string", "name": "string", "balance": "float"}, copy=True) + + + @handler_wrapper('Iniciando master_checker','Master checker terminado con exito','Error realizando chequeos','Error realizando chequeos de puc') + def master_checker(self): + self.revert_negative_chapters() + self.level_asign() + self.subchapter_check('first') + self.created_accounts() + self.subchapter_check('final') + self.finance_math() + self.finantial_equation_balancer() + + self.results_response["data"] = self.df_ready.to_json(index=False, orient="table") + + + @handler_wrapper('Empezando chequeo de capitulos negativos','Chequeo de capitulos negativos terminado correctamente','Error durante el chequeo de capitulos negativos','Error durante el chequeo de capitulos negativos') + def revert_negative_chapters(self): + account_groups = ["2", "3", "4", "6"] + report_message = [] + for group in account_groups: + try: + group_value = self.df_ready.loc[self.df_ready["account"] == group]["balance"].values[0] + except Exception: + continue + if group_value < 0: + report_message.append(f"Se ha realizado un cambio de signo en la cuenta {group} y sus subcuentas") + + self.results_response["NegativeAccountInfo"] = report_message + + + @handler_wrapper('Asignando niveles a dataframe','Niveles asignados a dataframe','Error al asignar niveles a dataframe','Error al procesor los datos a chequear') + def level_asign(self): + if 'nivel' not in self.df_ready.columns: + self.df_ready["checked"] = False + self.df_ready['nivel'] = self.df_ready['account'].str.len() + + + @handler_wrapper('Iniciando primer chequeo de subcapitulos','terminado primer chequeo de subcuentas','','') + def subchapter_check(self, context): + niveles = list(self.df_ready["nivel"].unique()) + niveles = sorted(niveles, reverse=True) + balance_directory = {'first':'balance', 'final':'CHECKED_BALANCE'} + balance_to_use = balance_directory[context] + + for nivel in niveles[1:]: + #logger.info("Revisando las cuentas de nivel: "+str(nivel)) + level_accounts = self.df_ready.loc[self.df_ready["nivel"] == nivel, 'account'].tolist() + for upper_cat in level_accounts: + + lower_cat_df = self.df_ready.loc[(self.df_ready["nivel"] > nivel) & + (self.df_ready["account"].str.startswith(upper_cat)) & + (self.df_ready["checked"] == False)] + + if lower_cat_df.empty: + continue + + lower_cat_df = lower_cat_df.loc[lower_cat_df['nivel'] == lower_cat_df['nivel'].min()] + + upper_cat_value = self.df_ready.loc[self.df_ready["account"] == upper_cat, balance_to_use].values[0] + lower_cat_sum = lower_cat_df[balance_to_use].sum() + + self.df_ready.loc[self.df_ready['account'].isin(lower_cat_df.account), 'checked'] = checker(upper_cat_value, lower_cat_sum) + + if nivel == 1: + self.df_ready.loc[self.df_ready['nivel'] == 1, 'checked'] = True + + result_directory = {'first':'SubChapterCheckInfo', 'final':'AfterLoopFailedAccounts'} + + self.results_response[result_directory[context]] = self.df_ready.loc[self.df_ready["checked"] == False, ["account","name","balance"]].to_json(index=False, orient="table") + + + @handler_wrapper('Buscando las cuentas que hayan sido creadas','Busqueda terminada y asignada a resultados','Error buscando las cuentas creadas para chequeo de sub cuentas','Error revisando chequeo de subcuentas') + def created_accounts(self): + self.results_response['NewAccountsInfo'] = self.df_ready.loc[self.df_ready['CREATED_DATA'] == 1, ["account","name","balance"]].to_json(index=False, orient="table") + + + @handler_wrapper('Empezando chequeo de finanzas','Chequeo de finanzas terminado con exito','Error durante el chequeo de finanzas','Error durante el chequeo de finanzas') + def finance_math(self): + + logger.warning(f'[finance_math] dataframe entrando a chequeo de finanzas: {self.df_ready.head(3).to_string()}') + """ + activos = self.df_ready.loc[self.df_ready["account"] == "1", "balance"].values[0] + pasivos = self.df_ready.loc[self.df_ready["account"] == "2", "balance"].values[0] + patrimonio = self.df_ready.loc[self.df_ready["account"] == "3", "balance"].values[0] + ingresos = self.df_ready.loc[self.df_ready["account"] == "4", "balance"].values[0] + gastos = self.df_ready.loc[self.df_ready["account"] == "5", "balance"].values[0] + """ + self.activos, self.pasivos, self.patrimonio, self.ingresos, self.gastos = self.df_ready.loc[ + (self.df_ready["account"] == "1") | + (self.df_ready["account"] == "2") | + (self.df_ready["account"] == "3") | + (self.df_ready["account"] == "4") | + (self.df_ready["account"] == "5") , "CHECKED_BALANCE"].values.tolist() + + try: + ganancias_perdidas = self.df_ready.loc[self.df_ready["account"] == "59", "CHECKED_BALANCE"].values[0] + except Exception: + ganancias_perdidas = 0 + + logger.info(f'las propiedades son: \n Activos {self.activos}, \n Pasivos {self.pasivos}, \n Patrimonio {self.patrimonio}, \n Ingresos {self.ingresos}, \n Gastos {self.gastos}') + check_finance_list = [] + check_finance_list.append(checker(self.activos, self.pasivos + self.patrimonio)) + check_finance_list.append(checker(self.activos, self.pasivos + self.patrimonio + self.ingresos - self.gastos)) + check_finance_list.append(checker(self.activos, self.pasivos + self.patrimonio + self.ingresos - self.gastos + ganancias_perdidas)) + logger.info(f'[finance_math] Resultados financieros: {str(check_finance_list)}') + self.results_response['FinanceResult'] = [int(item) for item in check_finance_list] + + + @handler_wrapper('Revisando igualdad de ecuacion financiera','Ecuacion financiera analizada','Error al analizar la ecuacion financiera','Error al incorporar la ecuacion financiera') + def finantial_equation_balancer(self): + delta_value = self.ingresos - self.gastos + d_temp = {'activos': self.activos, 'pasivos':self.pasivos, 'patrimonio':self.patrimonio, 'ingresos':self.ingresos, 'gastos':self.gastos,'delta_value' : delta_value} + + for key, value in d_temp.items(): + value = "{0:,.2f}".format(value) + value = value.replace('.','/') + value = value.replace(',','.') + d_temp[key] = value.replace('/',',') + + if self.results_response['FinanceResult'][0]: + self.results_response['EquationBalancer'] = f"La ecuacion financiera primaria no requirió modificacion o creacion de datos: [] Activo: {d_temp['activos']} [] Pasivo: {d_temp['pasivos']} [] Patrimonio: {d_temp['patrimonio']}" + logger.warning(f"respuesta de balanceador: \n {self.results_response['EquationBalancer']}") + return + + account_to_modify_directory = {'Real':'36','Financiero':'39'} + account_to_modify = account_to_modify_directory[self.company_info['SECTOR']] + + if not self.df_ready.loc[self.df_ready['name'].str.startswith('[MODIFICADO POR ECUACION FINANCIERA] ')].empty: + self.results_response['EquationBalancer'] = f"La ecuacion financiera primaria no estaba balanceada, se tuvo que modificar la cuenta {account_to_modify} por un valor de {d_temp['delta_value']} [] Ingresos: {d_temp['ingresos']} [] Gastos: {d_temp['gastos']}" + else: + self.results_response['EquationBalancer'] = f"La ecuacion financiera primaria no estaba balanceada, se tuvo que crear la cuenta {account_to_modify} por un valor de {d_temp['delta_value']} [] Ingresos: {d_temp['ingresos']} [] Gastos: {d_temp['gastos']}" + logger.warning(f"respuesta de balanceador: \n {self.results_response['EquationBalancer']}") + + def response_maker(self, succesfull = False, exception_str = str()): + if not succesfull: + self.final_response['body'] = json.dumps(exception_str) + return self.final_response + self.final_response['body'] = json.dumps(self.results_response) + return self.final_response + + +def checker(a, b): + return np.isclose(a, b, atol=0.1, rtol=0.001) #DIFERENCIA RELATIVA PERMITIDA + + +def get_error_line(): + return str(sys.exc_info()[-1].tb_lineno) diff --git a/corporate_finances_back_py/puc-checks/utils.py b/corporate_finances_back_py/puc-checks/utils.py new file mode 100644 index 0000000..b4f81fa --- /dev/null +++ b/corporate_finances_back_py/puc-checks/utils.py @@ -0,0 +1,72 @@ +import base64 +import boto3 +import json +import logging +import os +import sys +import traceback + +from sqlalchemy import create_engine + +from decorators import handler_wrapper + + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + + +@handler_wrapper('Obteniendo secreto','secreto obtenido','Error al obtener secreto','error fatal de back') +def get_secret(secret_region, secret_name): + """ + Obtiene las credenciales que vienen del Secret Manager + :param secret_region: (string) Nombre de la region donde se encuentran las credenciales + :param secrete_name: (string) Nombre del secreto + :return: (dict) Diccionario con las credenciales + """ + logger.info('A') + session = boto3.session.Session() + logger.info('B') + client_secrets_manager = session.client(service_name='secretsmanager', region_name=secret_region) + logger.info('C') + secret_data = client_secrets_manager.get_secret_value(SecretId=secret_name) + logger.info('Procesando secreto') + if 'SecretString' in secret_data: + secret_str = secret_data['SecretString'] + else: + secret_str = base64.b64decode(secret_data['SecretBinary']) + logger.info('[utils] (get_secret) Se obtuvo el secreto') + logger.info('secreto procesado') + return json.loads(secret_str) + + +@handler_wrapper('Conectando a base de datos','Conectado correctamente a base de datos','Error en la conexion a base de datos','error fatal de back') +def connect_to_db(db_schema, db_secret): + """ + Se conecta a dos bases de datos por medio de las variables de entorno + :return: (tuple) Contiene los objetos sqlalchemy para ejecutar queries + """ + + conn_string = ('mysql+mysqlconnector://' + db_secret["username"] + ':' + db_secret["password"] + '@' + db_secret["host"] + ':' + str(db_secret["port"]) + '/' + db_schema) + sql_engine = create_engine(conn_string) + db_connection = sql_engine.connect() + return db_connection + + +def get_current_error_line(): + return str(sys.exc_info()[-1].tb_lineno) + + +def get_especific_error_line(): + _, _, exc_tb = sys.exc_info() + return str(traceback.extract_tb(exc_tb)[-1][1]) + + +@handler_wrapper('Conectando a rds','conectado a rds', 'Error en la conexion a base de datos','Error fatal de back conectando a base de datos') +def connect_to_db_local_dev(): + conn_string = "mysql+mysqlconnector://fincororchest_dev:KiqE7h57Y1x7@aurora-dev-sources-8-instance-1.cwejzmqeyiuq.us-east-1.rds.amazonaws.com:3306/src_corporate_finance" + #{"host":"aurora-dev-sources-8-instance-1.cwejzmqeyiuq.us-east-1.rds.amazonaws.com","password":"KiqE7h57Y1x7","port":"3306","username":"fincororchest_dev"} + + sql_engine = create_engine(conn_string) + db_connection = sql_engine.connect() + return db_connection + \ No newline at end of file diff --git a/corporate_finances_back_py/puc-columns-name/decorators.py b/corporate_finances_back_py/puc-columns-name/decorators.py new file mode 100644 index 0000000..1aba58c --- /dev/null +++ b/corporate_finances_back_py/puc-columns-name/decorators.py @@ -0,0 +1,47 @@ +#version 2022 - 12 - 06 +import logging +import sys +import traceback +from functools import wraps +from time import time + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + +def handler_wrapper(start, satisfactory_log, error_log, raise_error): + #esto se ejecuta en la inicializacion de primero + def decorator(func): + #print(message1) + #lo que yo ponga acá se ejecuta antes de hacer el llamado a la funcion + def wrapper(*args, **kwargs): + #esto sí se ejecuta solo cuando llama a la funcion decorada + #print(message2) + try: + logger.info(f'[{func.__name__}] {start}...') + resultado = func(*args, **kwargs) + logger.info(f'[{func.__name__}] {satisfactory_log}') + return resultado + except Exception as e: + logger.error(f"[{func.__name__}] {error_log}, linea: {get_especific_error_line(func.__name__)}, motivo: {str(e)}") + raise Exception(f"{raise_error}") + + return wrapper + return decorator + + +def get_especific_error_line(func_name): + _, _, exc_tb = sys.exc_info() + for trace in traceback.extract_tb(exc_tb): + if func_name in trace: + return str(trace[1]) + +def timing(f): + @wraps(f) + def wrap(*args, **kw): + ts = time() + result = f(*args, **kw) + te = time() + taken_time_message = '[timing] La funcion {}, toma: {:.2f} sec en ejecutarse'.format(f.__name__, te-ts) + logger.info(taken_time_message) + return result + return wrap diff --git a/corporate_finances_back_py/puc-columns-name/lambda_function.py b/corporate_finances_back_py/puc-columns-name/lambda_function.py new file mode 100644 index 0000000..9cc8a6b --- /dev/null +++ b/corporate_finances_back_py/puc-columns-name/lambda_function.py @@ -0,0 +1,364 @@ +""": +============================================================= + +Nombre: lbd-dev-layer-fincor-puc-columns-name-get +Tipo: Lambda AWS +Autor: Jeisson David Botache Yela +Tecnología - Precia + +Ultima modificación: 11/07/2022 + +Para el proyecto Delta de finanzas corporativas se construyó estra lambda para +reducir las manualidades que el analista debe realizar. La lambda se activa por +medio de apigateway y lo que hace es buscar la version json del excel que el +analista haya cargado a s3 (lbd_dev_fincorp_etl_pucs es la encargada de convertir +el excel a json) y recorrerlo sin modificarlo en busqueda de las cuentas 1 y 11 +(100000 y 110000 en caso de puc de super) para así encontrar en qué columna y fila +empieza la información de puc. +Si el json del excel no existe aún en s3, esta lambda esperará en intervalos de +un segundo para buscarla nuevamente. Dependiendo del timeout restante decidirá que +retornará un except personalizado. + +Requerimientos: +capas: +capa-pandas-data-transfer v.02 + +variables de entorno: +BUCKET_NAME : s3-dev-datalake-sources +PUC_BUCKET_PATH : corporate_finances/pucs/client/ + +RAM: 1024 MB +============================================================= +""" +import boto3 +import json +import logging +import sys +import time + +import pandas as pd +from utils import * + +logger = logging.getLogger() +logger.setLevel(logging.INFO) +failed_init = False + +try: + logger.info('[__INIT__] Inicializando Lambda ...') + bucket_name = os.environ['BUCKET_NAME'] + puc_bucket_path = os.environ['PUC_BUCKET_PATH'] + s3_client = boto3.client('s3') + logger.info('[__INIT__] Lambda inicializada exitosamente') + +except Exception as e: + failed_init = True + logger.error(f"[__INIT__] error en inicializacion, motivo: "+str(e)) + + +def lambda_handler(event, context): + """: + Funcion lambda_handler que se activa automaticamente. La función llama los demás metodos de la lambda + que contienen la logica necesaria para obtener los resultados. Si en el procedimiento hay errores + se dispara un raise que ejecuta una respuesta base que debería servir para encontrar la ubicacion + del error. + :param event: Se puede interpretar como variables base que activan la lambda + :param context: contiene informacion relevante al ambiente de la lambda, raramente se usa + :returns: La funcion debe devolver un objeto con los encabezados y el body en la estructura esperada; + """ + if failed_init: + return {'statusCode': 500,'body': json.dumps('Error al inicializar lambda')} + + try: + filename = process_event(event) + download_file(bucket_name, puc_bucket_path, filename, context) + df_full_excel = read_json(filename) + headers_row, account_column = find_columns_master(df_full_excel) + preview = preview_maker(df_full_excel, headers_row) + columns_headers_dict = columns_headers_maker(df_full_excel,headers_row) + return response_maker(columns_headers_dict, headers_row, account_column, preview, succesfull = True) + + except Exception as e: + error_line_int = get_error_line() + return response_maker({},0,0,[],succesfull = False, exception = str(e), error_line = error_line_int) + + +def process_event(event): + """: + Funcion que toma el event que disparó la lambda en busqueda del filename envíado por el front. + En la transformación del filename se debe anotar: los espacios vacíos del filename se convierten + en '%20', se debe reemplazar; algunos archivos pueden tener varios puntos en el nombre, por lo + tanto se debe hacer un split por puntos para eliminar el ultimo y eliminar la extenxión del archivo. + Se vuelven a unir las partes separadas con puntos y se agrega la extensión json + :param event: Se puede interpretar como variables base que activan la lambda + :returns: La funcion debe devolver el filename necesario para la descarga + """ + try: + logger.info(str(event)) + logger.info('[process_event] Obteniendo valores clave de event') + filename = event["pathParameters"]["filename"] + filename = '.'.join(filename.replace('%20',' ').split('.')[:-1]) + '.json' + logger.info('[process_event] Valores de event obtenidos correctamente') + return filename + except Exception as e: + logger.error(f"[process_event] Error al obtener valores clave de event, linea: {get_error_line()}, motivo: "+str(e)) + raise AttributeError('Fallo en la obtencion de valores clave de event') + + +def download_file(bucket_name, puc_bucket_path, filename, context): + """: + Funcion que toma el filename para descargar el archivo de mismo nombre al /tmp del lambda; + importante: una lambda automatica lee el archivo que se sube a s3 y hace una copia a json. + esta copia puede tardar entre 7 y 13 segundos, por lo tanto, esta lambda debe buscarlo por + un tiempo determinado, si no lo encuentra se debe evitar el timeout entregando una respuesta + tres segundos antes de que ocurra + :bucket_name: variable de entorno indicando el bucket donde se encuentra el archivo + :puc_bucket_path: variable de entorno indicando el key path donde se encuentra el archivo + :filename: nombre del archivo a buscar + :context: variable de entorno indicando el bucket donde se encuentra el archivo + :returns: La funcion no regresa nada, es un void que sólo descarga el archivo, pero es inevitable + tener un return ya que el while debe decidir cuando escapar por timeout. deben haber otras formas + de hacer esto pero esta me pareció la más diciente + """ + try: + logger.info(f'[download_file] Descargando archivo: bucket {bucket_name}, key {puc_bucket_path}, filename {filename}') + remaining_time = context.get_remaining_time_in_millis() + got_response = False + while not got_response and remaining_time>3000: + remaining_time = context.get_remaining_time_in_millis() + response = s3_client.list_objects_v2(Bucket=bucket_name,Prefix=puc_bucket_path+filename) + try: + a = response['Contents'] + s3_client.download_file(bucket_name, puc_bucket_path+filename,'/tmp/'+filename) + logger.info(f'[download_file] Descarga exitosa.') + return + + except Exception as e: + logger.info("[download_file] Archivo no encontrado, esperando...") + time.sleep(1) + logger.info("[download_file] Buscando nuevamente...") + logger.error(f"[download_file] El archivo no se encontró y el lambda se irá a timeout con remaining_time= {remaining_time} milisegundos") + raise AttributeError (f"[download_file] Se evita timeout por ausencia de {filename}") + except Exception as e: + raise AttributeError(f"[download_file] Error fatal al realizar la descarga del archivo {filename}") + + +def read_json(filename): + """: + Funcion que toma el filename para hacer la lectura del archivo json descargado como DataFrame, para mejorar + algunas funciones y el dibujado en el front se cambian los espacios vacios del excel a string vacío + :filename: nombre del archivo a buscar + :returns: La funcion regresa el dataframe del json. ya que el excel no sufrió cambios al + reformatearse a json lo nombro df_full_excel + """ + try: + logger.info(f'[read_json]Leyendo archivo {filename} a dataframe...') + df_full_excel = pd.read_json('/tmp/'+filename, orient="table") + df_full_excel.fillna('', inplace=True) + logger.info(f'[read_json] {filename} convertido a dataframe excitosamente') + return df_full_excel + except Exception as e: + logger.info(f"[read_json] Error al crear dataframe desde el archivo json {filename}, linea: {get_error_line()}, motivo: {str(e)}") + raise AttributeError(f"[read_json] Error fatal al realizar la lectura del archivo {filename} a dataframe") + + +def find_columns_master(df_full_excel): + """: + Funcion que toma el dataFrame del excel completo y lo inyecta en la funcion find_columns + junto a los parametros que desea buscar, en un puc normal se deben buscar los parametros + '1' y '11', en un puc de superfinanciera se deben buscar los parametros '100000' y + '110000'. En caso de que el puc no sea default o super se levanta una excepcion que destruye + la lambda avisando que no se encontró la informacion requerida. Esto se podría manejar + de forma diferente si en el front se tuviera una pantalla para escoger manualmente las + columnas y el row donde empieza el puc + :df_full_excel: DataFrame con la informacion del excel completa + :returns: La funcion regresa el row donde empieza el puc y la columna donde se encontraron + los codigos cuentas + """ + + try: + logger.warning(f'[mirar aca] \n{df_full_excel.head(5).to_string()}') + logger.info('[find_columns_master] Buscando cuentas 1 y 11...') + headers_row, account_column = find_columns(df_full_excel,['1','11']) + logger.info('[find_columns_master] Se encontraron las propiedades como puc default') + return headers_row, account_column + except Exception as e: + logger.warning('[find_columns_master] Error en la busqueda de cuentas default') + + try: + logger.info('[find_columns_master] Buscando cuentas 100000 y 110000...') + headers_row, account_column = find_columns(df_full_excel, ['100000','110000']) + logger.info('[find_columns_master] Se encontraron las propiedades como puc de superfinanciera') + return headers_row, account_column + except Exception as e: + logger.error('[find_columns_master] Error en la busqueda de cuentas superfinanciera') + raise AttributeError('[find_columns_master] No se encontraron las cuentas de interes, revisar puc') + + + +def find_columns(df_full_excel, search_values): + """: + La funcion find_columns toma el dataFrame de un excel completo y lo recorre columna a columna en + busqueda de las search_values, en caso de encontrarlos, se pregunta si la distancia entre estos + es solo una posicion, es decir si los search_values están uno tras otro. una vez encontrados se + devuelve a find_columns_master la columna y la fila donde se encontraron. En los PUCs que se + conceptualizaron para el desarrollo del proyecto se tomó en cuenta esta asunción. La plataforma + tiene entonces la limitación de que el puc debe poseer las cuentas '1' y '11' o las de superfinanciera + :df_full_excel: DataFrame con la informacion del excel completa + :search_values: Listado con las cuentas a buscar + :returns: La funcion regresa el row donde empieza el puc y la columna donde se encontraron + los codigos cuentas, en caso de no encontrarse devuelve una excepción que manejará find_columns_master + """ + try: + for column in df_full_excel.columns: + logger.warning(f'[mirar aca] {column}') + columnListing = df_full_excel[column].iloc[:].astype(str).str.strip().values.tolist() + #En caso de debug colocar acá un log de qué hay en column y qué hay en column listing + #logger.info(f'[find_columns] Buscando los datos {str(search_values)} en la columna {column} con data: {str(columnListing)} ') + if search_values[0] in columnListing and search_values[1] in columnListing: + index1 = columnListing.index(search_values[0]) + index11 = columnListing.index(search_values[1]) + if index11 - index1 == 1: + found_row = True + headers_row = index1 + account_column = column + return headers_row , account_column + + raise AttributeError(f'[find_columns] No se encontraron las cuentas {str(search_values)}') + except Exception as e: + logger.error(f'[find_columns] Error interno al buscar las columnas de puc, linea: {get_error_line()}, motivo: {str(e)}') + raise AttributeError('[find_columns] Error al buscar valores clave para encontrar columna de cuentas') + + +def preview_maker(df_full_excel, headers_row): + """: + Funcion que toma el dataFrame del excel completo y lo recorre fila a fila para generar un array de lineas json + para enviarle al front una preview de las lineas superiores del puc. Se hizo de esta manera ya que lso PUCs no + tienen una forma universal, y por lo tanto no se sabe cuantas columnas debera recibir y dibujar el front. + Tambien se probó la idea de envíar un array de arrays de pero al convertirlos a json dejaban de ser legibles + para Angular. Al cambiar rows_to_display puedes cambiar la cantidad de filas a llevar al front + :df_full_excel: DataFrame con la informacion del excel completa + :headers_row: numero de fila donde se encontró que empieza el puc + :returns: La funcion regresa un array de jsons con la cantidad de filas deseadas y a partir de donde empieza + la informacion relevante del puc + """ + try: + logger.info(f'[preview_maker] Construccion de preview...') + rows_to_display = 20 + df_full_excel = df_full_excel.reset_index(drop = True) + outerList = [] + + for _, row in df_full_excel[(headers_row-1):].head(rows_to_display).iterrows(): + innerList = row.astype(str).values.tolist() + outerList.append(json.dumps(innerList)) + return outerList + + except Exception as e: + logger.error(f'[preview_maker] Error al construir el preview, linea: {get_error_line()}, motivo: {str(e)}') + raise AttributeError('[preview_maker] Error al construir el preview') + + +def columns_headers_maker(df_full_excel, headers_row): + """: + Esta funcion crea un objeto clave valor con los valores de los encabezados (la linea inmediatamente arriba + de donde se encontró la cuenta '1' u '110000') y su index, ya que en algunos pucs hay encabezados con el mismo + nombre y por lo tanto la depuración debe hacerse por el numero de columna, no con su nombre. En la mayoría de + pucs las columnas como encabezados celdas vacías y era incomodo escogerlas para hacer la depuración. Para llenar + estas celdas se construye un array de columnas de excel: A,B..AA,AB,AC... para llenar estas celdas. este + algoritmo funciona tambien para darle nombre a los encabezado en el raro caso donde hay una fila vacia + entre la data del puc y los encabezados. + :df_full_excel: DataFrame con la informacion del excel completa + :headers_row: numero de fila donde se encontró que empieza el puc + :returns: La funcion regresa un objeto clave valor que representa la posicion y el valor del encabezado + """ + try: + logger.info(f'[columns_headers_maker] construyendo encabezados de puc...') + logger.info(f'[columns_headers_maker] creando listado de columnas excel...') + letters = list('ABCDEFGHIJKLMNOPQRSTUVWXYZ') # TODO: Puede existir que llegue hasta la columna AA o mayor? sí, esto es para generar AA, AB y así hasta ZZ pero ningun puc debería llegar hasta allá + letters_len = len(letters) + j = 0 + while len(letters) < len(df_full_excel.columns): + for i in range(letters_len): + letters.append(letters[j] + letters[i]) + j = j + 1 + logger.info(f'[columns_headers_maker] obtener los encabezados como listado...') + columns_headers_list = df_full_excel.iloc[headers_row-1].astype(str).values.flatten().tolist() + logger.info(f'[columns_headers_maker] reemplazando encabezados vacios...') + for i, val in enumerate(columns_headers_list): + if val == "": + columns_headers_list[i] = "Columna "+letters[i] + logger.info(f'[columns_headers_maker] creando diccionario index-columna...') + return dict(zip(range(len(columns_headers_list)),columns_headers_list)) + + except Exception as e: + logger.error(f'[columns_headers_maker] Error al construir los encabezados, linea: {get_error_line()}, motivo: {str(e)}') + raise AttributeError('[columns_headers_maker] Error al construir los encabezados') + + +def response_maker(columns_headers_dict, headers_row, account_column, preview, succesfull = True, exception = '', error_line = 0): + """: + Funcion que construye la respuesta general del lambda, para llegar se activa si todo salió bien en lambda handler + o si algo salió mal y se disparó el la excepcion general de esta. en el primer caso debo enviar aquí el contenido + de interés para el front: el clave valor de encabezados, la fila donde empieza la data del puc, la columna donde + se encontraron los codigos cuenta y el preview del excel. En caso de llegar a este metodo por medio de una excepcion + se trae un motivo de falla que no será mostrado al analista a menos que lo esté asesorando un desarrollador. + :columns_headers_dict: objeto clave valor de encabezados + :headers_row: numero de fila donde se encontró que empieza el puc + :account_column: numero de columna donde se encontraron los codigos cuenta + :preview: array de jsons de primeras filas del puc + :succesfull: determina si el metodo se está ejecutando como excepcion o como salida correcta + :exception: motivo de error + :error_line: linea de falla + :returns: la funcion regresa el objeto alistado que lambda handler rergesará al disparador. status_code dependiente + si hubieron errores y mensajes acordes o una respuesta positiva con los objetos que el front requiere. En cualquier + caso se deben agregar tambien los encabezados 'Acces-Control' para que api gateway no corte la comunicacion back-front + """ + if not succesfull: + try: + logger.warning(f'[response_maker] Creando respuesta de error..., error en la linea {error_line}, motivo: {exception}') + error_response = {'statusCode': 500, + 'headers': {'Access-Control-Allow-Headers': '*', + 'Access-Control-Allow-Origin': '*', + 'Access-Control-Allow-Methods': '*'}, + 'body' : json.dumps(f'error de ejecucion, motivo: {exception}')} # TODO: Esto es de valor para el front? sí jeje, al menos mientras salimos a prod + return error_response + except Exception as e: + logger.error(f'[response_maker] Error al construir la respuesta de error, linea: {get_error_line()}, motivo: {str(e)}') + return {'statusCode': 500, + 'headers': {'Access-Control-Allow-Headers': '*', + 'Access-Control-Allow-Origin': '*', + 'Access-Control-Allow-Methods': '*'}, + 'body' : json.dumps(f'[admin] error al crear respuesta')} + + try: + logger.info('[response_maker] creando respuesta ') + ok_response = {'statusCode': 200, + 'headers': {'Access-Control-Allow-Headers': '*', + 'Access-Control-Allow-Origin': '*', + 'Access-Control-Allow-Methods': '*'}} + + body = {'status_code':200} + body["columns"] = columns_headers_dict + body["row"] = headers_row + body["accounts"] = int(account_column) + body["file_preview"] = preview + + ok_response["body"] = json.dumps(body) + return ok_response + + except Exception as e: + logger.error(f'[response_maker] Error al construir la respuesta de aceptado, linea: {get_error_line}, motivo: {str(e)}') + return {'statusCode': 500, + 'headers': {'Access-Control-Allow-Headers': '*', + 'Access-Control-Allow-Origin': '*', + 'Access-Control-Allow-Methods': '*'}, + 'body' : json.dumps(f'[admin] error al crear respuesta')} + + +def get_error_line(): + """: + Funcion que busca la linea del ultimo error, en caso de usarse en cadena (como un except que recive el raise de + una funcion) se vuelve medianamente innecesario, ya que señalaría a la evocación de la función que falló, no a + la linea interna de la funcion que falló + :returns: La funcion regresa un string con la linea donde hubo la excepcion, sea por error o un raise + """ + return str(sys.exc_info()[-1].tb_lineno) \ No newline at end of file diff --git a/corporate_finances_back_py/puc-columns-name/utils.py b/corporate_finances_back_py/puc-columns-name/utils.py new file mode 100644 index 0000000..738f74f --- /dev/null +++ b/corporate_finances_back_py/puc-columns-name/utils.py @@ -0,0 +1,56 @@ +import base64 +import boto3 +import json +import logging +import os +import sys +import traceback + +from sqlalchemy import create_engine + +from decorators import handler_wrapper + + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + + +@handler_wrapper('Obteniendo secreto','secreto obtenido','Error al obtener secreto','error fatal de back') +def get_secret(secret_region, secret_name): + """ + Obtiene las credenciales que vienen del Secret Manager + :param secret_region: (string) Nombre de la region donde se encuentran las credenciales + :param secrete_name: (string) Nombre del secreto + :return: (dict) Diccionario con las credenciales + """ + session = boto3.session.Session() + client_secrets_manager = session.client(service_name='secretsmanager', region_name=secret_region) + secret_data = client_secrets_manager.get_secret_value(SecretId=secret_name) + if 'SecretString' in secret_data: + secret_str = secret_data['SecretString'] + else: + secret_str = base64.b64decode(secret_data['SecretBinary']) + logger.info('[utils] (get_secret) Se obtuvo el secreto') + return json.loads(secret_str) + + +@handler_wrapper('Conectando a base de datos {a}','Conectado correctamente a base de datos','Error en la conexion a base de datos','error fatal de back') +def connect_to_db(db_schema, db_secret): + """ + Se conecta a dos bases de datos por medio de las variables de entorno + :return: (tuple) Contiene los objetos sqlalchemy para ejecutar queries + """ + + conn_string = ('mysql+mysqlconnector://' + db_secret["username"] + ':' + db_secret["password"] + '@' + db_secret["host"] + ':' + str(db_secret["port"]) + '/' + db_schema) + sql_engine = create_engine(conn_string) + db_connection = sql_engine.connect() + return db_connection + + +def get_current_error_line(): + return str(sys.exc_info()[-1].tb_lineno) + + +def get_especific_error_line(): + _, _, exc_tb = sys.exc_info() + return str(traceback.extract_tb(exc_tb)[-1][1]) diff --git a/corporate_finances_back_py/pucs-to-json/lambda_function.py b/corporate_finances_back_py/pucs-to-json/lambda_function.py new file mode 100644 index 0000000..bdee7f0 --- /dev/null +++ b/corporate_finances_back_py/pucs-to-json/lambda_function.py @@ -0,0 +1,124 @@ +""": +============================================================= + +Nombre: lbd-dev-etl-fincor-pucs +Tipo: Lambda AWS +Autor: Jeisson David Botache Yela +Tecnología - Precia + +Ultima modificación: 07/07/2022 + +Para el proyecto delta de finanzas corporativas se implementa una etl que se activa cuando +se carga un archivo nuevo (.xls .xlsx) a la carpeta s3-dev-datalake-sources/corporate_finances/pucs/client/. +Este etl toma el archivo nuevo, lo lee con la librería pandas y devuelve archivo json con +la data aligerada a la carpeta original. Esto resuelve dos problemas: +la plataforma estaba tardando demasiado al hacer lectura del archivo excel multiples veces +El archivo json pesa mucho menos que el excel original +# TODO: incluir variables de entorno + +Requerimientos: +capas: +capa-precia-utils v.01 +capa-pandas-data-transfer v. +capa-openpyxl-s3fs-xlrd-fsspec v.01 + +Variables de entorno: +no utiliza, el nombre del bucket lo saca del event +============================================================= +""" + +import boto3 +from io import BytesIO +import json +import logging +import sys + +import pandas as pd + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + +failed_init = False +try: + logger.info('[__INIT__] Inicializando Lambda ...') + s3_client = boto3.client('s3') + +except Exception as e: + failed_init = True + logger.error(f"[__init__] error en inicializacion en la linea, motivo: {str(e)}") + +def lambda_handler(event, context): + logger.warning(f'event de entrada: {str(event)}') + if failed_init: + return {'statusCode': 500,'body': json.dumps('Error al inicializar lambda')} + + try: + bucket_name, key_path, tmp_file_path = process_event(event) + s3_get_file(bucket_name, key_path, tmp_file_path) + dataframe_from_excel = read_excel(tmp_file_path) + dataframe_from_excel = json_upload(dataframe_from_excel, bucket_name, key_path) + except Exception as e: + return {'statusCode': 500,'body': json.dumps('[lambda_handler] Error en la ejecucion '+ str(e))} + #TODO implement + return {'statusCode': 200,'body': json.dumps('Archivo de excel leido y copia en json exitosamente guardada')} # español + + +def process_event(event): + try: + logger.info("[process_event] localizacion de valores clave en event...") + bucket_name = event['Records'][0]['s3']['bucket']['name'] + key_path = event['Records'][0]['s3']['object']['key'] + key_path = key_path.replace('+',' ') # Los espacios vacios vienen de s3 como '+' + tmp_file_path = '/tmp/' + key_path.split('/')[-1] + logger.info(f'[process_event] Valores encontrados: Bucket_name: {bucket_name}, key_path: {key_path}, tmp_file_path: {tmp_file_path}') + return bucket_name, key_path, tmp_file_path + except Exception as e: + logger.error(f"[process_event] error en event_processor en la linea {get_error_line()}, motivo: "+str(e)) + raise TypeError("Fallo en la recoleccion de valores clave de event") + + +def s3_get_file(bucket_name, key_path, tmp_file_path): + try: + logger.info(f'[s3_get_file] Descargando archivo {key_path} desde s3...') + s3_client.download_file(bucket_name, key_path, tmp_file_path) + logger.info(f'[s3_get_file] Descarga exitosa.') + except Exception as e: + logger.error(f"[s3_get_file] error en s3_get_file en la linea {get_error_line()}, motivo: "+str(e)) + raise TypeError('Fallo la descarga del archivo ' + key_path + ' desde S3') + + +def read_excel(tmp_file_path): + try: + logger.info(f'[read_excel] Transformando el archivo {tmp_file_path[5:]} a dataframe...') + if tmp_file_path.endswith('xlsx'): + return pd.read_excel(tmp_file_path, header=None, engine='openpyxl') # TODO: hace la misma concardenacion en la linea 52 + elif tmp_file_path.endswith('xls'): + return pd.read_excel(tmp_file_path, header=None, engine='xlrd') + else: + logger.info('[read_excel] El archivo no era xls o xlsx') + raise TypeError(f'[read_excel] El archivo {tmp_file_path[5:]} no era xls o xlsx') + logger.info('[read_excel] Archivo excel transoformado a dataframe exitosamente.') + + except Exception as e: + logger.error(f"[read_excel] error reading excel to dataframe {get_error_line()}, motivo: "+str(e)) + raise TypeError('Fallo la transformacion archivo ' + tmp_file_path[5:] + ' a dataframe') + + +def json_upload(dataframe_from_excel, bucket_name, key_path): + try: + logger.info('[json_upload] Transformando dataframe a JSON ...') + dataframe_from_excel.columns = [str(item) for item in dataframe_from_excel.columns] + df_full_excel_json = dataframe_from_excel.to_json(index=False, orient="table") + df_json_bytes = BytesIO(bytes(df_full_excel_json,'UTF-8')) + logger.info('[json_upload] Dataframe transformado a JSON exitosamente,') + logger.info('[json_upload] Subiendo JSON a bucket S3...') + key_path = '.'.join(key_path.split('.')[:-1]) + s3_client.upload_fileobj(df_json_bytes, bucket_name, key_path+'.json') + logger.info('[json_upload] JSON subido al bucket S3 exitosamente.') + except Exception as e: + logger.error("[json_upload] Error al subir el json a s3 {get_error_line()}, motivo: "+str(e)) + raise TypeError('No se subio al bucket S3 la version JSON del archivo excel.') + + +def get_error_line(): + return str(sys.exc_info()[-1].tb_lineno) \ No newline at end of file diff --git a/corporate_finances_back_py/pyg-calculator/decorators.py b/corporate_finances_back_py/pyg-calculator/decorators.py new file mode 100644 index 0000000..071760a --- /dev/null +++ b/corporate_finances_back_py/pyg-calculator/decorators.py @@ -0,0 +1,63 @@ +#version 2023 - 05 - 04 +import logging +import sys +import traceback +from functools import wraps +from time import time + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + +def handler_wrapper(start, satisfactory_log, error_log, raise_error): + #esto se ejecuta en la inicializacion de primero + def decorator(func): + #print(message1) + #lo que yo ponga acá se ejecuta antes de hacer el llamado a la funcion + @wraps(func) + def wrapper(*args, **kwargs): + #esto sí se ejecuta solo cuando llama a la funcion decorada + #print(message2) + try: + logger.info(f'[{func.__name__}] {start}...') + resultado = func(*args, **kwargs) + logger.info(f'[{func.__name__}] {satisfactory_log}') + return resultado + except Exception as e: + logger.error(f"[{func.__name__}] {error_log}, linea: {get_especific_error_line(func.__name__)}, motivo: {str(e)}") + raise Exception(f"{raise_error}") + + return wrapper + return decorator + +def debugger_wrapper(error_log, raise_error): + def decorator(func): + @wraps(func) + def wrapper(*args, **kwargs): + try: + resultado = func(*args, **kwargs) + return resultado + except Exception as e: + logger.error(f"[{func.__name__}] {error_log}, linea: {get_especific_error_line(func.__name__)}, motivo: {str(e)}") + raise Exception(f"{raise_error}") + return wrapper + return decorator + + +def get_especific_error_line(func_name): + _, _, exc_tb = sys.exc_info() + for trace in traceback.extract_tb(exc_tb): + if func_name in trace: + return str(trace[1]) + +def timing(f): + @wraps(f) + def wrap(*args, **kw): + ts = time() + result = f(*args, **kw) + te = time() + taken_time_message = '[timing] La funcion {}, toma: {:.2f} sec en ejecutarse'.format(f.__name__, te-ts) + logger.info(taken_time_message) + return result + return wrap + + diff --git a/corporate_finances_back_py/pyg-calculator/lambda_function.py b/corporate_finances_back_py/pyg-calculator/lambda_function.py new file mode 100644 index 0000000..fd2592c --- /dev/null +++ b/corporate_finances_back_py/pyg-calculator/lambda_function.py @@ -0,0 +1,368 @@ + +import datetime +import json +import logging +import os +import sys +import sqlalchemy +import traceback +import copy +import pandas as pd + +from decorators import handler_wrapper, timing, debugger_wrapper +from utils import get_secret, connect_to_db, call_dynamic_engine +from vars import pyg_all_items, pyg_simple_calculations, pyg_partials, pyg_totals + +#logging.basicConfig() +logger = logging.getLogger() +logger.setLevel(logging.INFO) +######################################### +#######LAMBDA DEPRECIABLE################ +######################################### + +def lambda_handler(event, context): + sc_obj = script_object(event) + lambda_response = sc_obj.starter() + logger.info(f'respuesta final de lambda: \n{lambda_response}') + return lambda_response + + +class script_object(): + + @handler_wrapper('Obteniendo valores clave de event', 'Valores de event obtenidos correctamente', + 'Error al obtener valores event', 'Fallo en la obtencion de valores clave de event') + def __init__(self, event) -> None: + try: + self.failed_init = False + self.final_response = {'headers':{'Access-Control-Allow-Headers': '*', + 'Access-Control-Allow-Origin': '*', + 'Access-Control-Allow-Methods': '*'}, "statusCode": 500, 'body': {}} + self.db_connection = 0 + self.detailed_raise = '' + self.partial_response = {} + + logger.warning(f'event de entrada: {str(event)}') + + self.id_assessment = event['pathParameters']['id_assessment'] + + self.signs_inverter = '+-'.maketrans({'+':'-','-':'+'}) + + self.historic_dates = list() + self.projection_dates = list() + self.total_asssessment_dates = 0 + + self.pyg_table = dict() + self.subs_results = list() + + self.pyg_values_vector = dict() + self.pyg_hints_vector = dict() + self.raw_pyg_id_dict = dict() + + self.capex_exists = False + self.debt_exists = False + + except Exception as e: + logger.error(f'[__init__] Error inicializando objeto lambda, linea: {get_current_error_line()}, motivo: {str(e)}') + self.failed_init = True + + + def starter(self): + try: + logger.info(f'[starter] Empezando starter de objeto lambda') + self.create_conection_to_db() + self.get_assessment_dates() + self.get_raw_pyg_data() + self.initialize_zero_vectors() + self.get_summary_results() + self.pyg_calculator() + self.calculate_partial_totals() + + #self.invert_period_dep_amo() #Colocar acá para invertir solo los historicos + + if self.projection_dates: + self.get_projections_data() + self.consume_projections_data() + self.check_capex_existance() + self.check_debt_existance() + + self.invert_period_dep_amo() #Al invertir acá estoy invirtiendo resultados de proyecciones también, creo que debo invertir solo los historicos + + if self.capex_exists: #Acá se debe sobreescribir amortizacion y depreciacion del periodo y la linea de capex + self.consume_capex_data() + else: + del self.pyg_values_vector['Depreciación Capex'] + del self.pyg_hints_vector['Depreciación Capex'] + + if self.debt_exists: + self.consume_debt_data() + + self.calculate_pyg_totals() + + self.create_uploable_dataframes() + self.check_previous_data() + self.upload_dataframes_to_bd() + call_dynamic_engine(self.id_assessment) + return self.response_maker(succesfull_run = True) + + except Exception as e: + logger.error(f'[starter] Hubieron problemas en el comando de la linea: {get_current_error_line()}') + return self.response_maker(succesfull_run = False, error_str = (str(e))) + + + @handler_wrapper('Creando conexion a bd','Conexion a bd creada con exito','Error en la conexion a bd','Problemas creando la conexion a bd') + def create_conection_to_db(self): + db_schema = os.environ['DB_SCHEMA'] + secret_db_region = os.environ['SECRET_DB_REGION'] + secret_db_name = os.environ['SECRET_DB_NAME'] + db_secret = get_secret(secret_db_region, secret_db_name) + self.db_connection = connect_to_db(db_schema, db_secret) + + + @handler_wrapper('Obteniendo las fechas del proceso de valoración', 'Fechas del proceso de valroación obtenidas con exito', 'Error obteniendo las fechas del proceso de valoración', 'Error obteniendo fechas del proceso de valoración') + def get_assessment_dates(self): + query = f"SELECT DATES, PROPERTY FROM ASSESSMENT_DATES WHERE ID_ASSESSMENT = {self.id_assessment} ORDER BY DATES" + logger.info(f"[get_assessment_dates] Query a base de datos para obtener las fechas utilizadas en el proces de valoración:\n {query}") + rds_data = self.db_connection.execute(query) + directory = {'HISTORIC': self.historic_dates, 'PROJECTION': self.projection_dates} + for date_item in rds_data.fetchall(): + directory.get(date_item.PROPERTY, []).append(date_item.DATES) + self.total_asssessment_dates = self.total_asssessment_dates +1 + + self.historic_dates = [date.strftime('%Y-%m-%d %H:%M:%S') for date in self.historic_dates] + self.projection_dates = [date.strftime('%Y-%m-%d %H:%M:%S') for date in self.projection_dates] + + logger.info(f'[get_assessment_dates] Fechas del proceso de valoración:\nhistoricas: {self.historic_dates}\nproyecciones: {self.projection_dates}') + + + @handler_wrapper('Adquiriendo raw de pyg', 'Raw de pyg obtenido con exito', 'Error obteniendo datos Raw de pyg', 'Error adquiriendo identificadores de pyg') + def get_raw_pyg_data(self): + query = "SELECT * FROM RAW_PYG" + logger.info(f"[get_raw_pyg_data] Query a base de datos para obtener el RAW PYG base:\n{query}") + rds_data = self.db_connection.execute(query) + self.raw_pyg = [item._asdict() for item in rds_data.fetchall()] + self.raw_pyg_id_dict = {item['PYG_ITEM_NAME']:int(item['ID']) for item in self.raw_pyg} + logger.info(f'[get_raw_pyg_data] Directorio adquirido de raw pyg:\n{self.raw_pyg_id_dict}') + + + @handler_wrapper('Inicializando todos los vectores a zero', 'Vectores de flujo de caja inicializados', 'Error inicializando vectores de flujo de caja', 'Error iniciando sistema vectorial') + def initialize_zero_vectors(self): + for row in pyg_all_items: + self.pyg_values_vector[row] = [0] * self.total_asssessment_dates + self.pyg_hints_vector[row] = [''] * self.total_asssessment_dates + + + @handler_wrapper('Obteniendo datos summary de clasificacion','summaries de clasificacion obtenidos','Error obteniendo summaries','Error al buscar informacion de sumaries') + def get_summary_results(self): + query = f"""SELECT B.CLASSIFICATION, A.HINT AS hint, A.ANNUALIZED AS value, B.IS_PARENT +FROM CLASSIFICATION_SUMMARY A, RAW_CLASSIFICATION B, ARCHIVE C +WHERE A.ID_RAW_CLASSIFICATION = B.ID AND A.ID_ARCHIVE = C.ID +AND A.ID_ASSESSMENT = {self.id_assessment} ORDER BY C.INITIAL_DATE""" + + + logger.info(f"[get_archive_info] Query a base de datos para obtener los summaries de clasificacion calculados:\n {query}") + rds_data = self.db_connection.execute(query) + + self.summary_data = [dict(item) for item in rds_data.mappings().all()] + for item in self.summary_data: + item['value'] = float(item['value']) + logger.warning(f'[get_summary_results] Summaries encontrados para el proceso de valoración:\n{self.summary_data}') + + + @handler_wrapper('Empezando master calculador de pyg','Master calculador de pyg terminado','Error en el master de calculo para pyg','Error calculando') + def pyg_calculator(self): + + for classification in pyg_simple_calculations: + classification_value_vector, classification_hint_vector = self.filter_classification(classification) + self.pyg_values_vector[classification] = classification_value_vector + self.pyg_hints_vector[classification] = classification_hint_vector + + parents_accounts = sorted(set(item['CLASSIFICATION'] for item in self.summary_data if item['IS_PARENT'])) + logger.warning(f'[pyg_calculator] parents_accounts encontrados: \n{parents_accounts}') + for parent in parents_accounts: + self.filter_parents_of(parent) + + logger.warning(f'[pyg_calculator] Resultados pyg post calculadora\n**Vector de valores por clasificacion**\n{self.pyg_values_vector}\n\n**Vector de hints por clasificacion**\n') + + + @debugger_wrapper('Error filtrando clasificaciones','Error construyendo clasificaciones') + def filter_classification(self, classification): + result = [item for item in self.summary_data if item['CLASSIFICATION'] == classification] + logger.warning(f'[filter_classification] Buscando clasificacion: {classification}, summary encontrado: {result}') + if not result: + return [0] * len(self.historic_dates), ['Clasificación no encontrada'] * len(self.historic_dates) + + value_vector = [item['value'] for item in result] + hint_vector = [item['hint'] for item in result] + return value_vector, hint_vector + + + @debugger_wrapper('Error filtrando clasificaciones','Error construyendo clasificaciones') + def filter_parents_of(self, parent): + found_sons_classifications = sorted(set(son['CLASSIFICATION'] for son in self.summary_data if son['CLASSIFICATION'].startswith(parent) and (son['IS_PARENT'] == 0))) + found_items_dict = {} + logger.warning(f'[filter_parents_of] Agregando values y hints de la clasificacion padre {parent}, clasificaciones hijas encontradas:\n{found_sons_classifications}') + for son_classification in found_sons_classifications: + classification_value_vector, classification_hint_vector = self.filter_classification(son_classification) + self.pyg_values_vector[son_classification] = classification_value_vector + self.pyg_hints_vector[son_classification] = classification_hint_vector + + + @handler_wrapper('Calculando totales parciales', 'Totales parciales calculadas', 'Error calculando totales parciales', 'No se pudieron calcular "Otros ingresos y egresos"') + def calculate_partial_totals(self): + for total_partial, total_dict in pyg_partials.items(): + self.pyg_values_vector[total_partial] = self.calculate_total_vector(total_dict['dependencies'], total_dict['is_sum']) + self.pyg_hints_vector[total_partial] = [' - '.join(total_dict['dependencies'])] * len(self.historic_dates) + logger.info(f'[calculate_partial_totals] El vector de totales de {total_partial} obtenido es {self.pyg_values_vector[total_partial]}') + + + @handler_wrapper('Realizando query a proyecciones del proceso de valoracion', 'Proyecciones adquiridas con exito', 'Error adquiriendo proyecciones de pyg', 'Error adquiriendo proyecciones') + def get_projections_data(self): + query = f"""SELECT B.PYG_ITEM_NAME as name, B.IS_SUB, A.VALUE AS value, C.PROJECTION_TYPE FROM PROJECTED_PYG A, RAW_PYG B, PYG_ITEM C +WHERE A.ID_RAW_PYG = B.ID AND C.ID_ASSESSMENT = A.ID_ASSESSMENT AND A.ID_RAW_PYG = C.ID_RAW_PYG AND A.ID_ASSESSMENT = {self.id_assessment} ORDER BY A.PROJECTED_DATE""" + + logger.info(f'[get_projections_data] Query para obtener proyecciones del proceso de valoracion:\n{query}') + rds_data = self.db_connection.execute(query) + self.projection_data = [item._asdict() for item in rds_data.fetchall()] + for item in self.projection_data: + item['value'] = float(item['value']) + + + + @handler_wrapper('Proyecciones de pyg encontradas, consumiendo', 'Proyecciones de pyg consumidas con exito', 'Error consumiendo proyecciones de pyg', 'Error integrando proyecciones de pyg') + def consume_projections_data(self): + for pyg_item, pyg_values in self.pyg_values_vector.items(): + projection_vector = [item['value'] for item in self.projection_data if item['name'] == pyg_item] + if not projection_vector: + projection_vector = [0] * len(self.projection_dates) + projection_hint = next((item['PROJECTION_TYPE'] for item in self.projection_data if item['name'] == pyg_item), 'proyeccion del item no encontrada') + logger.info(f'[consume_projections_data] Vector de proyecciones encontradas para {pyg_item}:\n{projection_vector}\nCon hint:{projection_hint}') #\ndesde el objeto:.\n{self.projection_data} + pyg_values.extend(projection_vector) + self.pyg_hints_vector[pyg_item].extend([projection_hint] * len(self.projection_dates)) + + + @handler_wrapper('Chequeando si hay datos de capex', 'Chequeo de datos de capex terminado', 'Error chequeando si hay datos de capex', 'Error chequeando existencia de datos capex') + def check_capex_existance(self): + query = f"""SELECT * FROM CAPEX_SUMMARY WHERE ID_ASSESSMENT = {self.id_assessment} ORDER BY SUMMARY_DATE""" + + logger.info(f'[check_capex_existance] Query para obtener datos del summary de capex, si los hay:\n{query}') + rds_data = self.db_connection.execute(query) + self.capex_data = [item._asdict() for item in rds_data.fetchall()] + capex_dates_len = len(set(item['SUMMARY_DATE'] for item in self.capex_data)) + if capex_dates_len == self.total_asssessment_dates: + self.capex_exists = True + for row in self.capex_data: + row['Depreciación del periodo'] = float(row['PERIOD_DEPRECIATION']) + row['Amortización del periodo'] = float(row['PERIOD_AMORTIZATION']) + #row['CAPEX'] = float(row['CAPEX']) + row['Depreciación Capex'] = float(row['NEW_CAPEX']) + + @handler_wrapper('Chequeando si hay datos de capex', 'Chequeo de datos de capex terminado', 'Error chequeando si hay datos de capex', 'Error chequeando existencia de datos capex') + def check_debt_existance(self): + query = f"""SELECT INTEREST_VALUE FROM COUPLED_DEBT WHERE ID_ASSESSMENT = {self.id_assessment} ORDER BY SUMMARY_DATE""" + + logger.info(f'[check_debt_existance] Query para obtener datos del summary de deuda, si los hay:\n{query}') + rds_data = self.db_connection.execute(query) + self.debt_data = [float(item.INTEREST_VALUE) for item in rds_data.fetchall()] + if len(self.debt_data) == self.total_asssessment_dates: + self.debt_exists = True + + + @handler_wrapper('Invirtiendo depreciacion y amortización del periodo','Inversiones realizadas','Error invirtiendo depreciacion y amortización','Error invirtiendo resultados de depreciacion y amortización') + def invert_period_dep_amo(self): + for row in ['Depreciación del periodo', 'Amortización del periodo']: + self.pyg_values_vector[row] = [-1* item for item in self.pyg_values_vector[row]] + self.pyg_hints_vector[row] = [item.translate(self.signs_inverter) for item in self.pyg_hints_vector[row]] + + + @handler_wrapper('Se encontraron datos de capex, consumiendo', 'Datos de capex consumidos con exito', 'Error consumiendo datos de capex', 'Error integrando datos de capex') + def consume_capex_data(self): + capex_vector_dict = {'Depreciación del periodo': [], 'Amortización del periodo': [], 'Depreciación Capex':[]} + for row in self.capex_data: + capex_vector_dict['Depreciación del periodo'].append(row['Depreciación del periodo']) + capex_vector_dict['Amortización del periodo'].append(row['Amortización del periodo']) + capex_vector_dict['Depreciación Capex'].append(row['Depreciación Capex']) + + for key, vector in capex_vector_dict.items(): + self.pyg_values_vector[key] = vector + self.pyg_hints_vector[key] = ['Modificado desde capex'] * self.total_asssessment_dates + + + @handler_wrapper('Se encontraron resultados de deuda, consumiendo', 'Datos de deuda consumidos con exito', 'Error consumiendo datos de deuda', 'Error adjuntando datos de deuda') + def consume_debt_data(self): + self.pyg_values_vector['Intereses/gasto financiero'][-1 * len(self.projection_dates):] = self.debt_data[-1 * len(self.projection_dates):] + self.pyg_hints_vector['Intereses/gasto financiero'][-1 * len(self.projection_dates):] = ['Modificado por existencia de deuda'] * len(self.projection_dates) + + + @handler_wrapper('Calculando totales de pyg', 'Totales de pyg calculados con exito', 'Error calculando totales de pyg', 'Error calculando totales de pyg') + def calculate_pyg_totals(self): + for total_key, total_dict in pyg_totals.items(): + self.pyg_values_vector[total_key] = self.calculate_total_vector(total_dict['dependencies'], total_dict['is_sum']) + self.pyg_hints_vector[total_key] = ['Total parcial Pyg'] * self.total_asssessment_dates + logger.info(f'[calculate_pyg_totals] El vector de totales de {total_key} obtenido es {self.pyg_values_vector[total_key]}') + + + @debugger_wrapper('Error calculando sub total de tabla', 'Error calculando totales de flujo de caja') + def calculate_total_vector(self, dependencies, vector_signs): + logger.info(f'[mira aca] dependencias que se estan inyectando:\n{dependencies}\ncon signos:{vector_signs}') + dependencies_vectors = [self.pyg_values_vector.get(dependence, [0]*self.total_asssessment_dates) for dependence in dependencies] + partial_vector = [] + logger.info(f'[mira aca] vectores de dependencias:\n{dependencies_vectors}') + for year_values in zip(*dependencies_vectors): + year_total = 0 + for index, value in enumerate(year_values): + year_total = year_total + value * vector_signs[index] + partial_vector.append(year_total) + return partial_vector + + + + @handler_wrapper('Creando dataframes de carga a bd', 'Dataframes de carga a bd construídos con exito', 'Error creando dataframes de carga a bd', 'Error creando objetos de carga a bd') + def create_uploable_dataframes(self): + for item in ['Otros ingresos operativos', 'Otros egresos operativos', 'Otros ingresos no operativos', 'Otros egresos no operativos']: + del self.pyg_values_vector[item] + del self.pyg_hints_vector[item] + logger.info(f'[create_uploable_dataframes] Estos son los datos que se van a pasar a dataframe:\n**Vectores de values:**\n{self.pyg_values_vector}\n\n**Vectores de hints:**\n{self.pyg_hints_vector}') + df = pd.DataFrame.from_dict(self.pyg_values_vector).transpose() + all_columns = ['pyg_raw'] + self.historic_dates + self.projection_dates + df.reset_index(inplace = True) + df.columns = all_columns + self.to_db_df = df.melt(id_vars = 'pyg_raw', value_vars = self.historic_dates + self.projection_dates, var_name='DATES', value_name='VALUE') + self.to_db_df['ID_ASSESSMENT'] = self.id_assessment + self.to_db_df['ID_RAW_PYG'] = self.to_db_df['pyg_raw'].map(self.raw_pyg_id_dict) + self.to_db_df['HINT'] = '' + + for key, hint_vector in self.pyg_hints_vector.items(): + self.to_db_df.loc[self.to_db_df['pyg_raw']==key, 'HINT'] = hint_vector + self.to_db_df.drop(['pyg_raw'], axis=1, inplace = True) + + #logger.info(f'[create_uploable_dataframes] DataFrame acomodado hasta este punto:\n{self.to_db_df.to_string()}') + + + @handler_wrapper('Verificando que no existan datos anteriores', 'Borrado de posibles datos anteriores terminado', 'Error eliminando datos anteriores', 'Error sobreescribiendo datos anteriores') + def check_previous_data(self): + query = f"DELETE FROM PYG_RESULTS WHERE ID_ASSESSMENT = {self.id_assessment}" + logger.info(f"[check_previous_data] Query a base de datos para eliminar posibles resultados anteriores de la tabla de pyg:\n{query}") + rds_data = self.db_connection.execute(query) + + + @handler_wrapper('Cargando dataframes a bd', 'Carga de datos de capex exitosa', 'Error cargando datos de capex a bd', 'Error cargando datos a bd') + def upload_dataframes_to_bd(self): + logger.info(f'[upload_dataframes_to_bd] Tabla que se está cargando a bd:\n{self.to_db_df.to_string()}') + self.to_db_df.to_sql(name= 'PYG_RESULTS', con=self.db_connection, if_exists='append', index=False) + + + @debugger_wrapper('Error construyendo respuesta final', 'Error construyendo respuesta') + def response_maker(self, succesfull_run = False, error_str = str()): + if self.db_connection: + self.db_connection.close() + if succesfull_run: + self.final_response['statusCode'] = 200 + self.final_response['body'] = json.dumps('ok') + return self.final_response + + self.final_response['body'] = json.dumps(self.detailed_raise if self.detailed_raise else error_str) + return self.final_response + + +def get_current_error_line(): + return str(sys.exc_info()[-1].tb_lineno) \ No newline at end of file diff --git a/corporate_finances_back_py/pyg-calculator/utils.py b/corporate_finances_back_py/pyg-calculator/utils.py new file mode 100644 index 0000000..b0c0c01 --- /dev/null +++ b/corporate_finances_back_py/pyg-calculator/utils.py @@ -0,0 +1,46 @@ +#version 2023 - 05 - 04 +import base64 +import boto3 +import json +import logging +import os + +from sqlalchemy import create_engine + +from decorators import handler_wrapper, debugger_wrapper + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + + +@debugger_wrapper('Error al obtener secreto','Error fatal de back conectando a base de datos') +def get_secret(secret_region, secret_name): + session = boto3.session.Session() + client_secrets_manager = session.client(service_name='secretsmanager', region_name=secret_region) + secret_data = client_secrets_manager.get_secret_value(SecretId=secret_name) + if 'SecretString' in secret_data: + secret_str = secret_data['SecretString'] + else: + secret_str = base64.b64decode(secret_data['SecretBinary']) + logger.info('[utils] (get_secret) Se obtuvo el secreto') + return json.loads(secret_str) + + +@debugger_wrapper('Error en la conexion a base de datos','Error fatal de back conectando a base de datos') +def connect_to_db(db_schema, db_secret): + conn_string = ('mysql+mysqlconnector://' + db_secret["username"] + ':' + db_secret["password"] + '@' + db_secret["host"] + ':' + str(db_secret["port"]) + '/' + db_schema) + sql_engine = create_engine(conn_string) + db_connection = sql_engine.connect() + return db_connection + + +@handler_wrapper('Invocando asincronamente a Engine de dinamismo', 'Invocación a Engine exitosa', 'Error invocando a Engine', 'Error invocando dinamismo') +def call_dynamic_engine(id_assessment): + lambda_engine = os.environ['LAMBDA_ENGINE'] + data = json.dumps({'id_assessment':id_assessment}).encode() + client = boto3.client('lambda') + response = client.invoke( + FunctionName=lambda_engine, + InvocationType='Event', + Payload= data +) diff --git a/corporate_finances_back_py/pyg-calculator/vars.py b/corporate_finances_back_py/pyg-calculator/vars.py new file mode 100644 index 0000000..af06341 --- /dev/null +++ b/corporate_finances_back_py/pyg-calculator/vars.py @@ -0,0 +1,55 @@ + +pyg_all_items = ['Costos (Sin depreciación)', + 'Depreciación del periodo', + 'Amortización del periodo', + 'Otros ingresos operativos', + 'Otros egresos operativos', + 'Otros ingresos no operativos', + 'Otros egresos no operativos', + 'Depreciación Capex', + 'Deterioro', + 'Impuestos de renta', + 'Intereses/gasto financiero', + 'Ingresos operacionales', + 'Gastos operacionales', + 'Otros ingresos y egresos no operativos', + 'Otros ingresos y egresos operativos', + 'Utilidad bruta', + 'EBITDA', + 'EBIT', + 'Utilidad antes de impuestos', + 'Utilidad neta'] + + +pyg_simple_calculations = ['Costos (Sin depreciación)', + 'Depreciación del periodo', + 'Depreciación Capex', + 'Amortización del periodo', + 'Otros ingresos operativos', + 'Otros egresos operativos', + 'Otros ingresos no operativos', + 'Otros egresos no operativos', + 'Deterioro', + 'Impuestos de renta', + 'Intereses/gasto financiero', + 'Ingresos operacionales', + 'Gastos operacionales'] + + +#TODO: Debo arreglar estos totales a los totales de pyg +pyg_partials = {'Otros ingresos y egresos no operativos':{'dependencies': ['Otros ingresos no operativos','Otros egresos no operativos'], + 'is_sum': [1,-1]}, + 'Otros ingresos y egresos operativos':{'dependencies':['Otros ingresos operativos','Otros egresos operativos'], + 'is_sum':[1,-1]}} + +pyg_totals = {'Utilidad bruta':{'dependencies':['Ingresos operacionales','Costos (Sin depreciación)'], + 'is_sum':[1,-1]}, + 'EBITDA':{'dependencies':['Utilidad bruta','Gastos operacionales','Otros ingresos y egresos operativos'], + 'is_sum':[1,-1,1]}, + 'EBIT':{'dependencies':['EBITDA','Depreciación del periodo','Amortización del periodo','Depreciación Capex','Deterioro'], + 'is_sum':[1,-1,-1,-1,-1]}, + 'Utilidad antes de impuestos':{'dependencies':['EBIT','Otros ingresos y egresos no operativos','Intereses/gasto financiero'], + 'is_sum':[1,1,-1]}, + 'Utilidad neta':{'dependencies':['Utilidad antes de impuestos','Impuestos de renta'], + 'is_sum':[1,-1]}, + } diff --git a/corporate_finances_back_py/pyg-projections-calculator/decorators.py b/corporate_finances_back_py/pyg-projections-calculator/decorators.py new file mode 100644 index 0000000..071760a --- /dev/null +++ b/corporate_finances_back_py/pyg-projections-calculator/decorators.py @@ -0,0 +1,63 @@ +#version 2023 - 05 - 04 +import logging +import sys +import traceback +from functools import wraps +from time import time + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + +def handler_wrapper(start, satisfactory_log, error_log, raise_error): + #esto se ejecuta en la inicializacion de primero + def decorator(func): + #print(message1) + #lo que yo ponga acá se ejecuta antes de hacer el llamado a la funcion + @wraps(func) + def wrapper(*args, **kwargs): + #esto sí se ejecuta solo cuando llama a la funcion decorada + #print(message2) + try: + logger.info(f'[{func.__name__}] {start}...') + resultado = func(*args, **kwargs) + logger.info(f'[{func.__name__}] {satisfactory_log}') + return resultado + except Exception as e: + logger.error(f"[{func.__name__}] {error_log}, linea: {get_especific_error_line(func.__name__)}, motivo: {str(e)}") + raise Exception(f"{raise_error}") + + return wrapper + return decorator + +def debugger_wrapper(error_log, raise_error): + def decorator(func): + @wraps(func) + def wrapper(*args, **kwargs): + try: + resultado = func(*args, **kwargs) + return resultado + except Exception as e: + logger.error(f"[{func.__name__}] {error_log}, linea: {get_especific_error_line(func.__name__)}, motivo: {str(e)}") + raise Exception(f"{raise_error}") + return wrapper + return decorator + + +def get_especific_error_line(func_name): + _, _, exc_tb = sys.exc_info() + for trace in traceback.extract_tb(exc_tb): + if func_name in trace: + return str(trace[1]) + +def timing(f): + @wraps(f) + def wrap(*args, **kw): + ts = time() + result = f(*args, **kw) + te = time() + taken_time_message = '[timing] La funcion {}, toma: {:.2f} sec en ejecutarse'.format(f.__name__, te-ts) + logger.info(taken_time_message) + return result + return wrap + + diff --git a/corporate_finances_back_py/pyg-projections-calculator/lambda_function.py b/corporate_finances_back_py/pyg-projections-calculator/lambda_function.py new file mode 100644 index 0000000..88a083d --- /dev/null +++ b/corporate_finances_back_py/pyg-projections-calculator/lambda_function.py @@ -0,0 +1,233 @@ + +from decorators import handler_wrapper, debugger_wrapper +from sqlalchemy import text +import json +import logging +import sys +import pandas as pd +import datetime +import os +from utils import get_secret, connect_to_db, call_dynamic_engine, connect_to_db_local_dev + + +logging.basicConfig() +logging.basicConfig(format='%(asctime)s [%(levelname)s] [%(module)s] %(message)s', force=True, datefmt='%Y-%m-%d %H:%M:%S') +logger = logging.getLogger() +logger.setLevel(logging.INFO) + + +def lambda_handler(event, context): + sc_obj = script_object(event) + lambda_response = sc_obj.starter() + logger.info(f'respuesta final de lambda: \n{lambda_response}') + return lambda_response + + +class script_object: + + def __init__(self, event) -> None: + try: + self.failed_init = False + self.final_response = {'headers':{'Access-Control-Allow-Headers': '*', + 'Access-Control-Allow-Origin': '*', + 'Access-Control-Allow-Methods': '*'}, "statusCode": 500, 'body': {}} + self.db_connection = 0 + self.detailed_raise = '' + self.partial_response = [] + + logger.warning(f'event de entrada: {str(event)}') + event_body_dict = json.loads(event['body']) + self.years = event_body_dict["year"] + self.historic_dates = [] + self.projection_dates = event_body_dict["datesProjections"] + self.projection_dates_len = len(self.projection_dates) + self.projected_items = event_body_dict["projection_data"] + self.id_assessment = event_body_dict["id_assessment"] + + self.master_raw_pyg = dict() + + self.nan_years = [float('NaN')]*self.years + self.projections_to_db_df = pd.DataFrame() + self.pyg_items_to_db_df = pd.DataFrame() + + except Exception as e: + logger.error(f'[__init__] Error inicializando objeto lambda, linea: {get_current_error_line()}, motivo: {str(e)}') + self.failed_init = True + + def starter(self): + try: + if self.failed_init: + raise AttributeError('Error con los datos recibidos al servicio') + logger.info("iniciando tareas de lambda") + self.create_conection_to_db() + self.get_assessment_dates() + self.get_raw_pyg() + self.delete_earlier_pyg_items_in_bd() + + self.organize_bd_projections_data() + self.organize_pyg_items() + self.organize_projection_dates_to_df() + + self.upload_projections_df() + self.pyg_items_to_db() + self.save_projection_dates() + + self.save_assessment_step() + call_dynamic_engine(self.id_assessment, __name__) + + logger.info("Tareas de lambda finalizadas con exito") + return self.response_maker(succesfull=True) + except Exception as e: + logger.error( + f"[starter] Error critico de lambda en el comando de la linea {get_current_error_line()}, motivo: {str(e)}") + return self.response_maker(exception_str = str(e)) + + + @handler_wrapper('Creando conexion a bd','Conexion a bd creada con exito','Error en la conexion a bd','Problemas creando la conexion a bd') + def create_conection_to_db(self): + if __name__ != 'lambda_function': + self.db_connection = connect_to_db_local_dev() + self.db_connection.begin() + return + db_schema = os.environ['DB_SCHEMA'] + secret_db_region = os.environ['SECRET_DB_REGION'] + secret_db_name = os.environ['SECRET_DB_NAME'] + db_secret = get_secret(secret_db_region, secret_db_name) + self.db_connection = connect_to_db(db_schema, db_secret) + + + @handler_wrapper('Obteniendo las fechas del proceso de valoración', 'Fechas del proceso de valroación obtenidas con exito', 'Error obteniendo las fechas del proceso de valoración', 'Error obteniendo fechas del proceso de valoración') + def get_assessment_dates(self): + query = f"SELECT DATES, PROPERTY FROM ASSESSMENT_DATES WHERE ID_ASSESSMENT = {self.id_assessment} ORDER BY DATES" + logger.info(f"[get_assessment_dates] Query a base de datos para obtener las fechas utilizadas en el proces de valoración:\n {query}") + rds_data = self.db_connection.execute(text(query)) + directory = {'HISTORIC': self.historic_dates} + for date_item in rds_data.fetchall(): + directory.get(date_item.PROPERTY, []).append(date_item.DATES) #Las self.projection_dates no las estoy usando para nada + + projection_dates_temp = [] + assessment_date = self.historic_dates[-1] + for i in range(1, self.projection_dates_len+1): + projection_dates_temp.append(f'{assessment_date.year + i}-01-01') + + if '-12-' not in assessment_date.strftime(f'%Y-%m-%d'): + projection_dates_temp = [f'{assessment_date.year}-12-01'] + projection_dates_temp[:-1] + self.projection_dates = projection_dates_temp + logger.info(f'[get_assessment_dates] Fechas del proceso de valoración:\nhistoricas: {self.historic_dates}\nproyecciones: {self.projection_dates}') + + + @handler_wrapper('Realizando query de raw_pyg', 'Raw pyg obtenido correctamente', 'Error adquiriendo raw_pyg','Error adquiriendo identificadores de pyg') + def get_raw_pyg(self): + query = "SELECT * FROM RAW_PYG" + logger.info(f'[get_raw_pyg] Query para obtener los raw pyg: {query}') + rds_data = rds_data = self.db_connection.execute(text(query), {"id_assessment":self.id_assessment}) + self.master_raw_pyg = {item.PYG_ITEM_NAME:item.ID for item in rds_data.fetchall()} + + + @handler_wrapper('Chequeando si ya hay Proyecciones en BD', 'Chequeo terminado de proyecciones en BD terminado', 'Error chequeando si ya hay proyecciones en BD', 'Errores verificando proyecciones en BD') + def delete_earlier_pyg_items_in_bd(self): + query = "DELETE FROM PYG_ITEM WHERE ID_ASSESSMENT = :id_assessment" + logger.warning(f'[delete_earlier_pyg_items_in_bd] Query para eliminacion de pyg items: \n{query}') + self.db_connection.execute(text(query), {"id_assessment":self.id_assessment}) + + query = "DELETE FROM PROJECTED_PYG WHERE ID_ASSESSMENT = :id_assessment" + logger.warning(f'[delete_earlier_pyg_items_in_bd] Query para eliminacion de pyg proyectados: \n{query}') + self.db_connection.execute(text(query), {"id_assessment":self.id_assessment}) + + query = "DELETE FROM ASSESSMENT_DATES WHERE ID_ASSESSMENT = :id_assessment AND PROPERTY =\"PROJECTION\" " + logger.info(f'[delete_earlier_pyg_items_in_bd] Query para eliminar fechas de proyeccion existentes del proceso de valoración: \n{query}') + self.db_connection.execute(text(query), {"id_assessment":self.id_assessment}) + + + @handler_wrapper('Organizando informacion de proyecciones a BD', 'Información organizada con exito', 'Error organizando informacion a bd', 'Error organizando datos que se subiran a bd') + def organize_bd_projections_data(self): + to_db_item_list = [] + + for item in self.projected_items: + item_name_id = self.master_raw_pyg[item['account']] + for index, proyection_date in enumerate(self.projection_dates): + try: + to_db_item = {'ID_RAW_PYG':item_name_id, 'PROJECTED_DATE': proyection_date, 'VALUE': 0, 'ATRIBUTE':item['atributes'].get('projection',self.nan_years)[index]} + except: + print('hola') + to_db_item_list.append(to_db_item) + self.projections_to_db_df = pd.DataFrame.from_records(to_db_item_list) + self.projections_to_db_df['ID_ASSESSMENT'] = self.id_assessment + self.projections_to_db_df.fillna(value= {'ATRIBUTE': ''}, inplace = True) + + + @handler_wrapper('Organizando items de pyg', 'Items de pyg organizados con exito', 'Error organizando items de pyg', 'Error organizando resultados del pyg actual para carga en db') + def organize_pyg_items(self): + pyg_items_list = [] + for item in self.projected_items: + if item['method'] in ["Porcentaje de otra variable", "Tasas impositivas"]: + this_item_dependence_id = self.master_raw_pyg[item['accountProjector']] + else: + this_item_dependence_id = self.master_raw_pyg['No aplica'] + this_item_raw_pyg_id = self.master_raw_pyg[item['account']] + this_item_made = {'ID_RAW_PYG': this_item_raw_pyg_id, + 'ID_DEPENDENCE': this_item_dependence_id, + 'ORIGINAL_VALUE': 0, + 'PROJECTION_TYPE': item['method'], + 'COMMENT': item.get('explication', '')} + pyg_items_list.append(this_item_made) + self.pyg_items_to_db_df = pd.DataFrame.from_records(pyg_items_list) + self.pyg_items_to_db_df['ID_ASSESSMENT'] = self.id_assessment + logger.info(f'[organize_pyg_items] Dataframe de items de pyg a subir: \n{self.pyg_items_to_db_df}') + + + @handler_wrapper('Organizando fechas historicas para cargar en bd', 'Fechas historicas construidas a dataframe', 'Error organizando fechas historicas a dataframe', 'Error manipulando fechas historicas para guardado en bd') + def organize_projection_dates_to_df(self): + self.projection_dates_to_db = [datetime.datetime.strptime(date, '%Y-%m-%d').strftime('%Y-%m-%d %H:%M:%S') for date in self.projection_dates] + self.projection_dates_df = pd.DataFrame({'DATES': self.projection_dates_to_db, + 'ID_ASSESSMENT': [self.id_assessment] * self.projection_dates_len, + 'PROPERTY': ['PROJECTION']* self.projection_dates_len}) + + + @handler_wrapper('Subiendo dataframe de proyecciones a bd', 'Carga de datos exitosa', 'Error en la carga de datos', 'Error cargando datos de proyecciones a bd') + def upload_projections_df(self): + logger.info(f'[upload_projections_df] Dataframe de proyecciones a subir: \n{self.projections_to_db_df}') + self.projections_to_db_df.to_sql(name='PROJECTED_PYG', con=self.db_connection, if_exists='append', index=False) + + + @handler_wrapper('cargando items de pyg a db', 'items de pyg cargados con exito', 'Error cargando los items de pyg', 'Error cargando los items de pyg a bd, es posible que las proyecciones sí se hayan cargado con exito') + def pyg_items_to_db(self): + logger.info(f'[pyg_items_to_db] Dataframe de pyg_items a subir: \n{self.pyg_items_to_db_df.to_string()}') + self.pyg_items_to_db_df.to_sql(name='PYG_ITEM', con=self.db_connection, if_exists='append', index=False) + + + @handler_wrapper('Guardando fechas historicas del proceso de valoración en bd','fechas historicas guardadadas con exito','Error guardando fechas historicas en bd', 'Error guardando fechas historicas en bd') + def save_projection_dates(self): + logger.info(f'[save_historic_dates] Dataframe de fechas que se va a guardar en bd:\n{self.projection_dates_df.to_string()}') + self.projection_dates_df.to_sql(name='ASSESSMENT_DATES', con=self.db_connection, if_exists='append', index=False) + + + @handler_wrapper('Guardando el paso del proceso de valoracion','Paso guardado correctamente','Error guardando el paso del proceso de valoración', 'Error guardando informacion') + def save_assessment_step(self): + try: + query = "INSERT INTO ASSESSMENT_STEPS VALUES (:id_assessment, \"PYG\");" + logger.info(f"[save_assessment_step] Query a base de datos para guardar el paso del proceso de valoracion: \n{query}") + self.db_connection.execute(text(query), {"id_assessment":self.id_assessment}) + except Exception as e: + logger.warning(f'[save_assessment_step] Es posible que el step del proceso de valoracion ya haya sido guardado, sin embargo, este es el mensaje de error:\n{str(e)}') + + + def response_maker(self, succesfull=False, exception_str=""): + if self.db_connection: + self.db_connection.close() + if not succesfull: + self.final_response["body"] = json.dumps(exception_str) + else: + self.final_response["statusCode"] = 200 + self.final_response["body"] = json.dumps("ok") + return self.final_response + + +def get_current_error_line(): + return str(sys.exc_info()[-1].tb_lineno) + + +if __name__ == "__main__": + #event = {'body': "{\"id_assessment\":55,\"projections\":{\"year\":3,\"dates_projection\":[\"2024\",\"2025\",\"2026\"],\"projection_data\":[{\"account\":\"Ingresos operacionales 1\",\"accountProjector\":\"Seleccione\",\"method\":\"Valor constante\",\"atributes\":[\"\",\"\",\"\"],\"explication\":\"a\"},{\"account\":\"Costos (Sin depreciación)\",\"accountProjector\":\"Seleccione\",\"method\":\"Valor constante\",\"atributes\":[\"\",\"\",\"\"],\"explication\":\"a\"},{\"account\":\"Gastos operacionales 1\",\"accountProjector\":\"Seleccione\",\"method\":\"Valor constante\",\"atributes\":[\"\",\"\",\"\"],\"explication\":\"a\"},{\"account\":\"Otros ingresos y egresos operativos\",\"accountProjector\":\"Seleccione\",\"method\":\"Valor constante\",\"atributes\":[\"\",\"\",\"\"],\"explication\":\"a\"},{\"account\":\"Depreciación del periodo\",\"accountProjector\":\"Seleccione\",\"method\":\"Valor constante\",\"atributes\":[\"\",\"\",\"\"],\"explication\":\"a\"},{\"account\":\"Amortización del periodo\",\"accountProjector\":\"Seleccione\",\"method\":\"Valor constante\",\"atributes\":[\"\",\"\",\"\"],\"explication\":\"a\"},{\"account\":\"Deterioro\",\"accountProjector\":\"Seleccione\",\"method\":\"Valor constante\",\"atributes\":[\"\",\"\",\"\"],\"explication\":\"a\"},{\"account\":\"Otros ingresos y egresos no operativos\",\"accountProjector\":\"Seleccione\",\"method\":\"Valor constante\",\"atributes\":[\"\",\"\",\"\"],\"explication\":\"a\"},{\"account\":\"Intereses/gasto financiero\",\"accountProjector\":\"Seleccione\",\"method\":\"Valor constante\",\"atributes\":[\"\",\"\",\"\"],\"explication\":\"a\"},{\"account\":\"Impuestos de renta\",\"accountProjector\":\"Seleccione\",\"method\":\"Valor constante\",\"atributes\":[\"\",\"\",\"\"],\"explication\":\"a\"}]}}"} + event = {'body': '{"id_assessment":"2055","year":4,"datesHistory":["2021-12-31","2022-12-31","2023-03-23"],"datesProjections":["Diciembre 2023","2024","2025","2026","2027"],"projection_data":[{"account":"Ingresos operacionales 1","accountProjector":"Seleccione","method":"Tasa de crecimiento fija","atributes":{"history":[35160.28,43801.61,42685.68],"projection":[10,10,10,10,10]},"explication":"A"},{"account":"Costos (Sin depreciación)","accountProjector":"Seleccione","method":"Tasa de crecimiento fija","atributes":{"history":[0,0,0],"projection":[10,10,10,10,10]},"explication":"a"},{"account":"Gastos operacionales 1","accountProjector":"Seleccione","method":"Valor constante","atributes":{"history":[26595.48,28935.46,24025.02],"projection":["","","","",""]},"explication":"a"},{"account":"Otros ingresos y egresos operativos","accountProjector":"Seleccione","method":"Valor constante","atributes":{"history":[0,0,0],"projection":["","","","",""]},"explication":"a"},{"account":"Deterioro","accountProjector":"Seleccione","method":"Valor constante","atributes":{"history":[0,0,0],"projection":["","","","",""]},"explication":"a"},{"account":"Otros ingresos y egresos no operativos","accountProjector":"Seleccione","method":"Valor constante","atributes":{"history":[851.6299999999999,2024.0300000000002,6526.65],"projection":["","","","",""]},"explication":"a"},{"account":"Intereses/gasto financiero","accountProjector":"Seleccione","method":"Valor constante","atributes":{"history":[0,0,0],"projection":["","","","",""]},"explication":"a"},{"account":"Impuestos de renta","accountProjector":"Seleccione","method":"Valor constante","atributes":{"history":[0,0,0],"projection":["","","","",""]},"explication":"a"}]}'} + lambda_handler(event, '') \ No newline at end of file diff --git a/corporate_finances_back_py/pyg-projections-calculator/utils.py b/corporate_finances_back_py/pyg-projections-calculator/utils.py new file mode 100644 index 0000000..8248570 --- /dev/null +++ b/corporate_finances_back_py/pyg-projections-calculator/utils.py @@ -0,0 +1,59 @@ +#version 2023 - 05 - 04 +import base64 +import boto3 +import json +import logging +import os + +from sqlalchemy import create_engine + +from decorators import handler_wrapper, debugger_wrapper + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + + +@debugger_wrapper('Error al obtener secreto','Error fatal de back conectando a base de datos') +def get_secret(secret_region, secret_name): + session = boto3.session.Session() + client_secrets_manager = session.client(service_name='secretsmanager', region_name=secret_region) + secret_data = client_secrets_manager.get_secret_value(SecretId=secret_name) + if 'SecretString' in secret_data: + secret_str = secret_data['SecretString'] + else: + secret_str = base64.b64decode(secret_data['SecretBinary']) + logger.info('[utils] (get_secret) Se obtuvo el secreto') + return json.loads(secret_str) + + +@debugger_wrapper('Error en la conexion a base de datos','Error fatal de back conectando a base de datos') +def connect_to_db(db_schema, db_secret): + conn_string = ('mysql+mysqlconnector://' + db_secret["username"] + ':' + db_secret["password"] + '@' + db_secret["host"] + ':' + str(db_secret["port"]) + '/' + db_schema) + sql_engine = create_engine(conn_string) + db_connection = sql_engine.connect() + return db_connection + + +@debugger_wrapper('Error en la conexion a base de datos','Error fatal de back conectando a base de datos') +def connect_to_db_local_dev(): + from dotenv import load_dotenv + load_dotenv() + conn_string = os.environ['local_dev_connector'] + sql_engine = create_engine(conn_string) + db_connection = sql_engine.connect() + return db_connection + + +@handler_wrapper('Invocando asincronamente a Engine de dinamismo', 'Invocación a Engine exitosa', 'Error invocando a Engine', 'Error invocando dinamismo') +def call_dynamic_engine(id_assessment, context): + if context == 'lambda_function': + lambda_engine = os.environ['LAMBDA_ENGINE'] + data = json.dumps({'id_assessment':id_assessment}).encode() + client = boto3.client('lambda') + response = client.invoke( + FunctionName=lambda_engine, + InvocationType='Event', + Payload= data + ) + else: + logger.warning('[call_dynamic_engine] no se ejecuta engine ya que el contexto es local') diff --git a/corporate_finances_back_py/pyg-projections-retrieve/decorators.py b/corporate_finances_back_py/pyg-projections-retrieve/decorators.py new file mode 100644 index 0000000..071760a --- /dev/null +++ b/corporate_finances_back_py/pyg-projections-retrieve/decorators.py @@ -0,0 +1,63 @@ +#version 2023 - 05 - 04 +import logging +import sys +import traceback +from functools import wraps +from time import time + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + +def handler_wrapper(start, satisfactory_log, error_log, raise_error): + #esto se ejecuta en la inicializacion de primero + def decorator(func): + #print(message1) + #lo que yo ponga acá se ejecuta antes de hacer el llamado a la funcion + @wraps(func) + def wrapper(*args, **kwargs): + #esto sí se ejecuta solo cuando llama a la funcion decorada + #print(message2) + try: + logger.info(f'[{func.__name__}] {start}...') + resultado = func(*args, **kwargs) + logger.info(f'[{func.__name__}] {satisfactory_log}') + return resultado + except Exception as e: + logger.error(f"[{func.__name__}] {error_log}, linea: {get_especific_error_line(func.__name__)}, motivo: {str(e)}") + raise Exception(f"{raise_error}") + + return wrapper + return decorator + +def debugger_wrapper(error_log, raise_error): + def decorator(func): + @wraps(func) + def wrapper(*args, **kwargs): + try: + resultado = func(*args, **kwargs) + return resultado + except Exception as e: + logger.error(f"[{func.__name__}] {error_log}, linea: {get_especific_error_line(func.__name__)}, motivo: {str(e)}") + raise Exception(f"{raise_error}") + return wrapper + return decorator + + +def get_especific_error_line(func_name): + _, _, exc_tb = sys.exc_info() + for trace in traceback.extract_tb(exc_tb): + if func_name in trace: + return str(trace[1]) + +def timing(f): + @wraps(f) + def wrap(*args, **kw): + ts = time() + result = f(*args, **kw) + te = time() + taken_time_message = '[timing] La funcion {}, toma: {:.2f} sec en ejecutarse'.format(f.__name__, te-ts) + logger.info(taken_time_message) + return result + return wrap + + diff --git a/corporate_finances_back_py/pyg-projections-retrieve/lambda_function.py b/corporate_finances_back_py/pyg-projections-retrieve/lambda_function.py new file mode 100644 index 0000000..d441b96 --- /dev/null +++ b/corporate_finances_back_py/pyg-projections-retrieve/lambda_function.py @@ -0,0 +1,250 @@ +import json +import logging +import sys +import os +import datetime +from sqlalchemy import text + +from decorators import handler_wrapper, timing, debugger_wrapper +from utils import get_secret, connect_to_db, connect_to_db_local_dev + + +logging.basicConfig() +logging.basicConfig(format='%(asctime)s [%(levelname)s] [%(module)s] %(message)s', force=True, datefmt='%Y-%m-%d %H:%M:%S') +logger = logging.getLogger() +logger.setLevel(logging.INFO) + + +def lambda_handler(event,context): + sc_obj = script_object(event) + lambda_response = sc_obj.starter() + logger.info(f'respuesta final de lambda: \n{lambda_response}') + return lambda_response + + +class script_object: + def __init__(self, event): + try: + self.failed_init = False + self.final_response = {'headers':{'Access-Control-Allow-Headers': '*', + 'Access-Control-Allow-Origin': '*', + 'Access-Control-Allow-Methods': '*'}, "statusCode": 500, 'body': {}} + self.db_connection = 0 + self.detailed_raise = '' + self.partial_response = [] + + logger.warning(f'event de entrada: {str(event)}') + + self.accounts_to_skip = ("EBITDA", "Utilidad bruta", "EBIT", "Utilidad antes de impuestos", "Utilidad neta", "Ingresos operacionales", "Gastos operacionales") + self.pyg_totals = {'Otros ingresos y egresos operativos': {'dependencies': ['Otros ingresos operativos','Otros egresos operativos'],'is_sum':[1,-1]}, + 'Otros ingresos y egresos no operativos': {'dependencies': ['Otros ingresos no operativos','Otros egresos no operativos'], 'is_sum': [1,-1]}} + + self.projections_order = {'Ingresos operacionales': True, + 'Costos (Sin depreciación)': False, + 'Gastos operacionales': True, + 'Otros ingresos y egresos operativos': False, + #'Depreciación del periodo': False, + #'Amortización del periodo': False, + 'Deterioro': False, + 'Otros ingresos y egresos no operativos': False, + 'Intereses/gasto financiero': False, + 'Impuestos de renta': False, + } + self.first_time_projecting_object = {'PYG_DEPENDANCE_NAME': 'No aplica', 'COMMENT': 'Proyección primera vez, debug', 'PROJECTION_TYPE': 'Cero' } + + event_dict = event['pathParameters'] + self.id_assessment = event_dict['id_assessment'] + self.projections_found = False + self.projection_dates = list() + self.historic_dates = list() + self.atributes_dict = dict() + self.years_projected = int() + + except Exception as e: + logger.error(f'[__init__] Error inicializando objeto lambda, linea: {get_current_error_line()}, motivo: {str(e)}') + self.failed_init = True + + def starter(self): + try: + if self.failed_init: + raise AttributeError('Error con los datos recibidos al servicio') + + self.create_conection_to_db() + self.get_raw_pyg() + self.get_assessment_dates() + self.update_subs_classifications() + self.get_projections_information() + + self.organize_atributes() + self.organize_projection_data() + + return self.response_maker(succesfull_run = True) + except Exception as e: + + logger.error(f'[starter] Hubieron problemas en el comando de la linea: {get_current_error_line()}') + return self.response_maker(succesfull_run = False, error_str = (str(e))) + + + @handler_wrapper('Creando conexion a bd','Conexion a bd creada con exito','Error en la conexion a bd','Problemas creando la conexion a bd') + def create_conection_to_db(self): + if __name__ != 'lambda_function': + self.db_connection = connect_to_db_local_dev() + self.db_connection.begin() + return + db_schema = os.environ['DB_SCHEMA'] + secret_db_region = os.environ['SECRET_DB_REGION'] + secret_db_name = os.environ['SECRET_DB_NAME'] + db_secret = get_secret(secret_db_region, secret_db_name) + self.db_connection = connect_to_db(db_schema, db_secret) + + + @handler_wrapper('Realizando query de raw_pyg', 'Raw pyg obtenido correctamente', 'Error adquiriendo raw_pyg','Error adquiriendo identificadores de pyg') + def get_raw_pyg(self): + query = "SELECT * FROM RAW_PYG" + logger.info(f'[get_raw_pyg] Query para obtener los raw pyg: {query}') + rds_data = self.db_connection.execute(text(query)) + self.master_raw_pyg = {item.ID:item.PYG_ITEM_NAME for item in rds_data.fetchall()} + + + @handler_wrapper('Obteniendo las fechas del proceso de valoración', 'Fechas del proceso de valroación obtenidas con exito', 'Error obteniendo las fechas del proceso de valoración', 'Error obteniendo fechas del proceso de valoración') + def get_assessment_dates(self): + query = f"SELECT DATES, PROPERTY FROM ASSESSMENT_DATES WHERE ID_ASSESSMENT = {self.id_assessment} ORDER BY DATES" + logger.info(f"[get_assessment_dates] Query a base de datos para obtener las fechas utilizadas en el proces de valoración:\n {query}") + rds_data = self.db_connection.execute(text(query)) + directory = {'HISTORIC': self.historic_dates, 'PROJECTION': self.projection_dates} + for date_item in rds_data.fetchall(): + directory.get(date_item.PROPERTY, []).append(date_item.DATES) + + self.historic_dates = [date.strftime('%Y-%m-%d') for date in self.historic_dates] + if not self.projection_dates: + logger.info(f'[get_assessment_dates] Fechas del proceso de valoración:\nhistoricas: {self.historic_dates}\nAún no existen fechas de proyección') + return + self.projection_dates = [date.strftime('%Y') for date in self.projection_dates] #'%Y-%m-%d %H:%M:%S' + self.projection_dates[0] = self.projection_dates[0] if '-12-' in self.historic_dates[-1] else f'Diciembre {self.projection_dates[0]}' #Se agrega esta linea para que llegue diciembre con formato de anualización a front + logger.info(f'[get_assessment_dates] Fechas del proceso de valoración:\nhistoricas: {self.historic_dates}\nproyecciones: {self.projection_dates}') + + + @handler_wrapper('Adquiriendo las clasificaciones actualizadas', 'Clasificaciones de assessment actualizadas con exito', 'Error actualizando clasificaciones de assessment', 'Error comparando clasificaciones de assessment') + def update_subs_classifications(self): + #Se mapea cuales clasificaciones existen, para que si desapareció un sub de las clasificaciones, este no sea enviado al front de proyecciones pyg + query = f"""SELECT B.CLASSIFICATION, A.ANNUALIZED FROM CLASSIFICATION_SUMMARY A, RAW_CLASSIFICATION B, ARCHIVE C +WHERE A.ID_RAW_CLASSIFICATION = B.ID AND C.ID = A.ID_ARCHIVE AND A.ID_ASSESSMENT = :id_assessment ORDER BY C.INITIAL_DATE """ + + logger.info(f'[get_projections_information] Query para obtener proyecciones del proceso de valoracion:\n{query}') + rds_data = self.db_connection.execute(text(query), {'id_assessment': self.id_assessment}) + self.historic_data = [row._asdict() for row in rds_data.fetchall()] + self.updated_classifications = set(row['CLASSIFICATION'] for row in self.historic_data) + for row in self.historic_data: + row['ANNUALIZED'] = float(row['ANNUALIZED']) + + + @handler_wrapper('Realizando query a proyecciones del proceso de valoracion', 'Proyecciones adquiridas con exito', 'Error adquiriendo proyecciones de pyg', 'Error adquiriendo proyecciones') + def get_projections_information(self): + query = f"""SELECT C.PYG_ITEM_NAME, A.ID_DEPENDENCE, A.ORIGINAL_VALUE, A.PROJECTION_TYPE, A.`COMMENT`, B.PROJECTED_DATE, B.ATRIBUTE, B.VALUE, C.IS_SUB +FROM PYG_ITEM A, PROJECTED_PYG B, RAW_PYG C +WHERE A.ID_ASSESSMENT = B.ID_ASSESSMENT AND A.ID_RAW_PYG = B.ID_RAW_PYG AND A.ID_RAW_PYG = C.ID +AND C.PYG_ITEM_NAME NOT IN {str(self.accounts_to_skip)} +AND A.ID_ASSESSMENT = {self.id_assessment} ORDER BY A.ID_RAW_PYG, B.PROJECTED_DATE""" + + logger.info(f'[get_projections_information] Query para obtener proyecciones del proceso de valoracion: {query}') + rds_data = self.db_connection.execute(text(query)) + projection_data = [item._asdict() for item in rds_data.fetchall()] + for item in projection_data: + self.projections_found = True + item['value'] = float(item['ORIGINAL_VALUE']) + item['PYG_DEPENDANCE_NAME'] = self.master_raw_pyg[item['ID_DEPENDENCE']] + item['ATRIBUTE'] = float(item['ATRIBUTE']) if item['ATRIBUTE'].replace('.', '').replace('-','').isalnum() else '' + + self.projection_data = projection_data + logger.info(f'[get_projections_information] records de proyecciones:\n{projection_data}') + + + @handler_wrapper('Acomodando atribute values', 'Atribute values acomodados con exito', 'Error construyendo objetos de atributes de proyeccion anual', 'Error construyendo caracteristicas de proyeccion') + def organize_atributes(self): + self.atributes_dict = {classification: {'history': list(), 'projection': list()} for classification in self.updated_classifications.union(set(self.projections_order))} + + for classification in self.atributes_dict: + history_vector = [row['ANNUALIZED'] for row in self.historic_data if row['CLASSIFICATION'] == classification] + self.atributes_dict[classification]['history'] = history_vector if history_vector else [0] * len(self.historic_dates) + + projections_vector = [row['ATRIBUTE'] for row in self.projection_data if row['PYG_ITEM_NAME'] == classification] + self.atributes_dict[classification]['projection'] = projections_vector if projections_vector else [''] * len(self.projection_dates) + + for total, properties in self.pyg_totals.items(): + historic_dependance_vectors = self.calculate_total_vector(properties['dependencies'], properties['is_sum'], self.atributes_dict) + self.atributes_dict[total] = {'history': historic_dependance_vectors} + self.atributes_dict[total]['projection'] = [row['ATRIBUTE'] for row in self.projection_data if row['PYG_ITEM_NAME'] == total] + + + @debugger_wrapper('Error calculando sub total de tabla', 'Error calculando totales de proyecciones de pyg') + def calculate_total_vector(self, dependencies, vector_signs, search_in): + for dep in dependencies: + if dep not in search_in: + search_in[dep] = {'history': [0] * len(self.historic_dates)} + dependencies_vectors = [search_in[dependence]['history'] for dependence in dependencies] + partial_vector = [] + for year_values in zip(*dependencies_vectors): + year_total = 0 + for index, value in enumerate(year_values): + year_total = year_total + value * vector_signs[index] + partial_vector.append(year_total) + return partial_vector + + + @handler_wrapper('Organizando respuesta de proyecciones', 'Respuesta de proyecciones creada con exito', 'Error construyendo objeto final de respuesta', 'Error construyendo objeto de respuesta') + def organize_projection_data(self): + logger.warning(f'[organize_projection_data] Set de proyecciones encontrado:\n{self.updated_classifications}') + for item_name, is_parent in self.projections_order.items(): + if is_parent: + subs_to_use = sorted([item for item in self.updated_classifications if item.startswith(item_name) and item != item_name]) + self.organize_found_subs(subs_to_use) + else: + item_to_use = next((item for item in self.projection_data if item['PYG_ITEM_NAME'] == item_name ), self.first_time_projecting_object) + item_to_add = {'account': item_name, + 'accountProjector': item_to_use['PYG_DEPENDANCE_NAME'], + 'explication': item_to_use['COMMENT'], + 'method': item_to_use['PROJECTION_TYPE'], + 'atributes': self.atributes_dict[item_name]} + self.partial_response.append(item_to_add) + + + @debugger_wrapper('Error organizando paquete de subs', 'Error organizando paquete de subs') + def organize_found_subs(self, subs_package): + for sub_name in subs_package: + item_to_use = next((item for item in self.projection_data if item['PYG_ITEM_NAME'] == sub_name ), self.first_time_projecting_object) + if sub_name not in self.updated_classifications: + return + if sub_name in self.updated_classifications: + item_to_add = {'account': sub_name, + 'accountProjector': item_to_use['PYG_DEPENDANCE_NAME'], + 'explication': item_to_use['COMMENT'], + 'method': item_to_use['PROJECTION_TYPE'], + 'atributes': self.atributes_dict[sub_name]} + self.partial_response.append(item_to_add) + self.updated_classifications.discard(sub_name) + + + @debugger_wrapper('Error construyendo respuesta final', 'Error construyendo respuesta') + def response_maker(self, succesfull_run = False, error_str = str()): + if self.db_connection: + self.db_connection.close() + + if succesfull_run: + self.final_response['statusCode'] = 200 + self.final_response['body'] = json.dumps({'year': len(self.projection_dates),'datesHistory': self.historic_dates, 'datesProjections' : self.projection_dates, 'id_assessment': self.id_assessment, 'projection_data': self.partial_response}) + return self.final_response + + self.final_response['body'] = json.dumps(self.detailed_raise if self.detailed_raise else error_str) + return self.final_response + + + + +def get_current_error_line(): + return str(sys.exc_info()[-1].tb_lineno) + + +if __name__ == "__main__": + event = {"pathParameters": {"id_assessment": "55"}} + lambda_handler(event, '') + diff --git a/corporate_finances_back_py/pyg-projections-retrieve/utils.py b/corporate_finances_back_py/pyg-projections-retrieve/utils.py new file mode 100644 index 0000000..69381be --- /dev/null +++ b/corporate_finances_back_py/pyg-projections-retrieve/utils.py @@ -0,0 +1,53 @@ +#version 2023 - 05 - 04 +import base64 +import boto3 +import json +import logging +import os +from sqlalchemy import create_engine + +from decorators import handler_wrapper, debugger_wrapper + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + + +@debugger_wrapper('Error al obtener secreto','Error fatal de back conectando a base de datos') +def get_secret(secret_region, secret_name): + session = boto3.session.Session() + client_secrets_manager = session.client(service_name='secretsmanager', region_name=secret_region) + secret_data = client_secrets_manager.get_secret_value(SecretId=secret_name) + if 'SecretString' in secret_data: + secret_str = secret_data['SecretString'] + else: + secret_str = base64.b64decode(secret_data['SecretBinary']) + logger.info('[utils] (get_secret) Se obtuvo el secreto') + return json.loads(secret_str) + + +@debugger_wrapper('Error en la conexion a base de datos','Error fatal de back conectando a base de datos') +def connect_to_db(db_schema, db_secret): + conn_string = ('mysql+mysqlconnector://' + db_secret["username"] + ':' + db_secret["password"] + '@' + db_secret["host"] + ':' + str(db_secret["port"]) + '/' + db_schema) + sql_engine = create_engine(conn_string) + db_connection = sql_engine.connect() + return db_connection + + +@debugger_wrapper('Error en la conexion a base de datos','Error fatal de back conectando a base de datos') +def connect_to_db_local_dev(): + from dotenv import load_dotenv + load_dotenv() + conn_string = os.environ['local_dev_connector'] + sql_engine = create_engine(conn_string) + db_connection = sql_engine.connect() + return db_connection + + +@debugger_wrapper('Error en la conexion a base de datos','Error fatal de back conectando a base de datos') +def connect_to_db_local_dev(): + from dotenv import load_dotenv + load_dotenv() + conn_string = os.environ['local_dev_connector'] + sql_engine = create_engine(conn_string) + db_connection = sql_engine.connect() + return db_connection diff --git a/corporate_finances_back_py/pyg-retrieve/decorators.py b/corporate_finances_back_py/pyg-retrieve/decorators.py new file mode 100644 index 0000000..071760a --- /dev/null +++ b/corporate_finances_back_py/pyg-retrieve/decorators.py @@ -0,0 +1,63 @@ +#version 2023 - 05 - 04 +import logging +import sys +import traceback +from functools import wraps +from time import time + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + +def handler_wrapper(start, satisfactory_log, error_log, raise_error): + #esto se ejecuta en la inicializacion de primero + def decorator(func): + #print(message1) + #lo que yo ponga acá se ejecuta antes de hacer el llamado a la funcion + @wraps(func) + def wrapper(*args, **kwargs): + #esto sí se ejecuta solo cuando llama a la funcion decorada + #print(message2) + try: + logger.info(f'[{func.__name__}] {start}...') + resultado = func(*args, **kwargs) + logger.info(f'[{func.__name__}] {satisfactory_log}') + return resultado + except Exception as e: + logger.error(f"[{func.__name__}] {error_log}, linea: {get_especific_error_line(func.__name__)}, motivo: {str(e)}") + raise Exception(f"{raise_error}") + + return wrapper + return decorator + +def debugger_wrapper(error_log, raise_error): + def decorator(func): + @wraps(func) + def wrapper(*args, **kwargs): + try: + resultado = func(*args, **kwargs) + return resultado + except Exception as e: + logger.error(f"[{func.__name__}] {error_log}, linea: {get_especific_error_line(func.__name__)}, motivo: {str(e)}") + raise Exception(f"{raise_error}") + return wrapper + return decorator + + +def get_especific_error_line(func_name): + _, _, exc_tb = sys.exc_info() + for trace in traceback.extract_tb(exc_tb): + if func_name in trace: + return str(trace[1]) + +def timing(f): + @wraps(f) + def wrap(*args, **kw): + ts = time() + result = f(*args, **kw) + te = time() + taken_time_message = '[timing] La funcion {}, toma: {:.2f} sec en ejecutarse'.format(f.__name__, te-ts) + logger.info(taken_time_message) + return result + return wrap + + diff --git a/corporate_finances_back_py/pyg-retrieve/lambda_function.py b/corporate_finances_back_py/pyg-retrieve/lambda_function.py new file mode 100644 index 0000000..35b6703 --- /dev/null +++ b/corporate_finances_back_py/pyg-retrieve/lambda_function.py @@ -0,0 +1,205 @@ +import json +import logging +import sys +import os +from sqlalchemy import text + +from decorators import handler_wrapper, timing, debugger_wrapper +from utils import get_secret, connect_to_db, connect_to_db_local_dev + +logging.basicConfig() +logging.basicConfig(format='%(asctime)s [%(levelname)s] [%(module)s] %(message)s', force=True, datefmt='%Y-%m-%d %H:%M:%S') +logger = logging.getLogger() +logger.setLevel(logging.INFO) + +def lambda_handler(event,context): + sc_obj = script_object(event) + lambda_response = sc_obj.starter() + logger.info(f'respuesta final de lambda: \n{lambda_response}') + return lambda_response + + +class script_object: + def __init__(self, event): + try: + self.failed_init = False + self.final_response = {'headers':{'Access-Control-Allow-Headers': '*', + 'Access-Control-Allow-Origin': '*', + 'Access-Control-Allow-Methods': '*'}, "statusCode": 500, 'body': {}} + self.db_connection = 0 + self.detailed_raise = '' + self.partial_response = {} + + logger.warning(f'[__init__] Event de entrada:\n{str(event)}') + + event_dict = event['pathParameters'] + self.id_assessment = event_dict['id_assessment'] + + self.pyg_front_items = ["Ingresos operacionales", + "Costos (Sin depreciación)", + "Utilidad bruta", + "Gastos operacionales", + "Otros ingresos y egresos operativos", + "EBITDA", + "Depreciación Capex", + "Depreciación del Periodo", + "Amortización del Periodo", + "Deterioro", + "EBIT", + "Otros ingresos y egresos no operativos", + "Intereses/gasto financiero", + "Utilidad antes de impuestos", + "Impuestos de renta", + "Utilidad neta"] + self.pyg_parents = ['Ingresos operacionales', 'Gastos operacionales'] + + self.historic_dates = list() + self.projection_dates = list() + self.total_asssessment_dates = 0 + self.found_subs = list() + self.parents_sub_relations = dict() + self.pyg_rows_vectors = dict() + + + + + except Exception as e: + logger.error(f'[__init__] Error inicializando objeto lambda, linea: {get_current_error_line()}, motivo: {str(e)}') + self.failed_init = True + + def starter(self): + try: + if self.failed_init: + raise AttributeError('Error con los datos recibidos al servicio') + + self.create_conection_to_db() + self.get_assessment_dates() + self.get_pyg_results() + self.relate_parents_with_subs() + self.create_row_vectors() + self.organize_final_response() + + return self.response_maker(succesfull_run = True) + except Exception as e: + logger.error(f'[starter] Hubieron problemas en el comando de la linea: {get_current_error_line()}') + return self.response_maker(succesfull_run = False, error_str = (str(e))) + + + @handler_wrapper('Creando conexion a bd','Conexion a bd creada con exito','Error en la conexion a bd','Problemas creando la conexion a bd') + def create_conection_to_db(self): + if __name__ == "__main__": + self.db_connection = connect_to_db_local_dev() + return + db_schema = os.environ['DB_SCHEMA'] + secret_db_region = os.environ['SECRET_DB_REGION'] + secret_db_name = os.environ['SECRET_DB_NAME'] + db_secret = get_secret(secret_db_region, secret_db_name) + self.db_connection = connect_to_db(db_schema, db_secret) + + + @handler_wrapper('Obteniendo las fechas del proceso de valoración', 'Fechas del proceso de valroación obtenidas con exito', 'Error obteniendo las fechas del proceso de valoración', 'Error obteniendo fechas del proceso de valoración') + def get_assessment_dates(self): + query = f"SELECT DATES, PROPERTY FROM ASSESSMENT_DATES WHERE ID_ASSESSMENT = {self.id_assessment} ORDER BY DATES" + logger.info(f"[get_assessment_dates] Query a base de datos para obtener las fechas utilizadas en el proces de valoración:\n {query}") + rds_data = self.db_connection.execute(text(query)) + directory = {'HISTORIC': self.historic_dates, 'PROJECTION': self.projection_dates} + for date_item in rds_data.fetchall(): + directory.get(date_item.PROPERTY, []).append(date_item.DATES) + self.total_asssessment_dates = self.total_asssessment_dates +1 + + self.historic_dates = [date.strftime('%Y-%m-%d') for date in self.historic_dates] + self.projection_dates = [date.strftime('%Y') for date in self.projection_dates] #'%Y-%m-%d %H:%M:%S' + try: + self.projection_dates[0] = self.projection_dates[0] if '-12-' in self.historic_dates[-1] else f'Diciembre {self.projection_dates[0]}' #Se agrega esta linea para que llegue diciembre con formato de anualización a front + except: + pass + logger.info(f'[get_assessment_dates] Fechas del proceso de valoración:\nhistoricas: {self.historic_dates}\nproyecciones: {self.projection_dates}') + + + @handler_wrapper('Obteniendo los resultados calculados de pyg', 'Resultados calculados de pyg obtenidos con exito', 'Error obteniendo resultados de pyg', 'Error obteniendo resultados de pyg') + def get_pyg_results(self): + query = f"""SELECT B.PYG_ITEM_NAME AS name, B.IS_SUB, A.VALUE AS value, A.HINT FROM PYG_RESULTS A, RAW_PYG B +WHERE A.ID_RAW_PYG = B.ID AND A.ID_ASSESSMENT = {self.id_assessment} ORDER BY A.DATES""" + + logger.info(f"[get_pyg_results] Query a base de datos para obtener los resultados de pyg del proceso de valoración:\n {query}") + rds_data = self.db_connection.execute(text(query)) + self.pyg_data = [row._asdict() for row in rds_data.fetchall()] + for row in self.pyg_data: + row['value'] = float(row['value']) + if row['IS_SUB'] and row['name'] not in self.found_subs: + self.found_subs.append(row['name']) + + + @handler_wrapper('Relacionando cuentas padre con subs hallados', 'Relación construída', 'Error creando relación de cuentas padres con subs', 'Error analizando sub cuentas') + def relate_parents_with_subs(self): + for parent in self.pyg_parents: + self.parents_sub_relations[parent] = [sub for sub in self.found_subs if sub.startswith(parent)] + + + @handler_wrapper('Creando vectores para todos los resultados obtenidos de pyg', 'Vectores creados con exito', 'Error creando vectores de resultados', 'Error creando tabla de resultados') + def create_row_vectors(self): + current_all_rows = self.pyg_front_items + self.found_subs + for pyg_row in current_all_rows: + self.pyg_rows_vectors[pyg_row] = [{'value':item['value'], 'hint': item['HINT']} for item in self.pyg_data if item['name'] == pyg_row] + + dep_capex_vector = [item['value'] for item in self.pyg_data if item['name'] == "Depreciación Capex"] + logger.warning(f'[mira aca] {dep_capex_vector}') + if not any(dep_capex_vector): + self.shadowing_capex_dependant_projections() + del self.pyg_rows_vectors["Depreciación Capex"] + self.pyg_front_items.remove("Depreciación Capex") + + + @handler_wrapper('Ocultando proyecciones dependientes activos fijos y capex', 'Proyecciones ocultadas con éxito', 'Error ocultando proyecciones dependientes', 'Error ocultando resultados dependientes de capex') + def shadowing_capex_dependant_projections(self): + for pyg_row in ["Depreciación Capex", "Depreciación del Periodo", "Amortización del Periodo"]: + self.pyg_rows_vectors[pyg_row] = self.pyg_rows_vectors[pyg_row][:len(self.historic_dates)] + [-1] * len(self.projection_dates) + #del self.pyg_rows_vectors[pyg_row] + #del self.pyg_front_items[self.pyg_front_items.index(pyg_row)] + + + @handler_wrapper('Organizando respuesta final', 'Respuesta final organizada satisfactoriamente', 'Error organizando respuesta final', 'Error organizando respuesta de servicio') + def organize_final_response(self): + data = [] + for pyg_row in self.pyg_front_items: + if pyg_row in self.parents_sub_relations: + partial_parent_data = self.micro_pyg_object_creator(pyg_row) + partial_parent_data['subs'] = [] + for sub in self.parents_sub_relations[pyg_row]: + partial_parent_data['subs'].append(self.micro_pyg_object_creator(sub)) + data.append(partial_parent_data) + else: + data.append(self.micro_pyg_object_creator(pyg_row)) + + self.partial_response = {'datesHistory': self.historic_dates, 'datesProjection': self.projection_dates, 'data': data} + + + @debugger_wrapper('Error creando una linea de pyg', 'Error creando una de las lineas de pyg') + def micro_pyg_object_creator(self, pyg_row): + if not self.projection_dates: + return {'name': pyg_row, 'values': {'history': self.pyg_rows_vectors[pyg_row][:len(self.historic_dates)], 'projection': []}} + return {'name': pyg_row, 'values': {'history': self.pyg_rows_vectors[pyg_row][:len(self.historic_dates)], 'projection': self.pyg_rows_vectors[pyg_row][-1 * len(self.projection_dates):]}} + + + + @debugger_wrapper('Error construyendo respuesta final', 'Error construyendo respuesta') + def response_maker(self, succesfull_run = False, error_str = str()): + if self.db_connection: + self.db_connection.close() + if succesfull_run: + self.final_response['statusCode'] = 200 + self.final_response['body'] = json.dumps(self.partial_response) + return self.final_response + + self.final_response['body'] = json.dumps(self.detailed_raise if self.detailed_raise else error_str) + return self.final_response + + + +def get_current_error_line(): + return str(sys.exc_info()[-1].tb_lineno) + + +if __name__ == "__main__": + event = {"pathParameters": {"id_assessment": "2049"}} + lambda_handler(event, '') \ No newline at end of file diff --git a/corporate_finances_back_py/pyg-retrieve/utils.py b/corporate_finances_back_py/pyg-retrieve/utils.py new file mode 100644 index 0000000..6abae56 --- /dev/null +++ b/corporate_finances_back_py/pyg-retrieve/utils.py @@ -0,0 +1,44 @@ +#version 2023 - 05 - 04 +import base64 +import boto3 +import json +import logging +import os +from sqlalchemy import create_engine + +from decorators import debugger_wrapper + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + + +@debugger_wrapper('Error al obtener secreto','Error fatal de back conectando a base de datos') +def get_secret(secret_region, secret_name): + session = boto3.session.Session() + client_secrets_manager = session.client(service_name='secretsmanager', region_name=secret_region) + secret_data = client_secrets_manager.get_secret_value(SecretId=secret_name) + if 'SecretString' in secret_data: + secret_str = secret_data['SecretString'] + else: + secret_str = base64.b64decode(secret_data['SecretBinary']) + logger.info('[utils] (get_secret) Se obtuvo el secreto') + return json.loads(secret_str) + + +@debugger_wrapper('Error en la conexion a base de datos','Error fatal de back conectando a base de datos') +def connect_to_db(db_schema, db_secret): + conn_string = ('mysql+mysqlconnector://' + db_secret["username"] + ':' + db_secret["password"] + '@' + db_secret["host"] + ':' + str(db_secret["port"]) + '/' + db_schema) + sql_engine = create_engine(conn_string) + db_connection = sql_engine.connect() + return db_connection + + +@debugger_wrapper('Error en la conexion a base de datos','Error fatal de back conectando a base de datos') +def connect_to_db_local_dev(): + from dotenv import load_dotenv + load_dotenv() + conn_string = os.environ['local_dev_connector'] + sql_engine = create_engine(conn_string) + db_connection = sql_engine.connect() + return db_connection + diff --git a/corporate_finances_back_py/requirements.txt b/corporate_finances_back_py/requirements.txt new file mode 100644 index 0000000..ee0d161 --- /dev/null +++ b/corporate_finances_back_py/requirements.txt @@ -0,0 +1,8 @@ +pandas +sqlalchemy +python-dotenv +jwt +requests +cryptography +xlsxwriter +mysql-connector-python \ No newline at end of file diff --git a/corporate_finances_back_py/skipped-classifications-checker/decorators.py b/corporate_finances_back_py/skipped-classifications-checker/decorators.py new file mode 100644 index 0000000..071760a --- /dev/null +++ b/corporate_finances_back_py/skipped-classifications-checker/decorators.py @@ -0,0 +1,63 @@ +#version 2023 - 05 - 04 +import logging +import sys +import traceback +from functools import wraps +from time import time + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + +def handler_wrapper(start, satisfactory_log, error_log, raise_error): + #esto se ejecuta en la inicializacion de primero + def decorator(func): + #print(message1) + #lo que yo ponga acá se ejecuta antes de hacer el llamado a la funcion + @wraps(func) + def wrapper(*args, **kwargs): + #esto sí se ejecuta solo cuando llama a la funcion decorada + #print(message2) + try: + logger.info(f'[{func.__name__}] {start}...') + resultado = func(*args, **kwargs) + logger.info(f'[{func.__name__}] {satisfactory_log}') + return resultado + except Exception as e: + logger.error(f"[{func.__name__}] {error_log}, linea: {get_especific_error_line(func.__name__)}, motivo: {str(e)}") + raise Exception(f"{raise_error}") + + return wrapper + return decorator + +def debugger_wrapper(error_log, raise_error): + def decorator(func): + @wraps(func) + def wrapper(*args, **kwargs): + try: + resultado = func(*args, **kwargs) + return resultado + except Exception as e: + logger.error(f"[{func.__name__}] {error_log}, linea: {get_especific_error_line(func.__name__)}, motivo: {str(e)}") + raise Exception(f"{raise_error}") + return wrapper + return decorator + + +def get_especific_error_line(func_name): + _, _, exc_tb = sys.exc_info() + for trace in traceback.extract_tb(exc_tb): + if func_name in trace: + return str(trace[1]) + +def timing(f): + @wraps(f) + def wrap(*args, **kw): + ts = time() + result = f(*args, **kw) + te = time() + taken_time_message = '[timing] La funcion {}, toma: {:.2f} sec en ejecutarse'.format(f.__name__, te-ts) + logger.info(taken_time_message) + return result + return wrap + + diff --git a/corporate_finances_back_py/skipped-classifications-checker/lambda_function.py b/corporate_finances_back_py/skipped-classifications-checker/lambda_function.py new file mode 100644 index 0000000..17f3c51 --- /dev/null +++ b/corporate_finances_back_py/skipped-classifications-checker/lambda_function.py @@ -0,0 +1,151 @@ +""": +capas: +capa-pandas-data-transfer + +variables de entorno: +DB_SCHEMA : src_corporate_finance +RAW_CLASSIFICATION_TABLE : RAW_CLASSIFICATION +SECRET_DB_NAME : precia/rds8/sources/finanzas_corporativas +SECRET_DB_REGION : us-east-1 + +RAM: 1024 MB + +""" + +import json +import logging +import sys +import traceback +import time +import copy +from utils import * +import pandas as pd +from decorators import handler_wrapper, timing +import os + +#logging.basicConfig() #En lambdas borra este +logger = logging.getLogger() +logger.setLevel(logging.INFO) + + +def lambda_handler(event, context): + lo = lambda_object(event) + return lo.starter() + + +class lambda_object(): + + @handler_wrapper('Obteniendo valores clave de event', 'Valores de event obtenidos correctamente', + 'Error al obtener valores event', 'Fallo en la obtencion de valores clave de event') + def __init__(self, event) -> None: + logger.warning(f'event que llega a la lambda: {str(event)}') + + self.raw_classifications_table = os.environ['RAW_CLASSIFICATION_TABLE'] + + event_body_json = event["body"] + event_body_dict = json.loads(event_body_json) + + self.data_oriented_index = event_body_dict['data'] + + self.received_classifications_set = set() + + self.raw_classification_data = list() + self.raw_classification_names = list() + + self.unused_classifications = list() + + self.non_alerted_classificacitions = ['No aplica', + 'Ingresos operacionales 1', + 'Ingresos operacionales 2', + 'Ingresos operacionales 3', + 'Ingresos operacionales 4', + 'Ingresos operacionales 5', + 'Gastos operacionales 1', + 'Gastos operacionales 2', + 'Gastos operacionales 3', ] #acá toca ver si el qa quiere omitir cartera + self.final_response = {'headers':{'Access-Control-Allow-Headers': '*', 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Methods': '*'}} + + + def starter(self): + try: + logger.info(f'[starter] Empezando starter de objeto lambda') + self.create_conection_to_resources() + self.get_classification_raw_info() + self.group_received_classifications() + self.classification_filter() + + self.db_connection.close() + return self.response_maker(succesfull = True) + + except Exception as e: + if self.db_connection: + self.db_connection.close() + logger.error(f'[starter] Error en el procesamieno del comando de la linea: {get_current_error_line()}, motivo: {e}') + return self.response_maker(succesfull = False, exception_str = str(e)) + + + @handler_wrapper('Creando conexion a bd','Conexion a bd creada con exito','Error en la conexion a bd','Problemas creando la conexion a bd') + def create_conection_to_resources(self): + db_schema = os.environ['DB_SCHEMA'] + secret_db_region = os.environ['SECRET_DB_REGION'] + secret_db_name = os.environ['SECRET_DB_NAME'] + db_secret = get_secret(secret_db_region, secret_db_name) + self.db_connection = connect_to_db(db_schema, db_secret) + + + @handler_wrapper('Trayendo todas las clasificaciones en raw_classifications','Clasificaciones obtenidas con exito', 'Error obteniendo clasificaciones raw', 'Error obteniendo clasificaciones raw') + def get_classification_raw_info(self): + query = f"SELECT * FROM {self.raw_classifications_table}" + logger.info(f'[get_classification_raw_info] Query para obtener las clasificaciones raw: {query}') + query_result = self.db_connection.execute(query).mappings().all() + raw_classification_data = [dict(item) for item in query_result] + + non_parent_items = list(filter(lambda item: item['IS_PARENT'] == 0, raw_classification_data)) + self.non_parent_classification_names = [item['CLASSIFICATION'] for item in non_parent_items] + + is_parent_items = list(filter(lambda item: item['IS_PARENT'] == 1, raw_classification_data)) + self.is_parent_classification_names = [item['CLASSIFICATION'] for item in is_parent_items] + + + @handler_wrapper('obteniendo set de clasificaciones recibidas', 'Set de clasificaciones recibidas calculado', 'Error encontrando agrupando las clasificaciones recibidas', 'Error de datos recibidos') + def group_received_classifications(self): + self.received_classifications_set = list(set(item['classification'] for item in self.data_oriented_index)) + logger.info(f'[group_received_classifications] set de clasificaciones encontradas:\n {self.received_classifications_set}') + + + @handler_wrapper('Inicializando filtrador de clasificaciones', 'Filtrador de clasificaciones terminado con exito', 'Error en el filtrador de clasificaciones', 'Error filtrando informacion') + def classification_filter(self): + for classification in self.non_alerted_classificacitions: + self.non_parent_classification_names.remove(classification) + + logger.warning(f'Longitud de non parents antes de filtro: {len(self.non_parent_classification_names)}') + self.non_parent_classification_names = list(filter(lambda item: item not in self.received_classifications_set, self.non_parent_classification_names)) + logger.warning(f'Longitud de non parents despues de filtro: {len(self.non_parent_classification_names)}') + + logger.warning(f'Longitud de parents antes de filtro: {len(self.is_parent_classification_names)}') + self.is_parent_classification_names = list(filter(self.check_parents_startwith, self.is_parent_classification_names)) + logger.warning(f'Longitud de parents despues de filtro: {len(self.is_parent_classification_names)}') + + self.skipped_classification = self.non_parent_classification_names + self.is_parent_classification_names + + + def check_parents_startwith(self, parent): + for received_classification in self.received_classifications_set: + if received_classification.startswith(parent): + return False + return True + + + def response_maker(self, succesfull = False, exception_str = str): + if not succesfull: + self.final_response['body'] = json.dumps(exception_str) + return self.final_response + else: + self.final_response['body'] = json.dumps(self.skipped_classification) + return self.final_response + + + +def get_current_error_line(): + return str(sys.exc_info()[-1].tb_lineno) + diff --git a/corporate_finances_back_py/skipped-classifications-checker/utils.py b/corporate_finances_back_py/skipped-classifications-checker/utils.py new file mode 100644 index 0000000..9efbdea --- /dev/null +++ b/corporate_finances_back_py/skipped-classifications-checker/utils.py @@ -0,0 +1,33 @@ +#version 2023 - 05 - 04 +import base64 +import boto3 +import json +import logging + +from sqlalchemy import create_engine + +from decorators import handler_wrapper, debugger_wrapper + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + + +@debugger_wrapper('Error al obtener secreto','Error fatal de back conectando a base de datos') +def get_secret(secret_region, secret_name): + session = boto3.session.Session() + client_secrets_manager = session.client(service_name='secretsmanager', region_name=secret_region) + secret_data = client_secrets_manager.get_secret_value(SecretId=secret_name) + if 'SecretString' in secret_data: + secret_str = secret_data['SecretString'] + else: + secret_str = base64.b64decode(secret_data['SecretBinary']) + logger.info('[utils] (get_secret) Se obtuvo el secreto') + return json.loads(secret_str) + + +@debugger_wrapper('Error en la conexion a base de datos','Error fatal de back conectando a base de datos') +def connect_to_db(db_schema, db_secret): + conn_string = ('mysql+mysqlconnector://' + db_secret["username"] + ':' + db_secret["password"] + '@' + db_secret["host"] + ':' + str(db_secret["port"]) + '/' + db_schema) + sql_engine = create_engine(conn_string) + db_connection = sql_engine.connect() + return db_connection \ No newline at end of file diff --git a/corporate_finances_back_py/status-seeker/decorators.py b/corporate_finances_back_py/status-seeker/decorators.py new file mode 100644 index 0000000..071760a --- /dev/null +++ b/corporate_finances_back_py/status-seeker/decorators.py @@ -0,0 +1,63 @@ +#version 2023 - 05 - 04 +import logging +import sys +import traceback +from functools import wraps +from time import time + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + +def handler_wrapper(start, satisfactory_log, error_log, raise_error): + #esto se ejecuta en la inicializacion de primero + def decorator(func): + #print(message1) + #lo que yo ponga acá se ejecuta antes de hacer el llamado a la funcion + @wraps(func) + def wrapper(*args, **kwargs): + #esto sí se ejecuta solo cuando llama a la funcion decorada + #print(message2) + try: + logger.info(f'[{func.__name__}] {start}...') + resultado = func(*args, **kwargs) + logger.info(f'[{func.__name__}] {satisfactory_log}') + return resultado + except Exception as e: + logger.error(f"[{func.__name__}] {error_log}, linea: {get_especific_error_line(func.__name__)}, motivo: {str(e)}") + raise Exception(f"{raise_error}") + + return wrapper + return decorator + +def debugger_wrapper(error_log, raise_error): + def decorator(func): + @wraps(func) + def wrapper(*args, **kwargs): + try: + resultado = func(*args, **kwargs) + return resultado + except Exception as e: + logger.error(f"[{func.__name__}] {error_log}, linea: {get_especific_error_line(func.__name__)}, motivo: {str(e)}") + raise Exception(f"{raise_error}") + return wrapper + return decorator + + +def get_especific_error_line(func_name): + _, _, exc_tb = sys.exc_info() + for trace in traceback.extract_tb(exc_tb): + if func_name in trace: + return str(trace[1]) + +def timing(f): + @wraps(f) + def wrap(*args, **kw): + ts = time() + result = f(*args, **kw) + te = time() + taken_time_message = '[timing] La funcion {}, toma: {:.2f} sec en ejecutarse'.format(f.__name__, te-ts) + logger.info(taken_time_message) + return result + return wrap + + diff --git a/corporate_finances_back_py/status-seeker/lambda_function.py b/corporate_finances_back_py/status-seeker/lambda_function.py new file mode 100644 index 0000000..fadcb0a --- /dev/null +++ b/corporate_finances_back_py/status-seeker/lambda_function.py @@ -0,0 +1,136 @@ +import json +import logging +import sys +import os +import datetime +from decorators import handler_wrapper, timing, debugger_wrapper +from utils import get_secret, connect_to_db + + +#logging.basicConfig() #En lambdas borra este + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + + +def lambda_handler(event,context): + sc_obj = script_object(event) + lambda_response = sc_obj.starter() + logger.info(f'respuesta final de lambda: \n{lambda_response}') + return lambda_response + + +class script_object: + def __init__(self, event): + try: + self.failed_init = False + logger.info(f'Event que llega:\n{event}') + self.final_response = {'headers':{'Access-Control-Allow-Headers': '*', + 'Access-Control-Allow-Origin': '*', + 'Access-Control-Allow-Methods': '*'}, "statusCode": 500, 'body': {}} + self.db_connection = 0 + self.detailed_raise = '' + self.partial_response = list() + + event_dict = event['pathParameters'] + self.id_assessment = event_dict['id-assessment'] + + self.orchestrator_status = str() + self.found_notes = list() + + logger.warning(f'event de entrada: {str(event)}') + + + except Exception as e: + logger.error(f'[__init__] Error inicializando objeto lambda, linea: {get_current_error_line()}, motivo: {str(e)}') + self.failed_init = True + + def starter(self): + try: + if self.failed_init: + raise AttributeError('Error con los datos recibidos al servicio') + self.create_conection_to_db() + self.acquire_orchestrator_status() + #[TIMEOUT, ERROR, SUCCES, WORKING] + if self.orchestrator_status in ['SUCCES', 'ERROR']: + self.acquire_orchestrator_notes() + if self.delta_time > datetime.timedelta(seconds=30): + self.acquire_orchestrator_notes() + self.orchestrator_status = 'TIMEOUT' + + self.organize_partial_response() + + return self.response_maker(succesfull_run = True) + + except Exception as e: + logger.error(f'[starter] Hubieron problemas en el comando de la linea: {get_current_error_line()}') + return self.response_maker(succesfull_run = False, error_str = (str(e))) + + @handler_wrapper('Creando conexion a bd','Conexion a bd creada con exito','Error en la conexion a bd','Problemas creando la conexion a bd') + def create_conection_to_db(self): + db_schema = os.environ['DB_SCHEMA'] + secret_db_region = os.environ['SECRET_DB_REGION'] + secret_db_name = os.environ['SECRET_DB_NAME'] + db_secret = get_secret(secret_db_region, secret_db_name) + self.db_connection = connect_to_db(db_schema, db_secret) + + + @handler_wrapper('Adquiriendo el status del Engine de recalculo', 'Datos adquiridos con exito', 'Error adquiriendo el status del orquestador', 'Error adquiriendo status') + def acquire_orchestrator_status(self): + query = f"""SELECT STATE, LAST_STATE_TS FROM ORCHESTRATOR_STATUS WHERE ID_ASSESSMENT = {self.id_assessment}""" + logger.info(f'[get_capex_data] Query para obtener status del proceso de valoración:\n{query}') + rds_data = self.db_connection.execute(query) + self.orchestrator_status_info = next(item._asdict() for item in rds_data.fetchall()) + self.orchestrator_status = self.orchestrator_status_info['STATE'] + orchestrator_last_timestamp = self.orchestrator_status_info['LAST_STATE_TS'] + now_time = datetime.datetime.now() + self.delta_time = now_time - orchestrator_last_timestamp + logger.info(f'[acquire_orchestrator_status] Resultados de status query:\n{self.orchestrator_status_info}') + logger.info(f'[mira aca] {now_time} - {orchestrator_last_timestamp}') + logger.warning(f'[deltatime]: {self.delta_time}') + + + @handler_wrapper('Es posible que hayan notas de orquestador; adquiriendo', 'Adquisición de notas terminado', 'Error adquiriendo anotaciones del orquestador', 'Error chqeuando anotaciones') + def acquire_orchestrator_notes(self): + condensed_contexts = ('Pyg', 'Proyecciones pyg') + query = f"""SELECT TASK, NOTE FROM NOTES WHERE ID_ASSESSMENT = {self.id_assessment}""" + logger.info(f'[acquire_orchestrator_notes] Query para obtener notas de orquestador para el proceso de valoración:\n{query}') + + rds_data = self.db_connection.execute(query) + found_notes = [item._asdict() for item in rds_data.fetchall()] + logger.warning(f'[mira aca] found_notes recien salido: {found_notes}') + contexts_set = list(set(item['TASK'] for item in found_notes if not item['TASK'].startswith(condensed_contexts))) + contexts_set = sorted(contexts_set + list(condensed_contexts)) + + self.found_notes = [] + for context in contexts_set: + logger.info(f'[mira aca] buscando {context} en \n{found_notes}') + context_notes = [item['NOTE'] for item in found_notes if item['TASK'].startswith(context)] + if context_notes: + self.found_notes.append({'context': context, 'notes': context_notes}) + + + @handler_wrapper('Organizando respuesta a front', 'Respuesta a front organizada', 'Error organizando respuesta a front', 'Error organizando respuesta') + def organize_partial_response(self): + self.partial_response = {'status': self.orchestrator_status} + if self.found_notes: + self.partial_response['notes'] = self.found_notes + + + @debugger_wrapper('Error construyendo respuesta final', 'Error construyendo respuesta') + def response_maker(self, succesfull_run = False, error_str = str()): + if self.db_connection: + self.db_connection.close() + if succesfull_run: + self.final_response['statusCode'] = 200 + self.final_response['body'] = json.dumps(self.partial_response) + return self.final_response + + self.final_response['body'] = json.dumps(self.detailed_raise if self.detailed_raise else error_str) + return self.final_response + + + +def get_current_error_line(): + return str(sys.exc_info()[-1].tb_lineno) + \ No newline at end of file diff --git a/corporate_finances_back_py/status-seeker/utils.py b/corporate_finances_back_py/status-seeker/utils.py new file mode 100644 index 0000000..a04bb54 --- /dev/null +++ b/corporate_finances_back_py/status-seeker/utils.py @@ -0,0 +1,44 @@ +#version 2023 - 05 - 04 +import base64 +import boto3 +import json +import logging + +from sqlalchemy import create_engine + +from decorators import handler_wrapper, debugger_wrapper + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + + +@debugger_wrapper('Error al obtener secreto','Error fatal de back conectando a base de datos') +def get_secret(secret_region, secret_name): + session = boto3.session.Session() + client_secrets_manager = session.client(service_name='secretsmanager', region_name=secret_region) + secret_data = client_secrets_manager.get_secret_value(SecretId=secret_name) + if 'SecretString' in secret_data: + secret_str = secret_data['SecretString'] + else: + secret_str = base64.b64decode(secret_data['SecretBinary']) + logger.info('[utils] (get_secret) Se obtuvo el secreto') + return json.loads(secret_str) + + +@debugger_wrapper('Error en la conexion a base de datos','Error fatal de back conectando a base de datos') +def connect_to_db(db_schema, db_secret): + conn_string = ('mysql+mysqlconnector://' + db_secret["username"] + ':' + db_secret["password"] + '@' + db_secret["host"] + ':' + str(db_secret["port"]) + '/' + db_schema) + sql_engine = create_engine(conn_string) + db_connection = sql_engine.connect() + return db_connection + + +@handler_wrapper('Invocando asincronamente a Engine de dinamismo', 'Invocación a Engine exitosa', 'Error invocando a Engine', 'Error invocando dinamismo') +def call_dynamic_engine(id_assessment): + data = json.dumps({'id_assessment':id_assessment}).encode() + client = boto3.client('lambda') + response = client.invoke( + FunctionName='lbd-dev-finanzas-super-orchestrator', + InvocationType='Event', + Payload= data +) diff --git a/corporate_finances_back_py/super-orchestrator/_calc_assessment.py b/corporate_finances_back_py/super-orchestrator/_calc_assessment.py new file mode 100644 index 0000000..69c9381 --- /dev/null +++ b/corporate_finances_back_py/super-orchestrator/_calc_assessment.py @@ -0,0 +1,189 @@ + +from dataclasses_box import fclo_object, calculated_assessment_object, asdict +from decorators import handler_wrapper, timing, debugger_wrapper +import logging +from datetime import datetime, timedelta +import sys +import math +import numpy as np + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + + +class assessment_class(): + + @handler_wrapper('Actualizando ventana de valoración', 'Ventana de valoración recalculada con exito', 'Error actualizando ventana de valoración', 'Error actualizando ventana de valoración') + def assessment_recalc(self): + if not self.assessment_models['MODEL_CALCULATED_ASSESSMENT']: + logger.warning('[assessment_recalc] No se encontró modelo de la pantalla de valoración') + return + self.assessment_info = self.assessment_models['MODEL_CALCULATED_ASSESSMENT'][0] + self.assessment_dates_manager() + self.flux_discount() + self.company_value() + self.assets_passives_adjust() + self.organize_calculated_assessment_record() + self.organize_fclo_record() + + self.df_and_upload(self.calculated_assessment_record, 'CALCULATED_ASSESSMENT') + self.df_and_upload(self.fclo_records, 'FCLO_DISCOUNT') + + self.save_assessment_step("VALORATION") + + + @handler_wrapper('Acomodando fechas para ajuste de la pantalla de valoración', 'Fechas recalculadas con éxito', 'Error recalculando fechas de la ventana de valoración', 'Error calculando fechas de la ventana de valoración') + def assessment_dates_manager(self): + false_user_assessment_date = self.assessment_info['ASSESSMENT_DATE'] + false_assessment_initial_date = self.assessment_info['INITIAL_DATE'] + delting_assessment_time = (false_user_assessment_date - false_assessment_initial_date) + + self.user_assessment_date = datetime.strptime(self.assessment_initial_date, '%Y-%m-%d %H:%M:%S') + delting_assessment_time #Fecha de publicacion + + starting_year = max(datetime.strptime(self.assessment_initial_date, '%Y-%m-%d %H:%M:%S'), self.user_assessment_date).replace(day = 1, month = 1) + self.current_closing_date = starting_year.replace(day = 31, month = 12) + + self.current_half_period = self.user_assessment_date + (self.current_closing_date-self.user_assessment_date)/2 + self.next_half_period = self.current_closing_date + timedelta(days = 180) + self.next_half_period = self.next_half_period.replace(day = 30, month = 6) + self.dates_adjust_num = (datetime.combine(self.user_assessment_date, datetime.min.time()).timestamp() - datetime.strptime(self.assessment_initial_date, '%Y-%m-%d %H:%M:%S').timestamp()) /30 + self.dates_adjust_den = (datetime.combine(self.current_closing_date, datetime.min.time()).timestamp() - datetime.strptime(self.assessment_initial_date, '%Y-%m-%d %H:%M:%S').timestamp()) / 30 + + if delting_assessment_time.total_seconds() == 0: + self.dates_adjust = 1 if '-12-' in self.assessment_initial_date else 0 + else: + try: + self.dates_adjust = round(self.dates_adjust_num/(24*3600)) / round(self.dates_adjust_den/(24*3600)) + except Exception as e: + logger.debug(f'[assessment_dates_manager] El error de esta division de ajuste es: {str(e)}') + self.dates_adjust = 1 + logger.info(f"""[assessment_dates_manager] Salida de fechas: +Fechas de valoración: {self.user_assessment_date} +Fecha de corte de información: {self.assessment_initial_date} +Cierre periodo flujo actual: {self.current_closing_date} +periodo intermedio de flujos: {self.current_half_period} +Mitad de año, flujo siguiente: {self.next_half_period} +Numerador de ajuste: {self.dates_adjust_num} +Denominador de ajuste: {self.dates_adjust_den} +Ajuste por fechas: {self.dates_adjust}""") + print('Debug prueba') + + @handler_wrapper('Calculando flujos de descuento', 'Flujos de descuento calculados con exito', 'Error calculando flujos de descuento', 'Error calculando flujos de descuento') + def flux_discount(self): + cash_flow_chosen_vector = self.cash_flow_table[self.assessment_info['CHOSEN_FLOW_NAME']] + self.free_operational_cash_flow = cash_flow_chosen_vector[self.historic_dates_len-1:] + logger.debug(f'[flux_discount] vector que se va a manejar: {self.free_operational_cash_flow}') + self.free_operational_cash_flow[0] = self.free_operational_cash_flow[0] if '-12-' in self.historic_dates_long[-1] else self.free_operational_cash_flow[1] - self.free_operational_cash_flow.pop(0) + + self.free_operational_cash_flow[0] = self.free_operational_cash_flow[0] * (1 - self.dates_adjust) + discount_for_period1 = days360(self.user_assessment_date, self.current_closing_date) + discount_for_period1 = discount_for_period1/720 + + discount_for_period2 = days360(self.current_half_period, self.next_half_period) + discount_for_period2 = discount_for_period2/360 + + if datetime.strptime(self.assessment_initial_date, '%Y-%m-%d %H:%M:%S').year == self.user_assessment_date.year: + self.discount_for_period = [discount_for_period1, discount_for_period2] + [1] * self.projection_dates_len + else: + self.discount_for_period = [0] + [discount_for_period1, discount_for_period2] + [1] * (self.projection_dates_len-1) + + + self.discount_rates = [float(item['DISCOUNT_RATE'])/100 for item in self.assessment_models['MODEL_FCLO_DISCOUNT']] + self.discount_factor = [1] + for index, (i, j) in enumerate(zip(self.discount_rates, self.discount_for_period), start=1): + self.discount_factor.append(self.discount_factor[index-1] * np.power(1/(1+i), j)) + self.discount_factor = self.discount_factor[1:] + + self.discounted_fclo = [i * j for i,j in zip(self.discount_factor, self.free_operational_cash_flow)] + + logger.info(f"""[flux_discount] +Vector de periodo de descuento: {self.discount_for_period} +Tasas de descuento manuales:{self.discount_rates} +Factor de descuento: {self.discount_factor} +Vector de caja libre operacional: {self.free_operational_cash_flow} +FCLO descontado: {self.discounted_fclo}""") + + + @handler_wrapper('Calculando valor de la empresa', 'Valor de la empresa calculado con exito', 'Error calculando valor de la empresa', 'Error calcuiando valor de empresa') + def company_value(self): + self.vp_flux = round(sum(self.discounted_fclo), 2) + gradient = float(self.assessment_info['GRADIENT'])/100 + self.normalized_cash_flow = self.free_operational_cash_flow[-1] * (1+gradient) + self.terminal_value = self.normalized_cash_flow / (self.discount_rates[-1] - gradient) + self.vp_terminal_value = self.terminal_value * self.discount_factor[-1] + + + self.enterprise_value = float(self.vp_flux + self.vp_terminal_value) + logger.info(f"""[company_value] +VP flujos: {self.vp_flux} +Flujo de caja normalizado: {self.normalized_cash_flow} +valor terminal: {self.terminal_value} +vp valor terminal: {self.vp_terminal_value} +valor de empresa: {self.enterprise_value} +Gradiente: {gradient} +Tasa de descuento: {self.discount_rates[-1]} +""") + + + @handler_wrapper('Calculando ajuste por activos y pasivos', 'Ajuste de activos y pasivos calculado', 'Error calculando ajuste por activos y pasivos', 'Error calculando ajuste por activos y pasivos') + def assets_passives_adjust(self): + logger.info(f'mira aca este objeto: {self.assessment_info}') + if self.assessment_info['ADJUST_METHOD'] == 'Automatico': + self.non_operational_assets = self.get_historic_summary_values('Efectivo y no operacionales')[-1] + self.operational_passives = self.get_historic_summary_values('Deuda con costo financiero')[-1] + else: + self.non_operational_assets = self.assessment_info['TOTAL_NOT_OPERATIONAL_ASSETS'] + self.operational_passives = self.assessment_info['TOTAL_OPERATIONAL_PASIVES'] + self.financial_adjust = float(self.non_operational_assets - self.operational_passives) + + self.patrimony_value = self.enterprise_value + self.financial_adjust + + self.stock_value = self.patrimony_value/self.assessment_info['OUTSTANDING_SHARES'] + + logger.info(f"""[assets_passives_adjust] Resultados de pantalla de valoración: +Activos no operacionales: {self.non_operational_assets} +Pasivos no operacionales: {self.operational_passives} +Ajuste de activos y pasivos: {self.financial_adjust} +valor patrimonial: {self.patrimony_value} +Valor por acción: {self.stock_value} con {self.assessment_info['OUTSTANDING_SHARES']} acciones""") + @handler_wrapper('Organizando record de CALCULATED_ASSESSMENT', 'Record de calculated assessment construido', 'Error construyendo record de calculated assessment', 'Error actualizando propiedades de ventana de valoraciòn') + def organize_calculated_assessment_record(self): + self.calculated_assessment_record = [asdict(calculated_assessment_object(self.user_assessment_date, self.assessment_initial_date, self.current_closing_date, self.current_half_period, self.next_half_period, self.dates_adjust, self.assessment_info['DATES_ADJUST_COMMENT'], + self.assessment_info['CHOSEN_FLOW_NAME'], 'False', 'False', + self.vp_flux, self.assessment_info['GRADIENT'], self.normalized_cash_flow, str(self.discount_rates[-1]*100), self.terminal_value, str(self.discount_factor[-1]), self.vp_terminal_value, self.enterprise_value, + self.financial_adjust, self.non_operational_assets, self.operational_passives, 'False', 'False', + self.patrimony_value, self.assessment_info['OUTSTANDING_SHARES'], self.stock_value, self.assessment_info['ADJUST_METHOD']))] + + + @handler_wrapper('Organizando records de FCLO', 'Records de fclo construidos', 'Error construyendo records de tabla fclo', 'Error actualizando propiedades de FCLO') + def organize_fclo_record(self): + self.discount_rates = [item * 100 for item in self.discount_rates] + self.fclo_records = [asdict(fclo_object(*items)) for items in zip(self.all_dates_long[self.historic_dates_len-1:], self.free_operational_cash_flow, self.discount_for_period, self.discount_rates, self.discount_factor, self.discounted_fclo)] + + +def get_current_error_line(): + return str(sys.exc_info()[-1].tb_lineno) + + +def days360(start_date, end_date, method_eu=False): + start_day = start_date.day + start_month = start_date.month + start_year = start_date.year + end_day = end_date.day + end_month = end_date.month + end_year = end_date.year + + if (start_day == 31 or (method_eu is False and start_month == 2 and (start_day == 29 or (start_day == 28 and start_date.is_leap_year is False)))): + start_day = 30 + if end_day == 31: + if method_eu is False and start_day != 30: + end_day = 1 + if end_month == 12: + end_year += 1 + end_month = 1 + else: + end_month += 1 + else: + end_day = 30 + + return (end_day + end_month * 30 + end_year * 360 - start_day - start_month * 30 - start_year * 360) \ No newline at end of file diff --git a/corporate_finances_back_py/super-orchestrator/_calc_capex_summary.py b/corporate_finances_back_py/super-orchestrator/_calc_capex_summary.py new file mode 100644 index 0000000..40d3db4 --- /dev/null +++ b/corporate_finances_back_py/super-orchestrator/_calc_capex_summary.py @@ -0,0 +1,166 @@ +from decorators import handler_wrapper, timing, debugger_wrapper +import logging +import pandas as pd +import datetime +import sys +from _orchester_utils import acute +from dataclasses_box import capex_summary_object, asdict + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + + +class capex_summary_class(object): + @handler_wrapper("Actualizando datos de nuevo capex", "Nuevo capex calculado con exito", "Error actualizando resultados de nuevo capex", "Error actualizando capex") + def capex_summary_recalc(self): + #if not self.assessment_models.get("MODEL_CAPEX", False): + # logger.warning("[new_capex_recalc] No hay atributos para las proyecciones de capex") + # self.assessment_projections_found = False + # return + + self.capex_summary_vectors = { + "Depreciación del Periodo": {}, + "Depreciación Acumulada": {}, + "Amortización del Periodo": {}, + "Amortización Acumulada": {}, + "brute_assets": {}, + } + self.dep_am_historic_vectors = {'Depreciación del Periodo': [], 'Depreciación Acumulada': [], 'Amortización del Periodo': [], 'Amortización Acumulada': []} + + self.get_historic_dep_am_data() + self.calculate_net_value_results() + self.organize_fixed_assets_results() + self.calculate_historic_summary_capex() + logger.info(f"[capex_summary_recalc] Matriz organizada de activos fijos:\n{self.capex_summary_vectors}") + self.brute_assets_vector = self.capex_summary_vectors.pop("brute_assets") + self.create_depre_amort_vectors() + logger.info(f"[capex_summary_recalc] Resultado de vectorización para depreciaciones y amortizaciones:\n{self.capex_summary_vectors}") + self.create_brute_assets_vector() + + logger.info(f"""[capex_summary_recalc] Resultados de summary: +Ingresos operacionales: {self.operation_income_vector} +Activos brutos: {self.brute_assets_vector} +CAPEX: {self.new_capex_vector} +Depreciación capex: {self.dep_capex} +Depreciación del Periodo: {self.capex_summary_vectors['Depreciación del Periodo']} +Amortización del Periodo: {self.capex_summary_vectors['Amortización del Periodo']} +Depreciación Acumulada: {self.capex_summary_vectors['Depreciación Acumulada']} +Amortización Acumulada: {self.capex_summary_vectors['Amortización Acumulada']}""") + self.organize_capex_summary_records() + self.df_and_upload(self.capex_summary_records, "CAPEX_SUMMARY") + + self.save_assessment_step("CAPEX") + + + @handler_wrapper('Adquiriendo summaries para las clasificaciones que se requieren en capex', 'totales adquiridos', 'Error adquiriendo summaries que requiere capex', 'Error adquiriendo insumos de capex') + def get_historic_dep_am_data(self): + for classification, vector in self.dep_am_historic_vectors.items(): + self.dep_am_historic_vectors[classification] = self.get_historic_summary_values(classification, startswith = True) + + acum_vector = [] + for classification in ['Activo Fijo', 'Activos intangibles']: + acum_vector.append(self.get_historic_summary_values(classification, startswith = True)) + self.fixed_assets_hist_vector = [sum(items) for items in zip(*acum_vector)] + + + @handler_wrapper('Vectorizando resultados de activos fijos', 'Valores de activos fijos vectorizados con exito', 'Error vectorizando resultados de depreciación de activos fijos', 'Error trayendo resultados de depreciación de activos fijos a calculo de nuevo capex') + def calculate_net_value_results(self): + #logger.warning(f'[vectorize_fixed_assets_results] datos que llegan desde depreciacion de assets:\n{self.fixed_assets_data_to_new_capex}') + #for proy_year in self.projection_dates: + # year_items = [item[str(proy_year)] for item in self.fixed_assets_data_to_new_capex if item.get(str(proy_year), False)] + # for key, vector in self.fixed_assets_proy_vectors.items(): + # vector.append(sum(item[key] for item in year_items)) + + self.fixed_assets_proy_vectors['period'] = [i+j for i,j in zip(self.dep_am_historic_vectors['Depreciación del Periodo'], self.dep_am_historic_vectors['Amortización del Periodo'])] + self.fixed_assets_proy_vectors['period'] + self.fixed_assets_proy_vectors['acumulated'] = [i+j for i,j in zip(self.dep_am_historic_vectors['Depreciación Acumulada'], self.dep_am_historic_vectors['Amortización Acumulada'])] + self.fixed_assets_proy_vectors['acumulated'] + self.fixed_assets_proy_vectors['asset'] = self.fixed_assets_hist_vector + self.fixed_assets_proy_vectors['asset'] + self.fixed_assets_proy_vectors['net_value'] = [i-j for i, j in zip(self.fixed_assets_proy_vectors['asset'], self.fixed_assets_proy_vectors['acumulated'])] + logger.warning(f'[vectorize_fixed_assets_results] vectores resultados: \n{self.fixed_assets_proy_vectors}') + + @handler_wrapper('Calculando historico de nuevo capex', 'Historicos de nuevo capex calculado con exito', 'Error calculando historico de nuevo capex', 'Error calculando historicos de nuevo capex') + def calculate_historic_summary_capex(self): + self.capex_historic_vector = [0] + for index, _ in enumerate(self.historic_dates[1:]): + self.capex_historic_vector.append(self.fixed_assets_proy_vectors['net_value'][index+1] - self.fixed_assets_proy_vectors['net_value'][index] + self.fixed_assets_proy_vectors['period'][index + 1]) + + logger.info(f"[calculate_historic_new_capex] historicos de nuevo capex: {self.new_capex_vector}") + self.new_capex_vector = self.capex_historic_vector + self.new_capex_vector[self.historic_dates_len:] + + + @handler_wrapper("organizando información que llega a summary de capex", "Información organizada con exito", "Error organizando información que llega a calculadora de capex summary", "Error construyendo insumos de capex summary") + def organize_fixed_assets_results(self): + all_fixed_assets_accounts = set() + accounts_classificacion_dict = {} + for _, accounts_dict in self.fixed_assets_data_to_capex_summary.items(): + all_fixed_assets_accounts.update(list(accounts_dict.values())) + #for account in all_fixed_assets_accounts: + # accounts_classificacion_dict[account] = next((item["classification"] for item in self.purged_items if item["account"] == account ), False, ) + logger.info(f"[organize_fixed_assets_results] diccionario de cuentas:clasificaciones:\n{accounts_classificacion_dict}") + logger.warning(f'[organize_fixed_assets_results] Parece que esto está llegando vacion:\n{self.fixed_assets_proy_to_capex_summary}') + for proy_row in self.fixed_assets_proy_to_capex_summary: + logger.debug(f'[organize_fixed_assets_results] {proy_row}') + if str(proy_row["date"]) not in self.projection_dates_long: + continue + proy_accounts = self.fixed_assets_data_to_capex_summary[proy_row["id_items_group"]] + acumul_classification = self.easy_classification_dict[int(proy_accounts["acumulated_account"])] + if not acumul_classification: + self.noting_list.append({"TASK": self.current_context, "NOTE": f"La cuenta {proy_accounts['acumulated_account']} de activos fijos no tiene clasificacion", }) + continue + + period_classification = self.easy_classification_dict[int(proy_accounts["period_account"])] + if not period_classification: + self.noting_list.append({"TASK": self.current_context,"NOTE": f"La cuenta {proy_accounts['period_account']} de activos fijos no tiene clasificacion"}) + continue + + self.integrate_proy_row(proy_row, ' '.join(acumul_classification.split(' ')[:-1]), ' '.join(period_classification.split(' ')[:-1])) + + @debugger_wrapper("Error integrando un resultado de proyeccion de activos fijos al diccionario de vectores summary", "Error integramdo activos fijos a summary",) + def integrate_proy_row(self, proy_row, acumul_classification, period_classification): + row_year = proy_row["date"] + if row_year not in self.capex_summary_vectors[acumul_classification]: + self.capex_summary_vectors[acumul_classification][row_year] = proy_row["acumulated"] + else: + self.capex_summary_vectors[acumul_classification][row_year] = (self.capex_summary_vectors[acumul_classification][row_year] + proy_row["acumulated"]) + + if row_year not in self.capex_summary_vectors[period_classification]: + self.capex_summary_vectors[period_classification][row_year] = proy_row["period"] + else: + self.capex_summary_vectors[period_classification][row_year] = (self.capex_summary_vectors[period_classification][row_year] + proy_row["period"]) + + if row_year not in self.capex_summary_vectors["brute_assets"]: + self.capex_summary_vectors["brute_assets"][row_year] = proy_row["asset_value"] + else: + self.capex_summary_vectors["brute_assets"][row_year] = (self.capex_summary_vectors["brute_assets"][row_year] + proy_row["asset_value"]) + + + @handler_wrapper("Creando vectores de depreciacion y amortizacion", "vectores de depreciacion y amortización construídos", "Error creando vectores de depreciación y amortización", "Error creando vectores de activos fijos") + def create_depre_amort_vectors(self): + for classification, vector in self.capex_summary_vectors.items(): + historic_vector = self.get_historic_summary_values(classification, startswith = True) + proy_vector = [vector.get(date, 0) for date in self.projection_dates_long] + self.capex_summary_vectors[classification] = historic_vector + proy_vector + + + @handler_wrapper("Creando vector de activos existentes brutos", "Vector de activos existentes brutos creado con exito", "Error creando vector de activos existentes brutos", "Error creando linea de capex summary para activos existentes brutos",) + def create_brute_assets_vector(self): + historic_vector = [i + j for i, j in zip(self.get_historic_summary_values("Activo Fijo", startswith = True), self.get_historic_summary_values("Activos intangibles 1", startswith = True))] + proy_vector = [self.brute_assets_vector.get(date, 0) for date in self.projection_dates_long] + self.brute_assets_vector = historic_vector + proy_vector + + + @handler_wrapper("Organizando records de capex summary", "Records de capex summary organizados con exito", "Error organizando records de capex summary", "Error creando tabla de capex summary",) + def organize_capex_summary_records(self): + if not self.new_capex_vector: + self.new_capex_vector = [0] * self.all_dates_len + self.dep_capex = [0] * self.all_dates_len + self.capex_summary_records = [ + asdict(capex_summary_object(*args)) for args in zip( + self.all_dates_long, + self.operation_income_vector, + self.brute_assets_vector, + self.new_capex_vector, + self.dep_capex, + self.capex_summary_vectors["Depreciación del Periodo"], + self.capex_summary_vectors["Amortización del Periodo"], + self.capex_summary_vectors["Depreciación Acumulada"], + self.capex_summary_vectors["Amortización Acumulada"])] diff --git a/corporate_finances_back_py/super-orchestrator/_calc_cash_flow.py b/corporate_finances_back_py/super-orchestrator/_calc_cash_flow.py new file mode 100644 index 0000000..2ca983d --- /dev/null +++ b/corporate_finances_back_py/super-orchestrator/_calc_cash_flow.py @@ -0,0 +1,221 @@ +from decorators import handler_wrapper, timing, debugger_wrapper +import logging +from sqlalchemy import text +import datetime +import numpy as np +import sys + +from dataclasses import dataclass, asdict#, field #field es para cuando se debe crear algo en __post_init__ +from cash_flow_vars import cash_flow_all_items, cash_flow_totals, pyg_names, capex_items + + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + + +@dataclass +class cash_flow_object: + SUMMARY_DATE : str + ID_RAW_CASH_FLOW : int + VALUE : float + + + +class cash_flow_class(object): + @handler_wrapper('Actualizando pantalla de flujo de caja', 'Flujo de caja actualizado con exito', 'Error actualizando flujo de caja', 'Error actualizando flujo de caja') + def cash_flow_recalc(self): + self.cash_flow_table = dict() + self.cash_flow_records = list() + existance_checker = [{'exists': self.dep_capex, 'function': self.consume_capex_data}, + {'exists': self.patrimony_results_records, 'function': self.consume_patrimony_data}, + {'exists': self.op_results_records, 'function': self.consume_other_projections_data}, + {'exists': self.wk_results_records, 'function': self.consume_working_capital_data}, + {'exists': self.coupled_debt_records, 'function': self.consume_debt_data}] + + self.initialize_cash_flow_zero_vectors() + self.acquire_pyg_values() + self.consume_pyg_data() + + for existance_function_pair in existance_checker: + if existance_function_pair['exists']: + existance_function_pair['function']() + + self.get_treasure_rates() + self.calculate_cash_flow_totals() + self.calculate_cash_flow() + self.check_if_trasure_debt() + + logger.info(f'[cash_flow_class] Terminación de flujo de caja:\n{self.cash_flow_table}') + self.create_cash_flow_records() + + if self.all_dates_len == self.historic_dates_len: + return + self.df_and_upload(self.cash_flow_records, 'CASH_FLOW') + + self.save_assessment_step("CASH_FLOW") + + + @handler_wrapper('Inicializando vectores en cero', 'Vectores en cero inicializados correctamente', 'Error inicializando vectores en cero de flujo de caja', 'Error creando tabla de flujo de caja') + def initialize_cash_flow_zero_vectors(self): + self.cash_flow_table = {item: [0] * self.all_dates_len for item in cash_flow_all_items} + + + @handler_wrapper('Obteniendo resultados de pyg', 'Resultados de pyg obtenidos con exito', 'Error obteniendo resultados de pyg', 'Error adquiriendo resultados de pyg') + def acquire_pyg_values(self): + logger.info(f'[cash aca] antes de agregar cosas de pyg:\n{self.cash_flow_table}') + for name in pyg_names: + self.cash_flow_table[name] = self.pyg_values_vectors[name] + logger.info(f'[cash aca] despues de agregar cosas de pyg:\n{self.cash_flow_table}') + + + @handler_wrapper('Utilizando informacion de pyg para calcular partes de flujo de caja','Pyg aplicado con exito', 'Error aplicando informacion de pyg a flujo de caja','Error aplicando pyg') + def consume_pyg_data(self): + self.cash_flow_table['Impuestos operacionales'] = [i*j/k for i,j,k in zip( + self.cash_flow_table['EBIT'], + self.cash_flow_table['Impuestos de renta'], + self.cash_flow_table['Utilidad antes de impuestos'])] + + self.cash_flow_table['Impuestos no operacionales'] = [i - j for i,j in zip(self.cash_flow_table['Impuestos de renta'], self.cash_flow_table['Impuestos operacionales'])] + self.cash_flow_table['UODI (NOPAT)'] = [i * (1- j/k) for i,j,k in zip(self.cash_flow_table['EBIT'], self.cash_flow_table['Impuestos de renta'], self.cash_flow_table['Utilidad antes de impuestos'])] + logger.info(f'[consume_pyg_data] Resultados de flujo de caja al aplicar datos de pyg:\n{self.cash_flow_table}') + + + @handler_wrapper('Se encontraron datos de capex, adquiriendo', 'Datos de capex adquiridos con exito', 'Error adquiriendo datos de capx', 'Error adquiriendo dependencias de capex') + def consume_capex_data(self): + for item in capex_items: + self.cash_flow_table[item] = self.capex_summary_vectors[item] + self.cash_flow_table['CAPEX'] = self.new_capex_vector + self.cash_flow_table['Depreciación Capex'] = self.dep_capex + + + @handler_wrapper('Se encontraron calculos anteriores de patrimonio, consumiendo', 'Calculos de patrimonio consumidos con exito', 'Error utilizando los calculos encontrados de patrimonio', 'Error consumiendo resultados patrimonio') + def consume_patrimony_data(self): + self.cash_flow_table['Aportes de capital social u otros'] = [row['SOCIAL_CONTRIBUTIONS'] for row in self.patrimony_results_records] + self.cash_flow_table['Dividentos en efectivo'] = [row['CASH_DIVIDENDS'] for row in self.patrimony_results_records] + + + @handler_wrapper('Se encontraron datos de otras proyecciones, consumiendo', 'Calculos de otras proyecciones consumidos con exito', 'Error consumiendo datos de otras proyecciones', 'Error consumientos resultados de otras proyecciones') + def consume_other_projections_data(self): + self.cash_flow_table['Otros movimientos que no son salida ni entrada de efectivo operativos'] = [row['OTHER_OPERATIVE_MOVEMENTS'] for row in self.op_results_records] + self.cash_flow_table['Otros movimientos netos de activos operativos que afecta el FCLA'] = [row['FCLA'] for row in self.op_results_records] + self.cash_flow_table['Otros movimientos netos de activos operativos que afecta el FCLO'] = [row['FCLO'] for row in self.op_results_records] + + + @handler_wrapper('Se encontraron datos de capital de trabajo, consumiendo', 'Datos de capital de trabajo consumidos con exito', 'Error consumiendo datos de capital de trabajo', 'Error consumientos resultados de capital de trabajo') + def consume_working_capital_data(self): + self.cash_flow_table['Capital de trabajo'] = [row['WK_VARIATION'] for row in self.wk_results_records] + + + @handler_wrapper('Consumiendo datos encontrados de deuda', 'Datos de deuda consumidos con exito', 'Error consumiendo datos de deuda', 'Error consumiendo datos de deuda') + def consume_debt_data(self): + self.cash_flow_table['Variación de deuda'] = [row['DISBURSEMENT'] for row in self.coupled_debt_records] + self.cash_flow_table['Intereses/gasto financiero'] = [row['INTEREST_VALUE'] for row in self.coupled_debt_records] + self.cash_flow_table['Intereses/gasto financiero FC'] = self.cash_flow_table['Intereses/gasto financiero'] + + @handler_wrapper('Chequeando si se asaignaron tasas de deuda de tesorería', 'Chequeo de tasas terminado', 'Error chequeando y asignando deudas de tesorería', 'Error chequeando existencia de deudas de tesorería') + def get_treasure_rates(self): + query = """SELECT RATE_ATRIBUTE, SPREAD_ATRIBUTE FROM PROJECTED_DEBT WHERE ID_ASSESSMENT = :id_assessment AND ALIAS_NAME = "Deuda de Tesoreria" ORDER BY ITEM_DATE""" + logger.info(f"[get_debt_data] Query a base de datos para obtener as tasas de deuda de tesorería:\n {query}") + rds_data = self.db_connection.execute(text(query), {"id_assessment":self.id_assessment}) + self.treasure_rates = [float(row.RATE_ATRIBUTE) + float(row.SPREAD_ATRIBUTE) for row in rds_data.fetchall()] + if len(self.treasure_rates) < self.projection_dates_len: + self.treasure_rates = [0] * (self.projection_dates_len - len(self.treasure_rates)) + self.treasure_rates + if not self.treasure_rates: + self.treasure_rates = [0] * self.projection_dates_len + + + @handler_wrapper('Calculando totales de salida con los datos encontrados', 'Totales de flujo de caja calculados correctamente', 'Error calculando totales de flujo de caja', 'Error calculando totales') + def calculate_cash_flow_totals(self): + for key, depen_signs in cash_flow_totals.items(): + #logger.warning(f'[mira aca] sacando totales de {key} que depende de {depen_signs} desde {self.cash_flow_table}') + self.cash_flow_table[key] = self.calculate_total_vector(depen_signs['dependencies'], depen_signs['is_sum'], self.cash_flow_table) + logger.info(f'[calculate_cash_flow_totals] El vector de totales de {key} obtenido es {self.cash_flow_table[key]}') + + + + @handler_wrapper('Organizando flujos de caja', 'Flujos de caja organizados con exito', 'Error organizando flujos de caja', 'Error organizando flujo de caja') + def calculate_cash_flow(self): + logger.info(f"[calculate_cash_flow] Generando saldos de caja a partir del flujo de caja del periodo:\n{self.cash_flow_table['Flujo de caja del periodo']}") + self.cash_flow_table['Saldo de caja final'] = [value for value in self.get_historic_summary_values('Caja')] + self.cash_flow_table['Saldo de caja inicial'] = [0] + [value for value in self.get_historic_summary_values('Caja')] + + for index in range(self.historic_dates_len, self.all_dates_len): + logger.info(f'valor de index {index}') + self.cash_flow_table['Saldo de caja inicial'].append(self.cash_flow_table['Saldo de caja final'][index-1]) + self.cash_flow_table['Saldo de caja final'].append(self.cash_flow_table['Saldo de caja inicial'][index] + self.cash_flow_table['Flujo de caja del periodo'][index]) + + self.cash_flow_table['Check'] = ['Sí'] * self.all_dates_len + + + @handler_wrapper('Chequeando si es necesario agregar deudas de tesorería', 'Chequeo de deudas de tesorería terminado', 'Error calculando deudas de tesorería', 'Error construyendo deudas de tesorería') + def check_if_trasure_debt(self): + logger.warning(f'[check_if_trasure_debt] flujos de caja final obtenidos:\n{self.cash_flow_table["Saldo de caja final"]}') + for proy_year in range(self.projection_dates_len): + table_vectors_index = self.historic_dates_len + proy_year + final_cash_flow_current_year = self.cash_flow_table['Saldo de caja final'][table_vectors_index] + final_cash_flow_current_year = 0 if np.isclose(final_cash_flow_current_year,0) else final_cash_flow_current_year + if final_cash_flow_current_year < 0: + self.calculate_year_treasure_debt(proy_year, final_cash_flow_current_year) + else: + last_acumulated_treasure = self.cash_flow_table['Deuda de tesorería acumulada'][table_vectors_index - 1] + self.cash_flow_table['Deuda de tesorería acumulada'][table_vectors_index] = last_acumulated_treasure - final_cash_flow_current_year + if self.cash_flow_table['Deuda de tesorería acumulada'][table_vectors_index] > 0: + self.cash_flow_table['Saldo de caja final'][table_vectors_index] = 0 + else: + self.cash_flow_table['Deuda de tesorería acumulada'][table_vectors_index] = 0 + self.cash_flow_table['Saldo de caja final'][table_vectors_index] = final_cash_flow_current_year - last_acumulated_treasure + + self.pyg_final_projections_recalc() + self.final_pyg() + + #TODO: quedé solucionando este bug + @debugger_wrapper('Error calculando la deuda de tesorería de uno de los periodos', 'Error calculando deuda de tesorería') + def calculate_year_treasure_debt(self, proy_year, final_cash_flow): + table_vectors_index = self.historic_dates_len + proy_year + yearly_interest = self.treasure_rates[proy_year]/100 #como el trasure debt lo estoy capturando directo de base de datos, puede que allá está más corto que acá, colocare un try-except para que si se queda corto el vector de intereses, asuma interés de 0 + interest_acum = [yearly_interest] + for i in range(10): + interest_acum.append(interest_acum[i] * (1 + yearly_interest)) + this_year_total_interest = interest_acum[-1] + + while True: + logger.info(f"[mira aca] antes de reasignar valor de interés: {self.pyg_values_vectors['Intereses/gasto financiero']}") + real_balance_to_calculate_interest = self.cash_flow_table['Deuda de tesorería acumulada'][table_vectors_index - 1] - final_cash_flow /2 + this_iteration_interest = real_balance_to_calculate_interest * this_year_total_interest + this_iteration_debt = this_iteration_interest - final_cash_flow + self.cash_flow_table['Deuda de tesorería del periodo'][table_vectors_index] = self.cash_flow_table['Deuda de tesorería del periodo'][table_vectors_index] + this_iteration_debt + self.cash_flow_table['Deuda de tesorería acumulada'][table_vectors_index] = self.cash_flow_table['Deuda de tesorería acumulada'][table_vectors_index-1] + self.cash_flow_table['Deuda de tesorería del periodo'][table_vectors_index] + self.cash_flow_table['Intereses/gasto financiero FC'][table_vectors_index] = self.cash_flow_table['Intereses/gasto financiero FC'][table_vectors_index] + this_iteration_interest + self.pyg_values_vectors['Intereses/gasto financiero'] = self.cash_flow_table['Intereses/gasto financiero FC'] + self.pyg_projected_vectors['Intereses/gasto financiero'] = self.cash_flow_table['Intereses/gasto financiero FC'][self.historic_dates_len:] + + logger.info(f"[mira aca] despues de reasignar valor de interés: {self.pyg_values_vectors['Intereses/gasto financiero']}") + self.pyg_final_projections_recalc(save_to_db = False) + self.final_pyg(save_to_db = False) + logger.info(f"[mira aca] despues de recalcular pygs valor de interés: {self.pyg_values_vectors['Intereses/gasto financiero']}") + self.acquire_pyg_values() + self.calculate_cash_flow_totals() + + self.calculate_cash_flow() + end_iteration_final_cash_flow_value = self.cash_flow_table['Saldo de caja final'][table_vectors_index] + logger.warning(f'[calculate_year_treasure_debt] revisión de flujo de caja final:\nValor original: {final_cash_flow}\nValor al terminar la iteracion: {end_iteration_final_cash_flow_value}') + if end_iteration_final_cash_flow_value < final_cash_flow or end_iteration_final_cash_flow_value == final_cash_flow: + logger.error('[calculate_year_treasure_debt] Las iteraciones de deuda de tesorería se fueron hacia el contrario') + break + #TODO: mandar a notas que la deuda está convergiendo hacia el laod equivocado + final_cash_flow = end_iteration_final_cash_flow_value + + if (final_cash_flow > 0 or np.isclose(final_cash_flow,0)): + break + + + + @handler_wrapper('Emergiendo ids de flujo de caja', 'Ids de flujo de caja emergidos con exito', 'Error emergiendo ids de flujo de caja', 'Error resolvindo tabla de flujo de caja') + def create_cash_flow_records(self): + for key in cash_flow_all_items: + values_vector = self.cash_flow_table[key] + self.cash_flow_records.extend(asdict(cash_flow_object(date, self.cash_flow_id_dict[key], value)) for date, value in zip(self.all_dates_long, values_vector)) + + +def get_current_error_line(): + return str(sys.exc_info()[-1].tb_lineno) \ No newline at end of file diff --git a/corporate_finances_back_py/super-orchestrator/_calc_debt.py b/corporate_finances_back_py/super-orchestrator/_calc_debt.py new file mode 100644 index 0000000..bdd6365 --- /dev/null +++ b/corporate_finances_back_py/super-orchestrator/_calc_debt.py @@ -0,0 +1,181 @@ +from decorators import handler_wrapper, timing, debugger_wrapper +from dataclasses_box import projected_debt_object, debt_object, coupled_debt_object, asdict +import logging +import pandas as pd +import datetime +import sys + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + +class debt_class(): + + @handler_wrapper('Actualizando datos de deuda', 'Datos de deuda calculados con exito', 'Error actualizando resultados de deuda', 'Error actualizando deuda') + def debt_recalc(self): + self.debt_info = self.assessment_models['MODEL_DEBT'] + if not self.debt_info: + logger.warning('[debt_recalc] No se encontró modelo de deuda') + #self.noting_list.append({'TASK': self.current_context, 'NOTE': "No se halló modelo para calculo de deuda"}) + return + self.debt_projection_records = list() + self.debt_records = list() + + self.process_all_debts() + self.calculate_coupled_debt() + + self.df_and_upload(self.debt_records, 'DEBT') + self.df_and_upload(self.debt_projection_records, 'PROJECTED_DEBT') + self.df_and_upload(self.coupled_debt_records, 'COUPLED_DEBT') + + def process_all_debts(self): + current_debts = [] + projected_debts = [] + debt_directory = {'0': projected_debts} + for debt in self.debt_info: + debt_directory.get(debt['ACCOUNT_NUMBER'], current_debts).append(debt) + + logger.info(f'[debt_recalc] Deudas repartidas:\nDeudas actuales:{current_debts}\n\nDeudas futuras:{projected_debts}') + for current_debt in current_debts: + try: + self.process_current_debts(current_debt) + except: + self.noting_list.append({'TASK': self.current_context, 'NOTE': f"La deuda con numero de cuenta {current_debt['ACCOUNT_NUMBER']} No pudo ser calculada"}) + continue + + for proy_debt in projected_debts: + try: + self.process_projection_debts(proy_debt) + except: + self.noting_list.append({'TASK': self.current_context, 'NOTE': f"La deuda con alias {current_debt['ALIAS_NAME']} No pudo ser calculada"}) + continue + + + @debugger_wrapper('Error calculando una deuda actual', 'Error calculando deuda actual') + def process_current_debts(self, debt_info): + debt_info['value'] = self.get_historic_account_values(debt_info['ACCOUNT_NUMBER'])[-1] + projections_items = [item for item in self.assessment_models['MODEL_PROJECTED_DEBT'] if item['ACCOUNT_NUMBER'] == debt_info['ACCOUNT_NUMBER']] + logger.debug(f'[process_current_debts] items de la deuda, los rates deberían estar bien: {projections_items}, buscando {debt_info["ACCOUNT_NUMBER"]} en {self.assessment_models["MODEL_PROJECTED_DEBT"]}') + rate_vector = [safe_of(item['RATE_ATRIBUTE']) for item in projections_items][self.historic_dates_len:] + spread_vector = [safe_of(item['SPREAD_ATRIBUTE']) for item in projections_items][self.historic_dates_len:] #TODO: En algunos casos este vector se queda corto al modelo de la empresa, pendiente de replicar + projections_interest_vector = [i + j for i,j in zip(rate_vector, spread_vector)] + debt_projection_years = int(debt_info['ENDING_YEAR']) - int(debt_info['START_YEAR']) + 1 + + debt_vectors = self.calculate_current_debt_projections(debt_info['value'], projections_interest_vector) #TODO: por el bug anterior, este está quedando mal + dates_vector = [] + debt_ending_year = str(int(self.historic_dates_long[-1].split('-')[0]) + debt_projection_years) + for proy_date in self.projection_dates_long: #acá manejo fechas proyectadas + dates_vector.append(proy_date) + if debt_ending_year in proy_date: + break + + projection_records = [asdict(projected_debt_object(debt_info['ACCOUNT_NUMBER'], debt_info['ALIAS_NAME'], + vectors[0], vectors[1], vectors[2], vectors[3], vectors[4], vectors[5], vectors[6], vectors[7], vectors[8])) for vectors in zip(dates_vector, *debt_vectors, rate_vector, spread_vector)] + + for date in self.historic_dates_long: #acá manejo fechas historicas + logger.info(f'[fechas ingresando] mira aca {date}') + self.debt_projection_records.append(asdict(projected_debt_object(debt_info['ACCOUNT_NUMBER'], debt_info['ALIAS_NAME'], date, 0, 0, 0, 0, 0, 0, 0, 0))) + + logger.info(f'[process_current_debts] records proyectados de la deuda corriente con numero de cuenta {debt_info["ACCOUNT_NUMBER"]}:\n{projection_records}') + self.debt_projection_records.extend(projection_records) + self.debt_records.append(asdict(debt_object(debt_info['value'], debt_info['ACCOUNT_NUMBER'], debt_info['ALIAS_NAME'], + debt_info['PROJECTION_TYPE'], dates_vector[0][:4], dates_vector[-1], debt_info['DEBT_COMMENT'], debt_info['RATE_COMMENT'], debt_info['SPREAD_COMMENT']))) + + + @debugger_wrapper('Error calculando una de las deudas futuras', 'Error calculando una de las deudas futuras') + def process_projection_debts(self, proy_debt): + proy_debt['value'] = float(proy_debt['ORIGINAL_VALUE']) + projections_items = [item for item in self.assessment_models['MODEL_PROJECTED_DEBT'] if item['ALIAS_NAME'] == proy_debt['ALIAS_NAME']] + + rate_vector = [safe_of(item['RATE_ATRIBUTE']) for item in projections_items] + spread_vector = [safe_of(item['SPREAD_ATRIBUTE']) for item in projections_items] + projections_interest_vector = [i + j for i,j in zip(rate_vector, spread_vector)] + + debt_vectors = self.calculate_projection_debt_projections(proy_debt['value'], projections_interest_vector) + if self.context == 'full_recurrency': + new_start_year = int(self.historic_dates_long[-1].split('-')[0]) + 1 #Voy a asumir que todas las deudas futuras del modelo empiezan un año después del año que se está valorando + new_ending_year = new_start_year + int(proy_debt['ENDING_YEAR']) - int(proy_debt['START_YEAR']) + dates_vector = [datetime.datetime.strptime(str(date_year), '%Y').strftime('%Y-%m-%d %H:%M:%S') for date_year in range(new_start_year, new_ending_year +1)] + else: + dates_vector = [datetime.datetime.strptime(str(date_year), '%Y').strftime('%Y-%m-%d %H:%M:%S') for date_year in range(int(proy_debt['START_YEAR']), int(proy_debt['ENDING_YEAR']) +1)] + + projection_records = [asdict(projected_debt_object(proy_debt['ACCOUNT_NUMBER'], proy_debt['ALIAS_NAME'], + vectors[0], vectors[1], vectors[2], vectors[3], vectors[4], vectors[5], vectors[6], vectors[7], vectors[8])) for vectors in zip(dates_vector, *debt_vectors, rate_vector, spread_vector)] + + logger.info(f'[process_projection_debts] records de la deuda proyectada con alias {proy_debt["ALIAS_NAME"]}:\n{projection_records}') + self.debt_projection_records.extend(projection_records) + #self.debt_records.append(asdict(debt_object(proy_debt['value'], proy_debt['ACCOUNT_NUMBER'], proy_debt['ALIAS_NAME'], + #proy_debt['PROJECTION_TYPE'], proy_debt['START_YEAR'], proy_debt['ENDING_YEAR'], proy_debt['DEBT_COMMENT'], proy_debt['RATE_COMMENT'], proy_debt['SPREAD_COMMENT']))) + self.debt_records.append(asdict(debt_object(proy_debt['value'], proy_debt['ACCOUNT_NUMBER'], proy_debt['ALIAS_NAME'], + proy_debt['PROJECTION_TYPE'], dates_vector[0][:4], dates_vector[-1], proy_debt['DEBT_COMMENT'], proy_debt['RATE_COMMENT'], proy_debt['SPREAD_COMMENT']))) + + + @debugger_wrapper('Error calculando las proyecciones de una deuda', 'Error calculando proyecciones de deuda') + def calculate_current_debt_projections(self, initial_value, interest_vector): + projections_years = len(interest_vector) + yearly_amortization_value = initial_value / projections_years + disbursement = [0] * projections_years + amortization = [yearly_amortization_value] * projections_years + ending_balance_variation = [-yearly_amortization_value] * projections_years + + ending_balance = [initial_value - yearly_amortization_value] + interest_balance = [interest_vector[0] * initial_value / 100] + initial_balance_vector = [initial_value] + for index, interest in enumerate(interest_vector[1:], start = 1): + initial_balance_vector.append(ending_balance[index - 1]) + ending_balance.append(initial_balance_vector[index] - amortization[index]) + interest_balance.append(initial_balance_vector[index] * interest / 100) + + return [initial_balance_vector, disbursement, amortization, ending_balance, interest_balance, ending_balance_variation] + + + @debugger_wrapper('Error calculando las proyecciones de una deuda', 'Error calculando proyecciones de deuda') + def calculate_projection_debt_projections(self, initial_value, interest_vector): + projections_years = len(interest_vector) - 1 + + yearly_amortization_value = initial_value / (projections_years + 1) + + disbursement = [initial_value] + [0] * projections_years #Esto pareciera diferente pero en realidad está bien, projections_years está recortado por una posicion + amortization = [yearly_amortization_value] * (projections_years + 1) + ending_balance_variation = [initial_value - yearly_amortization_value] + [-yearly_amortization_value] * projections_years #Creo que este está mal, en el otro código dice que debería empezar por el ending_balance en la primera posicion, no por [0] + + initial_balance_vector = [initial_value] + ending_balance = [initial_value - yearly_amortization_value] #este parece que está bien + interest_balance = [initial_value * interest_vector[0]/100] #este parece que está bien + + for index, interest in enumerate(interest_vector[1:], start = 1): + initial_balance_vector.append(ending_balance[index - 1]) + ending_balance.append(initial_balance_vector[index] - amortization[index]) + interest_balance.append(initial_balance_vector[index] * interest / 100) #este parece que está bien + + return [initial_balance_vector, disbursement, amortization, ending_balance, interest_balance, ending_balance_variation] + + + @handler_wrapper('Calculando resultados finales de deuda', 'Resultados finales de deuda calculados con exito', 'Error calculando resultados finales de deuda', 'Error calculando resultados de deuda') + def calculate_coupled_debt(self): + self.coupled_debt_partial = {date:{'DISBURSEMENT': float(), 'INTEREST_VALUE': float()} for date in self.projection_dates_long} + logger.info(f'[mira aca] estos son los datos a los que se les va a procesar deuda: {self.debt_projection_records} y {self.coupled_debt_partial}') + for row in self.debt_projection_records: + row['ITEM_DATE'] = str(row['ITEM_DATE']) + if row['ITEM_DATE'] not in self.coupled_debt_partial: + continue + self.coupled_debt_partial[row['ITEM_DATE']]['INTEREST_VALUE'] = self.coupled_debt_partial[row['ITEM_DATE']]['INTEREST_VALUE'] + row['INTEREST_VALUE'] + self.coupled_debt_partial[row['ITEM_DATE']]['DISBURSEMENT'] = self.coupled_debt_partial[row['ITEM_DATE']]['DISBURSEMENT'] + row['ENDING_BALANCE_VARIATION'] + for date in self.projection_dates_long: + if date not in self.coupled_debt_partial: + self.coupled_debt_partial[date] = {'DISBURSEMENT': 0, 'INTEREST_VALUE': 0} + + + self.coupled_debt_records = [asdict(coupled_debt_object(date, 0, historic_interest)) for date, historic_interest in zip(self.historic_dates_long, self.get_historic_summary_values('Intereses/gasto financiero'))] + + self.coupled_debt_records.extend(asdict(coupled_debt_object(date, properties['DISBURSEMENT'], properties['INTEREST_VALUE'])) for date, properties in zip(self.projection_dates_long, self.coupled_debt_partial.values())) + + + +def get_current_error_line(): + return str(sys.exc_info()[-1].tb_lineno) + +def safe_of(number): + try: + return(float(number)) + except: + return 0 \ No newline at end of file diff --git a/corporate_finances_back_py/super-orchestrator/_calc_fixed_assets.py b/corporate_finances_back_py/super-orchestrator/_calc_fixed_assets.py new file mode 100644 index 0000000..02334d9 --- /dev/null +++ b/corporate_finances_back_py/super-orchestrator/_calc_fixed_assets.py @@ -0,0 +1,124 @@ + +from dataclasses_box import fixed_assets_object, fixed_assets_projected_item, asdict +from decorators import handler_wrapper, timing, debugger_wrapper +import logging +import pandas as pd +import datetime +import sys + + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + + +class fixed_assets_class(object): + @handler_wrapper('Actualizando proyecciones de activos fijos', 'Activos fijos proyectados correctamente', 'Error proyectando depreciación de activos fijos', 'Error proyectando activos fijos') + def fixed_assets_recalc(self): + if not self.assessment_models['MODEL_FIXED_ASSETS']: + logger.warning('[fixed_assets_recalc] No se encontraron modelos para depreciación de activos fijos') + return + tab_info_records = [] + tab_proy_records = [] + for tab in self.assessment_models['MODEL_FIXED_ASSETS']: + try: + self.recalculate_tab_info(tab) + if tab['PROJECTION_TYPE'] == 'D&A en línea recta': + proy_info = self.assets_fixed_increment(tab) + else: + proy_info = self.assets_manual_increment(tab) + + tab_info_records.append(tab) + tab_proy_records.extend([asdict(item) for item in proy_info]) + self.fixed_assets_data_to_new_capex.extend([item.capex_output() for item in proy_info]) + self.fixed_assets_proy_to_capex_summary.extend([item.capex_summary_output() for item in proy_info]) + except: + continue + + self.df_and_upload(tab_info_records, 'FIXED_ASSETS') + + self.df_and_upload(tab_proy_records, 'PROJECTED_FIXED_ASSETS') + self.save_assessment_step("CAPEX") + + + @debugger_wrapper('Error calculando pestaña de depreciación de activos fijos', 'Error recalculando pestaña de activos fijos') + def recalculate_tab_info(self, tab): + tab['ASSET_ORIGINAL_VALUE'] = self.get_historic_summary_values(self.easy_classification_dict[int(tab['ASSET_ACCOUNT'])])[-1] + tab['ACUMULATED_ORIGINAL_VALUE'] = self.get_historic_summary_values(self.easy_classification_dict[int(tab['ACUMULATED_ACCOUNT'])])[-1] + tab['PERIOD_ORIGINAL_VALUE'] = self.get_historic_summary_values(self.easy_classification_dict[int(tab['PERIOD_ACCOUNT'])])[-1] + self.fixed_assets_data_to_capex_summary.update(fixed_assets_object(tab['ID_ITEMS_GROUP'], + tab['PROJECTION_TYPE'], + tab['ASSET_ACCOUNT'], + tab['ACUMULATED_ACCOUNT'], + tab['PERIOD_ACCOUNT'], + tab['ASSET_ORIGINAL_VALUE'], + tab['ACUMULATED_ORIGINAL_VALUE'], + tab['PERIOD_ORIGINAL_VALUE'], + tab['PROJECTED_YEARS'], + tab['CALCULATION_COMMENT']).capex_summary_output()) + + + @debugger_wrapper('Error en incremento a tasa fija de activo fijo', 'Error calculando pestaña de activo fijo') + def assets_fixed_increment(self, tab): + asset_vector= [tab['ASSET_ORIGINAL_VALUE']] * (tab['PROJECTED_YEARS'] + 2) + + acumulated_vector = [tab['ACUMULATED_ORIGINAL_VALUE']] + existing_vector = [tab['ASSET_ORIGINAL_VALUE'] - tab['ACUMULATED_ORIGINAL_VALUE']] + period_dep_value = existing_vector[-1] / tab['PROJECTED_YEARS'] + period_vector = [period_dep_value] * (tab['PROJECTED_YEARS'] + 1) + tab_dates = [self.projection_dates_long[0]] + + if '-12-' not in self.historic_dates_long[-1]: + delta_period = tab['PERIOD_ORIGINAL_VALUE'] * 12 / int(self.historic_dates_long[-1].split('-')[1]) - tab['PERIOD_ORIGINAL_VALUE'] + acumulated_vector.append(acumulated_vector[0] + delta_period) + existing_vector.append(asset_vector[1] - acumulated_vector[1]) + period_dep_value = existing_vector[-1] / tab['PROJECTED_YEARS'] + period_vector[1:] = [tab['PERIOD_ORIGINAL_VALUE'] + delta_period] + [period_dep_value] * (tab['PROJECTED_YEARS']) + + acumulated_vector = acumulated_vector + [acumulated_vector[-1] + i * period_dep_value for i in range(1, tab['PROJECTED_YEARS'] + 1)] + existing_vector = existing_vector + [existing_vector[-1] - i * period_dep_value for i in range(1, tab['PROJECTED_YEARS'] + 1)] + + for vector in [asset_vector, period_vector, acumulated_vector, existing_vector]: + vector.pop(0) + + first_projection_year = datetime.datetime.strptime(self.projection_dates_long[0], '%Y-%m-%d %H:%M:%S').replace(day = 1, month = 1) + tab_dates = tab_dates + [first_projection_year.replace(year = first_projection_year.year + year).strftime('%Y-%m-%d %H:%M:%S') for year in range(1, tab['PROJECTED_YEARS'] + 1)] + + return [fixed_assets_projected_item(tab['ID_ITEMS_GROUP'], date, asset, acumulated, existing, period) + for date, asset, acumulated, existing, period in zip(tab_dates, asset_vector, acumulated_vector, existing_vector, period_vector)] + + + @debugger_wrapper('Error en incremento manual de activo fijo', 'Error calculando pestaña de activo fijo') + def assets_manual_increment(self, tab): + tab_dates = [self.projection_dates_long[0]] + first_projection_year = datetime.datetime.strptime(self.projection_dates_long[0], '%Y-%m-%d %H:%M:%S').replace(day = 1, month = 1) + tab_dates = tab_dates + [first_projection_year.replace(year = first_projection_year.year + year).strftime('%Y-%m-%d %H:%M:%S') for year in range(1, tab['PROJECTED_YEARS'] + 1)] + + period_vector = [float(item['PERIOD_VALUE']) for item in self.assessment_models['MODEL_PROJECTED_FIXED_ASSETS'] if item['ID_ITEMS_GROUP'] == tab['ID_ITEMS_GROUP']] + period_vector = period_vector if len(period_vector) >= self.projection_dates_len else period_vector + [0] * self.projection_dates_len + asset_vector= [tab['ASSET_ORIGINAL_VALUE']] * len(tab_dates) + acumulated_vector = [tab['ACUMULATED_ORIGINAL_VALUE']] #pop de index 0 + existing_vector = [tab['ASSET_ORIGINAL_VALUE']] #pop de index 0 + a = 0 + if '-12-' not in self.historic_dates_long[-1]: + delta_period = tab['PERIOD_ORIGINAL_VALUE'] * 12 / int(self.historic_dates_long[-1].split('-')[1]) - tab['PERIOD_ORIGINAL_VALUE'] + acumulated_vector.append(acumulated_vector[0] + delta_period) + existing_vector.append(asset_vector[1] - acumulated_vector[1]) + a = 1 + + for proy_index, _ in enumerate(tab_dates): + try: + acumulated_vector.append(acumulated_vector [-1] + period_vector[proy_index + a]) + existing_vector.append(asset_vector[0] - acumulated_vector[-1]) + except: + self.noting_list.append({"TASK": self.current_context, "NOTE": f"El tab con cuentas {tab['ASSET_ACCOUNT']}, {tab['ACUMULATED_ACCOUNT']} y {tab['PERIOD_ACCOUNT']}; tuvo una terminación de fechas imprevista"}) + break + + acumulated_vector.pop(0) + existing_vector.pop(0) + return [fixed_assets_projected_item(tab['ID_ITEMS_GROUP'], date, i, j, k, m) for date, i, j, k, m in zip(tab_dates, asset_vector, acumulated_vector, existing_vector, period_vector)] + + + + +def get_current_error_line(): + return str(sys.exc_info()[-1].tb_lineno) \ No newline at end of file diff --git a/corporate_finances_back_py/super-orchestrator/_calc_new_capex.py b/corporate_finances_back_py/super-orchestrator/_calc_new_capex.py new file mode 100644 index 0000000..aa1dc66 --- /dev/null +++ b/corporate_finances_back_py/super-orchestrator/_calc_new_capex.py @@ -0,0 +1,151 @@ + +from decorators import handler_wrapper, timing, debugger_wrapper +from dataclasses import dataclass, asdict#, field #field es para cuando se debe crear algo en __post_init__ +from dataclasses_box import capex_values_object + +import logging +import pandas as pd +import datetime +import sys +from _orchester_utils import acute + + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + + +class new_capex_class(object): + @handler_wrapper('Actualizando datos de nuevo capex', 'Nuevo capex calculado con exito', 'Error actualizando resultados de nuevo capex', 'Error actualizando capex') + def new_capex_recalc(self): + if not self.assessment_models.get('MODEL_CAPEX', False): + logger.warning(f'[new_capex_recalc] No hay atributos para las proyecciones de capex') + #self.noting_list.append({'TASK': self.current_context, 'NOTE': f"No se halló información de proyeccion de nuevo capex"}) + self.assessment_projections_found = False + return + + self.fixed_assets_proy_vectors = {'acumulated': [], 'period': [], 'asset': []} + + self.proyection_mode_directory = {'Proyección automatica': self.proyeccion_auto_new_capex, 'Porcentaje de otra variable': self.percentage_capex_projection, 'Manual': self.manual_projection} + self.capex_records = list() + self.capex_values_records = list() + self.acumulative_capex = [0] * self.projection_dates_len + self.acumulative_dep_capex = [0] * self.projection_dates_len + + try: + self.partial_calculator_master() + self.new_capex_vector = [0] * self.historic_dates_len + self.acumulative_capex + self.dep_capex = [0] * self.historic_dates_len + self.acumulative_dep_capex + except: + self.new_capex_vector = [0] * self.all_dates_long #CAPEX + self.dep_capex = [0] * self.all_dates_long #Depreciación capex + + self.df_and_upload(self.capex_records, 'CAPEX') + self.df_and_upload(self.capex_values_records, 'CAPEX_VALUES') + + @handler_wrapper('Iniciando master de calculos parciales', 'Master de calculos terminado con éxito', 'Error en el master de calculos de nuevo capex', 'Error calculando nuevo capex') + def partial_calculator_master(self): + for partial_capex in self.assessment_models['MODEL_CAPEX']: + self.current_capex_name = partial_capex['CAPEX_NAME'] + user_chosen_pyg_row = partial_capex['USED_ACCOUNT_NAME'] + """ + historic_chosen_vector = self.pyg_values_vectors.get(user_chosen_pyg_row, False) + if not historic_chosen_vector: + self.noting_list.append({'TASK': self.current_context, 'NOTE': f'No se halló {user_chosen_pyg_row} para el calculo de la linea depreciación nuevo capex'}) + historic_chosen_vector = [0] * self.historic_dates_len + """ + projected_chosen_vector = self.pyg_projected_vectors.get(user_chosen_pyg_row, False) + if not projected_chosen_vector: + self.noting_list.append({'TASK': self.current_context, 'NOTE': f'No se halló proyeccion de {user_chosen_pyg_row} calculada para calculo de nuevo capex'}) + projected_chosen_vector = [0] * self.projection_dates_len + + self.user_chosen_vector = projected_chosen_vector + + self.proyection_mode_directory[partial_capex['METHOD']]() + + self.calculate_historic_new_capex() + self.new_capex_vector.extend(self.new_capex_projections) + self.capex_depreciation() + logger.info(f'[new_capex_recalc] Resultado final de nuevo capex:\n{self.new_capex_vector}\n\nDepreciación capex:\n{self.dep_capex}') + self.capex_records.append(partial_capex) + self.acumulative_capex = [i + j for i, j in zip(self.acumulative_capex, self.new_capex_projections)] + self.acumulative_dep_capex = [i + j for i, j in zip(self.acumulative_dep_capex, self.dep_capex)] + self.organize_db_records() + + + + + + @handler_wrapper('Calculando historico de nuevo capex', 'Historicos de nuevo capex calculado con exito', 'Error calculando historico de nuevo capex', 'Error calculando historicos de nuevo capex') + def calculate_historic_new_capex(self): + """ + operational_income_vector = self.pyg_values_vectors['Ingresos operacionales'] + self.pyg_projected_vectors['Ingresos operacionales'] + #net_asset_vector = [0] + [sum(items) for items in zip(self.user_chosen_vector, self.fixed_assets_proy_vectors['acumulated'])] + logger.info(f'[calculate_historic_new_capex] Vectores con los que se calcula net_asset_vector:\noperational_income_vector: {operational_income_vector}\nself.fixed_assets_proy_vectors.acumulated:{self.fixed_assets_proy_vectors["acumulated"]}') + net_asset_vector = [0] + [sum(items) for items in zip(operational_income_vector, self.fixed_assets_proy_vectors['acumulated'])] + self.new_capex_vector = [] + for index, _ in enumerate(self.historic_dates): + self.new_capex_vector.append(net_asset_vector[index+1] - net_asset_vector[index] + self.fixed_assets_proy_vectors['period'][index]) + #self.new_capex_vector.append(0) + """ + """ + self.fixed_assets_proy_vectors['net_value'] + self.new_capex_vector = [0] + for index, _ in enumerate(self.historic_dates[1:]): + self.new_capex_vector.append(self.fixed_assets_proy_vectors['net_value'][index+1] - self.fixed_assets_proy_vectors['net_value'][index] + self.fixed_assets_proy_vectors['period'][index + 1]) + + logger.info(f"[calculate_historic_new_capex] historicos de nuevo capex: {self.new_capex_vector}") + """ + self.new_capex_vector = [0] * self.historic_dates_len + + @handler_wrapper('Calculando proyecciones automaticas de nuevo capex', 'Proyecciones de nuevo capex calculadas con exito', 'Error calculando proyecciones automaticas de nuevo capex', 'Error calculando proyecciones de nuevo capex') + def proyeccion_auto_new_capex(self): + #Este metodo no se debería estar usando + try: + logger.info(f'[proyeccion_auto_new_capex] información requerida para sacar calcular proyecciones de nuevo capex:\nself.new_capex_vector: {self.new_capex_vector}\nself.user_chosen_vector: {self.user_chosen_vector}') + self.new_capex_projections = [self.new_capex_vector[-1] / self.user_chosen_vector[self.historic_dates_len -1] * self.user_chosen_vector[self.historic_dates_len]] + for index, user_chosen_value in enumerate(self.user_chosen_vector[self.historic_dates_len + 1:], start = self.historic_dates_len + 1): + self.new_capex_projections.append( user_chosen_value + self.user_chosen_vector[index - 1]) + + except: + self.new_capex_projections = [0] * self.projection_dates_len + self.noting_list.append({'TASK': self.current_context, 'NOTE':'Error calculando nuevo capex, esposible que la cuenta dependiente haya desaparecido o haya sido proyectada a cero'}) + logger.info(f'[proyeccion_auto_new_capex] resultado CAPEX: {self.new_capex_projections}') + + + @debugger_wrapper('Error calculando proyecciones de tipo porcentual de capex parcial', 'Error calculando proyecciones porcentuales de capex parcial') + def percentage_capex_projection(self): + manual_capex_atributes = [ item['MANUAL_PERCENTAGE'] for item in self.assessment_models['MODEL_CAPEX_VALUES'] if item ['CAPEX_NAME'] == self.current_capex_name][-self.projection_dates_len:] + manual_capex_atributes = [float(item) for item in manual_capex_atributes] + self.new_capex_projections = [i*j/100 for i,j in zip(self.user_chosen_vector, manual_capex_atributes)] + + + @debugger_wrapper('Error calculando proyecciones manuales de nuevo capex', 'Error calculando proyecciones de capex parcial') + def manual_projection(self): + self.new_capex_projections = [ item['MANUAL_PERCENTAGE'] for item in self.assessment_models['MODEL_CAPEX_VALUES'] if item ['CAPEX_NAME'] == self.current_capex_name][-self.projection_dates_len:] + self.new_capex_projections = [float(item) for item in self.new_capex_projections] + + + @handler_wrapper('Calculando depreciación de capex', 'Depreciación de capex calculada con exito', 'Error calculando depreciación de capex', 'Error calculando depreciación de capex') + def capex_depreciation(self): + dep_years = self.assessment_models['MODEL_CAPEX'][0]['PERIODS'] + dep_matrix = [[0] * len(self.new_capex_projections) for _ in self.new_capex_projections] + for index, value in enumerate(self.new_capex_projections): + yearly_dep_vector = value / dep_years + for year in range(dep_years): + try: + dep_matrix[index][index+1+year] = yearly_dep_vector + except: + break + logger.warning(f'[capex_depreciation] Matrix de depreciación capex:\n{dep_matrix}') + self.dep_capex = [0] * self.historic_dates_len + [sum(items) for items in zip(*dep_matrix)] + + + @handler_wrapper('Organizando records para envio a bd', 'Records de capex organizados con exito', 'Error organizando records de capex', 'Error guardando datos en bd') + def organize_db_records(self): + manual_capex_atributes = [ item['MANUAL_PERCENTAGE'] for item in self.assessment_models['MODEL_CAPEX_VALUES'] if item ['CAPEX_NAME'] == self.current_capex_name][-self.projection_dates_len:] + self.capex_values_records.extend([ asdict(capex_values_object(*args)) for args in zip([self.current_capex_name] * self.historic_dates_len, self.historic_dates_long, [''] * self.historic_dates_len, self.new_capex_vector, self.dep_capex)]) #sí acá me toca cambiar la forma de las fechas debo inyectarlo manualmente + self.capex_values_records.extend([ asdict(capex_values_object(*args)) for args in zip([self.current_capex_name] * self.projection_dates_len, self.projection_dates_long, manual_capex_atributes, self.new_capex_vector[self.historic_dates_len:], self.dep_capex[self.historic_dates_len:])]) + + +def get_current_error_line(): + return str(sys.exc_info()[-1].tb_lineno) \ No newline at end of file diff --git a/corporate_finances_back_py/super-orchestrator/_calc_other_projections.py b/corporate_finances_back_py/super-orchestrator/_calc_other_projections.py new file mode 100644 index 0000000..0a6cb02 --- /dev/null +++ b/corporate_finances_back_py/super-orchestrator/_calc_other_projections.py @@ -0,0 +1,163 @@ +from decorators import handler_wrapper, timing, debugger_wrapper, runs_ok +import logging +import pandas as pd +import datetime +import sys +from _projection_methods import projection_calc_class +from dataclasses_box import other_modal_results_object, modal_windows_projected_object, asdict + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + + +class other_projections_class(projection_calc_class): + @handler_wrapper('Actualizando pantalla de capital de trabajo', 'Capital de trabajo actualizado con exito', 'Error actualizando capital de trabajo', 'Error actualizando capital de trabajo') + def other_projections_recalc(self): + self.op_info = [item for item in self.assessment_models['MODEL_MODAL_WINDOWS'] if item['CONTEXT_WINDOW'] == 'other_projections'] + if not self.op_info: + logger.warning('[working_capital_class] No se encontró modelo de capital de trabajo') + #self.noting_list.append({'TASK': self.current_context, 'NOTE': "No se halló modelo para calculo de otras proyecciones"}) + return + + self.organizer = { + "Cero": self.op_zero, + "Valor constante": self.op_constant, + "Input": self.op_input, + "Tasa de crecimiento fija": self.op_fixed, + "Porcentaje de otra variable": self.op_master_dependencies, + "Tasas impositivas": self.op_master_dependencies} + + self.op_projected_vectors = dict() + self.op_proy_records = list() + + self.op_add_merge_account_original_values() + self.op_projections_loop() + + self.op_organize_items() + self.calculate_op_inputs() + self.op_summary() + + self.df_and_upload(self.op_info, 'MODAL_WINDOWS', and_clause='AND CONTEXT_WINDOW = "other_projections"') + + self.df_and_upload(self.op_proy_records, 'MODAL_WINDOWS_PROJECTED', and_clause='AND CONTEXT_WINDOW = "other_projections"') + + self.df_and_upload(self.op_results_records, 'OTHER_MODAL_RESULTS') + + + @handler_wrapper('Emergiendo valores originales de las cuentas proyectadas', 'Valores originales adquiridos', 'Error emergiendo valores originales de cuentas proyectadas en patrmonio', 'Error adquiriendo valores originales de cuentas de patrimonio') + def op_add_merge_account_original_values(self): + assessment_accounts = [item['account'] for item in self.purged_items if item['classification'] in ['Otros movimientos que no son salida ni entrada de efectivo no operativos','Otros movimientos que no son salida ni entrada de efectivo operativos','Otros movimientos netos de activos operativos que afecta el FCLO','Otros movimientos netos de activos operativos que afecta el FCLA']] + modal_window_model_accounts = [item['ACCOUNT_NUMBER'] for item in self.op_info] + + for account in assessment_accounts: + if account not in modal_window_model_accounts: + self.op_info.append({'ACCOUNT_NUMBER': account, 'CONTEXT_WINDOW':'other_projections', 'VS_ACCOUNT_NAME': 'Seleccione', 'PROJECTION_TYPE': 'Cero', 'COMMENT': 'Cuenta agregada por actualización de clasificaciones'}) + self.noting_list.append({'TASK': self.current_context, 'NOTE': f'Se agrega la cuenta {account} a la ventana modal de otras proyecciones'}) + + for account in modal_window_model_accounts: + if account not in assessment_accounts: + self.op_info = [item for item in self.op_info if item['ACCOUNT_NUMBER'] != account] + self.noting_list.append({'TASK': self.current_context, 'NOTE': f'Se elimina la cuenta {account} de la ventana modal de otras proyecciones'}) + + for item in self.op_info: + item['ORIGINAL_VALUE'] = self.get_historic_account_values(item['ACCOUNT_NUMBER'])[-1] + + + + @handler_wrapper('Iniciando loop de proyecciones de capital de trabajo', 'Loop de capital de trabajo terminado', 'Error calculando loop de capital de trabajo', 'Error calculando capital de trabajo') + def op_projections_loop(self): + items_to_project = self.op_info.copy() + max_loops = len(items_to_project) * len(items_to_project) + while max_loops: + if not items_to_project: + logger.warning(f'[op_projections_loop] Ya se acabaron los datos para proyectar') + break + + projecting_item = items_to_project.pop(0) + projected_success = self.organizer[projecting_item['PROJECTION_TYPE']](projecting_item) + if not projected_success: + logger.warning(f'[op_projections_loop] el item {projecting_item} no fue proyectado') + items_to_project.append(projecting_item) + max_loops = max_loops-1 + + if not max_loops: + logger.warning(f'[op_projections_loop] El loop se fue a infinito, pero no deberia porque depende de pyg que ya debería estar totalmente calculado') + infinite_cycle_rows = [row['ACCOUNT_NUMBER'] for row in items_to_project] + infinite_cycle_rows_str = str(infinite_cycle_rows).replace('[', '').replace(']', '') + self.noting_list.append({'TASK': self.current_context, 'NOTE': f"Las sigtes filas de pyg se fueron a ciclo infinito {infinite_cycle_rows_str}"}) + + + @runs_ok + @debugger_wrapper('Error proyectando zeros', 'Error proyectando un item con proyeccion cero') + def op_zero(self, projecting_item): + self.op_projected_vectors[projecting_item['ACCOUNT_NUMBER']] = self.pm_calculate_zero() + + + @runs_ok + @debugger_wrapper('Error proyectando constante', 'Error proyectando un item con proyeccion constante') + def op_constant(self, projecting_item): + self.op_projected_vectors[projecting_item['ACCOUNT_NUMBER']] = self.pm_calculate_constant(projecting_item['ORIGINAL_VALUE']) + + + @runs_ok + @debugger_wrapper('Error proyectando input', 'Error proyectando un item con proyeccion input') + def op_input(self, projecting_item): + projections = [float(item['ATRIBUTE']) for item in self.assessment_models['MODEL_MODAL_WINDOWS_PROJECTED'] if item['CONTEXT_WINDOW'] == 'other_projections' and item['ACCOUNT_NUMBER'] == projecting_item['ACCOUNT_NUMBER']] + self.op_projected_vectors[projecting_item['ACCOUNT_NUMBER']] = projections + + + @runs_ok + @debugger_wrapper('Error proyectando porcentaje fijo', 'Error proyectando un item con proyeccion a porcentajes') + def op_fixed(self, projecting_item): + fixed_percentages = [float(item['ATRIBUTE']) for item in self.assessment_models['MODEL_MODAL_WINDOWS_PROJECTED'] if item['CONTEXT_WINDOW'] == 'other_projections' and item['ACCOUNT_NUMBER'] == projecting_item['ACCOUNT_NUMBER']] + self.op_projected_vectors[projecting_item['ACCOUNT_NUMBER']] = self.pm_calculate_fixed(projecting_item['ORIGINAL_VALUE'], fixed_percentages) + + + @runs_ok + @debugger_wrapper("Error en calculo de proyecciones proporcionales", "Error calculando proyecciones") #si le colocas el debugger_wrapper se sobreescribe el AttributeError('personalizada') que espera master_items_loop + def op_master_dependencies(self, projecting_item): + vs_vector = self.pyg_values_vectors.get(projecting_item['VS_ACCOUNT_NAME']) + if projecting_item["PROJECTION_TYPE"] == 'Porcentaje de otra variable': + items_projections = self.pm_calculate_proportion(projecting_item['ORIGINAL_VALUE'], vs_vector) + if projecting_item["PROJECTION_TYPE"] == 'Tasas impositivas': + atributes = [float(item['ATRIBUTE']) for item in self.assessment_models['MODEL_MODAL_WINDOWS_PROJECTED'] if item['CONTEXT_WINDOW'] == 'other_projections' and item['ACCOUNT_NUMBER'] == projecting_item['ACCOUNT_NUMBER']] + items_projections = self.pm_calculate_impositive(atributes, vs_vector) + self.op_projected_vectors[projecting_item['ACCOUNT_NUMBER']] = items_projections + + + @handler_wrapper('Organizando items basicos de capital de trabajo', 'Resultados basicos de capital de trabajo calculados con exito', 'Error calculando bases de datos de capital de trabajo', 'Error organizando tablas de capital de trabajo') + def op_organize_items(self): + for item in self.op_info: + account = item['ACCOUNT_NUMBER'] + atri_vect = [row['ATRIBUTE'] for row in self.assessment_models['MODEL_MODAL_WINDOWS_PROJECTED'] if (row['CONTEXT_WINDOW'] == 'other_projections' and row['ACCOUNT_NUMBER'] == account)] + if not atri_vect: + atri_vect = [''] * len(self.projection_dates_long) + self.op_proy_records.extend([asdict(modal_windows_projected_object(proy_value, account, date, atri, 'other_projections')) for proy_value, date, atri in zip(self.op_projected_vectors[account], self.projection_dates_long, atri_vect)]) + + + @handler_wrapper('Creando directorio easy de cuentas y vector de historicos', 'Directorio de historicos creado con exito', 'Error creando directorio de historicos', 'Error organizando vector de valores historicos') + def calculate_op_inputs(self): + accounts_full_vectors = {} + for account, proy_vector in self.op_projected_vectors.items(): + historic_vector = self.get_historic_account_values(account) + accounts_full_vectors[account] = historic_vector + proy_vector + + self.variations_vectors = {} + for classification in ['Otros movimientos que no son salida ni entrada de efectivo operativos', 'Otros movimientos netos de activos operativos que afecta el FCLO', 'Otros movimientos netos de activos operativos que afecta el FCLA']: + classification_accounts = set(item['account'] for item in self.purged_items if item['account'] in self.op_projected_vectors and item['classification'] == classification) + if classification_accounts: + accounts_vectors = [accounts_full_vectors[account] for account in classification_accounts] + classification_vector = [sum(items) for items in zip(*accounts_vectors)] + else: + classification_vector = [0] * self.all_dates_len + self.variations_vectors[classification] = [0] + [ value - classification_vector[previous_index] for previous_index, value in enumerate(classification_vector[1:])] + logger.warning(f'[calculate_op_inputs] Resultados de variaciones para otras proyecciones:\n{self.variations_vectors}') + + + @handler_wrapper('Construyendo summary de Otras proyecciones', 'Lógica de otras proyecciones construída con exito', 'Error construyendo lógica de negocio de otras proyecciones', 'Error calculando resultados de otras proyecciones') + def op_summary(self): + self.op_results_records = [asdict(other_modal_results_object(date, i,j,k)) for date, i, j, k in zip(self.all_dates_long, *list(self.variations_vectors.values()))] + + +def get_current_error_line(): + return str(sys.exc_info()[-1].tb_lineno) \ No newline at end of file diff --git a/corporate_finances_back_py/super-orchestrator/_calc_patrimony.py b/corporate_finances_back_py/super-orchestrator/_calc_patrimony.py new file mode 100644 index 0000000..3ed687c --- /dev/null +++ b/corporate_finances_back_py/super-orchestrator/_calc_patrimony.py @@ -0,0 +1,172 @@ +from decorators import handler_wrapper, timing, debugger_wrapper, runs_ok +import logging +import pandas as pd +import datetime +import sys +from _projection_methods import projection_calc_class +from dataclasses_box import patrimony_results_object, modal_windows_projected_object, asdict + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + + +class patrimony_class(projection_calc_class): + @handler_wrapper('Actualizando pantalla de patrimonio', 'Patrimonio actualizado con exito', 'Error actualizando patrimonio', 'Error actualizando patrimonio') + def patrimony_recalc(self): + self.patrimony_info = [item for item in self.assessment_models['MODEL_MODAL_WINDOWS'] if item['CONTEXT_WINDOW'] == 'patrimony'] + if not self.patrimony_info: + logger.warning('[patrimony_class] No se encontró modelo de patrimonio') + #self.noting_list.append({'TASK': self.current_context, 'NOTE': "No se halló modelo para calculo de patrimonio"}) + return + + self.organizer = { + "Cero": self.patrimony_zero, + "Valor constante": self.patrimony_constant, + "Input": self.patrimony_input, + "Tasa de crecimiento fija": self.patrimony_fixed, + "Porcentaje de otra variable": self.patrimony_master_dependencies, + "Tasas impositivas": self.patrimony_master_dependencies} + + self.patrimony_projected_vectors = dict() + self.patrimony_account_history_vector = dict() + self.patrimony_classification_easy_dict = dict() + self.pat_social_capital_contributions = list() + self.patrimony_proy_records = list() + + self.pat_add_merge_account_original_values() + self.patrimony_projections_loop() + self.get_patrimony_historical_values() + + self.patrimony_organize_items() + self.patrimony_summary() + + self.df_and_upload(self.patrimony_info, 'MODAL_WINDOWS', and_clause='AND CONTEXT_WINDOW = "patrimony"') + + self.df_and_upload(self.patrimony_proy_records, 'MODAL_WINDOWS_PROJECTED', and_clause='AND CONTEXT_WINDOW = "patrimony"') + + self.df_and_upload(self.patrimony_results_records, 'PATRIMONY_RESULTS') + + + @handler_wrapper('Emergiendo valores originales de las cuentas proyectadas', 'Valores originales adquiridos', 'Error emergiendo valores originales de cuentas proyectadas en patrmonio', 'Error adquiriendo valores originales de cuentas de patrimonio') + def pat_add_merge_account_original_values(self): + assessment_accounts = [item['account'] for item in self.purged_items if item['classification'] in ['Aportes de capital social u otros', 'Cambios en el patrimonio']] + modal_window_model_accounts = [item['ACCOUNT_NUMBER'] for item in self.patrimony_info] + + for account in assessment_accounts: + if account not in modal_window_model_accounts: + self.patrimony_info.append({'ACCOUNT_NUMBER': account, 'CONTEXT_WINDOW':'patrimony', 'VS_ACCOUNT_NAME': 'Seleccione', 'PROJECTION_TYPE': 'Cero', 'COMMENT': 'Cuenta agregada por actualización de clasificaciones'}) + self.noting_list.append({'TASK': self.current_context, 'NOTE': f'Se agrega la cuenta {account} a la ventana modal de patrimonio'}) + + for account in modal_window_model_accounts: + if account not in assessment_accounts: + self.patrimony_info = [item for item in self.patrimony_info if item['ACCOUNT_NUMBER'] != account] + self.noting_list.append({'TASK': self.current_context, 'NOTE': f'Se elimina la cuenta {account} de la ventana modal de patrimonio'}) + + for item in self.patrimony_info: + item['ORIGINAL_VALUE'] = self.get_historic_account_values(item['ACCOUNT_NUMBER'])[-1] + + + + @handler_wrapper('Iniciando loop de proyecciones de patrimonio', 'Loop de patrimonio terminado', 'Error calculando loop de patrimonio', 'Error calculando patrimonio') + def patrimony_projections_loop(self): + items_to_project = self.patrimony_info.copy() + max_loops = len(items_to_project) * len(items_to_project) + while max_loops: + if not items_to_project: + logger.warning('[patrimony_projections_loop] Ya se acabaron los datos para proyectar') + break + + projecting_item = items_to_project.pop(0) + projected_success = self.organizer[projecting_item['PROJECTION_TYPE']](projecting_item) + if not projected_success: + logger.warning(f'[patrimony_projections_loop] el item {projecting_item} no fue proyectado') + items_to_project.append(projecting_item) + max_loops = max_loops-1 + + if not max_loops: + logger.warning('[patrimony_projections_loop] El loop se fue a infinito, pero no deberia porque depende de pyg que ya debería estar totalmente calculado') + infinite_cycle_rows = [row['ACCOUNT_NUMBER'] for row in items_to_project] + infinite_cycle_rows_str = str(infinite_cycle_rows).replace('[', '').replace(']', '') + self.noting_list.append({'TASK': self.current_context, 'NOTE': f"Las sigtes filas de pyg se fueron a ciclo infinito {infinite_cycle_rows_str}"}) + + + @runs_ok + @debugger_wrapper('Error proyectando zeros', 'Error proyectando un item con proyeccion cero') + def patrimony_zero(self, projecting_item): + self.patrimony_projected_vectors[projecting_item['ACCOUNT_NUMBER']] = self.pm_calculate_zero() + + + @runs_ok + @debugger_wrapper('Error proyectando constante', 'Error proyectando un item con proyeccion constante') + def patrimony_constant(self, projecting_item): + self.patrimony_projected_vectors[projecting_item['ACCOUNT_NUMBER']] = self.pm_calculate_constant(projecting_item['ORIGINAL_VALUE']) + + + @runs_ok + @debugger_wrapper('Error proyectando input', 'Error proyectando un item con proyeccion input') + def patrimony_input(self, projecting_item): + projections = [float(item['ATRIBUTE']) for item in self.assessment_models['MODEL_MODAL_WINDOWS_PROJECTED'] if item['CONTEXT_WINDOW'] == 'patrimony' and item['ACCOUNT_NUMBER'] == projecting_item['ACCOUNT_NUMBER']] + self.patrimony_projected_vectors[projecting_item['ACCOUNT_NUMBER']] = projections + + + @runs_ok + @debugger_wrapper('Error proyectando porcentaje fijo', 'Error proyectando un item con proyeccion a porcentajes') + def patrimony_fixed(self, projecting_item): + fixed_percentages = [float(item['ATRIBUTE']) for item in self.assessment_models['MODEL_MODAL_WINDOWS_PROJECTED'] if item['CONTEXT_WINDOW'] == 'patrimony' and item['ACCOUNT_NUMBER'] == projecting_item['ACCOUNT_NUMBER']] + self.patrimony_projected_vectors[projecting_item['ACCOUNT_NUMBER']] = self.pm_calculate_fixed(projecting_item['ORIGINAL_VALUE'], fixed_percentages) + + + @runs_ok + @debugger_wrapper("Error en calculo de proyecciones proporcionales", "Error calculando proyecciones") #si le colocas el debugger_wrapper se sobreescribe el AttributeError('personalizada') que espera master_items_loop + def patrimony_master_dependencies(self, projecting_item): + vs_vector = self.pyg_values_vectors.get(projecting_item['VS_ACCOUNT_NAME']) + if projecting_item["PROJECTION_TYPE"] == 'Porcentaje de otra variable': + items_projections = self.pm_calculate_proportion(projecting_item['ORIGINAL_VALUE'], vs_vector) + if projecting_item["PROJECTION_TYPE"] == 'Tasas impositivas': + #logger.debug(f'[patrimony_master_dependencies] A esto esta dando error: {projecting_item}') + atributes = [float(item['ATRIBUTE']) for item in self.assessment_models['MODEL_MODAL_WINDOWS_PROJECTED'] if item['CONTEXT_WINDOW'] == 'patrimony' and item['ACCOUNT_NUMBER'] == projecting_item['ACCOUNT_NUMBER']] + #logger.debug(f'[patrimony_master_dependencies] B esto esta dando error: {atributes}') + items_projections = self.pm_calculate_impositive(atributes, vs_vector) + #logger.debug(f'[patrimony_master_dependencies] C esto esta dando error: {items_projections}') + self.patrimony_projected_vectors[projecting_item['ACCOUNT_NUMBER']] = items_projections + + + + + @handler_wrapper('Organizando items basicos de patrimonio', 'Resultados basicos de patrimonio calculados con exito', 'Error calculando bases de datos de patrimonio', 'Error organizando tablas de patrimonio') + def patrimony_organize_items(self): + for item in self.patrimony_info: + account = item['ACCOUNT_NUMBER'] + atri_vect = [row['ATRIBUTE'] for row in self.assessment_models['MODEL_MODAL_WINDOWS_PROJECTED'] if (row['CONTEXT_WINDOW'] == 'patrimony' and row['ACCOUNT_NUMBER'] == account)] + if not atri_vect: + atri_vect = [''] * len(self.projection_dates_long) + logger.info(f'[mira aca] algo de esto está botando problemas: A {self.patrimony_projected_vectors[account]} \nB:{self.projection_dates_long}\nC:{atri_vect}') + self.patrimony_proy_records.extend([asdict(modal_windows_projected_object(proy_value, account, date, atri, 'patrimony')) for proy_value, date, atri in zip(self.patrimony_projected_vectors[account], self.projection_dates_long, atri_vect)]) + + + @handler_wrapper('Creando directorio easy de cuentas y vector de historicos', 'Directorio de historicos creado con exito', 'Error creando directorio de historicos', 'Error organizando vector de valores historicos') + def get_patrimony_historical_values(self): + self.patrimony_account_history_vector = {account: self.get_historic_account_values(account) for account in self.patrimony_projected_vectors} + for classification in ['Aportes de capital social u otros', 'Cambios en el patrimonio']: + self.patrimony_classification_easy_dict[classification] = set(item['account'] for item in self.purged_items if item['account'] in self.patrimony_projected_vectors and item['classification'] == classification) + + + @handler_wrapper('Construyendo summary de patrimonio', 'Lógica de patrimonio construída con exito', 'Error construyendo lógica de negocio de patrimonio', 'Error calculando resultados de patrimonio') + def patrimony_summary(self): + full_patrimony_vectors = {account: self.patrimony_account_history_vector[account] + self.patrimony_projected_vectors[account] for account in self.patrimony_projected_vectors} + classification_vector = {} + for classification in ['Aportes de capital social u otros', 'Cambios en el patrimonio']: + accounts_vectors = [full_patrimony_vectors[account] for account in self.patrimony_classification_easy_dict[classification]] + classification_vector[classification] = [sum(items) for items in zip(*accounts_vectors)] + + social_capital_contributions_deltas = [0] + for index, value in enumerate(classification_vector['Aportes de capital social u otros'][1:], start = 1): + social_capital_contributions_deltas.append(value - classification_vector['Aportes de capital social u otros'][index-1]) + + classification_vector['Cambios en el patrimonio'] = classification_vector['Cambios en el patrimonio'] if classification_vector['Cambios en el patrimonio'] else [0] * self.all_dates_len + cash_dividends = [-classification_vector['Cambios en el patrimonio'][0]] + for index, value in enumerate(classification_vector['Cambios en el patrimonio'][1:], start = 1): + cash_dividends.append(self.pyg_values_vectors['Utilidad neta'][index-1] - value + classification_vector['Cambios en el patrimonio'][index-1]) + + self.patrimony_results_records = [asdict(patrimony_results_object(*items)) for items in zip(self.all_dates_long, social_capital_contributions_deltas, cash_dividends)] + diff --git a/corporate_finances_back_py/super-orchestrator/_calc_pyg.py b/corporate_finances_back_py/super-orchestrator/_calc_pyg.py new file mode 100644 index 0000000..b64bad1 --- /dev/null +++ b/corporate_finances_back_py/super-orchestrator/_calc_pyg.py @@ -0,0 +1,159 @@ +from decorators import handler_wrapper, timing, debugger_wrapper +import logging +import pandas as pd +import datetime +import sys +from dataclasses import dataclass, asdict#, field #field es para cuando se debe crear algo en __post_init__ + +@dataclass +class pyg_results_object: + ID_RAW_PYG : str + DATES : str + VALUE : float + HINT : float + + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + + +class pyg_class(object): + @handler_wrapper('Actualizando datos iniciales de pyg', 'pyg primera parte calculada', 'Error calculando primera parte de pyg', 'Error actualizando pyg') + def pyg_first_half_recalc(self): + pyg_simple_calculations_A = ['Ingresos operacionales', + 'Costos (Sin depreciación)', + 'Gastos operacionales', + 'Otros ingresos operativos', + 'Otros egresos operativos', + 'Deterioro', + 'Impuestos de renta', + 'Intereses/gasto financiero', + 'Otros ingresos no operativos', + 'Otros egresos no operativos','Depreciación del Periodo', 'Amortización del Periodo'] + + #TODO: ver en vscode si a esta variable le puedo cambiar el nombre fácil, algo self.current_pyg_totals_A + self.current_pyg_totals = { 'Ingresos operacionales': {'dependencies': [], 'is_sum': []}, + 'Gastos operacionales': {'dependencies': [], 'is_sum': []}, + 'Otros ingresos y egresos operativos': {'dependencies':['Otros ingresos operativos','Otros egresos operativos'],'is_sum':[1,-1]}, + 'Otros ingresos y egresos no operativos': {'dependencies': ['Otros ingresos no operativos','Otros egresos no operativos'], 'is_sum': [1,-1]}, + 'Utilidad bruta': {'dependencies': ['Ingresos operacionales','Costos (Sin depreciación)'],'is_sum': [1, -1]}, + 'EBITDA': {'dependencies': ['Utilidad bruta','Gastos operacionales','Otros ingresos y egresos operativos'],'is_sum': [1, -1, 1]}} + + + for classification in pyg_simple_calculations_A: + classification_value_vector, classification_hint_vector = self.filter_classification(classification) + self.pyg_values_vectors[classification] = classification_value_vector + self.pyg_hints_vectors[classification] = classification_hint_vector + + parents_accounts = sorted(set(item['CLASSIFICATION'] for item in self.summary_data if item['IS_PARENT'])) + logger.warning(f'[pyg_first_half_recalc] parents_accounts encontrados: \n{parents_accounts}') + + for parent in parents_accounts: + sons_of = self.filter_parents_of(parent) + self.current_pyg_totals[parent]['dependencies'] = sons_of + self.current_pyg_totals[parent]['is_sum'] = [1] * len(sons_of) + + for total_partial, total_dict in self.current_pyg_totals.items(): + self.calculate_partial_totals(total_partial, total_dict, self.historic_dates_len) + + + del self.current_pyg_totals['Otros ingresos y egresos operativos'] + del self.current_pyg_totals['Otros ingresos y egresos no operativos'] + for classification in ['Otros ingresos operativos', 'Otros egresos operativos', 'Otros ingresos no operativos', 'Otros egresos no operativos']: + del self.pyg_values_vectors[classification] + + logger.warning(f'[pyg_first_half_recalc] Resultados pyg post calculadora\n**Vector de valores por clasificacion**\n{self.pyg_values_vectors}\n\n**Vector de hints por clasificacion**\n{self.pyg_hints_vectors}') + + + @debugger_wrapper('Error filtrando clasificaciones','Error construyendo clasificaciones') + def filter_classification(self, classification): + result = [item for item in self.summary_data if item['CLASSIFICATION'] == classification] + logger.warning(f'[filter_classification] Buscando clasificacion: {classification}, summary encontrado: {result}') + if not result: + return [0] * len(self.historic_dates), ['Clasificación no encontrada'] * len(self.historic_dates) + + value_vector = [item['value'] for item in result] + hint_vector = [item['hint'] for item in result] + return value_vector, hint_vector + + + @debugger_wrapper('Error filtrando clasificaciones','Error construyendo clasificaciones') + def filter_parents_of(self, parent): + found_sons_classifications = sorted(set(son['CLASSIFICATION'] for son in self.summary_data if son['CLASSIFICATION'].startswith(parent) and (son['IS_PARENT'] == 0))) + logger.warning(f'[filter_parents_of] Agregando values y hints de la clasificacion padre {parent}, clasificaciones hijas encontradas:\n{found_sons_classifications}') + for son_classification in found_sons_classifications: + classification_value_vector, classification_hint_vector = self.filter_classification(son_classification) + self.pyg_values_vectors[son_classification] = classification_value_vector + self.pyg_hints_vectors[son_classification] = classification_hint_vector + return found_sons_classifications + + + #TODO: tengo 3 totalizadores en total para pyg, depronto usando solo uno y agregandolo en el loop de proyecciones, pueda sacar más fácil esta pantalla + @handler_wrapper('Calculando totales parciales', 'Totales parciales calculadas', 'Error calculando totales parciales', 'No se pudieron calcular "Otros ingresos y egresos"') + def calculate_partial_totals(self, partial_total, dependencies_dict, hint_length): + self.pyg_values_vectors[partial_total] = self.calculate_total_vector(dependencies_dict['dependencies'], dependencies_dict['is_sum'], self.pyg_values_vectors) + self.pyg_hints_vectors[partial_total] = ['+ '.join(dependencies_dict['dependencies'])] * hint_length + logger.debug(f'[calculate_partial_totals] El vector de totales de {partial_total} obtenido es\n{self.pyg_values_vectors[partial_total]} a partir de las dependencias:{dependencies_dict}') + + + @handler_wrapper('Actualizando datos finales de pyg', 'pyg segunda parte calculada', 'Error calculando parte final de pyg', 'Error actualizando pyg') + def pyg_second_half_recalc(self): + self.current_pyg_totals.update({ 'EBIT':{'dependencies': ['EBITDA','Depreciación del Periodo','Amortización del Periodo','Deterioro', 'Depreciación Capex'], 'is_sum':[1,-1,-1,-1,-1]}, + 'Utilidad antes de impuestos':{'dependencies': ['EBIT','Otros ingresos y egresos no operativos','Intereses/gasto financiero'], 'is_sum':[1,1,-1]}, + 'Utilidad neta':{'dependencies': ['Utilidad antes de impuestos','Impuestos de renta'], 'is_sum':[1,-1]}}) + + + if self.capex_summary_records: + self.pyg_projected_vectors['Depreciación Capex'] = self.dep_capex[self.historic_dates_len:] + for name in ['Depreciación Capex', 'Depreciación del Periodo', 'Amortización del Periodo']: + self.pyg_values_vectors[name] = self.capex_summary_vectors.get(name, self.dep_capex) + self.pyg_hints_vectors[name] = ['Modificado desde Capex'] * self.all_dates_len + + self.pyg_projected_vectors[name] = self.capex_summary_vectors.get(name, self.dep_capex)[self.historic_dates_len:] + + logger.info(f'[pyg_second_half_recalc] datos que estan llegando desde el summary de capex {name}: {self.capex_summary_vectors.get(name, self.dep_capex)}') + + + else: + #pyg_simple_calculations_B.extend(['Depreciación del Periodo', 'Amortización del Periodo']) + self.current_pyg_totals['EBIT']['dependencies'].pop(-1) + self.current_pyg_totals['EBIT']['is_sum'].pop(-1) + for name in ['Depreciación del Periodo', 'Amortización del Periodo']: + self.pyg_values_vectors[name][self.historic_dates_len:] = [0] * self.projection_dates_len + + + if self.coupled_debt_records: + interest_proy_vector = [item['INTEREST_VALUE'] for item in self.coupled_debt_records] + self.pyg_values_vectors['Intereses/gasto financiero'][-self.projection_dates_len:] = interest_proy_vector + self.pyg_hints_vectors['Intereses/gasto financiero'][-self.projection_dates_len:] = ['Modificado por ventana modal de deuda'] * self.projection_dates_len + + + + @handler_wrapper('Creando records de pyg para carga en bd', 'Records de pyg creados con exito', 'Error creando records de pyg', 'Error creando tablas de pyg en bd') + def final_pyg(self, save_to_db = True): + logger.info(f'[mira aca] antes de nuevo calculo de totales: {self.pyg_values_vectors}') + for total_partial, total_dict in self.current_pyg_totals.items(): + self.calculate_partial_totals(total_partial, total_dict, self.all_dates_len) + + logger.info(f'[mira aca] despues de nuevo calculo de totales: {self.pyg_values_vectors}') + + if save_to_db: + self.create_pyg_records() + self.df_and_upload(self.pyg_results_records, 'PYG_RESULTS') + + #logger.info(f'[mira pyg aca] pyg que le mando a flujo de caja:\n{self.pyg_values_vectors}') + + + + @handler_wrapper('Creando records de pyg para carga en bd', 'Records de pyg creados con exito', 'Error creando records de pyg', 'Error creando tablas de pyg en bd') + def create_pyg_records(self): + self.pyg_results_records = [] + for name, values_vector in self.pyg_values_vectors.items(): + try: + records_to_add = [asdict(pyg_results_object(self.easy_raw_pyg_dict[name], *items)) for items in zip(self.all_dates_long, values_vector, self.pyg_hints_vectors[name])] + except: + logger.info(f'[create_pyg_records] No se encontraron propiedades para {name}, lo cual puede ser raro o directamente estar mal') + continue + if len(records_to_add) != self.all_dates_len: + raise Exception (f'revisar código: {name} se quedó corto:\nvalues:{values_vector}\nHint: {self.pyg_hints_vectors[name]}\nDates: {self.all_dates_long}') + self.pyg_results_records.extend( records_to_add ) diff --git a/corporate_finances_back_py/super-orchestrator/_calc_pyg_projections.py b/corporate_finances_back_py/super-orchestrator/_calc_pyg_projections.py new file mode 100644 index 0000000..36b477a --- /dev/null +++ b/corporate_finances_back_py/super-orchestrator/_calc_pyg_projections.py @@ -0,0 +1,291 @@ +from decorators import handler_wrapper, timing, debugger_wrapper +from dataclasses_box import pyg_item_object, pyg_projected_object, asdict +import logging +import pandas as pd +import datetime +import sys + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + + +class pyg_projections_class(object): + @handler_wrapper('Actualizando proyecciones de pyg', 'Proyecciones de pyg calculadas', 'Error calculando proyecciones de pyg', 'Error actualizando proyecciones pyg') + def pyg_first_half_projections_recalc(self): + if not self.assessment_models.get('MODEL_PROJECTED_PYG', False): #TODO: si acá en el modelo le saco las proyecciones sum, puedo ejecutar todo el loop sin necesidad de usar el metodo 'calculate_sum' + logger.warning(f'[pyg_projections_recalc] No hay atributos para las proyecciones de pyg') + #self.noting_list.append({'TASK': self.current_context, 'NOTE': f"No se halló información de proyeccion de pyg"}) + self.assessment_projections_found = False + return + self.obligatory_pyg_items = ['Costos (Sin depreciación)', + #'Depreciación del Periodo', + #'Amortización del Periodo', + 'Otros ingresos y egresos operativos', + 'Otros ingresos y egresos no operativos', + 'Deterioro', + 'Impuestos de renta', + 'Intereses/gasto financiero', + 'Ingresos operacionales', + 'Gastos operacionales', + 'Utilidad bruta', + 'EBITDA', + 'EBIT', + 'Utilidad antes de impuestos', + 'Utilidad neta', + 'Depreciación Capex'] + + self.organizer = { + "Cero": self.calculate_zero, + "Valor constante": self.calculate_constant, + "Input": self.calculate_input, + "Tasa de crecimiento fija": self.calculate_fixed, + "Porcentaje de otra variable": self.master_calculate_dependencies, + "Tasas impositivas": self.master_calculate_dependencies, + "sum": self.master_calculate_dependencies} + + self.pyg_projected_vectors = {} + self.pyg_projected_hints = {} + + self.initialize_zero_vectors() + self.merge_pyg_raw() + self.merge_summaries() + self.merge_atributes() + self.pyg_projections_master_loop() + logger.info(f'[mira aca] Al terminar el loop tengo estas proyecciones: {self.pyg_projected_vectors}') + self.calculate_projections_totals() + logger.warning(f'[pyg_projections_recalc] Vectores resultados de proyecciones:\n{self.pyg_projected_vectors}') + self.operation_income_vector = self.pyg_values_vectors['Ingresos operacionales'] + self.pyg_projected_vectors['Ingresos operacionales'] + self.save_assessment_step('PYG') + + @handler_wrapper('Inicializando vectores en cero para las proyecciones de pyg', 'Vectores inicializados en cero', 'Error inicializando vectores de proyecciones de pyg en cero', 'Error inicializando vectores') + def initialize_zero_vectors(self): + for pyg_row in self.pyg_values_vectors: + self.pyg_projected_vectors[pyg_row] = [0] * self.projection_dates_len + pyg_item_model_names = [self.id_raw_pyg_dict[item['ID_RAW_PYG']] for item in self.assessment_models['MODEL_PYG_ITEM']] + for item in self.obligatory_pyg_items: + if item not in pyg_item_model_names: + self.assessment_models['MODEL_PYG_ITEM'].append({'ID_RAW_PYG': self.easy_raw_pyg_dict[item], 'PROJECTION_TYPE': 'Cero', 'COMMENT': 'Cuenta obligatoria creada ya que fue omitida en el modelo', 'ID_DEPENDENCE': self.easy_raw_pyg_dict['No aplica']}) + + + @handler_wrapper('Emergiendo raw de pyg con datos existentes', 'Raw pyg emergido con exito', 'Error emergiendo raw de pyg', 'Error asignando nombres de pyg') + def merge_pyg_raw(self): + logger.warning(f'[mira aca] este es el modelo original: {self.assessment_models["MODEL_PYG_ITEM"]}') + for item in self.assessment_models['MODEL_PYG_ITEM']: + item['classification'] = self.id_raw_pyg_dict[item['ID_RAW_PYG']] + item['dependence'] = self.id_raw_pyg_dict[item['ID_DEPENDENCE']] + self.pyg_projected_hints[item['classification']] = item['PROJECTION_TYPE'] + if item['classification'].startswith(('Ingresos operacionales ','Gastos operacionales ')) and item['classification'] not in self.pyg_values_vectors: + self.noting_list.append({'TASK': self.current_context, 'NOTE': f'La cuenta {item["classification"]} proyectada, dejó de existir en el registro de clasificaciones'}) + + self.assessment_models['MODEL_PYG_ITEM'] = [item for item in self.assessment_models['MODEL_PYG_ITEM'] if item['classification'] in self.pyg_values_vectors] + + for item_name in [ item for item in self.pyg_values_vectors if item.startswith(('Ingresos operacionales ','Gastos operacionales '))]: + if not next((projection_item for projection_item in self.assessment_models['MODEL_PYG_ITEM'] if projection_item['classification'] == item_name), False): + self.assessment_models['MODEL_PYG_ITEM'].append({'classification': item_name, 'PROJECTION_TYPE': 'Cero', 'COMMENT': 'Nueva clasificacion, proyeccion no especificada', 'ID_RAW_PYG': self.easy_raw_pyg_dict[item_name], 'ID_DEPENDENCE': self.easy_raw_pyg_dict['No aplica']}) + self.pyg_projected_hints[item_name] = 'Cero' + self.noting_list.append({'TASK': self.current_context, 'NOTE': f'La cuenta {item_name} es nueva a la clasificación, se proyecta en ceros'}) + + + + @handler_wrapper('Emergiendo valore originales de pyg', 'Valores originales de pyg adquiridos', 'Error adquiriendo valores originales de filas pyg', 'Error calculando pygs') + def merge_summaries(self): + for item in self.assessment_models['MODEL_PYG_ITEM']: + if self.pyg_values_vectors.get(item['classification'], False): + item['value'] = self.pyg_values_vectors[item['classification']][-1] + else: + item['value'] = self.get_historic_summary_values(item['classification'])[-1] + + + @handler_wrapper('Emergiendo los atributos de las clasificaciones', 'Atributos emergidos correctamente', 'Error emergiendo atributos de lineas pyg', 'Error emergiendo caracteristicas de pyg') + def merge_atributes(self): + for item in self.assessment_models['MODEL_PYG_ITEM']: + item['atributes'] = [row['ATRIBUTE'] for row in self.assessment_models['MODEL_PROJECTED_PYG'] if row['ID_RAW_PYG'] == item['ID_RAW_PYG']] + if item['PROJECTION_TYPE'] == "sum": + try: + item['dependence'] = self.current_pyg_totals[item['classification']]['dependencies'] + item['is_sum'] = self.current_pyg_totals[item['classification']]['is_sum'] + except Exception: + logger.warning(f'[merge_atributes] no se emergió el item de total {item["classification"]} puede que sea parte de una sección posterior de pyg') + + + @handler_wrapper('Calculando loop de proyecciones', 'Loop de proyecciones terminado', 'Error calculando loop de proyecciones', 'Error calculando proyecciones') + def pyg_projections_master_loop(self): + logger.warning(f'[mira aca] este es el modelo a pasar a loop: {self.assessment_models["MODEL_PYG_ITEM"]}') + rows_to_project = self.assessment_models['MODEL_PYG_ITEM'].copy() + max_loops = len(rows_to_project) * len(rows_to_project) + while max_loops: + if not rows_to_project: + logger.warning(f'[pyg_projections_master_loop] Ya se acabaron los datos para proyectar') + break + + projecting_row = rows_to_project.pop(0) + projected_success = self.organizer[projecting_row['PROJECTION_TYPE']](projecting_row) + if not projected_success: + #logger.warning(f'[pyg_projections_master_loop] el item {projecting_row} no fue proyectado') + rows_to_project.append(projecting_row) + max_loops = max_loops-1 + + if not max_loops: + logger.warning(f'[pyg_projections_master_loop] el loop calculador de proyecciones se fue a infinito') + infinite_cycle_rows = [row['classification'] for row in rows_to_project] + infinite_cycle_rows_str = str(infinite_cycle_rows).replace('[', '').replace(']', '') + #self.noting_list.append({'TASK': self.current_context, 'NOTE': f"Las sigtes filas de pyg se fueron a ciclo infinito {infinite_cycle_rows_str}"}) + + + @debugger_wrapper('Error proyectando zeros', 'Error proyectando un item con proyeccion cero') + def calculate_zero(self, projecting_item): + projections = [0] * self.projection_dates_len + self.pyg_projected_vectors[projecting_item['classification']] = projections + return True + + + @debugger_wrapper('Error proyectando constante', 'Error proyectando un item con proyeccion constante') + def calculate_constant(self, projecting_item): + if projecting_item['classification'] in ('Otros ingresos y egresos no operativos', 'Otros ingresos y egresos operativos'): + self.pyg_projected_vectors[projecting_item['classification']] = [projecting_item['value']] * self.projection_dates_len + return True + + projections = [self.get_historic_summary_values(projecting_item['classification'])[-1]] * self.projection_dates_len + self.pyg_projected_vectors[projecting_item['classification']] = projections + return True + + @debugger_wrapper('Error proyectando input', 'Error proyectando un item con proyeccion input') + def calculate_input(self, projecting_item): + projections = [float(row['ATRIBUTE']) for row in self.assessment_models['MODEL_PROJECTED_PYG'] if row['ID_RAW_PYG'] == projecting_item['ID_RAW_PYG']] + logger.debug(f"[calculate_input] estas projectiones estan quedando en cero: {projections}, buscando {projecting_item['ID_RAW_PYG']} en {self.assessment_models['MODEL_PROJECTED_PYG']}") + self.pyg_projected_vectors[projecting_item['classification']] = projections + return True + + + @debugger_wrapper('Error proyectando porcentaje fijo', 'Error proyectando un item con proyeccion a porcentajes') + def calculate_fixed(self, projecting_item): + + fixed_percentages = [float(interest) for interest in projecting_item["atributes"]] + projections = [projecting_item["value"] * (1 + fixed_percentages[0]/100)] + for i in range(1, self.projection_dates_len): + projections.append(projections[i - 1] * (1 + fixed_percentages[i]/100)) + + self.pyg_projected_vectors[projecting_item['classification']] = projections + return True + + + @debugger_wrapper("Error en calculo de proyecciones proporcionales", "Error calculando proyecciones") #si le colocas el debugger_wrapper se sobreescribe el AttributeError('personalizada') que espera master_items_loop + def master_calculate_dependencies(self, projecting_item): + vs_item = self.search_vs_item_projections(projecting_item['dependence']) + if not vs_item: + return False + + return self.calculate_proportion_projections(projecting_item, vs_item) + + + @debugger_wrapper('Error buscando los vs dependientes del item a proyectar', 'Error, es posible que una relación dependiente esté masl descrita') + def search_vs_item_projections(self, current_item_vs): + if type(current_item_vs) is str: + return self.pyg_projected_vectors.get(current_item_vs, False) + + if type(current_item_vs) is list: + multi_vs_items = list(map(self.search_vs_item_projections, current_item_vs)) + if not all(multi_vs_items): + return False + return multi_vs_items + + + @debugger_wrapper("Error en el calculo de la proporcion", "Error calculando") + def calculate_proportion_projections(self, current_item, vs_item): + proportion_organizer = {'Porcentaje de otra variable':self.calculate_proportion, + 'Tasas impositivas':self.calculate_impositive, + 'sum':self.calculate_sum} + return proportion_organizer[current_item["PROJECTION_TYPE"]](current_item, vs_item) + + + @debugger_wrapper('Error generando items de sumatorias', 'Error en el calculo de item sumatorios') + def calculate_proportion(self, current_item, vs_item_vector): + projections = [current_item["value"]] + vs_item_vector.insert(0, self.get_historic_summary_values(current_item["dependence"])[-1]) + for i in range(1, self.projection_dates_len + 1): + try: + projections.append(projections[i - 1] / vs_item_vector[i - 1] * vs_item_vector[i]) + except Exception as e: + projections.append(0) + + projections.pop(0) + vs_item_vector.pop(0) + self.pyg_projected_vectors[current_item['classification']] = projections + return True + + + @debugger_wrapper('Error generando items de sumatorias', 'Error en el calculo de item sumatorios') + def calculate_impositive(self, current_item, vs_item_vector): + logger.info(f'[calculate_impositive] si está entrando al impositivo con los datos {current_item} y {vs_item_vector}') + projections = [] + for i in range(self.projection_dates_len): + projections.append(vs_item_vector[i] * float(current_item["atributes"][i])/100) + + self.pyg_projected_vectors[current_item['classification']] = projections + return True + + + @debugger_wrapper('Error generando items de sumatorias', 'Error en el calculo de item sumatorios') + def calculate_sum(self, current_item, _): + projections = self.calculate_total_vector(current_item['dependence'], current_item['is_sum'], self.pyg_projected_vectors) + self.pyg_projected_vectors[current_item['classification']] = projections + return True + + #TODO si este totalizador lo meto en el loop, puede ser buena idea + @handler_wrapper('Calculando totales de salida con los datos encontrados', 'Totales de proyecciones de pyg calculados correctamente', 'Error calculando totales de proyecciones de pyg', 'Error calculando totales de pyg') + def calculate_projections_totals(self): + for key, depen_signs in self.current_pyg_totals.items(): + self.pyg_projected_vectors[key] = self.calculate_total_vector(depen_signs['dependencies'], depen_signs['is_sum'], self.pyg_projected_vectors) + logger.info(f'[calculate_projections_totals] El vector de totales de {key} obtenido es {self.pyg_projected_vectors[key]}') + + + @handler_wrapper('Organizando records de pyg', 'Records de pyg organizados con exito', 'Error organizando records de pyg', 'Error orgnizando tablas de pyg') + def organize_pyg_records(self): + try: + self.pyg_items_records = [asdict(pyg_item_object(item['ID_RAW_PYG'], item['ID_DEPENDENCE'], item['value'], item['PROJECTION_TYPE'], item['COMMENT'])) for item in self.assessment_models['MODEL_PYG_ITEM']] + except: + pass + + self.pyg_projection_records = [] + logger.info(f'[organize_pyg_records] este es antes de crear records: {self.pyg_projected_vectors}') + for classification, proy_vector in self.pyg_projected_vectors.items(): + logger.warning(f'[mira aca] este diccionario no posee depreciacion del periodo: {self.easy_raw_pyg_dict}') + id_raw_pyg = self.easy_raw_pyg_dict[classification] + logger.info(f'[mira aca] este objeto no tiene clasification: {self.assessment_models["MODEL_PYG_ITEM"]}') + atributes_vector = next((item['atributes'] for item in self.assessment_models['MODEL_PYG_ITEM'] if item['classification'] == classification), False) + if not atributes_vector: + atributes_vector = [''] * self.projection_dates_len + for date, value, atribute in zip(self.projection_dates_long, proy_vector, atributes_vector): + self.pyg_projection_records.append(asdict(pyg_projected_object(id_raw_pyg, date, value, atribute))) + + logger.info(f'[organize_pyg_records] Records creados de pyg proyecciones: {self.pyg_projection_records}') + + + @handler_wrapper('Emergiendo proyecciones de pyg a la calculadora de pyg', 'Proyecciones emergidas con exito', 'Error emergiendo proyecciones de pyg a calculdora de pyg', 'Error emergiendo resultados de pyg') + def merge_proyections_to_pyg_vectors(self): + logger.info(f'[mira aca] parece que aca se metió un no aplica: {self.pyg_projected_vectors}') + logger.info(f'[mira aca] antes de agregar proyecciones: {self.pyg_values_vectors}') + for classification, proy_vector in self.pyg_projected_vectors.items(): + try: + #self.pyg_values_vectors.get(classification, []).extend(proy_vector) #en este + self.pyg_values_vectors[classification] = self.pyg_values_vectors.get(classification, [])[:self.historic_dates_len] + proy_vector + proy_hints_vector = [self.pyg_projected_hints.get(classification, 'Posible cuenta no proyectada')] * self.projection_dates_len + #self.pyg_hints_vectors.get(classification, []).extend(proy_hints_vector) #y en este, no deberìa manejarse extend sino self.pyg_hints_vectors.get(classification, []) = self.pyg_hints_vectors.get(classification, [])[self.historic_dates_len] + proy_hints_vector + self.pyg_hints_vectors[classification] = self.pyg_hints_vectors.get(classification, [])[:self.historic_dates_len] + proy_hints_vector + except Exception as e: + logger.info(f'[merge_proyections_to_pyg_vectors] no se extienden las proyecciones de {classification} al pyg, motivo: {str(e)}') + continue + logger.info(f'[mira aca] despues de agregar proyecciones: {self.pyg_values_vectors}') + + + @handler_wrapper('Calculando totales finales de pyg proyecciones', 'Segundos totales de pyg proyecciones calculados con exito', 'Error calculando totales finales de pyg proyecciones', 'Error calculando totales de proyecciones pyg') + def pyg_final_projections_recalc(self, save_to_db = True): + self.calculate_projections_totals() + self.organize_pyg_records() + self.merge_proyections_to_pyg_vectors() + + if save_to_db: + self.df_and_upload(self.pyg_items_records, 'PYG_ITEM') + self.df_and_upload(self.pyg_projection_records, 'PROJECTED_PYG') + self.save_assessment_step("CAPEX") + \ No newline at end of file diff --git a/corporate_finances_back_py/super-orchestrator/_calc_working_capital.py b/corporate_finances_back_py/super-orchestrator/_calc_working_capital.py new file mode 100644 index 0000000..369d9c8 --- /dev/null +++ b/corporate_finances_back_py/super-orchestrator/_calc_working_capital.py @@ -0,0 +1,164 @@ +from decorators import handler_wrapper, timing, debugger_wrapper, runs_ok +import logging +import pandas as pd +import datetime +import sys +from _projection_methods import projection_calc_class +from dataclasses_box import wk_results_object, modal_windows_projected_object, asdict + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + + +class working_capital_class(projection_calc_class): + @handler_wrapper('Actualizando pantalla de capital de trabajo', 'Capital de trabajo actualizado con exito', 'Error actualizando capital de trabajo', 'Error actualizando capital de trabajo') + def working_capital_recalc(self): + self.wk_info = [item for item in self.assessment_models['MODEL_MODAL_WINDOWS'] if item['CONTEXT_WINDOW'] == 'wk'] + if not self.wk_info: + logger.warning(f'[working_capital_class] No se encontró modelo de capital de trabajo') + #self.noting_list.append({'TASK': self.current_context, 'NOTE': f"No se halló modelo para calculo de capital de trabajo"}) + return + + self.organizer = { + "Cero": self.wk_zero, + "Valor constante": self.wk_constant, + "Input": self.wk_input, + "Tasa de crecimiento fija": self.wk_fixed, + "Porcentaje de otra variable": self.wk_master_dependencies, + "Tasas impositivas": self.wk_master_dependencies} + + self.wk_projected_vectors = dict() + self.wk_db_records = list() + + self.wk_add_merge_account_original_values() + self.wk_projections_loop() + + self.wk_organize_items() + self.calculate_wk_inputs() + self.wk_summary() + + self.df_and_upload(self.wk_info, 'MODAL_WINDOWS', and_clause='AND CONTEXT_WINDOW = "wk"') + + self.df_and_upload(self.wk_db_records, 'MODAL_WINDOWS_PROJECTED', and_clause='AND CONTEXT_WINDOW = "wk"') + + self.df_and_upload(self.wk_results_records, 'WK_RESULTS') + + + @handler_wrapper('Emergiendo valores originales de las cuentas proyectadas', 'Valores originales adquiridos', 'Error emergiendo valores originales de cuentas proyectadas en patrmonio', 'Error adquiriendo valores originales de cuentas de patrimonio') + def wk_add_merge_account_original_values(self): + assessment_accounts = [item['account'] for item in self.purged_items if item['classification'] == 'Capital de trabajo'] + modal_window_model_accounts = [item['ACCOUNT_NUMBER'] for item in self.wk_info] + + for account in assessment_accounts: + if account not in modal_window_model_accounts: + self.wk_info.append({'ACCOUNT_NUMBER': account, 'CONTEXT_WINDOW':'wk', 'VS_ACCOUNT_NAME': 'Seleccione', 'PROJECTION_TYPE': 'Cero', 'COMMENT': 'Cuenta agregada por actualización de clasificaciones'}) + self.noting_list.append({'TASK': self.current_context, 'NOTE': f'Se agrega la cuenta {account} a la ventana modal de capital de trabajo'}) + + for account in modal_window_model_accounts: + if account not in assessment_accounts: + self.wk_info = [item for item in self.wk_info if item['ACCOUNT_NUMBER'] != account] + self.noting_list.append({'TASK': self.current_context, 'NOTE': f'Se elimina la cuenta {account} de la ventana modal de capital de trabajo'}) + + for item in self.wk_info: + item['ORIGINAL_VALUE'] = self.get_historic_account_values(item['ACCOUNT_NUMBER'])[-1] + + + + @handler_wrapper('Iniciando loop de proyecciones de capital de trabajo', 'Loop de capital de trabajo terminado', 'Error calculando loop de capital de trabajo', 'Error calculando capital de trabajo') + def wk_projections_loop(self): + items_to_project = self.wk_info.copy() + logger.info(f'[mira aca] esto es lo que se va a loopear de capital de trabajo: {items_to_project}') + max_loops = len(items_to_project) * len(items_to_project) + while max_loops: + if not items_to_project: + logger.warning(f'[wk_projections_loop] Ya se acabaron los datos para proyectar') + break + + projecting_item = items_to_project.pop(0) + projected_success = self.organizer[projecting_item['PROJECTION_TYPE']](projecting_item) + if not projected_success: + logger.warning(f'[wk_projections_loop] el item {projecting_item} no fue proyectado') + items_to_project.append(projecting_item) + max_loops = max_loops-1 + + if not max_loops: + logger.warning(f'[wk_projections_loop] El loop se fue a infinito, pero no deberia porque depende de pyg que ya debería estar totalmente calculado') + infinite_cycle_rows = [row['ACCOUNT_NUMBER'] for row in items_to_project] + infinite_cycle_rows_str = str(infinite_cycle_rows).replace('[', '').replace(']', '') + self.noting_list.append({'TASK': self.current_context, 'NOTE': f"Las sigtes filas de pyg se fueron a ciclo infinito {infinite_cycle_rows_str}"}) + + logger.info(f'[mira aca] resultado de los loops de capital de trabajo {self.wk_projected_vectors} ') + + + @runs_ok + @debugger_wrapper('Error proyectando zeros', 'Error proyectando un item con proyeccion cero') + def wk_zero(self, projecting_item): + self.wk_projected_vectors[projecting_item['ACCOUNT_NUMBER']] = self.pm_calculate_zero() + + + @runs_ok + @debugger_wrapper('Error proyectando constante', 'Error proyectando un item con proyeccion constante') + def wk_constant(self, projecting_item): + self.wk_projected_vectors[projecting_item['ACCOUNT_NUMBER']] = self.pm_calculate_constant(projecting_item['ORIGINAL_VALUE']) + + + @runs_ok + @debugger_wrapper('Error proyectando input', 'Error proyectando un item con proyeccion input') + def wk_input(self, projecting_item): + projections = [float(item['ATRIBUTE']) for item in self.assessment_models['MODEL_MODAL_WINDOWS_PROJECTED'] if item['CONTEXT_WINDOW'] == 'wk' and item['ACCOUNT_NUMBER'] == projecting_item['ACCOUNT_NUMBER']] + self.wk_projected_vectors[projecting_item['ACCOUNT_NUMBER']] = projections + + + @runs_ok + @debugger_wrapper('Error proyectando porcentaje fijo', 'Error proyectando un item con proyeccion a porcentajes') + def wk_fixed(self, projecting_item): + fixed_percentages = [float(item['ATRIBUTE']) for item in self.assessment_models['MODEL_MODAL_WINDOWS_PROJECTED'] if item['CONTEXT_WINDOW'] == 'wk' and item['ACCOUNT_NUMBER'] == projecting_item['ACCOUNT_NUMBER']] + self.wk_projected_vectors[projecting_item['ACCOUNT_NUMBER']] = self.pm_calculate_fixed(projecting_item['ORIGINAL_VALUE'], fixed_percentages) + + + @runs_ok + @debugger_wrapper("Error en calculo de proyecciones proporcionales", "Error calculando proyecciones") #si le colocas el debugger_wrapper se sobreescribe el AttributeError('personalizada') que espera master_items_loop + def wk_master_dependencies(self, projecting_item): + vs_vector = self.pyg_values_vectors.get(projecting_item['VS_ACCOUNT_NAME']) + if projecting_item["PROJECTION_TYPE"] == 'Porcentaje de otra variable': + logger.info(f"[mira aca] le voy a inyectar: {projecting_item['ORIGINAL_VALUE']} y vs vector {vs_vector}") + items_projections = self.pm_calculate_proportion(projecting_item['ORIGINAL_VALUE'], vs_vector) + logger.info(f"[mira aca] con resultados: {items_projections}") + if projecting_item["PROJECTION_TYPE"] == 'Tasas impositivas': + atributes = [float(item['ATRIBUTE']) for item in self.assessment_models['MODEL_MODAL_WINDOWS_PROJECTED'] if item['CONTEXT_WINDOW'] == 'wk' and item['ACCOUNT_NUMBER'] == projecting_item['ACCOUNT_NUMBER']] + items_projections = self.pm_calculate_impositive(atributes, vs_vector) + self.wk_projected_vectors[projecting_item['ACCOUNT_NUMBER']] = items_projections + + + @handler_wrapper('Organizando items basicos de capital de trabajo', 'Resultados basicos de capital de trabajo calculados con exito', 'Error calculando bases de datos de capital de trabajo', 'Error organizando tablas de capital de trabajo') + def wk_organize_items(self): + for item in self.wk_info: + account = item['ACCOUNT_NUMBER'] + atri_vect = [row['ATRIBUTE'] for row in self.assessment_models['MODEL_MODAL_WINDOWS_PROJECTED'] if (row['CONTEXT_WINDOW'] == 'wk' and row['ACCOUNT_NUMBER'] == account)] + if not atri_vect: + atri_vect = [''] * len(self.projection_dates_long) + self.wk_db_records.extend([asdict(modal_windows_projected_object(proy_value, account, date, atri, 'wk')) for proy_value, date, atri in zip(self.wk_projected_vectors[account], self.projection_dates_long, atri_vect)]) + + + @handler_wrapper('Creando directorio easy de cuentas y vector de historicos', 'Directorio de historicos creado con exito', 'Error creando directorio de historicos', 'Error organizando vector de valores historicos') + def calculate_wk_inputs(self): + self.active_pasive_vectors = {} + for account, proy_vector in self.wk_projected_vectors.items(): + historic_values = self.get_historic_account_values(account) + summed_vector = [i+j for i,j in zip(self.active_pasive_vectors.get(account[0], [0] * self.all_dates_len), historic_values + proy_vector)] + self.active_pasive_vectors[account[0]] = summed_vector + logger.info(f'[calculate_wk_inputs] Vectorización de capital de trabajo:\n{self.active_pasive_vectors}') + + @handler_wrapper('Construyendo summary de capital de trabajo', 'Lógica de capital de trabajo construída con exito', 'Error construyendo lógica de negocio de capital de trabajo', 'Error calculando resultados de capital de trabajo') + def wk_summary(self): + self.yearly_working_capital = [i-j for i,j in zip(self.active_pasive_vectors['1'], self.active_pasive_vectors['2'])] + self.wk_results = [value - self.yearly_working_capital[previous_index] for previous_index, value in enumerate(self.yearly_working_capital[1:])] + self.wk_results.insert(0, 0) + logger.info(f'[wk_summary] Resultado summary de working capital:\n{self.wk_results}') + self.wk_results_records = [asdict(wk_results_object(date, variation)) for date, variation in zip(self.all_dates_long, self.wk_results)] + + + + +def get_current_error_line(): + return str(sys.exc_info()[-1].tb_lineno) \ No newline at end of file diff --git a/corporate_finances_back_py/super-orchestrator/_full_dynamic.py b/corporate_finances_back_py/super-orchestrator/_full_dynamic.py new file mode 100644 index 0000000..9cce56a --- /dev/null +++ b/corporate_finances_back_py/super-orchestrator/_full_dynamic.py @@ -0,0 +1,61 @@ +from sqlalchemy import text +from decorators import handler_wrapper, timing, debugger_wrapper +import logging +import pandas as pd +import datetime +import sys +from models_tables import simple_atributes_tables, ordered_atributes_tables +from dataclasses import dataclass, asdict#, field #field es para cuando se debe crear algo en __post_init__ + + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + + + +class dynamic_class(object): + @debugger_wrapper('Error en starter de recurrence_class', 'Error en master de recurrencia') + def full_dynamic_starter(self): + self.get_assessment_dates() + self.acquire_assessment_simple_attributes() + self.acquire_assessment_ordered_attributes() + + @handler_wrapper('Obteniendo las fechas del proceso de valoración', 'Fechas del proceso de valroación obtenidas con exito', 'Error obteniendo las fechas del proceso de valoración', 'Error obteniendo fechas del proceso de valoración') + def get_assessment_dates(self): + query = "SELECT DATES, PROPERTY FROM ASSESSMENT_DATES WHERE ID_ASSESSMENT = :id_assessment ORDER BY DATES" + logger.info(f"[get_assessment_dates] Query a base de datos para obtener las fechas utilizadas en el proces de valoración:\n {query}") + rds_data = self.db_connection.execute(text(query), {"id_assessment":self.id_assessment}) + directory = {'HISTORIC': self.historic_dates, 'PROJECTION': self.projection_dates} + for date_item in rds_data.fetchall(): + directory.get(date_item.PROPERTY, []).append(date_item.DATES) + + #self.historic_dates = [date.strftime('%Y-%m-%d %H:%M:%S') for date in self.historic_dates] + self.projection_dates = [date.strftime('%Y-%m-%d') for date in self.projection_dates] + logger.info(f'[get_assessment_dates] Fechas del proceso de valoración:\nhistoricas: {self.historic_dates}\nproyecciones: {self.projection_dates}') + + @handler_wrapper('Obteniendo Atributos simples del proceso de valoración', 'Atributos simples del proceso de valoración obtenidos con exito', 'Error obteniendo los atributos simples del proceso de valoración', 'Error obteniendo atributos del proceso de valoración') + def acquire_assessment_simple_attributes(self): + for table, columns in simple_atributes_tables.items(): + cleaned_columns = str(columns).replace('[','').replace(']','').replace("'", '') + query = f"SELECT {cleaned_columns} FROM {table} WHERE ID_ASSESSMENT = :id_assessment" + logger.info(f"[acquire_assessment_simple_attributes] Query a base de datos para obtener los atributos de la tabla {table}:\n{query}") + rds_data = self.db_connection.execute(text(query), {"id_assessment":self.id_assessment}) + self.assessment_models[f'MODEL_{table}'] = [row._asdict() for row in rds_data.fetchall()] + logger.warning(f'[acquire_assessment_simple_attributes] Modelo hallado para la tabla {table}:\n{self.assessment_models[f"MODEL_{table}"]}') + + + @handler_wrapper('Obteniendo Atributos del proceso de valoración', 'Atributos del proceso de valoración obtenidos con exito', 'Error obteniendo atributos del proceso de valoración', 'Error obteniendo atributos del proceso de valoración') + def acquire_assessment_ordered_attributes(self): + for table, cols_order in ordered_atributes_tables.items(): + cleaned_columns = str(cols_order['columns']).replace('[','').replace(']','').replace("'", '') + query = f"SELECT {cleaned_columns} FROM {table} WHERE ID_ASSESSMENT = :id_assessment ORDER BY {cols_order['order']}" + logger.info(f"[acquire_assessment_ordered_attributes] Query a base de datos para obtener los atributos de la tabla {table}:\n{query}") + rds_data = self.db_connection.execute(text(query), {"id_assessment":self.id_assessment}) + self.assessment_models[f'MODEL_{table}'] = [row._asdict() for row in rds_data.fetchall()] + logger.warning(f'[acquire_assessment_ordered_attributes] Modelo hallado para la tabla MODEL_{table}:\n{self.assessment_models[f"MODEL_{table}"]}') + + + + +def get_current_error_line(): + return str(sys.exc_info()[-1].tb_lineno) \ No newline at end of file diff --git a/corporate_finances_back_py/super-orchestrator/_full_recurrence.py b/corporate_finances_back_py/super-orchestrator/_full_recurrence.py new file mode 100644 index 0000000..cb64710 --- /dev/null +++ b/corporate_finances_back_py/super-orchestrator/_full_recurrence.py @@ -0,0 +1,280 @@ +from sqlalchemy import text +from decorators import handler_wrapper, debugger_wrapper +import logging +import datetime +import sys +from models_tables import models_tables +from dataclasses import dataclass, asdict#, field #field es para cuando se debe crear algo en __post_init__ +from dataclasses_box import assessment_checked_object, classification_summary_object + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + + + +class recurrence_class(object): + @debugger_wrapper('Error en starter de recurrence_class', 'Error en master de recurrencia') + def full_recurrence_starter(self): + self.archive_pucs_data = dict() + self.assessment_checked_records = list() + self.classification_summary_records = list() + + self.assesstment_archive_data() + self.get_assessment_data() + + self.get_company_id() + self.acquire_model_atributtes() + self.calculate_assessment_historic_dates() + self.upload_historic_assessment_dates() + + if not self.assessment_models['MODEL_USER_CLASSIFICATION']: + return #Este return me asegura que si no se hallaron modelos, no se va a construir nada de recucrrencia; esta validaciòn la hace el front con otro servicio, colocarlo acá puede ser redundante + + + self.df_and_upload(self.assessment_models['MODEL_USER_CLASSIFICATION'], 'USER_CLASSIFICATION') + self.save_assessment_step("CLASSIFICATION") + if not self.calculate_recurrence: #Si el front pide no hacer recurrencia, no se hace nada más + return + + + self.calculate_assessment_projection_dates() + + self.upload_new_assessment_dates() + self.new_assessment_summary_builder() + self.master_process_recurrence_pucs() + + self.df_and_upload(self.assessment_checked_records, 'ASSESSMENT_CHECKED') + + self.df_and_upload(self.classification_summary_records, 'CLASSIFICATION_SUMMARY') + + self.df_and_upload(self.assessment_models['MODEL_USER_CLASSIFICATION'], 'USER_CLASSIFICATION') + + + @handler_wrapper('Adquiriendo información del puc a valorar', 'Información adquirida con exito', 'Error adquiriendo información del PUC a valorar', 'Error adquiriendo información de puc') + def assesstment_archive_data(self): + query = 'SELECT B.ID FROM COMPANY A, ARCHIVE B WHERE A.ID = B.ID_COMPANY AND A.NIT = :nit AND B.INITIAL_DATE = :current_long_date AND B.PERIODICITY = :current_periodicity LIMIT 1' + logger.info(f'[assesstment_archive_data] Query para obtener datos del puc de valoracion: {query}') + rds_data = self.db_connection.execute(text(query), {'nit':self.nit, 'current_long_date': self.current_long_date, 'current_periodicity': self.current_periodicity}) + self.this_assessment_archive_id = rds_data.scalar() + + + @handler_wrapper('Buscando existencia del modelo','Chequeo de id_assessment terminado','Error chequeando si existe un id_assessment para este proceso de valoración en particulas','Se encontraron problemas chequeando posible existencia del proceso de valoración') + def get_assessment_data(self): + query = 'SELECT * FROM COMPANY A, ARCHIVE B, ASSESSMENT C WHERE A.ID = B.ID_COMPANY AND C.ID_ARCHIVE = B.ID AND A.NIT = :nit AND B.INITIAL_DATE = :current_long_date AND B.PERIODICITY = :current_periodicity AND C.USER = :user LIMIT 1' + logger.info(f'[get_assessment_data] Query para obtener datos del proceso de valoracion: {query}') + rds_data = self.db_connection.execute(text(query), {'nit':self.nit, 'current_long_date': self.current_long_date, 'current_periodicity': self.current_periodicity, 'user':self.user}) + try: + self.assessment_data = [row._asdict() for row in rds_data.fetchall()][0] + + self.id_assessment = self.assessment_data['ID'] + logger.info(f'[get_assessment_data] El proceso de valoración fue encontrado y tiene un id_assessment: {self.id_assessment}') + except Exception as e: + logger.info(f'[get_assessment_data] El proceso de valoración no existe, {str(e)}') + today_date = datetime.datetime.today().strftime('%Y-%m-%d %H:%M:%S') + query = f'INSERT INTO ASSESSMENT (ID_ARCHIVE, USER, ASSESSMENT_DATE,STATUS) VALUES ({self.this_assessment_archive_id}, "{self.user}", "{today_date}", \"Partial\")' + logger.info(f'[create_id_assessment] Query de creacion assessment: {query}') + self.db_connection.execute(text(query)) + self.get_assessment_data() + + + @handler_wrapper('Obteniendo el ID de la empresa', 'ID de la empresa obtenido con exito', 'Error obteniendo ID de la empresa', 'Error obteniendo identificador de empresa') + def get_company_id(self): + query = "SELECT ID FROM COMPANY WHERE NIT = :nit LIMIT 1" + logger.info(f'[get_company_id] Query para obtener el ID de la empresa que se está valorando: {query}') + rds_data = self.db_connection.execute(text(query), {'nit':self.nit}) + self.id_company = int(rds_data.scalar()) + + @handler_wrapper('Adquiriendo atributos de modelo del proceso de valoración', 'Atributos modelo adquiridos exitosamente', 'Error adquiriendo atributos del modelo de valoración', 'Error adquiriendo modelos') + def acquire_model_atributtes(self): + #TODO: Mirar en models_tables.py el directorio ordered_atributes_tables, es posible que estos modelos deban recogerse con un sql organizado por las columnas de fechas + for table in models_tables: + query = f"SELECT * FROM {table} WHERE ID_COMPANY = :id_company" + logger.info(f'[acquire_model_atributtes] Query para el modelo de la tabla {table}:\n{query}') + rds_data = self.db_connection.execute(text(query), {'id_company': self.id_company}) + self.assessment_models[table] = [row._asdict() for row in rds_data.fetchall()] + for row in self.assessment_models[table]: + del row['ID_COMPANY'] + logger.warning(f'[acquire_model_atributtes] Modelo hallado para la tabla {table}:\n{self.assessment_models[table]}') + + + @handler_wrapper('Eligiendo fechas historicas del nuevo proceso de valoración', 'Fechas historicas elegidas con exito', 'Error eligiendo fechas historicas del proceso de valoración', 'Error calculando fechas historicas del nuevo proceso de valoración') + def calculate_assessment_historic_dates(self): + #model_historic_dates = int(self.assessment_models['MODEL_ASSESSMENT_YEARS'][0]['HISTORIC_YEARS']) + query = "SELECT * FROM ARCHIVE WHERE ID_COMPANY = :id_company" #Posiblemente acá deba colocar la periodicidad + logger.info(f'[calculate_assessment_historic_dates] Query para obtener los datos de archives de la empresa:\n{query}') + rds_data = self.db_connection.execute(text(query), {'id_company': self.id_company}) + + company_pucs_data = {row.INITIAL_DATE.strftime('%Y-%m-%d'): row.ID for row in rds_data.fetchall()} + logger.warning(f'[calculate_assessment_historic_dates] data de pucs hallados para la empresa de nit {self.nit}:\n{company_pucs_data}') + + self.new_assessment_historic_archives = [company_pucs_data[date] for date in self.historic_dates_chosen] + self.historic_dates = sorted(self.historic_dates_chosen) + logger.info(f'[calculate_assessment_historic_dates] historicos encontrados para recurrencia:\n{self.historic_dates}') + + + @handler_wrapper('Organizando los datos construídos a dataframes', 'Dataframes creados con exito', 'Error creando dataframes de guardado', 'Error creando tablas de datos base') + def upload_historic_assessment_dates(self): + dates_records = [] + dates_records.extend([{'DATES': datetime.datetime.strptime(str(date), '%Y-%m-%d').strftime('%Y-%m-%d %H:%M:%S'), 'PROPERTY': 'HISTORIC'} for date in self.historic_dates]) + self.df_and_upload(dates_records, 'ASSESSMENT_DATES') + + + @handler_wrapper('Calculando fechas de proyección', 'fechas de proyeccion calculadas con exito', 'Error calculando fechas de proyeccion', 'No se pudo calcular fechas de proyección') + def calculate_assessment_projection_dates(self): + model_projection_years = int(self.assessment_models['MODEL_ASSESSMENT_YEARS'][0]['PROJECTION_YEARS']) + self.projection_dates = [] + assessment_year = int(self.current_short_date.split('-')[-1]) + + if int(self.current_short_date.split("-")[1]) != 12: + self.projection_dates.append(f'{assessment_year}-12-01') + self.new_assessment_has_annual = True + + if int(self.assessment_models['MODEL_ASSESSMENT_YEARS'][0]['ANNUAL_ATTRIBUTE']): + self.projection_dates.extend([f'{assessment_year + year}-01-01' for year in range(1, model_projection_years)]) + else: + self.projection_dates.extend([f'{assessment_year + year}-01-01' for year in range(1, model_projection_years + 1)]) + logger.info(f"[calculate_assessment_projection_dates] Las fechas proyectadas serían:\n{self.projection_dates}") + + + @handler_wrapper('Organizando los datos construídos a dataframes', 'Dataframes creados con exito', 'Error creando dataframes de guardado', 'Error creando tablas de datos base') + def upload_new_assessment_dates(self): + dates_records = [] + dates_records.extend([{'DATES': datetime.datetime.strptime(str(date), '%Y-%m-%d').strftime('%Y-%m-%d %H:%M:%S') , 'PROPERTY': 'PROJECTION'} for date in self.projection_dates]) + dates_records.extend([{'DATES': datetime.datetime.strptime(str(date), '%Y-%m-%d').strftime('%Y-%m-%d %H:%M:%S'), 'PROPERTY': 'HISTORIC'} for date in self.historic_dates]) #para ahorrar procesamiento se puede cambiar este str(date) por un combine entre fecha date y H-M-S en ceros + self.df_and_upload(dates_records, 'ASSESSMENT_DATES') + self.historic_dates = [datetime.datetime.strptime(str(date), '%Y-%m-%d') for date in self.historic_dates] + + + @handler_wrapper('Adquiriendo los datos originales de puc para los archives encontrados', 'Datos originales adquiridos y distribuidos con exito', 'Error adquiriendo y organizando los datos originales de puc', 'Error procesando los nuevos pucs') + def new_assessment_summary_builder(self): + new_assessment_archives_str = str(self.new_assessment_historic_archives).replace('[', '').replace(']', '') + query = f"SELECT ID_ARCHIVE, ACCOUNT_NUMBER, CHECKED_BALANCE, ACCOUNT_NAME FROM ORIGINAL_PUC WHERE ID_ARCHIVE IN ({new_assessment_archives_str})" + logger.info(f'[new_assessment_summary_builder] Query para traer los datos de los pucs originales para los archives encontrados:\n{query}') + rds_data = self.db_connection.execute(text(query)) #, {'new_assessment_archives_str': new_assessment_archives_str} + full_historic_asessment_data = [row._asdict() for row in rds_data.fetchall()] + if not full_historic_asessment_data: + self.detailed_raise = "Existe el archive de puc pero no se hallaron datos internos como cuentas, saldos y nombres" + raise Exception (ImportError) + + full_historic_asessment_data = self.balance_pucs_accounts(full_historic_asessment_data) + + for master_row in self.assessment_models['MODEL_USER_CLASSIFICATION']: + #Acá estoy filtrando los numeros de cuentas de todos los archives que empiecen como el master row + assessment_rows = [item for item in full_historic_asessment_data if item['ACCOUNT_NUMBER'].startswith(master_row['ACCOUNT_NUMBER'])] + for filtered_row in assessment_rows: + filtered_row['ID_RAW_CLASSIFICATION'] = master_row['ID_RAW_CLASSIFICATION'] #las cuentas filtradas son clasificadas como el master row + + for row in full_historic_asessment_data: + row['ACCOUNT_NAME'] = f"{row['ACCOUNT_NAME']} ({row['ACCOUNT_NUMBER']})" + row['CHECKED_BALANCE'] = float(row['CHECKED_BALANCE']) + row['ID_RAW_CLASSIFICATION'] = row.get('ID_RAW_CLASSIFICATION', self.classification_id_dict['No aplica']) + self.archive_pucs_data[row['ID_ARCHIVE']] = self.archive_pucs_data.get(row['ID_ARCHIVE'], []) #si el directorio self.archive_pucs_data no tiene el id_archive, lo crea como una lista vacía, si existe se auto clona los datos; es como si estuviera repartiendo los pucs dependiendo su ID_ARCHIVE + self.archive_pucs_data[row['ID_ARCHIVE']].append(row) + + + @handler_wrapper('Balanceando numeros de cuentas entre pucs historicos', 'Balanceado de pucs historics exitoso', 'Error balanceando cuentas de pucs historicos', 'Error construyendo cuentas para balanceado de pucs historicos') + def balance_pucs_accounts(self, full_historic_asessment_data): + archives_accounts_directory = {archive: list() for archive in self.new_assessment_historic_archives} + all_historic_account_numbers = set() + for row in full_historic_asessment_data: + all_historic_account_numbers.add(row['ACCOUNT_NUMBER']) + archives_accounts_directory[row['ID_ARCHIVE']].append(row['ACCOUNT_NUMBER']) + for archive, this_archive_accounts in archives_accounts_directory.items(): + this_archive_missing_accounts = [item for item in all_historic_account_numbers if item not in this_archive_accounts] + logger.warning(f'[balance_pucs_accounts] al archive {archive} le hacen falta las cuentas {this_archive_missing_accounts}') + for account_number in this_archive_missing_accounts: + full_historic_asessment_data.append({'ACCOUNT_NUMBER': account_number, 'ACCOUNT_NAME': 'Cuenta creada para balanceo de pucs historicos', 'CHECKED_BALANCE': 0, 'ID_RAW_CLASSIFICATION':self.classification_id_dict['No aplica'], 'ID_ARCHIVE': archive}) + return full_historic_asessment_data + + + @handler_wrapper('Procesando los pucs historicos de recurrencia', 'Pucs historicos de recurrencia procesados con exito', 'Error procesando pucs historicos de recurrencia', 'Error procesando pucs de recurrencia') + def master_process_recurrence_pucs(self): + self.second_grade_classifications = ['Amortización del periodo', 'Amortización acumulada', 'Depreciación del periodo', 'Depreciación acumulada', 'Intangibles', 'Propiedad, planta y equipo'] + for archive, data in self.archive_pucs_data.items(): + self.archive_purged_accounts = [] + self.archive_summaries = [] + self.process_puc_checked(archive, data) + self.process_puc_summary(archive, data) + self.process_summary_parents(archive) + + + @debugger_wrapper('Error calculando cuentas de puc', 'Error procesando pucs historicos') + def process_puc_checked(self, archive, data): + archive_accounts_classifications = {item['ACCOUNT_NUMBER']: item['ID_RAW_CLASSIFICATION'] for item in data} + erasing_accounts = [] + for account, raw_classification in archive_accounts_classifications.items(): + all_parents = [row for row in archive_accounts_classifications if (account.startswith(row) and account != row)] + if not all_parents: + continue + closest_parent_classification = archive_accounts_classifications[all_parents[-1]] + if raw_classification == closest_parent_classification: + if self.easy_classification_dict.get(raw_classification, 'No aplica') in self.second_grade_classifications: + if len(all_parents) == 1: + erasing_accounts.append(all_parents[-1]) + continue + grand_parents_classification = [archive_accounts_classifications[parent] for parent in all_parents][-2] + if grand_parents_classification == raw_classification: + erasing_accounts.append(account) + continue + else: + erasing_accounts.append(all_parents[-1]) + continue + erasing_accounts.append(account) + + for account in erasing_accounts: + archive_accounts_classifications.pop(account, None) + + to_db_accounts = [item for item in data if item['ACCOUNT_NUMBER'] in archive_accounts_classifications] + self.archive_purged_accounts = [self.purge_accounts(account_row, to_db_accounts) for account_row in to_db_accounts] + self.assessment_checked_records.extend(asdict(assessment_checked_object(archive, item['ID_RAW_CLASSIFICATION'], item['ACCOUNT_NUMBER'], item['CHECKED_BALANCE'], item['purged_balance'], item['ACCOUNT_NAME'], item['hint'])) for item in self.archive_purged_accounts if item['ID_RAW_CLASSIFICATION'] != 0) + + + @debugger_wrapper('Error purgando cuentas de puc', 'Error calculando disminuciones entre cuentas inferiores') + def purge_accounts(self, item, accounts_items): + different_sub_accounts = [row for row in accounts_items if (row['ACCOUNT_NUMBER'].startswith(item['ACCOUNT_NUMBER']) and row['ACCOUNT_NUMBER'] != item['ACCOUNT_NUMBER']) ] + sub_accounts_levels = sorted(len(row['ACCOUNT_NUMBER']) for row in different_sub_accounts ) + substracted_accounts = [] + sub_accounts_subtraction = 0 + item['hint'] = item['ACCOUNT_NUMBER'] + for level in sub_accounts_levels: + this_level_accounts = [row for row in different_sub_accounts if (len(row['ACCOUNT_NUMBER']) == level and not row['ACCOUNT_NUMBER'].startswith(tuple(substracted_accounts)))] + substracted_accounts.extend(row['ACCOUNT_NUMBER'] for row in this_level_accounts) + sub_accounts_level_values = sum(row['CHECKED_BALANCE'] for row in this_level_accounts) + sub_accounts_subtraction += sub_accounts_level_values + if sub_accounts_subtraction: + logger.info(f'[purge_accounts] La cuenta {item["ACCOUNT_NUMBER"]} tuvo como substracciones a {substracted_accounts}') + item['hint'] = f"{item['hint']} - ({'+'.join(substracted_accounts)})" + item['purged_balance'] = item['CHECKED_BALANCE'] - sub_accounts_subtraction + return item + + + @debugger_wrapper('Error calculando summaries de historicos', 'Error calculando summaries') + def process_puc_summary(self, archive, data): + raw_classifications_ids = set(item['ID_RAW_CLASSIFICATION'] for item in self.archive_purged_accounts if item['ID_RAW_CLASSIFICATION'] != 0) + for raw_id in raw_classifications_ids: + classification_items = [item for item in self.archive_purged_accounts if item['ID_RAW_CLASSIFICATION'] == raw_id] + classification_hint = ' + '.join([item['hint'] for item in classification_items]) + classification_value = sum(item['purged_balance'] for item in classification_items) + self.archive_summaries.append({'id': raw_id, 'value': classification_value}) + self.classification_summary_records.append(asdict(classification_summary_object(archive, raw_id, classification_value, classification_value, classification_hint))) + + @debugger_wrapper('Error agregando cuentas padres a summaries', 'Error calculando cuentas padres') + def process_summary_parents(self, archive): + raw_parents_classifications = {item['CLASSIFICATION']:item['ID'] for item in self.raw_classification if item['IS_PARENT']} + parents_calculated = {parent: 0 for parent in raw_parents_classifications} + parents_calculated_hints = {parent: '' for parent in raw_parents_classifications} + for summary in self.archive_summaries: + summary_classification = self.easy_classification_dict[summary['id']] + found_parent = next((key for key in raw_parents_classifications if summary_classification.startswith(key) and summary_classification != key), False) + if not found_parent: + continue + parents_calculated[found_parent] = parents_calculated[found_parent] + summary['value'] + parents_calculated_hints[found_parent] = parents_calculated_hints[found_parent] + summary_classification + + for parent_name, id in raw_parents_classifications.items(): + + self.classification_summary_records.append(asdict(classification_summary_object(archive, id, parents_calculated[parent_name], parents_calculated[parent_name], parents_calculated_hints[parent_name]))) + + +def get_current_error_line(): + return str(sys.exc_info()[-1].tb_lineno) \ No newline at end of file diff --git a/corporate_finances_back_py/super-orchestrator/_orchester_utils.py b/corporate_finances_back_py/super-orchestrator/_orchester_utils.py new file mode 100644 index 0000000..a9812ae --- /dev/null +++ b/corporate_finances_back_py/super-orchestrator/_orchester_utils.py @@ -0,0 +1,108 @@ +from sqlalchemy import text +from decorators import handler_wrapper, timing, debugger_wrapper, try_pass_wrapper +import logging +import pandas as pd +import datetime +import sys +import pprint +from models_tables import models_tables + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + + +class orchester_utils_class(object): + @debugger_wrapper('Error borrando datos de una de las tablas de bd', 'Error sobreescribiendo información') + def delete_from_bd(self, table, and_clause): + query = f"DELETE FROM {table} WHERE ID_ASSESSMENT = {self.id_assessment} {and_clause}" + logger.info(f'[delete_from_bd] Query para borrar posibles datos en {table}:\n{query}') + self.db_connection.execute(text(query)) #, {'id_assessment': self.id_assessment} + + @debugger_wrapper('Error cargando datos a bd', 'Error sobreescribiendo información a bd') + def df_and_upload(self, records, table_to, and_clause = ''): + try: + logger.info(f'[df_and_upload] Cargando datos a la tabla: {table_to}') + self.delete_from_bd(table_to, and_clause) + uploading_df = pd.DataFrame.from_records(records) + uploading_df['ID_ASSESSMENT'] = self.id_assessment + logger.debug(f'[df_and_upload] Datos que se cargarán a {table_to}:\n{uploading_df.to_string()}') + uploading_df.to_sql(name = table_to, con=self.db_connection, schema='src_corporate_finance', if_exists='append', index=False) + logger.info('[df_and_upload] Carga exitosa') + + except Exception as e: + logger.error(f'[df_and_upload] No se pudo cargar información a la tabla {table_to}, motivo:{str(e)}') + logger.warning(f'[df_and_upload] dataframe que no se pudo cargar a {table_to}:\n{uploading_df.to_string()}') + self.noting_list.append({'TASK': self.current_context, 'NOTE': f"No se pudo cargar información a la tabla de {table_to}"}) if self.current_context else None + + + + @try_pass_wrapper('Error escribiendo step de valoración, posiblemente ya exista') + def save_assessment_step(self, step): + if step not in self.steps_list: + query = 'INSERT ASSESSMENT_STEPS VALUES(:id_assessment, :step)' + logger.info(f'[save_assessment_step] Query para insertar paso completado del proceso de valoración:\n{query}') + self.db_connection.execute(text(query), {'id_assessment': self.id_assessment, 'step': step}) + + + @debugger_wrapper('Error cambiando estado del orquestador', 'Error modificando estado') + def orchestrator_state_update(self, new_status): + if self.db_connection: + query = f"""INSERT INTO ORCHESTRATOR_STATUS (ID_ASSESSMENT, STATE) VALUES ({self.id_assessment}, "{new_status}") +ON DUPLICATE KEY UPDATE STATE=VALUES(STATE), LAST_STATE_TS = CURRENT_TIMESTAMP""" + logger.info(f'[orchestrator_state_update] query para actualizar el estado del orquestador:\n{query}') + self.db_connection.execute(text(query)) #, {'id_assessment': self.id_assessment, 'new_status':new_status} + + + @debugger_wrapper('Error obteniendo valor para la cuenta', 'Error obteniendo valor original de una cuenta') + def get_historic_account_values(self, account_num): + found_values = [float(item['value']) for item in self.purged_items if item['account'] == account_num] + if found_values: + return found_values + return [0] * len(self.historic_dates) + + + @debugger_wrapper('Error obteniendo valor del summarie', 'Error obteniendo valor original del summarie') + def get_historic_summary_values(self, classification, startswith = False): + if startswith: + accumulator = {} + for item in self.summary_data: + if not item['CLASSIFICATION'].startswith(classification): + continue + if item['id_archive'] not in accumulator: + accumulator[item['id_archive']] = item['value'] + else: + accumulator[item['id_archive']] = accumulator[item['id_archive']] + item['value'] + found_values = [value for _, value in accumulator.items()] + + else: + found_values = [float(item['value']) for item in self.summary_data if item['CLASSIFICATION'] == classification] + if found_values: + return found_values + return [0] * len(self.historic_dates) + + + @debugger_wrapper('Error calculando sub total de tabla', 'Error calculando totales de proyecciones de pyg') + def calculate_total_vector(self, dependencies, vector_signs, search_in): + #logger.info(f'[calculate_total_vector] buscando {dependencies} en {search_in}') + dependencies_vectors = [search_in[dependence] for dependence in dependencies] + partial_vector = [] + for year_values in zip(*dependencies_vectors): + year_total = 0 + for index, value in enumerate(year_values): + year_total = year_total + value * vector_signs[index] + partial_vector.append(year_total) + return partial_vector + + +def get_current_error_line(): + return str(sys.exc_info()[-1].tb_lineno) + +def acute(object): + return f"""{pprint.pformat(object, indent = 4)}""" + +def is_ok(func, *args, **kw): + try: + func(*args, **kw) + return True + except Exception: + return False \ No newline at end of file diff --git a/corporate_finances_back_py/super-orchestrator/_projection_methods.py b/corporate_finances_back_py/super-orchestrator/_projection_methods.py new file mode 100644 index 0000000..3abe784 --- /dev/null +++ b/corporate_finances_back_py/super-orchestrator/_projection_methods.py @@ -0,0 +1,54 @@ +from decorators import handler_wrapper, timing, debugger_wrapper +import logging +import datetime +import sys + + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + + +class projection_calc_class(object): + @debugger_wrapper('Error proyectando zeros', 'Error proyectando zeros') + def pm_calculate_zero(self): + return [0] * self.projection_dates_len + + @debugger_wrapper('Error proyectando constante', 'Error proyectando constante') + def pm_calculate_constant(self, account_value): + return [account_value] * self.projection_dates_len + + + @debugger_wrapper('Error proyectando fijo', 'Error proyectando cuenta a tasa fija') + def pm_calculate_fixed(self, account_value, fixed_percentages): + projections = [account_value * (1 + fixed_percentages[0]/100)] + for i in range(1, self.projection_dates_len): + projections.append(projections[i - 1] * (1 + fixed_percentages[i]/100)) + return projections + + + @debugger_wrapper('Error generando proyecciones de proporcion', 'Error proyectando en proporción') + def pm_calculate_proportion(self, account_value, vs_vector): + projections = [account_value] + #vs_vector.insert(0, 0) + + for i in range(1, self.projection_dates_len + 1): + try: + logger.info(f'[esta intentando] A: {projections[i - 1]} B: {vs_vector[i - 1]} C: {vs_vector[i]}') + projections.append(projections[i - 1] / vs_vector[i - 1] * vs_vector[i]) + except Exception as e: + logger.error(f'[mira aca] marcó el sgte error: {str(e)}') + projections.append(0) + + projections.pop(0) + #vs_vector.pop(0) #Estos pop son necesarios porque el vector de entrada fue modificado y a la función entraron referenciados, no copiados + return projections + + + @debugger_wrapper('Error generando proyecciones impositvas', 'Error calculando proyecciones impositvas') + def pm_calculate_impositive(self, atributes, vs_vector): + projections = [] + for i in range(self.projection_dates_len): + projections.append(vs_vector[i] * float(atributes[i])/100) + return projections + + diff --git a/corporate_finances_back_py/super-orchestrator/_recalculating_methods.py b/corporate_finances_back_py/super-orchestrator/_recalculating_methods.py new file mode 100644 index 0000000..d1d4692 --- /dev/null +++ b/corporate_finances_back_py/super-orchestrator/_recalculating_methods.py @@ -0,0 +1,203 @@ +import logging +import sys +import datetime + +from dataclasses_box import capex_values_object, projected_debt_object, fixed_assets_projected_item, modal_windows_projected_object, pyg_item_object, pyg_projected_object, asdict + +from _calc_capex_summary import capex_summary_class +from _calc_cash_flow import cash_flow_class +from _calc_debt import debt_class +from _calc_fixed_assets import fixed_assets_class +from _calc_new_capex import new_capex_class +from _calc_other_projections import other_projections_class +from _calc_patrimony import patrimony_class +from _calc_pyg import pyg_class +from _calc_pyg_projections import pyg_projections_class +from _calc_working_capital import working_capital_class +from _calc_assessment import assessment_class + +from decorators import handler_wrapper +from sqlalchemy import text +from models_tables import ordered_atributes_tables + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + + +class recalculating_methods_class(fixed_assets_class,patrimony_class,working_capital_class,other_projections_class,debt_class,new_capex_class,pyg_class,pyg_projections_class,capex_summary_class,cash_flow_class, assessment_class): + def recalculating_starter(self): + self.get_purged_items() + self.get_summary_results() + self.get_assessment_steps() + self.annualize_checking() + self.delete_from_bd("NOTES", '') #TODO: ver qué pasa con esto y con lo de modelo transaccional + + for context, fun in self.context_methods.items(): + try: + self.current_context = context + fun() + except Exception as e: + self.orchestrator_state_update(f"Error: {context}") + logger.error(f"[recalculating_starter] Falló la ejecución del contexto {context}") + self.noting_list.append({"TASK": self.current_context,"NOTE": f"Falló la ejecución de {context}, motivo: {str(e)}"}) + continue + + @handler_wrapper("Obteniendo datos de puc purgados", "Datos de puc obtenidos", "Error obteniendo datos de puc", "Error al buscar datos de puc purgados") + def get_purged_items(self): + query = f"""SELECT A.ACCOUNT_NUMBER AS account, B.CLASSIFICATION AS classification, A.ANNUALIZED AS value, A.ACCOUNT_NAME AS NAME, A.HINT + FROM ASSESSMENT_CHECKED A, RAW_CLASSIFICATION B, ARCHIVE C + WHERE A.ID_RAW_CLASSIFICATION = B.ID AND A.ID_ARCHIVE = C.ID AND ID_ASSESSMENT = {self.id_assessment} ORDER BY C.INITIAL_DATE""" + + logger.info(f"[get_purged_items] Query a base de datos para obtener los datos de puc calculados:\n {query}") + rds_data = self.db_connection.execute(text(query)) + self.purged_items = [item._asdict() for item in rds_data.fetchall()] + logger.info(f"[get_purged_items] Datos de cuentas traídas desde bd:\n{self.purged_items}") + for item in self.purged_items: + item["value"] = float(item["value"]) + + logger.warning(f"[get_purged_items] datos de cuentas post procesamiento inicial:\n{self.purged_items}") + + @handler_wrapper("Obteniendo datos summary de clasificacion","summaries de clasificacion obtenidos","Error obteniendo summaries","Error al buscar informacion de sumaries") + def get_summary_results(self): + # trunk-ignore(bandit/B608) + query = f"""SELECT C.ID AS id_archive, B.CLASSIFICATION, A.HINT AS hint, A.ANNUALIZED AS value, B.IS_PARENT +FROM CLASSIFICATION_SUMMARY A, RAW_CLASSIFICATION B, ARCHIVE C +WHERE A.ID_RAW_CLASSIFICATION = B.ID AND A.ID_ARCHIVE = C.ID +AND ID_ASSESSMENT = {self.id_assessment} ORDER BY C.INITIAL_DATE""" + + logger.info(f"[get_archive_info] Query a base de datos para obtener los summaries de clasificacion calculados:\n {query}") + rds_data = self.db_connection.execute(text(query)) + + self.summary_data = [dict(item) for item in rds_data.mappings().all()] + for item in self.summary_data: + item["value"] = float(item["value"]) + self.all_assessment_classifications = tuple(item["CLASSIFICATION"] for item in self.summary_data) + logger.warning(f"[get_summary_results] Summaries encontrados para el proceso de valoración:\n{self.summary_data}") + + @handler_wrapper('Obteniendo los steps del proceso de valoración', 'Steps del proceso de valoración obtenidos', 'Error obteniendo steps del proceso de valoración', 'Error obteniendo steps del proceso de valoración') + def get_assessment_steps(self): + query = f"""SELECT SERVICE FROM ASSESSMENT_STEPS WHERE ID_ASSESSMENT = {self.id_assessment}""" + logger.info(f"[get_assessment_steps] Query a base de datos para obtener los steps existentes del proceso de valoración:\n {query}") + rds_data = self.db_connection.execute(text(query)) + self.steps_list = [row.SERVICE for row in rds_data.fetchall()] + + + + @handler_wrapper("Revisando si se requiere modificaciones de atributos por anualización","Chequeo de anualización terminado", "Error realizando chequeo de anualización","Error realizando anualización") + def annualize_checking(self): + if self.context == "full_recurrency": + if self.assessment_models["MODEL_ASSESSMENT_YEARS"][0]["ANNUAL_ATTRIBUTE"]== 1 and not self.new_assessment_has_annual: + #TODO: aca toca poner una función para eliminar un año de proyeccion + logger.warning("[annualize_checking] Se encontró que el modelo es anualizado y el nuevo proceso de valoración no requiere anualización") + logger.debug(f'[annualize_checking] modelos previos a borrado de atributo de anualización:\n{self.assessment_models}') + self.delete_all_annual_attributes() + logger.debug(f'[annualize_checking] modelos sin atributos de anualización:\n{self.assessment_models}') + elif self.assessment_models["MODEL_ASSESSMENT_YEARS"][0]["ANNUAL_ATTRIBUTE"]== 0 and self.new_assessment_has_annual: + #TODO: aca toca poner una función que agregué una proyeccion, el de anualización + self.add_annual_attributes() + + + @handler_wrapper("Eliminando atributo de anualización de todos los modelos","Atributo de anualización eliminado con éxito","Error eliminando atributo de anualización","Error procesando modelo anualizacido y proceso de valoración que no requiere anualizacion") + def delete_all_annual_attributes(self): + #MODEL_FIXED_ASSETS + for row in self.assessment_models['MODEL_FIXED_ASSETS']: + row['PROJECTED_YEARS'] = row['PROJECTED_YEARS'] - 1 + + #MODEL_CAPEX_VALUES + self.assessment_models['MODEL_CAPEX_VALUES'] = self.assessment_models['MODEL_CAPEX_VALUES'][1:] + + #MODEL_FCLO_DISCOUNT #no debo borrar esta propiedad porque la cantidad de atributos va estar ok + #self.assessment_models['MODEL_FCLO_DISCOUNT'] = self.assessment_models['MODEL_FCLO_DISCOUNT'][1:] + + #MODEL_PROJECTED_DEBT + cleaned_items = tuple() + for row in self.assessment_models['MODEL_PROJECTED_DEBT']: + if (row['ACCOUNT_NUMBER'], row['ALIAS_NAME']) not in cleaned_items: + cleaned_items = cleaned_items + ((row['ACCOUNT_NUMBER'], row['ALIAS_NAME']),) + row['DELETE_ROW'] = True + #logger.debug(f"[delete_all_annual_attributes] estoy pidiendo quemar el row: {row} porque {(row['ACCOUNT_NUMBER'], row['ALIAS_NAME'])} no está en {cleaned_items}") + else: + row['DELETE_ROW'] = False + self.assessment_models['MODEL_PROJECTED_DEBT'] = [row for row in self.assessment_models['MODEL_PROJECTED_DEBT'] if not row['DELETE_ROW']] + + #MODEL_PROJECTED_FIXED_ASSETS + cleaned_items = tuple() + for row in self.assessment_models['MODEL_PROJECTED_FIXED_ASSETS']: + if (row['ID_ITEMS_GROUP']) not in cleaned_items: + cleaned_items = cleaned_items + (row['ID_ITEMS_GROUP'], ) + row['DELETE_ROW'] = True + else: + row['DELETE_ROW'] = False + self.assessment_models['MODEL_PROJECTED_FIXED_ASSETS'] = [row for row in self.assessment_models['MODEL_PROJECTED_FIXED_ASSETS'] if not row['DELETE_ROW']] + + #MODEL_MODAL_WINDOWS_PROJECTED + cleaned_items = tuple() + for row in self.assessment_models['MODEL_MODAL_WINDOWS_PROJECTED']: + if (row['CONTEXT_WINDOW'], row['ACCOUNT_NUMBER']) not in cleaned_items: + cleaned_items = cleaned_items + ((row['CONTEXT_WINDOW'], row['ACCOUNT_NUMBER']),) + row['DELETE_ROW'] = True + else: + row['DELETE_ROW'] = False + self.assessment_models['MODEL_MODAL_WINDOWS_PROJECTED'] = [row for row in self.assessment_models['MODEL_MODAL_WINDOWS_PROJECTED'] if not row['DELETE_ROW']] + + #MODEL_PROJECTED_PYG + cleaned_items = tuple() + for row in self.assessment_models['MODEL_PROJECTED_PYG']: + if (row['ID_RAW_PYG']) not in cleaned_items: + cleaned_items = cleaned_items + (row['ID_RAW_PYG'], ) + row['DELETE_ROW'] = True + else: + row['DELETE_ROW'] = False + self.assessment_models['MODEL_PROJECTED_PYG'] = [row for row in self.assessment_models['MODEL_PROJECTED_PYG'] if not row['DELETE_ROW']] + + + @handler_wrapper("Agregando atributo de anualización a todos los modelos", "Atributo de anualización agregado con éxito", "Error agregando atributo de anualización", "Error procesando modelo no anualizado y proceso de valoración que requiere anualizacion") + def add_annual_attributes(self): + annualized_date_short = self.projection_dates[0] + annualized_date_long = datetime.datetime.strptime(annualized_date_short, '%Y-%m-%d').strftime('%Y-%m-%d %H:%M:%S') + #MODEL_FIXED_ASSETS + for row in self.assessment_models['MODEL_FIXED_ASSETS']: + row['PROJECTED_YEARS'] = row['PROJECTED_YEARS'] + 1 + + #MODEL_CAPEX_VALUES + self.assessment_models['MODEL_CAPEX_VALUES'] =[asdict(capex_values_object(annualized_date_long, '0', 0, 0))] + self.assessment_models['MODEL_CAPEX_VALUES'][1:] + + #MODEL_FCLO_DISCOUNT + self.assessment_models['MODEL_FCLO_DISCOUNT'] = [{'ITEM_DATE':annualized_date_long, 'DISCOUNT_PERIOD':0, 'DISCOUNT_RATE':0, 'DISCOUNT_FACTOR':0}] + self.assessment_models['MODEL_FCLO_DISCOUNT'] + + #MODEL_PROJECTED_DEBT + debts_ids = set([(row['ACCOUNT_NUMBER'], row['ALIAS_NAME']) for row in self.assessment_models['MODEL_PROJECTED_DEBT']]) + adding_rows = [] + for pair in debts_ids: + logger.debug(f'[mira aca] Esto no debería tener diccionarios repetidos:\n{debts_ids}') + adding_rows.append(asdict(projected_debt_object(pair[0], pair[1], annualized_date_long, 0, 0, 0, 0, 0, 0, '0', '0'))) + + self.assessment_models['MODEL_PROJECTED_DEBT'] = adding_rows + self.assessment_models['MODEL_PROJECTED_DEBT'] + + #MODEL_PROJECTED_FIXED_ASSETS + groups_ids = set([row['ID_ITEMS_GROUP'] for row in self.assessment_models['MODEL_PROJECTED_FIXED_ASSETS']]) + adding_rows = [] + for group_id in groups_ids: + adding_rows.append(asdict(fixed_assets_projected_item(group_id, annualized_date_long, 0, 0, 0, 0))) + + self.assessment_models['MODEL_PROJECTED_FIXED_ASSETS'] = adding_rows + self.assessment_models['MODEL_PROJECTED_FIXED_ASSETS'] + + #MODEL_MODAL_WINDOWS_PROJECTED + modal_pairs = set([(row['ACCOUNT_NUMBER'], row['CONTEXT_WINDOW']) for row in self.assessment_models['MODEL_MODAL_WINDOWS_PROJECTED']]) + adding_rows = [] + for pair in modal_pairs: + logger.debug(f'[mira aca] Esto no debería tener diccionarios repetidos:\n{modal_pairs}') + adding_rows.append(asdict(modal_windows_projected_object(0, pair[0], annualized_date_long, '0', pair[1]))) + + self.assessment_models['MODEL_MODAL_WINDOWS_PROJECTED'] = adding_rows + self.assessment_models['MODEL_MODAL_WINDOWS_PROJECTED'] + + #MODEL_PROJECTED_PYG + raw_pyg_ids = set([row['ID_RAW_PYG'] for row in self.assessment_models['MODEL_PROJECTED_PYG']]) + adding_rows = [] + for raw_id in raw_pyg_ids: + adding_rows.append(asdict(pyg_projected_object(raw_id, annualized_date_long, 0, '0'))) + self.assessment_models['MODEL_PROJECTED_PYG'] = adding_rows + self.assessment_models['MODEL_PROJECTED_PYG'] + + +def get_current_error_line(): + return str(sys.exc_info()[-1].tb_lineno) diff --git a/corporate_finances_back_py/super-orchestrator/cash_flow_vars.py b/corporate_finances_back_py/super-orchestrator/cash_flow_vars.py new file mode 100644 index 0000000..f0413e0 --- /dev/null +++ b/corporate_finances_back_py/super-orchestrator/cash_flow_vars.py @@ -0,0 +1,57 @@ + +cash_flow_all_items = ['Utilidad neta', + 'Impuestos de renta', + 'Intereses/gasto financiero', + 'EBIT', + 'Impuestos operacionales', + 'UODI (NOPAT)', + 'Depreciación del Periodo', + 'Deterioro', + 'Amortización del Periodo', + 'Depreciación Capex', + 'Otros movimientos que no son salida ni entrada de efectivo operativos', + 'Flujo de caja bruto', + 'Capital de trabajo', + 'CAPEX', + 'Otros movimientos netos de activos operativos que afecta el FCLO', + 'Otros ingresos y egresos operativos', + 'Flujo de caja Libre Operacional', + 'Intereses/gasto financiero FC', + 'Impuestos no operacionales', + 'Variación de deuda', + 'Deuda de tesorería del periodo', + 'Deuda de tesorería acumulada', + 'Otros movimientos netos de activos operativos que afecta el FCLA', + 'Otros ingresos y egresos no operativos', + 'Flujo de caja del accionista', + 'Aportes de capital social u otros', + 'Dividentos en efectivo', + 'Flujo de caja del periodo', + 'Saldo de caja inicial', + 'Saldo de caja final', + 'Check'] + + +pyg_names = ['Utilidad antes de impuestos', + 'Impuestos de renta', + 'Intereses/gasto financiero', + 'Deterioro', + 'Otros ingresos y egresos operativos', + 'Otros ingresos y egresos no operativos', + 'Utilidad neta', + 'EBIT'] + + +capex_items = ['Depreciación del Periodo', 'Amortización del Periodo'] + + +cash_flow_totals = {'Flujo de caja bruto':{'dependencies': ['UODI (NOPAT)','Depreciación del Periodo','Deterioro','Amortización del Periodo', 'Depreciación Capex','Otros movimientos que no son salida ni entrada de efectivo operativos'], + 'is_sum': [1,1,1,1,1,-1]}, + 'Flujo de caja Libre Operacional':{'dependencies':['Flujo de caja bruto', 'Capital de trabajo', 'CAPEX', 'Otros movimientos netos de activos operativos que afecta el FCLO', 'Otros ingresos y egresos operativos'], + 'is_sum':[1,-1,-1,-1,1]}, #revisar si FCLO suma o resta + 'Flujo de caja del accionista':{'dependencies':['Flujo de caja Libre Operacional', 'Intereses/gasto financiero FC', 'Impuestos no operacionales', 'Variación de deuda', 'Deuda de tesorería del periodo', 'Otros movimientos netos de activos operativos que afecta el FCLA', 'Otros ingresos y egresos no operativos'], + 'is_sum':[1,-1,-1,1,1,-1,1]}, + 'Flujo de caja del periodo':{'dependencies':['Flujo de caja del accionista','Aportes de capital social u otros', 'Dividentos en efectivo'], + 'is_sum':[1,1,-1]} + } + \ No newline at end of file diff --git a/corporate_finances_back_py/super-orchestrator/dataclasses_box.py b/corporate_finances_back_py/super-orchestrator/dataclasses_box.py new file mode 100644 index 0000000..94267ad --- /dev/null +++ b/corporate_finances_back_py/super-orchestrator/dataclasses_box.py @@ -0,0 +1,203 @@ + +from dataclasses import dataclass, asdict#, field #field es para cuando se debe crear algo en __post_init__ + + +@dataclass +class assessment_checked_object: + ID_ARCHIVE : int + ID_RAW_CLASSIFICATION : int + ACCOUNT_NUMBER : str + CALCULATED_BALANCE : float + ANNUALIZED : float + ACCOUNT_NAME : str + HINT : str + NATURE : str = '' + +@dataclass +class classification_summary_object: + ID_ARCHIVE : int + ID_RAW_CLASSIFICATION : int + CALCULATED_BALANCE : float + ANNUALIZED : float + HINT : str + +@dataclass +class capex_values_object: + CAPEX_NAME : str + CALCULATED_DATE : str + MANUAL_PERCENTAGE : str + CAPEX_SUMMARY : float + CAPEX_ACUMULATED : float + +@dataclass +class capex_object: + USED_ACCOUNT_NAME : str + METHOD : str + TIME_PERIOD : str + PERIODS : int + CALCULATION_COMMENT : str + +@dataclass +class fclo_object: + ITEM_DATE : str + OPERATIVE_CASH_FLOW : float + DISCOUNT_PERIOD : str + DISCOUNT_RATE : str + DISCOUNT_FACTOR : str + FCLO : float + +@dataclass +class projected_debt_object: + ACCOUNT_NUMBER : str + ALIAS_NAME : str + ITEM_DATE : int + INITIAL_BALANCE : float + DISBURSEMENT : float + AMORTIZATION : float + ENDING_BALANCE : float + INTEREST_VALUE : float + ENDING_BALANCE_VARIATION: float + RATE_ATRIBUTE : float + SPREAD_ATRIBUTE : float + + def coupled_exit (self): + #TODO: este proy_year puede que necesite solo el año, le estoy mandando el item_date completo + return {'proy_year': self.ITEM_DATE,'interest': self.INTEREST_VALUE, 'variation': self.ENDING_BALANCE_VARIATION} #acá debo traer el que hace falta en flujo de caja + + +@dataclass +class debt_object: + ORIGINAL_VALUE : float + ACCOUNT_NUMBER : str + ALIAS_NAME : str + PROJECTION_TYPE : str + START_YEAR : str + ENDING_YEAR : str + DEBT_COMMENT : float + RATE_COMMENT : float + SPREAD_COMMENT : float + +@dataclass +class coupled_debt_object: + SUMMARY_DATE : str + DISBURSEMENT : float + INTEREST_VALUE : float + +@dataclass +class fixed_assets_object: + ID_ITEMS_GROUP : int + PROJECTION_TYPE : int + ASSET_ACCOUNT : str + ACUMULATED_ACCOUNT : str + PERIOD_ACCOUNT : str + ASSET_ORIGINAL_VALUE : float + ACUMULATED_ORIGINAL_VALUE : float + PERIOD_ORIGINAL_VALUE : float + PROJECTED_YEARS : int + CALCULATION_COMMENT : str + + def capex_summary_output(self): + return {self.ID_ITEMS_GROUP: {'asset_account': self.ASSET_ACCOUNT, 'acumulated_account':self.ACUMULATED_ACCOUNT, 'period_account': self.PERIOD_ACCOUNT}} + + +@dataclass +class fixed_assets_projected_item: + ID_ITEMS_GROUP : int + PROJECTED_DATE : str + ASSET_VALUE : float + ACUMULATED_VALUE : float + EXISTING_ASSET_VALUE: float + PERIOD_VALUE : float + + def capex_output(self): + return {self.PROJECTED_DATE.split('-')[0]: + {'asset': self.ASSET_VALUE, 'acumulated': self.ACUMULATED_VALUE, 'existing': self.EXISTING_ASSET_VALUE, 'period': self.PERIOD_VALUE}} + + def capex_summary_output(self): + return {'date': self.PROJECTED_DATE, 'acumulated': self.ACUMULATED_VALUE, 'period': self.PERIOD_VALUE, 'id_items_group': self.ID_ITEMS_GROUP, 'asset_value': self.ASSET_VALUE} + + +@dataclass +class wk_results_object: + SUMMARY_DATE : str + WK_VARIATION : float + INTEREST_VALUE : float = 0 + +@dataclass +class patrimony_results_object: + SUMMARY_DATE : str + SOCIAL_CONTRIBUTIONS : float + CASH_DIVIDENDS : float + +@dataclass +class other_modal_results_object: + SUMMARY_DATE : str + OTHER_OPERATIVE_MOVEMENTS : float + FCLO : float + FCLA : float + +@dataclass +class modal_windows_projected_object: + VALUE : float + ACCOUNT_NUMBER : str + PROJECTED_DATE : str + ATRIBUTE : str + CONTEXT_WINDOW : str + +@dataclass +class pyg_item_object: + ID_RAW_PYG : int + ID_DEPENDENCE : int + ORIGINAL_VALUE : float + PROJECTION_TYPE : str + COMMENT : str + +@dataclass +class pyg_projected_object: + ID_RAW_PYG : int + PROJECTED_DATE : str + VALUE : float + ATRIBUTE : str + +@dataclass +class capex_summary_object: + SUMMARY_DATE: str + OPERATIONAL_INCOME: str + EXISTING_ASSETS: float + CAPEX: float + NEW_CAPEX: float + PERIOD_DEPRECIATION: float + PERIOD_AMORTIZATION: float + ACUMULATED_DEPRECIATION: float + ACUMULATED_AMORTIZATION: float + ACUMULATIVE_CHECK: int = 1 + +@dataclass +class calculated_assessment_object: + ASSESSMENT_DATE : str + INITIAL_DATE : str + CURRENT_CLOSING_DATE : str + FLOW_HALF_PERIOD : str + NEXT_FLOW_HALF_YEAR : str + DATES_ADJUST_ATRIBUTE : str + DATES_ADJUST_COMMENT : str + CHOSEN_FLOW_NAME : str + CHOSEN_FLOW_COMMENT : str + DISCOUNT_RATE_COMMENT : str + VP_FLOWS : float + GRADIENT : str + NORMALIZED_CASH_FLOW : float + DISCOUNT_RATE_ATRIBUTE : str + TERMINAL_VALUE : float + DISCOUNT_FACTOR : str + VP_TERMINAL_VALUE : float + ENTERPRISE_VALUE : float + FINANCIAL_ADJUST : float + TOTAL_NOT_OPERATIONAL_ASSETS : float + TOTAL_OPERATIONAL_PASIVES : float + ASSETS_COMMENT : str + PASIVES_COMMENT : str + PATRIMONY_VALUE : float + OUTSTANDING_SHARES : int + ASSESSMENT_VALUE : float + ADJUST_METHOD : str \ No newline at end of file diff --git a/corporate_finances_back_py/super-orchestrator/decorators.py b/corporate_finances_back_py/super-orchestrator/decorators.py new file mode 100644 index 0000000..db17c59 --- /dev/null +++ b/corporate_finances_back_py/super-orchestrator/decorators.py @@ -0,0 +1,84 @@ +#version 2024 - 02 - 20 +import logging +import sys +import traceback +from functools import wraps +from time import time + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + +def handler_wrapper(start, satisfactory_log, error_log, raise_error): + #esto se ejecuta en la inicializacion de primero + def decorator(func): + #print(message1) + #lo que yo ponga acá se ejecuta antes de hacer el llamado a la funcion + @wraps(func) + def wrapper(*args, **kwargs): + #esto sí se ejecuta solo cuando llama a la funcion decorada + #print(message2) + try: + logger.info(f'[{func.__name__}] {start}...') + resultado = func(*args, **kwargs) + logger.info(f'[{func.__name__}] {satisfactory_log}') + return resultado + except Exception as e: + logger.error(f"[{func.__name__}] {error_log}, linea: {get_especific_error_line(func.__name__)}, motivo: {str(e)}") + raise Exception(f"{raise_error}") + + return wrapper + return decorator + +def debugger_wrapper(error_log, raise_error): + def decorator(func): + @wraps(func) + def wrapper(*args, **kwargs): + try: + resultado = func(*args, **kwargs) + return resultado + except Exception as e: + logger.error(f"[{func.__name__}] {error_log}, linea: {get_especific_error_line(func.__name__)}, motivo: {str(e)}") + raise Exception(f"{raise_error}") + return wrapper + return decorator + +def try_pass_wrapper(error_log): + def decorator(func): + @wraps(func) + def wrapper(*args, **kwargs): + try: + resultado = func(*args, **kwargs) + return resultado + except Exception as e: + logger.debug(f"[{func.__name__}] {error_log}, linea: {get_especific_error_line(func.__name__)}, motivo: {str(e)}") + return wrapper + return decorator + +def runs_ok(func): + def wrapper_func(*args, **kwargs): + try: + func(*args, **kwargs) + return True + except Exception: + return False + return wrapper_func + + +def get_especific_error_line(func_name): + _, _, exc_tb = sys.exc_info() + for trace in traceback.extract_tb(exc_tb): + if func_name in trace: + return str(trace[1]) + +def timing(f): + @wraps(f) + def wrap(*args, **kw): + ts = time() + result = f(*args, **kw) + te = time() + taken_time_message = '[timing] La funcion {}, toma: {:.2f} sec en ejecutarse'.format(f.__name__, te-ts) + logger.info(taken_time_message) + return result + return wrap + + diff --git a/corporate_finances_back_py/super-orchestrator/lambda_function.py b/corporate_finances_back_py/super-orchestrator/lambda_function.py new file mode 100644 index 0000000..de553ff --- /dev/null +++ b/corporate_finances_back_py/super-orchestrator/lambda_function.py @@ -0,0 +1,239 @@ +from sqlalchemy import text +import datetime +import json +import logging +import os +import sys +import sqlalchemy +import traceback +import pandas as pd + +from decorators import handler_wrapper, timing, debugger_wrapper +from utils import get_secret, connect_to_db, connect_to_db_local_dev +from _full_recurrence import recurrence_class +from _full_dynamic import dynamic_class +from _recalculating_methods import recalculating_methods_class +from _orchester_utils import orchester_utils_class + +logging.basicConfig() +logging.basicConfig(format='%(asctime)s [%(levelname)s] [%(module)s] %(message)s', force=True, datefmt='%Y-%m-%d %H:%M:%S') +logger = logging.getLogger() +logger.setLevel(logging.DEBUG) + + +def lambda_handler(event, context): + sc_obj = script_object(event) + lambda_response = sc_obj.starter() + logger.info(f'respuesta final de lambda: \n{lambda_response}') + return lambda_response + + +class script_object(recurrence_class, recalculating_methods_class, orchester_utils_class, dynamic_class): + + @handler_wrapper('Obteniendo valores clave de event', 'Valores de event obtenidos correctamente', + 'Error al obtener valores event', 'Fallo en la obtencion de valores clave de event') + def __init__(self, event) -> None: + try: + self.failed_init = False + self.final_response = {'headers':{'Access-Control-Allow-Headers': '*', + 'Access-Control-Allow-Origin': '*', + 'Access-Control-Allow-Methods': '*'}, "statusCode": 500, 'body': {}} + self.db_connection = 0 + self.detailed_raise = '' + self.partial_response = {} + self.id_assessment = 0 + + logger.warning(f'event de entrada: {str(event)}') + event_dict = event.get('body', False) + + if event_dict: + event_dict = json.loads(event_dict) + self.calculate_recurrence = event_dict['recurrence'] #Esta llave la manda el front para ver si crea el id_assessment y ejecuta (o no) recurrencia + self.nit = event_dict['nit'] + self.current_short_date = event_dict['date'] + self.current_date_dt = datetime.datetime.strptime(self.current_short_date, "%d-%m-%Y") + self.current_long_date = self.current_date_dt.strftime('%Y-%m-%d %H:%M:%S') #este tenerlo en cuenta, creo que de todas formas no se está usando porque ya se usa self.assessment_initial_date + self.historic_dates_chosen = [event_dict['date']] + event_dict['selected_dates'] + self.historic_dates_chosen = ['-'.join(date.split('-')[::-1]) for date in self.historic_dates_chosen] #acá estoy girando las fechas de entrada para que sean %Y-%m-d + self.current_periodicity = event_dict['periodicity'] + self.user = event_dict['user'] + self.context = 'full_recurrency' + + + else: + self.id_assessment = event['id_assessment'] + self.context = 'dynamic_calc' + + self.context_methods = { + 'Depreciación de activos existentes' : self.fixed_assets_recalc, + 'Deuda financiera' : self.debt_recalc, + 'Pyg A' : self.pyg_first_half_recalc, + 'Proyecciones pyg A' : self.pyg_first_half_projections_recalc, + 'D&A Capex' : self.new_capex_recalc, + 'Summary capex' : self.capex_summary_recalc, + 'Pyg B' : self.pyg_second_half_recalc, + 'Proyecciones pyg B' : self.pyg_final_projections_recalc, + 'Pyg' : self.final_pyg, + 'Patrimonio' : self.patrimony_recalc, + 'Capital de trabajo' : self.working_capital_recalc, + 'Otras proyecciones' : self.other_projections_recalc, + 'Flujo de caja' : self.cash_flow_recalc, + 'Valoración' : self.assessment_recalc + } + + self.current_context = 0 + + self.historic_dates = list() + self.historic_dates_len = int() + self.historic_dates_long = list() + + self.projection_dates = list() + self.projection_dates_len = int() + self.projection_dates_long = list() + self.new_assessment_date = str() + self.all_dates_long = list() + self.all_dates_len = int() + + self.raw_classification = list() + self.raw_pyg = list() + self.raw_cash_flow = list() + + self.fixed_assets_data_to_new_capex = list() + self.fixed_assets_data_to_capex_summary =dict() + self.fixed_assets_proy_to_capex_summary = list() + self.raw_cash_flow = list() + self.assessment_projections_found = False + + self.noting_list = list() + self.steps_list = list() + self.capex_summary_vectors = dict() + self.coupled_debt_records = list() + self.pyg_results_records = list() + self.patrimony_results_records = list() + + self.capex_summary_records = list() + self.wk_results_records = list() + self.op_results_records = list() + self.dep_capex = list() + self.assessment_models = dict() + self.new_assessment_historic_archives = list() + self.pyg_values_vectors = dict() + self.pyg_hints_vectors = dict() + self.current_pyg_totals = dict() + self.new_capex_vector = list() + self.operation_income_vector = list() + self.new_assessment_has_annual = False + + except Exception as e: + logger.error(f'[__init__] Error inicializando objeto lambda, linea: {get_current_error_line()}, motivo: {str(e)}') + self.failed_init = True + + + def starter(self): + try: + if self.failed_init: + raise AttributeError('Error con los datos recibidos al servicio') + + logger.info('[starter] Empezando starter de objeto lambda') + self.create_conection_to_db() + self.get_raw_classification() + self.get_raw_pyg() + self.get_raw_cash_flow() + if self.context == 'full_recurrency': + self.full_recurrence_starter() + if not self.calculate_recurrence: + return self.response_maker(succesfull_run = True) + + if self.context == 'dynamic_calc': + self.full_dynamic_starter() + + self.organize_all_dates_info() + self.orchestrator_state_update('WORKING') + self.recalculating_starter() + #self.db_connection.commit() + return self.response_maker(succesfull_run = True) + except Exception as e: + logger.error(f'[starter] Hubieron problemas en el comando de la linea: {get_current_error_line()}') + return self.response_maker(succesfull_run = False, error_str = (str(e))) + + + @handler_wrapper('Creando conexion a bd','Conexion a bd creada con exito','Error en la conexion a bd','Problemas creando la conexion a bd') + def create_conection_to_db(self): + if __name__ != 'lambda_function': + self.db_connection = connect_to_db_local_dev() + self.db_connection.begin() + return + + db_schema = os.environ['DB_SCHEMA'] + secret_db_region = os.environ['SECRET_DB_REGION'] + secret_db_name = os.environ['SECRET_DB_NAME'] + db_secret = get_secret(secret_db_region, secret_db_name) + self.db_connection = connect_to_db(db_schema, db_secret) + + + def get_raw_classification(self): + query = """SELECT * FROM RAW_CLASSIFICATION""" + logger.info(f"[get_raw_classification] Query a base de datos para obtener el raw de clasificaciones:\n {query}") + rds_data = self.db_connection.execute(text(query)) + self.raw_classification = [row._asdict() for row in rds_data.fetchall()] + self.easy_classification_dict = {item['ID']:item['CLASSIFICATION'] for item in self.raw_classification} + self.classification_id_dict = {item['CLASSIFICATION']: item['ID'] for item in self.raw_classification} + + + def get_raw_pyg(self): + query = """SELECT * FROM RAW_PYG""" + logger.info(f"[get_raw_pyg] Query a base de datos para obtener el raw de pyg:\n {query}") + rds_data = self.db_connection.execute(text(query)) + self.raw_pyg = [row._asdict() for row in rds_data.fetchall()] + self.easy_raw_pyg_dict = {item['PYG_ITEM_NAME']:item['ID'] for item in self.raw_pyg} + self.id_raw_pyg_dict = {item['ID']:item['PYG_ITEM_NAME'] for item in self.raw_pyg} + + def get_raw_cash_flow(self): + query = """SELECT * FROM RAW_CASH_FLOW""" + logger.info(f"[get_raw_cash_flow] Query a base de datos para obtener el raw de cash_flow:\n {query}") + rds_data = self.db_connection.execute(text(query)) + self.raw_cash_flow = [row._asdict() for row in rds_data.fetchall()] + self.cash_flow_id_dict = {item['CASH_FLOW_ITEM_NAME']: item['ID'] for item in self.raw_cash_flow} + + + @handler_wrapper('Organizando las formas de fechas que se van a utilizar', 'Fechas del proceso de valoración organizadas con exito', 'Error organizando fechas dle proceso de valoración', 'Error organizando fechas') + def organize_all_dates_info(self): + self.new_assessment_date = self.historic_dates[-1] #esta variable se usa solo una vez en pyg, revisar si hay otra forma de usarla allá para eliminarla acá + self.historic_dates_len = len(self.historic_dates) + self.projection_dates_len = len(self.projection_dates) + + logger.warning(f'[mira aca] esto debería estar en formato fecha: {self.historic_dates}') + self.historic_dates_long = [date.strftime('%Y-%m-%d %H:%M:%S') for date in self.historic_dates] + self.assessment_initial_date = self.historic_dates_long[-1] + self.projection_dates_long = [datetime.datetime.strptime(str(date), '%Y-%m-%d').strftime('%Y-%m-%d %H:%M:%S') for date in self.projection_dates] + self.all_dates_long = self.historic_dates_long + self.projection_dates_long + self.all_dates_len = len(self.all_dates_long) + + + @debugger_wrapper('Error construyendo respuesta final', 'Error construyendo respuesta') + def response_maker(self, succesfull_run = False, error_str = str()): + if succesfull_run: + self.final_response['statusCode'] = 200 + self.final_response['body'] = json.dumps({"id_assessment": self.id_assessment}) + self.orchestrator_state_update('SUCCES') + self.db_connection.commit() if __name__ != 'lambda_function' else None + else: + self.orchestrator_state_update('ERROR') + self.final_response['body'] = json.dumps(self.detailed_raise if self.detailed_raise else error_str) + self.db_connection.rollback() if __name__ != 'lambda_function' else None + if self.db_connection: + self.df_and_upload(self.noting_list, 'NOTES') + self.db_connection.close() + return self.final_response + + + +def get_current_error_line(): + return str(sys.exc_info()[-1].tb_lineno) + + +if __name__ == "__main__": + #event = {'body': "{\"date\":\"18-08-2023\",\"nit\":\"262626262-1\",\"periodicity\":\"Anual\",\"user\":\"dmanchola@precia.co\",\"recurrence\":false, \"selected_dates\": []}"} + event = {"id_assessment": 2071} + lambda_handler(event, '') + diff --git a/corporate_finances_back_py/super-orchestrator/models_tables.py b/corporate_finances_back_py/super-orchestrator/models_tables.py new file mode 100644 index 0000000..c3b851f --- /dev/null +++ b/corporate_finances_back_py/super-orchestrator/models_tables.py @@ -0,0 +1,52 @@ +models_tables = [ +'MODEL_USER_CLASSIFICATION', +"MODEL_ASSESSMENT_YEARS", +"MODEL_CAPEX", +"MODEL_CALCULATED_ASSESSMENT", +"MODEL_DEBT", +"MODEL_FIXED_ASSETS", +"MODEL_MODAL_WINDOWS", +"MODEL_PYG_ITEM", +"MODEL_CAPEX_VALUES", +"MODEL_PROJECTED_DEBT", +"MODEL_FCLO_DISCOUNT", +"MODEL_PROJECTED_FIXED_ASSETS", +"MODEL_MODAL_WINDOWS_PROJECTED", +"MODEL_PROJECTED_PYG", +] + + +assessment_tables = [ +'USER_CLASSIFICATION', +"ASSESSMENT_YEARS", +"CAPEX", +"CALCULATED_ASSESSMENT", +"DEBT", +"FIXED_ASSETS", +"MODAL_WINDOWS", +"PYG_ITEM", +"CAPEX_VALUES", +"PROJECTED_DEBT", +"FCLO_DISCOUNT", +"PROJECTED_FIXED_ASSETS", +"MODAL_WINDOWS_PROJECTED", +"PROJECTED_PYG", +] + + +simple_atributes_tables = {'CAPEX': ['CAPEX_NAME', 'USED_ACCOUNT_NAME', 'METHOD', 'TIME_PERIOD', 'PERIODS', 'CALCULATION_COMMENT'], + 'DEBT': ['ORIGINAL_VALUE', 'ACCOUNT_NUMBER', 'ALIAS_NAME', 'PROJECTION_TYPE', 'START_YEAR', 'ENDING_YEAR', 'DEBT_COMMENT', 'RATE_COMMENT', 'SPREAD_COMMENT'], + 'FIXED_ASSETS': ['ID_ITEMS_GROUP', 'PROJECTION_TYPE', 'ASSET_ACCOUNT', 'ACUMULATED_ACCOUNT', 'PERIOD_ACCOUNT', 'PROJECTED_YEARS', 'CALCULATION_COMMENT'], + 'MODAL_WINDOWS': ['ACCOUNT_NUMBER', 'CONTEXT_WINDOW', 'VS_ACCOUNT_NAME', 'PROJECTION_TYPE', 'COMMENT'], + 'PYG_ITEM': ['ID_RAW_PYG', 'ID_DEPENDENCE', 'PROJECTION_TYPE', 'COMMENT'], + 'USER_CLASSIFICATION': ['ACCOUNT_NUMBER', 'ID_RAW_CLASSIFICATION'], + 'CALCULATED_ASSESSMENT': ['ASSESSMENT_DATE', 'INITIAL_DATE', 'DATES_ADJUST_ATRIBUTE', 'DATES_ADJUST_COMMENT', 'CHOSEN_FLOW_NAME', 'GRADIENT', 'TERMINAL_VALUE', 'TOTAL_NOT_OPERATIONAL_ASSETS', 'TOTAL_OPERATIONAL_PASIVES', 'OUTSTANDING_SHARES', 'ADJUST_METHOD', ] +} + + +ordered_atributes_tables = {'CAPEX_VALUES': {'columns': ['CAPEX_NAME', 'CALCULATED_DATE', 'MANUAL_PERCENTAGE', 'CAPEX_SUMMARY', 'CAPEX_ACUMULATED'], 'order':'CALCULATED_DATE'}, + 'PROJECTED_DEBT': {'columns': ['ITEM_DATE', 'ACCOUNT_NUMBER', 'ALIAS_NAME', 'INITIAL_BALANCE', 'DISBURSEMENT', 'AMORTIZATION', 'ENDING_BALANCE', 'INTEREST_VALUE','ENDING_BALANCE_VARIATION', 'RATE_ATRIBUTE', 'SPREAD_ATRIBUTE'], 'order':'ITEM_DATE'}, + 'FCLO_DISCOUNT': {'columns': ['ITEM_DATE', 'DISCOUNT_PERIOD', 'DISCOUNT_RATE', 'DISCOUNT_FACTOR'], 'order':'ITEM_DATE'}, + 'PROJECTED_FIXED_ASSETS': {'columns': ['PROJECTED_DATE', 'ID_ITEMS_GROUP', 'ASSET_VALUE', 'ACUMULATED_VALUE', 'EXISTING_ASSET_VALUE', 'PERIOD_VALUE'], 'order':'PROJECTED_DATE'}, + 'MODAL_WINDOWS_PROJECTED': {'columns': ['PROJECTED_DATE', 'ACCOUNT_NUMBER', 'CONTEXT_WINDOW', 'ATRIBUTE', 'VALUE'], 'order': 'PROJECTED_DATE'}, + 'PROJECTED_PYG': {'columns': ['PROJECTED_DATE', 'ID_RAW_PYG', 'ATRIBUTE', 'VALUE'], 'order':'PROJECTED_DATE'}} \ No newline at end of file diff --git a/corporate_finances_back_py/super-orchestrator/utils.py b/corporate_finances_back_py/super-orchestrator/utils.py new file mode 100644 index 0000000..3e28406 --- /dev/null +++ b/corporate_finances_back_py/super-orchestrator/utils.py @@ -0,0 +1,48 @@ +#version 2024 - 03 - 15 +import base64 +import boto3 +import json +import logging +import os +from sqlalchemy import create_engine +from sqlalchemy.pool import NullPool + +if __name__ in ['utils']: + from decorators import handler_wrapper, timing, debugger_wrapper + +else: + from .decorators import handler_wrapper, timing, debugger_wrapper + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + + +@debugger_wrapper('Error al obtener secreto','Error fatal de back conectando a base de datos') +def get_secret(secret_region, secret_name): + session = boto3.session.Session() + client_secrets_manager = session.client(service_name='secretsmanager', region_name=secret_region) + secret_data = client_secrets_manager.get_secret_value(SecretId=secret_name) + if 'SecretString' in secret_data: + secret_str = secret_data['SecretString'] + else: + secret_str = base64.b64decode(secret_data['SecretBinary']) + logger.info('[utils] (get_secret) Se obtuvo el secreto') + return json.loads(secret_str) + + +@debugger_wrapper('Error en la conexion a base de datos','Error fatal de back conectando a base de datos') +def connect_to_db(db_schema, db_secret): + conn_string = ('mysql+mysqlconnector://' + db_secret["username"] + ':' + db_secret["password"] + '@' + db_secret["host"] + ':' + str(db_secret["port"]) + '/' + db_schema) + sql_engine = create_engine(conn_string, poolclass=NullPool) + db_connection = sql_engine.connect() + return db_connection + + +@debugger_wrapper('Error en la conexion a base de datos','Error fatal de back conectando a base de datos') +def connect_to_db_local_dev(): + from dotenv import load_dotenv + load_dotenv() + conn_string = os.environ['local_dev_connector'] + sql_engine = create_engine(conn_string, poolclass=NullPool) + db_connection = sql_engine.connect() + return db_connection diff --git a/corporate_finances_back_py/token-checking/decorators.py b/corporate_finances_back_py/token-checking/decorators.py new file mode 100644 index 0000000..071760a --- /dev/null +++ b/corporate_finances_back_py/token-checking/decorators.py @@ -0,0 +1,63 @@ +#version 2023 - 05 - 04 +import logging +import sys +import traceback +from functools import wraps +from time import time + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + +def handler_wrapper(start, satisfactory_log, error_log, raise_error): + #esto se ejecuta en la inicializacion de primero + def decorator(func): + #print(message1) + #lo que yo ponga acá se ejecuta antes de hacer el llamado a la funcion + @wraps(func) + def wrapper(*args, **kwargs): + #esto sí se ejecuta solo cuando llama a la funcion decorada + #print(message2) + try: + logger.info(f'[{func.__name__}] {start}...') + resultado = func(*args, **kwargs) + logger.info(f'[{func.__name__}] {satisfactory_log}') + return resultado + except Exception as e: + logger.error(f"[{func.__name__}] {error_log}, linea: {get_especific_error_line(func.__name__)}, motivo: {str(e)}") + raise Exception(f"{raise_error}") + + return wrapper + return decorator + +def debugger_wrapper(error_log, raise_error): + def decorator(func): + @wraps(func) + def wrapper(*args, **kwargs): + try: + resultado = func(*args, **kwargs) + return resultado + except Exception as e: + logger.error(f"[{func.__name__}] {error_log}, linea: {get_especific_error_line(func.__name__)}, motivo: {str(e)}") + raise Exception(f"{raise_error}") + return wrapper + return decorator + + +def get_especific_error_line(func_name): + _, _, exc_tb = sys.exc_info() + for trace in traceback.extract_tb(exc_tb): + if func_name in trace: + return str(trace[1]) + +def timing(f): + @wraps(f) + def wrap(*args, **kw): + ts = time() + result = f(*args, **kw) + te = time() + taken_time_message = '[timing] La funcion {}, toma: {:.2f} sec en ejecutarse'.format(f.__name__, te-ts) + logger.info(taken_time_message) + return result + return wrap + + diff --git a/corporate_finances_back_py/token-checking/lambda_function.py b/corporate_finances_back_py/token-checking/lambda_function.py new file mode 100644 index 0000000..bf87377 --- /dev/null +++ b/corporate_finances_back_py/token-checking/lambda_function.py @@ -0,0 +1,130 @@ +""": +variables de entorno: +SECRET_AUTENTICATION_INFO : finanzas/valoracionempresas/autenticacion +SECRET_REGION : us-east-1 + +capas: +capa-requests-cryptography-pyjwt-3-9 + +ram: +1024MB + +""" + + +import jwt +import requests +from cryptography.x509 import load_pem_x509_certificate +from cryptography.hazmat.backends import default_backend +import logging +import sys +import os +import json +from utils import get_secret + +from decorators import handler_wrapper, timing, debugger_wrapper + +#logging.basicConfig() #En lambdas borra este + +logger = logging.getLogger() +logger.setLevel(logging.INFO) +#raise Exception('fallida esperada') + +def lambda_handler(event,context): + lo = lambda_object(event) + return lo.starter() + + +class lambda_object: + def __init__(self, event): + try: + self.failed_init = False + #self.final_response = {"isAuthorized": "true","context": {"exampleKey": "exampleValue"}} + self.final_response = {"principalId": "user", + "policyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": "execute-api:Invoke", + "Effect": "Deny", #Allow #Deny + "Resource": str()}]}} + + + self.detailed_raise = '' + self.partial_response = {} + + logger.warning(f'event de entrada: {str(event)}') + self.token = event['authorizationToken'] + #self.company_table = os.environ['COMPANY_TABLE'] + + self.final_response['policyDocument']['Statement'][0]['Resource'] = event['methodArn'] + + + except Exception as e: + logger.error(f'[__init__] Error inicializando objeto lambda, linea: {get_current_error_line()}, motivo: {str(e)}') + self.failed_init = True + + def starter(self): + try: + if self.failed_init: + raise AttributeError('Error con los datos recibidos al servicio') + self.get_secret_information() + self.check_token() + + return self.response_maker(succesfull_run = True) + except Exception as e: + logger.error(f'[starter] Hubieron problemas en el comando de la linea: {get_current_error_line()}') + return self.response_maker(succesfull_run = False, error_str = (str(e))) + + + @handler_wrapper('Obteniendo secretos', 'Secretos obtenidos con exito', 'Error obteniendo secretos', 'Error descifrando información empresarial') + def get_secret_information(self): + secret_autentication_info = os.environ['SECRET_AUTENTICATION_INFO'] + secret_region = os.environ['SECRET_REGION'] + + autenticacion_info = get_secret(secret_region, secret_autentication_info) + #logger.info(f'[mira aca] {autenticacion_info}') + self.ms_tenant = autenticacion_info['ms_tenant'] + self.client_id = autenticacion_info['client_id'] + + + @handler_wrapper('Chequeando token', 'Token chequeado, generando respuesta', 'Error chequeando token', 'Error chequeando token') + def check_token(self): + PEMSTART = "-----BEGIN CERTIFICATE-----\n" + PEMEND = "\n-----END CERTIFICATE-----\n" + + jwt_token = self.token + #ms_tenant = "caa1dfbf-34d5-4061-9cdf-0ceaa516bf03" + #client_id = "dcd76a6c-30fe-4390-bf3c-dfefd29d304c" + + jwks_uri = f"https://login.microsoftonline.com/{self.ms_tenant}/discovery/v2.0/keys" + + #issuer = f'https://login.microsoftonline.com/{ms_tenant}/v2.0' + issuer = f'https://sts.windows.net/{self.ms_tenant}/' + + uri_response = requests.get(jwks_uri).json() + keys = uri_response.get("keys", False) + + if keys: + kid = jwt.get_unverified_header(jwt_token).get("kid") + for key in keys: + if kid == key["kid"]: + cert = PEMSTART + key["x5c"][0] + PEMEND + cert_obj = load_pem_x509_certificate(cert.encode(), default_backend()) + public_key = cert_obj.public_key() + decoded = jwt.decode(jwt_token, public_key, algorithms=["RS256"], audience=self.client_id, issuer=issuer) #aca cambie el tenant por client id + #logger.warning(str(decoded)) + logger.warning(f"[check_token] El usuario {decoded['unique_name']} se autenticó correctamente") + self.final_response['policyDocument']['Statement'][0]['Effect'] = 'Allow' + self.final_response['context'] = {'stringKey':decoded['unique_name']} + break + + + @debugger_wrapper('Error construyendo respuesta final', 'Error construyendo respuesta') + def response_maker(self, succesfull_run = False, error_str = str()): + return self.final_response + + +def get_current_error_line(): + return str(sys.exc_info()[-1].tb_lineno) + \ No newline at end of file diff --git a/corporate_finances_back_py/token-checking/utils.py b/corporate_finances_back_py/token-checking/utils.py new file mode 100644 index 0000000..5109e1c --- /dev/null +++ b/corporate_finances_back_py/token-checking/utils.py @@ -0,0 +1,33 @@ +#version 2023 - 05 - 04 +import base64 +import boto3 +import json +import logging + +#from sqlalchemy import create_engine + +from decorators import handler_wrapper, debugger_wrapper + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + + +@debugger_wrapper('Error al obtener secreto','Error fatal de back conectando a base de datos') +def get_secret(secret_region, secret_name): + session = boto3.session.Session() + client_secrets_manager = session.client(service_name='secretsmanager', region_name=secret_region) + secret_data = client_secrets_manager.get_secret_value(SecretId=secret_name) + if 'SecretString' in secret_data: + secret_str = secret_data['SecretString'] + else: + secret_str = base64.b64decode(secret_data['SecretBinary']) + logger.info('[utils] (get_secret) Se obtuvo el secreto') + return json.loads(secret_str) + + +@debugger_wrapper('Error en la conexion a base de datos','Error fatal de back conectando a base de datos') +def connect_to_db(db_schema, db_secret): + conn_string = ('mysql+mysqlconnector://' + db_secret["username"] + ':' + db_secret["password"] + '@' + db_secret["host"] + ':' + str(db_secret["port"]) + '/' + db_schema) + sql_engine = create_engine(conn_string) + db_connection = sql_engine.connect() + return db_connection \ No newline at end of file diff --git a/corporate_finances_back_py/zip_creator.py b/corporate_finances_back_py/zip_creator.py new file mode 100644 index 0000000..81f60c2 --- /dev/null +++ b/corporate_finances_back_py/zip_creator.py @@ -0,0 +1,22 @@ +import os +import zipfile + + +zip_output_folder = '\\'.join(os.getcwd().split('\\')[:-1]) + '\\compressed_files' + +#os.mkdir(zip_output_folder) + +def make_zipfile(master_folder_name, compressing_folder_name): + with zipfile.ZipFile(f'{zip_output_folder}\\{compressing_folder_name}.zip', 'w') as myzip: + files_in_folder = [file for file in os.listdir(f'{master_folder_name}\\{compressing_folder_name}') if '__pycache__' not in file] + for file in files_in_folder: + myzip.write(f'{master_folder_name}\\{compressing_folder_name}\\{file}', file) + + +current_folder = os.getcwd() +folders_in_current_folder = [folder_name for folder_name in os.listdir(current_folder) if ('.' not in folder_name)] +print(f'Carpetas encontradas en {current_folder}:\n{folders_in_current_folder}') + + +for folder in folders_in_current_folder: + make_zipfile(current_folder, folder) diff --git a/corporate_finances_ui_py/.editorconfig b/corporate_finances_ui_py/.editorconfig new file mode 100644 index 0000000..59d9a3a --- /dev/null +++ b/corporate_finances_ui_py/.editorconfig @@ -0,0 +1,16 @@ +# Editor configuration, see https://editorconfig.org +root = true + +[*] +charset = utf-8 +indent_style = space +indent_size = 2 +insert_final_newline = true +trim_trailing_whitespace = true + +[*.ts] +quote_type = single + +[*.md] +max_line_length = off +trim_trailing_whitespace = false diff --git a/corporate_finances_ui_py/angular.json b/corporate_finances_ui_py/angular.json new file mode 100644 index 0000000..f5a8ee4 --- /dev/null +++ b/corporate_finances_ui_py/angular.json @@ -0,0 +1,138 @@ +{ + "$schema": "./node_modules/@angular/cli/lib/config/schema.json", + "cli": { + "analytics": false + }, + "version": 1, + "newProjectRoot": "projects", + "projects": { + "deltaws2": { + "projectType": "application", + "schematics": { + "@schematics/angular:application": { + "strict": true + } + }, + "root": "", + "sourceRoot": "src", + "prefix": "app", + "architect": { + "build": { + "builder": "@angular-devkit/build-angular:browser", + "options": { + "allowedCommonJsDependencies": [ + "sweetalert2" + ], + "outputPath": "dist/deltaws2", + "index": "src/index.html", + "main": "src/main.ts", + "polyfills": "src/polyfills.ts", + "tsConfig": "tsconfig.app.json", + "assets": [ + "src/favicon.ico", + "src/assets" + ], + "styles": [ + "node_modules/bootstrap/dist/css/bootstrap.min.css", + "node_modules/ngx-spinner/animations/square-jelly-box.css", + "src/styles.css" + ], + "scripts": [ + "node_modules/bootstrap/dist/js/bootstrap.min.js" + ] + }, + "configurations": { + "production": { + "budgets": [ + { + "type": "initial", + "maximumWarning": "2mb", + "maximumError": "2mb" + }, + { + "type": "anyComponentStyle", + "maximumWarning": "2mb", + "maximumError": "2mb" + } + ], + "fileReplacements": [ + { + "replace": "src/environments/environment.ts", + "with": "src/environments/environment.prod.ts" + } + ], + "outputHashing": "all" + }, + "qa": { + "budgets": [ + { + "type": "initial", + "maximumWarning": "2mb", + "maximumError": "2mb" + }, + { + "type": "anyComponentStyle", + "maximumWarning": "2mb", + "maximumError": "2mb" + } + ], + "fileReplacements": [ + { + "replace": "src/environments/environment.ts", + "with": "src/environments/environment.qa.ts" + } + ], + "outputHashing": "all" + }, + "development": { + "buildOptimizer": false, + "optimization": false, + "vendorChunk": true, + "extractLicenses": false, + "sourceMap": true, + "namedChunks": true + } + }, + "defaultConfiguration": "production" + }, + "serve": { + "builder": "@angular-devkit/build-angular:dev-server", + "configurations": { + "production": { + "browserTarget": "deltaws2:build:production" + }, + "qa": { + "browserTarget": "angular-multiple-env:build:qa" + }, + "development": { + "browserTarget": "deltaws2:build:development" + } + }, + "defaultConfiguration": "development" + }, + "extract-i18n": { + "builder": "@angular-devkit/build-angular:extract-i18n", + "options": { + "browserTarget": "deltaws2:build" + } + }, + "test": { + "builder": "@angular-devkit/build-angular:karma", + "options": { + "main": "src/test.ts", + "polyfills": "src/polyfills.ts", + "tsConfig": "tsconfig.spec.json", + "assets": [ + "src/favicon.ico", + "src/assets" + ], + "styles": [ + "src/styles.css" + ], + "scripts": [] + } + } + } + } + } +} \ No newline at end of file diff --git a/corporate_finances_ui_py/package-lock.json b/corporate_finances_ui_py/package-lock.json new file mode 100644 index 0000000..69da055 --- /dev/null +++ b/corporate_finances_ui_py/package-lock.json @@ -0,0 +1,25177 @@ +{ + "name": "deltaws2", + "version": "0.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "deltaws2", + "version": "0.0.0", + "dependencies": { + "@angular/animations": "^15.2.10", + "@angular/cdk": "^13.3.8", + "@angular/common": "^15.2.10", + "@angular/compiler": "^15.2.10", + "@angular/core": "^15.2.10", + "@angular/forms": "^15.2.10", + "@angular/localize": "^15.2.10", + "@angular/platform-browser": "^15.2.10", + "@angular/platform-browser-dynamic": "^15.2.10", + "@angular/router": "^15.2.10", + "@azure/msal-angular": "^2.5.4", + "@azure/msal-browser": "^2.34.0", + "@ng-bootstrap/ng-bootstrap": "^12.1.2", + "@ng-idle/core": "^11.1.0", + "@ng-idle/keepalive": "^11.0.3", + "@popperjs/core": "^2.11.5", + "bootstrap": "^5.1.3", + "exceljs": "^4.3.0", + "file-saver": "^2.0.5", + "ngx-bootstrap-multiselect": "^2.1.1", + "ngx-spinner": "^13.1.1", + "rxjs": "~7.5.0", + "sweetalert2": "^11.4.17", + "tslib": "^2.3.0", + "xlsx": "^0.18.5", + "zone.js": "~0.11.4" + }, + "devDependencies": { + "@angular-devkit/build-angular": "^15.2.10", + "@angular/cli": "^15.2.10", + "@angular/compiler-cli": "^15.2.10", + "@types/events": "^3.0.0", + "@types/file-saver": "^2.0.5", + "@types/jasmine": "~3.10.0", + "@types/node": "^12.11.1", + "@typescript-eslint/parser": "^5.26.0", + "eslint": "^8.16.0", + "eslint-import-resolver-typescript": "^2.7.1", + "eslint-plugin-import": "^2.26.0", + "jasmine-core": "~4.0.0", + "karma": "~6.3.0", + "karma-chrome-launcher": "~3.1.0", + "karma-coverage": "~2.1.0", + "karma-jasmine": "~4.0.0", + "karma-jasmine-html-reporter": "~1.7.0", + "typescript": "~4.9.5" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", + "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", + "dependencies": { + "@jridgewell/gen-mapping": "^0.1.0", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@angular-devkit/architect": { + "version": "0.1502.10", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1502.10.tgz", + "integrity": "sha512-S8lN73WYCfpEpw1Q41ZcUinw7JfDeSM8LyGs797OVshnW75QcOkOecWj/3CKR23G44IgFrHN6sqtzWxKmMxLig==", + "dev": true, + "dependencies": { + "@angular-devkit/core": "15.2.10", + "rxjs": "6.6.7" + }, + "engines": { + "node": "^14.20.0 || ^16.13.0 || >=18.10.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@angular-devkit/architect/node_modules/rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "dev": true, + "dependencies": { + "tslib": "^1.9.0" + }, + "engines": { + "npm": ">=2.0.0" + } + }, + "node_modules/@angular-devkit/architect/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "node_modules/@angular-devkit/build-angular": { + "version": "15.2.11", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-15.2.11.tgz", + "integrity": "sha512-MnpVCJdk5jHuK7CH/cTcRT0JQkkKkRTEV3WTyOUhTm0O3PlKwvTM6/Sner+zyuhKyw5VFBBMypHh59aTUDEZ1A==", + "dev": true, + "dependencies": { + "@ampproject/remapping": "2.2.0", + "@angular-devkit/architect": "0.1502.11", + "@angular-devkit/build-webpack": "0.1502.11", + "@angular-devkit/core": "15.2.11", + "@babel/core": "7.20.12", + "@babel/generator": "7.20.14", + "@babel/helper-annotate-as-pure": "7.18.6", + "@babel/helper-split-export-declaration": "7.18.6", + "@babel/plugin-proposal-async-generator-functions": "7.20.7", + "@babel/plugin-transform-async-to-generator": "7.20.7", + "@babel/plugin-transform-runtime": "7.19.6", + "@babel/preset-env": "7.20.2", + "@babel/runtime": "7.20.13", + "@babel/template": "7.20.7", + "@discoveryjs/json-ext": "0.5.7", + "@ngtools/webpack": "15.2.11", + "ansi-colors": "4.1.3", + "autoprefixer": "10.4.13", + "babel-loader": "9.1.2", + "babel-plugin-istanbul": "6.1.1", + "browserslist": "4.21.5", + "cacache": "17.0.4", + "chokidar": "3.5.3", + "copy-webpack-plugin": "11.0.0", + "critters": "0.0.16", + "css-loader": "6.7.3", + "esbuild-wasm": "0.17.8", + "glob": "8.1.0", + "https-proxy-agent": "5.0.1", + "inquirer": "8.2.4", + "jsonc-parser": "3.2.0", + "karma-source-map-support": "1.4.0", + "less": "4.1.3", + "less-loader": "11.1.0", + "license-webpack-plugin": "4.0.2", + "loader-utils": "3.2.1", + "magic-string": "0.29.0", + "mini-css-extract-plugin": "2.7.2", + "open": "8.4.1", + "ora": "5.4.1", + "parse5-html-rewriting-stream": "7.0.0", + "piscina": "3.2.0", + "postcss": "8.4.31", + "postcss-loader": "7.0.2", + "resolve-url-loader": "5.0.0", + "rxjs": "6.6.7", + "sass": "1.58.1", + "sass-loader": "13.2.0", + "semver": "7.5.3", + "source-map-loader": "4.0.1", + "source-map-support": "0.5.21", + "terser": "5.16.3", + "text-table": "0.2.0", + "tree-kill": "1.2.2", + "tslib": "2.5.0", + "webpack": "5.76.1", + "webpack-dev-middleware": "6.1.2", + "webpack-dev-server": "4.11.1", + "webpack-merge": "5.8.0", + "webpack-subresource-integrity": "5.1.0" + }, + "engines": { + "node": "^14.20.0 || ^16.13.0 || >=18.10.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "optionalDependencies": { + "esbuild": "0.17.8" + }, + "peerDependencies": { + "@angular/compiler-cli": "^15.0.0", + "@angular/localize": "^15.0.0", + "@angular/platform-server": "^15.0.0", + "@angular/service-worker": "^15.0.0", + "karma": "^6.3.0", + "ng-packagr": "^15.0.0", + "protractor": "^7.0.0", + "tailwindcss": "^2.0.0 || ^3.0.0", + "typescript": ">=4.8.2 <5.0" + }, + "peerDependenciesMeta": { + "@angular/localize": { + "optional": true + }, + "@angular/platform-server": { + "optional": true + }, + "@angular/service-worker": { + "optional": true + }, + "karma": { + "optional": true + }, + "ng-packagr": { + "optional": true + }, + "protractor": { + "optional": true + }, + "tailwindcss": { + "optional": true + } + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@angular-devkit/architect": { + "version": "0.1502.11", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1502.11.tgz", + "integrity": "sha512-+hkG5UjIaKMRdo6SFLNQs+Cv7yAVeN8ijfDwI2z/mp7/otowuSEy+H3Tii195jfJ8TQ+y1B7svnx2D6O7oOYbQ==", + "dev": true, + "dependencies": { + "@angular-devkit/core": "15.2.11", + "rxjs": "6.6.7" + }, + "engines": { + "node": "^14.20.0 || ^16.13.0 || >=18.10.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@angular-devkit/core": { + "version": "15.2.11", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-15.2.11.tgz", + "integrity": "sha512-zd6QelJ8pOPvz6TsehR0JqixjDjzgEOkKywBJBuwNXY+Nw3MJGayJeWS0UgC+Gk+LoTkpI21RoyaYELkAmD/tw==", + "dev": true, + "dependencies": { + "ajv": "8.12.0", + "ajv-formats": "2.1.1", + "jsonc-parser": "3.2.0", + "rxjs": "6.6.7", + "source-map": "0.7.4" + }, + "engines": { + "node": "^14.20.0 || ^16.13.0 || >=18.10.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "peerDependencies": { + "chokidar": "^3.5.2" + }, + "peerDependenciesMeta": { + "chokidar": { + "optional": true + } + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@babel/core": { + "version": "7.20.12", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.20.12.tgz", + "integrity": "sha512-XsMfHovsUYHFMdrIHkZphTN/2Hzzi78R08NuHfDBehym2VsPDL6Zn/JAD/JQdnRvbSsbQc4mVaU1m6JgtTEElg==", + "dev": true, + "dependencies": { + "@ampproject/remapping": "^2.1.0", + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.20.7", + "@babel/helper-compilation-targets": "^7.20.7", + "@babel/helper-module-transforms": "^7.20.11", + "@babel/helpers": "^7.20.7", + "@babel/parser": "^7.20.7", + "@babel/template": "^7.20.7", + "@babel/traverse": "^7.20.12", + "@babel/types": "^7.20.7", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.2", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@babel/core/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@babel/helper-split-export-declaration": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", + "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/browserslist": { + "version": "4.21.5", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz", + "integrity": "sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001449", + "electron-to-chromium": "^1.4.284", + "node-releases": "^2.0.8", + "update-browserslist-db": "^1.0.10" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "dev": true, + "dependencies": { + "tslib": "^1.9.0" + }, + "engines": { + "npm": ">=2.0.0" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/rxjs/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "node_modules/@angular-devkit/build-angular/node_modules/semver": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz", + "integrity": "sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@angular-devkit/build-webpack": { + "version": "0.1502.11", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1502.11.tgz", + "integrity": "sha512-OTONIRp770Jfems4+cULmtoeSzjnpx5UjV2EazojnhRXXBSJMWRMPvwD2QvQl9UO/6eOV3d2mgmP2xOZgc/D6w==", + "dev": true, + "dependencies": { + "@angular-devkit/architect": "0.1502.11", + "rxjs": "6.6.7" + }, + "engines": { + "node": "^14.20.0 || ^16.13.0 || >=18.10.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "peerDependencies": { + "webpack": "^5.30.0", + "webpack-dev-server": "^4.0.0" + } + }, + "node_modules/@angular-devkit/build-webpack/node_modules/@angular-devkit/architect": { + "version": "0.1502.11", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1502.11.tgz", + "integrity": "sha512-+hkG5UjIaKMRdo6SFLNQs+Cv7yAVeN8ijfDwI2z/mp7/otowuSEy+H3Tii195jfJ8TQ+y1B7svnx2D6O7oOYbQ==", + "dev": true, + "dependencies": { + "@angular-devkit/core": "15.2.11", + "rxjs": "6.6.7" + }, + "engines": { + "node": "^14.20.0 || ^16.13.0 || >=18.10.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@angular-devkit/build-webpack/node_modules/@angular-devkit/core": { + "version": "15.2.11", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-15.2.11.tgz", + "integrity": "sha512-zd6QelJ8pOPvz6TsehR0JqixjDjzgEOkKywBJBuwNXY+Nw3MJGayJeWS0UgC+Gk+LoTkpI21RoyaYELkAmD/tw==", + "dev": true, + "dependencies": { + "ajv": "8.12.0", + "ajv-formats": "2.1.1", + "jsonc-parser": "3.2.0", + "rxjs": "6.6.7", + "source-map": "0.7.4" + }, + "engines": { + "node": "^14.20.0 || ^16.13.0 || >=18.10.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "peerDependencies": { + "chokidar": "^3.5.2" + }, + "peerDependenciesMeta": { + "chokidar": { + "optional": true + } + } + }, + "node_modules/@angular-devkit/build-webpack/node_modules/rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "dev": true, + "dependencies": { + "tslib": "^1.9.0" + }, + "engines": { + "npm": ">=2.0.0" + } + }, + "node_modules/@angular-devkit/build-webpack/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "node_modules/@angular-devkit/core": { + "version": "15.2.10", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-15.2.10.tgz", + "integrity": "sha512-bFPm7wjvfBds9km2rCJxUhzkqe4h3h/199yJtzC1bNvwRr2LMHvtyoQAzftda+gs7Ulqac5wzUEZX/cVV3WrsA==", + "dev": true, + "dependencies": { + "ajv": "8.12.0", + "ajv-formats": "2.1.1", + "jsonc-parser": "3.2.0", + "rxjs": "6.6.7", + "source-map": "0.7.4" + }, + "engines": { + "node": "^14.20.0 || ^16.13.0 || >=18.10.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "peerDependencies": { + "chokidar": "^3.5.2" + }, + "peerDependenciesMeta": { + "chokidar": { + "optional": true + } + } + }, + "node_modules/@angular-devkit/core/node_modules/rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "dev": true, + "dependencies": { + "tslib": "^1.9.0" + }, + "engines": { + "npm": ">=2.0.0" + } + }, + "node_modules/@angular-devkit/core/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "node_modules/@angular-devkit/schematics": { + "version": "15.2.10", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-15.2.10.tgz", + "integrity": "sha512-EeoDs4oKFpLZNa21G/8dqBdclEc4U2piI9EeXCVTaN6z5DYXIZ0G1WtCXU8nhD+GckS47rmfZ4/3lMaXAvED+g==", + "dev": true, + "dependencies": { + "@angular-devkit/core": "15.2.10", + "jsonc-parser": "3.2.0", + "magic-string": "0.29.0", + "ora": "5.4.1", + "rxjs": "6.6.7" + }, + "engines": { + "node": "^14.20.0 || ^16.13.0 || >=18.10.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@angular-devkit/schematics/node_modules/rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "dev": true, + "dependencies": { + "tslib": "^1.9.0" + }, + "engines": { + "npm": ">=2.0.0" + } + }, + "node_modules/@angular-devkit/schematics/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "node_modules/@angular/animations": { + "version": "15.2.10", + "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-15.2.10.tgz", + "integrity": "sha512-yxfN8qQpMaukRU5LjFkJBmy85rqrOp86tYVCsf+hmPEFRiXBMUj6xYLeCMcpk3Mt1JtnWGBR34ivGx+7bNeAow==", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^14.20.0 || ^16.13.0 || >=18.10.0" + }, + "peerDependencies": { + "@angular/core": "15.2.10" + } + }, + "node_modules/@angular/cdk": { + "version": "13.3.8", + "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-13.3.8.tgz", + "integrity": "sha512-ciLYoVxsqnA9hGJTUW74A56NjArYhFdqFYmVDimWWNYAgY7jY1gCfKq9UtixUErDi29FGSCWRbLuZ6w4q0NYnA==", + "dependencies": { + "tslib": "^2.3.0" + }, + "optionalDependencies": { + "parse5": "^5.0.0" + }, + "peerDependencies": { + "@angular/common": "^13.0.0 || ^14.0.0-0", + "@angular/core": "^13.0.0 || ^14.0.0-0", + "rxjs": "^6.5.3 || ^7.4.0" + } + }, + "node_modules/@angular/cli": { + "version": "15.2.10", + "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-15.2.10.tgz", + "integrity": "sha512-/TSnm/ZQML6A4lvunyN2tjTB5utuvk3d1Pnfyehp/FXtV6YfZm6+EZrOpKkKPCxTuAgW6c9KK4yQtt3RuNVpwQ==", + "dev": true, + "dependencies": { + "@angular-devkit/architect": "0.1502.10", + "@angular-devkit/core": "15.2.10", + "@angular-devkit/schematics": "15.2.10", + "@schematics/angular": "15.2.10", + "@yarnpkg/lockfile": "1.1.0", + "ansi-colors": "4.1.3", + "ini": "3.0.1", + "inquirer": "8.2.4", + "jsonc-parser": "3.2.0", + "npm-package-arg": "10.1.0", + "npm-pick-manifest": "8.0.1", + "open": "8.4.1", + "ora": "5.4.1", + "pacote": "15.1.0", + "resolve": "1.22.1", + "semver": "7.5.3", + "symbol-observable": "4.0.0", + "yargs": "17.6.2" + }, + "bin": { + "ng": "bin/ng.js" + }, + "engines": { + "node": "^14.20.0 || ^16.13.0 || >=18.10.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@angular/cli/node_modules/semver": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz", + "integrity": "sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@angular/common": { + "version": "15.2.10", + "resolved": "https://registry.npmjs.org/@angular/common/-/common-15.2.10.tgz", + "integrity": "sha512-jdBn3fctkqoNrJn9VLsUHpcCEhCxWSczdsR+BBbD6T0oLl6vMrAVNjPwfBejnlgfWN1KoRU9kgOYsMxa5apIWQ==", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^14.20.0 || ^16.13.0 || >=18.10.0" + }, + "peerDependencies": { + "@angular/core": "15.2.10", + "rxjs": "^6.5.3 || ^7.4.0" + } + }, + "node_modules/@angular/compiler": { + "version": "15.2.10", + "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-15.2.10.tgz", + "integrity": "sha512-M0XkeU0O73UlJZwDvOyp8/apetz9UKj78eTFDseMYJDLcxe6MpkbkxqpsGZnKYDj7LIep8PmCAKEkhtenE82zw==", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^14.20.0 || ^16.13.0 || >=18.10.0" + }, + "peerDependencies": { + "@angular/core": "15.2.10" + }, + "peerDependenciesMeta": { + "@angular/core": { + "optional": true + } + } + }, + "node_modules/@angular/compiler-cli": { + "version": "15.2.10", + "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-15.2.10.tgz", + "integrity": "sha512-mCFIxrs60XicKfA2o42hA7LrQvhybi9BQveWuZn/2iIEOXx7R62Iemz8E21pLWftAZHGxEW3NECfBrY1d3gVmA==", + "dev": true, + "dependencies": { + "@babel/core": "7.19.3", + "@jridgewell/sourcemap-codec": "^1.4.14", + "chokidar": "^3.0.0", + "convert-source-map": "^1.5.1", + "dependency-graph": "^0.11.0", + "magic-string": "^0.27.0", + "reflect-metadata": "^0.1.2", + "semver": "^7.0.0", + "tslib": "^2.3.0", + "yargs": "^17.2.1" + }, + "bin": { + "ng-xi18n": "bundles/src/bin/ng_xi18n.js", + "ngc": "bundles/src/bin/ngc.js", + "ngcc": "bundles/ngcc/main-ngcc.js" + }, + "engines": { + "node": "^14.20.0 || ^16.13.0 || >=18.10.0" + }, + "peerDependencies": { + "@angular/compiler": "15.2.10", + "typescript": ">=4.8.2 <5.0" + } + }, + "node_modules/@angular/compiler-cli/node_modules/magic-string": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.27.0.tgz", + "integrity": "sha512-8UnnX2PeRAPZuN12svgR9j7M1uWMovg/CEnIwIG0LFkXSJJe4PdfUGiTGl8V9bsBHFUtfVINcSyYxd7q+kx9fA==", + "dev": true, + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.4.13" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@angular/core": { + "version": "15.2.10", + "resolved": "https://registry.npmjs.org/@angular/core/-/core-15.2.10.tgz", + "integrity": "sha512-meGGidnitQJGDxYd9/LrqYiVlId+vGaLoiLgJdKBz+o2ZO6OmXQGuNw2VBqf17/Cc0/UjzrOY7+kILNFKkk/WQ==", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^14.20.0 || ^16.13.0 || >=18.10.0" + }, + "peerDependencies": { + "rxjs": "^6.5.3 || ^7.4.0", + "zone.js": "~0.11.4 || ~0.12.0 || ~0.13.0" + } + }, + "node_modules/@angular/forms": { + "version": "15.2.10", + "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-15.2.10.tgz", + "integrity": "sha512-NIntGsNcN6o8L1txsbWXOf6f3K/CUBizdKsxsYVYGJIXEW5qU6UnWmfAZffNNXsT/XvbgUCjgDwT0cAwcqZPuQ==", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^14.20.0 || ^16.13.0 || >=18.10.0" + }, + "peerDependencies": { + "@angular/common": "15.2.10", + "@angular/core": "15.2.10", + "@angular/platform-browser": "15.2.10", + "rxjs": "^6.5.3 || ^7.4.0" + } + }, + "node_modules/@angular/localize": { + "version": "15.2.10", + "resolved": "https://registry.npmjs.org/@angular/localize/-/localize-15.2.10.tgz", + "integrity": "sha512-RHN+mUR4H34c/LLnNPAyQbfuZME4i9JgodK5YRRX8cSAFPafYLT0SspSuLsKtcCCEDadAZNDHzb8qv5MBtzJtg==", + "dependencies": { + "@babel/core": "7.19.3", + "glob": "8.1.0", + "yargs": "^17.2.1" + }, + "bin": { + "localize-extract": "tools/bundles/src/extract/cli.js", + "localize-migrate": "tools/bundles/src/migrate/cli.js", + "localize-translate": "tools/bundles/src/translate/cli.js" + }, + "engines": { + "node": "^14.20.0 || ^16.13.0 || >=18.10.0" + }, + "peerDependencies": { + "@angular/compiler": "15.2.10", + "@angular/compiler-cli": "15.2.10" + } + }, + "node_modules/@angular/localize/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@angular/localize/node_modules/glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@angular/localize/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@angular/platform-browser": { + "version": "15.2.10", + "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-15.2.10.tgz", + "integrity": "sha512-9tbgVGSJqwfrOzT8aA/kWBLNhJSQ9gUg0CJxwFBSJm8VkBUJrszoBlDsnSvlxx8/W2ejNULKHFTXeUzq0O/+RQ==", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^14.20.0 || ^16.13.0 || >=18.10.0" + }, + "peerDependencies": { + "@angular/animations": "15.2.10", + "@angular/common": "15.2.10", + "@angular/core": "15.2.10" + }, + "peerDependenciesMeta": { + "@angular/animations": { + "optional": true + } + } + }, + "node_modules/@angular/platform-browser-dynamic": { + "version": "15.2.10", + "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-15.2.10.tgz", + "integrity": "sha512-JHP6W+FX715Qv7DhqvfZLuBZXSDJrboiQsR06gUAgDSjAUyhbqmpVg/2YOtgeWpPkzNDtXdPU2PhcRdIv5J3Yg==", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^14.20.0 || ^16.13.0 || >=18.10.0" + }, + "peerDependencies": { + "@angular/common": "15.2.10", + "@angular/compiler": "15.2.10", + "@angular/core": "15.2.10", + "@angular/platform-browser": "15.2.10" + } + }, + "node_modules/@angular/router": { + "version": "15.2.10", + "resolved": "https://registry.npmjs.org/@angular/router/-/router-15.2.10.tgz", + "integrity": "sha512-LmuqEg0iIXSw7bli6HKJ19cbxP91v37GtRwbGKswyLihqzTgvjBYpvcfMnB5FRQ5LWkTwq5JclkX03dZw290Yg==", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^14.20.0 || ^16.13.0 || >=18.10.0" + }, + "peerDependencies": { + "@angular/common": "15.2.10", + "@angular/core": "15.2.10", + "@angular/platform-browser": "15.2.10", + "rxjs": "^6.5.3 || ^7.4.0" + } + }, + "node_modules/@assemblyscript/loader": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/@assemblyscript/loader/-/loader-0.10.1.tgz", + "integrity": "sha512-H71nDOOL8Y7kWRLqf6Sums+01Q5msqBW2KhDUTemh1tvY04eSkSXrK0uj/4mmY0Xr16/3zyZmsrxN7CKuRbNRg==", + "dev": true + }, + "node_modules/@azure/msal-angular": { + "version": "2.5.4", + "resolved": "https://registry.npmjs.org/@azure/msal-angular/-/msal-angular-2.5.4.tgz", + "integrity": "sha512-BX83pkTBlVP8oEC33MmGqXYY+WYm1jl/WyVndoeO5Q8tFvlqdANVIrdsgnCW3LAXx8L4tJIDIs32E8WHManMEQ==", + "dependencies": { + "tslib": "^2.0.0" + }, + "peerDependencies": { + "@azure/msal-browser": "^2.34.0", + "rxjs": "^6.0.0 || ^7.0.0" + } + }, + "node_modules/@azure/msal-browser": { + "version": "2.34.0", + "resolved": "https://registry.npmjs.org/@azure/msal-browser/-/msal-browser-2.34.0.tgz", + "integrity": "sha512-stoXdlfAtyVIMOp1lS5PorgO5f66MGRi3Q1FBlXhVZFTsTfAWrNdSOx1m/PXWHskWE9aXO+NEzXVOoWmDNnvNA==", + "dependencies": { + "@azure/msal-common": "^11.0.0" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@azure/msal-common": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/@azure/msal-common/-/msal-common-11.0.0.tgz", + "integrity": "sha512-SZH8ObQ3Hq5v3ogVGBYJp1nNW7p+MtM4PH4wfNadBP9wf7K0beQHF9iOtRcjPOkwZf+ZD49oXqw91LndIkdk8g==", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz", + "integrity": "sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==", + "dependencies": { + "@babel/highlight": "^7.23.4", + "chalk": "^2.4.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.5.tgz", + "integrity": "sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.19.3", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.19.3.tgz", + "integrity": "sha512-WneDJxdsjEvyKtXKsaBGbDeiyOjR5vYq4HcShxnIbG0qixpoHjI3MqeZM9NDvsojNCEBItQE4juOo/bU6e72gQ==", + "dependencies": { + "@ampproject/remapping": "^2.1.0", + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.19.3", + "@babel/helper-compilation-targets": "^7.19.3", + "@babel/helper-module-transforms": "^7.19.0", + "@babel/helpers": "^7.19.0", + "@babel/parser": "^7.19.3", + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.19.3", + "@babel/types": "^7.19.3", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.1", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/@babel/generator": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.5.tgz", + "integrity": "sha512-BPssCHrBD+0YrxviOa3QzpqwhNIXKEtOa2jQrm4FlmkC2apYgRnQcmPWiGZDlGxiNtltnUFolMe8497Esry+jA==", + "dependencies": { + "@babel/types": "^7.23.5", + "@jridgewell/gen-mapping": "^0.3.2", + "@jridgewell/trace-mapping": "^0.3.17", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core/node_modules/@jridgewell/gen-mapping": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", + "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/generator": { + "version": "7.20.14", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.14.tgz", + "integrity": "sha512-AEmuXHdcD3A52HHXxaTmYlb8q/xMEhoRP67B3T4Oq7lbmSoqroMZzjnGj3+i1io3pdnF8iBYVu4Ilj+c4hBxYg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.20.7", + "@jridgewell/gen-mapping": "^0.3.2", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/generator/node_modules/@jridgewell/gen-mapping": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", + "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz", + "integrity": "sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.22.15.tgz", + "integrity": "sha512-QkBXwGgaoC2GtGZRoma6kv7Szfv06khvhFav67ZExau2RaXzy8MpHSMO2PNoP2XtmQphJQRHFfg77Bq731Yizw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.15" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.15.tgz", + "integrity": "sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw==", + "dependencies": { + "@babel/compat-data": "^7.22.9", + "@babel/helper-validator-option": "^7.22.15", + "browserslist": "^4.21.9", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" + }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.23.5.tgz", + "integrity": "sha512-QELlRWxSpgdwdJzSJn4WAhKC+hvw/AtHbbrIoncKHkhKKR/luAlKkgBDcri1EzWAo8f8VvYVryEHN4tax/V67A==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-member-expression-to-functions": "^7.23.0", + "@babel/helper-optimise-call-expression": "^7.22.5", + "@babel/helper-replace-supers": "^7.22.20", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-class-features-plugin/node_modules/@babel/helper-annotate-as-pure": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz", + "integrity": "sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-create-class-features-plugin/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.22.15.tgz", + "integrity": "sha512-29FkPLFjn4TPEa3RE7GpW+qbE8tlsu3jntNYNfcGsc49LphF1PQIiD+vMZ1z1xVOKt+93khA9tc2JBs3kBjA7w==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "regexpu-core": "^5.3.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin/node_modules/@babel/helper-annotate-as-pure": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz", + "integrity": "sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.3.tgz", + "integrity": "sha512-z5aQKU4IzbqCC1XH0nAqfsFLMVSo22SBKUc0BxGrLkolTdPTructy0ToNnlO2zA4j9Q/7pjMZf0DSY+DSTYzww==", + "dev": true, + "dependencies": { + "@babel/helper-compilation-targets": "^7.17.7", + "@babel/helper-plugin-utils": "^7.16.7", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2", + "semver": "^6.1.2" + }, + "peerDependencies": { + "@babel/core": "^7.4.0-0" + } + }, + "node_modules/@babel/helper-define-polyfill-provider/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-environment-visitor": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-function-name": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", + "dependencies": { + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-function-name/node_modules/@babel/template": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", + "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", + "dependencies": { + "@babel/code-frame": "^7.22.13", + "@babel/parser": "^7.22.15", + "@babel/types": "^7.22.15" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-hoist-variables": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.23.0.tgz", + "integrity": "sha512-6gfrPwh7OuT6gZyJZvd6WbTfrqAo7vm4xCzAXOusKqq/vWdKXphTpj5klHKNmRUU6/QRGlBsyU9mAIPaWHlqJA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.23.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz", + "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==", + "dependencies": { + "@babel/types": "^7.22.15" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz", + "integrity": "sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==", + "dependencies": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-module-imports": "^7.22.15", + "@babel/helper-simple-access": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/helper-validator-identifier": "^7.22.20" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.22.5.tgz", + "integrity": "sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-remap-async-to-generator": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.22.20.tgz", + "integrity": "sha512-pBGyV4uBqOns+0UvhsTO8qgl8hO89PmiDYv+/COyp1aeMcmfrfruz+/nCMFiYyFF/Knn0yfrC85ZzNFjembFTw==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-wrap-function": "^7.22.20" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-remap-async-to-generator/node_modules/@babel/helper-annotate-as-pure": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz", + "integrity": "sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.22.20.tgz", + "integrity": "sha512-qsW0In3dbwQUbK8kejJ4R7IHVGwHJlV6lpG6UA7a9hSa2YEiAib+N1T2kr6PEeUT+Fl7najmSOS6SmAwCHK6Tw==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-member-expression-to-functions": "^7.22.15", + "@babel/helper-optimise-call-expression": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", + "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.22.5.tgz", + "integrity": "sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz", + "integrity": "sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz", + "integrity": "sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-wrap-function": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.22.20.tgz", + "integrity": "sha512-pms/UwkOpnQe/PDAEdV/d7dVCoBbB+R4FvYoHGZz+4VPcg7RtYy2KP7S2lbuWM6FCSgob5wshfGESbC/hzNXZw==", + "dev": true, + "dependencies": { + "@babel/helper-function-name": "^7.22.5", + "@babel/template": "^7.22.15", + "@babel/types": "^7.22.19" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-wrap-function/node_modules/@babel/template": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", + "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.22.13", + "@babel/parser": "^7.22.15", + "@babel/types": "^7.22.15" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.5.tgz", + "integrity": "sha512-oO7us8FzTEsG3U6ag9MfdF1iA/7Z6dz+MtFhifZk8C8o453rGJFFWUP1t+ULM9TUIAzC9uxXEiXjOiVMyd7QPg==", + "dependencies": { + "@babel/template": "^7.22.15", + "@babel/traverse": "^7.23.5", + "@babel/types": "^7.23.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers/node_modules/@babel/template": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", + "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", + "dependencies": { + "@babel/code-frame": "^7.22.13", + "@babel/parser": "^7.22.15", + "@babel/types": "^7.22.15" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz", + "integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==", + "dependencies": { + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.5.tgz", + "integrity": "sha512-hOOqoiNXrmGdFbhgCzu6GiURxUgM27Xwd/aPuu8RfHEZPBzL1Z54okAHAQjXfcQNwvrlkAmAp4SlRTZ45vlthQ==", + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.23.3.tgz", + "integrity": "sha512-iRkKcCqb7iGnq9+3G6rZ+Ciz5VywC4XNRHe57lKM+jOeYAoR0lVqdeeDRfh0tQcTfw/+vBhHn926FmQhLtlFLQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.23.3.tgz", + "integrity": "sha512-WwlxbfMNdVEpQjZmK5mhm7oSwD3dS6eU+Iwsi4Knl9wAletWem7kaRsGOG+8UEbRyqxY4SS5zvtfXwX+jMxUwQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/plugin-transform-optional-chaining": "^7.23.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.13.0" + } + }, + "node_modules/@babel/plugin-proposal-async-generator-functions": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.20.7.tgz", + "integrity": "sha512-xMbiLsn/8RK7Wq7VeVytytS2L6qE69bXPB10YCmMdDZbKF4okCqY74pI/jJQ/8U0b/F6NrT2+14b8/P9/3AMGA==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-async-generator-functions instead.", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-remap-async-to-generator": "^7.18.9", + "@babel/plugin-syntax-async-generators": "^7.8.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-class-properties": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.18.6.tgz", + "integrity": "sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-class-properties instead.", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-class-static-block": { + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.21.0.tgz", + "integrity": "sha512-XP5G9MWNUskFuP30IfFSEFB0Z6HzLIUcjYM4bYOPHXl7eiJ9HFv8tWj6TXTN5QODiEhDZAeI4hLok2iHFFV4hw==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-class-static-block instead.", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.21.0", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/plugin-syntax-class-static-block": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0" + } + }, + "node_modules/@babel/plugin-proposal-dynamic-import": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.18.6.tgz", + "integrity": "sha512-1auuwmK+Rz13SJj36R+jqFPMJWyKEDd7lLSdOj4oJK0UTgGueSAtkrCvz9ewmgyU/P941Rv2fQwZJN8s6QruXw==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-dynamic-import instead.", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-dynamic-import": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-export-namespace-from": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.18.9.tgz", + "integrity": "sha512-k1NtHyOMvlDDFeb9G5PhUXuGj8m/wiwojgQVEhJ/fsVsMCpLyOP4h0uGEjYJKrRI+EVPlb5Jk+Gt9P97lOGwtA==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-export-namespace-from instead.", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-json-strings": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.18.6.tgz", + "integrity": "sha512-lr1peyn9kOdbYc0xr0OdHTZ5FMqS6Di+H0Fz2I/JwMzGmzJETNeOFq2pBySw6X/KFL5EWDjlJuMsUGRFb8fQgQ==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-json-strings instead.", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-json-strings": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-logical-assignment-operators": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.20.7.tgz", + "integrity": "sha512-y7C7cZgpMIjWlKE5T7eJwp+tnRYM89HmRvWM5EQuB5BoHEONjmQ8lSNmBUwOyy/GFRsohJED51YBF79hE1djug==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-logical-assignment-operators instead.", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-nullish-coalescing-operator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.18.6.tgz", + "integrity": "sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-nullish-coalescing-operator instead.", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-numeric-separator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.18.6.tgz", + "integrity": "sha512-ozlZFogPqoLm8WBr5Z8UckIoE4YQ5KESVcNudyXOR8uqIkliTEgJ3RoketfG6pmzLdeZF0H/wjE9/cCEitBl7Q==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-numeric-separator instead.", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-numeric-separator": "^7.10.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-object-rest-spread": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.20.7.tgz", + "integrity": "sha512-d2S98yCiLxDVmBmE8UjGcfPvNEUbA1U5q5WxaWFUGRzJSVAZqm5W6MbPct0jxnegUZ0niLeNX+IOzEs7wYg9Dg==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-object-rest-spread instead.", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.20.5", + "@babel/helper-compilation-targets": "^7.20.7", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.20.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-optional-catch-binding": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.18.6.tgz", + "integrity": "sha512-Q40HEhs9DJQyaZfUjjn6vE8Cv4GmMHCYuMGIWUnlxH6400VGxOuwWsPt4FxXxJkC/5eOzgn0z21M9gMT4MOhbw==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-optional-catch-binding instead.", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-optional-chaining": { + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.21.0.tgz", + "integrity": "sha512-p4zeefM72gpmEe2fkUr/OnOXpWEf8nAgk7ZYVqqfFiyIG7oFfVZcCrU64hWn5xp4tQ9LkV4bTIa5rD0KANpKNA==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-optional-chaining instead.", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0", + "@babel/plugin-syntax-optional-chaining": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-private-methods": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.18.6.tgz", + "integrity": "sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-private-methods instead.", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-private-property-in-object": { + "version": "7.21.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.11.tgz", + "integrity": "sha512-0QZ8qP/3RLDVBwBFoWAwCtgcDZJVwA5LUJRZU8x2YFfKNuFq161wK3cuGrALu5yiPu+vzwTAg/sMWVNeWeNyaw==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-private-property-in-object instead.", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-create-class-features-plugin": "^7.21.0", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-unicode-property-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.18.6.tgz", + "integrity": "sha512-2BShG/d5yoZyXZfVePH91urL5wTG6ASZU9M4o03lKK8u8UW1y08OMttBSOADTcJrnPMpvDXRG3G8fyLh4ovs8w==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-unicode-property-regex instead.", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-dynamic-import": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", + "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-export-namespace-from": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", + "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-assertions": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.23.3.tgz", + "integrity": "sha512-lPgDSU+SJLK3xmFDTV2ZRQAiM7UuUjGidwBywFavObCiZc1BeAAcMtHJKUya92hPHO+at63JJPLygilZard8jw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-arrow-functions": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.23.3.tgz", + "integrity": "sha512-NzQcQrzaQPkaEwoTm4Mhyl8jI1huEL/WWIEvudjTCMJ9aBZNpsJbMASx7EQECtQQPS/DcnFpo0FIh3LvEO9cxQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-to-generator": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.20.7.tgz", + "integrity": "sha512-Uo5gwHPT9vgnSXQxqGtpdufUiWp96gk7yiP4Mp5bm1QMkEmLXBO7PAGYbKoJ6DhAwiNkcHFBol/x5zZZkL/t0Q==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-remap-async-to-generator": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoped-functions": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.23.3.tgz", + "integrity": "sha512-vI+0sIaPIO6CNuM9Kk5VmXcMVRiOpDh7w2zZt9GXzmE/9KD70CUEVhvPR/etAeNK/FAEkhxQtXOzVF3EuRL41A==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoping": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.23.4.tgz", + "integrity": "sha512-0QqbP6B6HOh7/8iNR4CQU2Th/bbRtBp4KS9vcaZd1fZ0wSh5Fyssg0UCIHwxh+ka+pNDREbVLQnHCMHKZfPwfw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-classes": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.23.5.tgz", + "integrity": "sha512-jvOTR4nicqYC9yzOHIhXG5emiFEOpappSJAl73SDSEDcybD+Puuze8Tnpb9p9qEyYup24tq891gkaygIFvWDqg==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-compilation-targets": "^7.22.15", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-optimise-call-expression": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-replace-supers": "^7.22.20", + "@babel/helper-split-export-declaration": "^7.22.6", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-classes/node_modules/@babel/helper-annotate-as-pure": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz", + "integrity": "sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/plugin-transform-computed-properties": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.23.3.tgz", + "integrity": "sha512-dTj83UVTLw/+nbiHqQSFdwO9CbTtwq1DsDqm3CUEtDrZNET5rT5E6bIdTlOftDTDLMYxvxHNEYO4B9SLl8SLZw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/template": "^7.22.15" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-computed-properties/node_modules/@babel/template": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", + "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.22.13", + "@babel/parser": "^7.22.15", + "@babel/types": "^7.22.15" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/plugin-transform-destructuring": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.23.3.tgz", + "integrity": "sha512-n225npDqjDIr967cMScVKHXJs7rout1q+tt50inyBCPkyZ8KxeI6d+GIbSBTT/w/9WdlWDOej3V9HE5Lgk57gw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-dotall-regex": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.23.3.tgz", + "integrity": "sha512-vgnFYDHAKzFaTVp+mneDsIEbnJ2Np/9ng9iviHw3P/KVcgONxpNULEW/51Z/BaFojG2GI2GwwXck5uV1+1NOYQ==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-keys": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.23.3.tgz", + "integrity": "sha512-RrqQ+BQmU3Oyav3J+7/myfvRCq7Tbz+kKLLshUmMwNlDHExbGL7ARhajvoBJEvc+fCguPPu887N+3RRXBVKZUA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-exponentiation-operator": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.23.3.tgz", + "integrity": "sha512-5fhCsl1odX96u7ILKHBj4/Y8vipoqwsJMh4csSA8qFfxrZDEA4Ssku2DyNvMJSmZNOEBT750LfFPbtrnTP90BQ==", + "dev": true, + "dependencies": { + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-for-of": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.23.3.tgz", + "integrity": "sha512-X8jSm8X1CMwxmK878qsUGJRmbysKNbdpTv/O1/v0LuY/ZkZrng5WYiekYSdg9m09OTmDDUWeEDsTE+17WYbAZw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-function-name": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.23.3.tgz", + "integrity": "sha512-I1QXp1LxIvt8yLaib49dRW5Okt7Q4oaxao6tFVKS/anCdEOMtYwWVKoiOA1p34GOWIZjUK0E+zCp7+l1pfQyiw==", + "dev": true, + "dependencies": { + "@babel/helper-compilation-targets": "^7.22.15", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-literals": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.23.3.tgz", + "integrity": "sha512-wZ0PIXRxnwZvl9AYpqNUxpZ5BiTGrYt7kueGQ+N5FiQ7RCOD4cm8iShd6S6ggfVIWaJf2EMk8eRzAh52RfP4rQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-member-expression-literals": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.23.3.tgz", + "integrity": "sha512-sC3LdDBDi5x96LA+Ytekz2ZPk8i/Ck+DEuDbRAll5rknJ5XRTSaPKEYwomLcs1AA8wg9b3KjIQRsnApj+q51Ag==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-amd": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.23.3.tgz", + "integrity": "sha512-vJYQGxeKM4t8hYCKVBlZX/gtIY2I7mRGFNcm85sgXGMTBcoV3QdVtdpbcWEbzbfUIUZKwvgFT82mRvaQIebZzw==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.23.3.tgz", + "integrity": "sha512-aVS0F65LKsdNOtcz6FRCpE4OgsP2OFnW46qNxNIX9h3wuzaNcSQsJysuMwqSibC98HPrf2vCgtxKNwS0DAlgcA==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-simple-access": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-systemjs": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.23.3.tgz", + "integrity": "sha512-ZxyKGTkF9xT9YJuKQRo19ewf3pXpopuYQd8cDXqNzc3mUNbOME0RKMoZxviQk74hwzfQsEe66dE92MaZbdHKNQ==", + "dev": true, + "dependencies": { + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.20" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-umd": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.23.3.tgz", + "integrity": "sha512-zHsy9iXX2nIsCBFPud3jKn1IRPWg3Ing1qOZgeKV39m1ZgIdpJqvlWVeiHBZC6ITRG0MfskhYe9cLgntfSFPIg==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.22.5.tgz", + "integrity": "sha512-YgLLKmS3aUBhHaxp5hi1WJTgOUb/NCuDHzGT9z9WTt3YG+CPRhJs6nprbStx6DnWM4dh6gt7SU3sZodbZ08adQ==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-new-target": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.23.3.tgz", + "integrity": "sha512-YJ3xKqtJMAT5/TIZnpAR3I+K+WaDowYbN3xyxI8zxx/Gsypwf9B9h0VB+1Nh6ACAAPRS5NSRje0uVv5i79HYGQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-super": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.23.3.tgz", + "integrity": "sha512-BwQ8q0x2JG+3lxCVFohg+KbQM7plfpBwThdW9A6TMtWwLsbDA01Ek2Zb/AgDN39BiZsExm4qrXxjk+P1/fzGrA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-replace-supers": "^7.22.20" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-chaining": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.23.4.tgz", + "integrity": "sha512-ZU8y5zWOfjM5vZ+asjgAPwDaBjJzgufjES89Rs4Lpq63O300R/kOz30WCLo6BxxX6QVEilwSlpClnG5cZaikTA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/plugin-syntax-optional-chaining": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-parameters": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.23.3.tgz", + "integrity": "sha512-09lMt6UsUb3/34BbECKVbVwrT9bO6lILWln237z7sLaWnMsTi7Yc9fhX5DLpkJzAGfaReXI22wP41SZmnAA3Vw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-property-literals": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.23.3.tgz", + "integrity": "sha512-jR3Jn3y7cZp4oEWPFAlRsSWjxKe4PZILGBSd4nis1TsC5qeSpb+nrtihJuDhNI7QHiVbUaiXa0X2RZY3/TI6Nw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-regenerator": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.23.3.tgz", + "integrity": "sha512-KP+75h0KghBMcVpuKisx3XTu9Ncut8Q8TuvGO4IhY+9D5DFEckQefOuIsB/gQ2tG71lCke4NMrtIPS8pOj18BQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "regenerator-transform": "^0.15.2" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-reserved-words": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.23.3.tgz", + "integrity": "sha512-QnNTazY54YqgGxwIexMZva9gqbPa15t/x9VS+0fsEFWplwVpXYZivtgl43Z1vMpc1bdPP2PP8siFeVcnFvA3Cg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-runtime": { + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.19.6.tgz", + "integrity": "sha512-PRH37lz4JU156lYFW1p8OxE5i7d6Sl/zV58ooyr+q1J1lnQPyg5tIiXlIwNVhJaY4W3TmOtdc8jqdXQcB1v5Yw==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-plugin-utils": "^7.19.0", + "babel-plugin-polyfill-corejs2": "^0.3.3", + "babel-plugin-polyfill-corejs3": "^0.6.0", + "babel-plugin-polyfill-regenerator": "^0.4.1", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-runtime/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/plugin-transform-shorthand-properties": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.23.3.tgz", + "integrity": "sha512-ED2fgqZLmexWiN+YNFX26fx4gh5qHDhn1O2gvEhreLW2iI63Sqm4llRLCXALKrCnbN4Jy0VcMQZl/SAzqug/jg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-spread": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.23.3.tgz", + "integrity": "sha512-VvfVYlrlBVu+77xVTOAoxQ6mZbnIq5FM0aGBSFEcIh03qHf+zNqA4DC/3XMUozTg7bZV3e3mZQ0i13VB6v5yUg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-sticky-regex": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.23.3.tgz", + "integrity": "sha512-HZOyN9g+rtvnOU3Yh7kSxXrKbzgrm5X4GncPY1QOquu7epga5MxKHVpYu2hvQnry/H+JjckSYRb93iNfsioAGg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-template-literals": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.23.3.tgz", + "integrity": "sha512-Flok06AYNp7GV2oJPZZcP9vZdszev6vPBkHLwxwSpaIqx75wn6mUd3UFWsSsA0l8nXAKkyCmL/sR02m8RYGeHg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typeof-symbol": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.23.3.tgz", + "integrity": "sha512-4t15ViVnaFdrPC74be1gXBSMzXk3B4Us9lP7uLRQHTFpV5Dvt33pn+2MyyNxmN3VTTm3oTrZVMUmuw3oBnQ2oQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-escapes": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.23.3.tgz", + "integrity": "sha512-OMCUx/bU6ChE3r4+ZdylEqAjaQgHAgipgW8nsCfu5pGqDcFytVd91AwRvUJSBZDz0exPGgnjoqhgRYLRjFZc9Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-regex": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.23.3.tgz", + "integrity": "sha512-wMHpNA4x2cIA32b/ci3AfwNgheiva2W0WUKWTK7vBHBhDKfPsc5cFGNWm69WBqpwd86u1qwZ9PWevKqm1A3yAw==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-env": { + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.20.2.tgz", + "integrity": "sha512-1G0efQEWR1EHkKvKHqbG+IN/QdgwfByUpM5V5QroDzGV2t3S/WXNQd693cHiHTlCFMpr9B6FkPFXDA2lQcKoDg==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.20.1", + "@babel/helper-compilation-targets": "^7.20.0", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-validator-option": "^7.18.6", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.18.6", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.18.9", + "@babel/plugin-proposal-async-generator-functions": "^7.20.1", + "@babel/plugin-proposal-class-properties": "^7.18.6", + "@babel/plugin-proposal-class-static-block": "^7.18.6", + "@babel/plugin-proposal-dynamic-import": "^7.18.6", + "@babel/plugin-proposal-export-namespace-from": "^7.18.9", + "@babel/plugin-proposal-json-strings": "^7.18.6", + "@babel/plugin-proposal-logical-assignment-operators": "^7.18.9", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.18.6", + "@babel/plugin-proposal-numeric-separator": "^7.18.6", + "@babel/plugin-proposal-object-rest-spread": "^7.20.2", + "@babel/plugin-proposal-optional-catch-binding": "^7.18.6", + "@babel/plugin-proposal-optional-chaining": "^7.18.9", + "@babel/plugin-proposal-private-methods": "^7.18.6", + "@babel/plugin-proposal-private-property-in-object": "^7.18.6", + "@babel/plugin-proposal-unicode-property-regex": "^7.18.6", + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3", + "@babel/plugin-syntax-import-assertions": "^7.20.0", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5", + "@babel/plugin-transform-arrow-functions": "^7.18.6", + "@babel/plugin-transform-async-to-generator": "^7.18.6", + "@babel/plugin-transform-block-scoped-functions": "^7.18.6", + "@babel/plugin-transform-block-scoping": "^7.20.2", + "@babel/plugin-transform-classes": "^7.20.2", + "@babel/plugin-transform-computed-properties": "^7.18.9", + "@babel/plugin-transform-destructuring": "^7.20.2", + "@babel/plugin-transform-dotall-regex": "^7.18.6", + "@babel/plugin-transform-duplicate-keys": "^7.18.9", + "@babel/plugin-transform-exponentiation-operator": "^7.18.6", + "@babel/plugin-transform-for-of": "^7.18.8", + "@babel/plugin-transform-function-name": "^7.18.9", + "@babel/plugin-transform-literals": "^7.18.9", + "@babel/plugin-transform-member-expression-literals": "^7.18.6", + "@babel/plugin-transform-modules-amd": "^7.19.6", + "@babel/plugin-transform-modules-commonjs": "^7.19.6", + "@babel/plugin-transform-modules-systemjs": "^7.19.6", + "@babel/plugin-transform-modules-umd": "^7.18.6", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.19.1", + "@babel/plugin-transform-new-target": "^7.18.6", + "@babel/plugin-transform-object-super": "^7.18.6", + "@babel/plugin-transform-parameters": "^7.20.1", + "@babel/plugin-transform-property-literals": "^7.18.6", + "@babel/plugin-transform-regenerator": "^7.18.6", + "@babel/plugin-transform-reserved-words": "^7.18.6", + "@babel/plugin-transform-shorthand-properties": "^7.18.6", + "@babel/plugin-transform-spread": "^7.19.0", + "@babel/plugin-transform-sticky-regex": "^7.18.6", + "@babel/plugin-transform-template-literals": "^7.18.9", + "@babel/plugin-transform-typeof-symbol": "^7.18.9", + "@babel/plugin-transform-unicode-escapes": "^7.18.10", + "@babel/plugin-transform-unicode-regex": "^7.18.6", + "@babel/preset-modules": "^0.1.5", + "@babel/types": "^7.20.2", + "babel-plugin-polyfill-corejs2": "^0.3.3", + "babel-plugin-polyfill-corejs3": "^0.6.0", + "babel-plugin-polyfill-regenerator": "^0.4.1", + "core-js-compat": "^3.25.1", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-env/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/preset-modules": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6.tgz", + "integrity": "sha512-ID2yj6K/4lKfhuU3+EX4UvNbIt7eACFbHmNUjzA+ep+B5971CknnA/9DEWKbRokfbbtblxxxXFJJrH47UEAMVg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", + "@babel/plugin-transform-dotall-regex": "^7.4.4", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/regjsgen": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@babel/regjsgen/-/regjsgen-0.8.0.tgz", + "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==", + "dev": true + }, + "node_modules/@babel/runtime": { + "version": "7.20.13", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.20.13.tgz", + "integrity": "sha512-gt3PKXs0DBoL9xCvOIIZ2NEqAGZqHjAnmVbfQtB620V0uReIQutpel14KcneZuer7UioY8ALKZ7iocavvzTNFA==", + "dev": true, + "dependencies": { + "regenerator-runtime": "^0.13.11" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.20.7.tgz", + "integrity": "sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==", + "dependencies": { + "@babel/code-frame": "^7.18.6", + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.5.tgz", + "integrity": "sha512-czx7Xy5a6sapWWRx61m1Ke1Ra4vczu1mCTtJam5zRTBOonfdJ+S/B6HYmGYu3fJtr8GGET3si6IhgWVBhJ/m8w==", + "dependencies": { + "@babel/code-frame": "^7.23.5", + "@babel/generator": "^7.23.5", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.23.5", + "@babel/types": "^7.23.5", + "debug": "^4.1.0", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse/node_modules/@babel/generator": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.5.tgz", + "integrity": "sha512-BPssCHrBD+0YrxviOa3QzpqwhNIXKEtOa2jQrm4FlmkC2apYgRnQcmPWiGZDlGxiNtltnUFolMe8497Esry+jA==", + "dependencies": { + "@babel/types": "^7.23.5", + "@jridgewell/gen-mapping": "^0.3.2", + "@jridgewell/trace-mapping": "^0.3.17", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse/node_modules/@jridgewell/gen-mapping": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", + "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/types": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.5.tgz", + "integrity": "sha512-ON5kSOJwVO6xXVRTvOI0eOnWe7VdUcIpsovGo9U/Br4Ie4UVFQTboO2cYnDhAGU6Fp+UxSiT+pMft0SMHfuq6w==", + "dependencies": { + "@babel/helper-string-parser": "^7.23.4", + "@babel/helper-validator-identifier": "^7.22.20", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@colors/colors": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", + "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", + "dev": true, + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/@discoveryjs/json-ext": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", + "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", + "dev": true, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.17.8", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.8.tgz", + "integrity": "sha512-0/rb91GYKhrtbeglJXOhAv9RuYimgI8h623TplY2X+vA4EXnk3Zj1fXZreJ0J3OJJu1bwmb0W7g+2cT/d8/l/w==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.17.8", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.8.tgz", + "integrity": "sha512-oa/N5j6v1svZQs7EIRPqR8f+Bf8g6HBDjD/xHC02radE/NjKHK7oQmtmLxPs1iVwYyvE+Kolo6lbpfEQ9xnhxQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.17.8", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.8.tgz", + "integrity": "sha512-bTliMLqD7pTOoPg4zZkXqCDuzIUguEWLpeqkNfC41ODBHwoUgZ2w5JBeYimv4oP6TDVocoYmEhZrCLQTrH89bg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.17.8", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.8.tgz", + "integrity": "sha512-ghAbV3ia2zybEefXRRm7+lx8J/rnupZT0gp9CaGy/3iolEXkJ6LYRq4IpQVI9zR97ID80KJVoUlo3LSeA/sMAg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.17.8", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.8.tgz", + "integrity": "sha512-n5WOpyvZ9TIdv2V1K3/iIkkJeKmUpKaCTdun9buhGRWfH//osmUjlv4Z5mmWdPWind/VGcVxTHtLfLCOohsOXw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.17.8", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.8.tgz", + "integrity": "sha512-a/SATTaOhPIPFWvHZDoZYgxaZRVHn0/LX1fHLGfZ6C13JqFUZ3K6SMD6/HCtwOQ8HnsNaEeokdiDSFLuizqv5A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.17.8", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.8.tgz", + "integrity": "sha512-xpFJb08dfXr5+rZc4E+ooZmayBW6R3q59daCpKZ/cDU96/kvDM+vkYzNeTJCGd8rtO6fHWMq5Rcv/1cY6p6/0Q==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.17.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.8.tgz", + "integrity": "sha512-6Ij8gfuGszcEwZpi5jQIJCVIACLS8Tz2chnEBfYjlmMzVsfqBP1iGmHQPp7JSnZg5xxK9tjCc+pJ2WtAmPRFVA==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.17.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.8.tgz", + "integrity": "sha512-v3iwDQuDljLTxpsqQDl3fl/yihjPAyOguxuloON9kFHYwopeJEf1BkDXODzYyXEI19gisEsQlG1bM65YqKSIww==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.17.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.8.tgz", + "integrity": "sha512-8svILYKhE5XetuFk/B6raFYIyIqydQi+GngEXJgdPdI7OMKUbSd7uzR02wSY4kb53xBrClLkhH4Xs8P61Q2BaA==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.17.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.8.tgz", + "integrity": "sha512-B6FyMeRJeV0NpyEOYlm5qtQfxbdlgmiGdD+QsipzKfFky0K5HW5Td6dyK3L3ypu1eY4kOmo7wW0o94SBqlqBSA==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.17.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.8.tgz", + "integrity": "sha512-CCb67RKahNobjm/eeEqeD/oJfJlrWyw29fgiyB6vcgyq97YAf3gCOuP6qMShYSPXgnlZe/i4a8WFHBw6N8bYAA==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.17.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.8.tgz", + "integrity": "sha512-bytLJOi55y55+mGSdgwZ5qBm0K9WOCh0rx+vavVPx+gqLLhxtSFU0XbeYy/dsAAD6xECGEv4IQeFILaSS2auXw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.17.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.8.tgz", + "integrity": "sha512-2YpRyQJmKVBEHSBLa8kBAtbhucaclb6ex4wchfY0Tj3Kg39kpjeJ9vhRU7x4mUpq8ISLXRXH1L0dBYjAeqzZAw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.17.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.8.tgz", + "integrity": "sha512-QgbNY/V3IFXvNf11SS6exkpVcX0LJcob+0RWCgV9OiDAmVElnxciHIisoSix9uzYzScPmS6dJFbZULdSAEkQVw==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.17.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.8.tgz", + "integrity": "sha512-mM/9S0SbAFDBc4OPoyP6SEOo5324LpUxdpeIUUSrSTOfhHU9hEfqRngmKgqILqwx/0DVJBzeNW7HmLEWp9vcOA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.17.8", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.8.tgz", + "integrity": "sha512-eKUYcWaWTaYr9zbj8GertdVtlt1DTS1gNBWov+iQfWuWyuu59YN6gSEJvFzC5ESJ4kMcKR0uqWThKUn5o8We6Q==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.17.8", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.8.tgz", + "integrity": "sha512-Vc9J4dXOboDyMXKD0eCeW0SIeEzr8K9oTHJU+Ci1mZc5njPfhKAqkRt3B/fUNU7dP+mRyralPu8QUkiaQn7iIg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.17.8", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.8.tgz", + "integrity": "sha512-0xvOTNuPXI7ft1LYUgiaXtpCEjp90RuBBYovdd2lqAFxje4sEucurg30M1WIm03+3jxByd3mfo+VUmPtRSVuOw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.17.8", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.8.tgz", + "integrity": "sha512-G0JQwUI5WdEFEnYNKzklxtBheCPkuDdu1YrtRrjuQv30WsYbkkoixKxLLv8qhJmNI+ATEWquZe/N0d0rpr55Mg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.17.8", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.8.tgz", + "integrity": "sha512-Fqy63515xl20OHGFykjJsMnoIWS+38fqfg88ClvPXyDbLtgXal2DTlhb1TfTX34qWi3u4I7Cq563QcHpqgLx8w==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.17.8", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.8.tgz", + "integrity": "sha512-1iuezdyDNngPnz8rLRDO2C/ZZ/emJLb72OsZeqQ6gL6Avko/XCXZw+NuxBSNhBAP13Hie418V7VMt9et1FMvpg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.0.tgz", + "integrity": "sha512-UWW0TMTmk2d7hLcWD1/e2g5HDM/HQ3csaLSqXCfqwh4uNDuNqlaKWXmEsL4Cs41Z0KnILNvwbHAah3C2yt06kw==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.3.2", + "globals": "^13.15.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@eslint/eslintrc/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "13.15.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.15.0.tgz", + "integrity": "sha512-bpzcOlgDhMG070Av0Vy5Owklpv1I6+j96GhUI7Rh7IzDCKLzboflLrrfqMu8NquDbiR4EOQk7XzJwqVJxicxog==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/eslintrc/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/@eslint/eslintrc/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@eslint/eslintrc/node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@fast-csv/format": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/@fast-csv/format/-/format-4.3.5.tgz", + "integrity": "sha512-8iRn6QF3I8Ak78lNAa+Gdl5MJJBM5vRHivFtMRUWINdevNo00K7OXxS2PshawLKTejVwieIlPmK5YlLu6w4u8A==", + "dependencies": { + "@types/node": "^14.0.1", + "lodash.escaperegexp": "^4.1.2", + "lodash.isboolean": "^3.0.3", + "lodash.isequal": "^4.5.0", + "lodash.isfunction": "^3.0.9", + "lodash.isnil": "^4.0.0" + } + }, + "node_modules/@fast-csv/format/node_modules/@types/node": { + "version": "14.18.18", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.18.tgz", + "integrity": "sha512-B9EoJFjhqcQ9OmQrNorItO+OwEOORNn3S31WuiHvZY/dm9ajkB7AKD/8toessEtHHNL+58jofbq7hMMY9v4yig==" + }, + "node_modules/@fast-csv/parse": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/@fast-csv/parse/-/parse-4.3.6.tgz", + "integrity": "sha512-uRsLYksqpbDmWaSmzvJcuApSEe38+6NQZBUsuAyMZKqHxH0g1wcJgsKUvN3WC8tewaqFjBMMGrkHmC+T7k8LvA==", + "dependencies": { + "@types/node": "^14.0.1", + "lodash.escaperegexp": "^4.1.2", + "lodash.groupby": "^4.6.0", + "lodash.isfunction": "^3.0.9", + "lodash.isnil": "^4.0.0", + "lodash.isundefined": "^3.0.1", + "lodash.uniq": "^4.5.0" + } + }, + "node_modules/@fast-csv/parse/node_modules/@types/node": { + "version": "14.18.18", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.18.tgz", + "integrity": "sha512-B9EoJFjhqcQ9OmQrNorItO+OwEOORNn3S31WuiHvZY/dm9ajkB7AKD/8toessEtHHNL+58jofbq7hMMY9v4yig==" + }, + "node_modules/@gar/promisify": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz", + "integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==", + "dev": true + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.9.5", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.5.tgz", + "integrity": "sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw==", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "dev": true, + "dependencies": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", + "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", + "dependencies": { + "@jridgewell/set-array": "^1.0.0", + "@jridgewell/sourcemap-codec": "^1.4.10" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", + "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.1.tgz", + "integrity": "sha512-Ct5MqZkLGEXTVmQYbGtx9SVqD2fqwvdubdps5D3djjAkgkKwT918VNOz65pEHFaYTeWcukmJmH5SwsA9Tn2ObQ==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.5.tgz", + "integrity": "sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "node_modules/@jridgewell/source-map/node_modules/@jridgewell/gen-mapping": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", + "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.20", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz", + "integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@leichtgewicht/ip-codec": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz", + "integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==", + "dev": true + }, + "node_modules/@ng-bootstrap/ng-bootstrap": { + "version": "12.1.2", + "resolved": "https://registry.npmjs.org/@ng-bootstrap/ng-bootstrap/-/ng-bootstrap-12.1.2.tgz", + "integrity": "sha512-p27c+mYVdHiJMYrj5hwClVJxLdiZxafAqlbw1sdJh2xJ1rGOe+H/kCf5YDRbhlHqRN+34Gr0RQqIUeD1I2V8hg==", + "dependencies": { + "tslib": "^2.3.0" + }, + "peerDependencies": { + "@angular/common": "^13.0.0", + "@angular/core": "^13.0.0", + "@angular/forms": "^13.0.0", + "@angular/localize": "^13.0.0", + "@popperjs/core": "^2.10.2", + "rxjs": "^6.5.3 || ^7.4.0" + } + }, + "node_modules/@ng-idle/core": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/@ng-idle/core/-/core-11.1.0.tgz", + "integrity": "sha512-/hf3LDFz3UCTe2H6r1bq6Kn6mo5B5mxaU5XVqcDfE4Vdlx9evTqBXyl0VpWbuzZbohVCfWq31mEjbxg9lbY4bw==", + "dependencies": { + "tslib": "^2.0.0" + }, + "peerDependencies": { + "@angular/common": ">=9.0.0", + "@angular/core": ">=9.0.0" + } + }, + "node_modules/@ng-idle/keepalive": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/@ng-idle/keepalive/-/keepalive-11.0.3.tgz", + "integrity": "sha512-etnPYnDua/uaFQebDHfC40iBb22KwPVkbt24/9IJBH9A4TGZa6zBrb+8DoRiRJm8I/WBuXdCDeaWzVHElfc9pg==", + "dependencies": { + "tslib": "^2.0.0" + }, + "peerDependencies": { + "@angular/common": ">=9.0.0", + "@angular/core": ">=9.0.0", + "@ng-idle/core": "^11.0.3" + } + }, + "node_modules/@ngtools/webpack": { + "version": "15.2.11", + "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-15.2.11.tgz", + "integrity": "sha512-yqp+FziuJ+wIVij4eTqfhuiTPNaG1PU8ukeGOdqkVH4nQMlmzs9UldXy1iYC/6swzn6XO/pkqisU3m/jxemMzA==", + "dev": true, + "engines": { + "node": "^14.20.0 || ^16.13.0 || >=18.10.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "peerDependencies": { + "@angular/compiler-cli": "^15.0.0", + "typescript": ">=4.8.2 <5.0", + "webpack": "^5.54.0" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@npmcli/fs": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-3.1.0.tgz", + "integrity": "sha512-7kZUAaLscfgbwBQRbvdMYaZOWyMEcPTH/tJjnyAWJ/dvvs9Ef+CERx/qJb9GExJpl1qipaDGn7KqHnFGGixd0w==", + "dev": true, + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/git": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-4.1.0.tgz", + "integrity": "sha512-9hwoB3gStVfa0N31ymBmrX+GuDGdVA/QWShZVqE0HK2Af+7QGGrCTbZia/SW0ImUTjTne7SP91qxDmtXvDHRPQ==", + "dev": true, + "dependencies": { + "@npmcli/promise-spawn": "^6.0.0", + "lru-cache": "^7.4.4", + "npm-pick-manifest": "^8.0.0", + "proc-log": "^3.0.0", + "promise-inflight": "^1.0.1", + "promise-retry": "^2.0.1", + "semver": "^7.3.5", + "which": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/git/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/@npmcli/git/node_modules/which": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/which/-/which-3.0.1.tgz", + "integrity": "sha512-XA1b62dzQzLfaEOSQFTCOd5KFf/1VSzZo7/7TUjnya6u0vGGKzU96UQBZTAThCb2j4/xjBAyii1OhRLJEivHvg==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/installed-package-contents": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@npmcli/installed-package-contents/-/installed-package-contents-2.0.2.tgz", + "integrity": "sha512-xACzLPhnfD51GKvTOOuNX2/V4G4mz9/1I2MfDoye9kBM3RYe5g2YbscsaGoTlaWqkxeiapBWyseULVKpSVHtKQ==", + "dev": true, + "dependencies": { + "npm-bundled": "^3.0.0", + "npm-normalize-package-bin": "^3.0.0" + }, + "bin": { + "installed-package-contents": "lib/index.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/move-file": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-2.0.1.tgz", + "integrity": "sha512-mJd2Z5TjYWq/ttPLLGqArdtnC74J6bOzg4rMDnN+p1xTacZ2yPRCk2y0oSWQtygLR9YVQXgOcONrwtnk3JupxQ==", + "deprecated": "This functionality has been moved to @npmcli/fs", + "dev": true, + "dependencies": { + "mkdirp": "^1.0.4", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/@npmcli/node-gyp": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/node-gyp/-/node-gyp-3.0.0.tgz", + "integrity": "sha512-gp8pRXC2oOxu0DUE1/M3bYtb1b3/DbJ5aM113+XJBgfXdussRAsX0YOrOhdd8WvnAR6auDBvJomGAkLKA5ydxA==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/promise-spawn": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@npmcli/promise-spawn/-/promise-spawn-6.0.2.tgz", + "integrity": "sha512-gGq0NJkIGSwdbUt4yhdF8ZrmkGKVz9vAdVzpOfnom+V8PLSmSOVhZwbNvZZS1EYcJN5hzzKBxmmVVAInM6HQLg==", + "dev": true, + "dependencies": { + "which": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/promise-spawn/node_modules/which": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/which/-/which-3.0.1.tgz", + "integrity": "sha512-XA1b62dzQzLfaEOSQFTCOd5KFf/1VSzZo7/7TUjnya6u0vGGKzU96UQBZTAThCb2j4/xjBAyii1OhRLJEivHvg==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/run-script": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-6.0.2.tgz", + "integrity": "sha512-NCcr1uQo1k5U+SYlnIrbAh3cxy+OQT1VtqiAbxdymSlptbzBb62AjH2xXgjNCoP073hoa1CfCAcwoZ8k96C4nA==", + "dev": true, + "dependencies": { + "@npmcli/node-gyp": "^3.0.0", + "@npmcli/promise-spawn": "^6.0.0", + "node-gyp": "^9.0.0", + "read-package-json-fast": "^3.0.0", + "which": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/run-script/node_modules/which": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/which/-/which-3.0.1.tgz", + "integrity": "sha512-XA1b62dzQzLfaEOSQFTCOd5KFf/1VSzZo7/7TUjnya6u0vGGKzU96UQBZTAThCb2j4/xjBAyii1OhRLJEivHvg==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@popperjs/core": { + "version": "2.11.5", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.5.tgz", + "integrity": "sha512-9X2obfABZuDVLCgPK9aX0a/x4jaOEweTTWE2+9sr0Qqqevj2Uv5XorvusThmc9XGYpS9yI+fhh8RTafBtGposw==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, + "node_modules/@schematics/angular": { + "version": "15.2.10", + "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-15.2.10.tgz", + "integrity": "sha512-eLdyP+T1TueNQ8FCP7sP+tt8z+YQ1BINsJsyAyoJT/XZjcCV7LUxgDIU94/kuvIotmJ2xTuFWHFPfAY+CN3duQ==", + "dev": true, + "dependencies": { + "@angular-devkit/core": "15.2.10", + "@angular-devkit/schematics": "15.2.10", + "jsonc-parser": "3.2.0" + }, + "engines": { + "node": "^14.20.0 || ^16.13.0 || >=18.10.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@sigstore/bundle": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@sigstore/bundle/-/bundle-1.1.0.tgz", + "integrity": "sha512-PFutXEy0SmQxYI4texPw3dd2KewuNqv7OuK1ZFtY2fM754yhvG2KdgwIhRnoEE2uHdtdGNQ8s0lb94dW9sELog==", + "dev": true, + "dependencies": { + "@sigstore/protobuf-specs": "^0.2.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@sigstore/protobuf-specs": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@sigstore/protobuf-specs/-/protobuf-specs-0.2.1.tgz", + "integrity": "sha512-XTWVxnWJu+c1oCshMLwnKvz8ZQJJDVOlciMfgpJBQbThVjKTCG8dwyhgLngBD2KN0ap9F/gOV8rFDEx8uh7R2A==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@sigstore/sign": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@sigstore/sign/-/sign-1.0.0.tgz", + "integrity": "sha512-INxFVNQteLtcfGmcoldzV6Je0sbbfh9I16DM4yJPw3j5+TFP8X6uIiA18mvpEa9yyeycAKgPmOA3X9hVdVTPUA==", + "dev": true, + "dependencies": { + "@sigstore/bundle": "^1.1.0", + "@sigstore/protobuf-specs": "^0.2.0", + "make-fetch-happen": "^11.0.1" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@sigstore/sign/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/@sigstore/sign/node_modules/make-fetch-happen": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-11.1.1.tgz", + "integrity": "sha512-rLWS7GCSTcEujjVBs2YqG7Y4643u8ucvCJeSRqiLYhesrDuzeuFIk37xREzAsfQaqzl8b9rNCE4m6J8tvX4Q8w==", + "dev": true, + "dependencies": { + "agentkeepalive": "^4.2.1", + "cacache": "^17.0.0", + "http-cache-semantics": "^4.1.1", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.0", + "is-lambda": "^1.0.1", + "lru-cache": "^7.7.1", + "minipass": "^5.0.0", + "minipass-fetch": "^3.0.0", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.3", + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^7.0.0", + "ssri": "^10.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@sigstore/sign/node_modules/minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@sigstore/sign/node_modules/minipass-fetch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.4.tgz", + "integrity": "sha512-jHAqnA728uUpIaFm7NWsCnqKT6UqZz7GcI/bDpPATuwYyKwJwW0remxSCxUlKiEty+eopHGa3oc8WxgQ1FFJqg==", + "dev": true, + "dependencies": { + "minipass": "^7.0.3", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + }, + "optionalDependencies": { + "encoding": "^0.1.13" + } + }, + "node_modules/@sigstore/sign/node_modules/minipass-fetch/node_modules/minipass": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", + "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", + "dev": true, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/@sigstore/tuf": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@sigstore/tuf/-/tuf-1.0.3.tgz", + "integrity": "sha512-2bRovzs0nJZFlCN3rXirE4gwxCn97JNjMmwpecqlbgV9WcxX7WRuIrgzx/X7Ib7MYRbyUTpBYE0s2x6AmZXnlg==", + "dev": true, + "dependencies": { + "@sigstore/protobuf-specs": "^0.2.0", + "tuf-js": "^1.1.7" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@socket.io/component-emitter": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.1.tgz", + "integrity": "sha512-dzJtaDAAoXx4GCOJpbB2eG/Qj8VDpdwkLsWGzGm+0L7E8/434RyMbAHmk9ubXWVAb9nXmc44jUf8GKqVDiKezg==", + "dev": true + }, + "node_modules/@tootallnate/once": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", + "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tufjs/canonical-json": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@tufjs/canonical-json/-/canonical-json-1.0.0.tgz", + "integrity": "sha512-QTnf++uxunWvG2z3UFNzAoQPHxnSXOwtaI3iJ+AohhV+5vONuArPjJE7aPXPVXfXJsqrVbZBu9b81AJoSd09IQ==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@tufjs/models": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tufjs/models/-/models-1.0.4.tgz", + "integrity": "sha512-qaGV9ltJP0EO25YfFUPhxRVK0evXFIAGicsVXuRim4Ed9cjPxYhNnNJ49SFmbeLgtxpslIkX317IgpfcHPVj/A==", + "dev": true, + "dependencies": { + "@tufjs/canonical-json": "1.0.0", + "minimatch": "^9.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@tufjs/models/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@tufjs/models/node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@types/body-parser": { + "version": "1.19.5", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", + "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", + "dev": true, + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/bonjour": { + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.13.tgz", + "integrity": "sha512-z9fJ5Im06zvUL548KvYNecEVlA7cVDkGUi6kZusb04mpyEFKCIZJvloCcmpmLaIahDpOQGHaHmG6imtPMmPXGQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/connect-history-api-fallback": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.4.tgz", + "integrity": "sha512-n6Cr2xS1h4uAulPRdlw6Jl6s1oG8KrVilPN2yUITEs+K48EzMJJ3W1xy8K5eWuFvjp3R74AOIGSmp2UfBJ8HFw==", + "dev": true, + "dependencies": { + "@types/express-serve-static-core": "*", + "@types/node": "*" + } + }, + "node_modules/@types/cookie": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz", + "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==", + "dev": true + }, + "node_modules/@types/cors": { + "version": "2.8.17", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.17.tgz", + "integrity": "sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/eslint": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.2.tgz", + "integrity": "sha512-Z1nseZON+GEnFjJc04sv4NSALGjhFwy6K0HXt7qsn5ArfAKtb63dXNJHf+1YW6IpOIYRBGUbu3GwJdj8DGnCjA==", + "dev": true, + "dependencies": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "node_modules/@types/eslint-scope": { + "version": "3.7.3", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.3.tgz", + "integrity": "sha512-PB3ldyrcnAicT35TWPs5IcwKD8S333HMaa2VVv4+wdvebJkjWuW/xESoB8IwRcog8HYVYamb1g/R31Qv5Bx03g==", + "dev": true, + "dependencies": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "node_modules/@types/estree": { + "version": "0.0.51", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz", + "integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==", + "dev": true + }, + "node_modules/@types/events": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/events/-/events-3.0.0.tgz", + "integrity": "sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g==", + "dev": true + }, + "node_modules/@types/express": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", + "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==", + "dev": true, + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.33", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "4.17.41", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.41.tgz", + "integrity": "sha512-OaJ7XLaelTgrvlZD8/aa0vvvxZdUmlCn6MtWeB7TkiKW70BQLc9XEPpDLPdbo52ZhXUCrznlWdCHWxJWtdyajA==", + "dev": true, + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/file-saver": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@types/file-saver/-/file-saver-2.0.5.tgz", + "integrity": "sha512-zv9kNf3keYegP5oThGLaPk8E081DFDuwfqjtiTzm6PoxChdJ1raSuADf2YGCVIyrSynLrgc8JWv296s7Q7pQSQ==", + "dev": true + }, + "node_modules/@types/http-errors": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", + "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==", + "dev": true + }, + "node_modules/@types/http-proxy": { + "version": "1.17.14", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.14.tgz", + "integrity": "sha512-SSrD0c1OQzlFX7pGu1eXxSEjemej64aaNPRhhVYUGqXh0BtldAAx37MG8btcumvpgKyZp1F5Gn3JkktdxiFv6w==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/jasmine": { + "version": "3.10.6", + "resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-3.10.6.tgz", + "integrity": "sha512-twY9adK/vz72oWxCWxzXaxoDtF9TpfEEsxvbc1ibjF3gMD/RThSuSud/GKUTR3aJnfbivAbC/vLqhY+gdWCHfA==", + "dev": true + }, + "node_modules/@types/json-schema": { + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", + "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", + "dev": true + }, + "node_modules/@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", + "dev": true + }, + "node_modules/@types/mime": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", + "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", + "dev": true + }, + "node_modules/@types/node": { + "version": "12.20.52", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.52.tgz", + "integrity": "sha512-cfkwWw72849SNYp3Zx0IcIs25vABmFh73xicxhCkTcvtZQeIez15PpwQN8fY3RD7gv1Wrxlc9MEtfMORZDEsGw==", + "dev": true + }, + "node_modules/@types/node-forge": { + "version": "1.3.10", + "resolved": "https://registry.npmjs.org/@types/node-forge/-/node-forge-1.3.10.tgz", + "integrity": "sha512-y6PJDYN4xYBxwd22l+OVH35N+1fCYWiuC3aiP2SlXVE6Lo7SS+rSx9r89hLxrP4pn6n1lBGhHJ12pj3F3Mpttw==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/parse-json": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz", + "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==", + "dev": true + }, + "node_modules/@types/qs": { + "version": "6.9.10", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.10.tgz", + "integrity": "sha512-3Gnx08Ns1sEoCrWssEgTSJs/rsT2vhGP+Ja9cnnk9k4ALxinORlQneLXFeFKOTJMOeZUFD1s7w+w2AphTpvzZw==", + "dev": true + }, + "node_modules/@types/range-parser": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", + "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", + "dev": true + }, + "node_modules/@types/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", + "dev": true + }, + "node_modules/@types/send": { + "version": "0.17.4", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", + "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", + "dev": true, + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "node_modules/@types/serve-index": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.4.tgz", + "integrity": "sha512-qLpGZ/c2fhSs5gnYsQxtDEq3Oy8SXPClIXkW5ghvAvsNuVSA8k+gCONcUCS/UjLEYvYps+e8uBtfgXgvhwfNug==", + "dev": true, + "dependencies": { + "@types/express": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "1.15.5", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.5.tgz", + "integrity": "sha512-PDRk21MnK70hja/YF8AHfC7yIsiQHn1rcXx7ijCFBX/k+XQJhQT/gw3xekXKJvx+5SXaMMS8oqQy09Mzvz2TuQ==", + "dev": true, + "dependencies": { + "@types/http-errors": "*", + "@types/mime": "*", + "@types/node": "*" + } + }, + "node_modules/@types/sockjs": { + "version": "0.3.36", + "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.36.tgz", + "integrity": "sha512-MK9V6NzAS1+Ud7JV9lJLFqW85VbC9dq3LmwZCuBe4wBDgKC0Kj/jd8Xl+nSviU+Qc3+m7umHHyHg//2KSa0a0Q==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/ws": { + "version": "8.5.10", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.10.tgz", + "integrity": "sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "5.26.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.26.0.tgz", + "integrity": "sha512-n/IzU87ttzIdnAH5vQ4BBDnLPly7rC5VnjN3m0xBG82HK6rhRxnCb3w/GyWbNDghPd+NktJqB/wl6+YkzZ5T5Q==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "5.26.0", + "@typescript-eslint/types": "5.26.0", + "@typescript-eslint/typescript-estree": "5.26.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "5.26.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.26.0.tgz", + "integrity": "sha512-gVzTJUESuTwiju/7NiTb4c5oqod8xt5GhMbExKsCTp6adU3mya6AGJ4Pl9xC7x2DX9UYFsjImC0mA62BCY22Iw==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.26.0", + "@typescript-eslint/visitor-keys": "5.26.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "5.26.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.26.0.tgz", + "integrity": "sha512-8794JZFE1RN4XaExLWLI2oSXsVImNkl79PzTOOWt9h0UHROwJedNOD2IJyfL0NbddFllcktGIO2aOu10avQQyA==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "5.26.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.26.0.tgz", + "integrity": "sha512-EyGpw6eQDsfD6jIqmXP3rU5oHScZ51tL/cZgFbFBvWuCwrIptl+oueUZzSmLtxFuSOQ9vDcJIs+279gnJkfd1w==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.26.0", + "@typescript-eslint/visitor-keys": "5.26.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "5.26.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.26.0.tgz", + "integrity": "sha512-wei+ffqHanYDOQgg/fS6Hcar6wAWv0CUPQ3TZzOWd2BLfgP539rb49bwua8WRAs7R6kOSLn82rfEu2ro6Llt8Q==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.26.0", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@webassemblyjs/ast": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz", + "integrity": "sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw==", + "dev": true, + "dependencies": { + "@webassemblyjs/helper-numbers": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1" + } + }, + "node_modules/@webassemblyjs/floating-point-hex-parser": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz", + "integrity": "sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-api-error": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz", + "integrity": "sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-buffer": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz", + "integrity": "sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-numbers": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz", + "integrity": "sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ==", + "dev": true, + "dependencies": { + "@webassemblyjs/floating-point-hex-parser": "1.11.1", + "@webassemblyjs/helper-api-error": "1.11.1", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/helper-wasm-bytecode": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz", + "integrity": "sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-wasm-section": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz", + "integrity": "sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1" + } + }, + "node_modules/@webassemblyjs/ieee754": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz", + "integrity": "sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ==", + "dev": true, + "dependencies": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "node_modules/@webassemblyjs/leb128": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.1.tgz", + "integrity": "sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw==", + "dev": true, + "dependencies": { + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/utf8": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.1.tgz", + "integrity": "sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ==", + "dev": true + }, + "node_modules/@webassemblyjs/wasm-edit": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz", + "integrity": "sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/helper-wasm-section": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1", + "@webassemblyjs/wasm-opt": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1", + "@webassemblyjs/wast-printer": "1.11.1" + } + }, + "node_modules/@webassemblyjs/wasm-gen": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz", + "integrity": "sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/ieee754": "1.11.1", + "@webassemblyjs/leb128": "1.11.1", + "@webassemblyjs/utf8": "1.11.1" + } + }, + "node_modules/@webassemblyjs/wasm-opt": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz", + "integrity": "sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1" + } + }, + "node_modules/@webassemblyjs/wasm-parser": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz", + "integrity": "sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-api-error": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/ieee754": "1.11.1", + "@webassemblyjs/leb128": "1.11.1", + "@webassemblyjs/utf8": "1.11.1" + } + }, + "node_modules/@webassemblyjs/wast-printer": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz", + "integrity": "sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "dev": true + }, + "node_modules/@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "dev": true + }, + "node_modules/@yarnpkg/lockfile": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz", + "integrity": "sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==", + "dev": true + }, + "node_modules/abab": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", + "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==", + "deprecated": "Use your platform's native atob() and btoa() methods instead", + "dev": true + }, + "node_modules/abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "dev": true + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dev": true, + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.7.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.1.tgz", + "integrity": "sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-import-assertions": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz", + "integrity": "sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==", + "dev": true, + "peerDependencies": { + "acorn": "^8" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/adjust-sourcemap-loader": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/adjust-sourcemap-loader/-/adjust-sourcemap-loader-4.0.0.tgz", + "integrity": "sha512-OXwN5b9pCUXNQHJpwwD2qP40byEmSgzj8B4ydSN0uMNYWiFmJ6x6KwUllMmfk8Rwu/HJDFR7U8ubsWBoN0Xp0A==", + "dev": true, + "dependencies": { + "loader-utils": "^2.0.0", + "regex-parser": "^2.2.11" + }, + "engines": { + "node": ">=8.9" + } + }, + "node_modules/adjust-sourcemap-loader/node_modules/loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "dev": true, + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/adler-32": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/adler-32/-/adler-32-1.3.1.tgz", + "integrity": "sha512-ynZ4w/nUUv5rrsR8UUGoe1VC9hZj6V5hU9Qw1HlMDJGEJw5S7TfTErWTjMys6M7vr0YWcPqs3qAr4ss0nDfP+A==", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/agentkeepalive": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.5.0.tgz", + "integrity": "sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew==", + "dev": true, + "dependencies": { + "humanize-ms": "^1.2.1" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "dev": true, + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "dev": true, + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/ansi-colors": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-html-community": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", + "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==", + "dev": true, + "engines": [ + "node >= 0.8.0" + ], + "bin": { + "ansi-html": "bin/ansi-html" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/aproba": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", + "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", + "dev": true + }, + "node_modules/archiver": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/archiver/-/archiver-5.3.1.tgz", + "integrity": "sha512-8KyabkmbYrH+9ibcTScQ1xCJC/CGcugdVIwB+53f5sZziXgwUh3iXlAlANMxcZyDEfTHMe6+Z5FofV8nopXP7w==", + "dependencies": { + "archiver-utils": "^2.1.0", + "async": "^3.2.3", + "buffer-crc32": "^0.2.1", + "readable-stream": "^3.6.0", + "readdir-glob": "^1.0.0", + "tar-stream": "^2.2.0", + "zip-stream": "^4.1.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/archiver-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-2.1.0.tgz", + "integrity": "sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw==", + "dependencies": { + "glob": "^7.1.4", + "graceful-fs": "^4.2.0", + "lazystream": "^1.0.0", + "lodash.defaults": "^4.2.0", + "lodash.difference": "^4.5.0", + "lodash.flatten": "^4.4.0", + "lodash.isplainobject": "^4.0.6", + "lodash.union": "^4.6.0", + "normalize-path": "^3.0.0", + "readable-stream": "^2.0.0" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/archiver-utils/node_modules/readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/archiver-utils/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/are-we-there-yet": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz", + "integrity": "sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==", + "dev": true, + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/array-flatten": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz", + "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==", + "dev": true + }, + "node_modules/array-includes": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.5.tgz", + "integrity": "sha512-iSDYZMMyTPkiFasVqfuAQnWAYcvO/SeBSCGKePoEthjp4LEMTe4uLc7b025o4jAZpHhihh8xPo99TNWUWWkGDQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.19.5", + "get-intrinsic": "^1.1.1", + "is-string": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flat": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.0.tgz", + "integrity": "sha512-12IUEkHsAhA4DY5s0FPgNXIdc8VRSqD9Zp78a5au9abH/SOBrsp082JOWFNTjkMozh8mqcdiKuaLGhPeYztxSw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.2", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/async": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.3.tgz", + "integrity": "sha512-spZRyzKL5l5BZQrr/6m/SqFdBN0q3OCI0f9rjfBzCMBIP4p75P620rR3gTmaksNOhmzgdxcaxdNfMy6anrbM0g==" + }, + "node_modules/autoprefixer": { + "version": "10.4.13", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.13.tgz", + "integrity": "sha512-49vKpMqcZYsJjwotvt4+h/BCjJVnhGwcLpDt5xkcaOG3eLrG/HUYLagrihYsQ+qrIBgIzX1Rw7a6L8I/ZA1Atg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + } + ], + "dependencies": { + "browserslist": "^4.21.4", + "caniuse-lite": "^1.0.30001426", + "fraction.js": "^4.2.0", + "normalize-range": "^0.1.2", + "picocolors": "^1.0.0", + "postcss-value-parser": "^4.2.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/babel-loader": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-9.1.2.tgz", + "integrity": "sha512-mN14niXW43tddohGl8HPu5yfQq70iUThvFL/4QzESA7GcZoC0eVOhvWdQ8+3UlSjaDE9MVtsW9mxDY07W7VpVA==", + "dev": true, + "dependencies": { + "find-cache-dir": "^3.3.2", + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 14.15.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0", + "webpack": ">=5" + } + }, + "node_modules/babel-plugin-istanbul": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", + "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^5.0.4", + "test-exclude": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-polyfill-corejs2": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.3.tgz", + "integrity": "sha512-8hOdmFYFSZhqg2C/JgLUQ+t52o5nirNwaWM2B9LWteozwIvM14VSwdsCAUET10qT+kmySAlseadmfeeSWFCy+Q==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.17.7", + "@babel/helper-define-polyfill-provider": "^0.3.3", + "semver": "^6.1.1" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/babel-plugin-polyfill-corejs2/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.6.0.tgz", + "integrity": "sha512-+eHqR6OPcBhJOGgsIar7xoAB1GcSwVUA3XjAd7HJNzOXT4wv6/H7KIdA/Nc60cvUlDbKApmqNvD1B1bzOt4nyA==", + "dev": true, + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.3.3", + "core-js-compat": "^3.25.1" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/babel-plugin-polyfill-regenerator": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.4.1.tgz", + "integrity": "sha512-NtQGmyQDXjQqQ+IzRkBVwEOz9lQ4zxAQZgoAYEtU9dJjnl1Oc98qnN7jcp+bE7O7aYzVpavXE3/VKXNzUbh7aw==", + "dev": true, + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.3.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/base64id": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", + "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==", + "dev": true, + "engines": { + "node": "^4.5.0 || >= 5.9" + } + }, + "node_modules/batch": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", + "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==", + "dev": true + }, + "node_modules/big-integer": { + "version": "1.6.51", + "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz", + "integrity": "sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/binary": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/binary/-/binary-0.3.0.tgz", + "integrity": "sha512-D4H1y5KYwpJgK8wk1Cue5LLPgmwHKYSChkbspQg5JtVuR5ulGckxfR62H3AE9UDkdMC8yyXlqYihuz3Aqg2XZg==", + "dependencies": { + "buffers": "~0.1.1", + "chainsaw": "~0.1.0" + }, + "engines": { + "node": "*" + } + }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/bluebird": { + "version": "3.4.7", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.4.7.tgz", + "integrity": "sha512-iD3898SR7sWVRHbiQv+sHUtHnMvC1o3nW5rAcqnq3uOn07DSAppZYUkIGslDz6gXC7HfunPe7YVBgoEJASPcHA==" + }, + "node_modules/body-parser": { + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", + "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", + "dev": true, + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/body-parser/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/body-parser/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "node_modules/bonjour-service": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.1.1.tgz", + "integrity": "sha512-Z/5lQRMOG9k7W+FkeGTNjh7htqn/2LMnfOvBZ8pynNZCM9MwkQkI3zeI4oz09uWdcgmgHugVvBqxGg4VQJ5PCg==", + "dev": true, + "dependencies": { + "array-flatten": "^2.1.2", + "dns-equal": "^1.0.0", + "fast-deep-equal": "^3.1.3", + "multicast-dns": "^7.2.5" + } + }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "dev": true + }, + "node_modules/bootstrap": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.1.3.tgz", + "integrity": "sha512-fcQztozJ8jToQWXxVuEyXWW+dSo8AiXWKwiSSrKWsRB/Qt+Ewwza+JWoLKiTuQLaEPhdNAJ7+Dosc9DOIqNy7Q==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/bootstrap" + }, + "peerDependencies": { + "@popperjs/core": "^2.10.2" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.22.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.2.tgz", + "integrity": "sha512-0UgcrvQmBDvZHFGdYUehrCNIazki7/lUP3kkoi/r3YB2amZbFM9J43ZRkJTXBUZK4gmx56+Sqk9+Vs9mwZx9+A==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001565", + "electron-to-chromium": "^1.4.601", + "node-releases": "^2.0.14", + "update-browserslist-db": "^1.0.13" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", + "engines": { + "node": "*" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "node_modules/buffer-indexof-polyfill": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/buffer-indexof-polyfill/-/buffer-indexof-polyfill-1.0.2.tgz", + "integrity": "sha512-I7wzHwA3t1/lwXQh+A5PbNvJxgfo5r3xulgpYDB5zckTu/Z9oUK9biouBKQUjEqzaz3HnAT6TYoovmE+GqSf7A==", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/buffers": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/buffers/-/buffers-0.1.1.tgz", + "integrity": "sha512-9q/rDEGSb/Qsvv2qvzIzdluL5k7AaJOTrw23z9reQthrbF7is4CtlT0DXyO1oei2DCp4uojjzQ7igaSHp1kAEQ==", + "engines": { + "node": ">=0.2.0" + } + }, + "node_modules/builtins": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/builtins/-/builtins-5.0.1.tgz", + "integrity": "sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ==", + "dev": true, + "dependencies": { + "semver": "^7.0.0" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/cacache": { + "version": "17.0.4", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-17.0.4.tgz", + "integrity": "sha512-Z/nL3gU+zTUjz5pCA5vVjYM8pmaw2kxM7JEiE0fv3w77Wj+sFbi70CrBruUWH0uNcEdvLDixFpgA2JM4F4DBjA==", + "dev": true, + "dependencies": { + "@npmcli/fs": "^3.1.0", + "fs-minipass": "^3.0.0", + "glob": "^8.0.1", + "lru-cache": "^7.7.1", + "minipass": "^4.0.0", + "minipass-collect": "^1.0.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "p-map": "^4.0.0", + "promise-inflight": "^1.0.1", + "ssri": "^10.0.0", + "tar": "^6.1.11", + "unique-filename": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/cacache/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/cacache/node_modules/glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/cacache/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/cacache/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001566", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001566.tgz", + "integrity": "sha512-ggIhCsTxmITBAMmK8yZjEhCO5/47jKXPu6Dha/wuCS4JePVL+3uiDEBuhu2aIoT+bqTOR8L76Ip1ARL9xYsEJA==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ] + }, + "node_modules/cfb": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cfb/-/cfb-1.2.2.tgz", + "integrity": "sha512-KfdUZsSOw19/ObEWasvBP/Ac4reZvAGauZhs6S/gqNhXhI7cKwvlH7ulj+dOEYnca4bm4SGo8C1bTAQvnTjgQA==", + "dependencies": { + "adler-32": "~1.3.0", + "crc-32": "~1.2.0" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/chainsaw": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/chainsaw/-/chainsaw-0.1.0.tgz", + "integrity": "sha512-75kWfWt6MEKNC8xYXIdRpDehRYY/tNSgwKaJq+dbbDcxORuVrrQ+SEHoWsniVn9XPYfP4gmdWIeDk/4YNp1rNQ==", + "dependencies": { + "traverse": ">=0.3.0 <0.4" + }, + "engines": { + "node": "*" + } + }, + "node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "dev": true + }, + "node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/chrome-trace-event": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", + "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", + "dev": true, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, + "dependencies": { + "restore-cursor": "^3.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-spinners": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.6.1.tgz", + "integrity": "sha512-x/5fWmGMnbKQAaNwN+UZlV79qBLM9JFnJuJ03gIi5whrob0xV0ofNVHy9DhwGdsMJQc2OKv0oGmLzvaqvAVv+g==", + "dev": true, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-width": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", + "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", + "dev": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/codepage": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/codepage/-/codepage-1.15.0.tgz", + "integrity": "sha512-3g6NUTPd/YtuuGrhMnOMRjFc+LJw/bnMp3+0r/Wcz3IXUuCosKRJvMphm5+Q+bvTVGcJJuRvVLuYba+WojaFaA==", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "node_modules/color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "dev": true, + "bin": { + "color-support": "bin.js" + } + }, + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "dev": true + }, + "node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "node_modules/commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", + "dev": true + }, + "node_modules/compress-commons": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-4.1.1.tgz", + "integrity": "sha512-QLdDLCKNV2dtoTorqgxngQCMA+gWXkM/Nwu7FpeBhk/RdkzimqC3jueb/FDmaZeXh+uby1jkBqE3xArsLBE5wQ==", + "dependencies": { + "buffer-crc32": "^0.2.13", + "crc32-stream": "^4.0.2", + "normalize-path": "^3.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "dev": true, + "dependencies": { + "mime-db": ">= 1.43.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/compression": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", + "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", + "dev": true, + "dependencies": { + "accepts": "~1.3.5", + "bytes": "3.0.0", + "compressible": "~2.0.16", + "debug": "2.6.9", + "on-headers": "~1.0.2", + "safe-buffer": "5.1.2", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/compression/node_modules/bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/compression/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/compression/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "node_modules/connect": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz", + "integrity": "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==", + "dev": true, + "dependencies": { + "debug": "2.6.9", + "finalhandler": "1.1.2", + "parseurl": "~1.3.3", + "utils-merge": "1.0.1" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/connect-history-api-fallback": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", + "integrity": "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==", + "dev": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/connect/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/connect/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "node_modules/console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", + "dev": true + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dev": true, + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-disposition/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/convert-source-map": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", + "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", + "dependencies": { + "safe-buffer": "~5.1.1" + } + }, + "node_modules/cookie": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", + "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", + "dev": true + }, + "node_modules/copy-anything": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-2.0.6.tgz", + "integrity": "sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==", + "dev": true, + "dependencies": { + "is-what": "^3.14.1" + }, + "funding": { + "url": "https://github.com/sponsors/mesqueeb" + } + }, + "node_modules/copy-webpack-plugin": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-11.0.0.tgz", + "integrity": "sha512-fX2MWpamkW0hZxMEg0+mYnA40LTosOSa5TqZ9GYIBzyJa9C3QUaMPSE2xAi/buNr8u89SfD9wHSQVBzrRa/SOQ==", + "dev": true, + "dependencies": { + "fast-glob": "^3.2.11", + "glob-parent": "^6.0.1", + "globby": "^13.1.1", + "normalize-path": "^3.0.0", + "schema-utils": "^4.0.0", + "serialize-javascript": "^6.0.0" + }, + "engines": { + "node": ">= 14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + } + }, + "node_modules/copy-webpack-plugin/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/core-js-compat": { + "version": "3.34.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.34.0.tgz", + "integrity": "sha512-4ZIyeNbW/Cn1wkMMDy+mvrRUxrwFNjKwbhCfQpDd+eLgYipDqp8oGFGtLmhh18EDPKA0g3VUBYOxQGGwvWLVpA==", + "dev": true, + "dependencies": { + "browserslist": "^4.22.2" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" + }, + "node_modules/cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "dev": true, + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/cosmiconfig": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", + "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", + "dev": true, + "dependencies": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/crc-32": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", + "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", + "bin": { + "crc32": "bin/crc32.njs" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/crc32-stream": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-4.0.2.tgz", + "integrity": "sha512-DxFZ/Hk473b/muq1VJ///PMNLj0ZMnzye9thBpmjpJKCc5eMgB95aK8zCGrGfQ90cWo561Te6HK9D+j4KPdM6w==", + "dependencies": { + "crc-32": "^1.2.0", + "readable-stream": "^3.4.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/critters": { + "version": "0.0.16", + "resolved": "https://registry.npmjs.org/critters/-/critters-0.0.16.tgz", + "integrity": "sha512-JwjgmO6i3y6RWtLYmXwO5jMd+maZt8Tnfu7VVISmEWyQqfLpB8soBswf8/2bu6SBXxtKA68Al3c+qIG1ApT68A==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "css-select": "^4.2.0", + "parse5": "^6.0.1", + "parse5-htmlparser2-tree-adapter": "^6.0.1", + "postcss": "^8.3.7", + "pretty-bytes": "^5.3.0" + } + }, + "node_modules/critters/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/critters/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/critters/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/critters/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/critters/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/critters/node_modules/parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", + "dev": true + }, + "node_modules/critters/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/cross-spawn/node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/css-loader": { + "version": "6.7.3", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.7.3.tgz", + "integrity": "sha512-qhOH1KlBMnZP8FzRO6YCH9UHXQhVMcEGLyNdb7Hv2cpcmJbW0YrddO+tG1ab5nT41KpHIYGsbeHqxB9xPu1pKQ==", + "dev": true, + "dependencies": { + "icss-utils": "^5.1.0", + "postcss": "^8.4.19", + "postcss-modules-extract-imports": "^3.0.0", + "postcss-modules-local-by-default": "^4.0.0", + "postcss-modules-scope": "^3.0.0", + "postcss-modules-values": "^4.0.0", + "postcss-value-parser": "^4.2.0", + "semver": "^7.3.8" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + } + }, + "node_modules/css-select": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", + "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.0.1", + "domhandler": "^4.3.1", + "domutils": "^2.8.0", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-what": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", + "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", + "dev": true, + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true, + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/custom-event": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/custom-event/-/custom-event-1.0.1.tgz", + "integrity": "sha1-XQKkaFCt8bSjF5RqOSj8y1v9BCU=", + "dev": true + }, + "node_modules/date-format": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/date-format/-/date-format-4.0.10.tgz", + "integrity": "sha512-RuMIHocrVjF84bUSTcd1uokIsLsOsk1Awb7TexNOI3f48ukCu39mjslWquDTA08VaDMF2umr3MB9ow5EyJTWyA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/dayjs": { + "version": "1.11.2", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.2.tgz", + "integrity": "sha512-F4LXf1OeU9hrSYRPTTj/6FbO4HTjPKXvEIC1P2kcnFurViINCVk3ZV0xAS3XVx9MkMsXbbqlK6hjseaYbgKEHw==" + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "node_modules/default-gateway": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz", + "integrity": "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==", + "dev": true, + "dependencies": { + "execa": "^5.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/defaults": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz", + "integrity": "sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=", + "dev": true, + "dependencies": { + "clone": "^1.0.2" + } + }, + "node_modules/define-lazy-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", + "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/define-properties": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz", + "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==", + "dev": true, + "dependencies": { + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", + "dev": true + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/dependency-graph": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/dependency-graph/-/dependency-graph-0.11.0.tgz", + "integrity": "sha512-JeMq7fEshyepOWDfcfHK06N3MhyPhz++vtqWhMT5O9A3K42rdsEDpfdVqjaqaAhsw6a+ZqeDvQVtD0hFHQWrzg==", + "dev": true, + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "dev": true, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/detect-node": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", + "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", + "dev": true + }, + "node_modules/di": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/di/-/di-0.0.1.tgz", + "integrity": "sha1-gGZJMmzqp8qjMG112YXqJ0i6kTw=", + "dev": true + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/dns-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz", + "integrity": "sha512-z+paD6YUQsk+AbGCEM4PrOXSss5gd66QfcVBFTKR/HpFL9jCqikS94HYwKww6fQyO7IxrIIyUu+g0Ka9tUS2Cg==", + "dev": true + }, + "node_modules/dns-packet": { + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.1.tgz", + "integrity": "sha512-l4gcSouhcgIKRvyy99RNVOgxXiicE+2jZoNmaNmZ6JXiGajBOJAesk1OBlJuM5k2c+eudGdLxDqXuPCKIj6kpw==", + "dev": true, + "dependencies": { + "@leichtgewicht/ip-codec": "^2.0.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/dom-serialize": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/dom-serialize/-/dom-serialize-2.2.1.tgz", + "integrity": "sha1-ViromZ9Evl6jB29UGdzVnrQ6yVs=", + "dev": true, + "dependencies": { + "custom-event": "~1.0.0", + "ent": "~2.2.0", + "extend": "^3.0.0", + "void-elements": "^2.0.0" + } + }, + "node_modules/dom-serializer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", + "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", + "dev": true, + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ] + }, + "node_modules/domhandler": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", + "dev": true, + "dependencies": { + "domelementtype": "^2.2.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "dev": true, + "dependencies": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/duplexer2": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", + "integrity": "sha1-ixLauHjA1p4+eJEFFmKjL8a93ME=", + "dependencies": { + "readable-stream": "^2.0.2" + } + }, + "node_modules/duplexer2/node_modules/readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/duplexer2/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=", + "dev": true + }, + "node_modules/electron-to-chromium": { + "version": "1.4.608", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.608.tgz", + "integrity": "sha512-J2f/3iIIm3Mo0npneITZ2UPe4B1bg8fTNrFjD8715F/k1BvbviRuqYGkET1PgprrczXYTHFvotbBOmUp6KE0uA==" + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "node_modules/emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/encoding": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", + "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "dev": true, + "optional": true, + "dependencies": { + "iconv-lite": "^0.6.2" + } + }, + "node_modules/encoding/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "optional": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/engine.io": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.5.4.tgz", + "integrity": "sha512-KdVSDKhVKyOi+r5uEabrDLZw2qXStVvCsEB/LN3mw4WFi6Gx50jTyuxYVCwAAC0U46FdnzP/ScKRBTXb/NiEOg==", + "dev": true, + "dependencies": { + "@types/cookie": "^0.4.1", + "@types/cors": "^2.8.12", + "@types/node": ">=10.0.0", + "accepts": "~1.3.4", + "base64id": "2.0.0", + "cookie": "~0.4.1", + "cors": "~2.8.5", + "debug": "~4.3.1", + "engine.io-parser": "~5.2.1", + "ws": "~8.11.0" + }, + "engines": { + "node": ">=10.2.0" + } + }, + "node_modules/engine.io-parser": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.2.tgz", + "integrity": "sha512-RcyUFKA93/CXH20l4SoVvzZfrSDMOTUS3bWVpTt2FuFP+XYrL8i8oonHP7WInRyVHXh0n/ORtoeiE1os+8qkSw==", + "dev": true, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/enhanced-resolve": { + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz", + "integrity": "sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/ent": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz", + "integrity": "sha1-6WQhkyWiHQX0RGai9obtbOX13R0=", + "dev": true + }, + "node_modules/entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "dev": true, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/err-code": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", + "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", + "dev": true + }, + "node_modules/errno": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz", + "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==", + "dev": true, + "optional": true, + "dependencies": { + "prr": "~1.0.1" + }, + "bin": { + "errno": "cli.js" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-abstract": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.1.tgz", + "integrity": "sha512-WEm2oBhfoI2sImeM4OF2zE2V3BYdSF+KnSi9Sidz51fQHd7+JuF8Xgcj9/0o+OWeIeIS/MiuNnlruQrJf16GQA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "function.prototype.name": "^1.1.5", + "get-intrinsic": "^1.1.1", + "get-symbol-description": "^1.0.0", + "has": "^1.0.3", + "has-property-descriptors": "^1.0.0", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.3", + "is-callable": "^1.2.4", + "is-negative-zero": "^2.0.2", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "is-string": "^1.0.7", + "is-weakref": "^1.0.2", + "object-inspect": "^1.12.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.2", + "regexp.prototype.flags": "^1.4.3", + "string.prototype.trimend": "^1.0.5", + "string.prototype.trimstart": "^1.0.5", + "unbox-primitive": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-module-lexer": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz", + "integrity": "sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==", + "dev": true + }, + "node_modules/es-shim-unscopables": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", + "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==", + "dev": true, + "dependencies": { + "has": "^1.0.3" + } + }, + "node_modules/es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/esbuild": { + "version": "0.17.8", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.8.tgz", + "integrity": "sha512-g24ybC3fWhZddZK6R3uD2iF/RIPnRpwJAqLov6ouX3hMbY4+tKolP0VMF3zuIYCaXun+yHwS5IPQ91N2BT191g==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/android-arm": "0.17.8", + "@esbuild/android-arm64": "0.17.8", + "@esbuild/android-x64": "0.17.8", + "@esbuild/darwin-arm64": "0.17.8", + "@esbuild/darwin-x64": "0.17.8", + "@esbuild/freebsd-arm64": "0.17.8", + "@esbuild/freebsd-x64": "0.17.8", + "@esbuild/linux-arm": "0.17.8", + "@esbuild/linux-arm64": "0.17.8", + "@esbuild/linux-ia32": "0.17.8", + "@esbuild/linux-loong64": "0.17.8", + "@esbuild/linux-mips64el": "0.17.8", + "@esbuild/linux-ppc64": "0.17.8", + "@esbuild/linux-riscv64": "0.17.8", + "@esbuild/linux-s390x": "0.17.8", + "@esbuild/linux-x64": "0.17.8", + "@esbuild/netbsd-x64": "0.17.8", + "@esbuild/openbsd-x64": "0.17.8", + "@esbuild/sunos-x64": "0.17.8", + "@esbuild/win32-arm64": "0.17.8", + "@esbuild/win32-ia32": "0.17.8", + "@esbuild/win32-x64": "0.17.8" + } + }, + "node_modules/esbuild-wasm": { + "version": "0.17.8", + "resolved": "https://registry.npmjs.org/esbuild-wasm/-/esbuild-wasm-0.17.8.tgz", + "integrity": "sha512-zCmpxv95E0FuCmvdw1K836UHnj4EdiQnFfjTby35y3LAjRPtXMj3sbHDRHjbD8Mqg5lTwq3knacr/1qIFU51CQ==", + "dev": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=", + "dev": true + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/eslint": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.16.0.tgz", + "integrity": "sha512-MBndsoXY/PeVTDJeWsYj7kLZ5hQpJOfMYLsF6LicLHQWbRDG19lK5jOix4DPl8yY4SUFcE3txy86OzFLWT+yoA==", + "dev": true, + "dependencies": { + "@eslint/eslintrc": "^1.3.0", + "@humanwhocodes/config-array": "^0.9.2", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.1.1", + "eslint-utils": "^3.0.0", + "eslint-visitor-keys": "^3.3.0", + "espree": "^9.3.2", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^6.0.1", + "globals": "^13.15.0", + "ignore": "^5.2.0", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "regexpp": "^3.2.0", + "strip-ansi": "^6.0.1", + "strip-json-comments": "^3.1.0", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-import-resolver-node": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz", + "integrity": "sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==", + "dev": true, + "dependencies": { + "debug": "^3.2.7", + "resolve": "^1.20.0" + } + }, + "node_modules/eslint-import-resolver-node/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-import-resolver-typescript": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-2.7.1.tgz", + "integrity": "sha512-00UbgGwV8bSgUv34igBDbTOtKhqoRMy9bFjNehT40bXg6585PNIct8HhXZ0SybqB9rWtXj9crcku8ndDn/gIqQ==", + "dev": true, + "dependencies": { + "debug": "^4.3.4", + "glob": "^7.2.0", + "is-glob": "^4.0.3", + "resolve": "^1.22.0", + "tsconfig-paths": "^3.14.1" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "*", + "eslint-plugin-import": "*" + } + }, + "node_modules/eslint-module-utils": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.3.tgz", + "integrity": "sha512-088JEC7O3lDZM9xGe0RerkOMd0EjFl+Yvd1jPWIkMT5u3H9+HC34mWWPnqPrN13gieT9pBOO+Qt07Nb/6TresQ==", + "dev": true, + "dependencies": { + "debug": "^3.2.7", + "find-up": "^2.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-module-utils/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-module-utils/node_modules/find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "dependencies": { + "locate-path": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-module-utils/node_modules/locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "dependencies": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-module-utils/node_modules/p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "dependencies": { + "p-try": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-module-utils/node_modules/p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "dependencies": { + "p-limit": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-module-utils/node_modules/p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-module-utils/node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-plugin-import": { + "version": "2.26.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.26.0.tgz", + "integrity": "sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.4", + "array.prototype.flat": "^1.2.5", + "debug": "^2.6.9", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.6", + "eslint-module-utils": "^2.7.3", + "has": "^1.0.3", + "is-core-module": "^2.8.1", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.values": "^1.1.5", + "resolve": "^1.22.0", + "tsconfig-paths": "^3.14.1" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" + } + }, + "node_modules/eslint-plugin-import/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/eslint-plugin-import/node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-import/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/eslint-plugin-import/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/eslint-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^2.0.0" + }, + "engines": { + "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=5" + } + }, + "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/eslint/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/eslint/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/eslint/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/eslint/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/eslint/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/eslint/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/eslint/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/eslint-scope": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", + "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/eslint/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/eslint/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/eslint/node_modules/globals": { + "version": "13.15.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.15.0.tgz", + "integrity": "sha512-bpzcOlgDhMG070Av0Vy5Owklpv1I6+j96GhUI7Rh7IzDCKLzboflLrrfqMu8NquDbiR4EOQk7XzJwqVJxicxog==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/eslint/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/eslint/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/eslint/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/espree": { + "version": "9.3.2", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.3.2.tgz", + "integrity": "sha512-D211tC7ZwouTIuY5x9XnS0E9sWNChB7IYKX/Xp5eQj3nFXhqmiUDB9q27y76oFl8jTg3pXcQx/bpxMfs3CIZbA==", + "dev": true, + "dependencies": { + "acorn": "^8.7.1", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esquery": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esquery/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/eventemitter-asyncresource": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/eventemitter-asyncresource/-/eventemitter-asyncresource-1.0.0.tgz", + "integrity": "sha512-39F7TBIV0G7gTelxwbEqnwhp90eqCPON1k0NwNfwhgKn4Co4ybUbj2pECcXT0B3ztRKZ7Pw1JujUUgmQJHcVAQ==", + "dev": true + }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "dev": true + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true, + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/exceljs": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/exceljs/-/exceljs-4.3.0.tgz", + "integrity": "sha512-hTAeo5b5TPvf8Z02I2sKIT4kSfCnOO2bCxYX8ABqODCdAjppI3gI9VYiGCQQYVcBaBSKlFDMKlAQRqC+kV9O8w==", + "dependencies": { + "archiver": "^5.0.0", + "dayjs": "^1.8.34", + "fast-csv": "^4.3.1", + "jszip": "^3.5.0", + "readable-stream": "^3.6.0", + "saxes": "^5.0.1", + "tmp": "^0.2.0", + "unzipper": "^0.10.11", + "uuid": "^8.3.0" + }, + "engines": { + "node": ">=8.3.0" + } + }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/exponential-backoff": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.1.tgz", + "integrity": "sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw==", + "dev": true + }, + "node_modules/express": { + "version": "4.19.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", + "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", + "dev": true, + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.2", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.6.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.11.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/express/node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "dev": true + }, + "node_modules/express/node_modules/cookie": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/express/node_modules/finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "dev": true, + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/express/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/express/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/express/node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true + }, + "node_modules/external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "dev": true, + "dependencies": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/external-editor/node_modules/tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "dependencies": { + "os-tmpdir": "~1.0.2" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/fast-csv": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/fast-csv/-/fast-csv-4.3.6.tgz", + "integrity": "sha512-2RNSpuwwsJGP0frGsOmTb9oUF+VkFSM4SyLTDgwf2ciHWTarN0lQTC+F2f/t5J9QjW+c65VFIAAu85GsvMIusw==", + "dependencies": { + "@fast-csv/format": "4.3.5", + "@fast-csv/parse": "4.3.6" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "node_modules/fastq": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", + "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/faye-websocket": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", + "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", + "dev": true, + "dependencies": { + "websocket-driver": ">=0.5.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "dev": true, + "dependencies": { + "escape-string-regexp": "^1.0.5" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/file-saver": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/file-saver/-/file-saver-2.0.5.tgz", + "integrity": "sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA==" + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "dev": true, + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "node_modules/finalhandler/node_modules/on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "dev": true, + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/find-cache-dir": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", + "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", + "dev": true, + "dependencies": { + "commondir": "^1.0.1", + "make-dir": "^3.0.2", + "pkg-dir": "^4.1.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/avajs/find-cache-dir?sponsor=1" + } + }, + "node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "dependencies": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.5.tgz", + "integrity": "sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg==", + "dev": true + }, + "node_modules/follow-redirects": { + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/foreground-child": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", + "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/foreground-child/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/frac": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/frac/-/frac-1.1.2.tgz", + "integrity": "sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA==", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/fraction.js": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", + "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==", + "dev": true, + "engines": { + "node": "*" + }, + "funding": { + "type": "patreon", + "url": "https://github.com/sponsors/rawify" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" + }, + "node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/fs-minipass": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.3.tgz", + "integrity": "sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw==", + "dev": true, + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/fs-minipass/node_modules/minipass": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", + "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", + "dev": true, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/fs-monkey": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.5.tgz", + "integrity": "sha512-8uMbBjrhzW76TYgEV27Y5E//W2f/lTFmx78P2w19FZSxarhI/798APGQyuGCwmkNxgwGRhrLfvWyLBvNtuOmew==", + "dev": true + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/fstream": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz", + "integrity": "sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==", + "dependencies": { + "graceful-fs": "^4.1.2", + "inherits": "~2.0.0", + "mkdirp": ">=0.5 0", + "rimraf": "2" + }, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/fstream/node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/fstream/node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "node_modules/function.prototype.name": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", + "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.0", + "functions-have-names": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gauge": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz", + "integrity": "sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==", + "dev": true, + "dependencies": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.3", + "console-control-strings": "^1.1.0", + "has-unicode": "^2.0.1", + "signal-exit": "^3.0.7", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.5" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", + "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "dev": true, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-symbol-description": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", + "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "dev": true + }, + "node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "engines": { + "node": ">=4" + } + }, + "node_modules/globby": { + "version": "13.2.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-13.2.2.tgz", + "integrity": "sha512-Y1zNGV+pzQdh7H39l9zgB4PJqjRNqydvdYCDG4HFXM4XuvSaQQlEc91IU1yALL8gUTDomgBAfz3XJdmUS+oo0w==", + "dev": true, + "dependencies": { + "dir-glob": "^3.0.1", + "fast-glob": "^3.3.0", + "ignore": "^5.2.4", + "merge2": "^1.4.1", + "slash": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==" + }, + "node_modules/handle-thing": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", + "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==", + "dev": true + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "engines": { + "node": ">=4" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", + "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", + "dev": true + }, + "node_modules/hdr-histogram-js": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/hdr-histogram-js/-/hdr-histogram-js-2.0.3.tgz", + "integrity": "sha512-Hkn78wwzWHNCp2uarhzQ2SGFLU3JY8SBDDd3TAABK4fc30wm+MuPOrg5QVFVfkKOQd6Bfz3ukJEI+q9sXEkK1g==", + "dev": true, + "dependencies": { + "@assemblyscript/loader": "^0.10.1", + "base64-js": "^1.2.0", + "pako": "^1.0.3" + } + }, + "node_modules/hdr-histogram-percentiles-obj": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hdr-histogram-percentiles-obj/-/hdr-histogram-percentiles-obj-3.0.0.tgz", + "integrity": "sha512-7kIufnBqdsBGcSZLPJwqHT3yhk1QTsSlFsVD3kx5ixH/AlgBs9yM1q6DPhXZ8f8gtdqgh7N7/5btRLpQsS2gHw==", + "dev": true + }, + "node_modules/hosted-git-info": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-6.1.1.tgz", + "integrity": "sha512-r0EI+HBMcXadMrugk0GCQ+6BQV39PiWAZVfq7oIckeGiN7sjRGyQxPdft3nQekFTCQbYxLBH+/axZMeH8UX6+w==", + "dev": true, + "dependencies": { + "lru-cache": "^7.5.1" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/hosted-git-info/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/hpack.js": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", + "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", + "dev": true, + "dependencies": { + "inherits": "^2.0.1", + "obuf": "^1.0.0", + "readable-stream": "^2.0.1", + "wbuf": "^1.1.0" + } + }, + "node_modules/hpack.js/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/hpack.js/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/html-entities": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.4.0.tgz", + "integrity": "sha512-igBTJcNNNhvZFRtm8uA6xMY6xYleeDwn3PeBCkDz7tHttv4F2hsDI2aPgNERWzvRcNYHNT3ymRaQzllmXj4YsQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/mdevils" + }, + { + "type": "patreon", + "url": "https://patreon.com/mdevils" + } + ] + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true + }, + "node_modules/http-cache-semantics": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", + "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", + "dev": true + }, + "node_modules/http-deceiver": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", + "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==", + "dev": true + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dev": true, + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-errors/node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-parser-js": { + "version": "0.5.8", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", + "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==", + "dev": true + }, + "node_modules/http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "dev": true, + "dependencies": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/http-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", + "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", + "dev": true, + "dependencies": { + "@tootallnate/once": "2", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/http-proxy-middleware": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz", + "integrity": "sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==", + "dev": true, + "dependencies": { + "@types/http-proxy": "^1.17.8", + "http-proxy": "^1.18.1", + "is-glob": "^4.0.1", + "is-plain-obj": "^3.0.0", + "micromatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "@types/express": "^4.17.13" + }, + "peerDependenciesMeta": { + "@types/express": { + "optional": true + } + } + }, + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dev": true, + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/humanize-ms": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", + "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", + "dev": true, + "dependencies": { + "ms": "^2.0.0" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/icss-utils": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", + "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", + "dev": true, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/ignore": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz", + "integrity": "sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/ignore-walk": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-6.0.4.tgz", + "integrity": "sha512-t7sv42WkwFkyKbivUCglsQW5YWMskWtbEf4MNKX5u/CCWHKSPzN4FtBQGsQZgCLbxOzpVlcbWVK5KB3auIOjSw==", + "dev": true, + "dependencies": { + "minimatch": "^9.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/ignore-walk/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/ignore-walk/node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/image-size": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz", + "integrity": "sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==", + "dev": true, + "optional": true, + "bin": { + "image-size": "bin/image-size.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/immediate": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", + "integrity": "sha1-nbHb0Pr43m++D13V5Wu2BigN5ps=" + }, + "node_modules/immutable": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.4.tgz", + "integrity": "sha512-fsXeu4J4i6WNWSikpI88v/PcVflZz+6kMhUfIwc5SY+poQRPnaf5V7qds6SUyUN3cVxEzuCab7QIoLOQ+DQ1wA==", + "dev": true + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-fresh/node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/infer-owner": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", + "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", + "dev": true + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/ini": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ini/-/ini-3.0.1.tgz", + "integrity": "sha512-it4HyVAUTKBc6m8e1iXWvXSTdndF7HbdN713+kvLrymxTaU4AUBWrJ4vEooP+V7fexnVD3LKcBshjGGPefSMUQ==", + "dev": true, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/inquirer": { + "version": "8.2.4", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.4.tgz", + "integrity": "sha512-nn4F01dxU8VeKfq192IjLsxu0/OmMZ4Lg3xKAns148rCaXP6ntAoEkVYZThWjwON8AlzdZZi6oqnhNbxUG9hVg==", + "dev": true, + "dependencies": { + "ansi-escapes": "^4.2.1", + "chalk": "^4.1.1", + "cli-cursor": "^3.1.0", + "cli-width": "^3.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.21", + "mute-stream": "0.0.8", + "ora": "^5.4.1", + "run-async": "^2.4.0", + "rxjs": "^7.5.5", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0", + "through": "^2.3.6", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/inquirer/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/inquirer/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/inquirer/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/inquirer/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/inquirer/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/inquirer/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/internal-slot": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", + "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.0", + "has": "^1.0.3", + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ip": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.1.tgz", + "integrity": "sha512-lJUL9imLTNi1ZfXT+DU6rBBdbiKGBuay9B6xGSPVjUeQwaH1RIGqef8RZkUtHioLmSNpPR5M4HVKJGm1j8FWVQ==", + "dev": true + }, + "node_modules/ipaddr.js": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.1.0.tgz", + "integrity": "sha512-LlbxQ7xKzfBusov6UMi4MFpEg0m+mAm9xyNGEduwXMEDuf4WfzB/RZwMVYEd7IKGvh4IUkEXYxtAVu9T3OelJQ==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true + }, + "node_modules/is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dev": true, + "dependencies": { + "has-bigints": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-callable": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", + "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-core-module": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.9.0.tgz", + "integrity": "sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A==", + "dev": true, + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "dev": true, + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-interactive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", + "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-lambda": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", + "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", + "dev": true + }, + "node_modules/is-negative-zero": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", + "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-plain-obj": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", + "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", + "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-what": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/is-what/-/is-what-3.14.1.tgz", + "integrity": "sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==", + "dev": true + }, + "node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dev": true, + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "node_modules/isbinaryfile": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-4.0.10.tgz", + "integrity": "sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw==", + "dev": true, + "engines": { + "node": ">= 8.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/gjtorikian/" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", + "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.0.tgz", + "integrity": "sha512-6Lthe1hqXHBNsqvgDzGO6l03XNeu3CrG4RqQ1KM9+l5+jNGpEJfIELx1NS3SEHmJQA8np/u+E4EPRKRiu6m19A==", + "dev": true, + "dependencies": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", + "dev": true, + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^3.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-report/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-report/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-source-maps": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", + "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", + "dev": true, + "dependencies": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-source-maps/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/istanbul-reports": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.4.tgz", + "integrity": "sha512-r1/DshN4KSE7xWEknZLLLLDn5CJybV3nw01VTkp6D5jzLuELlcbudfj/eSQFvrKsJuTVCGnePO7ho82Nw9zzfw==", + "dev": true, + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jackspeak": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", + "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==", + "dev": true, + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/jasmine-core": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-4.0.1.tgz", + "integrity": "sha512-w+JDABxQCkxbGGxg+a2hUVZyqUS2JKngvIyLGu/xiw2ZwgsoSB0iiecLQsQORSeaKQ6iGrCyWG86RfNDuoA7Lg==", + "dev": true + }, + "node_modules/jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "dev": true, + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/jest-worker/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonc-parser": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", + "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", + "dev": true + }, + "node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsonparse": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", + "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==", + "dev": true, + "engines": [ + "node >= 0.2.0" + ] + }, + "node_modules/jszip": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.0.tgz", + "integrity": "sha512-LDfVtOLtOxb9RXkYOwPyNBTQDL4eUbqahtoY6x07GiDJHwSYvn8sHHIw8wINImV3MqbMNve2gSuM1DDqEKk09Q==", + "dependencies": { + "lie": "~3.3.0", + "pako": "~1.0.2", + "readable-stream": "~2.3.6", + "setimmediate": "^1.0.5" + } + }, + "node_modules/jszip/node_modules/readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/jszip/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/karma": { + "version": "6.3.20", + "resolved": "https://registry.npmjs.org/karma/-/karma-6.3.20.tgz", + "integrity": "sha512-HRNQhMuKOwKpjYlWiJP0DUrJOh+QjaI/DTaD8b9rEm4Il3tJ8MijutVZH4ts10LuUFst/CedwTS6vieCN8yTSw==", + "dev": true, + "dependencies": { + "@colors/colors": "1.5.0", + "body-parser": "^1.19.0", + "braces": "^3.0.2", + "chokidar": "^3.5.1", + "connect": "^3.7.0", + "di": "^0.0.1", + "dom-serialize": "^2.2.1", + "glob": "^7.1.7", + "graceful-fs": "^4.2.6", + "http-proxy": "^1.18.1", + "isbinaryfile": "^4.0.8", + "lodash": "^4.17.21", + "log4js": "^6.4.1", + "mime": "^2.5.2", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.5", + "qjobs": "^1.2.0", + "range-parser": "^1.2.1", + "rimraf": "^3.0.2", + "socket.io": "^4.4.1", + "source-map": "^0.6.1", + "tmp": "^0.2.1", + "ua-parser-js": "^0.7.30", + "yargs": "^16.1.1" + }, + "bin": { + "karma": "bin/karma" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/karma-chrome-launcher": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/karma-chrome-launcher/-/karma-chrome-launcher-3.1.1.tgz", + "integrity": "sha512-hsIglcq1vtboGPAN+DGCISCFOxW+ZVnIqhDQcCMqqCp+4dmJ0Qpq5QAjkbA0X2L9Mi6OBkHi2Srrbmm7pUKkzQ==", + "dev": true, + "dependencies": { + "which": "^1.2.1" + } + }, + "node_modules/karma-coverage": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/karma-coverage/-/karma-coverage-2.1.1.tgz", + "integrity": "sha512-oxeOSBVK/jdZsiX03LhHQkO4eISSQb5GbHi6Nsw3Mw7G4u6yUgacBAftnO7q+emPBLMsrNbz1pGIrj+Jb3z17A==", + "dev": true, + "dependencies": { + "istanbul-lib-coverage": "^3.2.0", + "istanbul-lib-instrument": "^4.0.3", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.1", + "istanbul-reports": "^3.0.5", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/karma-coverage/node_modules/istanbul-lib-instrument": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz", + "integrity": "sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==", + "dev": true, + "dependencies": { + "@babel/core": "^7.7.5", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.0.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/karma-coverage/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/karma-jasmine": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/karma-jasmine/-/karma-jasmine-4.0.2.tgz", + "integrity": "sha512-ggi84RMNQffSDmWSyyt4zxzh2CQGwsxvYYsprgyR1j8ikzIduEdOlcLvXjZGwXG/0j41KUXOWsUCBfbEHPWP9g==", + "dev": true, + "dependencies": { + "jasmine-core": "^3.6.0" + }, + "engines": { + "node": ">= 10" + }, + "peerDependencies": { + "karma": "*" + } + }, + "node_modules/karma-jasmine-html-reporter": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/karma-jasmine-html-reporter/-/karma-jasmine-html-reporter-1.7.0.tgz", + "integrity": "sha512-pzum1TL7j90DTE86eFt48/s12hqwQuiD+e5aXx2Dc9wDEn2LfGq6RoAxEZZjFiN0RDSCOnosEKRZWxbQ+iMpQQ==", + "dev": true, + "peerDependencies": { + "jasmine-core": ">=3.8", + "karma": ">=0.9", + "karma-jasmine": ">=1.1" + } + }, + "node_modules/karma-jasmine/node_modules/jasmine-core": { + "version": "3.99.1", + "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-3.99.1.tgz", + "integrity": "sha512-Hu1dmuoGcZ7AfyynN3LsfruwMbxMALMka+YtZeGoLuDEySVmVAPaonkNoBRIw/ectu8b9tVQCJNgp4a4knp+tg==", + "dev": true + }, + "node_modules/karma-source-map-support": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/karma-source-map-support/-/karma-source-map-support-1.4.0.tgz", + "integrity": "sha512-RsBECncGO17KAoJCYXjv+ckIz+Ii9NCi+9enk+rq6XC81ezYkb4/RHE6CTXdA7IOJqoF3wcaLfVG0CPmE5ca6A==", + "dev": true, + "dependencies": { + "source-map-support": "^0.5.5" + } + }, + "node_modules/karma/node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/karma/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/karma/node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/karma/node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/klona": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.6.tgz", + "integrity": "sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/lazystream": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.1.tgz", + "integrity": "sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==", + "dependencies": { + "readable-stream": "^2.0.5" + }, + "engines": { + "node": ">= 0.6.3" + } + }, + "node_modules/lazystream/node_modules/readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/lazystream/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/less": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/less/-/less-4.1.3.tgz", + "integrity": "sha512-w16Xk/Ta9Hhyei0Gpz9m7VS8F28nieJaL/VyShID7cYvP6IL5oHeL6p4TXSDJqZE/lNv0oJ2pGVjJsRkfwm5FA==", + "dev": true, + "dependencies": { + "copy-anything": "^2.0.1", + "parse-node-version": "^1.0.1", + "tslib": "^2.3.0" + }, + "bin": { + "lessc": "bin/lessc" + }, + "engines": { + "node": ">=6" + }, + "optionalDependencies": { + "errno": "^0.1.1", + "graceful-fs": "^4.1.2", + "image-size": "~0.5.0", + "make-dir": "^2.1.0", + "mime": "^1.4.1", + "needle": "^3.1.0", + "source-map": "~0.6.0" + } + }, + "node_modules/less-loader": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/less-loader/-/less-loader-11.1.0.tgz", + "integrity": "sha512-C+uDBV7kS7W5fJlUjq5mPBeBVhYpTIm5gB09APT9o3n/ILeaXVsiSFTbZpTJCJwQ/Crczfn3DmfQFwxYusWFug==", + "dev": true, + "dependencies": { + "klona": "^2.0.4" + }, + "engines": { + "node": ">= 14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "less": "^3.5.0 || ^4.0.0", + "webpack": "^5.0.0" + } + }, + "node_modules/less/node_modules/make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "dev": true, + "optional": true, + "dependencies": { + "pify": "^4.0.1", + "semver": "^5.6.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/less/node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true, + "optional": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/less/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "optional": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/less/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/license-webpack-plugin": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/license-webpack-plugin/-/license-webpack-plugin-4.0.2.tgz", + "integrity": "sha512-771TFWFD70G1wLTC4oU2Cw4qvtmNrIw+wRvBtn+okgHl7slJVi7zfNcdmqDL72BojM30VNJ2UHylr1o77U37Jw==", + "dev": true, + "dependencies": { + "webpack-sources": "^3.0.0" + }, + "peerDependenciesMeta": { + "webpack": { + "optional": true + }, + "webpack-sources": { + "optional": true + } + } + }, + "node_modules/lie": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", + "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", + "dependencies": { + "immediate": "~3.0.5" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true + }, + "node_modules/listenercount": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/listenercount/-/listenercount-1.0.1.tgz", + "integrity": "sha1-hMinKrWcRyUyFIDJdeZQg0LnCTc=" + }, + "node_modules/loader-runner": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", + "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", + "dev": true, + "engines": { + "node": ">=6.11.5" + } + }, + "node_modules/loader-utils": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.2.1.tgz", + "integrity": "sha512-ZvFw1KWS3GVyYBYb7qkmRM/WwL2TQQBxgCK62rlvm4WpVQ23Nb4tYjApUlfjrEGvOs7KHEsmyUn75OHZrJMWPw==", + "dev": true, + "engines": { + "node": ">= 12.13.0" + } + }, + "node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "node_modules/lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", + "dev": true + }, + "node_modules/lodash.defaults": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", + "integrity": "sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw=" + }, + "node_modules/lodash.difference": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.difference/-/lodash.difference-4.5.0.tgz", + "integrity": "sha1-nMtOUF1Ia5FlE0V3KIWi3yf9AXw=" + }, + "node_modules/lodash.escaperegexp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.escaperegexp/-/lodash.escaperegexp-4.1.2.tgz", + "integrity": "sha1-ZHYsSGGAglGKw99Mz11YhtriA0c=" + }, + "node_modules/lodash.flatten": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", + "integrity": "sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8=" + }, + "node_modules/lodash.groupby": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.groupby/-/lodash.groupby-4.6.0.tgz", + "integrity": "sha1-Cwih3PaDl8OXhVwyOXg4Mt90A9E=" + }, + "node_modules/lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY=" + }, + "node_modules/lodash.isequal": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", + "integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA=" + }, + "node_modules/lodash.isfunction": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/lodash.isfunction/-/lodash.isfunction-3.0.9.tgz", + "integrity": "sha512-AirXNj15uRIMMPihnkInB4i3NHeb4iBtNg9WRWuK2o31S+ePwwNmDPaTL3o7dTJ+VXNZim7rFs4rxN4YU1oUJw==" + }, + "node_modules/lodash.isnil": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/lodash.isnil/-/lodash.isnil-4.0.0.tgz", + "integrity": "sha1-SeKM1VkBNFjIFMVHnTxmOiG/qmw=" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=" + }, + "node_modules/lodash.isundefined": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/lodash.isundefined/-/lodash.isundefined-3.0.1.tgz", + "integrity": "sha1-I+89lTVWUgOmbO/VuDD4SJEa+0g=" + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "node_modules/lodash.union": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.union/-/lodash.union-4.6.0.tgz", + "integrity": "sha1-SLtQiECfFvGCFmZkHETdGqrjzYg=" + }, + "node_modules/lodash.uniq": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", + "integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=" + }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-symbols/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/log-symbols/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/log-symbols/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/log-symbols/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/log-symbols/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/log-symbols/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/log4js": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/log4js/-/log4js-6.5.1.tgz", + "integrity": "sha512-z1hRRe5DDPzsP73PgN/GYmeSbIAl/g9kX3GLjABCpcU1ojns8S4cyjpJ21jU1P7z1wWkm69PjyMcEGqYYdDqaA==", + "dev": true, + "dependencies": { + "date-format": "^4.0.10", + "debug": "^4.3.4", + "flatted": "^3.2.5", + "rfdc": "^1.3.0", + "streamroller": "^3.1.1" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/magic-string": { + "version": "0.29.0", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.29.0.tgz", + "integrity": "sha512-WcfidHrDjMY+eLjlU+8OvwREqHwpgCeKVBUpQ3OhYYuvfaYCUgcbuBzappNzZvg/v8onU3oQj+BYpkOJe9Iw4Q==", + "dev": true, + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.4.13" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/make-fetch-happen": { + "version": "10.2.1", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-10.2.1.tgz", + "integrity": "sha512-NgOPbRiaQM10DYXvN3/hhGVI2M5MtITFryzBGxHM5p4wnFxsVCbxkrBrDsk+EZ5OB4jEOT7AjDxtdF+KVEFT7w==", + "dev": true, + "dependencies": { + "agentkeepalive": "^4.2.1", + "cacache": "^16.1.0", + "http-cache-semantics": "^4.1.0", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.0", + "is-lambda": "^1.0.1", + "lru-cache": "^7.7.1", + "minipass": "^3.1.6", + "minipass-collect": "^1.0.2", + "minipass-fetch": "^2.0.3", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.3", + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^7.0.0", + "ssri": "^9.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/make-fetch-happen/node_modules/@npmcli/fs": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-2.1.2.tgz", + "integrity": "sha512-yOJKRvohFOaLqipNtwYB9WugyZKhC/DZC4VYPmpaCzDBrA8YpK3qHZ8/HGscMnE4GqbkLNuVcCnxkeQEdGt6LQ==", + "dev": true, + "dependencies": { + "@gar/promisify": "^1.1.3", + "semver": "^7.3.5" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/make-fetch-happen/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/make-fetch-happen/node_modules/cacache": { + "version": "16.1.3", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-16.1.3.tgz", + "integrity": "sha512-/+Emcj9DAXxX4cwlLmRI9c166RuL3w30zp4R7Joiv2cQTtTtA+jeuCAjH3ZlGnYS3tKENSrKhAzVVP9GVyzeYQ==", + "dev": true, + "dependencies": { + "@npmcli/fs": "^2.1.0", + "@npmcli/move-file": "^2.0.0", + "chownr": "^2.0.0", + "fs-minipass": "^2.1.0", + "glob": "^8.0.1", + "infer-owner": "^1.0.4", + "lru-cache": "^7.7.1", + "minipass": "^3.1.6", + "minipass-collect": "^1.0.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "mkdirp": "^1.0.4", + "p-map": "^4.0.0", + "promise-inflight": "^1.0.1", + "rimraf": "^3.0.2", + "ssri": "^9.0.0", + "tar": "^6.1.11", + "unique-filename": "^2.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/make-fetch-happen/node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/make-fetch-happen/node_modules/glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/make-fetch-happen/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/make-fetch-happen/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/make-fetch-happen/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/make-fetch-happen/node_modules/ssri": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-9.0.1.tgz", + "integrity": "sha512-o57Wcn66jMQvfHG1FlYbWeZWW/dHZhJXjpIcTfXldXEk5nz5lStPo3mK0OJQfGR3RbZUlbISexbljkJzuEj/8Q==", + "dev": true, + "dependencies": { + "minipass": "^3.1.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/make-fetch-happen/node_modules/unique-filename": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-2.0.1.tgz", + "integrity": "sha512-ODWHtkkdx3IAR+veKxFV+VBkUMcN+FaqzUUd7IZzt+0zhDZFPFxhlqwPF3YQvMHx1TD0tdgYl+kuPnJ8E6ql7A==", + "dev": true, + "dependencies": { + "unique-slug": "^3.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/make-fetch-happen/node_modules/unique-slug": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-3.0.0.tgz", + "integrity": "sha512-8EyMynh679x/0gqE9fT9oilG+qEt+ibFyqjuVTsZn1+CMxH+XLlpvr2UZx4nVcCwTpx81nICr2JQFkM+HPLq4w==", + "dev": true, + "dependencies": { + "imurmurhash": "^0.1.4" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/memfs": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.5.3.tgz", + "integrity": "sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==", + "dev": true, + "dependencies": { + "fs-monkey": "^1.0.4" + }, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==", + "dev": true + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", + "dev": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/mini-css-extract-plugin": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.7.2.tgz", + "integrity": "sha512-EdlUizq13o0Pd+uCp+WO/JpkLvHRVGt97RqfeGhXqAcorYo1ypJSpkV+WDT0vY/kmh/p7wRdJNJtuyK540PXDw==", + "dev": true, + "dependencies": { + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + } + }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "dev": true + }, + "node_modules/minimatch": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.5.tgz", + "integrity": "sha512-tUpxzX0VAzJHjLu0xUfFv1gwVp9ba3IOuRAVH2EGuRW8a5emA2FlACLqiT/lDVtS1W+TGNwqz3sWaNyLgDJWuw==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" + }, + "node_modules/minipass": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.8.tgz", + "integrity": "sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-collect": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz", + "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minipass-collect/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-fetch": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-2.1.2.tgz", + "integrity": "sha512-LT49Zi2/WMROHYoqGgdlQIZh8mLPZmOrN2NdJjMXxYe4nkN6FUyuPuOAOedNJDrx0IRGg9+4guZewtp8hE6TxA==", + "dev": true, + "dependencies": { + "minipass": "^3.1.6", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + }, + "optionalDependencies": { + "encoding": "^0.1.13" + } + }, + "node_modules/minipass-fetch/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-flush": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", + "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minipass-flush/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-json-stream": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minipass-json-stream/-/minipass-json-stream-1.0.1.tgz", + "integrity": "sha512-ODqY18UZt/I8k+b7rl2AENgbWE8IDYam+undIJONvigAz8KR5GWblsFTEfQs0WODsjbSXWlm+JHEv8Gr6Tfdbg==", + "dev": true, + "dependencies": { + "jsonparse": "^1.3.1", + "minipass": "^3.0.0" + } + }, + "node_modules/minipass-json-stream/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-pipeline": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", + "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-pipeline/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-sized": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", + "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-sized/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minizlib/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/multicast-dns": { + "version": "7.2.5", + "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", + "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", + "dev": true, + "dependencies": { + "dns-packet": "^5.2.2", + "thunky": "^1.0.2" + }, + "bin": { + "multicast-dns": "cli.js" + } + }, + "node_modules/mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", + "dev": true + }, + "node_modules/nanoid": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, + "node_modules/needle": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/needle/-/needle-3.2.0.tgz", + "integrity": "sha512-oUvzXnyLiVyVGoianLijF9O/RecZUf7TkBfimjGrLM4eQhXyeJwM6GeAWccwfQ9aa4gMCZKqhAOuLaMIcQxajQ==", + "dev": true, + "optional": true, + "dependencies": { + "debug": "^3.2.6", + "iconv-lite": "^0.6.3", + "sax": "^1.2.4" + }, + "bin": { + "needle": "bin/needle" + }, + "engines": { + "node": ">= 4.4.x" + } + }, + "node_modules/needle/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "optional": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/needle/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "optional": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true + }, + "node_modules/ngx-bootstrap-multiselect": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ngx-bootstrap-multiselect/-/ngx-bootstrap-multiselect-2.1.1.tgz", + "integrity": "sha512-BKE34b8wavxAyUlsZSPwR8p048sjfgVwBLMh5U0pw4TEt3onuF3+JzoTa2LAhPBhNxu+wc7af4IjdJ4mlrhKmQ==", + "dependencies": { + "tslib": "^2.0.0" + }, + "peerDependencies": { + "@angular/common": "^10.0.6", + "@angular/core": "^10.0.6", + "@angular/forms": "^10.0.6" + } + }, + "node_modules/ngx-spinner": { + "version": "13.1.1", + "resolved": "https://registry.npmjs.org/ngx-spinner/-/ngx-spinner-13.1.1.tgz", + "integrity": "sha512-6aJz4KxIsBrlQckJxcM3CEvMcYbZoSDnQZPu0F/ZYAYunbBOTb9iydw0Gjczg9moum1VURWjX5dTVKmFo85c2Q==", + "dependencies": { + "tslib": "^2.3.0" + }, + "peerDependencies": { + "@angular/common": "^13.0.0", + "@angular/core": "^13.0.0" + } + }, + "node_modules/nice-napi": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/nice-napi/-/nice-napi-1.0.2.tgz", + "integrity": "sha512-px/KnJAJZf5RuBGcfD+Sp2pAKq0ytz8j+1NehvgIGFkvtvFrDM3T8E4x/JJODXK9WZow8RRGrbA9QQ3hs+pDhA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "!win32" + ], + "dependencies": { + "node-addon-api": "^3.0.0", + "node-gyp-build": "^4.2.2" + } + }, + "node_modules/node-addon-api": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz", + "integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==", + "dev": true, + "optional": true + }, + "node_modules/node-forge": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", + "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", + "dev": true, + "engines": { + "node": ">= 6.13.0" + } + }, + "node_modules/node-gyp": { + "version": "9.4.1", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-9.4.1.tgz", + "integrity": "sha512-OQkWKbjQKbGkMf/xqI1jjy3oCTgMKJac58G2+bjZb3fza6gW2YrCSdMQYaoTb70crvE//Gngr4f0AgVHmqHvBQ==", + "dev": true, + "dependencies": { + "env-paths": "^2.2.0", + "exponential-backoff": "^3.1.1", + "glob": "^7.1.4", + "graceful-fs": "^4.2.6", + "make-fetch-happen": "^10.0.3", + "nopt": "^6.0.0", + "npmlog": "^6.0.0", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.2", + "which": "^2.0.2" + }, + "bin": { + "node-gyp": "bin/node-gyp.js" + }, + "engines": { + "node": "^12.13 || ^14.13 || >=16" + } + }, + "node_modules/node-gyp-build": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.4.0.tgz", + "integrity": "sha512-amJnQCcgtRVw9SvoebO3BKGESClrfXGCUTX9hSn1OuGQTQBOZmVd0Z0OlecpuRksKvbsUqALE8jls/ErClAPuQ==", + "dev": true, + "optional": true, + "bin": { + "node-gyp-build": "bin.js", + "node-gyp-build-optional": "optional.js", + "node-gyp-build-test": "build-test.js" + } + }, + "node_modules/node-gyp/node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/node-releases": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", + "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==" + }, + "node_modules/nopt": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-6.0.0.tgz", + "integrity": "sha512-ZwLpbTgdhuZUnZzjd7nb1ZV+4DoiC6/sfiVKok72ym/4Tlf+DFdlHYmT2JPmcNNWV6Pi3SDf1kT+A4r9RTuT9g==", + "dev": true, + "dependencies": { + "abbrev": "^1.0.0" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/normalize-package-data": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-5.0.0.tgz", + "integrity": "sha512-h9iPVIfrVZ9wVYQnxFgtw1ugSvGEMOlyPWWtm8BMJhnwyEL/FLbYbTY3V3PpjI/BUK67n9PEWDu6eHzu1fB15Q==", + "dev": true, + "dependencies": { + "hosted-git-info": "^6.0.0", + "is-core-module": "^2.8.1", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-bundled": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-3.0.0.tgz", + "integrity": "sha512-Vq0eyEQy+elFpzsKjMss9kxqb9tG3YHg4dsyWuUENuzvSUWe1TCnW/vV9FkhvBk/brEDoDiVd+M1Btosa6ImdQ==", + "dev": true, + "dependencies": { + "npm-normalize-package-bin": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm-install-checks": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-6.3.0.tgz", + "integrity": "sha512-W29RiK/xtpCGqn6f3ixfRYGk+zRyr+Ew9F2E20BfXxT5/euLdA/Nm7fO7OeTGuAmTs30cpgInyJ0cYe708YTZw==", + "dev": true, + "dependencies": { + "semver": "^7.1.1" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm-normalize-package-bin": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-3.0.1.tgz", + "integrity": "sha512-dMxCf+zZ+3zeQZXKxmyuCKlIDPGuv8EF940xbkC4kQVDTtqoh6rJFO+JTKSA6/Rwi0getWmtuy4Itup0AMcaDQ==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm-package-arg": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-10.1.0.tgz", + "integrity": "sha512-uFyyCEmgBfZTtrKk/5xDfHp6+MdrqGotX/VoOyEEl3mBwiEE5FlBaePanazJSVMPT7vKepcjYBY2ztg9A3yPIA==", + "dev": true, + "dependencies": { + "hosted-git-info": "^6.0.0", + "proc-log": "^3.0.0", + "semver": "^7.3.5", + "validate-npm-package-name": "^5.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm-packlist": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-7.0.4.tgz", + "integrity": "sha512-d6RGEuRrNS5/N84iglPivjaJPxhDbZmlbTwTDX2IbcRHG5bZCdtysYMhwiPvcF4GisXHGn7xsxv+GQ7T/02M5Q==", + "dev": true, + "dependencies": { + "ignore-walk": "^6.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm-pick-manifest": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-8.0.1.tgz", + "integrity": "sha512-mRtvlBjTsJvfCCdmPtiu2bdlx8d/KXtF7yNXNWe7G0Z36qWA9Ny5zXsI2PfBZEv7SXgoxTmNaTzGSbbzDZChoA==", + "dev": true, + "dependencies": { + "npm-install-checks": "^6.0.0", + "npm-normalize-package-bin": "^3.0.0", + "npm-package-arg": "^10.0.0", + "semver": "^7.3.5" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm-registry-fetch": { + "version": "14.0.5", + "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-14.0.5.tgz", + "integrity": "sha512-kIDMIo4aBm6xg7jOttupWZamsZRkAqMqwqqbVXnUqstY5+tapvv6bkH/qMR76jdgV+YljEUCyWx3hRYMrJiAgA==", + "dev": true, + "dependencies": { + "make-fetch-happen": "^11.0.0", + "minipass": "^5.0.0", + "minipass-fetch": "^3.0.0", + "minipass-json-stream": "^1.0.1", + "minizlib": "^2.1.2", + "npm-package-arg": "^10.0.0", + "proc-log": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm-registry-fetch/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/npm-registry-fetch/node_modules/make-fetch-happen": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-11.1.1.tgz", + "integrity": "sha512-rLWS7GCSTcEujjVBs2YqG7Y4643u8ucvCJeSRqiLYhesrDuzeuFIk37xREzAsfQaqzl8b9rNCE4m6J8tvX4Q8w==", + "dev": true, + "dependencies": { + "agentkeepalive": "^4.2.1", + "cacache": "^17.0.0", + "http-cache-semantics": "^4.1.1", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.0", + "is-lambda": "^1.0.1", + "lru-cache": "^7.7.1", + "minipass": "^5.0.0", + "minipass-fetch": "^3.0.0", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.3", + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^7.0.0", + "ssri": "^10.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm-registry-fetch/node_modules/minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm-registry-fetch/node_modules/minipass-fetch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.4.tgz", + "integrity": "sha512-jHAqnA728uUpIaFm7NWsCnqKT6UqZz7GcI/bDpPATuwYyKwJwW0remxSCxUlKiEty+eopHGa3oc8WxgQ1FFJqg==", + "dev": true, + "dependencies": { + "minipass": "^7.0.3", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + }, + "optionalDependencies": { + "encoding": "^0.1.13" + } + }, + "node_modules/npm-registry-fetch/node_modules/minipass-fetch/node_modules/minipass": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", + "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", + "dev": true, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npmlog": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-6.0.2.tgz", + "integrity": "sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==", + "dev": true, + "dependencies": { + "are-we-there-yet": "^3.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^4.0.3", + "set-blocking": "^2.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.1.tgz", + "integrity": "sha512-Y/jF6vnvEtOPGiKD1+q+X0CiUYRQtEHp89MLLUJ7TUivtH8Ugn2+3A7Rynqk7BRsAoqeOQWnFnjpDrKSxDgIGA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", + "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "has-symbols": "^1.0.1", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.values": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.5.tgz", + "integrity": "sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/obuf": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", + "dev": true + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dev": true, + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/open": { + "version": "8.4.1", + "resolved": "https://registry.npmjs.org/open/-/open-8.4.1.tgz", + "integrity": "sha512-/4b7qZNhv6Uhd7jjnREh1NjnPxlTq+XNWPG88Ydkj5AILcA5m3ajvcg57pB24EQjKv0dK62XnDqk9c/hkIG5Kg==", + "dev": true, + "dependencies": { + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/ora": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", + "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", + "dev": true, + "dependencies": { + "bl": "^4.1.0", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "is-unicode-supported": "^0.1.0", + "log-symbols": "^4.1.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ora/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/ora/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/ora/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/ora/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/ora/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ora/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "dev": true, + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-retry": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", + "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", + "dev": true, + "dependencies": { + "@types/retry": "0.12.0", + "retry": "^0.13.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-retry/node_modules/retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/pacote": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/pacote/-/pacote-15.1.0.tgz", + "integrity": "sha512-FFcjtIl+BQNfeliSm7MZz5cpdohvUV1yjGnqgVM4UnVF7JslRY0ImXAygdaCDV0jjUADEWu4y5xsDV8brtrTLg==", + "dev": true, + "dependencies": { + "@npmcli/git": "^4.0.0", + "@npmcli/installed-package-contents": "^2.0.1", + "@npmcli/promise-spawn": "^6.0.1", + "@npmcli/run-script": "^6.0.0", + "cacache": "^17.0.0", + "fs-minipass": "^3.0.0", + "minipass": "^4.0.0", + "npm-package-arg": "^10.0.0", + "npm-packlist": "^7.0.0", + "npm-pick-manifest": "^8.0.0", + "npm-registry-fetch": "^14.0.0", + "proc-log": "^3.0.0", + "promise-retry": "^2.0.1", + "read-package-json": "^6.0.0", + "read-package-json-fast": "^3.0.0", + "sigstore": "^1.0.0", + "ssri": "^10.0.0", + "tar": "^6.1.11" + }, + "bin": { + "pacote": "lib/bin.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==" + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parse-node-version": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parse-node-version/-/parse-node-version-1.0.1.tgz", + "integrity": "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/parse5": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz", + "integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==", + "optional": true + }, + "node_modules/parse5-html-rewriting-stream": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/parse5-html-rewriting-stream/-/parse5-html-rewriting-stream-7.0.0.tgz", + "integrity": "sha512-mazCyGWkmCRWDI15Zp+UiCqMp/0dgEmkZRvhlsqqKYr4SsVm/TvnSpD9fCvqCA2zoWJcfRym846ejWBBHRiYEg==", + "dev": true, + "dependencies": { + "entities": "^4.3.0", + "parse5": "^7.0.0", + "parse5-sax-parser": "^7.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parse5-html-rewriting-stream/node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "dev": true, + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/parse5-html-rewriting-stream/node_modules/parse5": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", + "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", + "dev": true, + "dependencies": { + "entities": "^4.4.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parse5-htmlparser2-tree-adapter": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz", + "integrity": "sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==", + "dev": true, + "dependencies": { + "parse5": "^6.0.1" + } + }, + "node_modules/parse5-htmlparser2-tree-adapter/node_modules/parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", + "dev": true + }, + "node_modules/parse5-sax-parser": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/parse5-sax-parser/-/parse5-sax-parser-7.0.0.tgz", + "integrity": "sha512-5A+v2SNsq8T6/mG3ahcz8ZtQ0OUFTatxPbeidoMB7tkJSGDY3tdfl4MHovtLQHkEn5CGxijNWRQHhRQ6IRpXKg==", + "dev": true, + "dependencies": { + "parse5": "^7.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parse5-sax-parser/node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "dev": true, + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/parse5-sax-parser/node_modules/parse5": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", + "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", + "dev": true, + "dependencies": { + "entities": "^4.4.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "node_modules/path-scurry": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.1.tgz", + "integrity": "sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==", + "dev": true, + "dependencies": { + "lru-cache": "^9.1.1 || ^10.0.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.1.0.tgz", + "integrity": "sha512-/1clY/ui8CzjKFyjdvwPWJUYKiFVXG2I2cY0ssG7h4+hwk+XOIX7ZSG9Q7TW8TW3Kp3BUSqgFWBLgL4PJ+Blag==", + "dev": true, + "engines": { + "node": "14 || >=16.14" + } + }, + "node_modules/path-scurry/node_modules/minipass": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", + "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", + "dev": true, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==", + "dev": true + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true, + "optional": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/piscina": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/piscina/-/piscina-3.2.0.tgz", + "integrity": "sha512-yn/jMdHRw+q2ZJhFhyqsmANcbF6V2QwmD84c6xRau+QpQOmtrBCoRGdvTfeuFDYXB5W2m6MfLkjkvQa9lUSmIA==", + "dev": true, + "dependencies": { + "eventemitter-asyncresource": "^1.0.0", + "hdr-histogram-js": "^2.0.1", + "hdr-histogram-percentiles-obj": "^3.0.0" + }, + "optionalDependencies": { + "nice-napi": "^1.0.2" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/postcss": { + "version": "8.4.31", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", + "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "nanoid": "^3.3.6", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-loader": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-7.0.2.tgz", + "integrity": "sha512-fUJzV/QH7NXUAqV8dWJ9Lg4aTkDCezpTS5HgJ2DvqznexTbSTxgi/dTECvTZ15BwKTtk8G/bqI/QTu2HPd3ZCg==", + "dev": true, + "dependencies": { + "cosmiconfig": "^7.0.0", + "klona": "^2.0.5", + "semver": "^7.3.8" + }, + "engines": { + "node": ">= 14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "postcss": "^7.0.0 || ^8.0.1", + "webpack": "^5.0.0" + } + }, + "node_modules/postcss-modules-extract-imports": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz", + "integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==", + "dev": true, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-local-by-default": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.3.tgz", + "integrity": "sha512-2/u2zraspoACtrbFRnTijMiQtb4GW4BvatjaG/bCjYQo8kLTdevCUlwuBHx2sCnSyrI3x3qj4ZK1j5LQBgzmwA==", + "dev": true, + "dependencies": { + "icss-utils": "^5.0.0", + "postcss-selector-parser": "^6.0.2", + "postcss-value-parser": "^4.1.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-scope": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz", + "integrity": "sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.4" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-values": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", + "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", + "dev": true, + "dependencies": { + "icss-utils": "^5.0.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.0.13", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz", + "integrity": "sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ==", + "dev": true, + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "dev": true + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/pretty-bytes": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", + "integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==", + "dev": true, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/proc-log": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-3.0.0.tgz", + "integrity": "sha512-++Vn7NS4Xf9NacaU9Xq3URUuqZETPsf8L4j5/ckhaRYsfPeRyzGw+iDjFhV/Jr3uNmTvvddEJFWh5R1gRgUH8A==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "node_modules/promise-inflight": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", + "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==", + "dev": true + }, + "node_modules/promise-retry": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", + "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", + "dev": true, + "dependencies": { + "err-code": "^2.0.2", + "retry": "^0.12.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dev": true, + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/proxy-addr/node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/prr": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", + "integrity": "sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==", + "dev": true, + "optional": true + }, + "node_modules/punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/qjobs": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/qjobs/-/qjobs-1.2.0.tgz", + "integrity": "sha512-8YOJEHtxpySA3fFDyCRxA+UUV+fA+rTWnuWvylOK/NCjhY+b4ocCtmu8TtsWb+mYeU+GCHf/S66KZF/AsteKHg==", + "dev": true, + "engines": { + "node": ">=0.9" + } + }, + "node_modules/qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dev": true, + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "dev": true, + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/read-package-json": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-6.0.4.tgz", + "integrity": "sha512-AEtWXYfopBj2z5N5PbkAOeNHRPUg5q+Nen7QLxV8M2zJq1ym6/lCz3fYNTCXe19puu2d06jfHhrP7v/S2PtMMw==", + "dev": true, + "dependencies": { + "glob": "^10.2.2", + "json-parse-even-better-errors": "^3.0.0", + "normalize-package-data": "^5.0.0", + "npm-normalize-package-bin": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/read-package-json-fast": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/read-package-json-fast/-/read-package-json-fast-3.0.2.tgz", + "integrity": "sha512-0J+Msgym3vrLOUB3hzQCuZHII0xkNGCtz/HJH9xZshwv9DbDwkw1KaE3gx/e2J5rpEY5rtOy6cyhKOPrkP7FZw==", + "dev": true, + "dependencies": { + "json-parse-even-better-errors": "^3.0.0", + "npm-normalize-package-bin": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/read-package-json-fast/node_modules/json-parse-even-better-errors": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.1.tgz", + "integrity": "sha512-aatBvbL26wVUCLmbWdCpeu9iF5wOyWpagiKkInA+kfws3sWdBrTnsvN2CKcyCYyUrc7rebNBlK6+kteg7ksecg==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/read-package-json/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/read-package-json/node_modules/glob": { + "version": "10.3.10", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", + "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", + "dev": true, + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^2.3.5", + "minimatch": "^9.0.1", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", + "path-scurry": "^1.10.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/read-package-json/node_modules/json-parse-even-better-errors": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.1.tgz", + "integrity": "sha512-aatBvbL26wVUCLmbWdCpeu9iF5wOyWpagiKkInA+kfws3sWdBrTnsvN2CKcyCYyUrc7rebNBlK6+kteg7ksecg==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/read-package-json/node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/read-package-json/node_modules/minipass": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", + "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", + "dev": true, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readdir-glob": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/readdir-glob/-/readdir-glob-1.1.1.tgz", + "integrity": "sha512-91/k1EzZwDx6HbERR+zucygRFfiPl2zkIYZtv3Jjr6Mn7SkKcVct8aVO+sSRiGMc6fLf72du3d92/uY63YPdEA==", + "dependencies": { + "minimatch": "^3.0.4" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/reflect-metadata": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz", + "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==", + "dev": true + }, + "node_modules/regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", + "dev": true + }, + "node_modules/regenerate-unicode-properties": { + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.1.tgz", + "integrity": "sha512-X007RyZLsCJVVrjgEFVpLUTZwyOZk3oiL75ZcuYjlIWd6rNJtOjkBwQc5AsRrpbKVkxN6sklw/k/9m2jJYOf8Q==", + "dev": true, + "dependencies": { + "regenerate": "^1.4.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.13.11", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", + "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==", + "dev": true + }, + "node_modules/regenerator-transform": { + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.2.tgz", + "integrity": "sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.8.4" + } + }, + "node_modules/regex-parser": { + "version": "2.2.11", + "resolved": "https://registry.npmjs.org/regex-parser/-/regex-parser-2.2.11.tgz", + "integrity": "sha512-jbD/FT0+9MBU2XAZluI7w2OBs1RBi6p9M83nkoZayQXXU9e8Robt69FcZc7wU4eJD/YFTjn1JdCk3rbMJajz8Q==", + "dev": true + }, + "node_modules/regexp.prototype.flags": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", + "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "functions-have-names": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, + "node_modules/regexpu-core": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.3.2.tgz", + "integrity": "sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ==", + "dev": true, + "dependencies": { + "@babel/regjsgen": "^0.8.0", + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.1.0", + "regjsparser": "^0.9.1", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regjsparser": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", + "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", + "dev": true, + "dependencies": { + "jsesc": "~0.5.0" + }, + "bin": { + "regjsparser": "bin/parser" + } + }, + "node_modules/regjsparser/node_modules/jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=", + "dev": true + }, + "node_modules/resolve": { + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", + "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "dev": true, + "dependencies": { + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-url-loader": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-url-loader/-/resolve-url-loader-5.0.0.tgz", + "integrity": "sha512-uZtduh8/8srhBoMx//5bwqjQ+rfYOUq8zC9NrMUGtjBiGTtFJM42s58/36+hTqeqINcnYe08Nj3LkK9lW4N8Xg==", + "dev": true, + "dependencies": { + "adjust-sourcemap-loader": "^4.0.0", + "convert-source-map": "^1.7.0", + "loader-utils": "^2.0.0", + "postcss": "^8.2.14", + "source-map": "0.6.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/resolve-url-loader/node_modules/loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "dev": true, + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/resolve-url-loader/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dev": true, + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rfdc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz", + "integrity": "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==", + "dev": true + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/run-async": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", + "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/rxjs": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.5.tgz", + "integrity": "sha512-sy+H0pQofO95VDmFLzyaw9xNJU4KTRSwQIGM6+iG3SypAtCiLDzpeG8sJrNCWn2Up9km+KhkvTdbkrdy+yzZdw==", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "node_modules/sass": { + "version": "1.58.1", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.58.1.tgz", + "integrity": "sha512-bnINi6nPXbP1XNRaranMFEBZWUfdW/AF16Ql5+ypRxfTvCRTTKrLsMIakyDcayUt2t/RZotmL4kgJwNH5xO+bg==", + "dev": true, + "dependencies": { + "chokidar": ">=3.0.0 <4.0.0", + "immutable": "^4.0.0", + "source-map-js": ">=0.6.2 <2.0.0" + }, + "bin": { + "sass": "sass.js" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/sass-loader": { + "version": "13.2.0", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-13.2.0.tgz", + "integrity": "sha512-JWEp48djQA4nbZxmgC02/Wh0eroSUutulROUusYJO9P9zltRbNN80JCBHqRGzjd4cmZCa/r88xgfkjGD0TXsHg==", + "dev": true, + "dependencies": { + "klona": "^2.0.4", + "neo-async": "^2.6.2" + }, + "engines": { + "node": ">= 14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "fibers": ">= 3.1.0", + "node-sass": "^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0", + "sass": "^1.3.0", + "sass-embedded": "*", + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "fibers": { + "optional": true + }, + "node-sass": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + } + } + }, + "node_modules/sax": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.3.0.tgz", + "integrity": "sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA==", + "dev": true, + "optional": true + }, + "node_modules/saxes": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", + "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==", + "dependencies": { + "xmlchars": "^2.2.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/schema-utils": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", + "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/select-hose": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", + "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==", + "dev": true + }, + "node_modules/selfsigned": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.4.1.tgz", + "integrity": "sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q==", + "dev": true, + "dependencies": { + "@types/node-forge": "^1.3.0", + "node-forge": "^1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "dev": true, + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/send/node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/send/node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/serialize-javascript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", + "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "dev": true, + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/serve-index": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==", + "dev": true, + "dependencies": { + "accepts": "~1.3.4", + "batch": "0.6.1", + "debug": "2.6.9", + "escape-html": "~1.0.3", + "http-errors": "~1.6.2", + "mime-types": "~2.1.17", + "parseurl": "~1.3.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/serve-index/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/serve-index/node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-index/node_modules/http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", + "dev": true, + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-index/node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", + "dev": true + }, + "node_modules/serve-index/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/serve-index/node_modules/setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", + "dev": true + }, + "node_modules/serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "dev": true, + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "dev": true + }, + "node_modules/setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=" + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "dev": true + }, + "node_modules/shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "node_modules/sigstore": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/sigstore/-/sigstore-1.9.0.tgz", + "integrity": "sha512-0Zjz0oe37d08VeOtBIuB6cRriqXse2e8w+7yIy2XSXjshRKxbc2KkhXjL229jXSxEm7UbcjS76wcJDGQddVI9A==", + "dev": true, + "dependencies": { + "@sigstore/bundle": "^1.1.0", + "@sigstore/protobuf-specs": "^0.2.0", + "@sigstore/sign": "^1.0.0", + "@sigstore/tuf": "^1.0.3", + "make-fetch-happen": "^11.0.1" + }, + "bin": { + "sigstore": "bin/sigstore.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/sigstore/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/sigstore/node_modules/make-fetch-happen": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-11.1.1.tgz", + "integrity": "sha512-rLWS7GCSTcEujjVBs2YqG7Y4643u8ucvCJeSRqiLYhesrDuzeuFIk37xREzAsfQaqzl8b9rNCE4m6J8tvX4Q8w==", + "dev": true, + "dependencies": { + "agentkeepalive": "^4.2.1", + "cacache": "^17.0.0", + "http-cache-semantics": "^4.1.1", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.0", + "is-lambda": "^1.0.1", + "lru-cache": "^7.7.1", + "minipass": "^5.0.0", + "minipass-fetch": "^3.0.0", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.3", + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^7.0.0", + "ssri": "^10.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/sigstore/node_modules/minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/sigstore/node_modules/minipass-fetch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.4.tgz", + "integrity": "sha512-jHAqnA728uUpIaFm7NWsCnqKT6UqZz7GcI/bDpPATuwYyKwJwW0remxSCxUlKiEty+eopHGa3oc8WxgQ1FFJqg==", + "dev": true, + "dependencies": { + "minipass": "^7.0.3", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + }, + "optionalDependencies": { + "encoding": "^0.1.13" + } + }, + "node_modules/sigstore/node_modules/minipass-fetch/node_modules/minipass": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", + "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", + "dev": true, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/slash": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", + "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "dev": true, + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socket.io": { + "version": "4.7.5", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.7.5.tgz", + "integrity": "sha512-DmeAkF6cwM9jSfmp6Dr/5/mfMwb5Z5qRrSXLpo3Fq5SqyU8CMF15jIN4ZhfSwu35ksM1qmHZDQ/DK5XTccSTvA==", + "dev": true, + "dependencies": { + "accepts": "~1.3.4", + "base64id": "~2.0.0", + "cors": "~2.8.5", + "debug": "~4.3.2", + "engine.io": "~6.5.2", + "socket.io-adapter": "~2.5.2", + "socket.io-parser": "~4.2.4" + }, + "engines": { + "node": ">=10.2.0" + } + }, + "node_modules/socket.io-adapter": { + "version": "2.5.4", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.4.tgz", + "integrity": "sha512-wDNHGXGewWAjQPt3pyeYBtpWSq9cLE5UW1ZUPL/2eGK9jtse/FpXib7epSTsz0Q0m+6sg6Y4KtcFTlah1bdOVg==", + "dev": true, + "dependencies": { + "debug": "~4.3.4", + "ws": "~8.11.0" + } + }, + "node_modules/socket.io-parser": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz", + "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==", + "dev": true, + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/sockjs": { + "version": "0.3.24", + "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", + "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==", + "dev": true, + "dependencies": { + "faye-websocket": "^0.11.3", + "uuid": "^8.3.2", + "websocket-driver": "^0.7.4" + } + }, + "node_modules/socks": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz", + "integrity": "sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==", + "dev": true, + "dependencies": { + "ip": "^2.0.0", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.13.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks-proxy-agent": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-7.0.0.tgz", + "integrity": "sha512-Fgl0YPZ902wEsAyiQ+idGd1A7rSFx/ayC1CQVMw5P+EQx2V0SgpGtf6OKFhVjPflPUl9YMmEOnmfjCdMUsygww==", + "dev": true, + "dependencies": { + "agent-base": "^6.0.2", + "debug": "^4.3.3", + "socks": "^2.6.2" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-loader": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/source-map-loader/-/source-map-loader-4.0.1.tgz", + "integrity": "sha512-oqXpzDIByKONVY8g1NUPOTQhe0UTU5bWUl32GSkqK2LjJj0HmwTMVKxcUip0RgAYhY1mqgOxjbQM48a0mmeNfA==", + "dev": true, + "dependencies": { + "abab": "^2.0.6", + "iconv-lite": "^0.6.3", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": ">= 14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.72.1" + } + }, + "node_modules/source-map-loader/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/source-map-support/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/spdx-correct": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", + "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", + "dev": true, + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", + "dev": true + }, + "node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.16", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.16.tgz", + "integrity": "sha512-eWN+LnM3GR6gPu35WxNgbGl8rmY1AEmoMDvL/QD6zYmPWgywxWqJWNdLGT+ke8dKNWrcYgYjPpG5gbTfghP8rw==", + "dev": true + }, + "node_modules/spdy": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", + "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", + "dev": true, + "dependencies": { + "debug": "^4.1.0", + "handle-thing": "^2.0.0", + "http-deceiver": "^1.2.7", + "select-hose": "^2.0.0", + "spdy-transport": "^3.0.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/spdy-transport": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", + "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", + "dev": true, + "dependencies": { + "debug": "^4.1.0", + "detect-node": "^2.0.4", + "hpack.js": "^2.1.6", + "obuf": "^1.1.2", + "readable-stream": "^3.0.6", + "wbuf": "^1.7.3" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "node_modules/ssf": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/ssf/-/ssf-0.11.2.tgz", + "integrity": "sha512-+idbmIXoYET47hH+d7dfm2epdOMUDjqcB4648sTZ+t2JwoyBFL/insLfB/racrDmsKB3diwsDA696pZMieAC5g==", + "dependencies": { + "frac": "~1.1.2" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/ssri": { + "version": "10.0.5", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-10.0.5.tgz", + "integrity": "sha512-bSf16tAFkGeRlUNDjXu8FzaMQt6g2HZJrun7mtMbIPOddxt3GLMSz5VWUWcqTJUPfLEaDIepGxv+bYQW49596A==", + "dev": true, + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/ssri/node_modules/minipass": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", + "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", + "dev": true, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/streamroller": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-3.1.1.tgz", + "integrity": "sha512-iPhtd9unZ6zKdWgMeYGfSBuqCngyJy1B/GPi/lTpwGpa3bajuX30GjUVd0/Tn/Xhg0mr4DOSENozz9Y06qyonQ==", + "dev": true, + "dependencies": { + "date-format": "^4.0.10", + "debug": "^4.3.4", + "fs-extra": "^10.1.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string_decoder/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.5.tgz", + "integrity": "sha512-I7RGvmjV4pJ7O3kdf+LXFpVfdNOxtCW/2C8f6jNiW4+PQchwxkCDzlk1/7p+Wl4bqFIZeF47qAHXLuHHWKAxog==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.19.5" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.5.tgz", + "integrity": "sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.19.5" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/sweetalert2": { + "version": "11.10.7", + "resolved": "https://registry.npmjs.org/sweetalert2/-/sweetalert2-11.10.7.tgz", + "integrity": "sha512-5Jlzrmaitay6KzU+2+LhYu9q+L4v/dZ8oZyEDH14ep0C/QilCnFLHmqAyD/Lhq/lm5DiwsOs6Tr58iv8k3wyGg==", + "funding": { + "type": "individual", + "url": "https://github.com/sponsors/limonte" + } + }, + "node_modules/symbol-observable": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-4.0.0.tgz", + "integrity": "sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ==", + "dev": true, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/tar": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", + "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", + "dev": true, + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^5.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "dependencies": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tar/node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/tar/node_modules/fs-minipass/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tar/node_modules/minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/terser": { + "version": "5.16.3", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.16.3.tgz", + "integrity": "sha512-v8wWLaS/xt3nE9dgKEWhNUFP6q4kngO5B8eYFUuebsu7Dw/UNAnpUod6UHo04jSSkv8TzKHjZDSd7EXdDQAl8Q==", + "dev": true, + "dependencies": { + "@jridgewell/source-map": "^0.3.2", + "acorn": "^8.5.0", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser-webpack-plugin": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.1.tgz", + "integrity": "sha512-GvlZdT6wPQKbDNW/GDQzZFg/j4vKU96yl2q6mcUkzKOgW4gwf1Z8cZToUCrz31XHlPWH8MVb1r2tFtdDtTGJ7g==", + "dev": true, + "dependencies": { + "jest-worker": "^27.4.5", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.0", + "source-map": "^0.6.1", + "terser": "^5.7.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "uglify-js": { + "optional": true + } + } + }, + "node_modules/terser-webpack-plugin/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/terser-webpack-plugin/node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/terser-webpack-plugin/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/terser-webpack-plugin/node_modules/schema-utils": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", + "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/terser-webpack-plugin/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, + "node_modules/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", + "dev": true + }, + "node_modules/thunky": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", + "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", + "dev": true + }, + "node_modules/tmp": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", + "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", + "dependencies": { + "rimraf": "^3.0.0" + }, + "engines": { + "node": ">=8.17.0" + } + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "engines": { + "node": ">=4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "dev": true, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/traverse": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.3.9.tgz", + "integrity": "sha1-cXuPIgzAu3tE5AUUwisui7xw2Lk=", + "engines": { + "node": "*" + } + }, + "node_modules/tree-kill": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", + "dev": true, + "bin": { + "tree-kill": "cli.js" + } + }, + "node_modules/tsconfig-paths": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz", + "integrity": "sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==", + "dev": true, + "dependencies": { + "@types/json5": "^0.0.29", + "json5": "^1.0.1", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + } + }, + "node_modules/tsconfig-paths/node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "dev": true, + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==" + }, + "node_modules/tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dev": true, + "dependencies": { + "tslib": "^1.8.1" + }, + "engines": { + "node": ">= 6" + }, + "peerDependencies": { + "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" + } + }, + "node_modules/tsutils/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "node_modules/tuf-js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/tuf-js/-/tuf-js-1.1.7.tgz", + "integrity": "sha512-i3P9Kgw3ytjELUfpuKVDNBJvk4u5bXL6gskv572mcevPbSKCV3zt3djhmlEQ65yERjIbOSncy7U4cQJaB1CBCg==", + "dev": true, + "dependencies": { + "@tufjs/models": "1.0.4", + "debug": "^4.3.4", + "make-fetch-happen": "^11.1.1" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/tuf-js/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/tuf-js/node_modules/make-fetch-happen": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-11.1.1.tgz", + "integrity": "sha512-rLWS7GCSTcEujjVBs2YqG7Y4643u8ucvCJeSRqiLYhesrDuzeuFIk37xREzAsfQaqzl8b9rNCE4m6J8tvX4Q8w==", + "dev": true, + "dependencies": { + "agentkeepalive": "^4.2.1", + "cacache": "^17.0.0", + "http-cache-semantics": "^4.1.1", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.0", + "is-lambda": "^1.0.1", + "lru-cache": "^7.7.1", + "minipass": "^5.0.0", + "minipass-fetch": "^3.0.0", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.3", + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^7.0.0", + "ssri": "^10.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/tuf-js/node_modules/minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/tuf-js/node_modules/minipass-fetch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.4.tgz", + "integrity": "sha512-jHAqnA728uUpIaFm7NWsCnqKT6UqZz7GcI/bDpPATuwYyKwJwW0remxSCxUlKiEty+eopHGa3oc8WxgQ1FFJqg==", + "dev": true, + "dependencies": { + "minipass": "^7.0.3", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + }, + "optionalDependencies": { + "encoding": "^0.1.13" + } + }, + "node_modules/tuf-js/node_modules/minipass-fetch/node_modules/minipass": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", + "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", + "dev": true, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dev": true, + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typed-assert": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/typed-assert/-/typed-assert-1.0.9.tgz", + "integrity": "sha512-KNNZtayBCtmnNmbo5mG47p1XsCyrx6iVqomjcZnec/1Y5GGARaxPs6r49RnSPeUP3YjNYiU9sQHAtY4BBvnZwg==", + "dev": true + }, + "node_modules/typescript": { + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/ua-parser-js": { + "version": "0.7.37", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.37.tgz", + "integrity": "sha512-xV8kqRKM+jhMvcHWUKthV9fNebIzrNy//2O9ZwWcfiBFR5f25XVZPLlEajk/sf3Ra15V92isyQqnIEXRDaZWEA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/ua-parser-js" + }, + { + "type": "paypal", + "url": "https://paypal.me/faisalman" + }, + { + "type": "github", + "url": "https://github.com/sponsors/faisalman" + } + ], + "engines": { + "node": "*" + } + }, + "node_modules/unbox-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/unicode-canonical-property-names-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", + "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", + "dev": true, + "dependencies": { + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-value-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz", + "integrity": "sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-property-aliases-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", + "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/unique-filename": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-3.0.0.tgz", + "integrity": "sha512-afXhuC55wkAmZ0P18QsVE6kp8JaxrEokN2HGIoIVv2ijHQd419H0+6EigAFcIzXeMIkcIkNBpB3L/DXB3cTS/g==", + "dev": true, + "dependencies": { + "unique-slug": "^4.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/unique-slug": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-4.0.0.tgz", + "integrity": "sha512-WrcA6AyEfqDX5bWige/4NQfPZMtASNVxdmWR76WESYQVAACSgWcR6e9i0mofqqBxYFtL4oAxPIptY73/0YE1DQ==", + "dev": true, + "dependencies": { + "imurmurhash": "^0.1.4" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "dev": true, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/unzipper": { + "version": "0.10.11", + "resolved": "https://registry.npmjs.org/unzipper/-/unzipper-0.10.11.tgz", + "integrity": "sha512-+BrAq2oFqWod5IESRjL3S8baohbevGcVA+teAIOYWM3pDVdseogqbzhhvvmiyQrUNKFUnDMtELW3X8ykbyDCJw==", + "dependencies": { + "big-integer": "^1.6.17", + "binary": "~0.3.0", + "bluebird": "~3.4.1", + "buffer-indexof-polyfill": "~1.0.0", + "duplexer2": "~0.1.4", + "fstream": "^1.0.12", + "graceful-fs": "^4.2.2", + "listenercount": "~1.0.1", + "readable-stream": "~2.3.6", + "setimmediate": "~1.0.4" + } + }, + "node_modules/unzipper/node_modules/readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/unzipper/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", + "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", + "dev": true, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/v8-compile-cache": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", + "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", + "dev": true + }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/validate-npm-package-name": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-5.0.0.tgz", + "integrity": "sha512-YuKoXDAhBYxY7SfOKxHBDoSyENFeW5VvIIQp2TGQuit8gpK6MnWaQelBKxso72DoxTZfZdcP3W90LqpSkgPzLQ==", + "dev": true, + "dependencies": { + "builtins": "^5.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/void-elements": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz", + "integrity": "sha1-wGavtYK7HLQSjWDqkjkulNXp2+w=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/watchpack": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", + "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", + "dev": true, + "dependencies": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/wbuf": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", + "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", + "dev": true, + "dependencies": { + "minimalistic-assert": "^1.0.0" + } + }, + "node_modules/wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g=", + "dev": true, + "dependencies": { + "defaults": "^1.0.3" + } + }, + "node_modules/webpack": { + "version": "5.76.1", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.76.1.tgz", + "integrity": "sha512-4+YIK4Abzv8172/SGqObnUjaIHjLEuUasz9EwQj/9xmPPkYJy2Mh03Q/lJfSD3YLzbxy5FeTq5Uw0323Oh6SJQ==", + "dev": true, + "dependencies": { + "@types/eslint-scope": "^3.7.3", + "@types/estree": "^0.0.51", + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/wasm-edit": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1", + "acorn": "^8.7.1", + "acorn-import-assertions": "^1.7.6", + "browserslist": "^4.14.5", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.10.0", + "es-module-lexer": "^0.9.0", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.9", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.1.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.1.3", + "watchpack": "^2.4.0", + "webpack-sources": "^3.2.3" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-dev-middleware": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-6.1.2.tgz", + "integrity": "sha512-Wu+EHmX326YPYUpQLKmKbTyZZJIB8/n6R09pTmB03kJmnMsVPTo9COzHZFr01txwaCAuZvfBJE4ZCHRcKs5JaQ==", + "dev": true, + "dependencies": { + "colorette": "^2.0.10", + "memfs": "^3.4.12", + "mime-types": "^2.1.31", + "range-parser": "^1.2.1", + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "webpack": { + "optional": true + } + } + }, + "node_modules/webpack-dev-server": { + "version": "4.11.1", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.11.1.tgz", + "integrity": "sha512-lILVz9tAUy1zGFwieuaQtYiadImb5M3d+H+L1zDYalYoDl0cksAB1UNyuE5MMWJrG6zR1tXkCP2fitl7yoUJiw==", + "dev": true, + "dependencies": { + "@types/bonjour": "^3.5.9", + "@types/connect-history-api-fallback": "^1.3.5", + "@types/express": "^4.17.13", + "@types/serve-index": "^1.9.1", + "@types/serve-static": "^1.13.10", + "@types/sockjs": "^0.3.33", + "@types/ws": "^8.5.1", + "ansi-html-community": "^0.0.8", + "bonjour-service": "^1.0.11", + "chokidar": "^3.5.3", + "colorette": "^2.0.10", + "compression": "^1.7.4", + "connect-history-api-fallback": "^2.0.0", + "default-gateway": "^6.0.3", + "express": "^4.17.3", + "graceful-fs": "^4.2.6", + "html-entities": "^2.3.2", + "http-proxy-middleware": "^2.0.3", + "ipaddr.js": "^2.0.1", + "open": "^8.0.9", + "p-retry": "^4.5.0", + "rimraf": "^3.0.2", + "schema-utils": "^4.0.0", + "selfsigned": "^2.1.1", + "serve-index": "^1.9.1", + "sockjs": "^0.3.24", + "spdy": "^4.0.2", + "webpack-dev-middleware": "^5.3.1", + "ws": "^8.4.2" + }, + "bin": { + "webpack-dev-server": "bin/webpack-dev-server.js" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.37.0 || ^5.0.0" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-dev-server/node_modules/webpack-dev-middleware": { + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.4.tgz", + "integrity": "sha512-BVdTqhhs+0IfoeAf7EoH5WE+exCmqGerHfDM0IL096Px60Tq2Mn9MAbnaGUe6HiMa41KMCYF19gyzZmBcq/o4Q==", + "dev": true, + "dependencies": { + "colorette": "^2.0.10", + "memfs": "^3.4.3", + "mime-types": "^2.1.31", + "range-parser": "^1.2.1", + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/webpack-dev-server/node_modules/ws": { + "version": "8.14.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.14.2.tgz", + "integrity": "sha512-wEBG1ftX4jcglPxgFCMJmZ2PLtSbJ2Peg6TmpJFTbe9GZYOQCDPdMYu/Tm0/bGZkw8paZnJY45J4K2PZrLYq8g==", + "dev": true, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/webpack-merge": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.8.0.tgz", + "integrity": "sha512-/SaI7xY0831XwP6kzuwhKWVKDP9t1QY1h65lAFLbZqMPIuYcD9QAW4u9STIbU9kaJbPBB/geU/gLr1wDjOhQ+Q==", + "dev": true, + "dependencies": { + "clone-deep": "^4.0.1", + "wildcard": "^2.0.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/webpack-sources": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", + "dev": true, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/webpack-subresource-integrity": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/webpack-subresource-integrity/-/webpack-subresource-integrity-5.1.0.tgz", + "integrity": "sha512-sacXoX+xd8r4WKsy9MvH/q/vBtEHr86cpImXwyg74pFIpERKt6FmB8cXpeuh0ZLgclOlHI4Wcll7+R5L02xk9Q==", + "dev": true, + "dependencies": { + "typed-assert": "^1.0.8" + }, + "engines": { + "node": ">= 12" + }, + "peerDependencies": { + "html-webpack-plugin": ">= 5.0.0-beta.1 < 6", + "webpack": "^5.12.0" + }, + "peerDependenciesMeta": { + "html-webpack-plugin": { + "optional": true + } + } + }, + "node_modules/webpack/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/webpack/node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/webpack/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/webpack/node_modules/schema-utils": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", + "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/websocket-driver": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", + "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", + "dev": true, + "dependencies": { + "http-parser-js": ">=0.5.1", + "safe-buffer": ">=5.1.0", + "websocket-extensions": ">=0.1.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/websocket-extensions": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", + "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dev": true, + "dependencies": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/wide-align": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "dev": true, + "dependencies": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, + "node_modules/wildcard": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.0.tgz", + "integrity": "sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw==", + "dev": true + }, + "node_modules/wmf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wmf/-/wmf-1.0.2.tgz", + "integrity": "sha512-/p9K7bEh0Dj6WbXg4JG0xvLQmIadrner1bi45VMJTfnbVHsc7yIajZyoSoK60/dtVBs12Fm6WkUI5/3WAVsNMw==", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/word": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/word/-/word-0.3.0.tgz", + "integrity": "sha512-OELeY0Q61OXpdUfTp+oweA/vtLVg5VDOXh+3he3PNzLGG/y0oylSOC1xRVj0+l4vQ3tj/bB1HVHv1ocXkQceFA==", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/wrap-ansi/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "node_modules/ws": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", + "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==", + "dev": true, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xlsx": { + "version": "0.18.5", + "resolved": "https://registry.npmjs.org/xlsx/-/xlsx-0.18.5.tgz", + "integrity": "sha512-dmg3LCjBPHZnQp5/F/+nnTa+miPJxUXB6vtk42YjBBKayDNagxGEeIdWApkYPOf3Z3pm3k62Knjzp7lMeTEtFQ==", + "dependencies": { + "adler-32": "~1.3.0", + "cfb": "~1.2.1", + "codepage": "~1.15.0", + "crc-32": "~1.2.1", + "ssf": "~0.11.2", + "wmf": "~1.0.1", + "word": "~0.3.0" + }, + "bin": { + "xlsx": "bin/xlsx.njs" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==" + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/yargs": { + "version": "17.6.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.6.2.tgz", + "integrity": "sha512-1/9UrdHjDZc0eOU0HxOHoS78C69UD3JRMvzlJ7S79S2nTaWRA/whGCTV8o9e/N/1Va9YIV7Q4sOxD8VV4pCWOw==", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs/node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/zip-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-4.1.0.tgz", + "integrity": "sha512-zshzwQW7gG7hjpBlgeQP9RuyPGNxvJdzR8SUM3QhxCnLjWN2E7j3dOvpeDcQoETfHx0urRS7EtmVToql7YpU4A==", + "dependencies": { + "archiver-utils": "^2.1.0", + "compress-commons": "^4.1.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/zone.js": { + "version": "0.11.5", + "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.11.5.tgz", + "integrity": "sha512-D1/7VxEuQ7xk6z/kAROe4SUbd9CzxY4zOwVGnGHerd/SgLIVU5f4esDzQUsOCeArn933BZfWMKydH7l7dPEp0g==", + "dependencies": { + "tslib": "^2.3.0" + } + } + }, + "dependencies": { + "@ampproject/remapping": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", + "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", + "requires": { + "@jridgewell/gen-mapping": "^0.1.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "@angular-devkit/architect": { + "version": "0.1502.10", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1502.10.tgz", + "integrity": "sha512-S8lN73WYCfpEpw1Q41ZcUinw7JfDeSM8LyGs797OVshnW75QcOkOecWj/3CKR23G44IgFrHN6sqtzWxKmMxLig==", + "dev": true, + "requires": { + "@angular-devkit/core": "15.2.10", + "rxjs": "6.6.7" + }, + "dependencies": { + "rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + }, + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "@angular-devkit/build-angular": { + "version": "15.2.11", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-15.2.11.tgz", + "integrity": "sha512-MnpVCJdk5jHuK7CH/cTcRT0JQkkKkRTEV3WTyOUhTm0O3PlKwvTM6/Sner+zyuhKyw5VFBBMypHh59aTUDEZ1A==", + "dev": true, + "requires": { + "@ampproject/remapping": "2.2.0", + "@angular-devkit/architect": "0.1502.11", + "@angular-devkit/build-webpack": "0.1502.11", + "@angular-devkit/core": "15.2.11", + "@babel/core": "7.20.12", + "@babel/generator": "7.20.14", + "@babel/helper-annotate-as-pure": "7.18.6", + "@babel/helper-split-export-declaration": "7.18.6", + "@babel/plugin-proposal-async-generator-functions": "7.20.7", + "@babel/plugin-transform-async-to-generator": "7.20.7", + "@babel/plugin-transform-runtime": "7.19.6", + "@babel/preset-env": "7.20.2", + "@babel/runtime": "7.20.13", + "@babel/template": "7.20.7", + "@discoveryjs/json-ext": "0.5.7", + "@ngtools/webpack": "15.2.11", + "ansi-colors": "4.1.3", + "autoprefixer": "10.4.13", + "babel-loader": "9.1.2", + "babel-plugin-istanbul": "6.1.1", + "browserslist": "4.21.5", + "cacache": "17.0.4", + "chokidar": "3.5.3", + "copy-webpack-plugin": "11.0.0", + "critters": "0.0.16", + "css-loader": "6.7.3", + "esbuild": "0.17.8", + "esbuild-wasm": "0.17.8", + "glob": "8.1.0", + "https-proxy-agent": "5.0.1", + "inquirer": "8.2.4", + "jsonc-parser": "3.2.0", + "karma-source-map-support": "1.4.0", + "less": "4.1.3", + "less-loader": "11.1.0", + "license-webpack-plugin": "4.0.2", + "loader-utils": "3.2.1", + "magic-string": "0.29.0", + "mini-css-extract-plugin": "2.7.2", + "open": "8.4.1", + "ora": "5.4.1", + "parse5-html-rewriting-stream": "7.0.0", + "piscina": "3.2.0", + "postcss": "8.4.31", + "postcss-loader": "7.0.2", + "resolve-url-loader": "5.0.0", + "rxjs": "6.6.7", + "sass": "1.58.1", + "sass-loader": "13.2.0", + "semver": "7.5.3", + "source-map-loader": "4.0.1", + "source-map-support": "0.5.21", + "terser": "5.16.3", + "text-table": "0.2.0", + "tree-kill": "1.2.2", + "tslib": "2.5.0", + "webpack": "5.76.1", + "webpack-dev-middleware": "6.1.2", + "webpack-dev-server": "4.11.1", + "webpack-merge": "5.8.0", + "webpack-subresource-integrity": "5.1.0" + }, + "dependencies": { + "@angular-devkit/architect": { + "version": "0.1502.11", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1502.11.tgz", + "integrity": "sha512-+hkG5UjIaKMRdo6SFLNQs+Cv7yAVeN8ijfDwI2z/mp7/otowuSEy+H3Tii195jfJ8TQ+y1B7svnx2D6O7oOYbQ==", + "dev": true, + "requires": { + "@angular-devkit/core": "15.2.11", + "rxjs": "6.6.7" + } + }, + "@angular-devkit/core": { + "version": "15.2.11", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-15.2.11.tgz", + "integrity": "sha512-zd6QelJ8pOPvz6TsehR0JqixjDjzgEOkKywBJBuwNXY+Nw3MJGayJeWS0UgC+Gk+LoTkpI21RoyaYELkAmD/tw==", + "dev": true, + "requires": { + "ajv": "8.12.0", + "ajv-formats": "2.1.1", + "jsonc-parser": "3.2.0", + "rxjs": "6.6.7", + "source-map": "0.7.4" + } + }, + "@babel/core": { + "version": "7.20.12", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.20.12.tgz", + "integrity": "sha512-XsMfHovsUYHFMdrIHkZphTN/2Hzzi78R08NuHfDBehym2VsPDL6Zn/JAD/JQdnRvbSsbQc4mVaU1m6JgtTEElg==", + "dev": true, + "requires": { + "@ampproject/remapping": "^2.1.0", + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.20.7", + "@babel/helper-compilation-targets": "^7.20.7", + "@babel/helper-module-transforms": "^7.20.11", + "@babel/helpers": "^7.20.7", + "@babel/parser": "^7.20.7", + "@babel/template": "^7.20.7", + "@babel/traverse": "^7.20.12", + "@babel/types": "^7.20.7", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.2", + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true + } + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", + "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", + "dev": true, + "requires": { + "@babel/types": "^7.18.6" + } + }, + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + }, + "browserslist": { + "version": "4.21.5", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz", + "integrity": "sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30001449", + "electron-to-chromium": "^1.4.284", + "node-releases": "^2.0.8", + "update-browserslist-db": "^1.0.10" + } + }, + "glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + } + }, + "minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + }, + "rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "semver": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz", + "integrity": "sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + } + } + }, + "@angular-devkit/build-webpack": { + "version": "0.1502.11", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1502.11.tgz", + "integrity": "sha512-OTONIRp770Jfems4+cULmtoeSzjnpx5UjV2EazojnhRXXBSJMWRMPvwD2QvQl9UO/6eOV3d2mgmP2xOZgc/D6w==", + "dev": true, + "requires": { + "@angular-devkit/architect": "0.1502.11", + "rxjs": "6.6.7" + }, + "dependencies": { + "@angular-devkit/architect": { + "version": "0.1502.11", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1502.11.tgz", + "integrity": "sha512-+hkG5UjIaKMRdo6SFLNQs+Cv7yAVeN8ijfDwI2z/mp7/otowuSEy+H3Tii195jfJ8TQ+y1B7svnx2D6O7oOYbQ==", + "dev": true, + "requires": { + "@angular-devkit/core": "15.2.11", + "rxjs": "6.6.7" + } + }, + "@angular-devkit/core": { + "version": "15.2.11", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-15.2.11.tgz", + "integrity": "sha512-zd6QelJ8pOPvz6TsehR0JqixjDjzgEOkKywBJBuwNXY+Nw3MJGayJeWS0UgC+Gk+LoTkpI21RoyaYELkAmD/tw==", + "dev": true, + "requires": { + "ajv": "8.12.0", + "ajv-formats": "2.1.1", + "jsonc-parser": "3.2.0", + "rxjs": "6.6.7", + "source-map": "0.7.4" + } + }, + "rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + }, + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "@angular-devkit/core": { + "version": "15.2.10", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-15.2.10.tgz", + "integrity": "sha512-bFPm7wjvfBds9km2rCJxUhzkqe4h3h/199yJtzC1bNvwRr2LMHvtyoQAzftda+gs7Ulqac5wzUEZX/cVV3WrsA==", + "dev": true, + "requires": { + "ajv": "8.12.0", + "ajv-formats": "2.1.1", + "jsonc-parser": "3.2.0", + "rxjs": "6.6.7", + "source-map": "0.7.4" + }, + "dependencies": { + "rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + }, + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "@angular-devkit/schematics": { + "version": "15.2.10", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-15.2.10.tgz", + "integrity": "sha512-EeoDs4oKFpLZNa21G/8dqBdclEc4U2piI9EeXCVTaN6z5DYXIZ0G1WtCXU8nhD+GckS47rmfZ4/3lMaXAvED+g==", + "dev": true, + "requires": { + "@angular-devkit/core": "15.2.10", + "jsonc-parser": "3.2.0", + "magic-string": "0.29.0", + "ora": "5.4.1", + "rxjs": "6.6.7" + }, + "dependencies": { + "rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + }, + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "@angular/animations": { + "version": "15.2.10", + "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-15.2.10.tgz", + "integrity": "sha512-yxfN8qQpMaukRU5LjFkJBmy85rqrOp86tYVCsf+hmPEFRiXBMUj6xYLeCMcpk3Mt1JtnWGBR34ivGx+7bNeAow==", + "requires": { + "tslib": "^2.3.0" + } + }, + "@angular/cdk": { + "version": "13.3.8", + "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-13.3.8.tgz", + "integrity": "sha512-ciLYoVxsqnA9hGJTUW74A56NjArYhFdqFYmVDimWWNYAgY7jY1gCfKq9UtixUErDi29FGSCWRbLuZ6w4q0NYnA==", + "requires": { + "parse5": "^5.0.0", + "tslib": "^2.3.0" + } + }, + "@angular/cli": { + "version": "15.2.10", + "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-15.2.10.tgz", + "integrity": "sha512-/TSnm/ZQML6A4lvunyN2tjTB5utuvk3d1Pnfyehp/FXtV6YfZm6+EZrOpKkKPCxTuAgW6c9KK4yQtt3RuNVpwQ==", + "dev": true, + "requires": { + "@angular-devkit/architect": "0.1502.10", + "@angular-devkit/core": "15.2.10", + "@angular-devkit/schematics": "15.2.10", + "@schematics/angular": "15.2.10", + "@yarnpkg/lockfile": "1.1.0", + "ansi-colors": "4.1.3", + "ini": "3.0.1", + "inquirer": "8.2.4", + "jsonc-parser": "3.2.0", + "npm-package-arg": "10.1.0", + "npm-pick-manifest": "8.0.1", + "open": "8.4.1", + "ora": "5.4.1", + "pacote": "15.1.0", + "resolve": "1.22.1", + "semver": "7.5.3", + "symbol-observable": "4.0.0", + "yargs": "17.6.2" + }, + "dependencies": { + "semver": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz", + "integrity": "sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + } + } + }, + "@angular/common": { + "version": "15.2.10", + "resolved": "https://registry.npmjs.org/@angular/common/-/common-15.2.10.tgz", + "integrity": "sha512-jdBn3fctkqoNrJn9VLsUHpcCEhCxWSczdsR+BBbD6T0oLl6vMrAVNjPwfBejnlgfWN1KoRU9kgOYsMxa5apIWQ==", + "requires": { + "tslib": "^2.3.0" + } + }, + "@angular/compiler": { + "version": "15.2.10", + "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-15.2.10.tgz", + "integrity": "sha512-M0XkeU0O73UlJZwDvOyp8/apetz9UKj78eTFDseMYJDLcxe6MpkbkxqpsGZnKYDj7LIep8PmCAKEkhtenE82zw==", + "requires": { + "tslib": "^2.3.0" + } + }, + "@angular/compiler-cli": { + "version": "15.2.10", + "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-15.2.10.tgz", + "integrity": "sha512-mCFIxrs60XicKfA2o42hA7LrQvhybi9BQveWuZn/2iIEOXx7R62Iemz8E21pLWftAZHGxEW3NECfBrY1d3gVmA==", + "dev": true, + "requires": { + "@babel/core": "7.19.3", + "@jridgewell/sourcemap-codec": "^1.4.14", + "chokidar": "^3.0.0", + "convert-source-map": "^1.5.1", + "dependency-graph": "^0.11.0", + "magic-string": "^0.27.0", + "reflect-metadata": "^0.1.2", + "semver": "^7.0.0", + "tslib": "^2.3.0", + "yargs": "^17.2.1" + }, + "dependencies": { + "magic-string": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.27.0.tgz", + "integrity": "sha512-8UnnX2PeRAPZuN12svgR9j7M1uWMovg/CEnIwIG0LFkXSJJe4PdfUGiTGl8V9bsBHFUtfVINcSyYxd7q+kx9fA==", + "dev": true, + "requires": { + "@jridgewell/sourcemap-codec": "^1.4.13" + } + } + } + }, + "@angular/core": { + "version": "15.2.10", + "resolved": "https://registry.npmjs.org/@angular/core/-/core-15.2.10.tgz", + "integrity": "sha512-meGGidnitQJGDxYd9/LrqYiVlId+vGaLoiLgJdKBz+o2ZO6OmXQGuNw2VBqf17/Cc0/UjzrOY7+kILNFKkk/WQ==", + "requires": { + "tslib": "^2.3.0" + } + }, + "@angular/forms": { + "version": "15.2.10", + "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-15.2.10.tgz", + "integrity": "sha512-NIntGsNcN6o8L1txsbWXOf6f3K/CUBizdKsxsYVYGJIXEW5qU6UnWmfAZffNNXsT/XvbgUCjgDwT0cAwcqZPuQ==", + "requires": { + "tslib": "^2.3.0" + } + }, + "@angular/localize": { + "version": "15.2.10", + "resolved": "https://registry.npmjs.org/@angular/localize/-/localize-15.2.10.tgz", + "integrity": "sha512-RHN+mUR4H34c/LLnNPAyQbfuZME4i9JgodK5YRRX8cSAFPafYLT0SspSuLsKtcCCEDadAZNDHzb8qv5MBtzJtg==", + "requires": { + "@babel/core": "7.19.3", + "glob": "8.1.0", + "yargs": "^17.2.1" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "requires": { + "balanced-match": "^1.0.0" + } + }, + "glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + } + }, + "minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "requires": { + "brace-expansion": "^2.0.1" + } + } + } + }, + "@angular/platform-browser": { + "version": "15.2.10", + "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-15.2.10.tgz", + "integrity": "sha512-9tbgVGSJqwfrOzT8aA/kWBLNhJSQ9gUg0CJxwFBSJm8VkBUJrszoBlDsnSvlxx8/W2ejNULKHFTXeUzq0O/+RQ==", + "requires": { + "tslib": "^2.3.0" + } + }, + "@angular/platform-browser-dynamic": { + "version": "15.2.10", + "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-15.2.10.tgz", + "integrity": "sha512-JHP6W+FX715Qv7DhqvfZLuBZXSDJrboiQsR06gUAgDSjAUyhbqmpVg/2YOtgeWpPkzNDtXdPU2PhcRdIv5J3Yg==", + "requires": { + "tslib": "^2.3.0" + } + }, + "@angular/router": { + "version": "15.2.10", + "resolved": "https://registry.npmjs.org/@angular/router/-/router-15.2.10.tgz", + "integrity": "sha512-LmuqEg0iIXSw7bli6HKJ19cbxP91v37GtRwbGKswyLihqzTgvjBYpvcfMnB5FRQ5LWkTwq5JclkX03dZw290Yg==", + "requires": { + "tslib": "^2.3.0" + } + }, + "@assemblyscript/loader": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/@assemblyscript/loader/-/loader-0.10.1.tgz", + "integrity": "sha512-H71nDOOL8Y7kWRLqf6Sums+01Q5msqBW2KhDUTemh1tvY04eSkSXrK0uj/4mmY0Xr16/3zyZmsrxN7CKuRbNRg==", + "dev": true + }, + "@azure/msal-angular": { + "version": "2.5.4", + "resolved": "https://registry.npmjs.org/@azure/msal-angular/-/msal-angular-2.5.4.tgz", + "integrity": "sha512-BX83pkTBlVP8oEC33MmGqXYY+WYm1jl/WyVndoeO5Q8tFvlqdANVIrdsgnCW3LAXx8L4tJIDIs32E8WHManMEQ==", + "requires": { + "tslib": "^2.0.0" + } + }, + "@azure/msal-browser": { + "version": "2.34.0", + "resolved": "https://registry.npmjs.org/@azure/msal-browser/-/msal-browser-2.34.0.tgz", + "integrity": "sha512-stoXdlfAtyVIMOp1lS5PorgO5f66MGRi3Q1FBlXhVZFTsTfAWrNdSOx1m/PXWHskWE9aXO+NEzXVOoWmDNnvNA==", + "requires": { + "@azure/msal-common": "^11.0.0" + } + }, + "@azure/msal-common": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/@azure/msal-common/-/msal-common-11.0.0.tgz", + "integrity": "sha512-SZH8ObQ3Hq5v3ogVGBYJp1nNW7p+MtM4PH4wfNadBP9wf7K0beQHF9iOtRcjPOkwZf+ZD49oXqw91LndIkdk8g==" + }, + "@babel/code-frame": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz", + "integrity": "sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==", + "requires": { + "@babel/highlight": "^7.23.4", + "chalk": "^2.4.2" + } + }, + "@babel/compat-data": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.5.tgz", + "integrity": "sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw==" + }, + "@babel/core": { + "version": "7.19.3", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.19.3.tgz", + "integrity": "sha512-WneDJxdsjEvyKtXKsaBGbDeiyOjR5vYq4HcShxnIbG0qixpoHjI3MqeZM9NDvsojNCEBItQE4juOo/bU6e72gQ==", + "requires": { + "@ampproject/remapping": "^2.1.0", + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.19.3", + "@babel/helper-compilation-targets": "^7.19.3", + "@babel/helper-module-transforms": "^7.19.0", + "@babel/helpers": "^7.19.0", + "@babel/parser": "^7.19.3", + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.19.3", + "@babel/types": "^7.19.3", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.1", + "semver": "^6.3.0" + }, + "dependencies": { + "@babel/generator": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.5.tgz", + "integrity": "sha512-BPssCHrBD+0YrxviOa3QzpqwhNIXKEtOa2jQrm4FlmkC2apYgRnQcmPWiGZDlGxiNtltnUFolMe8497Esry+jA==", + "requires": { + "@babel/types": "^7.23.5", + "@jridgewell/gen-mapping": "^0.3.2", + "@jridgewell/trace-mapping": "^0.3.17", + "jsesc": "^2.5.1" + } + }, + "@jridgewell/gen-mapping": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", + "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "requires": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" + } + } + }, + "@babel/generator": { + "version": "7.20.14", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.14.tgz", + "integrity": "sha512-AEmuXHdcD3A52HHXxaTmYlb8q/xMEhoRP67B3T4Oq7lbmSoqroMZzjnGj3+i1io3pdnF8iBYVu4Ilj+c4hBxYg==", + "dev": true, + "requires": { + "@babel/types": "^7.20.7", + "@jridgewell/gen-mapping": "^0.3.2", + "jsesc": "^2.5.1" + }, + "dependencies": { + "@jridgewell/gen-mapping": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", + "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "dev": true, + "requires": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + } + } + } + }, + "@babel/helper-annotate-as-pure": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz", + "integrity": "sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA==", + "dev": true, + "requires": { + "@babel/types": "^7.18.6" + } + }, + "@babel/helper-builder-binary-assignment-operator-visitor": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.22.15.tgz", + "integrity": "sha512-QkBXwGgaoC2GtGZRoma6kv7Szfv06khvhFav67ZExau2RaXzy8MpHSMO2PNoP2XtmQphJQRHFfg77Bq731Yizw==", + "dev": true, + "requires": { + "@babel/types": "^7.22.15" + } + }, + "@babel/helper-compilation-targets": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.15.tgz", + "integrity": "sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw==", + "requires": { + "@babel/compat-data": "^7.22.9", + "@babel/helper-validator-option": "^7.22.15", + "browserslist": "^4.21.9", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "dependencies": { + "lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "requires": { + "yallist": "^3.0.2" + } + }, + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" + }, + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" + } + } + }, + "@babel/helper-create-class-features-plugin": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.23.5.tgz", + "integrity": "sha512-QELlRWxSpgdwdJzSJn4WAhKC+hvw/AtHbbrIoncKHkhKKR/luAlKkgBDcri1EzWAo8f8VvYVryEHN4tax/V67A==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-member-expression-to-functions": "^7.23.0", + "@babel/helper-optimise-call-expression": "^7.22.5", + "@babel/helper-replace-supers": "^7.22.20", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "semver": "^6.3.1" + }, + "dependencies": { + "@babel/helper-annotate-as-pure": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz", + "integrity": "sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==", + "dev": true, + "requires": { + "@babel/types": "^7.22.5" + } + }, + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true + } + } + }, + "@babel/helper-create-regexp-features-plugin": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.22.15.tgz", + "integrity": "sha512-29FkPLFjn4TPEa3RE7GpW+qbE8tlsu3jntNYNfcGsc49LphF1PQIiD+vMZ1z1xVOKt+93khA9tc2JBs3kBjA7w==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "regexpu-core": "^5.3.1", + "semver": "^6.3.1" + }, + "dependencies": { + "@babel/helper-annotate-as-pure": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz", + "integrity": "sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==", + "dev": true, + "requires": { + "@babel/types": "^7.22.5" + } + }, + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true + } + } + }, + "@babel/helper-define-polyfill-provider": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.3.tgz", + "integrity": "sha512-z5aQKU4IzbqCC1XH0nAqfsFLMVSo22SBKUc0BxGrLkolTdPTructy0ToNnlO2zA4j9Q/7pjMZf0DSY+DSTYzww==", + "dev": true, + "requires": { + "@babel/helper-compilation-targets": "^7.17.7", + "@babel/helper-plugin-utils": "^7.16.7", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2", + "semver": "^6.1.2" + }, + "dependencies": { + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true + } + } + }, + "@babel/helper-environment-visitor": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==" + }, + "@babel/helper-function-name": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", + "requires": { + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" + }, + "dependencies": { + "@babel/template": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", + "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", + "requires": { + "@babel/code-frame": "^7.22.13", + "@babel/parser": "^7.22.15", + "@babel/types": "^7.22.15" + } + } + } + }, + "@babel/helper-hoist-variables": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", + "requires": { + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-member-expression-to-functions": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.23.0.tgz", + "integrity": "sha512-6gfrPwh7OuT6gZyJZvd6WbTfrqAo7vm4xCzAXOusKqq/vWdKXphTpj5klHKNmRUU6/QRGlBsyU9mAIPaWHlqJA==", + "dev": true, + "requires": { + "@babel/types": "^7.23.0" + } + }, + "@babel/helper-module-imports": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz", + "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==", + "requires": { + "@babel/types": "^7.22.15" + } + }, + "@babel/helper-module-transforms": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz", + "integrity": "sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==", + "requires": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-module-imports": "^7.22.15", + "@babel/helper-simple-access": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/helper-validator-identifier": "^7.22.20" + } + }, + "@babel/helper-optimise-call-expression": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.22.5.tgz", + "integrity": "sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw==", + "dev": true, + "requires": { + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==", + "dev": true + }, + "@babel/helper-remap-async-to-generator": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.22.20.tgz", + "integrity": "sha512-pBGyV4uBqOns+0UvhsTO8qgl8hO89PmiDYv+/COyp1aeMcmfrfruz+/nCMFiYyFF/Knn0yfrC85ZzNFjembFTw==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-wrap-function": "^7.22.20" + }, + "dependencies": { + "@babel/helper-annotate-as-pure": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz", + "integrity": "sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==", + "dev": true, + "requires": { + "@babel/types": "^7.22.5" + } + } + } + }, + "@babel/helper-replace-supers": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.22.20.tgz", + "integrity": "sha512-qsW0In3dbwQUbK8kejJ4R7IHVGwHJlV6lpG6UA7a9hSa2YEiAib+N1T2kr6PEeUT+Fl7najmSOS6SmAwCHK6Tw==", + "dev": true, + "requires": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-member-expression-to-functions": "^7.22.15", + "@babel/helper-optimise-call-expression": "^7.22.5" + } + }, + "@babel/helper-simple-access": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", + "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", + "requires": { + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.22.5.tgz", + "integrity": "sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q==", + "dev": true, + "requires": { + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", + "requires": { + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-string-parser": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz", + "integrity": "sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==" + }, + "@babel/helper-validator-identifier": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==" + }, + "@babel/helper-validator-option": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz", + "integrity": "sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==" + }, + "@babel/helper-wrap-function": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.22.20.tgz", + "integrity": "sha512-pms/UwkOpnQe/PDAEdV/d7dVCoBbB+R4FvYoHGZz+4VPcg7RtYy2KP7S2lbuWM6FCSgob5wshfGESbC/hzNXZw==", + "dev": true, + "requires": { + "@babel/helper-function-name": "^7.22.5", + "@babel/template": "^7.22.15", + "@babel/types": "^7.22.19" + }, + "dependencies": { + "@babel/template": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", + "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.22.13", + "@babel/parser": "^7.22.15", + "@babel/types": "^7.22.15" + } + } + } + }, + "@babel/helpers": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.5.tgz", + "integrity": "sha512-oO7us8FzTEsG3U6ag9MfdF1iA/7Z6dz+MtFhifZk8C8o453rGJFFWUP1t+ULM9TUIAzC9uxXEiXjOiVMyd7QPg==", + "requires": { + "@babel/template": "^7.22.15", + "@babel/traverse": "^7.23.5", + "@babel/types": "^7.23.5" + }, + "dependencies": { + "@babel/template": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", + "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", + "requires": { + "@babel/code-frame": "^7.22.13", + "@babel/parser": "^7.22.15", + "@babel/types": "^7.22.15" + } + } + } + }, + "@babel/highlight": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz", + "integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==", + "requires": { + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.5.tgz", + "integrity": "sha512-hOOqoiNXrmGdFbhgCzu6GiURxUgM27Xwd/aPuu8RfHEZPBzL1Z54okAHAQjXfcQNwvrlkAmAp4SlRTZ45vlthQ==" + }, + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.23.3.tgz", + "integrity": "sha512-iRkKcCqb7iGnq9+3G6rZ+Ciz5VywC4XNRHe57lKM+jOeYAoR0lVqdeeDRfh0tQcTfw/+vBhHn926FmQhLtlFLQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.23.3.tgz", + "integrity": "sha512-WwlxbfMNdVEpQjZmK5mhm7oSwD3dS6eU+Iwsi4Knl9wAletWem7kaRsGOG+8UEbRyqxY4SS5zvtfXwX+jMxUwQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/plugin-transform-optional-chaining": "^7.23.3" + } + }, + "@babel/plugin-proposal-async-generator-functions": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.20.7.tgz", + "integrity": "sha512-xMbiLsn/8RK7Wq7VeVytytS2L6qE69bXPB10YCmMdDZbKF4okCqY74pI/jJQ/8U0b/F6NrT2+14b8/P9/3AMGA==", + "dev": true, + "requires": { + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-remap-async-to-generator": "^7.18.9", + "@babel/plugin-syntax-async-generators": "^7.8.4" + } + }, + "@babel/plugin-proposal-class-properties": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.18.6.tgz", + "integrity": "sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-proposal-class-static-block": { + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.21.0.tgz", + "integrity": "sha512-XP5G9MWNUskFuP30IfFSEFB0Z6HzLIUcjYM4bYOPHXl7eiJ9HFv8tWj6TXTN5QODiEhDZAeI4hLok2iHFFV4hw==", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.21.0", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/plugin-syntax-class-static-block": "^7.14.5" + } + }, + "@babel/plugin-proposal-dynamic-import": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.18.6.tgz", + "integrity": "sha512-1auuwmK+Rz13SJj36R+jqFPMJWyKEDd7lLSdOj4oJK0UTgGueSAtkrCvz9ewmgyU/P941Rv2fQwZJN8s6QruXw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-dynamic-import": "^7.8.3" + } + }, + "@babel/plugin-proposal-export-namespace-from": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.18.9.tgz", + "integrity": "sha512-k1NtHyOMvlDDFeb9G5PhUXuGj8m/wiwojgQVEhJ/fsVsMCpLyOP4h0uGEjYJKrRI+EVPlb5Jk+Gt9P97lOGwtA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3" + } + }, + "@babel/plugin-proposal-json-strings": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.18.6.tgz", + "integrity": "sha512-lr1peyn9kOdbYc0xr0OdHTZ5FMqS6Di+H0Fz2I/JwMzGmzJETNeOFq2pBySw6X/KFL5EWDjlJuMsUGRFb8fQgQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-json-strings": "^7.8.3" + } + }, + "@babel/plugin-proposal-logical-assignment-operators": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.20.7.tgz", + "integrity": "sha512-y7C7cZgpMIjWlKE5T7eJwp+tnRYM89HmRvWM5EQuB5BoHEONjmQ8lSNmBUwOyy/GFRsohJED51YBF79hE1djug==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" + } + }, + "@babel/plugin-proposal-nullish-coalescing-operator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.18.6.tgz", + "integrity": "sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" + } + }, + "@babel/plugin-proposal-numeric-separator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.18.6.tgz", + "integrity": "sha512-ozlZFogPqoLm8WBr5Z8UckIoE4YQ5KESVcNudyXOR8uqIkliTEgJ3RoketfG6pmzLdeZF0H/wjE9/cCEitBl7Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-numeric-separator": "^7.10.4" + } + }, + "@babel/plugin-proposal-object-rest-spread": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.20.7.tgz", + "integrity": "sha512-d2S98yCiLxDVmBmE8UjGcfPvNEUbA1U5q5WxaWFUGRzJSVAZqm5W6MbPct0jxnegUZ0niLeNX+IOzEs7wYg9Dg==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.20.5", + "@babel/helper-compilation-targets": "^7.20.7", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.20.7" + } + }, + "@babel/plugin-proposal-optional-catch-binding": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.18.6.tgz", + "integrity": "sha512-Q40HEhs9DJQyaZfUjjn6vE8Cv4GmMHCYuMGIWUnlxH6400VGxOuwWsPt4FxXxJkC/5eOzgn0z21M9gMT4MOhbw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" + } + }, + "@babel/plugin-proposal-optional-chaining": { + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.21.0.tgz", + "integrity": "sha512-p4zeefM72gpmEe2fkUr/OnOXpWEf8nAgk7ZYVqqfFiyIG7oFfVZcCrU64hWn5xp4tQ9LkV4bTIa5rD0KANpKNA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0", + "@babel/plugin-syntax-optional-chaining": "^7.8.3" + } + }, + "@babel/plugin-proposal-private-methods": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.18.6.tgz", + "integrity": "sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA==", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-proposal-private-property-in-object": { + "version": "7.21.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.11.tgz", + "integrity": "sha512-0QZ8qP/3RLDVBwBFoWAwCtgcDZJVwA5LUJRZU8x2YFfKNuFq161wK3cuGrALu5yiPu+vzwTAg/sMWVNeWeNyaw==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-create-class-features-plugin": "^7.21.0", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5" + } + }, + "@babel/plugin-proposal-unicode-property-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.18.6.tgz", + "integrity": "sha512-2BShG/d5yoZyXZfVePH91urL5wTG6ASZU9M4o03lKK8u8UW1y08OMttBSOADTcJrnPMpvDXRG3G8fyLh4ovs8w==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.12.13" + } + }, + "@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-syntax-dynamic-import": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", + "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-export-namespace-from": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", + "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@babel/plugin-syntax-import-assertions": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.23.3.tgz", + "integrity": "sha512-lPgDSU+SJLK3xmFDTV2ZRQAiM7UuUjGidwBywFavObCiZc1BeAAcMtHJKUya92hPHO+at63JJPLygilZard8jw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-transform-arrow-functions": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.23.3.tgz", + "integrity": "sha512-NzQcQrzaQPkaEwoTm4Mhyl8jI1huEL/WWIEvudjTCMJ9aBZNpsJbMASx7EQECtQQPS/DcnFpo0FIh3LvEO9cxQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-async-to-generator": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.20.7.tgz", + "integrity": "sha512-Uo5gwHPT9vgnSXQxqGtpdufUiWp96gk7yiP4Mp5bm1QMkEmLXBO7PAGYbKoJ6DhAwiNkcHFBol/x5zZZkL/t0Q==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-remap-async-to-generator": "^7.18.9" + } + }, + "@babel/plugin-transform-block-scoped-functions": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.23.3.tgz", + "integrity": "sha512-vI+0sIaPIO6CNuM9Kk5VmXcMVRiOpDh7w2zZt9GXzmE/9KD70CUEVhvPR/etAeNK/FAEkhxQtXOzVF3EuRL41A==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-block-scoping": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.23.4.tgz", + "integrity": "sha512-0QqbP6B6HOh7/8iNR4CQU2Th/bbRtBp4KS9vcaZd1fZ0wSh5Fyssg0UCIHwxh+ka+pNDREbVLQnHCMHKZfPwfw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-classes": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.23.5.tgz", + "integrity": "sha512-jvOTR4nicqYC9yzOHIhXG5emiFEOpappSJAl73SDSEDcybD+Puuze8Tnpb9p9qEyYup24tq891gkaygIFvWDqg==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-compilation-targets": "^7.22.15", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-optimise-call-expression": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-replace-supers": "^7.22.20", + "@babel/helper-split-export-declaration": "^7.22.6", + "globals": "^11.1.0" + }, + "dependencies": { + "@babel/helper-annotate-as-pure": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz", + "integrity": "sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==", + "dev": true, + "requires": { + "@babel/types": "^7.22.5" + } + } + } + }, + "@babel/plugin-transform-computed-properties": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.23.3.tgz", + "integrity": "sha512-dTj83UVTLw/+nbiHqQSFdwO9CbTtwq1DsDqm3CUEtDrZNET5rT5E6bIdTlOftDTDLMYxvxHNEYO4B9SLl8SLZw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/template": "^7.22.15" + }, + "dependencies": { + "@babel/template": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", + "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.22.13", + "@babel/parser": "^7.22.15", + "@babel/types": "^7.22.15" + } + } + } + }, + "@babel/plugin-transform-destructuring": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.23.3.tgz", + "integrity": "sha512-n225npDqjDIr967cMScVKHXJs7rout1q+tt50inyBCPkyZ8KxeI6d+GIbSBTT/w/9WdlWDOej3V9HE5Lgk57gw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-dotall-regex": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.23.3.tgz", + "integrity": "sha512-vgnFYDHAKzFaTVp+mneDsIEbnJ2Np/9ng9iviHw3P/KVcgONxpNULEW/51Z/BaFojG2GI2GwwXck5uV1+1NOYQ==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-duplicate-keys": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.23.3.tgz", + "integrity": "sha512-RrqQ+BQmU3Oyav3J+7/myfvRCq7Tbz+kKLLshUmMwNlDHExbGL7ARhajvoBJEvc+fCguPPu887N+3RRXBVKZUA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-exponentiation-operator": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.23.3.tgz", + "integrity": "sha512-5fhCsl1odX96u7ILKHBj4/Y8vipoqwsJMh4csSA8qFfxrZDEA4Ssku2DyNvMJSmZNOEBT750LfFPbtrnTP90BQ==", + "dev": true, + "requires": { + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-for-of": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.23.3.tgz", + "integrity": "sha512-X8jSm8X1CMwxmK878qsUGJRmbysKNbdpTv/O1/v0LuY/ZkZrng5WYiekYSdg9m09OTmDDUWeEDsTE+17WYbAZw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-function-name": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.23.3.tgz", + "integrity": "sha512-I1QXp1LxIvt8yLaib49dRW5Okt7Q4oaxao6tFVKS/anCdEOMtYwWVKoiOA1p34GOWIZjUK0E+zCp7+l1pfQyiw==", + "dev": true, + "requires": { + "@babel/helper-compilation-targets": "^7.22.15", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-literals": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.23.3.tgz", + "integrity": "sha512-wZ0PIXRxnwZvl9AYpqNUxpZ5BiTGrYt7kueGQ+N5FiQ7RCOD4cm8iShd6S6ggfVIWaJf2EMk8eRzAh52RfP4rQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-member-expression-literals": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.23.3.tgz", + "integrity": "sha512-sC3LdDBDi5x96LA+Ytekz2ZPk8i/Ck+DEuDbRAll5rknJ5XRTSaPKEYwomLcs1AA8wg9b3KjIQRsnApj+q51Ag==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-modules-amd": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.23.3.tgz", + "integrity": "sha512-vJYQGxeKM4t8hYCKVBlZX/gtIY2I7mRGFNcm85sgXGMTBcoV3QdVtdpbcWEbzbfUIUZKwvgFT82mRvaQIebZzw==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-modules-commonjs": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.23.3.tgz", + "integrity": "sha512-aVS0F65LKsdNOtcz6FRCpE4OgsP2OFnW46qNxNIX9h3wuzaNcSQsJysuMwqSibC98HPrf2vCgtxKNwS0DAlgcA==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-simple-access": "^7.22.5" + } + }, + "@babel/plugin-transform-modules-systemjs": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.23.3.tgz", + "integrity": "sha512-ZxyKGTkF9xT9YJuKQRo19ewf3pXpopuYQd8cDXqNzc3mUNbOME0RKMoZxviQk74hwzfQsEe66dE92MaZbdHKNQ==", + "dev": true, + "requires": { + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.20" + } + }, + "@babel/plugin-transform-modules-umd": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.23.3.tgz", + "integrity": "sha512-zHsy9iXX2nIsCBFPud3jKn1IRPWg3Ing1qOZgeKV39m1ZgIdpJqvlWVeiHBZC6ITRG0MfskhYe9cLgntfSFPIg==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.22.5.tgz", + "integrity": "sha512-YgLLKmS3aUBhHaxp5hi1WJTgOUb/NCuDHzGT9z9WTt3YG+CPRhJs6nprbStx6DnWM4dh6gt7SU3sZodbZ08adQ==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-new-target": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.23.3.tgz", + "integrity": "sha512-YJ3xKqtJMAT5/TIZnpAR3I+K+WaDowYbN3xyxI8zxx/Gsypwf9B9h0VB+1Nh6ACAAPRS5NSRje0uVv5i79HYGQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-object-super": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.23.3.tgz", + "integrity": "sha512-BwQ8q0x2JG+3lxCVFohg+KbQM7plfpBwThdW9A6TMtWwLsbDA01Ek2Zb/AgDN39BiZsExm4qrXxjk+P1/fzGrA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-replace-supers": "^7.22.20" + } + }, + "@babel/plugin-transform-optional-chaining": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.23.4.tgz", + "integrity": "sha512-ZU8y5zWOfjM5vZ+asjgAPwDaBjJzgufjES89Rs4Lpq63O300R/kOz30WCLo6BxxX6QVEilwSlpClnG5cZaikTA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/plugin-syntax-optional-chaining": "^7.8.3" + } + }, + "@babel/plugin-transform-parameters": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.23.3.tgz", + "integrity": "sha512-09lMt6UsUb3/34BbECKVbVwrT9bO6lILWln237z7sLaWnMsTi7Yc9fhX5DLpkJzAGfaReXI22wP41SZmnAA3Vw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-property-literals": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.23.3.tgz", + "integrity": "sha512-jR3Jn3y7cZp4oEWPFAlRsSWjxKe4PZILGBSd4nis1TsC5qeSpb+nrtihJuDhNI7QHiVbUaiXa0X2RZY3/TI6Nw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-regenerator": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.23.3.tgz", + "integrity": "sha512-KP+75h0KghBMcVpuKisx3XTu9Ncut8Q8TuvGO4IhY+9D5DFEckQefOuIsB/gQ2tG71lCke4NMrtIPS8pOj18BQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.22.5", + "regenerator-transform": "^0.15.2" + } + }, + "@babel/plugin-transform-reserved-words": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.23.3.tgz", + "integrity": "sha512-QnNTazY54YqgGxwIexMZva9gqbPa15t/x9VS+0fsEFWplwVpXYZivtgl43Z1vMpc1bdPP2PP8siFeVcnFvA3Cg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-runtime": { + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.19.6.tgz", + "integrity": "sha512-PRH37lz4JU156lYFW1p8OxE5i7d6Sl/zV58ooyr+q1J1lnQPyg5tIiXlIwNVhJaY4W3TmOtdc8jqdXQcB1v5Yw==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-plugin-utils": "^7.19.0", + "babel-plugin-polyfill-corejs2": "^0.3.3", + "babel-plugin-polyfill-corejs3": "^0.6.0", + "babel-plugin-polyfill-regenerator": "^0.4.1", + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true + } + } + }, + "@babel/plugin-transform-shorthand-properties": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.23.3.tgz", + "integrity": "sha512-ED2fgqZLmexWiN+YNFX26fx4gh5qHDhn1O2gvEhreLW2iI63Sqm4llRLCXALKrCnbN4Jy0VcMQZl/SAzqug/jg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-spread": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.23.3.tgz", + "integrity": "sha512-VvfVYlrlBVu+77xVTOAoxQ6mZbnIq5FM0aGBSFEcIh03qHf+zNqA4DC/3XMUozTg7bZV3e3mZQ0i13VB6v5yUg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5" + } + }, + "@babel/plugin-transform-sticky-regex": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.23.3.tgz", + "integrity": "sha512-HZOyN9g+rtvnOU3Yh7kSxXrKbzgrm5X4GncPY1QOquu7epga5MxKHVpYu2hvQnry/H+JjckSYRb93iNfsioAGg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-template-literals": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.23.3.tgz", + "integrity": "sha512-Flok06AYNp7GV2oJPZZcP9vZdszev6vPBkHLwxwSpaIqx75wn6mUd3UFWsSsA0l8nXAKkyCmL/sR02m8RYGeHg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-typeof-symbol": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.23.3.tgz", + "integrity": "sha512-4t15ViVnaFdrPC74be1gXBSMzXk3B4Us9lP7uLRQHTFpV5Dvt33pn+2MyyNxmN3VTTm3oTrZVMUmuw3oBnQ2oQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-unicode-escapes": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.23.3.tgz", + "integrity": "sha512-OMCUx/bU6ChE3r4+ZdylEqAjaQgHAgipgW8nsCfu5pGqDcFytVd91AwRvUJSBZDz0exPGgnjoqhgRYLRjFZc9Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-unicode-regex": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.23.3.tgz", + "integrity": "sha512-wMHpNA4x2cIA32b/ci3AfwNgheiva2W0WUKWTK7vBHBhDKfPsc5cFGNWm69WBqpwd86u1qwZ9PWevKqm1A3yAw==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/preset-env": { + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.20.2.tgz", + "integrity": "sha512-1G0efQEWR1EHkKvKHqbG+IN/QdgwfByUpM5V5QroDzGV2t3S/WXNQd693cHiHTlCFMpr9B6FkPFXDA2lQcKoDg==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.20.1", + "@babel/helper-compilation-targets": "^7.20.0", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-validator-option": "^7.18.6", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.18.6", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.18.9", + "@babel/plugin-proposal-async-generator-functions": "^7.20.1", + "@babel/plugin-proposal-class-properties": "^7.18.6", + "@babel/plugin-proposal-class-static-block": "^7.18.6", + "@babel/plugin-proposal-dynamic-import": "^7.18.6", + "@babel/plugin-proposal-export-namespace-from": "^7.18.9", + "@babel/plugin-proposal-json-strings": "^7.18.6", + "@babel/plugin-proposal-logical-assignment-operators": "^7.18.9", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.18.6", + "@babel/plugin-proposal-numeric-separator": "^7.18.6", + "@babel/plugin-proposal-object-rest-spread": "^7.20.2", + "@babel/plugin-proposal-optional-catch-binding": "^7.18.6", + "@babel/plugin-proposal-optional-chaining": "^7.18.9", + "@babel/plugin-proposal-private-methods": "^7.18.6", + "@babel/plugin-proposal-private-property-in-object": "^7.18.6", + "@babel/plugin-proposal-unicode-property-regex": "^7.18.6", + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3", + "@babel/plugin-syntax-import-assertions": "^7.20.0", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5", + "@babel/plugin-transform-arrow-functions": "^7.18.6", + "@babel/plugin-transform-async-to-generator": "^7.18.6", + "@babel/plugin-transform-block-scoped-functions": "^7.18.6", + "@babel/plugin-transform-block-scoping": "^7.20.2", + "@babel/plugin-transform-classes": "^7.20.2", + "@babel/plugin-transform-computed-properties": "^7.18.9", + "@babel/plugin-transform-destructuring": "^7.20.2", + "@babel/plugin-transform-dotall-regex": "^7.18.6", + "@babel/plugin-transform-duplicate-keys": "^7.18.9", + "@babel/plugin-transform-exponentiation-operator": "^7.18.6", + "@babel/plugin-transform-for-of": "^7.18.8", + "@babel/plugin-transform-function-name": "^7.18.9", + "@babel/plugin-transform-literals": "^7.18.9", + "@babel/plugin-transform-member-expression-literals": "^7.18.6", + "@babel/plugin-transform-modules-amd": "^7.19.6", + "@babel/plugin-transform-modules-commonjs": "^7.19.6", + "@babel/plugin-transform-modules-systemjs": "^7.19.6", + "@babel/plugin-transform-modules-umd": "^7.18.6", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.19.1", + "@babel/plugin-transform-new-target": "^7.18.6", + "@babel/plugin-transform-object-super": "^7.18.6", + "@babel/plugin-transform-parameters": "^7.20.1", + "@babel/plugin-transform-property-literals": "^7.18.6", + "@babel/plugin-transform-regenerator": "^7.18.6", + "@babel/plugin-transform-reserved-words": "^7.18.6", + "@babel/plugin-transform-shorthand-properties": "^7.18.6", + "@babel/plugin-transform-spread": "^7.19.0", + "@babel/plugin-transform-sticky-regex": "^7.18.6", + "@babel/plugin-transform-template-literals": "^7.18.9", + "@babel/plugin-transform-typeof-symbol": "^7.18.9", + "@babel/plugin-transform-unicode-escapes": "^7.18.10", + "@babel/plugin-transform-unicode-regex": "^7.18.6", + "@babel/preset-modules": "^0.1.5", + "@babel/types": "^7.20.2", + "babel-plugin-polyfill-corejs2": "^0.3.3", + "babel-plugin-polyfill-corejs3": "^0.6.0", + "babel-plugin-polyfill-regenerator": "^0.4.1", + "core-js-compat": "^3.25.1", + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true + } + } + }, + "@babel/preset-modules": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6.tgz", + "integrity": "sha512-ID2yj6K/4lKfhuU3+EX4UvNbIt7eACFbHmNUjzA+ep+B5971CknnA/9DEWKbRokfbbtblxxxXFJJrH47UEAMVg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", + "@babel/plugin-transform-dotall-regex": "^7.4.4", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + } + }, + "@babel/regjsgen": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@babel/regjsgen/-/regjsgen-0.8.0.tgz", + "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==", + "dev": true + }, + "@babel/runtime": { + "version": "7.20.13", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.20.13.tgz", + "integrity": "sha512-gt3PKXs0DBoL9xCvOIIZ2NEqAGZqHjAnmVbfQtB620V0uReIQutpel14KcneZuer7UioY8ALKZ7iocavvzTNFA==", + "dev": true, + "requires": { + "regenerator-runtime": "^0.13.11" + } + }, + "@babel/template": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.20.7.tgz", + "integrity": "sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==", + "requires": { + "@babel/code-frame": "^7.18.6", + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7" + } + }, + "@babel/traverse": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.5.tgz", + "integrity": "sha512-czx7Xy5a6sapWWRx61m1Ke1Ra4vczu1mCTtJam5zRTBOonfdJ+S/B6HYmGYu3fJtr8GGET3si6IhgWVBhJ/m8w==", + "requires": { + "@babel/code-frame": "^7.23.5", + "@babel/generator": "^7.23.5", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.23.5", + "@babel/types": "^7.23.5", + "debug": "^4.1.0", + "globals": "^11.1.0" + }, + "dependencies": { + "@babel/generator": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.5.tgz", + "integrity": "sha512-BPssCHrBD+0YrxviOa3QzpqwhNIXKEtOa2jQrm4FlmkC2apYgRnQcmPWiGZDlGxiNtltnUFolMe8497Esry+jA==", + "requires": { + "@babel/types": "^7.23.5", + "@jridgewell/gen-mapping": "^0.3.2", + "@jridgewell/trace-mapping": "^0.3.17", + "jsesc": "^2.5.1" + } + }, + "@jridgewell/gen-mapping": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", + "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "requires": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + } + } + } + }, + "@babel/types": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.5.tgz", + "integrity": "sha512-ON5kSOJwVO6xXVRTvOI0eOnWe7VdUcIpsovGo9U/Br4Ie4UVFQTboO2cYnDhAGU6Fp+UxSiT+pMft0SMHfuq6w==", + "requires": { + "@babel/helper-string-parser": "^7.23.4", + "@babel/helper-validator-identifier": "^7.22.20", + "to-fast-properties": "^2.0.0" + } + }, + "@colors/colors": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", + "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", + "dev": true + }, + "@discoveryjs/json-ext": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", + "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", + "dev": true + }, + "@esbuild/android-arm": { + "version": "0.17.8", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.8.tgz", + "integrity": "sha512-0/rb91GYKhrtbeglJXOhAv9RuYimgI8h623TplY2X+vA4EXnk3Zj1fXZreJ0J3OJJu1bwmb0W7g+2cT/d8/l/w==", + "dev": true, + "optional": true + }, + "@esbuild/android-arm64": { + "version": "0.17.8", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.8.tgz", + "integrity": "sha512-oa/N5j6v1svZQs7EIRPqR8f+Bf8g6HBDjD/xHC02radE/NjKHK7oQmtmLxPs1iVwYyvE+Kolo6lbpfEQ9xnhxQ==", + "dev": true, + "optional": true + }, + "@esbuild/android-x64": { + "version": "0.17.8", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.8.tgz", + "integrity": "sha512-bTliMLqD7pTOoPg4zZkXqCDuzIUguEWLpeqkNfC41ODBHwoUgZ2w5JBeYimv4oP6TDVocoYmEhZrCLQTrH89bg==", + "dev": true, + "optional": true + }, + "@esbuild/darwin-arm64": { + "version": "0.17.8", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.8.tgz", + "integrity": "sha512-ghAbV3ia2zybEefXRRm7+lx8J/rnupZT0gp9CaGy/3iolEXkJ6LYRq4IpQVI9zR97ID80KJVoUlo3LSeA/sMAg==", + "dev": true, + "optional": true + }, + "@esbuild/darwin-x64": { + "version": "0.17.8", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.8.tgz", + "integrity": "sha512-n5WOpyvZ9TIdv2V1K3/iIkkJeKmUpKaCTdun9buhGRWfH//osmUjlv4Z5mmWdPWind/VGcVxTHtLfLCOohsOXw==", + "dev": true, + "optional": true + }, + "@esbuild/freebsd-arm64": { + "version": "0.17.8", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.8.tgz", + "integrity": "sha512-a/SATTaOhPIPFWvHZDoZYgxaZRVHn0/LX1fHLGfZ6C13JqFUZ3K6SMD6/HCtwOQ8HnsNaEeokdiDSFLuizqv5A==", + "dev": true, + "optional": true + }, + "@esbuild/freebsd-x64": { + "version": "0.17.8", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.8.tgz", + "integrity": "sha512-xpFJb08dfXr5+rZc4E+ooZmayBW6R3q59daCpKZ/cDU96/kvDM+vkYzNeTJCGd8rtO6fHWMq5Rcv/1cY6p6/0Q==", + "dev": true, + "optional": true + }, + "@esbuild/linux-arm": { + "version": "0.17.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.8.tgz", + "integrity": "sha512-6Ij8gfuGszcEwZpi5jQIJCVIACLS8Tz2chnEBfYjlmMzVsfqBP1iGmHQPp7JSnZg5xxK9tjCc+pJ2WtAmPRFVA==", + "dev": true, + "optional": true + }, + "@esbuild/linux-arm64": { + "version": "0.17.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.8.tgz", + "integrity": "sha512-v3iwDQuDljLTxpsqQDl3fl/yihjPAyOguxuloON9kFHYwopeJEf1BkDXODzYyXEI19gisEsQlG1bM65YqKSIww==", + "dev": true, + "optional": true + }, + "@esbuild/linux-ia32": { + "version": "0.17.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.8.tgz", + "integrity": "sha512-8svILYKhE5XetuFk/B6raFYIyIqydQi+GngEXJgdPdI7OMKUbSd7uzR02wSY4kb53xBrClLkhH4Xs8P61Q2BaA==", + "dev": true, + "optional": true + }, + "@esbuild/linux-loong64": { + "version": "0.17.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.8.tgz", + "integrity": "sha512-B6FyMeRJeV0NpyEOYlm5qtQfxbdlgmiGdD+QsipzKfFky0K5HW5Td6dyK3L3ypu1eY4kOmo7wW0o94SBqlqBSA==", + "dev": true, + "optional": true + }, + "@esbuild/linux-mips64el": { + "version": "0.17.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.8.tgz", + "integrity": "sha512-CCb67RKahNobjm/eeEqeD/oJfJlrWyw29fgiyB6vcgyq97YAf3gCOuP6qMShYSPXgnlZe/i4a8WFHBw6N8bYAA==", + "dev": true, + "optional": true + }, + "@esbuild/linux-ppc64": { + "version": "0.17.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.8.tgz", + "integrity": "sha512-bytLJOi55y55+mGSdgwZ5qBm0K9WOCh0rx+vavVPx+gqLLhxtSFU0XbeYy/dsAAD6xECGEv4IQeFILaSS2auXw==", + "dev": true, + "optional": true + }, + "@esbuild/linux-riscv64": { + "version": "0.17.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.8.tgz", + "integrity": "sha512-2YpRyQJmKVBEHSBLa8kBAtbhucaclb6ex4wchfY0Tj3Kg39kpjeJ9vhRU7x4mUpq8ISLXRXH1L0dBYjAeqzZAw==", + "dev": true, + "optional": true + }, + "@esbuild/linux-s390x": { + "version": "0.17.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.8.tgz", + "integrity": "sha512-QgbNY/V3IFXvNf11SS6exkpVcX0LJcob+0RWCgV9OiDAmVElnxciHIisoSix9uzYzScPmS6dJFbZULdSAEkQVw==", + "dev": true, + "optional": true + }, + "@esbuild/linux-x64": { + "version": "0.17.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.8.tgz", + "integrity": "sha512-mM/9S0SbAFDBc4OPoyP6SEOo5324LpUxdpeIUUSrSTOfhHU9hEfqRngmKgqILqwx/0DVJBzeNW7HmLEWp9vcOA==", + "dev": true, + "optional": true + }, + "@esbuild/netbsd-x64": { + "version": "0.17.8", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.8.tgz", + "integrity": "sha512-eKUYcWaWTaYr9zbj8GertdVtlt1DTS1gNBWov+iQfWuWyuu59YN6gSEJvFzC5ESJ4kMcKR0uqWThKUn5o8We6Q==", + "dev": true, + "optional": true + }, + "@esbuild/openbsd-x64": { + "version": "0.17.8", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.8.tgz", + "integrity": "sha512-Vc9J4dXOboDyMXKD0eCeW0SIeEzr8K9oTHJU+Ci1mZc5njPfhKAqkRt3B/fUNU7dP+mRyralPu8QUkiaQn7iIg==", + "dev": true, + "optional": true + }, + "@esbuild/sunos-x64": { + "version": "0.17.8", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.8.tgz", + "integrity": "sha512-0xvOTNuPXI7ft1LYUgiaXtpCEjp90RuBBYovdd2lqAFxje4sEucurg30M1WIm03+3jxByd3mfo+VUmPtRSVuOw==", + "dev": true, + "optional": true + }, + "@esbuild/win32-arm64": { + "version": "0.17.8", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.8.tgz", + "integrity": "sha512-G0JQwUI5WdEFEnYNKzklxtBheCPkuDdu1YrtRrjuQv30WsYbkkoixKxLLv8qhJmNI+ATEWquZe/N0d0rpr55Mg==", + "dev": true, + "optional": true + }, + "@esbuild/win32-ia32": { + "version": "0.17.8", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.8.tgz", + "integrity": "sha512-Fqy63515xl20OHGFykjJsMnoIWS+38fqfg88ClvPXyDbLtgXal2DTlhb1TfTX34qWi3u4I7Cq563QcHpqgLx8w==", + "dev": true, + "optional": true + }, + "@esbuild/win32-x64": { + "version": "0.17.8", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.8.tgz", + "integrity": "sha512-1iuezdyDNngPnz8rLRDO2C/ZZ/emJLb72OsZeqQ6gL6Avko/XCXZw+NuxBSNhBAP13Hie418V7VMt9et1FMvpg==", + "dev": true, + "optional": true + }, + "@eslint/eslintrc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.0.tgz", + "integrity": "sha512-UWW0TMTmk2d7hLcWD1/e2g5HDM/HQ3csaLSqXCfqwh4uNDuNqlaKWXmEsL4Cs41Z0KnILNvwbHAah3C2yt06kw==", + "dev": true, + "requires": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.3.2", + "globals": "^13.15.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "dependencies": { + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "globals": { + "version": "13.15.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.15.0.tgz", + "integrity": "sha512-bpzcOlgDhMG070Av0Vy5Owklpv1I6+j96GhUI7Rh7IzDCKLzboflLrrfqMu8NquDbiR4EOQk7XzJwqVJxicxog==", + "dev": true, + "requires": { + "type-fest": "^0.20.2" + } + }, + "js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "requires": { + "argparse": "^2.0.1" + } + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true + } + } + }, + "@fast-csv/format": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/@fast-csv/format/-/format-4.3.5.tgz", + "integrity": "sha512-8iRn6QF3I8Ak78lNAa+Gdl5MJJBM5vRHivFtMRUWINdevNo00K7OXxS2PshawLKTejVwieIlPmK5YlLu6w4u8A==", + "requires": { + "@types/node": "^14.0.1", + "lodash.escaperegexp": "^4.1.2", + "lodash.isboolean": "^3.0.3", + "lodash.isequal": "^4.5.0", + "lodash.isfunction": "^3.0.9", + "lodash.isnil": "^4.0.0" + }, + "dependencies": { + "@types/node": { + "version": "14.18.18", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.18.tgz", + "integrity": "sha512-B9EoJFjhqcQ9OmQrNorItO+OwEOORNn3S31WuiHvZY/dm9ajkB7AKD/8toessEtHHNL+58jofbq7hMMY9v4yig==" + } + } + }, + "@fast-csv/parse": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/@fast-csv/parse/-/parse-4.3.6.tgz", + "integrity": "sha512-uRsLYksqpbDmWaSmzvJcuApSEe38+6NQZBUsuAyMZKqHxH0g1wcJgsKUvN3WC8tewaqFjBMMGrkHmC+T7k8LvA==", + "requires": { + "@types/node": "^14.0.1", + "lodash.escaperegexp": "^4.1.2", + "lodash.groupby": "^4.6.0", + "lodash.isfunction": "^3.0.9", + "lodash.isnil": "^4.0.0", + "lodash.isundefined": "^3.0.1", + "lodash.uniq": "^4.5.0" + }, + "dependencies": { + "@types/node": { + "version": "14.18.18", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.18.tgz", + "integrity": "sha512-B9EoJFjhqcQ9OmQrNorItO+OwEOORNn3S31WuiHvZY/dm9ajkB7AKD/8toessEtHHNL+58jofbq7hMMY9v4yig==" + } + } + }, + "@gar/promisify": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz", + "integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==", + "dev": true + }, + "@humanwhocodes/config-array": { + "version": "0.9.5", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.5.tgz", + "integrity": "sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw==", + "dev": true, + "requires": { + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.4" + } + }, + "@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true + }, + "@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "requires": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true + }, + "ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true + }, + "emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "requires": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + } + }, + "strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "requires": { + "ansi-regex": "^6.0.1" + } + }, + "wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "requires": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + } + } + } + }, + "@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "dev": true, + "requires": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + } + }, + "@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "dev": true + }, + "@jridgewell/gen-mapping": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", + "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", + "requires": { + "@jridgewell/set-array": "^1.0.0", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "@jridgewell/resolve-uri": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", + "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==" + }, + "@jridgewell/set-array": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.1.tgz", + "integrity": "sha512-Ct5MqZkLGEXTVmQYbGtx9SVqD2fqwvdubdps5D3djjAkgkKwT918VNOz65pEHFaYTeWcukmJmH5SwsA9Tn2ObQ==" + }, + "@jridgewell/source-map": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.5.tgz", + "integrity": "sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==", + "dev": true, + "requires": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "dependencies": { + "@jridgewell/gen-mapping": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", + "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "dev": true, + "requires": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + } + } + } + }, + "@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" + }, + "@jridgewell/trace-mapping": { + "version": "0.3.20", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz", + "integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==", + "requires": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "@leichtgewicht/ip-codec": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz", + "integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==", + "dev": true + }, + "@ng-bootstrap/ng-bootstrap": { + "version": "12.1.2", + "resolved": "https://registry.npmjs.org/@ng-bootstrap/ng-bootstrap/-/ng-bootstrap-12.1.2.tgz", + "integrity": "sha512-p27c+mYVdHiJMYrj5hwClVJxLdiZxafAqlbw1sdJh2xJ1rGOe+H/kCf5YDRbhlHqRN+34Gr0RQqIUeD1I2V8hg==", + "requires": { + "tslib": "^2.3.0" + } + }, + "@ng-idle/core": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/@ng-idle/core/-/core-11.1.0.tgz", + "integrity": "sha512-/hf3LDFz3UCTe2H6r1bq6Kn6mo5B5mxaU5XVqcDfE4Vdlx9evTqBXyl0VpWbuzZbohVCfWq31mEjbxg9lbY4bw==", + "requires": { + "tslib": "^2.0.0" + } + }, + "@ng-idle/keepalive": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/@ng-idle/keepalive/-/keepalive-11.0.3.tgz", + "integrity": "sha512-etnPYnDua/uaFQebDHfC40iBb22KwPVkbt24/9IJBH9A4TGZa6zBrb+8DoRiRJm8I/WBuXdCDeaWzVHElfc9pg==", + "requires": { + "tslib": "^2.0.0" + } + }, + "@ngtools/webpack": { + "version": "15.2.11", + "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-15.2.11.tgz", + "integrity": "sha512-yqp+FziuJ+wIVij4eTqfhuiTPNaG1PU8ukeGOdqkVH4nQMlmzs9UldXy1iYC/6swzn6XO/pkqisU3m/jxemMzA==", + "dev": true + }, + "@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + } + }, + "@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true + }, + "@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "requires": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + } + }, + "@npmcli/fs": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-3.1.0.tgz", + "integrity": "sha512-7kZUAaLscfgbwBQRbvdMYaZOWyMEcPTH/tJjnyAWJ/dvvs9Ef+CERx/qJb9GExJpl1qipaDGn7KqHnFGGixd0w==", + "dev": true, + "requires": { + "semver": "^7.3.5" + } + }, + "@npmcli/git": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-4.1.0.tgz", + "integrity": "sha512-9hwoB3gStVfa0N31ymBmrX+GuDGdVA/QWShZVqE0HK2Af+7QGGrCTbZia/SW0ImUTjTne7SP91qxDmtXvDHRPQ==", + "dev": true, + "requires": { + "@npmcli/promise-spawn": "^6.0.0", + "lru-cache": "^7.4.4", + "npm-pick-manifest": "^8.0.0", + "proc-log": "^3.0.0", + "promise-inflight": "^1.0.1", + "promise-retry": "^2.0.1", + "semver": "^7.3.5", + "which": "^3.0.0" + }, + "dependencies": { + "lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "dev": true + }, + "which": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/which/-/which-3.0.1.tgz", + "integrity": "sha512-XA1b62dzQzLfaEOSQFTCOd5KFf/1VSzZo7/7TUjnya6u0vGGKzU96UQBZTAThCb2j4/xjBAyii1OhRLJEivHvg==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "@npmcli/installed-package-contents": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@npmcli/installed-package-contents/-/installed-package-contents-2.0.2.tgz", + "integrity": "sha512-xACzLPhnfD51GKvTOOuNX2/V4G4mz9/1I2MfDoye9kBM3RYe5g2YbscsaGoTlaWqkxeiapBWyseULVKpSVHtKQ==", + "dev": true, + "requires": { + "npm-bundled": "^3.0.0", + "npm-normalize-package-bin": "^3.0.0" + } + }, + "@npmcli/move-file": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-2.0.1.tgz", + "integrity": "sha512-mJd2Z5TjYWq/ttPLLGqArdtnC74J6bOzg4rMDnN+p1xTacZ2yPRCk2y0oSWQtygLR9YVQXgOcONrwtnk3JupxQ==", + "dev": true, + "requires": { + "mkdirp": "^1.0.4", + "rimraf": "^3.0.2" + } + }, + "@npmcli/node-gyp": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/node-gyp/-/node-gyp-3.0.0.tgz", + "integrity": "sha512-gp8pRXC2oOxu0DUE1/M3bYtb1b3/DbJ5aM113+XJBgfXdussRAsX0YOrOhdd8WvnAR6auDBvJomGAkLKA5ydxA==", + "dev": true + }, + "@npmcli/promise-spawn": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@npmcli/promise-spawn/-/promise-spawn-6.0.2.tgz", + "integrity": "sha512-gGq0NJkIGSwdbUt4yhdF8ZrmkGKVz9vAdVzpOfnom+V8PLSmSOVhZwbNvZZS1EYcJN5hzzKBxmmVVAInM6HQLg==", + "dev": true, + "requires": { + "which": "^3.0.0" + }, + "dependencies": { + "which": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/which/-/which-3.0.1.tgz", + "integrity": "sha512-XA1b62dzQzLfaEOSQFTCOd5KFf/1VSzZo7/7TUjnya6u0vGGKzU96UQBZTAThCb2j4/xjBAyii1OhRLJEivHvg==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "@npmcli/run-script": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-6.0.2.tgz", + "integrity": "sha512-NCcr1uQo1k5U+SYlnIrbAh3cxy+OQT1VtqiAbxdymSlptbzBb62AjH2xXgjNCoP073hoa1CfCAcwoZ8k96C4nA==", + "dev": true, + "requires": { + "@npmcli/node-gyp": "^3.0.0", + "@npmcli/promise-spawn": "^6.0.0", + "node-gyp": "^9.0.0", + "read-package-json-fast": "^3.0.0", + "which": "^3.0.0" + }, + "dependencies": { + "which": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/which/-/which-3.0.1.tgz", + "integrity": "sha512-XA1b62dzQzLfaEOSQFTCOd5KFf/1VSzZo7/7TUjnya6u0vGGKzU96UQBZTAThCb2j4/xjBAyii1OhRLJEivHvg==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "optional": true + }, + "@popperjs/core": { + "version": "2.11.5", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.5.tgz", + "integrity": "sha512-9X2obfABZuDVLCgPK9aX0a/x4jaOEweTTWE2+9sr0Qqqevj2Uv5XorvusThmc9XGYpS9yI+fhh8RTafBtGposw==" + }, + "@schematics/angular": { + "version": "15.2.10", + "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-15.2.10.tgz", + "integrity": "sha512-eLdyP+T1TueNQ8FCP7sP+tt8z+YQ1BINsJsyAyoJT/XZjcCV7LUxgDIU94/kuvIotmJ2xTuFWHFPfAY+CN3duQ==", + "dev": true, + "requires": { + "@angular-devkit/core": "15.2.10", + "@angular-devkit/schematics": "15.2.10", + "jsonc-parser": "3.2.0" + } + }, + "@sigstore/bundle": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@sigstore/bundle/-/bundle-1.1.0.tgz", + "integrity": "sha512-PFutXEy0SmQxYI4texPw3dd2KewuNqv7OuK1ZFtY2fM754yhvG2KdgwIhRnoEE2uHdtdGNQ8s0lb94dW9sELog==", + "dev": true, + "requires": { + "@sigstore/protobuf-specs": "^0.2.0" + } + }, + "@sigstore/protobuf-specs": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@sigstore/protobuf-specs/-/protobuf-specs-0.2.1.tgz", + "integrity": "sha512-XTWVxnWJu+c1oCshMLwnKvz8ZQJJDVOlciMfgpJBQbThVjKTCG8dwyhgLngBD2KN0ap9F/gOV8rFDEx8uh7R2A==", + "dev": true + }, + "@sigstore/sign": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@sigstore/sign/-/sign-1.0.0.tgz", + "integrity": "sha512-INxFVNQteLtcfGmcoldzV6Je0sbbfh9I16DM4yJPw3j5+TFP8X6uIiA18mvpEa9yyeycAKgPmOA3X9hVdVTPUA==", + "dev": true, + "requires": { + "@sigstore/bundle": "^1.1.0", + "@sigstore/protobuf-specs": "^0.2.0", + "make-fetch-happen": "^11.0.1" + }, + "dependencies": { + "lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "dev": true + }, + "make-fetch-happen": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-11.1.1.tgz", + "integrity": "sha512-rLWS7GCSTcEujjVBs2YqG7Y4643u8ucvCJeSRqiLYhesrDuzeuFIk37xREzAsfQaqzl8b9rNCE4m6J8tvX4Q8w==", + "dev": true, + "requires": { + "agentkeepalive": "^4.2.1", + "cacache": "^17.0.0", + "http-cache-semantics": "^4.1.1", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.0", + "is-lambda": "^1.0.1", + "lru-cache": "^7.7.1", + "minipass": "^5.0.0", + "minipass-fetch": "^3.0.0", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.3", + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^7.0.0", + "ssri": "^10.0.0" + } + }, + "minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "dev": true + }, + "minipass-fetch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.4.tgz", + "integrity": "sha512-jHAqnA728uUpIaFm7NWsCnqKT6UqZz7GcI/bDpPATuwYyKwJwW0remxSCxUlKiEty+eopHGa3oc8WxgQ1FFJqg==", + "dev": true, + "requires": { + "encoding": "^0.1.13", + "minipass": "^7.0.3", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" + }, + "dependencies": { + "minipass": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", + "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", + "dev": true + } + } + } + } + }, + "@sigstore/tuf": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@sigstore/tuf/-/tuf-1.0.3.tgz", + "integrity": "sha512-2bRovzs0nJZFlCN3rXirE4gwxCn97JNjMmwpecqlbgV9WcxX7WRuIrgzx/X7Ib7MYRbyUTpBYE0s2x6AmZXnlg==", + "dev": true, + "requires": { + "@sigstore/protobuf-specs": "^0.2.0", + "tuf-js": "^1.1.7" + } + }, + "@socket.io/component-emitter": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.1.tgz", + "integrity": "sha512-dzJtaDAAoXx4GCOJpbB2eG/Qj8VDpdwkLsWGzGm+0L7E8/434RyMbAHmk9ubXWVAb9nXmc44jUf8GKqVDiKezg==", + "dev": true + }, + "@tootallnate/once": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", + "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", + "dev": true + }, + "@tufjs/canonical-json": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@tufjs/canonical-json/-/canonical-json-1.0.0.tgz", + "integrity": "sha512-QTnf++uxunWvG2z3UFNzAoQPHxnSXOwtaI3iJ+AohhV+5vONuArPjJE7aPXPVXfXJsqrVbZBu9b81AJoSd09IQ==", + "dev": true + }, + "@tufjs/models": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tufjs/models/-/models-1.0.4.tgz", + "integrity": "sha512-qaGV9ltJP0EO25YfFUPhxRVK0evXFIAGicsVXuRim4Ed9cjPxYhNnNJ49SFmbeLgtxpslIkX317IgpfcHPVj/A==", + "dev": true, + "requires": { + "@tufjs/canonical-json": "1.0.0", + "minimatch": "^9.0.0" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + }, + "minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + } + } + }, + "@types/body-parser": { + "version": "1.19.5", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", + "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", + "dev": true, + "requires": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "@types/bonjour": { + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.13.tgz", + "integrity": "sha512-z9fJ5Im06zvUL548KvYNecEVlA7cVDkGUi6kZusb04mpyEFKCIZJvloCcmpmLaIahDpOQGHaHmG6imtPMmPXGQ==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/connect": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/connect-history-api-fallback": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.4.tgz", + "integrity": "sha512-n6Cr2xS1h4uAulPRdlw6Jl6s1oG8KrVilPN2yUITEs+K48EzMJJ3W1xy8K5eWuFvjp3R74AOIGSmp2UfBJ8HFw==", + "dev": true, + "requires": { + "@types/express-serve-static-core": "*", + "@types/node": "*" + } + }, + "@types/cookie": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz", + "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==", + "dev": true + }, + "@types/cors": { + "version": "2.8.17", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.17.tgz", + "integrity": "sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/eslint": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.2.tgz", + "integrity": "sha512-Z1nseZON+GEnFjJc04sv4NSALGjhFwy6K0HXt7qsn5ArfAKtb63dXNJHf+1YW6IpOIYRBGUbu3GwJdj8DGnCjA==", + "dev": true, + "requires": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "@types/eslint-scope": { + "version": "3.7.3", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.3.tgz", + "integrity": "sha512-PB3ldyrcnAicT35TWPs5IcwKD8S333HMaa2VVv4+wdvebJkjWuW/xESoB8IwRcog8HYVYamb1g/R31Qv5Bx03g==", + "dev": true, + "requires": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "@types/estree": { + "version": "0.0.51", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz", + "integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==", + "dev": true + }, + "@types/events": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/events/-/events-3.0.0.tgz", + "integrity": "sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g==", + "dev": true + }, + "@types/express": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", + "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==", + "dev": true, + "requires": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.33", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "@types/express-serve-static-core": { + "version": "4.17.41", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.41.tgz", + "integrity": "sha512-OaJ7XLaelTgrvlZD8/aa0vvvxZdUmlCn6MtWeB7TkiKW70BQLc9XEPpDLPdbo52ZhXUCrznlWdCHWxJWtdyajA==", + "dev": true, + "requires": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "@types/file-saver": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@types/file-saver/-/file-saver-2.0.5.tgz", + "integrity": "sha512-zv9kNf3keYegP5oThGLaPk8E081DFDuwfqjtiTzm6PoxChdJ1raSuADf2YGCVIyrSynLrgc8JWv296s7Q7pQSQ==", + "dev": true + }, + "@types/http-errors": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", + "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==", + "dev": true + }, + "@types/http-proxy": { + "version": "1.17.14", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.14.tgz", + "integrity": "sha512-SSrD0c1OQzlFX7pGu1eXxSEjemej64aaNPRhhVYUGqXh0BtldAAx37MG8btcumvpgKyZp1F5Gn3JkktdxiFv6w==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/jasmine": { + "version": "3.10.6", + "resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-3.10.6.tgz", + "integrity": "sha512-twY9adK/vz72oWxCWxzXaxoDtF9TpfEEsxvbc1ibjF3gMD/RThSuSud/GKUTR3aJnfbivAbC/vLqhY+gdWCHfA==", + "dev": true + }, + "@types/json-schema": { + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", + "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", + "dev": true + }, + "@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", + "dev": true + }, + "@types/mime": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", + "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", + "dev": true + }, + "@types/node": { + "version": "12.20.52", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.52.tgz", + "integrity": "sha512-cfkwWw72849SNYp3Zx0IcIs25vABmFh73xicxhCkTcvtZQeIez15PpwQN8fY3RD7gv1Wrxlc9MEtfMORZDEsGw==", + "dev": true + }, + "@types/node-forge": { + "version": "1.3.10", + "resolved": "https://registry.npmjs.org/@types/node-forge/-/node-forge-1.3.10.tgz", + "integrity": "sha512-y6PJDYN4xYBxwd22l+OVH35N+1fCYWiuC3aiP2SlXVE6Lo7SS+rSx9r89hLxrP4pn6n1lBGhHJ12pj3F3Mpttw==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/parse-json": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz", + "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==", + "dev": true + }, + "@types/qs": { + "version": "6.9.10", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.10.tgz", + "integrity": "sha512-3Gnx08Ns1sEoCrWssEgTSJs/rsT2vhGP+Ja9cnnk9k4ALxinORlQneLXFeFKOTJMOeZUFD1s7w+w2AphTpvzZw==", + "dev": true + }, + "@types/range-parser": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", + "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", + "dev": true + }, + "@types/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", + "dev": true + }, + "@types/send": { + "version": "0.17.4", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", + "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", + "dev": true, + "requires": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "@types/serve-index": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.4.tgz", + "integrity": "sha512-qLpGZ/c2fhSs5gnYsQxtDEq3Oy8SXPClIXkW5ghvAvsNuVSA8k+gCONcUCS/UjLEYvYps+e8uBtfgXgvhwfNug==", + "dev": true, + "requires": { + "@types/express": "*" + } + }, + "@types/serve-static": { + "version": "1.15.5", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.5.tgz", + "integrity": "sha512-PDRk21MnK70hja/YF8AHfC7yIsiQHn1rcXx7ijCFBX/k+XQJhQT/gw3xekXKJvx+5SXaMMS8oqQy09Mzvz2TuQ==", + "dev": true, + "requires": { + "@types/http-errors": "*", + "@types/mime": "*", + "@types/node": "*" + } + }, + "@types/sockjs": { + "version": "0.3.36", + "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.36.tgz", + "integrity": "sha512-MK9V6NzAS1+Ud7JV9lJLFqW85VbC9dq3LmwZCuBe4wBDgKC0Kj/jd8Xl+nSviU+Qc3+m7umHHyHg//2KSa0a0Q==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/ws": { + "version": "8.5.10", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.10.tgz", + "integrity": "sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@typescript-eslint/parser": { + "version": "5.26.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.26.0.tgz", + "integrity": "sha512-n/IzU87ttzIdnAH5vQ4BBDnLPly7rC5VnjN3m0xBG82HK6rhRxnCb3w/GyWbNDghPd+NktJqB/wl6+YkzZ5T5Q==", + "dev": true, + "requires": { + "@typescript-eslint/scope-manager": "5.26.0", + "@typescript-eslint/types": "5.26.0", + "@typescript-eslint/typescript-estree": "5.26.0", + "debug": "^4.3.4" + } + }, + "@typescript-eslint/scope-manager": { + "version": "5.26.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.26.0.tgz", + "integrity": "sha512-gVzTJUESuTwiju/7NiTb4c5oqod8xt5GhMbExKsCTp6adU3mya6AGJ4Pl9xC7x2DX9UYFsjImC0mA62BCY22Iw==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.26.0", + "@typescript-eslint/visitor-keys": "5.26.0" + } + }, + "@typescript-eslint/types": { + "version": "5.26.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.26.0.tgz", + "integrity": "sha512-8794JZFE1RN4XaExLWLI2oSXsVImNkl79PzTOOWt9h0UHROwJedNOD2IJyfL0NbddFllcktGIO2aOu10avQQyA==", + "dev": true + }, + "@typescript-eslint/typescript-estree": { + "version": "5.26.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.26.0.tgz", + "integrity": "sha512-EyGpw6eQDsfD6jIqmXP3rU5oHScZ51tL/cZgFbFBvWuCwrIptl+oueUZzSmLtxFuSOQ9vDcJIs+279gnJkfd1w==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.26.0", + "@typescript-eslint/visitor-keys": "5.26.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "dependencies": { + "array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true + }, + "globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "requires": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + } + }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true + } + } + }, + "@typescript-eslint/visitor-keys": { + "version": "5.26.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.26.0.tgz", + "integrity": "sha512-wei+ffqHanYDOQgg/fS6Hcar6wAWv0CUPQ3TZzOWd2BLfgP539rb49bwua8WRAs7R6kOSLn82rfEu2ro6Llt8Q==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.26.0", + "eslint-visitor-keys": "^3.3.0" + } + }, + "@webassemblyjs/ast": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz", + "integrity": "sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw==", + "dev": true, + "requires": { + "@webassemblyjs/helper-numbers": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1" + } + }, + "@webassemblyjs/floating-point-hex-parser": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz", + "integrity": "sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ==", + "dev": true + }, + "@webassemblyjs/helper-api-error": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz", + "integrity": "sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg==", + "dev": true + }, + "@webassemblyjs/helper-buffer": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz", + "integrity": "sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA==", + "dev": true + }, + "@webassemblyjs/helper-numbers": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz", + "integrity": "sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ==", + "dev": true, + "requires": { + "@webassemblyjs/floating-point-hex-parser": "1.11.1", + "@webassemblyjs/helper-api-error": "1.11.1", + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/helper-wasm-bytecode": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz", + "integrity": "sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q==", + "dev": true + }, + "@webassemblyjs/helper-wasm-section": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz", + "integrity": "sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1" + } + }, + "@webassemblyjs/ieee754": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz", + "integrity": "sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ==", + "dev": true, + "requires": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "@webassemblyjs/leb128": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.1.tgz", + "integrity": "sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw==", + "dev": true, + "requires": { + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/utf8": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.1.tgz", + "integrity": "sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ==", + "dev": true + }, + "@webassemblyjs/wasm-edit": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz", + "integrity": "sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/helper-wasm-section": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1", + "@webassemblyjs/wasm-opt": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1", + "@webassemblyjs/wast-printer": "1.11.1" + } + }, + "@webassemblyjs/wasm-gen": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz", + "integrity": "sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/ieee754": "1.11.1", + "@webassemblyjs/leb128": "1.11.1", + "@webassemblyjs/utf8": "1.11.1" + } + }, + "@webassemblyjs/wasm-opt": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz", + "integrity": "sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1" + } + }, + "@webassemblyjs/wasm-parser": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz", + "integrity": "sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-api-error": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/ieee754": "1.11.1", + "@webassemblyjs/leb128": "1.11.1", + "@webassemblyjs/utf8": "1.11.1" + } + }, + "@webassemblyjs/wast-printer": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz", + "integrity": "sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.11.1", + "@xtuc/long": "4.2.2" + } + }, + "@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "dev": true + }, + "@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "dev": true + }, + "@yarnpkg/lockfile": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz", + "integrity": "sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==", + "dev": true + }, + "abab": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", + "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==", + "dev": true + }, + "abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "dev": true + }, + "accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dev": true, + "requires": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + } + }, + "acorn": { + "version": "8.7.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.1.tgz", + "integrity": "sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==", + "dev": true + }, + "acorn-import-assertions": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz", + "integrity": "sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==", + "dev": true + }, + "acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true + }, + "adjust-sourcemap-loader": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/adjust-sourcemap-loader/-/adjust-sourcemap-loader-4.0.0.tgz", + "integrity": "sha512-OXwN5b9pCUXNQHJpwwD2qP40byEmSgzj8B4ydSN0uMNYWiFmJ6x6KwUllMmfk8Rwu/HJDFR7U8ubsWBoN0Xp0A==", + "dev": true, + "requires": { + "loader-utils": "^2.0.0", + "regex-parser": "^2.2.11" + }, + "dependencies": { + "loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "dev": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + } + } + } + }, + "adler-32": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/adler-32/-/adler-32-1.3.1.tgz", + "integrity": "sha512-ynZ4w/nUUv5rrsR8UUGoe1VC9hZj6V5hU9Qw1HlMDJGEJw5S7TfTErWTjMys6M7vr0YWcPqs3qAr4ss0nDfP+A==" + }, + "agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "requires": { + "debug": "4" + } + }, + "agentkeepalive": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.5.0.tgz", + "integrity": "sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew==", + "dev": true, + "requires": { + "humanize-ms": "^1.2.1" + } + }, + "aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "dev": true, + "requires": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + } + }, + "ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + } + }, + "ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "dev": true, + "requires": { + "ajv": "^8.0.0" + } + }, + "ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.3" + } + }, + "ansi-colors": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", + "dev": true + }, + "ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "requires": { + "type-fest": "^0.21.3" + } + }, + "ansi-html-community": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", + "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==", + "dev": true + }, + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "requires": { + "color-convert": "^1.9.0" + } + }, + "anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "dev": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "aproba": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", + "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", + "dev": true + }, + "archiver": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/archiver/-/archiver-5.3.1.tgz", + "integrity": "sha512-8KyabkmbYrH+9ibcTScQ1xCJC/CGcugdVIwB+53f5sZziXgwUh3iXlAlANMxcZyDEfTHMe6+Z5FofV8nopXP7w==", + "requires": { + "archiver-utils": "^2.1.0", + "async": "^3.2.3", + "buffer-crc32": "^0.2.1", + "readable-stream": "^3.6.0", + "readdir-glob": "^1.0.0", + "tar-stream": "^2.2.0", + "zip-stream": "^4.1.0" + } + }, + "archiver-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-2.1.0.tgz", + "integrity": "sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw==", + "requires": { + "glob": "^7.1.4", + "graceful-fs": "^4.2.0", + "lazystream": "^1.0.0", + "lodash.defaults": "^4.2.0", + "lodash.difference": "^4.5.0", + "lodash.flatten": "^4.4.0", + "lodash.isplainobject": "^4.0.6", + "lodash.union": "^4.6.0", + "normalize-path": "^3.0.0", + "readable-stream": "^2.0.0" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "are-we-there-yet": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz", + "integrity": "sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==", + "dev": true, + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + } + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "array-flatten": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz", + "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==", + "dev": true + }, + "array-includes": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.5.tgz", + "integrity": "sha512-iSDYZMMyTPkiFasVqfuAQnWAYcvO/SeBSCGKePoEthjp4LEMTe4uLc7b025o4jAZpHhihh8xPo99TNWUWWkGDQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.19.5", + "get-intrinsic": "^1.1.1", + "is-string": "^1.0.7" + } + }, + "array.prototype.flat": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.0.tgz", + "integrity": "sha512-12IUEkHsAhA4DY5s0FPgNXIdc8VRSqD9Zp78a5au9abH/SOBrsp082JOWFNTjkMozh8mqcdiKuaLGhPeYztxSw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.2", + "es-shim-unscopables": "^1.0.0" + } + }, + "async": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.3.tgz", + "integrity": "sha512-spZRyzKL5l5BZQrr/6m/SqFdBN0q3OCI0f9rjfBzCMBIP4p75P620rR3gTmaksNOhmzgdxcaxdNfMy6anrbM0g==" + }, + "autoprefixer": { + "version": "10.4.13", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.13.tgz", + "integrity": "sha512-49vKpMqcZYsJjwotvt4+h/BCjJVnhGwcLpDt5xkcaOG3eLrG/HUYLagrihYsQ+qrIBgIzX1Rw7a6L8I/ZA1Atg==", + "dev": true, + "requires": { + "browserslist": "^4.21.4", + "caniuse-lite": "^1.0.30001426", + "fraction.js": "^4.2.0", + "normalize-range": "^0.1.2", + "picocolors": "^1.0.0", + "postcss-value-parser": "^4.2.0" + } + }, + "babel-loader": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-9.1.2.tgz", + "integrity": "sha512-mN14niXW43tddohGl8HPu5yfQq70iUThvFL/4QzESA7GcZoC0eVOhvWdQ8+3UlSjaDE9MVtsW9mxDY07W7VpVA==", + "dev": true, + "requires": { + "find-cache-dir": "^3.3.2", + "schema-utils": "^4.0.0" + } + }, + "babel-plugin-istanbul": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", + "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^5.0.4", + "test-exclude": "^6.0.0" + } + }, + "babel-plugin-polyfill-corejs2": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.3.tgz", + "integrity": "sha512-8hOdmFYFSZhqg2C/JgLUQ+t52o5nirNwaWM2B9LWteozwIvM14VSwdsCAUET10qT+kmySAlseadmfeeSWFCy+Q==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.17.7", + "@babel/helper-define-polyfill-provider": "^0.3.3", + "semver": "^6.1.1" + }, + "dependencies": { + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true + } + } + }, + "babel-plugin-polyfill-corejs3": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.6.0.tgz", + "integrity": "sha512-+eHqR6OPcBhJOGgsIar7xoAB1GcSwVUA3XjAd7HJNzOXT4wv6/H7KIdA/Nc60cvUlDbKApmqNvD1B1bzOt4nyA==", + "dev": true, + "requires": { + "@babel/helper-define-polyfill-provider": "^0.3.3", + "core-js-compat": "^3.25.1" + } + }, + "babel-plugin-polyfill-regenerator": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.4.1.tgz", + "integrity": "sha512-NtQGmyQDXjQqQ+IzRkBVwEOz9lQ4zxAQZgoAYEtU9dJjnl1Oc98qnN7jcp+bE7O7aYzVpavXE3/VKXNzUbh7aw==", + "dev": true, + "requires": { + "@babel/helper-define-polyfill-provider": "^0.3.3" + } + }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" + }, + "base64id": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", + "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==", + "dev": true + }, + "batch": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", + "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==", + "dev": true + }, + "big-integer": { + "version": "1.6.51", + "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz", + "integrity": "sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==" + }, + "big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "dev": true + }, + "binary": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/binary/-/binary-0.3.0.tgz", + "integrity": "sha512-D4H1y5KYwpJgK8wk1Cue5LLPgmwHKYSChkbspQg5JtVuR5ulGckxfR62H3AE9UDkdMC8yyXlqYihuz3Aqg2XZg==", + "requires": { + "buffers": "~0.1.1", + "chainsaw": "~0.1.0" + } + }, + "binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true + }, + "bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "requires": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "bluebird": { + "version": "3.4.7", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.4.7.tgz", + "integrity": "sha512-iD3898SR7sWVRHbiQv+sHUtHnMvC1o3nW5rAcqnq3uOn07DSAppZYUkIGslDz6gXC7HfunPe7YVBgoEJASPcHA==" + }, + "body-parser": { + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", + "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", + "dev": true, + "requires": { + "bytes": "3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "bonjour-service": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.1.1.tgz", + "integrity": "sha512-Z/5lQRMOG9k7W+FkeGTNjh7htqn/2LMnfOvBZ8pynNZCM9MwkQkI3zeI4oz09uWdcgmgHugVvBqxGg4VQJ5PCg==", + "dev": true, + "requires": { + "array-flatten": "^2.1.2", + "dns-equal": "^1.0.0", + "fast-deep-equal": "^3.1.3", + "multicast-dns": "^7.2.5" + } + }, + "boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "dev": true + }, + "bootstrap": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.1.3.tgz", + "integrity": "sha512-fcQztozJ8jToQWXxVuEyXWW+dSo8AiXWKwiSSrKWsRB/Qt+Ewwza+JWoLKiTuQLaEPhdNAJ7+Dosc9DOIqNy7Q==" + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "browserslist": { + "version": "4.22.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.2.tgz", + "integrity": "sha512-0UgcrvQmBDvZHFGdYUehrCNIazki7/lUP3kkoi/r3YB2amZbFM9J43ZRkJTXBUZK4gmx56+Sqk9+Vs9mwZx9+A==", + "requires": { + "caniuse-lite": "^1.0.30001565", + "electron-to-chromium": "^1.4.601", + "node-releases": "^2.0.14", + "update-browserslist-db": "^1.0.13" + } + }, + "buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==" + }, + "buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "buffer-indexof-polyfill": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/buffer-indexof-polyfill/-/buffer-indexof-polyfill-1.0.2.tgz", + "integrity": "sha512-I7wzHwA3t1/lwXQh+A5PbNvJxgfo5r3xulgpYDB5zckTu/Z9oUK9biouBKQUjEqzaz3HnAT6TYoovmE+GqSf7A==" + }, + "buffers": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/buffers/-/buffers-0.1.1.tgz", + "integrity": "sha512-9q/rDEGSb/Qsvv2qvzIzdluL5k7AaJOTrw23z9reQthrbF7is4CtlT0DXyO1oei2DCp4uojjzQ7igaSHp1kAEQ==" + }, + "builtins": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/builtins/-/builtins-5.0.1.tgz", + "integrity": "sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ==", + "dev": true, + "requires": { + "semver": "^7.0.0" + } + }, + "bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true + }, + "cacache": { + "version": "17.0.4", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-17.0.4.tgz", + "integrity": "sha512-Z/nL3gU+zTUjz5pCA5vVjYM8pmaw2kxM7JEiE0fv3w77Wj+sFbi70CrBruUWH0uNcEdvLDixFpgA2JM4F4DBjA==", + "dev": true, + "requires": { + "@npmcli/fs": "^3.1.0", + "fs-minipass": "^3.0.0", + "glob": "^8.0.1", + "lru-cache": "^7.7.1", + "minipass": "^4.0.0", + "minipass-collect": "^1.0.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "p-map": "^4.0.0", + "promise-inflight": "^1.0.1", + "ssri": "^10.0.0", + "tar": "^6.1.11", + "unique-filename": "^3.0.0" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + }, + "glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + } + }, + "lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "dev": true + }, + "minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + } + } + }, + "call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + } + }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, + "caniuse-lite": { + "version": "1.0.30001566", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001566.tgz", + "integrity": "sha512-ggIhCsTxmITBAMmK8yZjEhCO5/47jKXPu6Dha/wuCS4JePVL+3uiDEBuhu2aIoT+bqTOR8L76Ip1ARL9xYsEJA==" + }, + "cfb": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cfb/-/cfb-1.2.2.tgz", + "integrity": "sha512-KfdUZsSOw19/ObEWasvBP/Ac4reZvAGauZhs6S/gqNhXhI7cKwvlH7ulj+dOEYnca4bm4SGo8C1bTAQvnTjgQA==", + "requires": { + "adler-32": "~1.3.0", + "crc-32": "~1.2.0" + } + }, + "chainsaw": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/chainsaw/-/chainsaw-0.1.0.tgz", + "integrity": "sha512-75kWfWt6MEKNC8xYXIdRpDehRYY/tNSgwKaJq+dbbDcxORuVrrQ+SEHoWsniVn9XPYfP4gmdWIeDk/4YNp1rNQ==", + "requires": { + "traverse": ">=0.3.0 <0.4" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "dev": true + }, + "chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "requires": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "fsevents": "~2.3.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + } + }, + "chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "dev": true + }, + "chrome-trace-event": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", + "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", + "dev": true + }, + "clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true + }, + "cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, + "requires": { + "restore-cursor": "^3.1.0" + } + }, + "cli-spinners": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.6.1.tgz", + "integrity": "sha512-x/5fWmGMnbKQAaNwN+UZlV79qBLM9JFnJuJ03gIi5whrob0xV0ofNVHy9DhwGdsMJQc2OKv0oGmLzvaqvAVv+g==", + "dev": true + }, + "cli-width": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", + "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", + "dev": true + }, + "cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", + "dev": true + }, + "clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + } + }, + "codepage": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/codepage/-/codepage-1.15.0.tgz", + "integrity": "sha512-3g6NUTPd/YtuuGrhMnOMRjFc+LJw/bnMp3+0r/Wcz3IXUuCosKRJvMphm5+Q+bvTVGcJJuRvVLuYba+WojaFaA==" + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "dev": true + }, + "colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "dev": true + }, + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", + "dev": true + }, + "compress-commons": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-4.1.1.tgz", + "integrity": "sha512-QLdDLCKNV2dtoTorqgxngQCMA+gWXkM/Nwu7FpeBhk/RdkzimqC3jueb/FDmaZeXh+uby1jkBqE3xArsLBE5wQ==", + "requires": { + "buffer-crc32": "^0.2.13", + "crc32-stream": "^4.0.2", + "normalize-path": "^3.0.0", + "readable-stream": "^3.6.0" + } + }, + "compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "dev": true, + "requires": { + "mime-db": ">= 1.43.0 < 2" + } + }, + "compression": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", + "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", + "dev": true, + "requires": { + "accepts": "~1.3.5", + "bytes": "3.0.0", + "compressible": "~2.0.16", + "debug": "2.6.9", + "on-headers": "~1.0.2", + "safe-buffer": "5.1.2", + "vary": "~1.1.2" + }, + "dependencies": { + "bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", + "dev": true + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + } + } + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "connect": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz", + "integrity": "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==", + "dev": true, + "requires": { + "debug": "2.6.9", + "finalhandler": "1.1.2", + "parseurl": "~1.3.3", + "utils-merge": "1.0.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "connect-history-api-fallback": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", + "integrity": "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==", + "dev": true + }, + "console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", + "dev": true + }, + "content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dev": true, + "requires": { + "safe-buffer": "5.2.1" + }, + "dependencies": { + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true + } + } + }, + "content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "dev": true + }, + "convert-source-map": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", + "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", + "requires": { + "safe-buffer": "~5.1.1" + } + }, + "cookie": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", + "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", + "dev": true + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", + "dev": true + }, + "copy-anything": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-2.0.6.tgz", + "integrity": "sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==", + "dev": true, + "requires": { + "is-what": "^3.14.1" + } + }, + "copy-webpack-plugin": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-11.0.0.tgz", + "integrity": "sha512-fX2MWpamkW0hZxMEg0+mYnA40LTosOSa5TqZ9GYIBzyJa9C3QUaMPSE2xAi/buNr8u89SfD9wHSQVBzrRa/SOQ==", + "dev": true, + "requires": { + "fast-glob": "^3.2.11", + "glob-parent": "^6.0.1", + "globby": "^13.1.1", + "normalize-path": "^3.0.0", + "schema-utils": "^4.0.0", + "serialize-javascript": "^6.0.0" + }, + "dependencies": { + "glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "requires": { + "is-glob": "^4.0.3" + } + } + } + }, + "core-js-compat": { + "version": "3.34.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.34.0.tgz", + "integrity": "sha512-4ZIyeNbW/Cn1wkMMDy+mvrRUxrwFNjKwbhCfQpDd+eLgYipDqp8oGFGtLmhh18EDPKA0g3VUBYOxQGGwvWLVpA==", + "dev": true, + "requires": { + "browserslist": "^4.22.2" + } + }, + "core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" + }, + "cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "dev": true, + "requires": { + "object-assign": "^4", + "vary": "^1" + } + }, + "cosmiconfig": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", + "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", + "dev": true, + "requires": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + } + }, + "crc-32": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", + "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==" + }, + "crc32-stream": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-4.0.2.tgz", + "integrity": "sha512-DxFZ/Hk473b/muq1VJ///PMNLj0ZMnzye9thBpmjpJKCc5eMgB95aK8zCGrGfQ90cWo561Te6HK9D+j4KPdM6w==", + "requires": { + "crc-32": "^1.2.0", + "readable-stream": "^3.4.0" + } + }, + "critters": { + "version": "0.0.16", + "resolved": "https://registry.npmjs.org/critters/-/critters-0.0.16.tgz", + "integrity": "sha512-JwjgmO6i3y6RWtLYmXwO5jMd+maZt8Tnfu7VVISmEWyQqfLpB8soBswf8/2bu6SBXxtKA68Al3c+qIG1ApT68A==", + "dev": true, + "requires": { + "chalk": "^4.1.0", + "css-select": "^4.2.0", + "parse5": "^6.0.1", + "parse5-htmlparser2-tree-adapter": "^6.0.1", + "postcss": "^8.3.7", + "pretty-bytes": "^5.3.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "dependencies": { + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "css-loader": { + "version": "6.7.3", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.7.3.tgz", + "integrity": "sha512-qhOH1KlBMnZP8FzRO6YCH9UHXQhVMcEGLyNdb7Hv2cpcmJbW0YrddO+tG1ab5nT41KpHIYGsbeHqxB9xPu1pKQ==", + "dev": true, + "requires": { + "icss-utils": "^5.1.0", + "postcss": "^8.4.19", + "postcss-modules-extract-imports": "^3.0.0", + "postcss-modules-local-by-default": "^4.0.0", + "postcss-modules-scope": "^3.0.0", + "postcss-modules-values": "^4.0.0", + "postcss-value-parser": "^4.2.0", + "semver": "^7.3.8" + } + }, + "css-select": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", + "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", + "dev": true, + "requires": { + "boolbase": "^1.0.0", + "css-what": "^6.0.1", + "domhandler": "^4.3.1", + "domutils": "^2.8.0", + "nth-check": "^2.0.1" + } + }, + "css-what": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", + "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", + "dev": true + }, + "cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true + }, + "custom-event": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/custom-event/-/custom-event-1.0.1.tgz", + "integrity": "sha1-XQKkaFCt8bSjF5RqOSj8y1v9BCU=", + "dev": true + }, + "date-format": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/date-format/-/date-format-4.0.10.tgz", + "integrity": "sha512-RuMIHocrVjF84bUSTcd1uokIsLsOsk1Awb7TexNOI3f48ukCu39mjslWquDTA08VaDMF2umr3MB9ow5EyJTWyA==", + "dev": true + }, + "dayjs": { + "version": "1.11.2", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.2.tgz", + "integrity": "sha512-F4LXf1OeU9hrSYRPTTj/6FbO4HTjPKXvEIC1P2kcnFurViINCVk3ZV0xAS3XVx9MkMsXbbqlK6hjseaYbgKEHw==" + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "requires": { + "ms": "2.1.2" + } + }, + "deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "default-gateway": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz", + "integrity": "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==", + "dev": true, + "requires": { + "execa": "^5.0.0" + } + }, + "defaults": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz", + "integrity": "sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=", + "dev": true, + "requires": { + "clone": "^1.0.2" + } + }, + "define-lazy-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", + "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", + "dev": true + }, + "define-properties": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz", + "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==", + "dev": true, + "requires": { + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + } + }, + "delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", + "dev": true + }, + "depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true + }, + "dependency-graph": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/dependency-graph/-/dependency-graph-0.11.0.tgz", + "integrity": "sha512-JeMq7fEshyepOWDfcfHK06N3MhyPhz++vtqWhMT5O9A3K42rdsEDpfdVqjaqaAhsw6a+ZqeDvQVtD0hFHQWrzg==", + "dev": true + }, + "destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "dev": true + }, + "detect-node": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", + "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", + "dev": true + }, + "di": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/di/-/di-0.0.1.tgz", + "integrity": "sha1-gGZJMmzqp8qjMG112YXqJ0i6kTw=", + "dev": true + }, + "dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "requires": { + "path-type": "^4.0.0" + } + }, + "dns-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz", + "integrity": "sha512-z+paD6YUQsk+AbGCEM4PrOXSss5gd66QfcVBFTKR/HpFL9jCqikS94HYwKww6fQyO7IxrIIyUu+g0Ka9tUS2Cg==", + "dev": true + }, + "dns-packet": { + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.1.tgz", + "integrity": "sha512-l4gcSouhcgIKRvyy99RNVOgxXiicE+2jZoNmaNmZ6JXiGajBOJAesk1OBlJuM5k2c+eudGdLxDqXuPCKIj6kpw==", + "dev": true, + "requires": { + "@leichtgewicht/ip-codec": "^2.0.1" + } + }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "dom-serialize": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/dom-serialize/-/dom-serialize-2.2.1.tgz", + "integrity": "sha1-ViromZ9Evl6jB29UGdzVnrQ6yVs=", + "dev": true, + "requires": { + "custom-event": "~1.0.0", + "ent": "~2.2.0", + "extend": "^3.0.0", + "void-elements": "^2.0.0" + } + }, + "dom-serializer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", + "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", + "dev": true, + "requires": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + } + }, + "domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "dev": true + }, + "domhandler": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", + "dev": true, + "requires": { + "domelementtype": "^2.2.0" + } + }, + "domutils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "dev": true, + "requires": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + } + }, + "duplexer2": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", + "integrity": "sha1-ixLauHjA1p4+eJEFFmKjL8a93ME=", + "requires": { + "readable-stream": "^2.0.2" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=", + "dev": true + }, + "electron-to-chromium": { + "version": "1.4.608", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.608.tgz", + "integrity": "sha512-J2f/3iIIm3Mo0npneITZ2UPe4B1bg8fTNrFjD8715F/k1BvbviRuqYGkET1PgprrczXYTHFvotbBOmUp6KE0uA==" + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", + "dev": true + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", + "dev": true + }, + "encoding": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", + "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "dev": true, + "optional": true, + "requires": { + "iconv-lite": "^0.6.2" + }, + "dependencies": { + "iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "optional": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + } + } + } + }, + "end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "requires": { + "once": "^1.4.0" + } + }, + "engine.io": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.5.4.tgz", + "integrity": "sha512-KdVSDKhVKyOi+r5uEabrDLZw2qXStVvCsEB/LN3mw4WFi6Gx50jTyuxYVCwAAC0U46FdnzP/ScKRBTXb/NiEOg==", + "dev": true, + "requires": { + "@types/cookie": "^0.4.1", + "@types/cors": "^2.8.12", + "@types/node": ">=10.0.0", + "accepts": "~1.3.4", + "base64id": "2.0.0", + "cookie": "~0.4.1", + "cors": "~2.8.5", + "debug": "~4.3.1", + "engine.io-parser": "~5.2.1", + "ws": "~8.11.0" + } + }, + "engine.io-parser": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.2.tgz", + "integrity": "sha512-RcyUFKA93/CXH20l4SoVvzZfrSDMOTUS3bWVpTt2FuFP+XYrL8i8oonHP7WInRyVHXh0n/ORtoeiE1os+8qkSw==", + "dev": true + }, + "enhanced-resolve": { + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz", + "integrity": "sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + } + }, + "ent": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz", + "integrity": "sha1-6WQhkyWiHQX0RGai9obtbOX13R0=", + "dev": true + }, + "entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "dev": true + }, + "env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "dev": true + }, + "err-code": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", + "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", + "dev": true + }, + "errno": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz", + "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==", + "dev": true, + "optional": true, + "requires": { + "prr": "~1.0.1" + } + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "es-abstract": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.1.tgz", + "integrity": "sha512-WEm2oBhfoI2sImeM4OF2zE2V3BYdSF+KnSi9Sidz51fQHd7+JuF8Xgcj9/0o+OWeIeIS/MiuNnlruQrJf16GQA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "function.prototype.name": "^1.1.5", + "get-intrinsic": "^1.1.1", + "get-symbol-description": "^1.0.0", + "has": "^1.0.3", + "has-property-descriptors": "^1.0.0", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.3", + "is-callable": "^1.2.4", + "is-negative-zero": "^2.0.2", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "is-string": "^1.0.7", + "is-weakref": "^1.0.2", + "object-inspect": "^1.12.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.2", + "regexp.prototype.flags": "^1.4.3", + "string.prototype.trimend": "^1.0.5", + "string.prototype.trimstart": "^1.0.5", + "unbox-primitive": "^1.0.2" + } + }, + "es-module-lexer": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz", + "integrity": "sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==", + "dev": true + }, + "es-shim-unscopables": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", + "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "esbuild": { + "version": "0.17.8", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.8.tgz", + "integrity": "sha512-g24ybC3fWhZddZK6R3uD2iF/RIPnRpwJAqLov6ouX3hMbY4+tKolP0VMF3zuIYCaXun+yHwS5IPQ91N2BT191g==", + "dev": true, + "optional": true, + "requires": { + "@esbuild/android-arm": "0.17.8", + "@esbuild/android-arm64": "0.17.8", + "@esbuild/android-x64": "0.17.8", + "@esbuild/darwin-arm64": "0.17.8", + "@esbuild/darwin-x64": "0.17.8", + "@esbuild/freebsd-arm64": "0.17.8", + "@esbuild/freebsd-x64": "0.17.8", + "@esbuild/linux-arm": "0.17.8", + "@esbuild/linux-arm64": "0.17.8", + "@esbuild/linux-ia32": "0.17.8", + "@esbuild/linux-loong64": "0.17.8", + "@esbuild/linux-mips64el": "0.17.8", + "@esbuild/linux-ppc64": "0.17.8", + "@esbuild/linux-riscv64": "0.17.8", + "@esbuild/linux-s390x": "0.17.8", + "@esbuild/linux-x64": "0.17.8", + "@esbuild/netbsd-x64": "0.17.8", + "@esbuild/openbsd-x64": "0.17.8", + "@esbuild/sunos-x64": "0.17.8", + "@esbuild/win32-arm64": "0.17.8", + "@esbuild/win32-ia32": "0.17.8", + "@esbuild/win32-x64": "0.17.8" + } + }, + "esbuild-wasm": { + "version": "0.17.8", + "resolved": "https://registry.npmjs.org/esbuild-wasm/-/esbuild-wasm-0.17.8.tgz", + "integrity": "sha512-zCmpxv95E0FuCmvdw1K836UHnj4EdiQnFfjTby35y3LAjRPtXMj3sbHDRHjbD8Mqg5lTwq3knacr/1qIFU51CQ==", + "dev": true + }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==" + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==" + }, + "eslint": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.16.0.tgz", + "integrity": "sha512-MBndsoXY/PeVTDJeWsYj7kLZ5hQpJOfMYLsF6LicLHQWbRDG19lK5jOix4DPl8yY4SUFcE3txy86OzFLWT+yoA==", + "dev": true, + "requires": { + "@eslint/eslintrc": "^1.3.0", + "@humanwhocodes/config-array": "^0.9.2", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.1.1", + "eslint-utils": "^3.0.0", + "eslint-visitor-keys": "^3.3.0", + "espree": "^9.3.2", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^6.0.1", + "globals": "^13.15.0", + "ignore": "^5.2.0", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "regexpp": "^3.2.0", + "strip-ansi": "^6.0.1", + "strip-json-comments": "^3.1.0", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "dependencies": { + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true + }, + "eslint-scope": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", + "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + } + }, + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + }, + "glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "requires": { + "is-glob": "^4.0.3" + } + }, + "globals": { + "version": "13.15.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.15.0.tgz", + "integrity": "sha512-bpzcOlgDhMG070Av0Vy5Owklpv1I6+j96GhUI7Rh7IzDCKLzboflLrrfqMu8NquDbiR4EOQk7XzJwqVJxicxog==", + "dev": true, + "requires": { + "type-fest": "^0.20.2" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "requires": { + "argparse": "^2.0.1" + } + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true + } + } + }, + "eslint-import-resolver-node": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz", + "integrity": "sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==", + "dev": true, + "requires": { + "debug": "^3.2.7", + "resolve": "^1.20.0" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "eslint-import-resolver-typescript": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-2.7.1.tgz", + "integrity": "sha512-00UbgGwV8bSgUv34igBDbTOtKhqoRMy9bFjNehT40bXg6585PNIct8HhXZ0SybqB9rWtXj9crcku8ndDn/gIqQ==", + "dev": true, + "requires": { + "debug": "^4.3.4", + "glob": "^7.2.0", + "is-glob": "^4.0.3", + "resolve": "^1.22.0", + "tsconfig-paths": "^3.14.1" + } + }, + "eslint-module-utils": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.3.tgz", + "integrity": "sha512-088JEC7O3lDZM9xGe0RerkOMd0EjFl+Yvd1jPWIkMT5u3H9+HC34mWWPnqPrN13gieT9pBOO+Qt07Nb/6TresQ==", + "dev": true, + "requires": { + "debug": "^3.2.7", + "find-up": "^2.1.0" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "requires": { + "p-limit": "^1.1.0" + } + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + } + } + }, + "eslint-plugin-import": { + "version": "2.26.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.26.0.tgz", + "integrity": "sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==", + "dev": true, + "requires": { + "array-includes": "^3.1.4", + "array.prototype.flat": "^1.2.5", + "debug": "^2.6.9", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.6", + "eslint-module-utils": "^2.7.3", + "has": "^1.0.3", + "is-core-module": "^2.8.1", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.values": "^1.1.5", + "resolve": "^1.22.0", + "tsconfig-paths": "^3.14.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + } + }, + "eslint-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^2.0.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true + } + } + }, + "eslint-visitor-keys": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "dev": true + }, + "espree": { + "version": "9.3.2", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.3.2.tgz", + "integrity": "sha512-D211tC7ZwouTIuY5x9XnS0E9sWNChB7IYKX/Xp5eQj3nFXhqmiUDB9q27y76oFl8jTg3pXcQx/bpxMfs3CIZbA==", + "dev": true, + "requires": { + "acorn": "^8.7.1", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.3.0" + } + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "esquery": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "dev": true, + "requires": { + "estraverse": "^5.1.0" + }, + "dependencies": { + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + } + } + }, + "esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "requires": { + "estraverse": "^5.2.0" + }, + "dependencies": { + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + } + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "dev": true + }, + "eventemitter-asyncresource": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/eventemitter-asyncresource/-/eventemitter-asyncresource-1.0.0.tgz", + "integrity": "sha512-39F7TBIV0G7gTelxwbEqnwhp90eqCPON1k0NwNfwhgKn4Co4ybUbj2pECcXT0B3ztRKZ7Pw1JujUUgmQJHcVAQ==", + "dev": true + }, + "eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "dev": true + }, + "events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true + }, + "exceljs": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/exceljs/-/exceljs-4.3.0.tgz", + "integrity": "sha512-hTAeo5b5TPvf8Z02I2sKIT4kSfCnOO2bCxYX8ABqODCdAjppI3gI9VYiGCQQYVcBaBSKlFDMKlAQRqC+kV9O8w==", + "requires": { + "archiver": "^5.0.0", + "dayjs": "^1.8.34", + "fast-csv": "^4.3.1", + "jszip": "^3.5.0", + "readable-stream": "^3.6.0", + "saxes": "^5.0.1", + "tmp": "^0.2.0", + "unzipper": "^0.10.11", + "uuid": "^8.3.0" + } + }, + "execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + } + }, + "exponential-backoff": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.1.tgz", + "integrity": "sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw==", + "dev": true + }, + "express": { + "version": "4.19.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", + "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", + "dev": true, + "requires": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.2", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.6.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.11.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "dependencies": { + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "dev": true + }, + "cookie": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "dev": true + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "dev": true, + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true + }, + "statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true + } + } + }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true + }, + "external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "dev": true, + "requires": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + }, + "dependencies": { + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "requires": { + "os-tmpdir": "~1.0.2" + } + } + } + }, + "fast-csv": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/fast-csv/-/fast-csv-4.3.6.tgz", + "integrity": "sha512-2RNSpuwwsJGP0frGsOmTb9oUF+VkFSM4SyLTDgwf2ciHWTarN0lQTC+F2f/t5J9QjW+c65VFIAAu85GsvMIusw==", + "requires": { + "@fast-csv/format": "4.3.5", + "@fast-csv/parse": "4.3.6" + } + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + } + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "fastq": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", + "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", + "dev": true, + "requires": { + "reusify": "^1.0.4" + } + }, + "faye-websocket": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", + "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", + "dev": true, + "requires": { + "websocket-driver": ">=0.5.1" + } + }, + "figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5" + } + }, + "file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "requires": { + "flat-cache": "^3.0.4" + } + }, + "file-saver": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/file-saver/-/file-saver-2.0.5.tgz", + "integrity": "sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA==" + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "dev": true, + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "dev": true, + "requires": { + "ee-first": "1.1.1" + } + } + } + }, + "find-cache-dir": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", + "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", + "dev": true, + "requires": { + "commondir": "^1.0.1", + "make-dir": "^3.0.2", + "pkg-dir": "^4.1.0" + } + }, + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "requires": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + } + }, + "flatted": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.5.tgz", + "integrity": "sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg==", + "dev": true + }, + "follow-redirects": { + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", + "dev": true + }, + "foreground-child": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", + "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "dependencies": { + "signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true + } + } + }, + "forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "dev": true + }, + "frac": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/frac/-/frac-1.1.2.tgz", + "integrity": "sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA==" + }, + "fraction.js": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", + "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==", + "dev": true + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "dev": true + }, + "fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" + }, + "fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + }, + "fs-minipass": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.3.tgz", + "integrity": "sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw==", + "dev": true, + "requires": { + "minipass": "^7.0.3" + }, + "dependencies": { + "minipass": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", + "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", + "dev": true + } + } + }, + "fs-monkey": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.5.tgz", + "integrity": "sha512-8uMbBjrhzW76TYgEV27Y5E//W2f/lTFmx78P2w19FZSxarhI/798APGQyuGCwmkNxgwGRhrLfvWyLBvNtuOmew==", + "dev": true + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "optional": true + }, + "fstream": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz", + "integrity": "sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==", + "requires": { + "graceful-fs": "^4.1.2", + "inherits": "~2.0.0", + "mkdirp": ">=0.5 0", + "rimraf": "2" + }, + "dependencies": { + "mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "requires": { + "minimist": "^1.2.6" + } + }, + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "requires": { + "glob": "^7.1.3" + } + } + } + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "function.prototype.name": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", + "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.0", + "functions-have-names": "^1.2.2" + } + }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true + }, + "functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true + }, + "gauge": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz", + "integrity": "sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==", + "dev": true, + "requires": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.3", + "console-control-strings": "^1.1.0", + "has-unicode": "^2.0.1", + "signal-exit": "^3.0.7", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.5" + } + }, + "gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==" + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" + }, + "get-intrinsic": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", + "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1" + } + }, + "get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "dev": true + }, + "get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true + }, + "get-symbol-description": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", + "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + } + }, + "glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "dev": true + }, + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==" + }, + "globby": { + "version": "13.2.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-13.2.2.tgz", + "integrity": "sha512-Y1zNGV+pzQdh7H39l9zgB4PJqjRNqydvdYCDG4HFXM4XuvSaQQlEc91IU1yALL8gUTDomgBAfz3XJdmUS+oo0w==", + "dev": true, + "requires": { + "dir-glob": "^3.0.1", + "fast-glob": "^3.3.0", + "ignore": "^5.2.4", + "merge2": "^1.4.1", + "slash": "^4.0.0" + } + }, + "graceful-fs": { + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==" + }, + "handle-thing": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", + "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==", + "dev": true + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "dev": true + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==" + }, + "has-property-descriptors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", + "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "dev": true, + "requires": { + "get-intrinsic": "^1.1.1" + } + }, + "has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true + }, + "has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dev": true, + "requires": { + "has-symbols": "^1.0.2" + } + }, + "has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", + "dev": true + }, + "hdr-histogram-js": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/hdr-histogram-js/-/hdr-histogram-js-2.0.3.tgz", + "integrity": "sha512-Hkn78wwzWHNCp2uarhzQ2SGFLU3JY8SBDDd3TAABK4fc30wm+MuPOrg5QVFVfkKOQd6Bfz3ukJEI+q9sXEkK1g==", + "dev": true, + "requires": { + "@assemblyscript/loader": "^0.10.1", + "base64-js": "^1.2.0", + "pako": "^1.0.3" + } + }, + "hdr-histogram-percentiles-obj": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hdr-histogram-percentiles-obj/-/hdr-histogram-percentiles-obj-3.0.0.tgz", + "integrity": "sha512-7kIufnBqdsBGcSZLPJwqHT3yhk1QTsSlFsVD3kx5ixH/AlgBs9yM1q6DPhXZ8f8gtdqgh7N7/5btRLpQsS2gHw==", + "dev": true + }, + "hosted-git-info": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-6.1.1.tgz", + "integrity": "sha512-r0EI+HBMcXadMrugk0GCQ+6BQV39PiWAZVfq7oIckeGiN7sjRGyQxPdft3nQekFTCQbYxLBH+/axZMeH8UX6+w==", + "dev": true, + "requires": { + "lru-cache": "^7.5.1" + }, + "dependencies": { + "lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "dev": true + } + } + }, + "hpack.js": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", + "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "obuf": "^1.0.0", + "readable-stream": "^2.0.1", + "wbuf": "^1.1.0" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "html-entities": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.4.0.tgz", + "integrity": "sha512-igBTJcNNNhvZFRtm8uA6xMY6xYleeDwn3PeBCkDz7tHttv4F2hsDI2aPgNERWzvRcNYHNT3ymRaQzllmXj4YsQ==", + "dev": true + }, + "html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true + }, + "http-cache-semantics": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", + "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", + "dev": true + }, + "http-deceiver": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", + "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==", + "dev": true + }, + "http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dev": true, + "requires": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "dependencies": { + "statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true + } + } + }, + "http-parser-js": { + "version": "0.5.8", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", + "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==", + "dev": true + }, + "http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "dev": true, + "requires": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + } + }, + "http-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", + "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", + "dev": true, + "requires": { + "@tootallnate/once": "2", + "agent-base": "6", + "debug": "4" + } + }, + "http-proxy-middleware": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz", + "integrity": "sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==", + "dev": true, + "requires": { + "@types/http-proxy": "^1.17.8", + "http-proxy": "^1.18.1", + "is-glob": "^4.0.1", + "is-plain-obj": "^3.0.0", + "micromatch": "^4.0.2" + } + }, + "https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dev": true, + "requires": { + "agent-base": "6", + "debug": "4" + } + }, + "human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true + }, + "humanize-ms": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", + "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", + "dev": true, + "requires": { + "ms": "^2.0.0" + } + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "icss-utils": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", + "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", + "dev": true + }, + "ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" + }, + "ignore": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz", + "integrity": "sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==", + "dev": true + }, + "ignore-walk": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-6.0.4.tgz", + "integrity": "sha512-t7sv42WkwFkyKbivUCglsQW5YWMskWtbEf4MNKX5u/CCWHKSPzN4FtBQGsQZgCLbxOzpVlcbWVK5KB3auIOjSw==", + "dev": true, + "requires": { + "minimatch": "^9.0.0" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + }, + "minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + } + } + }, + "image-size": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz", + "integrity": "sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==", + "dev": true, + "optional": true + }, + "immediate": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", + "integrity": "sha1-nbHb0Pr43m++D13V5Wu2BigN5ps=" + }, + "immutable": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.4.tgz", + "integrity": "sha512-fsXeu4J4i6WNWSikpI88v/PcVflZz+6kMhUfIwc5SY+poQRPnaf5V7qds6SUyUN3cVxEzuCab7QIoLOQ+DQ1wA==", + "dev": true + }, + "import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "dependencies": { + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + } + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true + }, + "indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true + }, + "infer-owner": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", + "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "ini": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ini/-/ini-3.0.1.tgz", + "integrity": "sha512-it4HyVAUTKBc6m8e1iXWvXSTdndF7HbdN713+kvLrymxTaU4AUBWrJ4vEooP+V7fexnVD3LKcBshjGGPefSMUQ==", + "dev": true + }, + "inquirer": { + "version": "8.2.4", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.4.tgz", + "integrity": "sha512-nn4F01dxU8VeKfq192IjLsxu0/OmMZ4Lg3xKAns148rCaXP6ntAoEkVYZThWjwON8AlzdZZi6oqnhNbxUG9hVg==", + "dev": true, + "requires": { + "ansi-escapes": "^4.2.1", + "chalk": "^4.1.1", + "cli-cursor": "^3.1.0", + "cli-width": "^3.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.21", + "mute-stream": "0.0.8", + "ora": "^5.4.1", + "run-async": "^2.4.0", + "rxjs": "^7.5.5", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0", + "through": "^2.3.6", + "wrap-ansi": "^7.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "internal-slot": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", + "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", + "dev": true, + "requires": { + "get-intrinsic": "^1.1.0", + "has": "^1.0.3", + "side-channel": "^1.0.4" + } + }, + "ip": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.1.tgz", + "integrity": "sha512-lJUL9imLTNi1ZfXT+DU6rBBdbiKGBuay9B6xGSPVjUeQwaH1RIGqef8RZkUtHioLmSNpPR5M4HVKJGm1j8FWVQ==", + "dev": true + }, + "ipaddr.js": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.1.0.tgz", + "integrity": "sha512-LlbxQ7xKzfBusov6UMi4MFpEg0m+mAm9xyNGEduwXMEDuf4WfzB/RZwMVYEd7IKGvh4IUkEXYxtAVu9T3OelJQ==", + "dev": true + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true + }, + "is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dev": true, + "requires": { + "has-bigints": "^1.0.1" + } + }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-callable": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", + "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", + "dev": true + }, + "is-core-module": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.9.0.tgz", + "integrity": "sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, + "is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "dev": true + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" + }, + "is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-interactive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", + "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", + "dev": true + }, + "is-lambda": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", + "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", + "dev": true + }, + "is-negative-zero": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", + "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", + "dev": true + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-plain-obj": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", + "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", + "dev": true + }, + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, + "is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-shared-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", + "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2" + } + }, + "is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true + }, + "is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dev": true, + "requires": { + "has-symbols": "^1.0.2" + } + }, + "is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true + }, + "is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2" + } + }, + "is-what": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/is-what/-/is-what-3.14.1.tgz", + "integrity": "sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==", + "dev": true + }, + "is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dev": true, + "requires": { + "is-docker": "^2.0.0" + } + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "isbinaryfile": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-4.0.10.tgz", + "integrity": "sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw==", + "dev": true + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + }, + "istanbul-lib-coverage": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", + "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", + "dev": true + }, + "istanbul-lib-instrument": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.0.tgz", + "integrity": "sha512-6Lthe1hqXHBNsqvgDzGO6l03XNeu3CrG4RqQ1KM9+l5+jNGpEJfIELx1NS3SEHmJQA8np/u+E4EPRKRiu6m19A==", + "dev": true, + "requires": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true + } + } + }, + "istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", + "dev": true, + "requires": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^3.0.0", + "supports-color": "^7.1.0" + }, + "dependencies": { + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "istanbul-lib-source-maps": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", + "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", + "dev": true, + "requires": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "istanbul-reports": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.4.tgz", + "integrity": "sha512-r1/DshN4KSE7xWEknZLLLLDn5CJybV3nw01VTkp6D5jzLuELlcbudfj/eSQFvrKsJuTVCGnePO7ho82Nw9zzfw==", + "dev": true, + "requires": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + } + }, + "jackspeak": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", + "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==", + "dev": true, + "requires": { + "@isaacs/cliui": "^8.0.2", + "@pkgjs/parseargs": "^0.11.0" + } + }, + "jasmine-core": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-4.0.1.tgz", + "integrity": "sha512-w+JDABxQCkxbGGxg+a2hUVZyqUS2JKngvIyLGu/xiw2ZwgsoSB0iiecLQsQORSeaKQ6iGrCyWG86RfNDuoA7Lg==", + "dev": true + }, + "jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "dev": true, + "requires": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "dependencies": { + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==" + }, + "json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, + "json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==" + }, + "jsonc-parser": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", + "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", + "dev": true + }, + "jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6", + "universalify": "^2.0.0" + } + }, + "jsonparse": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", + "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==", + "dev": true + }, + "jszip": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.0.tgz", + "integrity": "sha512-LDfVtOLtOxb9RXkYOwPyNBTQDL4eUbqahtoY6x07GiDJHwSYvn8sHHIw8wINImV3MqbMNve2gSuM1DDqEKk09Q==", + "requires": { + "lie": "~3.3.0", + "pako": "~1.0.2", + "readable-stream": "~2.3.6", + "setimmediate": "^1.0.5" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "karma": { + "version": "6.3.20", + "resolved": "https://registry.npmjs.org/karma/-/karma-6.3.20.tgz", + "integrity": "sha512-HRNQhMuKOwKpjYlWiJP0DUrJOh+QjaI/DTaD8b9rEm4Il3tJ8MijutVZH4ts10LuUFst/CedwTS6vieCN8yTSw==", + "dev": true, + "requires": { + "@colors/colors": "1.5.0", + "body-parser": "^1.19.0", + "braces": "^3.0.2", + "chokidar": "^3.5.1", + "connect": "^3.7.0", + "di": "^0.0.1", + "dom-serialize": "^2.2.1", + "glob": "^7.1.7", + "graceful-fs": "^4.2.6", + "http-proxy": "^1.18.1", + "isbinaryfile": "^4.0.8", + "lodash": "^4.17.21", + "log4js": "^6.4.1", + "mime": "^2.5.2", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.5", + "qjobs": "^1.2.0", + "range-parser": "^1.2.1", + "rimraf": "^3.0.2", + "socket.io": "^4.4.1", + "source-map": "^0.6.1", + "tmp": "^0.2.1", + "ua-parser-js": "^0.7.30", + "yargs": "^16.1.1" + }, + "dependencies": { + "mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "requires": { + "minimist": "^1.2.6" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "requires": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + } + }, + "yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true + } + } + }, + "karma-chrome-launcher": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/karma-chrome-launcher/-/karma-chrome-launcher-3.1.1.tgz", + "integrity": "sha512-hsIglcq1vtboGPAN+DGCISCFOxW+ZVnIqhDQcCMqqCp+4dmJ0Qpq5QAjkbA0X2L9Mi6OBkHi2Srrbmm7pUKkzQ==", + "dev": true, + "requires": { + "which": "^1.2.1" + } + }, + "karma-coverage": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/karma-coverage/-/karma-coverage-2.1.1.tgz", + "integrity": "sha512-oxeOSBVK/jdZsiX03LhHQkO4eISSQb5GbHi6Nsw3Mw7G4u6yUgacBAftnO7q+emPBLMsrNbz1pGIrj+Jb3z17A==", + "dev": true, + "requires": { + "istanbul-lib-coverage": "^3.2.0", + "istanbul-lib-instrument": "^4.0.3", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.1", + "istanbul-reports": "^3.0.5", + "minimatch": "^3.0.4" + }, + "dependencies": { + "istanbul-lib-instrument": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz", + "integrity": "sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==", + "dev": true, + "requires": { + "@babel/core": "^7.7.5", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.0.0", + "semver": "^6.3.0" + } + }, + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true + } + } + }, + "karma-jasmine": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/karma-jasmine/-/karma-jasmine-4.0.2.tgz", + "integrity": "sha512-ggi84RMNQffSDmWSyyt4zxzh2CQGwsxvYYsprgyR1j8ikzIduEdOlcLvXjZGwXG/0j41KUXOWsUCBfbEHPWP9g==", + "dev": true, + "requires": { + "jasmine-core": "^3.6.0" + }, + "dependencies": { + "jasmine-core": { + "version": "3.99.1", + "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-3.99.1.tgz", + "integrity": "sha512-Hu1dmuoGcZ7AfyynN3LsfruwMbxMALMka+YtZeGoLuDEySVmVAPaonkNoBRIw/ectu8b9tVQCJNgp4a4knp+tg==", + "dev": true + } + } + }, + "karma-jasmine-html-reporter": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/karma-jasmine-html-reporter/-/karma-jasmine-html-reporter-1.7.0.tgz", + "integrity": "sha512-pzum1TL7j90DTE86eFt48/s12hqwQuiD+e5aXx2Dc9wDEn2LfGq6RoAxEZZjFiN0RDSCOnosEKRZWxbQ+iMpQQ==", + "dev": true + }, + "karma-source-map-support": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/karma-source-map-support/-/karma-source-map-support-1.4.0.tgz", + "integrity": "sha512-RsBECncGO17KAoJCYXjv+ckIz+Ii9NCi+9enk+rq6XC81ezYkb4/RHE6CTXdA7IOJqoF3wcaLfVG0CPmE5ca6A==", + "dev": true, + "requires": { + "source-map-support": "^0.5.5" + } + }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true + }, + "klona": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.6.tgz", + "integrity": "sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==", + "dev": true + }, + "lazystream": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.1.tgz", + "integrity": "sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==", + "requires": { + "readable-stream": "^2.0.5" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "less": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/less/-/less-4.1.3.tgz", + "integrity": "sha512-w16Xk/Ta9Hhyei0Gpz9m7VS8F28nieJaL/VyShID7cYvP6IL5oHeL6p4TXSDJqZE/lNv0oJ2pGVjJsRkfwm5FA==", + "dev": true, + "requires": { + "copy-anything": "^2.0.1", + "errno": "^0.1.1", + "graceful-fs": "^4.1.2", + "image-size": "~0.5.0", + "make-dir": "^2.1.0", + "mime": "^1.4.1", + "needle": "^3.1.0", + "parse-node-version": "^1.0.1", + "source-map": "~0.6.0", + "tslib": "^2.3.0" + }, + "dependencies": { + "make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "dev": true, + "optional": true, + "requires": { + "pify": "^4.0.1", + "semver": "^5.6.0" + } + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true, + "optional": true + }, + "semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "optional": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "optional": true + } + } + }, + "less-loader": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/less-loader/-/less-loader-11.1.0.tgz", + "integrity": "sha512-C+uDBV7kS7W5fJlUjq5mPBeBVhYpTIm5gB09APT9o3n/ILeaXVsiSFTbZpTJCJwQ/Crczfn3DmfQFwxYusWFug==", + "dev": true, + "requires": { + "klona": "^2.0.4" + } + }, + "levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + } + }, + "license-webpack-plugin": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/license-webpack-plugin/-/license-webpack-plugin-4.0.2.tgz", + "integrity": "sha512-771TFWFD70G1wLTC4oU2Cw4qvtmNrIw+wRvBtn+okgHl7slJVi7zfNcdmqDL72BojM30VNJ2UHylr1o77U37Jw==", + "dev": true, + "requires": { + "webpack-sources": "^3.0.0" + } + }, + "lie": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", + "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", + "requires": { + "immediate": "~3.0.5" + } + }, + "lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true + }, + "listenercount": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/listenercount/-/listenercount-1.0.1.tgz", + "integrity": "sha1-hMinKrWcRyUyFIDJdeZQg0LnCTc=" + }, + "loader-runner": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", + "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", + "dev": true + }, + "loader-utils": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.2.1.tgz", + "integrity": "sha512-ZvFw1KWS3GVyYBYb7qkmRM/WwL2TQQBxgCK62rlvm4WpVQ23Nb4tYjApUlfjrEGvOs7KHEsmyUn75OHZrJMWPw==", + "dev": true + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", + "dev": true + }, + "lodash.defaults": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", + "integrity": "sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw=" + }, + "lodash.difference": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.difference/-/lodash.difference-4.5.0.tgz", + "integrity": "sha1-nMtOUF1Ia5FlE0V3KIWi3yf9AXw=" + }, + "lodash.escaperegexp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.escaperegexp/-/lodash.escaperegexp-4.1.2.tgz", + "integrity": "sha1-ZHYsSGGAglGKw99Mz11YhtriA0c=" + }, + "lodash.flatten": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", + "integrity": "sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8=" + }, + "lodash.groupby": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.groupby/-/lodash.groupby-4.6.0.tgz", + "integrity": "sha1-Cwih3PaDl8OXhVwyOXg4Mt90A9E=" + }, + "lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY=" + }, + "lodash.isequal": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", + "integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA=" + }, + "lodash.isfunction": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/lodash.isfunction/-/lodash.isfunction-3.0.9.tgz", + "integrity": "sha512-AirXNj15uRIMMPihnkInB4i3NHeb4iBtNg9WRWuK2o31S+ePwwNmDPaTL3o7dTJ+VXNZim7rFs4rxN4YU1oUJw==" + }, + "lodash.isnil": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/lodash.isnil/-/lodash.isnil-4.0.0.tgz", + "integrity": "sha1-SeKM1VkBNFjIFMVHnTxmOiG/qmw=" + }, + "lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=" + }, + "lodash.isundefined": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/lodash.isundefined/-/lodash.isundefined-3.0.1.tgz", + "integrity": "sha1-I+89lTVWUgOmbO/VuDD4SJEa+0g=" + }, + "lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "lodash.union": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.union/-/lodash.union-4.6.0.tgz", + "integrity": "sha1-SLtQiECfFvGCFmZkHETdGqrjzYg=" + }, + "lodash.uniq": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", + "integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=" + }, + "log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "requires": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "log4js": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/log4js/-/log4js-6.5.1.tgz", + "integrity": "sha512-z1hRRe5DDPzsP73PgN/GYmeSbIAl/g9kX3GLjABCpcU1ojns8S4cyjpJ21jU1P7z1wWkm69PjyMcEGqYYdDqaA==", + "dev": true, + "requires": { + "date-format": "^4.0.10", + "debug": "^4.3.4", + "flatted": "^3.2.5", + "rfdc": "^1.3.0", + "streamroller": "^3.1.1" + } + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "magic-string": { + "version": "0.29.0", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.29.0.tgz", + "integrity": "sha512-WcfidHrDjMY+eLjlU+8OvwREqHwpgCeKVBUpQ3OhYYuvfaYCUgcbuBzappNzZvg/v8onU3oQj+BYpkOJe9Iw4Q==", + "dev": true, + "requires": { + "@jridgewell/sourcemap-codec": "^1.4.13" + } + }, + "make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "requires": { + "semver": "^6.0.0" + }, + "dependencies": { + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true + } + } + }, + "make-fetch-happen": { + "version": "10.2.1", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-10.2.1.tgz", + "integrity": "sha512-NgOPbRiaQM10DYXvN3/hhGVI2M5MtITFryzBGxHM5p4wnFxsVCbxkrBrDsk+EZ5OB4jEOT7AjDxtdF+KVEFT7w==", + "dev": true, + "requires": { + "agentkeepalive": "^4.2.1", + "cacache": "^16.1.0", + "http-cache-semantics": "^4.1.0", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.0", + "is-lambda": "^1.0.1", + "lru-cache": "^7.7.1", + "minipass": "^3.1.6", + "minipass-collect": "^1.0.2", + "minipass-fetch": "^2.0.3", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.3", + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^7.0.0", + "ssri": "^9.0.0" + }, + "dependencies": { + "@npmcli/fs": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-2.1.2.tgz", + "integrity": "sha512-yOJKRvohFOaLqipNtwYB9WugyZKhC/DZC4VYPmpaCzDBrA8YpK3qHZ8/HGscMnE4GqbkLNuVcCnxkeQEdGt6LQ==", + "dev": true, + "requires": { + "@gar/promisify": "^1.1.3", + "semver": "^7.3.5" + } + }, + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + }, + "cacache": { + "version": "16.1.3", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-16.1.3.tgz", + "integrity": "sha512-/+Emcj9DAXxX4cwlLmRI9c166RuL3w30zp4R7Joiv2cQTtTtA+jeuCAjH3ZlGnYS3tKENSrKhAzVVP9GVyzeYQ==", + "dev": true, + "requires": { + "@npmcli/fs": "^2.1.0", + "@npmcli/move-file": "^2.0.0", + "chownr": "^2.0.0", + "fs-minipass": "^2.1.0", + "glob": "^8.0.1", + "infer-owner": "^1.0.4", + "lru-cache": "^7.7.1", + "minipass": "^3.1.6", + "minipass-collect": "^1.0.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "mkdirp": "^1.0.4", + "p-map": "^4.0.0", + "promise-inflight": "^1.0.1", + "rimraf": "^3.0.2", + "ssri": "^9.0.0", + "tar": "^6.1.11", + "unique-filename": "^2.0.0" + } + }, + "fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "dev": true, + "requires": { + "minipass": "^3.0.0" + } + }, + "glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + } + }, + "lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "dev": true + }, + "minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + }, + "minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "ssri": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-9.0.1.tgz", + "integrity": "sha512-o57Wcn66jMQvfHG1FlYbWeZWW/dHZhJXjpIcTfXldXEk5nz5lStPo3mK0OJQfGR3RbZUlbISexbljkJzuEj/8Q==", + "dev": true, + "requires": { + "minipass": "^3.1.1" + } + }, + "unique-filename": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-2.0.1.tgz", + "integrity": "sha512-ODWHtkkdx3IAR+veKxFV+VBkUMcN+FaqzUUd7IZzt+0zhDZFPFxhlqwPF3YQvMHx1TD0tdgYl+kuPnJ8E6ql7A==", + "dev": true, + "requires": { + "unique-slug": "^3.0.0" + } + }, + "unique-slug": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-3.0.0.tgz", + "integrity": "sha512-8EyMynh679x/0gqE9fT9oilG+qEt+ibFyqjuVTsZn1+CMxH+XLlpvr2UZx4nVcCwTpx81nICr2JQFkM+HPLq4w==", + "dev": true, + "requires": { + "imurmurhash": "^0.1.4" + } + } + } + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", + "dev": true + }, + "memfs": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.5.3.tgz", + "integrity": "sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==", + "dev": true, + "requires": { + "fs-monkey": "^1.0.4" + } + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==", + "dev": true + }, + "merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "dev": true + }, + "micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "requires": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + } + }, + "mime": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", + "dev": true + }, + "mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true + }, + "mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "requires": { + "mime-db": "1.52.0" + } + }, + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true + }, + "mini-css-extract-plugin": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.7.2.tgz", + "integrity": "sha512-EdlUizq13o0Pd+uCp+WO/JpkLvHRVGt97RqfeGhXqAcorYo1ypJSpkV+WDT0vY/kmh/p7wRdJNJtuyK540PXDw==", + "dev": true, + "requires": { + "schema-utils": "^4.0.0" + } + }, + "minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "dev": true + }, + "minimatch": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.5.tgz", + "integrity": "sha512-tUpxzX0VAzJHjLu0xUfFv1gwVp9ba3IOuRAVH2EGuRW8a5emA2FlACLqiT/lDVtS1W+TGNwqz3sWaNyLgDJWuw==", + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" + }, + "minipass": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.8.tgz", + "integrity": "sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ==", + "dev": true + }, + "minipass-collect": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz", + "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", + "dev": true, + "requires": { + "minipass": "^3.0.0" + }, + "dependencies": { + "minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + } + } + }, + "minipass-fetch": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-2.1.2.tgz", + "integrity": "sha512-LT49Zi2/WMROHYoqGgdlQIZh8mLPZmOrN2NdJjMXxYe4nkN6FUyuPuOAOedNJDrx0IRGg9+4guZewtp8hE6TxA==", + "dev": true, + "requires": { + "encoding": "^0.1.13", + "minipass": "^3.1.6", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" + }, + "dependencies": { + "minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + } + } + }, + "minipass-flush": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", + "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", + "dev": true, + "requires": { + "minipass": "^3.0.0" + }, + "dependencies": { + "minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + } + } + }, + "minipass-json-stream": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minipass-json-stream/-/minipass-json-stream-1.0.1.tgz", + "integrity": "sha512-ODqY18UZt/I8k+b7rl2AENgbWE8IDYam+undIJONvigAz8KR5GWblsFTEfQs0WODsjbSXWlm+JHEv8Gr6Tfdbg==", + "dev": true, + "requires": { + "jsonparse": "^1.3.1", + "minipass": "^3.0.0" + }, + "dependencies": { + "minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + } + } + }, + "minipass-pipeline": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", + "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", + "dev": true, + "requires": { + "minipass": "^3.0.0" + }, + "dependencies": { + "minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + } + } + }, + "minipass-sized": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", + "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", + "dev": true, + "requires": { + "minipass": "^3.0.0" + }, + "dependencies": { + "minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + } + } + }, + "minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "dev": true, + "requires": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "dependencies": { + "minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + } + } + }, + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "multicast-dns": { + "version": "7.2.5", + "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", + "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", + "dev": true, + "requires": { + "dns-packet": "^5.2.2", + "thunky": "^1.0.2" + } + }, + "mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", + "dev": true + }, + "nanoid": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "dev": true + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, + "needle": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/needle/-/needle-3.2.0.tgz", + "integrity": "sha512-oUvzXnyLiVyVGoianLijF9O/RecZUf7TkBfimjGrLM4eQhXyeJwM6GeAWccwfQ9aa4gMCZKqhAOuLaMIcQxajQ==", + "dev": true, + "optional": true, + "requires": { + "debug": "^3.2.6", + "iconv-lite": "^0.6.3", + "sax": "^1.2.4" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "optional": true, + "requires": { + "ms": "^2.1.1" + } + }, + "iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "optional": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + } + } + } + }, + "negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "dev": true + }, + "neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true + }, + "ngx-bootstrap-multiselect": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ngx-bootstrap-multiselect/-/ngx-bootstrap-multiselect-2.1.1.tgz", + "integrity": "sha512-BKE34b8wavxAyUlsZSPwR8p048sjfgVwBLMh5U0pw4TEt3onuF3+JzoTa2LAhPBhNxu+wc7af4IjdJ4mlrhKmQ==", + "requires": { + "tslib": "^2.0.0" + } + }, + "ngx-spinner": { + "version": "13.1.1", + "resolved": "https://registry.npmjs.org/ngx-spinner/-/ngx-spinner-13.1.1.tgz", + "integrity": "sha512-6aJz4KxIsBrlQckJxcM3CEvMcYbZoSDnQZPu0F/ZYAYunbBOTb9iydw0Gjczg9moum1VURWjX5dTVKmFo85c2Q==", + "requires": { + "tslib": "^2.3.0" + } + }, + "nice-napi": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/nice-napi/-/nice-napi-1.0.2.tgz", + "integrity": "sha512-px/KnJAJZf5RuBGcfD+Sp2pAKq0ytz8j+1NehvgIGFkvtvFrDM3T8E4x/JJODXK9WZow8RRGrbA9QQ3hs+pDhA==", + "dev": true, + "optional": true, + "requires": { + "node-addon-api": "^3.0.0", + "node-gyp-build": "^4.2.2" + } + }, + "node-addon-api": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz", + "integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==", + "dev": true, + "optional": true + }, + "node-forge": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", + "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", + "dev": true + }, + "node-gyp": { + "version": "9.4.1", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-9.4.1.tgz", + "integrity": "sha512-OQkWKbjQKbGkMf/xqI1jjy3oCTgMKJac58G2+bjZb3fza6gW2YrCSdMQYaoTb70crvE//Gngr4f0AgVHmqHvBQ==", + "dev": true, + "requires": { + "env-paths": "^2.2.0", + "exponential-backoff": "^3.1.1", + "glob": "^7.1.4", + "graceful-fs": "^4.2.6", + "make-fetch-happen": "^10.0.3", + "nopt": "^6.0.0", + "npmlog": "^6.0.0", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.2", + "which": "^2.0.2" + }, + "dependencies": { + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "node-gyp-build": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.4.0.tgz", + "integrity": "sha512-amJnQCcgtRVw9SvoebO3BKGESClrfXGCUTX9hSn1OuGQTQBOZmVd0Z0OlecpuRksKvbsUqALE8jls/ErClAPuQ==", + "dev": true, + "optional": true + }, + "node-releases": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", + "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==" + }, + "nopt": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-6.0.0.tgz", + "integrity": "sha512-ZwLpbTgdhuZUnZzjd7nb1ZV+4DoiC6/sfiVKok72ym/4Tlf+DFdlHYmT2JPmcNNWV6Pi3SDf1kT+A4r9RTuT9g==", + "dev": true, + "requires": { + "abbrev": "^1.0.0" + } + }, + "normalize-package-data": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-5.0.0.tgz", + "integrity": "sha512-h9iPVIfrVZ9wVYQnxFgtw1ugSvGEMOlyPWWtm8BMJhnwyEL/FLbYbTY3V3PpjI/BUK67n9PEWDu6eHzu1fB15Q==", + "dev": true, + "requires": { + "hosted-git-info": "^6.0.0", + "is-core-module": "^2.8.1", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4" + } + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" + }, + "normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", + "dev": true + }, + "npm-bundled": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-3.0.0.tgz", + "integrity": "sha512-Vq0eyEQy+elFpzsKjMss9kxqb9tG3YHg4dsyWuUENuzvSUWe1TCnW/vV9FkhvBk/brEDoDiVd+M1Btosa6ImdQ==", + "dev": true, + "requires": { + "npm-normalize-package-bin": "^3.0.0" + } + }, + "npm-install-checks": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-6.3.0.tgz", + "integrity": "sha512-W29RiK/xtpCGqn6f3ixfRYGk+zRyr+Ew9F2E20BfXxT5/euLdA/Nm7fO7OeTGuAmTs30cpgInyJ0cYe708YTZw==", + "dev": true, + "requires": { + "semver": "^7.1.1" + } + }, + "npm-normalize-package-bin": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-3.0.1.tgz", + "integrity": "sha512-dMxCf+zZ+3zeQZXKxmyuCKlIDPGuv8EF940xbkC4kQVDTtqoh6rJFO+JTKSA6/Rwi0getWmtuy4Itup0AMcaDQ==", + "dev": true + }, + "npm-package-arg": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-10.1.0.tgz", + "integrity": "sha512-uFyyCEmgBfZTtrKk/5xDfHp6+MdrqGotX/VoOyEEl3mBwiEE5FlBaePanazJSVMPT7vKepcjYBY2ztg9A3yPIA==", + "dev": true, + "requires": { + "hosted-git-info": "^6.0.0", + "proc-log": "^3.0.0", + "semver": "^7.3.5", + "validate-npm-package-name": "^5.0.0" + } + }, + "npm-packlist": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-7.0.4.tgz", + "integrity": "sha512-d6RGEuRrNS5/N84iglPivjaJPxhDbZmlbTwTDX2IbcRHG5bZCdtysYMhwiPvcF4GisXHGn7xsxv+GQ7T/02M5Q==", + "dev": true, + "requires": { + "ignore-walk": "^6.0.0" + } + }, + "npm-pick-manifest": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-8.0.1.tgz", + "integrity": "sha512-mRtvlBjTsJvfCCdmPtiu2bdlx8d/KXtF7yNXNWe7G0Z36qWA9Ny5zXsI2PfBZEv7SXgoxTmNaTzGSbbzDZChoA==", + "dev": true, + "requires": { + "npm-install-checks": "^6.0.0", + "npm-normalize-package-bin": "^3.0.0", + "npm-package-arg": "^10.0.0", + "semver": "^7.3.5" + } + }, + "npm-registry-fetch": { + "version": "14.0.5", + "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-14.0.5.tgz", + "integrity": "sha512-kIDMIo4aBm6xg7jOttupWZamsZRkAqMqwqqbVXnUqstY5+tapvv6bkH/qMR76jdgV+YljEUCyWx3hRYMrJiAgA==", + "dev": true, + "requires": { + "make-fetch-happen": "^11.0.0", + "minipass": "^5.0.0", + "minipass-fetch": "^3.0.0", + "minipass-json-stream": "^1.0.1", + "minizlib": "^2.1.2", + "npm-package-arg": "^10.0.0", + "proc-log": "^3.0.0" + }, + "dependencies": { + "lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "dev": true + }, + "make-fetch-happen": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-11.1.1.tgz", + "integrity": "sha512-rLWS7GCSTcEujjVBs2YqG7Y4643u8ucvCJeSRqiLYhesrDuzeuFIk37xREzAsfQaqzl8b9rNCE4m6J8tvX4Q8w==", + "dev": true, + "requires": { + "agentkeepalive": "^4.2.1", + "cacache": "^17.0.0", + "http-cache-semantics": "^4.1.1", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.0", + "is-lambda": "^1.0.1", + "lru-cache": "^7.7.1", + "minipass": "^5.0.0", + "minipass-fetch": "^3.0.0", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.3", + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^7.0.0", + "ssri": "^10.0.0" + } + }, + "minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "dev": true + }, + "minipass-fetch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.4.tgz", + "integrity": "sha512-jHAqnA728uUpIaFm7NWsCnqKT6UqZz7GcI/bDpPATuwYyKwJwW0remxSCxUlKiEty+eopHGa3oc8WxgQ1FFJqg==", + "dev": true, + "requires": { + "encoding": "^0.1.13", + "minipass": "^7.0.3", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" + }, + "dependencies": { + "minipass": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", + "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", + "dev": true + } + } + } + } + }, + "npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "requires": { + "path-key": "^3.0.0" + } + }, + "npmlog": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-6.0.2.tgz", + "integrity": "sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==", + "dev": true, + "requires": { + "are-we-there-yet": "^3.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^4.0.3", + "set-blocking": "^2.0.0" + } + }, + "nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dev": true, + "requires": { + "boolbase": "^1.0.0" + } + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true + }, + "object-inspect": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.1.tgz", + "integrity": "sha512-Y/jF6vnvEtOPGiKD1+q+X0CiUYRQtEHp89MLLUJ7TUivtH8Ugn2+3A7Rynqk7BRsAoqeOQWnFnjpDrKSxDgIGA==", + "dev": true + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true + }, + "object.assign": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", + "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "has-symbols": "^1.0.1", + "object-keys": "^1.1.1" + } + }, + "object.values": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.5.tgz", + "integrity": "sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1" + } + }, + "obuf": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", + "dev": true + }, + "on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dev": true, + "requires": { + "ee-first": "1.1.1" + } + }, + "on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "dev": true + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1" + } + }, + "onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "requires": { + "mimic-fn": "^2.1.0" + } + }, + "open": { + "version": "8.4.1", + "resolved": "https://registry.npmjs.org/open/-/open-8.4.1.tgz", + "integrity": "sha512-/4b7qZNhv6Uhd7jjnREh1NjnPxlTq+XNWPG88Ydkj5AILcA5m3ajvcg57pB24EQjKv0dK62XnDqk9c/hkIG5Kg==", + "dev": true, + "requires": { + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" + } + }, + "optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "requires": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + } + }, + "ora": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", + "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", + "dev": true, + "requires": { + "bl": "^4.1.0", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "is-unicode-supported": "^0.1.0", + "log-symbols": "^4.1.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", + "dev": true + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + }, + "p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "dev": true, + "requires": { + "aggregate-error": "^3.0.0" + } + }, + "p-retry": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", + "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", + "dev": true, + "requires": { + "@types/retry": "0.12.0", + "retry": "^0.13.1" + }, + "dependencies": { + "retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", + "dev": true + } + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, + "pacote": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/pacote/-/pacote-15.1.0.tgz", + "integrity": "sha512-FFcjtIl+BQNfeliSm7MZz5cpdohvUV1yjGnqgVM4UnVF7JslRY0ImXAygdaCDV0jjUADEWu4y5xsDV8brtrTLg==", + "dev": true, + "requires": { + "@npmcli/git": "^4.0.0", + "@npmcli/installed-package-contents": "^2.0.1", + "@npmcli/promise-spawn": "^6.0.1", + "@npmcli/run-script": "^6.0.0", + "cacache": "^17.0.0", + "fs-minipass": "^3.0.0", + "minipass": "^4.0.0", + "npm-package-arg": "^10.0.0", + "npm-packlist": "^7.0.0", + "npm-pick-manifest": "^8.0.0", + "npm-registry-fetch": "^14.0.0", + "proc-log": "^3.0.0", + "promise-retry": "^2.0.1", + "read-package-json": "^6.0.0", + "read-package-json-fast": "^3.0.0", + "sigstore": "^1.0.0", + "ssri": "^10.0.0", + "tar": "^6.1.11" + } + }, + "pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==" + }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "requires": { + "callsites": "^3.0.0" + } + }, + "parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + } + }, + "parse-node-version": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parse-node-version/-/parse-node-version-1.0.1.tgz", + "integrity": "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==", + "dev": true + }, + "parse5": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz", + "integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==", + "optional": true + }, + "parse5-html-rewriting-stream": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/parse5-html-rewriting-stream/-/parse5-html-rewriting-stream-7.0.0.tgz", + "integrity": "sha512-mazCyGWkmCRWDI15Zp+UiCqMp/0dgEmkZRvhlsqqKYr4SsVm/TvnSpD9fCvqCA2zoWJcfRym846ejWBBHRiYEg==", + "dev": true, + "requires": { + "entities": "^4.3.0", + "parse5": "^7.0.0", + "parse5-sax-parser": "^7.0.0" + }, + "dependencies": { + "entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "dev": true + }, + "parse5": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", + "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", + "dev": true, + "requires": { + "entities": "^4.4.0" + } + } + } + }, + "parse5-htmlparser2-tree-adapter": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz", + "integrity": "sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==", + "dev": true, + "requires": { + "parse5": "^6.0.1" + }, + "dependencies": { + "parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", + "dev": true + } + } + }, + "parse5-sax-parser": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/parse5-sax-parser/-/parse5-sax-parser-7.0.0.tgz", + "integrity": "sha512-5A+v2SNsq8T6/mG3ahcz8ZtQ0OUFTatxPbeidoMB7tkJSGDY3tdfl4MHovtLQHkEn5CGxijNWRQHhRQ6IRpXKg==", + "dev": true, + "requires": { + "parse5": "^7.0.0" + }, + "dependencies": { + "entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "dev": true + }, + "parse5": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", + "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", + "dev": true, + "requires": { + "entities": "^4.4.0" + } + } + } + }, + "parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "dev": true + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "path-scurry": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.1.tgz", + "integrity": "sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==", + "dev": true, + "requires": { + "lru-cache": "^9.1.1 || ^10.0.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "dependencies": { + "lru-cache": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.1.0.tgz", + "integrity": "sha512-/1clY/ui8CzjKFyjdvwPWJUYKiFVXG2I2cY0ssG7h4+hwk+XOIX7ZSG9Q7TW8TW3Kp3BUSqgFWBLgL4PJ+Blag==", + "dev": true + }, + "minipass": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", + "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", + "dev": true + } + } + }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==", + "dev": true + }, + "path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true + }, + "picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + }, + "picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true + }, + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true, + "optional": true + }, + "piscina": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/piscina/-/piscina-3.2.0.tgz", + "integrity": "sha512-yn/jMdHRw+q2ZJhFhyqsmANcbF6V2QwmD84c6xRau+QpQOmtrBCoRGdvTfeuFDYXB5W2m6MfLkjkvQa9lUSmIA==", + "dev": true, + "requires": { + "eventemitter-asyncresource": "^1.0.0", + "hdr-histogram-js": "^2.0.1", + "hdr-histogram-percentiles-obj": "^3.0.0", + "nice-napi": "^1.0.2" + } + }, + "pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "requires": { + "find-up": "^4.0.0" + } + }, + "postcss": { + "version": "8.4.31", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", + "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", + "dev": true, + "requires": { + "nanoid": "^3.3.6", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + } + }, + "postcss-loader": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-7.0.2.tgz", + "integrity": "sha512-fUJzV/QH7NXUAqV8dWJ9Lg4aTkDCezpTS5HgJ2DvqznexTbSTxgi/dTECvTZ15BwKTtk8G/bqI/QTu2HPd3ZCg==", + "dev": true, + "requires": { + "cosmiconfig": "^7.0.0", + "klona": "^2.0.5", + "semver": "^7.3.8" + } + }, + "postcss-modules-extract-imports": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz", + "integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==", + "dev": true + }, + "postcss-modules-local-by-default": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.3.tgz", + "integrity": "sha512-2/u2zraspoACtrbFRnTijMiQtb4GW4BvatjaG/bCjYQo8kLTdevCUlwuBHx2sCnSyrI3x3qj4ZK1j5LQBgzmwA==", + "dev": true, + "requires": { + "icss-utils": "^5.0.0", + "postcss-selector-parser": "^6.0.2", + "postcss-value-parser": "^4.1.0" + } + }, + "postcss-modules-scope": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz", + "integrity": "sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg==", + "dev": true, + "requires": { + "postcss-selector-parser": "^6.0.4" + } + }, + "postcss-modules-values": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", + "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", + "dev": true, + "requires": { + "icss-utils": "^5.0.0" + } + }, + "postcss-selector-parser": { + "version": "6.0.13", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz", + "integrity": "sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ==", + "dev": true, + "requires": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + } + }, + "postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "dev": true + }, + "prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true + }, + "pretty-bytes": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", + "integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==", + "dev": true + }, + "proc-log": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-3.0.0.tgz", + "integrity": "sha512-++Vn7NS4Xf9NacaU9Xq3URUuqZETPsf8L4j5/ckhaRYsfPeRyzGw+iDjFhV/Jr3uNmTvvddEJFWh5R1gRgUH8A==", + "dev": true + }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "promise-inflight": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", + "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==", + "dev": true + }, + "promise-retry": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", + "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", + "dev": true, + "requires": { + "err-code": "^2.0.2", + "retry": "^0.12.0" + } + }, + "proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dev": true, + "requires": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "dependencies": { + "ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "dev": true + } + } + }, + "prr": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", + "integrity": "sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==", + "dev": true, + "optional": true + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true + }, + "qjobs": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/qjobs/-/qjobs-1.2.0.tgz", + "integrity": "sha512-8YOJEHtxpySA3fFDyCRxA+UUV+fA+rTWnuWvylOK/NCjhY+b4ocCtmu8TtsWb+mYeU+GCHf/S66KZF/AsteKHg==", + "dev": true + }, + "qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dev": true, + "requires": { + "side-channel": "^1.0.4" + } + }, + "queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true + }, + "randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "requires": { + "safe-buffer": "^5.1.0" + } + }, + "range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "dev": true + }, + "raw-body": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "dev": true, + "requires": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + } + }, + "read-package-json": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-6.0.4.tgz", + "integrity": "sha512-AEtWXYfopBj2z5N5PbkAOeNHRPUg5q+Nen7QLxV8M2zJq1ym6/lCz3fYNTCXe19puu2d06jfHhrP7v/S2PtMMw==", + "dev": true, + "requires": { + "glob": "^10.2.2", + "json-parse-even-better-errors": "^3.0.0", + "normalize-package-data": "^5.0.0", + "npm-normalize-package-bin": "^3.0.0" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + }, + "glob": { + "version": "10.3.10", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", + "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", + "dev": true, + "requires": { + "foreground-child": "^3.1.0", + "jackspeak": "^2.3.5", + "minimatch": "^9.0.1", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", + "path-scurry": "^1.10.1" + } + }, + "json-parse-even-better-errors": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.1.tgz", + "integrity": "sha512-aatBvbL26wVUCLmbWdCpeu9iF5wOyWpagiKkInA+kfws3sWdBrTnsvN2CKcyCYyUrc7rebNBlK6+kteg7ksecg==", + "dev": true + }, + "minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + }, + "minipass": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", + "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", + "dev": true + } + } + }, + "read-package-json-fast": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/read-package-json-fast/-/read-package-json-fast-3.0.2.tgz", + "integrity": "sha512-0J+Msgym3vrLOUB3hzQCuZHII0xkNGCtz/HJH9xZshwv9DbDwkw1KaE3gx/e2J5rpEY5rtOy6cyhKOPrkP7FZw==", + "dev": true, + "requires": { + "json-parse-even-better-errors": "^3.0.0", + "npm-normalize-package-bin": "^3.0.0" + }, + "dependencies": { + "json-parse-even-better-errors": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.1.tgz", + "integrity": "sha512-aatBvbL26wVUCLmbWdCpeu9iF5wOyWpagiKkInA+kfws3sWdBrTnsvN2CKcyCYyUrc7rebNBlK6+kteg7ksecg==", + "dev": true + } + } + }, + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "readdir-glob": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/readdir-glob/-/readdir-glob-1.1.1.tgz", + "integrity": "sha512-91/k1EzZwDx6HbERR+zucygRFfiPl2zkIYZtv3Jjr6Mn7SkKcVct8aVO+sSRiGMc6fLf72du3d92/uY63YPdEA==", + "requires": { + "minimatch": "^3.0.4" + } + }, + "readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "requires": { + "picomatch": "^2.2.1" + } + }, + "reflect-metadata": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz", + "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==", + "dev": true + }, + "regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", + "dev": true + }, + "regenerate-unicode-properties": { + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.1.tgz", + "integrity": "sha512-X007RyZLsCJVVrjgEFVpLUTZwyOZk3oiL75ZcuYjlIWd6rNJtOjkBwQc5AsRrpbKVkxN6sklw/k/9m2jJYOf8Q==", + "dev": true, + "requires": { + "regenerate": "^1.4.2" + } + }, + "regenerator-runtime": { + "version": "0.13.11", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", + "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==", + "dev": true + }, + "regenerator-transform": { + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.2.tgz", + "integrity": "sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==", + "dev": true, + "requires": { + "@babel/runtime": "^7.8.4" + } + }, + "regex-parser": { + "version": "2.2.11", + "resolved": "https://registry.npmjs.org/regex-parser/-/regex-parser-2.2.11.tgz", + "integrity": "sha512-jbD/FT0+9MBU2XAZluI7w2OBs1RBi6p9M83nkoZayQXXU9e8Robt69FcZc7wU4eJD/YFTjn1JdCk3rbMJajz8Q==", + "dev": true + }, + "regexp.prototype.flags": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", + "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "functions-have-names": "^1.2.2" + } + }, + "regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "dev": true + }, + "regexpu-core": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.3.2.tgz", + "integrity": "sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ==", + "dev": true, + "requires": { + "@babel/regjsgen": "^0.8.0", + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.1.0", + "regjsparser": "^0.9.1", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.1.0" + } + }, + "regjsparser": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", + "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", + "dev": true, + "requires": { + "jsesc": "~0.5.0" + }, + "dependencies": { + "jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==", + "dev": true + } + } + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=" + }, + "require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true + }, + "requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=", + "dev": true + }, + "resolve": { + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", + "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "dev": true, + "requires": { + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } + }, + "resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true + }, + "resolve-url-loader": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-url-loader/-/resolve-url-loader-5.0.0.tgz", + "integrity": "sha512-uZtduh8/8srhBoMx//5bwqjQ+rfYOUq8zC9NrMUGtjBiGTtFJM42s58/36+hTqeqINcnYe08Nj3LkK9lW4N8Xg==", + "dev": true, + "requires": { + "adjust-sourcemap-loader": "^4.0.0", + "convert-source-map": "^1.7.0", + "loader-utils": "^2.0.0", + "postcss": "^8.2.14", + "source-map": "0.6.1" + }, + "dependencies": { + "loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "dev": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dev": true, + "requires": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + } + }, + "retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", + "dev": true + }, + "reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true + }, + "rfdc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz", + "integrity": "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==", + "dev": true + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "requires": { + "glob": "^7.1.3" + } + }, + "run-async": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", + "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", + "dev": true + }, + "run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "requires": { + "queue-microtask": "^1.2.2" + } + }, + "rxjs": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.5.tgz", + "integrity": "sha512-sy+H0pQofO95VDmFLzyaw9xNJU4KTRSwQIGM6+iG3SypAtCiLDzpeG8sJrNCWn2Up9km+KhkvTdbkrdy+yzZdw==", + "requires": { + "tslib": "^2.1.0" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "sass": { + "version": "1.58.1", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.58.1.tgz", + "integrity": "sha512-bnINi6nPXbP1XNRaranMFEBZWUfdW/AF16Ql5+ypRxfTvCRTTKrLsMIakyDcayUt2t/RZotmL4kgJwNH5xO+bg==", + "dev": true, + "requires": { + "chokidar": ">=3.0.0 <4.0.0", + "immutable": "^4.0.0", + "source-map-js": ">=0.6.2 <2.0.0" + } + }, + "sass-loader": { + "version": "13.2.0", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-13.2.0.tgz", + "integrity": "sha512-JWEp48djQA4nbZxmgC02/Wh0eroSUutulROUusYJO9P9zltRbNN80JCBHqRGzjd4cmZCa/r88xgfkjGD0TXsHg==", + "dev": true, + "requires": { + "klona": "^2.0.4", + "neo-async": "^2.6.2" + } + }, + "sax": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.3.0.tgz", + "integrity": "sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA==", + "dev": true, + "optional": true + }, + "saxes": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", + "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==", + "requires": { + "xmlchars": "^2.2.0" + } + }, + "schema-utils": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", + "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + } + }, + "select-hose": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", + "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==", + "dev": true + }, + "selfsigned": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.4.1.tgz", + "integrity": "sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q==", + "dev": true, + "requires": { + "@types/node-forge": "^1.3.0", + "node-forge": "^1" + } + }, + "semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "dev": true, + "requires": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + }, + "dependencies": { + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + } + } + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true + } + } + }, + "serialize-javascript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", + "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "dev": true, + "requires": { + "randombytes": "^2.1.0" + } + }, + "serve-index": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==", + "dev": true, + "requires": { + "accepts": "~1.3.4", + "batch": "0.6.1", + "debug": "2.6.9", + "escape-html": "~1.0.3", + "http-errors": "~1.6.2", + "mime-types": "~2.1.17", + "parseurl": "~1.3.2" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "dev": true + }, + "http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", + "dev": true, + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", + "dev": true + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", + "dev": true + } + } + }, + "serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "dev": true, + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + } + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "dev": true + }, + "setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=" + }, + "setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "dev": true + }, + "shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dev": true, + "requires": { + "kind-of": "^6.0.2" + } + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, + "side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + } + }, + "signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "sigstore": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/sigstore/-/sigstore-1.9.0.tgz", + "integrity": "sha512-0Zjz0oe37d08VeOtBIuB6cRriqXse2e8w+7yIy2XSXjshRKxbc2KkhXjL229jXSxEm7UbcjS76wcJDGQddVI9A==", + "dev": true, + "requires": { + "@sigstore/bundle": "^1.1.0", + "@sigstore/protobuf-specs": "^0.2.0", + "@sigstore/sign": "^1.0.0", + "@sigstore/tuf": "^1.0.3", + "make-fetch-happen": "^11.0.1" + }, + "dependencies": { + "lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "dev": true + }, + "make-fetch-happen": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-11.1.1.tgz", + "integrity": "sha512-rLWS7GCSTcEujjVBs2YqG7Y4643u8ucvCJeSRqiLYhesrDuzeuFIk37xREzAsfQaqzl8b9rNCE4m6J8tvX4Q8w==", + "dev": true, + "requires": { + "agentkeepalive": "^4.2.1", + "cacache": "^17.0.0", + "http-cache-semantics": "^4.1.1", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.0", + "is-lambda": "^1.0.1", + "lru-cache": "^7.7.1", + "minipass": "^5.0.0", + "minipass-fetch": "^3.0.0", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.3", + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^7.0.0", + "ssri": "^10.0.0" + } + }, + "minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "dev": true + }, + "minipass-fetch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.4.tgz", + "integrity": "sha512-jHAqnA728uUpIaFm7NWsCnqKT6UqZz7GcI/bDpPATuwYyKwJwW0remxSCxUlKiEty+eopHGa3oc8WxgQ1FFJqg==", + "dev": true, + "requires": { + "encoding": "^0.1.13", + "minipass": "^7.0.3", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" + }, + "dependencies": { + "minipass": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", + "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", + "dev": true + } + } + } + } + }, + "slash": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", + "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", + "dev": true + }, + "smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "dev": true + }, + "socket.io": { + "version": "4.7.5", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.7.5.tgz", + "integrity": "sha512-DmeAkF6cwM9jSfmp6Dr/5/mfMwb5Z5qRrSXLpo3Fq5SqyU8CMF15jIN4ZhfSwu35ksM1qmHZDQ/DK5XTccSTvA==", + "dev": true, + "requires": { + "accepts": "~1.3.4", + "base64id": "~2.0.0", + "cors": "~2.8.5", + "debug": "~4.3.2", + "engine.io": "~6.5.2", + "socket.io-adapter": "~2.5.2", + "socket.io-parser": "~4.2.4" + } + }, + "socket.io-adapter": { + "version": "2.5.4", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.4.tgz", + "integrity": "sha512-wDNHGXGewWAjQPt3pyeYBtpWSq9cLE5UW1ZUPL/2eGK9jtse/FpXib7epSTsz0Q0m+6sg6Y4KtcFTlah1bdOVg==", + "dev": true, + "requires": { + "debug": "~4.3.4", + "ws": "~8.11.0" + } + }, + "socket.io-parser": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz", + "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==", + "dev": true, + "requires": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.1" + } + }, + "sockjs": { + "version": "0.3.24", + "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", + "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==", + "dev": true, + "requires": { + "faye-websocket": "^0.11.3", + "uuid": "^8.3.2", + "websocket-driver": "^0.7.4" + } + }, + "socks": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz", + "integrity": "sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==", + "dev": true, + "requires": { + "ip": "^2.0.0", + "smart-buffer": "^4.2.0" + } + }, + "socks-proxy-agent": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-7.0.0.tgz", + "integrity": "sha512-Fgl0YPZ902wEsAyiQ+idGd1A7rSFx/ayC1CQVMw5P+EQx2V0SgpGtf6OKFhVjPflPUl9YMmEOnmfjCdMUsygww==", + "dev": true, + "requires": { + "agent-base": "^6.0.2", + "debug": "^4.3.3", + "socks": "^2.6.2" + } + }, + "source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "dev": true + }, + "source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "dev": true + }, + "source-map-loader": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/source-map-loader/-/source-map-loader-4.0.1.tgz", + "integrity": "sha512-oqXpzDIByKONVY8g1NUPOTQhe0UTU5bWUl32GSkqK2LjJj0HmwTMVKxcUip0RgAYhY1mqgOxjbQM48a0mmeNfA==", + "dev": true, + "requires": { + "abab": "^2.0.6", + "iconv-lite": "^0.6.3", + "source-map-js": "^1.0.2" + }, + "dependencies": { + "iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + } + } + } + }, + "source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "spdx-correct": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", + "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", + "dev": true, + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", + "dev": true + }, + "spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.16", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.16.tgz", + "integrity": "sha512-eWN+LnM3GR6gPu35WxNgbGl8rmY1AEmoMDvL/QD6zYmPWgywxWqJWNdLGT+ke8dKNWrcYgYjPpG5gbTfghP8rw==", + "dev": true + }, + "spdy": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", + "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", + "dev": true, + "requires": { + "debug": "^4.1.0", + "handle-thing": "^2.0.0", + "http-deceiver": "^1.2.7", + "select-hose": "^2.0.0", + "spdy-transport": "^3.0.0" + } + }, + "spdy-transport": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", + "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", + "dev": true, + "requires": { + "debug": "^4.1.0", + "detect-node": "^2.0.4", + "hpack.js": "^2.1.6", + "obuf": "^1.1.2", + "readable-stream": "^3.0.6", + "wbuf": "^1.7.3" + } + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "ssf": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/ssf/-/ssf-0.11.2.tgz", + "integrity": "sha512-+idbmIXoYET47hH+d7dfm2epdOMUDjqcB4648sTZ+t2JwoyBFL/insLfB/racrDmsKB3diwsDA696pZMieAC5g==", + "requires": { + "frac": "~1.1.2" + } + }, + "ssri": { + "version": "10.0.5", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-10.0.5.tgz", + "integrity": "sha512-bSf16tAFkGeRlUNDjXu8FzaMQt6g2HZJrun7mtMbIPOddxt3GLMSz5VWUWcqTJUPfLEaDIepGxv+bYQW49596A==", + "dev": true, + "requires": { + "minipass": "^7.0.3" + }, + "dependencies": { + "minipass": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", + "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", + "dev": true + } + } + }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", + "dev": true + }, + "streamroller": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-3.1.1.tgz", + "integrity": "sha512-iPhtd9unZ6zKdWgMeYGfSBuqCngyJy1B/GPi/lTpwGpa3bajuX30GjUVd0/Tn/Xhg0mr4DOSENozz9Y06qyonQ==", + "dev": true, + "requires": { + "date-format": "^4.0.10", + "debug": "^4.3.4", + "fs-extra": "^10.1.0" + } + }, + "string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "requires": { + "safe-buffer": "~5.2.0" + }, + "dependencies": { + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + } + } + }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "string-width-cjs": { + "version": "npm:string-width@4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "string.prototype.trimend": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.5.tgz", + "integrity": "sha512-I7RGvmjV4pJ7O3kdf+LXFpVfdNOxtCW/2C8f6jNiW4+PQchwxkCDzlk1/7p+Wl4bqFIZeF47qAHXLuHHWKAxog==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.19.5" + } + }, + "string.prototype.trimstart": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.5.tgz", + "integrity": "sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.19.5" + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "strip-ansi-cjs": { + "version": "npm:strip-ansi@6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + }, + "strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true + }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "requires": { + "has-flag": "^3.0.0" + } + }, + "supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true + }, + "sweetalert2": { + "version": "11.10.7", + "resolved": "https://registry.npmjs.org/sweetalert2/-/sweetalert2-11.10.7.tgz", + "integrity": "sha512-5Jlzrmaitay6KzU+2+LhYu9q+L4v/dZ8oZyEDH14ep0C/QilCnFLHmqAyD/Lhq/lm5DiwsOs6Tr58iv8k3wyGg==" + }, + "symbol-observable": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-4.0.0.tgz", + "integrity": "sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ==", + "dev": true + }, + "tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "dev": true + }, + "tar": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", + "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", + "dev": true, + "requires": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^5.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "dependencies": { + "fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "dev": true, + "requires": { + "minipass": "^3.0.0" + }, + "dependencies": { + "minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + } + } + }, + "minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "dev": true + } + } + }, + "tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "requires": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + } + }, + "terser": { + "version": "5.16.3", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.16.3.tgz", + "integrity": "sha512-v8wWLaS/xt3nE9dgKEWhNUFP6q4kngO5B8eYFUuebsu7Dw/UNAnpUod6UHo04jSSkv8TzKHjZDSd7EXdDQAl8Q==", + "dev": true, + "requires": { + "@jridgewell/source-map": "^0.3.2", + "acorn": "^8.5.0", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + } + }, + "terser-webpack-plugin": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.1.tgz", + "integrity": "sha512-GvlZdT6wPQKbDNW/GDQzZFg/j4vKU96yl2q6mcUkzKOgW4gwf1Z8cZToUCrz31XHlPWH8MVb1r2tFtdDtTGJ7g==", + "dev": true, + "requires": { + "jest-worker": "^27.4.5", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.0", + "source-map": "^0.6.1", + "terser": "^5.7.2" + }, + "dependencies": { + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "schema-utils": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", + "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, + "requires": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + } + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", + "dev": true + }, + "thunky": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", + "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", + "dev": true + }, + "tmp": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", + "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", + "requires": { + "rimraf": "^3.0.0" + } + }, + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==" + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + }, + "toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "dev": true + }, + "traverse": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.3.9.tgz", + "integrity": "sha1-cXuPIgzAu3tE5AUUwisui7xw2Lk=" + }, + "tree-kill": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", + "dev": true + }, + "tsconfig-paths": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz", + "integrity": "sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==", + "dev": true, + "requires": { + "@types/json5": "^0.0.29", + "json5": "^1.0.1", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + }, + "dependencies": { + "json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + } + } + } + }, + "tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==" + }, + "tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dev": true, + "requires": { + "tslib": "^1.8.1" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "tuf-js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/tuf-js/-/tuf-js-1.1.7.tgz", + "integrity": "sha512-i3P9Kgw3ytjELUfpuKVDNBJvk4u5bXL6gskv572mcevPbSKCV3zt3djhmlEQ65yERjIbOSncy7U4cQJaB1CBCg==", + "dev": true, + "requires": { + "@tufjs/models": "1.0.4", + "debug": "^4.3.4", + "make-fetch-happen": "^11.1.1" + }, + "dependencies": { + "lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "dev": true + }, + "make-fetch-happen": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-11.1.1.tgz", + "integrity": "sha512-rLWS7GCSTcEujjVBs2YqG7Y4643u8ucvCJeSRqiLYhesrDuzeuFIk37xREzAsfQaqzl8b9rNCE4m6J8tvX4Q8w==", + "dev": true, + "requires": { + "agentkeepalive": "^4.2.1", + "cacache": "^17.0.0", + "http-cache-semantics": "^4.1.1", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.0", + "is-lambda": "^1.0.1", + "lru-cache": "^7.7.1", + "minipass": "^5.0.0", + "minipass-fetch": "^3.0.0", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.3", + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^7.0.0", + "ssri": "^10.0.0" + } + }, + "minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "dev": true + }, + "minipass-fetch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.4.tgz", + "integrity": "sha512-jHAqnA728uUpIaFm7NWsCnqKT6UqZz7GcI/bDpPATuwYyKwJwW0remxSCxUlKiEty+eopHGa3oc8WxgQ1FFJqg==", + "dev": true, + "requires": { + "encoding": "^0.1.13", + "minipass": "^7.0.3", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" + }, + "dependencies": { + "minipass": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", + "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", + "dev": true + } + } + } + } + }, + "type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1" + } + }, + "type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true + }, + "type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dev": true, + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + } + }, + "typed-assert": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/typed-assert/-/typed-assert-1.0.9.tgz", + "integrity": "sha512-KNNZtayBCtmnNmbo5mG47p1XsCyrx6iVqomjcZnec/1Y5GGARaxPs6r49RnSPeUP3YjNYiU9sQHAtY4BBvnZwg==", + "dev": true + }, + "typescript": { + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "dev": true + }, + "ua-parser-js": { + "version": "0.7.37", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.37.tgz", + "integrity": "sha512-xV8kqRKM+jhMvcHWUKthV9fNebIzrNy//2O9ZwWcfiBFR5f25XVZPLlEajk/sf3Ra15V92isyQqnIEXRDaZWEA==", + "dev": true + }, + "unbox-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + } + }, + "unicode-canonical-property-names-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", + "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==", + "dev": true + }, + "unicode-match-property-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", + "dev": true, + "requires": { + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" + } + }, + "unicode-match-property-value-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz", + "integrity": "sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==", + "dev": true + }, + "unicode-property-aliases-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", + "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", + "dev": true + }, + "unique-filename": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-3.0.0.tgz", + "integrity": "sha512-afXhuC55wkAmZ0P18QsVE6kp8JaxrEokN2HGIoIVv2ijHQd419H0+6EigAFcIzXeMIkcIkNBpB3L/DXB3cTS/g==", + "dev": true, + "requires": { + "unique-slug": "^4.0.0" + } + }, + "unique-slug": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-4.0.0.tgz", + "integrity": "sha512-WrcA6AyEfqDX5bWige/4NQfPZMtASNVxdmWR76WESYQVAACSgWcR6e9i0mofqqBxYFtL4oAxPIptY73/0YE1DQ==", + "dev": true, + "requires": { + "imurmurhash": "^0.1.4" + } + }, + "universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "dev": true + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", + "dev": true + }, + "unzipper": { + "version": "0.10.11", + "resolved": "https://registry.npmjs.org/unzipper/-/unzipper-0.10.11.tgz", + "integrity": "sha512-+BrAq2oFqWod5IESRjL3S8baohbevGcVA+teAIOYWM3pDVdseogqbzhhvvmiyQrUNKFUnDMtELW3X8ykbyDCJw==", + "requires": { + "big-integer": "^1.6.17", + "binary": "~0.3.0", + "bluebird": "~3.4.1", + "buffer-indexof-polyfill": "~1.0.0", + "duplexer2": "~0.1.4", + "fstream": "^1.0.12", + "graceful-fs": "^4.2.2", + "listenercount": "~1.0.1", + "readable-stream": "~2.3.6", + "setimmediate": "~1.0.4" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "update-browserslist-db": { + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", + "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", + "requires": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + } + }, + "uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", + "dev": true + }, + "uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" + }, + "v8-compile-cache": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", + "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", + "dev": true + }, + "validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "validate-npm-package-name": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-5.0.0.tgz", + "integrity": "sha512-YuKoXDAhBYxY7SfOKxHBDoSyENFeW5VvIIQp2TGQuit8gpK6MnWaQelBKxso72DoxTZfZdcP3W90LqpSkgPzLQ==", + "dev": true, + "requires": { + "builtins": "^5.0.0" + } + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", + "dev": true + }, + "void-elements": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz", + "integrity": "sha1-wGavtYK7HLQSjWDqkjkulNXp2+w=", + "dev": true + }, + "watchpack": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", + "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", + "dev": true, + "requires": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + } + }, + "wbuf": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", + "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", + "dev": true, + "requires": { + "minimalistic-assert": "^1.0.0" + } + }, + "wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g=", + "dev": true, + "requires": { + "defaults": "^1.0.3" + } + }, + "webpack": { + "version": "5.76.1", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.76.1.tgz", + "integrity": "sha512-4+YIK4Abzv8172/SGqObnUjaIHjLEuUasz9EwQj/9xmPPkYJy2Mh03Q/lJfSD3YLzbxy5FeTq5Uw0323Oh6SJQ==", + "dev": true, + "requires": { + "@types/eslint-scope": "^3.7.3", + "@types/estree": "^0.0.51", + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/wasm-edit": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1", + "acorn": "^8.7.1", + "acorn-import-assertions": "^1.7.6", + "browserslist": "^4.14.5", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.10.0", + "es-module-lexer": "^0.9.0", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.9", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.1.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.1.3", + "watchpack": "^2.4.0", + "webpack-sources": "^3.2.3" + }, + "dependencies": { + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "schema-utils": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", + "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + } + } + } + }, + "webpack-dev-middleware": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-6.1.2.tgz", + "integrity": "sha512-Wu+EHmX326YPYUpQLKmKbTyZZJIB8/n6R09pTmB03kJmnMsVPTo9COzHZFr01txwaCAuZvfBJE4ZCHRcKs5JaQ==", + "dev": true, + "requires": { + "colorette": "^2.0.10", + "memfs": "^3.4.12", + "mime-types": "^2.1.31", + "range-parser": "^1.2.1", + "schema-utils": "^4.0.0" + } + }, + "webpack-dev-server": { + "version": "4.11.1", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.11.1.tgz", + "integrity": "sha512-lILVz9tAUy1zGFwieuaQtYiadImb5M3d+H+L1zDYalYoDl0cksAB1UNyuE5MMWJrG6zR1tXkCP2fitl7yoUJiw==", + "dev": true, + "requires": { + "@types/bonjour": "^3.5.9", + "@types/connect-history-api-fallback": "^1.3.5", + "@types/express": "^4.17.13", + "@types/serve-index": "^1.9.1", + "@types/serve-static": "^1.13.10", + "@types/sockjs": "^0.3.33", + "@types/ws": "^8.5.1", + "ansi-html-community": "^0.0.8", + "bonjour-service": "^1.0.11", + "chokidar": "^3.5.3", + "colorette": "^2.0.10", + "compression": "^1.7.4", + "connect-history-api-fallback": "^2.0.0", + "default-gateway": "^6.0.3", + "express": "^4.17.3", + "graceful-fs": "^4.2.6", + "html-entities": "^2.3.2", + "http-proxy-middleware": "^2.0.3", + "ipaddr.js": "^2.0.1", + "open": "^8.0.9", + "p-retry": "^4.5.0", + "rimraf": "^3.0.2", + "schema-utils": "^4.0.0", + "selfsigned": "^2.1.1", + "serve-index": "^1.9.1", + "sockjs": "^0.3.24", + "spdy": "^4.0.2", + "webpack-dev-middleware": "^5.3.1", + "ws": "^8.4.2" + }, + "dependencies": { + "webpack-dev-middleware": { + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.4.tgz", + "integrity": "sha512-BVdTqhhs+0IfoeAf7EoH5WE+exCmqGerHfDM0IL096Px60Tq2Mn9MAbnaGUe6HiMa41KMCYF19gyzZmBcq/o4Q==", + "dev": true, + "requires": { + "colorette": "^2.0.10", + "memfs": "^3.4.3", + "mime-types": "^2.1.31", + "range-parser": "^1.2.1", + "schema-utils": "^4.0.0" + } + }, + "ws": { + "version": "8.14.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.14.2.tgz", + "integrity": "sha512-wEBG1ftX4jcglPxgFCMJmZ2PLtSbJ2Peg6TmpJFTbe9GZYOQCDPdMYu/Tm0/bGZkw8paZnJY45J4K2PZrLYq8g==", + "dev": true + } + } + }, + "webpack-merge": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.8.0.tgz", + "integrity": "sha512-/SaI7xY0831XwP6kzuwhKWVKDP9t1QY1h65lAFLbZqMPIuYcD9QAW4u9STIbU9kaJbPBB/geU/gLr1wDjOhQ+Q==", + "dev": true, + "requires": { + "clone-deep": "^4.0.1", + "wildcard": "^2.0.0" + } + }, + "webpack-sources": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", + "dev": true + }, + "webpack-subresource-integrity": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/webpack-subresource-integrity/-/webpack-subresource-integrity-5.1.0.tgz", + "integrity": "sha512-sacXoX+xd8r4WKsy9MvH/q/vBtEHr86cpImXwyg74pFIpERKt6FmB8cXpeuh0ZLgclOlHI4Wcll7+R5L02xk9Q==", + "dev": true, + "requires": { + "typed-assert": "^1.0.8" + } + }, + "websocket-driver": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", + "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", + "dev": true, + "requires": { + "http-parser-js": ">=0.5.1", + "safe-buffer": ">=5.1.0", + "websocket-extensions": ">=0.1.1" + } + }, + "websocket-extensions": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", + "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", + "dev": true + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dev": true, + "requires": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + } + }, + "wide-align": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "dev": true, + "requires": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, + "wildcard": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.0.tgz", + "integrity": "sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw==", + "dev": true + }, + "wmf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wmf/-/wmf-1.0.2.tgz", + "integrity": "sha512-/p9K7bEh0Dj6WbXg4JG0xvLQmIadrner1bi45VMJTfnbVHsc7yIajZyoSoK60/dtVBs12Fm6WkUI5/3WAVsNMw==" + }, + "word": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/word/-/word-0.3.0.tgz", + "integrity": "sha512-OELeY0Q61OXpdUfTp+oweA/vtLVg5VDOXh+3he3PNzLGG/y0oylSOC1xRVj0+l4vQ3tj/bB1HVHv1ocXkQceFA==" + }, + "word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true + }, + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + } + } + }, + "wrap-ansi-cjs": { + "version": "npm:wrap-ansi@7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + } + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "ws": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", + "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==", + "dev": true + }, + "xlsx": { + "version": "0.18.5", + "resolved": "https://registry.npmjs.org/xlsx/-/xlsx-0.18.5.tgz", + "integrity": "sha512-dmg3LCjBPHZnQp5/F/+nnTa+miPJxUXB6vtk42YjBBKayDNagxGEeIdWApkYPOf3Z3pm3k62Knjzp7lMeTEtFQ==", + "requires": { + "adler-32": "~1.3.0", + "cfb": "~1.2.1", + "codepage": "~1.15.0", + "crc-32": "~1.2.1", + "ssf": "~0.11.2", + "wmf": "~1.0.1", + "word": "~0.3.0" + } + }, + "xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==" + }, + "y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==" + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "dev": true + }, + "yargs": { + "version": "17.6.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.6.2.tgz", + "integrity": "sha512-1/9UrdHjDZc0eOU0HxOHoS78C69UD3JRMvzlJ7S79S2nTaWRA/whGCTV8o9e/N/1Va9YIV7Q4sOxD8VV4pCWOw==", + "requires": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "dependencies": { + "cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + } + } + } + }, + "yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==" + }, + "zip-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-4.1.0.tgz", + "integrity": "sha512-zshzwQW7gG7hjpBlgeQP9RuyPGNxvJdzR8SUM3QhxCnLjWN2E7j3dOvpeDcQoETfHx0urRS7EtmVToql7YpU4A==", + "requires": { + "archiver-utils": "^2.1.0", + "compress-commons": "^4.1.0", + "readable-stream": "^3.6.0" + } + }, + "zone.js": { + "version": "0.11.5", + "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.11.5.tgz", + "integrity": "sha512-D1/7VxEuQ7xk6z/kAROe4SUbd9CzxY4zOwVGnGHerd/SgLIVU5f4esDzQUsOCeArn933BZfWMKydH7l7dPEp0g==", + "requires": { + "tslib": "^2.3.0" + } + } + } +} diff --git a/corporate_finances_ui_py/package.json b/corporate_finances_ui_py/package.json new file mode 100644 index 0000000..7abc7fa --- /dev/null +++ b/corporate_finances_ui_py/package.json @@ -0,0 +1,63 @@ +{ + "name": "delta", + "version": "6.4.2", + "scripts": { + "ng": "ng", + "start": "ng serve", + "build": "ng build", + "dev": "ng build --c dev", + "qa": "ng build --c qa", + "production": "ng build --c production", + "watch": "ng build --watch --configuration development", + "test": "ng test" + }, + "private": true, + "dependencies": { + "@angular/animations": "^15.2.10", + "@angular/cdk": "^13.3.8", + "@angular/common": "^15.2.10", + "@angular/compiler": "^15.2.10", + "@angular/core": "^15.2.10", + "@angular/forms": "^15.2.10", + "@angular/localize": "^15.2.10", + "@angular/platform-browser": "^15.2.10", + "@angular/platform-browser-dynamic": "^15.2.10", + "@angular/router": "^15.2.10", + "@azure/msal-angular": "^2.5.4", + "@azure/msal-browser": "^2.34.0", + "@ng-bootstrap/ng-bootstrap": "^12.1.2", + "@ng-idle/core": "^11.1.0", + "@ng-idle/keepalive": "^11.0.3", + "@popperjs/core": "^2.11.5", + "bootstrap": "^5.1.3", + "exceljs": "^4.3.0", + "file-saver": "^2.0.5", + "ngx-bootstrap-multiselect": "^2.1.1", + "ngx-spinner": "^13.1.1", + "rxjs": "~7.5.0", + "sweetalert2": "^11.4.17", + "tslib": "^2.3.0", + "xlsx": "^0.18.5", + "zone.js": "~0.11.4" + }, + "devDependencies": { + "@angular-devkit/build-angular": "^15.2.10", + "@angular/cli": "^15.2.10", + "@angular/compiler-cli": "^15.2.10", + "@types/events": "^3.0.0", + "@types/file-saver": "^2.0.5", + "@types/jasmine": "~3.10.0", + "@types/node": "^12.11.1", + "@typescript-eslint/parser": "^5.26.0", + "eslint": "^8.16.0", + "eslint-import-resolver-typescript": "^2.7.1", + "eslint-plugin-import": "^2.26.0", + "jasmine-core": "~4.0.0", + "karma": "~6.3.0", + "karma-chrome-launcher": "~3.1.0", + "karma-coverage": "~2.1.0", + "karma-jasmine": "~4.0.0", + "karma-jasmine-html-reporter": "~1.7.0", + "typescript": "~4.9.5" + } +} \ No newline at end of file diff --git a/corporate_finances_ui_py/src/app/Common/Services/Assessment/orchestrator.service.ts b/corporate_finances_ui_py/src/app/Common/Services/Assessment/orchestrator.service.ts new file mode 100644 index 0000000..2e6a217 --- /dev/null +++ b/corporate_finances_ui_py/src/app/Common/Services/Assessment/orchestrator.service.ts @@ -0,0 +1,171 @@ +import { AuthenticationService } from "../Authentication/authentication.service"; +import { environment } from "src/environments/environment"; +import { HttpClient } from "@angular/common/http"; +import { Injectable } from "@angular/core"; +import { Note } from "src/app/Common/components/notification/interfaces/Notes"; +import { Observable, Subject, firstValueFrom } from 'rxjs'; +import { SessionStorageService } from "../Storage/session.service"; +import Swal from "sweetalert2"; + +@Injectable({ + providedIn: 'root', +}) + +export class OrchestratorService { + + private sharedToClasification = new Subject(); + + sharedToClasification$: Observable = this.sharedToClasification.asObservable(); + + private sharedToProfitLoss = new Subject(); + + sharedToProfitLoss$: Observable = this.sharedToProfitLoss.asObservable(); + + private sharedToCapex = new Subject(); + + sharedToCapex$: Observable = this.sharedToCapex.asObservable(); + + private sharedToCashFlow = new Subject(); + + sharedToCashFlow$: Observable = this.sharedToCashFlow.asObservable(); + + private sharedToValoration = new Subject(); + + sharedToValoration$: Observable = this.sharedToValoration.asObservable(); + + private sharedNotes = new Subject(); + + sharedNotes$: Observable = this.sharedNotes.asObservable(); + + constructor(private http: HttpClient, private authService: AuthenticationService, + private sessionStorageService: SessionStorageService) { } + + async validateOrchestator(obj: any) { + + let user = this.authService.userInfo()?.username + let url = environment.apiKey + 'orchestrator?' + 'date=' + obj.date + '&nit=' + obj.nit + '&periodicity=' + obj.periodicity + '&user=' + user + let response = await firstValueFrom(this.http.get(url)) + this.distributeToComponent(response) + } + + distributeToComponent(component: any) { + + if (component.data_to_get.length > 0) { + + for (let index = 0; index < component.data_to_get.length; index++) { + switch (component.data_to_get[index]) { + case 'CLASSIFICATION': { + this.setisClassification(component.id_assessment) + break + } + case 'PYG': { + this.setisProfitLoss(component.id_assessment) + break + } + case 'CAPEX': { + this.setisCapex(component.id_assessment) + break + } + case 'CASH_FLOW': { + this.setisCashFlow(component.id_assessment) + break + } + case 'VALORATION': { + this.setisValoration(true) + break + } + } + } + } + else { + this.setisClassification(0) + } + } + + setisClassification(number: number) { + this.sharedToClasification.next(number) + } + + getisClassification() { + return this.sharedToClasification$ + } + + setisProfitLoss(number: number) { + this.sharedToProfitLoss.next(number); + } + + getisProfitLoss() { + return this.sharedToProfitLoss$ + } + + setisCapex(number: number) { + this.sharedToCapex.next(number); + } + + setNotes(notes: Note[]) { + this.sharedNotes.next(notes); + } + + getisCapex() { + return this.sharedToCapex$ + } + + setisCashFlow(number: number) { + this.sharedToCashFlow.next(number); + } + + getisCashFlow() { + return this.sharedToCashFlow$ + } + + setisValoration(status: boolean) { + this.sharedToValoration.next(status); + } + + getisValoration() { + return this.sharedToValoration$ + } + + getNotes() { + return this.sharedNotes$ + } + + async getIdAssessment(obj: any) { + + let user = this.authService.userInfo()?.username + let url = environment.apiKey + 'orchestrator?' + 'date=' + obj.date + '&nit=' + obj.nit + '&periodicity=' + obj.periodicity + '&user=' + user + return await firstValueFrom(this.http.get(url)) + } + + async validateStatus(): Promise { + + let status = await this.callStatus() + + if (status.status == 'TIMEOUT' || status.status == 'WORKING') { + await this.sleep(500) + await this.validateStatus(); + } + else if (status.status == 'ERROR') { + throw Swal.fire({ + title: '¡Lo sentimos!', + icon: 'error', + html: 'Ha ocurrido un error al consultar el estado, por favor comuniquese con el administrador' + }) + } + this.setNotes(status.notes) + return true + + } + + async callStatus() { + + let idAssessment = JSON.parse(this.sessionStorageService.getData(environment.KEY_ID_ASSESSMENT)!) + return await firstValueFrom(this.http.get(environment.apiKey + 'orchestrator/status/' + idAssessment)) + + } + + sleep(timeInMileSecond: number) { + return new Promise(resolve => setTimeout(resolve, timeInMileSecond)); + } + +} diff --git a/corporate_finances_ui_py/src/app/Common/Services/Assessment/profit-loss.service.ts b/corporate_finances_ui_py/src/app/Common/Services/Assessment/profit-loss.service.ts new file mode 100644 index 0000000..dccc8c2 --- /dev/null +++ b/corporate_finances_ui_py/src/app/Common/Services/Assessment/profit-loss.service.ts @@ -0,0 +1,72 @@ +import { environment } from "src/environments/environment"; +import { firstValueFrom } from 'rxjs'; +import { HttpClient } from "@angular/common/http"; +import { Injectable } from "@angular/core"; +import { IProfitAndLoss } from "src/app/Models/Profit-Loss"; +import { IProjection } from "src/app/Models/Projections"; +import Swal from "sweetalert2"; + +@Injectable({ + providedIn: 'root', +}) + +export class ProfitLossService { + + constructor(private http: HttpClient) { } + + async getProfitAndLossByAssesmentId(idAssessment: number) { + + return await firstValueFrom(this.http.get(environment.apiKey + 'recovery/pyg/completed/' + idAssessment)) + + } + + async recalculateProfitAndLoss(idAssessment: number) { + + return await firstValueFrom(this.http.get(environment.apiKey + 'assessment/pyg/recalculate/' + idAssessment)) + + } + + async calculateImplicitGrowth(obj: any): Promise { + + try { + + const response = await firstValueFrom(this.http.post(environment.apiKey + 'assessment/pyg/implicit_growings', JSON.stringify(obj))); + return response; + + } catch (error: any) { + + throw Swal.fire({ + title: '¡Lo sentimos!', + icon: 'error', + html: 'Ha habido un error al intentar obtener las columnas. Por favor, inténtelo de nuevo más tarde o comuniquese con el administrador ' + }) + + } + + } + + async getProjectionByAssesmentId(idAssessment: number) { + + return await firstValueFrom(this.http.get(environment.apiKey + 'recovery/pyg/projections-only/' + idAssessment)) + } + + async saveProjections(obj: any): Promise { + + try { + + const response = await firstValueFrom(this.http.post(environment.apiKey + 'assessment/pyg/projections-calculator', JSON.stringify(obj))); + return response; + + } catch (error: any) { + + throw Swal.fire({ + title: '¡Lo sentimos!', + icon: 'error', + html: 'Ha habido un error al intentar obtener las columnas. Por favor, inténtelo de nuevo más tarde o comuniquese con el administrador ' + }) + + } + + } + +} diff --git a/corporate_finances_ui_py/src/app/Common/Services/Authentication/authentication.service.ts b/corporate_finances_ui_py/src/app/Common/Services/Authentication/authentication.service.ts new file mode 100644 index 0000000..de80615 --- /dev/null +++ b/corporate_finances_ui_py/src/app/Common/Services/Authentication/authentication.service.ts @@ -0,0 +1,77 @@ +import { Injectable, OnInit } from "@angular/core"; +import { Router } from "@angular/router"; +import { MsalService } from "@azure/msal-angular"; +import { AuthenticationResult } from "@azure/msal-browser"; +import { environment } from "src/environments/environment"; +import { SessionStorageService } from "../Storage/session.service"; + +const loginRequest = { + scopes: ["User.Read"], +} + +@Injectable({ + providedIn: 'root' +}) + +export class AuthenticationService { + + constructor(private msalService: MsalService, private sessionStorageService: SessionStorageService, private router: Router) { + + } + + logIn() { + + this.msalService.loginPopup(loginRequest).subscribe((response: AuthenticationResult) => { + this.msalService.instance.setActiveAccount(response.account) + this.msalService.handleRedirectObservable().subscribe(() => { + const silentRequest = { + scopes: [environment.azure.cliendId + "/.default"], + account: this.msalService.instance.getActiveAccount()! + } + + this.msalService.instance.acquireTokenSilent(silentRequest).then(response => { + this.sessionStorageService.saveData(environment.KEY_TOKEN, JSON.stringify(response)) + this.router.navigate(['assessment']) + }) + }) + }) + } + + logOut() { + this.msalService.logoutPopup({ + mainWindowRedirectUri: "/login" + }); + } + + isLoggedIn(): boolean { + return this.msalService.instance.getActiveAccount() != null + } + + userInfo() { + return this.msalService.instance.getActiveAccount() + } + + validateTokenExp() { + + const tokenExpirateOn = JSON.parse(this.sessionStorageService.getData(environment.KEY_TOKEN)!) + const forceRefresh = (new Date(tokenExpirateOn.expiresOn) < new Date()); + if (forceRefresh) { + return true + } + return false + } + + async refreshToken() { + + const silentRequest = { + scopes: [environment.azure.cliendId + "/.default"], + account: this.msalService.instance.getActiveAccount()! + } + + await this.msalService.instance.acquireTokenSilent(silentRequest).then(response => { + this.sessionStorageService.saveData(environment.KEY_TOKEN, JSON.stringify(response)) + }) + + } + +} \ No newline at end of file diff --git a/corporate_finances_ui_py/src/app/Common/Services/Idle/Idle.service.ts b/corporate_finances_ui_py/src/app/Common/Services/Idle/Idle.service.ts new file mode 100644 index 0000000..ce45340 --- /dev/null +++ b/corporate_finances_ui_py/src/app/Common/Services/Idle/Idle.service.ts @@ -0,0 +1,94 @@ +import { Idle, DEFAULT_INTERRUPTSOURCES } from '@ng-idle/core'; +import { Injectable } from '@angular/core'; +import { SessionStorageService } from '../Storage/session.service'; +import Swal from 'sweetalert2'; + +@Injectable({ providedIn: 'root' }) + +export class IdleService { + + private isSetUp: boolean = false; + + constructor(private idle: Idle, private sessionStorageService: SessionStorageService) { + this.setup(); + } + + isServiceRunning() { + return this.idle.isRunning(); + } + + startIdleSvc() { + if (this.idle.isRunning()) { + this.idle.stop(); + } + + this.idle.watch(); + } + + stopIdleSvc() { + this.idle.stop(); + } + + private setup() { + + if (!this.isSetUp) { + + let idleStartSec: number = 900; + let timeoutPeriodSec: number = 12; + + this.idle.setIdle(idleStartSec); + + this.idle.setTimeout(timeoutPeriodSec); + + this.idle.setInterrupts(DEFAULT_INTERRUPTSOURCES); + + this.idle.onIdleStart.subscribe(() => { + this.idleSwal(); + }); + + this.idle.onTimeout.subscribe(() => { + this.sessionStorageService.clearData() + }); + + this.isSetUp = true; + } + } + + + idleSwal() { + let timerInterval: any; + Swal.fire({ + title: 'Alerta de inactividad', + html: 'Tu sesion esta a punto de expirar en segundos, todo tu progreso se perdera.', + timer: 10000, + confirmButtonColor: '#198754', + cancelButtonColor: '#d33', + confirmButtonText: 'Continuar', + timerProgressBar: true, + didOpen: () => { + timerInterval = setInterval(() => { + Swal!.getHtmlContainer()!.querySelector('strong')!.textContent = ( + Swal.getTimerLeft()! / 1000 + ).toFixed(0); + }, 100); + }, + }).then((response) => { + if (response.isConfirmed) { + clearInterval(timerInterval); + } else { + clearInterval(timerInterval); + Swal.fire({ + title: 'La sesión ha caducado', + text: 'Vuelve a iniciar sesión', + icon: 'info', + confirmButtonText: 'Aceptar', + }).then((response) => { + if (response.isConfirmed || response.dismiss) { + window.location.reload() + } + }) + } + }); + } + +} \ No newline at end of file diff --git a/corporate_finances_ui_py/src/app/Common/Services/Spinner/interceptor.service.ts b/corporate_finances_ui_py/src/app/Common/Services/Spinner/interceptor.service.ts new file mode 100644 index 0000000..dfdf4be --- /dev/null +++ b/corporate_finances_ui_py/src/app/Common/Services/Spinner/interceptor.service.ts @@ -0,0 +1,61 @@ +import { AuthenticationService } from "../Authentication/authentication.service"; +import { environment } from "src/environments/environment"; +import { finalize, from, lastValueFrom, Observable } from "rxjs"; +import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from "@angular/common/http"; +import { Injectable } from "@angular/core"; +import { SessionStorageService } from "../Storage/session.service"; +import { SpinnerService } from "./spinner.service"; + +@Injectable({ + providedIn: 'root' +}) + +export class InterceptorService implements HttpInterceptor { + + constructor(private spinnerService: SpinnerService, private authenticationService: AuthenticationService, + private sessionStorageService: SessionStorageService) { + + } + + intercept(req: HttpRequest, next: HttpHandler): Observable> { + + return from(this.handle(req, next)) + + } + + async handle(req: HttpRequest, next: HttpHandler) { + + this.spinnerService.show(); + + if (this.authenticationService.validateTokenExp()) { + + await this.authenticationService.refreshToken() + + let token = JSON.parse(this.sessionStorageService.getData(environment.KEY_TOKEN)!) + + req = req.clone({ + headers: req.headers.set('Authorization', `${token.accessToken}`) + }); + + return await lastValueFrom(next.handle(req).pipe( + finalize(() => { + this.spinnerService.hide() + }) + )) + } + + let token = JSON.parse(this.sessionStorageService.getData(environment.KEY_TOKEN)!) + + req = req.clone({ + headers: req.headers.set('Authorization', `${token.accessToken}`) + }); + + return await lastValueFrom(next.handle(req).pipe( + finalize(() => { + this.spinnerService.hide() + }) + )) + + } + +} \ No newline at end of file diff --git a/corporate_finances_ui_py/src/app/Common/Services/Spinner/spinner.service.ts b/corporate_finances_ui_py/src/app/Common/Services/Spinner/spinner.service.ts new file mode 100644 index 0000000..4e15d32 --- /dev/null +++ b/corporate_finances_ui_py/src/app/Common/Services/Spinner/spinner.service.ts @@ -0,0 +1,23 @@ +import { Injectable } from "@angular/core"; +import { NgxSpinnerService } from "ngx-spinner"; + +@Injectable({ + providedIn: 'root' +}) + +export class SpinnerService { + + constructor(private spinnerService: NgxSpinnerService) { + + } + + show() { + this.spinnerService.show() + } + + hide() { + this.spinnerService.hide() + } + + +} \ No newline at end of file diff --git a/corporate_finances_ui_py/src/app/Common/Services/Storage/session.service.ts b/corporate_finances_ui_py/src/app/Common/Services/Storage/session.service.ts new file mode 100644 index 0000000..15c5140 --- /dev/null +++ b/corporate_finances_ui_py/src/app/Common/Services/Storage/session.service.ts @@ -0,0 +1,26 @@ +import { Injectable } from "@angular/core"; + +@Injectable({ + providedIn: 'root' +}) + +export class SessionStorageService { + + constructor() { } + + saveData(key: string, value: string) { + sessionStorage.setItem(key, value); + } + + getData(key: string) { + return sessionStorage.getItem(key) + } + + removeData(key: string) { + sessionStorage.removeItem(key); + } + + clearData() { + sessionStorage.clear(); + } +} \ No newline at end of file diff --git a/corporate_finances_ui_py/src/app/Common/Services/share-data.service.ts b/corporate_finances_ui_py/src/app/Common/Services/share-data.service.ts new file mode 100644 index 0000000..711a14e --- /dev/null +++ b/corporate_finances_ui_py/src/app/Common/Services/share-data.service.ts @@ -0,0 +1,201 @@ +import { Injectable } from '@angular/core'; +import { Observable, Subject } from 'rxjs'; +import { IProjection } from 'src/app/Models/Resume'; +import { AuthenticationService } from './Authentication/authentication.service'; + +@Injectable({ + providedIn: 'root' +}) +export class ShareDataService { + + private sharedDataPatrimony: Subject = new Subject(); + + sharedDataPatrimony$: Observable = this.sharedDataPatrimony.asObservable(); + + private sharedDataWorkingCapital: Subject = new Subject(); + + sharedDataWorkingCapital$: Observable = this.sharedDataWorkingCapital.asObservable(); + + private sharedDataOtherProjections: Subject = new Subject(); + + sharedDataOtherProjections$: Observable = this.sharedDataOtherProjections.asObservable(); + + private sharedDataCashFlow: Subject = new Subject(); + + sharedDataCashFlow$: Observable = this.sharedDataCashFlow.asObservable(); + + private sharedDataCapexToCashFlow: Subject = new Subject(); + + sharedDataCapexToCashFlow$: Observable = this.sharedDataCapexToCashFlow.asObservable(); + + private sharedDataCapexToPyg: Subject = new Subject(); + + sharedDataCapexToPyg$: Observable = this.sharedDataCapexToPyg.asObservable(); + + private sharedDataArchive: any + + private sharedDataProjection: any + + private sharedDataProjectionHistory: any + + private projectionsModals: any + + private sharedDataListAccountPyg: any + + private yearsProjecction: any + + private DataCashFlow: any + + private calculateProjection: any + + private sharedDataExistinProjection: Subject = new Subject(); + + sharedDataExistinProjection$: Observable = this.sharedDataExistinProjection.asObservable(); + + private sharedDataFutureProjection: Subject = new Subject(); + + sharedDataFutureProjection$: Observable = this.sharedDataFutureProjection.asObservable(); + + private companyInformation: any + + private existingProjection: any + + private futureProjection: any + + private sharedDataValuation: Subject = new Subject(); + + sharedDataValuation$: Observable = this.sharedDataValuation.asObservable(); + + private sharedDataCashFlowToPyg: Subject = new Subject(); + + sharedDataCashFlowToPyg$: Observable = this.sharedDataCashFlowToPyg.asObservable(); + + private sharedUtilityPygToCashFlow: Subject = new Subject(); + + sharedUtilityPygToCashFlow$: Observable = this.sharedUtilityPygToCashFlow.asObservable(); + + constructor(private authenticationService: AuthenticationService) { + + } + + setPatrimony(projection: any) { + this.sharedDataPatrimony.next(projection); + } + + setWorkingCapital(projection: any) { + this.sharedDataWorkingCapital.next(projection) + } + + setCapex(capex: any) { + this.sharedDataCapexToCashFlow.next(capex) + } + + setCapexToPyg(capex: any) { + this.sharedDataCapexToPyg.next(capex) + } + + setValuation(valuationList: any) { + this.sharedDataValuation.next(valuationList) + } + + setOtherProjection(projection: any) { + this.sharedDataOtherProjections.next(projection) + } + + setOtherDataCashFlow(projection: any) { + this.sharedDataCashFlow.next(projection) + } + + setCompanyInformation(obj: any) { + this.companyInformation = obj + } + + setCashFlowToPyg(obj: any) { + this.sharedDataCashFlowToPyg.next(obj) + } + + setUtilityPygToCashFlow(obj: any) { + this.sharedUtilityPygToCashFlow.next(obj) + } + + getCompanyInformation() { + return this.companyInformation + } + + setAccountPyg(obj: any) { + this.sharedDataListAccountPyg = obj + } + + setDataCashFlow(obj: any) { + this.DataCashFlow = obj + } + + getDataCashFlow() { + return this.DataCashFlow + } + + setProjectionModal(obj: any) { + this.projectionsModals = obj + } + + getAccountPyg() { + return this.sharedDataListAccountPyg + } + + setArchive(obj: any) { + this.sharedDataArchive = obj + } + + getArchive() { + return this.sharedDataArchive + } + + setProjection(obj: any) { + this.sharedDataProjection = obj + } + + getProjection() { + return this.sharedDataProjection + } + + setHistoryProjection(obj: any) { + this.sharedDataProjectionHistory = obj + } + + getHistoryProjection() { + return this.sharedDataProjectionHistory + } + + setCalculateProjection(obj: any) { + this.calculateProjection = obj + } + + getCalculateProjection() { + return this.calculateProjection + } + + setExistinProjection(projectionExisting: any) { + this.sharedDataExistinProjection.next(projectionExisting) + } + + setFutureProjection(projectionExisting: any) { + this.sharedDataFutureProjection.next(projectionExisting) + } + + setCashExistingProjection(listExistingProjection: any) { + this.existingProjection = listExistingProjection + } + + getCashExistingProjection() { + return this.existingProjection + } + + setCashFutureProjections(listExistingProjection: any) { + this.futureProjection = listExistingProjection + } + + getCashFutureProjections() { + return this.futureProjection + } + +} diff --git a/corporate_finances_ui_py/src/app/Common/components/not-found/not-found.component.html b/corporate_finances_ui_py/src/app/Common/components/not-found/not-found.component.html new file mode 100644 index 0000000..4ae5a4a --- /dev/null +++ b/corporate_finances_ui_py/src/app/Common/components/not-found/not-found.component.html @@ -0,0 +1,6 @@ +
+
+

404

+

Opps! Page not found.

+
+
\ No newline at end of file diff --git a/corporate_finances_ui_py/src/app/Common/components/not-found/not-found.component.ts b/corporate_finances_ui_py/src/app/Common/components/not-found/not-found.component.ts new file mode 100644 index 0000000..4cadb48 --- /dev/null +++ b/corporate_finances_ui_py/src/app/Common/components/not-found/not-found.component.ts @@ -0,0 +1,10 @@ +import { Component, OnInit } from '@angular/core'; + +@Component({ + selector: 'app-not-found', + templateUrl: './not-found.component.html' +}) +export class NotFoundComponent { + + +} diff --git a/corporate_finances_ui_py/src/app/Common/components/notification/interfaces/Notes.ts b/corporate_finances_ui_py/src/app/Common/components/notification/interfaces/Notes.ts new file mode 100644 index 0000000..c41022b --- /dev/null +++ b/corporate_finances_ui_py/src/app/Common/components/notification/interfaces/Notes.ts @@ -0,0 +1,8 @@ +export interface INotes { + notes: Note[]; +} + +export interface Note { + context: string; + notes: string[]; +} diff --git a/corporate_finances_ui_py/src/app/Common/components/notification/notification.component.css b/corporate_finances_ui_py/src/app/Common/components/notification/notification.component.css new file mode 100644 index 0000000..09cd087 --- /dev/null +++ b/corporate_finances_ui_py/src/app/Common/components/notification/notification.component.css @@ -0,0 +1,5 @@ +.float-button { + position: fixed; + bottom: 20px; + right: 20px; +} \ No newline at end of file diff --git a/corporate_finances_ui_py/src/app/Common/components/notification/notification.component.html b/corporate_finances_ui_py/src/app/Common/components/notification/notification.component.html new file mode 100644 index 0000000..e65f1fc --- /dev/null +++ b/corporate_finances_ui_py/src/app/Common/components/notification/notification.component.html @@ -0,0 +1,10 @@ + \ No newline at end of file diff --git a/corporate_finances_ui_py/src/app/Common/components/notification/notification.component.ts b/corporate_finances_ui_py/src/app/Common/components/notification/notification.component.ts new file mode 100644 index 0000000..9e103e3 --- /dev/null +++ b/corporate_finances_ui_py/src/app/Common/components/notification/notification.component.ts @@ -0,0 +1,69 @@ +import { Component, OnInit } from '@angular/core'; +import { Note } from 'src/app/Common/components/notification/interfaces/Notes'; +import { OrchestratorService } from '../../Services/Assessment/orchestrator.service'; +import Swal from 'sweetalert2'; + +@Component({ + selector: 'app-notification', + templateUrl: './notification.component.html', + styleUrls: ['./notification.component.css'] +}) +export class NotificationComponent implements OnInit { + + notes: Note[] = [] + + totalNotification = 0 + + constructor(private orchestratorService: OrchestratorService) { } + + ngOnInit(): void { + + this.orchestratorService.getNotes().subscribe(notes => { + + if (notes != undefined) { + this.notes = notes + this.totalNotification = notes.length + } + + }) + } + + showNotification() { + + let html = "" + + + if (this.notes.length > 0) { + + for (var value of this.notes) { + + html += "

" + value.context + "

" + "
" + html += '
    ' + + for (var note of value.notes) { + + html += '
  • ' + note + '
  • ' + + } + + html += '
' + } + + } + else { + + html = "No se encontraron notas" + + } + + Swal.fire({ + icon: 'info', + html: html, + width: '850px', + heightAuto: true + }) + + } + + +} diff --git a/corporate_finances_ui_py/src/app/Common/pages/footer/footer.component.html b/corporate_finances_ui_py/src/app/Common/pages/footer/footer.component.html new file mode 100644 index 0000000..754ff94 --- /dev/null +++ b/corporate_finances_ui_py/src/app/Common/pages/footer/footer.component.html @@ -0,0 +1,41 @@ + \ No newline at end of file diff --git a/corporate_finances_ui_py/src/app/Common/pages/footer/footer.component.ts b/corporate_finances_ui_py/src/app/Common/pages/footer/footer.component.ts new file mode 100644 index 0000000..ce921d1 --- /dev/null +++ b/corporate_finances_ui_py/src/app/Common/pages/footer/footer.component.ts @@ -0,0 +1,18 @@ +import { Component, OnInit } from '@angular/core'; + +@Component({ + selector: 'app-footer', + templateUrl: './footer.component.html' +}) + +export class FooterComponent implements OnInit { + + date: number = 0 + + ngOnInit(): void { + + this.date = new Date().getFullYear(); + + } + +} \ No newline at end of file diff --git a/corporate_finances_ui_py/src/app/Common/pages/header/header.component.html b/corporate_finances_ui_py/src/app/Common/pages/header/header.component.html new file mode 100644 index 0000000..0ab9b40 --- /dev/null +++ b/corporate_finances_ui_py/src/app/Common/pages/header/header.component.html @@ -0,0 +1,72 @@ + \ No newline at end of file diff --git a/corporate_finances_ui_py/src/app/Common/pages/header/header.component.ts b/corporate_finances_ui_py/src/app/Common/pages/header/header.component.ts new file mode 100644 index 0000000..9567b20 --- /dev/null +++ b/corporate_finances_ui_py/src/app/Common/pages/header/header.component.ts @@ -0,0 +1,36 @@ +import { Component } from '@angular/core'; +import Swal from 'sweetalert2'; +import { MsalService } from '@azure/msal-angular'; +import { AuthenticationService } from '../../Services/Authentication/authentication.service'; + +@Component({ + selector: 'app-header', + templateUrl: './header.component.html' +}) +export class HeaderComponent { + + constructor(private authenticationService: AuthenticationService) { + + } + + getName() { + return this.authenticationService.userInfo()?.username + } + + LogOut(): void { + + Swal.fire({ + title: '¿Estás seguro de que quieres cerrar la sesión en Delta?', + icon: 'warning', + showCancelButton: true, + confirmButtonColor: '#198754', + cancelButtonColor: '#d33', + confirmButtonText: 'Si', + cancelButtonText: 'Cancelar' + }).then((result) => { + if (result.isConfirmed) { + this.authenticationService.logOut() + } + }) + } +} diff --git a/corporate_finances_ui_py/src/app/Common/pipes/number.pipe.ts b/corporate_finances_ui_py/src/app/Common/pipes/number.pipe.ts new file mode 100644 index 0000000..04cc0a7 --- /dev/null +++ b/corporate_finances_ui_py/src/app/Common/pipes/number.pipe.ts @@ -0,0 +1,45 @@ +import { Pipe, PipeTransform } from '@angular/core'; + +@Pipe({ name: 'numberPipe' }) + +export class NumberTransformPipe implements PipeTransform { + + transform(val: string | number) { + + if (typeof val == 'number') { + val = String(val); + return this.assingInput(val); + } else { + val = val.replaceAll('.', ''); + return this.onChangeInput(val); + } + } + + assingInput(val: any) { + let newVal = val.split('.'); + + if (newVal.length > 1) { + let result = Number(newVal[0]); + return result.toLocaleString('es-CO') + ',' + newVal[1] + } + else { + let result = Number(newVal[0]); + return result.toLocaleString('es-CO') + } + } + + onChangeInput(val: any) { + if (val == '-') { + return val; + } else { + let newVal = val.split(','); + if (newVal.length > 1) { + let result = Number(newVal[0]); + return result.toLocaleString('es-CO') + ',' + newVal[1] + } else { + let result = Number(newVal[0]); + return result.toLocaleString('es-CO'); + } + } + } +} \ No newline at end of file diff --git a/corporate_finances_ui_py/src/app/Common/pipes/numberType.pipe.ts b/corporate_finances_ui_py/src/app/Common/pipes/numberType.pipe.ts new file mode 100644 index 0000000..aeca89c --- /dev/null +++ b/corporate_finances_ui_py/src/app/Common/pipes/numberType.pipe.ts @@ -0,0 +1,15 @@ +import { Pipe, PipeTransform } from '@angular/core'; + +@Pipe({ name: 'numberType' }) + +export class NumberType implements PipeTransform { + transform(val: string | number) { + + if (typeof val != 'string') { + return val + } + else { + return Number(val.replaceAll('.', '').replaceAll(',', '.')) + } + } +} \ No newline at end of file diff --git a/corporate_finances_ui_py/src/app/Common/pipes/validateNegative.pipe.ts b/corporate_finances_ui_py/src/app/Common/pipes/validateNegative.pipe.ts new file mode 100644 index 0000000..696d1b9 --- /dev/null +++ b/corporate_finances_ui_py/src/app/Common/pipes/validateNegative.pipe.ts @@ -0,0 +1,19 @@ +import { DecimalPipe } from '@angular/common'; +import { Pipe, PipeTransform } from '@angular/core'; + +@Pipe({ name: 'validateNegative' }) + +export class ValidateNegativePipe implements PipeTransform { + + transform(val: number): string | number { + + if (val == undefined) { + return 'Por Calcular' + } + else { + let decimalPipe = new DecimalPipe('es') + return decimalPipe.transform(val, '1.2-2')! + } + + } +} \ No newline at end of file diff --git a/corporate_finances_ui_py/src/app/Common/utils/constants.ts b/corporate_finances_ui_py/src/app/Common/utils/constants.ts new file mode 100644 index 0000000..02350f4 --- /dev/null +++ b/corporate_finances_ui_py/src/app/Common/utils/constants.ts @@ -0,0 +1,6 @@ +import { MethodProjectionAssests, MethodProjectionGeneral } from "./types"; + +export const ConstantsDelta = { + methodsProjectionGeneral: ['Tasa de crecimiento fija', 'Porcentaje de otra variable', 'Valor constante', 'Tasas impositivas', 'Input', 'Cero', 'PXQ'] as MethodProjectionGeneral[], + methodProjectionAssests: ['D&A en línea recta', 'D&A manual'] as MethodProjectionAssests[] +}; \ No newline at end of file diff --git a/corporate_finances_ui_py/src/app/Common/utils/tableUtil.ts b/corporate_finances_ui_py/src/app/Common/utils/tableUtil.ts new file mode 100644 index 0000000..f17cedb --- /dev/null +++ b/corporate_finances_ui_py/src/app/Common/utils/tableUtil.ts @@ -0,0 +1,32 @@ +import * as XLSX from "xlsx"; + +export class TableUtil { + + exportTableToExcel(tableId: string, name?: string) { + let { sheetName, fileName } = getFileName(name!); + let targetTableElm = document.getElementById(tableId); + let wb = XLSX.utils.table_to_book(targetTableElm, { + sheet: sheetName, + raw: true + }); + XLSX.writeFile(wb, `${fileName}.xlsx`); + } +} + +const getFileName = (name: string) => { + let timeSpan = new Date().toLocaleString('es-CO') + let sheetName = name || "ExportResult"; + let fileName = `${sheetName}-${timeSpan}`; + return { + sheetName, + fileName + }; +}; + +export function convertDate(date: string) { + + let dateParts: any[] = date.split("-"); + let unionDate = [dateParts[2], dateParts[1], dateParts[0]].join('-') + return new Date(unionDate) + +} \ No newline at end of file diff --git a/corporate_finances_ui_py/src/app/Common/utils/types.ts b/corporate_finances_ui_py/src/app/Common/utils/types.ts new file mode 100644 index 0000000..082b52f --- /dev/null +++ b/corporate_finances_ui_py/src/app/Common/utils/types.ts @@ -0,0 +1,11 @@ +export type GroupSelect = 'FixedAssets' | 'Period' | 'Acumulated' +export type MethodProjectionAssests = 'D&A manual' | 'D&A en línea recta' +export type MethodProjectionCapexDepreactionAmortization = 'Porcentaje de otra variable' | 'Manual' | '' +export type MethodProjectionGeneral = 'Tasa de crecimiento fija' | 'Porcentaje de otra variable' | 'Valor constante' | 'Tasas impositivas' | 'Input' | 'Cero' | 'PXQ' +export type Period = 'history' | 'projection' | 'projections' +export type ModalContext = { + 'PYG': 'PYG' + 'WORKING CAPITAL': 'WK' + 'PATRIMONY': 'PATRIMONY' + 'OTHER PROJECTION': 'OTHER PROJECTION' +} \ No newline at end of file diff --git a/corporate_finances_ui_py/src/app/Guards/auth.guard.spec.ts b/corporate_finances_ui_py/src/app/Guards/auth.guard.spec.ts new file mode 100644 index 0000000..68889d2 --- /dev/null +++ b/corporate_finances_ui_py/src/app/Guards/auth.guard.spec.ts @@ -0,0 +1,16 @@ +import { TestBed } from '@angular/core/testing'; + +import { AuthGuard } from './auth.guard'; + +describe('AuthGuard', () => { + let guard: AuthGuard; + + beforeEach(() => { + TestBed.configureTestingModule({}); + guard = TestBed.inject(AuthGuard); + }); + + it('should be created', () => { + expect(guard).toBeTruthy(); + }); +}); diff --git a/corporate_finances_ui_py/src/app/Guards/auth.guard.ts b/corporate_finances_ui_py/src/app/Guards/auth.guard.ts new file mode 100644 index 0000000..9810133 --- /dev/null +++ b/corporate_finances_ui_py/src/app/Guards/auth.guard.ts @@ -0,0 +1,24 @@ +import { Injectable } from '@angular/core'; +import { CanActivate, Router } from '@angular/router'; +import { MsalService } from '@azure/msal-angular'; + +@Injectable({ + providedIn: 'root' +}) + +export class AuthGuard implements CanActivate { + + constructor(private msalService: MsalService, private router: Router) { + + } + + canActivate() { + + if (this.msalService.instance.getActiveAccount() == null) { + this.router.navigate(['/login']); + return false + } + return true + + } +} diff --git a/corporate_finances_ui_py/src/app/Models/Companie.ts b/corporate_finances_ui_py/src/app/Models/Companie.ts new file mode 100644 index 0000000..00e3b56 --- /dev/null +++ b/corporate_finances_ui_py/src/app/Models/Companie.ts @@ -0,0 +1,17 @@ +export interface Companie { + company: Company; + data: Datum[]; + model: string +} + +export interface Company { + name: string; + sector: string; +} + +export interface Datum { + date: string; + periodicity: string; + id_assessment: number + user: string +} diff --git a/corporate_finances_ui_py/src/app/Models/ImplicitGrowing.ts b/corporate_finances_ui_py/src/app/Models/ImplicitGrowing.ts new file mode 100644 index 0000000..92ae4bf --- /dev/null +++ b/corporate_finances_ui_py/src/app/Models/ImplicitGrowing.ts @@ -0,0 +1,20 @@ +export interface ImplicitGrowing { + variations: Values[]; + proportions: Values[]; + statistics: Statistic[]; +} + +export interface Values { + name: string; + value: string[]; +} + +export interface Statistic { + account: string; + average: string; + median: string; + min: string; + max: string; + deviation: string; + beta: string; +} diff --git a/corporate_finances_ui_py/src/app/Models/Profit-Loss.ts b/corporate_finances_ui_py/src/app/Models/Profit-Loss.ts new file mode 100644 index 0000000..46d4782 --- /dev/null +++ b/corporate_finances_ui_py/src/app/Models/Profit-Loss.ts @@ -0,0 +1,27 @@ +export interface IProfitAndLoss { + datesHistory: string[]; + datesProjection: string[]; + data: ProfitAndLossData[]; +} + +export interface ProfitAndLossData { + name: string; + values: { + history: Data[]; + projection: Data[]; + }; + subs?: DataSubs[]; +} + +export interface Data { + hint: string; + value: number +} + +export interface DataSubs { + name: string; + values: { + history: Data[]; + projection?: Data[]; + }; +} \ No newline at end of file diff --git a/corporate_finances_ui_py/src/app/Models/Projections.ts b/corporate_finances_ui_py/src/app/Models/Projections.ts new file mode 100644 index 0000000..686c737 --- /dev/null +++ b/corporate_finances_ui_py/src/app/Models/Projections.ts @@ -0,0 +1,20 @@ +export interface IProjection { + id_assessment: string + year: number; + datesHistory: string[] + datesProjections: string[] + projection_data: IProjectionData[]; +} + +export interface IProjectionData { + name: string + account: string; + method: string; + accountProjector: string; + atributes: { + history: number[], + projection: number[] + }; + explication: string; +} + diff --git a/corporate_finances_ui_py/src/app/Models/Resume.ts b/corporate_finances_ui_py/src/app/Models/Resume.ts new file mode 100644 index 0000000..cfd0108 --- /dev/null +++ b/corporate_finances_ui_py/src/app/Models/Resume.ts @@ -0,0 +1,25 @@ +export interface IProjection { + name: string, + projections: number[], + year: number + capitulo:string +} + +export interface IStatic { + account: string, + average: string, + median: string, + deviation: string, + min: string, + max: string, + beta: string +} + +export interface IFileDepurate { + row: number, + accounts_column: number, + filename: string, + nit: string, + replace: number, + selected_columns: Array +} \ No newline at end of file diff --git a/corporate_finances_ui_py/src/app/Views/Authentication/login/login.component.html b/corporate_finances_ui_py/src/app/Views/Authentication/login/login.component.html new file mode 100644 index 0000000..d920a9e --- /dev/null +++ b/corporate_finances_ui_py/src/app/Views/Authentication/login/login.component.html @@ -0,0 +1,42 @@ +
+
+
+
+
+
+ logo-precia +
+
+
+

Entidad vigilada por la Superintendencia Financiera de Colombia, filial de la + Bolsa de Valores de Colombia (BVC).

+
+
+
+
+
+
+

Bienvenido a Delta

+

Para continuar, inicia sesión con tu cuenta.

+ +
+
+
+
+
+
\ No newline at end of file diff --git a/corporate_finances_ui_py/src/app/Views/Authentication/login/login.component.ts b/corporate_finances_ui_py/src/app/Views/Authentication/login/login.component.ts new file mode 100644 index 0000000..bac6edc --- /dev/null +++ b/corporate_finances_ui_py/src/app/Views/Authentication/login/login.component.ts @@ -0,0 +1,19 @@ +import { Component } from '@angular/core'; +import { AuthenticationService } from 'src/app/Common/Services/Authentication/authentication.service'; + +@Component({ + selector: 'app-login', + templateUrl: './login.component.html' +}) + +export class LoginComponent { + + constructor(private authenticationService: AuthenticationService) { + + } + + logIn() { + this.authenticationService.logIn() + } + +} diff --git a/corporate_finances_ui_py/src/app/Views/Companies/companie-create/companie-create.component.html b/corporate_finances_ui_py/src/app/Views/Companies/companie-create/companie-create.component.html new file mode 100644 index 0000000..395b316 --- /dev/null +++ b/corporate_finances_ui_py/src/app/Views/Companies/companie-create/companie-create.component.html @@ -0,0 +1,67 @@ +
+
+
+ Crear Empresa +
+
+
+
+
+
+ + +
+ El campo es obligatorio +
+
+ El nit debe ser de 9 digitos +
+
+
+ + +
+ El campo es obligatorio +
+
+
+
+
+
+
+ + +
+ El campo es obligatorio +
+
+
+ + +
+
+
+
+
+ +
+
+
+ +
+
\ No newline at end of file diff --git a/corporate_finances_ui_py/src/app/Views/Companies/companie-create/companie-create.component.ts b/corporate_finances_ui_py/src/app/Views/Companies/companie-create/companie-create.component.ts new file mode 100644 index 0000000..d97e0ab --- /dev/null +++ b/corporate_finances_ui_py/src/app/Views/Companies/companie-create/companie-create.component.ts @@ -0,0 +1,59 @@ +import { Component } from '@angular/core'; +import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; +import { CompanieService } from 'src/app/Views/Companies/services/companie.service'; +import Swal from 'sweetalert2'; + +@Component({ + selector: 'app-companie-create', + templateUrl: './companie-create.component.html' +}) + +export class CompanieCreateComponent { + + companieForm: FormGroup; + + constructor(private formBuilder: FormBuilder, private companieService: CompanieService) { + this.companieForm = this.formBuilder.group({ + nit: new FormControl('', Validators.compose([Validators.required, Validators.minLength(9)])), + digitVerification: new FormControl('', Validators.compose([Validators.required])), + name: new FormControl('', Validators.compose([Validators.required])), + sector: new FormControl(null, Validators.compose([Validators.required])) + }) + + } + + create() { + + const obj = { + nit: this.companieForm.get('nit')?.value + '-' + this.companieForm.get('digitVerification')?.value, + name: this.companieForm.get('name')?.value, + sector: this.companieForm.get('sector')?.value + } + this.companieService.create(obj).then(response => { + if (response != null) { + Swal.fire({ + title: 'Excelente', + text: 'La empresa se ha creado correctamente.', + icon: 'success' + }) + } + }) + } + + validateCompanie() { + + this.companieService.getCompanie(this.companieForm.get('nit')?.value + '-' + this.companieForm.get('digitVerification')?.value) + .then(companie => { + if (companie.hasOwnProperty('NIT')) { + Swal.fire({ + title: 'Lo sentimos', + text: 'El nit ingresado ya ha sido registrado.', + icon: 'warning' + }) + this.companieForm.get('nit')?.setValue(''); + this.companieForm.get('digitVerification')?.setValue(''); + } + }) + } + +} diff --git a/corporate_finances_ui_py/src/app/Views/Companies/services/companie.service.ts b/corporate_finances_ui_py/src/app/Views/Companies/services/companie.service.ts new file mode 100644 index 0000000..e96c37d --- /dev/null +++ b/corporate_finances_ui_py/src/app/Views/Companies/services/companie.service.ts @@ -0,0 +1,95 @@ +import { HttpClient } from "@angular/common/http"; +import { Injectable } from "@angular/core"; +import { firstValueFrom } from 'rxjs'; +import { Companie } from "src/app/Models/Companie"; +import { environment } from "src/environments/environment"; +import Swal from "sweetalert2"; + +@Injectable({ + providedIn: 'root', +}) + +export class CompanieService { + + constructor(private http: HttpClient) { } + + async create(objInfo: any) { + + try { + + const response = await firstValueFrom(this.http.post(environment.apiKey + 'companies', JSON.stringify(objInfo))) + return response; + + + } catch (error: any) { + + throw Swal.fire({ + title: '¡Lo sentimos!', + icon: 'error', + html: 'Ha habido un error al intentar depurar la información. Por favor, inténtelo de nuevo más tarde o comuniquese con el administrador ' + }) + + } + + } + + async getCompanie(nit: string): Promise { + + try { + + const response = await firstValueFrom(this.http.get(environment.apiKey + 'companies/' + nit)) + return response; + + + } catch (error: any) { + + throw Swal.fire({ + title: '¡Lo sentimos!', + icon: 'error', + html: 'Ha habido un error al intentar consultar la información. Por favor, inténtelo de nuevo más tarde o comuniquese con el administrador' + }) + + } + + } + + async getCompanieWithModel(nit: string) { + + try { + + const response = await firstValueFrom(this.http.get(environment.apiKey + 'companies?nit=' + nit)) + return response; + + + } catch (error: any) { + + throw Swal.fire({ + title: '¡Lo sentimos!', + icon: 'error', + html: 'Ha habido un error al intentar consultar la información. Por favor, inténtelo de nuevo más tarde o comuniquese con el administrador' + }) + + } + + } + + + async getHistoryValuation(nit: string): Promise { + + try { + + return await firstValueFrom(this.http.get(environment.apiKey + 'pucs/client/data/' + nit)) + + + } catch (error: any) { + + throw Swal.fire({ + title: '¡Lo sentimos!', + icon: 'error', + html: 'Ha habido un error al intentar consultar la información. Por favor, inténtelo de nuevo más tarde o comuniquese con el administrador' + }) + + } + + } +} diff --git a/corporate_finances_ui_py/src/app/Views/Navs/navs-implicit-growth/navs-implicit-growth.component.html b/corporate_finances_ui_py/src/app/Views/Navs/navs-implicit-growth/navs-implicit-growth.component.html new file mode 100644 index 0000000..3854bc6 --- /dev/null +++ b/corporate_finances_ui_py/src/app/Views/Navs/navs-implicit-growth/navs-implicit-growth.component.html @@ -0,0 +1,122 @@ + +
+
+
+
+ +
+
+ +
+
+ +
+
+
+
+ + + + + + + + + + + + + + + + + +
Cuenta{{date}}
{{dataAccountPyg?.name}}{{value.value| number : '1.2-2'}}
{{dataAccountProportion?.name}}{{value.value | number : + '1.2-2'}}
+
+
+
+

Variaciones

+ + + + + + + + + + + + + +
Cuenta{{date}}
{{data.name}}{{value}}
+
+
+

Proporción

+ + + + + + + + + + + + + +
Cuenta{{year}}
{{data.name}}{{value}}
+
+
+

Estadísticas Descriptivas

+ + + + + + + + + + + + + + + + + + + + + + + +
CuentaPromedioMedianaDesviaciónMinMaxBeta
+ {{value.account}} + + {{value.average}} + + {{value.median}} + + {{value.deviation}} + + {{value.min}} + + {{value.max}} + + {{value.beta}} +
+
+
+
+
\ No newline at end of file diff --git a/corporate_finances_ui_py/src/app/Views/Navs/navs-implicit-growth/navs-implicit-growth.component.ts b/corporate_finances_ui_py/src/app/Views/Navs/navs-implicit-growth/navs-implicit-growth.component.ts new file mode 100644 index 0000000..86067e0 --- /dev/null +++ b/corporate_finances_ui_py/src/app/Views/Navs/navs-implicit-growth/navs-implicit-growth.component.ts @@ -0,0 +1,159 @@ +import { Component, Input } from '@angular/core'; +import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; +import { ProfitLossService } from 'src/app/Common/Services/Assessment/profit-loss.service'; +import { ImplicitGrowing } from 'src/app/Models/ImplicitGrowing'; +import { DataSubs, IProfitAndLoss, ProfitAndLossData } from 'src/app/Models/Profit-Loss'; + +@Component({ + selector: 'app-navs-implicit-growth', + templateUrl: './navs-implicit-growth.component.html' +}) +export class NavsImplicitGrowthComponent { + + @Input() profitAndLossData!: IProfitAndLoss + @Input() accounts: string[] = []; + @Input() accountsComplete: string[] = []; + @Input() showList = true + @Input() implicitGrowthResult: ImplicitGrowing | undefined + implicitGrowthForm: FormGroup; + dataAccountPyg: ProfitAndLossData | DataSubs | undefined + dataAccountProportion: ProfitAndLossData | DataSubs | undefined + + + constructor(private formBuilder: FormBuilder, private profitAndLossService: ProfitLossService) { + + this.implicitGrowthForm = this.formBuilder.group({ + accountPyg: new FormControl(null, Validators.required), + accountProportion: new FormControl(null, Validators.required) + }) + + } + + search() { + + let indexPyg: number = 0; + let indexProportion: number = 0; + + if (this.isSub(this.implicitGrowthForm.get('accountPyg')?.value)) { + + indexPyg = this.getSubs()?.findIndex(value => value.name == this.implicitGrowthForm.get('accountPyg')?.value) + indexProportion = this.profitAndLossData.data.findIndex(value => value.name == this.implicitGrowthForm.get('accountProportion')?.value) as number + this.dataAccountPyg = this.getSubs()[indexPyg]; + this.dataAccountProportion = this.profitAndLossData.data[indexProportion]; + + } + else if (this.isSub(this.implicitGrowthForm.get('accountProportion')?.value)) { + + indexPyg = this.profitAndLossData.data.findIndex(value => value.name == this.implicitGrowthForm.get('accountPyg')?.value) as number + indexProportion = this.getSubs()?.findIndex(value => value.name == this.implicitGrowthForm.get('accountProportion')?.value) + this.dataAccountPyg = this.profitAndLossData.data[indexPyg]; + this.dataAccountProportion = this.getSubs()[indexProportion]; + + } + else { + + indexPyg = this.profitAndLossData.data.findIndex(value => value.name == this.implicitGrowthForm.get('accountPyg')?.value) as number + indexProportion = this.profitAndLossData.data.findIndex(value => value.name == this.implicitGrowthForm.get('accountProportion')?.value) as number + this.dataAccountPyg = this.profitAndLossData.data[indexPyg]; + this.dataAccountProportion = this.profitAndLossData.data[indexProportion]; + + } + + this.calculate() + + } + + isSub(str: string) { + return /\d/.test(str); + } + + getSubs() { + + let subs: DataSubs[] = [] + + for (let row of this.profitAndLossData.data) { + + if (row.subs) { + + row.subs.map(sub => { + subs.push(sub); + }) + } + + } + + return subs + + } + + calculate() { + + let obj: any = { + + accountPyg: [], + accountProportion: [] + + } + + for (let index = 0; index < this.profitAndLossData.datesHistory.length; index++) { + + obj.accountPyg.push({ + account: this.implicitGrowthForm.get('accountPyg')?.value, + date: this.profitAndLossData.datesHistory[index], + value: this.getValues(index, this.implicitGrowthForm.get('accountPyg')?.value) + }) + + obj.accountProportion.push({ + account: this.implicitGrowthForm.get('accountProportion')?.value, + date: this.profitAndLossData.datesHistory[index], + value: this.getValues(index, this.implicitGrowthForm.get('accountProportion')?.value) + }) + + } + + this.profitAndLossService.calculateImplicitGrowth(obj).then(response => { + this.implicitGrowthResult = response + }) + + } + + + getValues(indexOfYear: number, account: string) { + + if (this.isSub(account)) { + + let subs = this.getSubs() + + for (let row of subs) { + + if (row.name == account) { + return row.values.history[indexOfYear].value + } + else { + continue + } + } + + return 0 + + + } + else { + + for (let index = 0; index < this.profitAndLossData.data.length; index++) { + + if (this.profitAndLossData?.data[index].name == account) { + return this.profitAndLossData?.data[index].values.history[indexOfYear].value + } + else { + continue + } + } + + return 0 + + } + + } +} + diff --git a/corporate_finances_ui_py/src/app/Views/Navs/navs-projections/navs-projections.component.css b/corporate_finances_ui_py/src/app/Views/Navs/navs-projections/navs-projections.component.css new file mode 100644 index 0000000..e055d09 --- /dev/null +++ b/corporate_finances_ui_py/src/app/Views/Navs/navs-projections/navs-projections.component.css @@ -0,0 +1,4 @@ +.table td, +.table th { + min-width: 140px; +} \ No newline at end of file diff --git a/corporate_finances_ui_py/src/app/Views/Navs/navs-projections/navs-projections.component.html b/corporate_finances_ui_py/src/app/Views/Navs/navs-projections/navs-projections.component.html new file mode 100644 index 0000000..03cd3eb --- /dev/null +++ b/corporate_finances_ui_py/src/app/Views/Navs/navs-projections/navs-projections.component.html @@ -0,0 +1,98 @@ +
+

Proyecciones

+
+
+
+ + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
CuentaMétodo + + ? + + Cuenta de Proyectar + {{ dateHistory }} + + {{ dateProjection }} + Explicación
+ {{ projection.value.account }} + + + +
+ +
+
+
+ {{valueHistory | number : '1.2-2'}} +
+
+
+
+ +
+
+
+ +
+
+
+
+ +
+
\ No newline at end of file diff --git a/corporate_finances_ui_py/src/app/Views/Navs/navs-projections/navs-projections.component.ts b/corporate_finances_ui_py/src/app/Views/Navs/navs-projections/navs-projections.component.ts new file mode 100644 index 0000000..803077a --- /dev/null +++ b/corporate_finances_ui_py/src/app/Views/Navs/navs-projections/navs-projections.component.ts @@ -0,0 +1,215 @@ +import { Component, Input, OnInit } from '@angular/core'; +import { FormArray, FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; +import { ProfitLossService } from 'src/app/Common/Services/Assessment/profit-loss.service'; +import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; +import { IProjection, IProjectionData } from 'src/app/Models/Projections'; +import { environment } from 'src/environments/environment'; +import { SessionStorageService } from 'src/app/Common/Services/Storage/session.service'; +import { convertDate } from 'src/app/Common/Utils/tableUtil'; +import { ConstantsDelta } from 'src/app/Common/utils/constants'; +import Swal from 'sweetalert2'; +import { MethodProjectionGeneral } from 'src/app/Common/utils/types'; + +@Component({ + selector: 'app-navs-projections', + templateUrl: './navs-projections.component.html', + styleUrls: ['./navs-projections.component.css'] +}) + +export class NavsProjectionsComponent implements OnInit { + + @Input() accountsComplete: string[] = []; + projectionMethods: MethodProjectionGeneral[] = ConstantsDelta.methodsProjectionGeneral + projectionForm: FormGroup; + isRecovery = false; + isAnualize = false; + + constructor(private formBuilder: FormBuilder, private profitLossService: ProfitLossService, + private modalService: NgbActiveModal, private sessionStorageService: SessionStorageService) { + + this.projectionForm = new FormGroup({ + id_assessment: new FormControl('', Validators.required), + year: new FormControl('', Validators.required), + datesHistory: new FormArray([], Validators.required), + datesProjections: new FormArray([], Validators.required), + projection_data: new FormArray([], Validators.required), + }); + + } + + ngOnInit(): void { + + let idAssessment = Number(this.sessionStorageService.getData(environment.KEY_ID_ASSESSMENT)!) + this.profitLossService.getProjectionByAssesmentId(idAssessment).then(projection => { + + if (projection.datesProjections.length > 0) { + this.isRecovery = true; + this.assignValues(projection) + } + else { + this.assigvaluesFirstTime(projection) + } + }) + + } + + getDatesHistory(): FormArray { + return this.projectionForm.get('datesHistory') as FormArray; + } + + getDatesProjection(): FormArray { + return this.projectionForm.get('datesProjections') as FormArray; + } + + getProjections(): FormArray { + return this.projectionForm.get('projection_data') as FormArray; + } + + getAtributesProjection(empIndex: number, period: string): FormArray { + return this.getProjections().at(empIndex).get('atributes')?.get(period) as FormArray; + } + + save() { + + Swal.fire({ + title: '¿Estas seguro de guardar?', + icon: 'info', + showCancelButton: true, + confirmButtonColor: '#198754', + cancelButtonColor: '#d33', + confirmButtonText: 'Si', + cancelButtonText: 'Cancelar' + }).then((result) => { + if (result.isConfirmed) { + + this.profitLossService.saveProjections(this.projectionForm.value).then(() => { + Swal.fire({ + title: 'Guardado', + text: 'La información se ha guardado correctamente', + icon: 'success', + confirmButtonText: 'OK' + }).then(response => { + if (response.isConfirmed) { + this.modalService.close(); + } + }) + + }) + + } + }) + } + + assignValues(projectionData: IProjection) { + + this.projectionForm.get('year')?.setValue(projectionData.year) + + this.projectionForm.get('id_assessment')?.setValue(projectionData.id_assessment) + + projectionData.datesHistory.map(item => this.getDatesHistory().push(new FormControl(item))) + + projectionData.datesProjections.map((item) => this.getDatesProjection().push(new FormControl(item))) + + projectionData.projection_data.map((item) => this.getProjections().push(this.create(item))) + + } + + assigvaluesFirstTime(projectionData: IProjection) { + + this.projectionForm.get('year')?.setValue('') + + this.projectionForm.get('id_assessment')?.setValue(projectionData.id_assessment) + + projectionData.datesHistory.map(item => this.getDatesHistory().push(new FormControl(item))) + + projectionData.projection_data.forEach((item) => this.getProjections().push(this.createFirstTime(item))) + + } + + create(item: IProjectionData) { + return this.formBuilder.group({ + account: new FormControl(item.account), + accountProjector: new FormControl(item.accountProjector == 'No aplica' ? 'Seleccione' : item.accountProjector, Validators.required), + method: new FormControl(item.method, Validators.required), + atributes: new FormGroup({ + history: new FormArray(item.atributes.history.map((value: number) => new FormControl(value))), + projection: new FormArray(item.atributes.projection.map((value: number) => new FormControl(value))) + }), + explication: new FormControl(item.explication, Validators.required), + }); + } + + createFirstTime(item: IProjectionData) { + return this.formBuilder.group({ + account: new FormControl(item.account), + accountProjector: new FormControl('Seleccione', Validators.required), + method: new FormControl('Seleccione', Validators.required), + atributes: new FormGroup({ + history: new FormArray(item.atributes.history.map((value: number) => new FormControl(value))), + projection: new FormArray([]) + }), + explication: new FormControl('', Validators.required), + }); + } + + addDateProjections() { + + if (this.projectionForm.get('year')?.value != '') { + + this.getDatesProjection().clear(); + + let companieInformation = JSON.parse(this.sessionStorageService.getData(environment.KEY_COMPANIE_INFORMATION)!) + let dateCompanie = convertDate(companieInformation.date) + + if (dateCompanie.getMonth() < 11) { + this.isAnualize = true + this.getDatesProjection().push(new FormControl('Diciembre ' + dateCompanie.getFullYear().toString())) + } + + for (let index = 1; index <= this.projectionForm.get('year')?.value; index++) { + this.getDatesProjection().push(new FormControl(String(dateCompanie.getFullYear() + index))) + } + + this.addYearAtributes() + } + + } + + addYearAtributes() { + + let projections = this.getProjections() + let temProjectionValue = projections.value + let yearProjection = this.projectionForm.get('year')?.value + + for (let index = 0; index < projections.length; index++) { + + let atributesByAccount = projections.at(index).get('atributes')?.get('projection') as FormArray + atributesByAccount.clear(); + + let addYearProjection = this.isAnualize ? yearProjection + 1 : yearProjection + + for (let index2 = 0; index2 < addYearProjection; index2++) { + + if (this.isRecovery) { + let numbers = temProjectionValue[index].atributes.projection; + let isAssingValidator = projections.at(index).get('method')?.value == 'Tasa de crecimiento fija' || projections.at(index).get('method')?.value == 'Tasas impositivas' || projections.at(index).get('method')?.value == 'Input'; + atributesByAccount.push(new FormControl((numbers[index2] == '' || numbers[index2] == undefined) ? '' : Number(numbers[index2]), isAssingValidator ? Validators.required : null)); + } + else { + atributesByAccount.push(new FormControl('')) + } + } + } + + } + + helpEquation(): void { + Swal.fire({ + title: 'Tipos de proyección', + icon: 'question', + html: '
  • Tasa de crecimiento fija: Este método calcula el valor futuro de una línea de negocio a una tasa dada por el usuario:

    x = x t-1 * (1 + i%)

    donde x es el valor en el año proyectado.

    donde x t-1 es el valor a proyectar un periodo antes del año de proyección.

    i% la tasa dada para los años de proyección.

  • Porcentaje de otra variable: Este método calcula el valor futuro de una línea de negocio basado en su porcentaje de participación sobre otra línea principal de negocio (Ejemplo: ingresos):

    x = x t-1 / y t-1 * y

    donde x es el valor en el año proyectado.

    x t-1 es el valor a proyectar un periodo antes del año de proyección.

    y t-1 es el valor de la cuenta de la proporción un periodo antes del año de proyección.

    y es el valor de la cuenta de la proporción en el año de proyección.

  • Valor constante: Esta opción no aplica ningún método de proyección y deja el mismo valor para cada año de proyección.

  • Tasas impositivas: Este método calcula el valor futuro de una línea de negocio basado en un porcentaje sobre otra línea de negocio:

    x = y * i%

    donde x es el valor en el año proyectado.

    y es la linea de negocio sobre la que aplique la tasa.

    i% la tasa dada a los años de proyección

' + }) + } + + +} diff --git a/corporate_finances_ui_py/src/app/Views/Reports/interface/Export.ts b/corporate_finances_ui_py/src/app/Views/Reports/interface/Export.ts new file mode 100644 index 0000000..30734af --- /dev/null +++ b/corporate_finances_ui_py/src/app/Views/Reports/interface/Export.ts @@ -0,0 +1,6 @@ +export interface IExport { + date: string, + nit: string, + periodicity: string, + user: string +} \ No newline at end of file diff --git a/corporate_finances_ui_py/src/app/Views/Reports/report-search/report-search.component.html b/corporate_finances_ui_py/src/app/Views/Reports/report-search/report-search.component.html new file mode 100644 index 0000000..c966bcc --- /dev/null +++ b/corporate_finances_ui_py/src/app/Views/Reports/report-search/report-search.component.html @@ -0,0 +1,78 @@ +
+
+
+ Generar Reporte +
+
+
+
+
+
+ + +
+ El campo es obligatorio +
+
+ El nit debe ser de 9 digitos +
+
+
+ + +
+ El campo es obligatorio +
+
+
+ + +
+
+ + +
+
+
+
+ + +
+
+ + +
+
+ + +
+
+
+
+
+ +
+
\ No newline at end of file diff --git a/corporate_finances_ui_py/src/app/Views/Reports/report-search/report-search.component.ts b/corporate_finances_ui_py/src/app/Views/Reports/report-search/report-search.component.ts new file mode 100644 index 0000000..6942030 --- /dev/null +++ b/corporate_finances_ui_py/src/app/Views/Reports/report-search/report-search.component.ts @@ -0,0 +1,81 @@ +import { Component, OnInit } from '@angular/core'; +import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; +import { CompanieService } from 'src/app/Views/Companies/services/companie.service'; +import { ReportService } from 'src/app/Views/Reports/services/report.service'; +import { Companie } from 'src/app/Models/Companie'; +import Swal from 'sweetalert2'; +import { IExport } from '../interface/Export'; + +@Component({ + selector: 'app-report-search', + templateUrl: './report-search.component.html', +}) +export class ReportSearchComponent { + + reportForm: FormGroup; + periodicityOption: string[] = [] + email: string[] = [] + datesOption!: Companie | undefined + + constructor(private formBuilder: FormBuilder, private companieService: CompanieService, private reportService: ReportService) { + + this.reportForm = this.formBuilder.group({ + nit: new FormControl('', Validators.compose([Validators.required, Validators.minLength(9)])), + digitVerification: new FormControl('', Validators.compose([Validators.required])), + name: new FormControl({ value: '', disabled: true }), + sector: new FormControl({ value: '', disabled: true }), + date: new FormControl({ value: null, disabled: true }, Validators.required), + periodicity: new FormControl({ value: null, disabled: true }, Validators.required), + email: new FormControl({ value: null, disabled: true }, Validators.required) + }) + } + + getValorationsByCompanie() { + + let nit = this.reportForm.get('nit')?.value + '-' + this.reportForm.get('digitVerification')?.value; + + this.companieService.getCompanieWithModel(nit).then(response => { + response.data = response.data.filter(model => model.user != null) + this.datesOption = response + this.reportForm.get('name')?.setValue(response.company.name) + this.reportForm.get('sector')?.setValue(response.company.sector) + this.reportForm.get('date')?.enable() + }) + } + + filterPeriodicity() { + this.periodicityOption = [] + this.email = [] + this.periodicityOption.push(this.datesOption!.data.find(model => model.date == this.reportForm.get('date')!.value)!.periodicity) + this.email.push(this.datesOption!.data.find(model => model.date == this.reportForm.get('date')!.value)!.user) + this.reportForm.get('periodicity')?.enable() + this.reportForm.get('email')?.enable() + } + + export() { + + let obj: IExport = { + date: this.reportForm.get('date')?.value, + nit: this.reportForm.get('nit')?.value + '-' + this.reportForm.get('digitVerification')?.value, + periodicity: this.reportForm.get('periodicity')?.value, + user: this.reportForm.get('email')?.value + } + + this.reportService.download(obj).then(response => { + if (response != undefined) { + window.open(response.download_url) + } + else { + Swal.fire({ + title: 'Lo sentimos', + icon: 'info', + text: 'No se encontro información para descargar, valide con el administrador' + }) + } + }) + + } + + +} + diff --git a/corporate_finances_ui_py/src/app/Views/Reports/services/report.service.ts b/corporate_finances_ui_py/src/app/Views/Reports/services/report.service.ts new file mode 100644 index 0000000..ca876ee --- /dev/null +++ b/corporate_finances_ui_py/src/app/Views/Reports/services/report.service.ts @@ -0,0 +1,35 @@ +import { HttpClient } from "@angular/common/http"; +import { Injectable } from "@angular/core"; +import { firstValueFrom } from 'rxjs'; +import { environment } from "src/environments/environment"; +import { IExport } from "../interface/Export"; +import Swal from "sweetalert2"; + +@Injectable({ + providedIn: 'root', +}) + +export class ReportService { + + constructor(private http: HttpClient) { } + + async download(obj: IExport) { + + try { + + const response = await firstValueFrom(this.http.get(environment.apiKey + 'report?' + 'date=' + obj.date + '&' + 'nit=' + obj.nit + '&' + 'periodicity=' + obj.periodicity + '&' + 'user=' + obj.user)) + return response; + + + } catch (error: any) { + + throw Swal.fire({ + title: '¡Lo sentimos!', + icon: 'error', + html: 'Ha habido un error al intentar depurar la información. Por favor, inténtelo de nuevo más tarde o comuniquese con el administrador ' + }) + + } + + } +} diff --git a/corporate_finances_ui_py/src/app/app-routing.module.ts b/corporate_finances_ui_py/src/app/app-routing.module.ts new file mode 100644 index 0000000..e7e8240 --- /dev/null +++ b/corporate_finances_ui_py/src/app/app-routing.module.ts @@ -0,0 +1,24 @@ +import { AuthGuard } from './Guards/auth.guard'; +import { CompanieCreateComponent } from './Views/Companies/companie-create/companie-create.component'; +import { LoginComponent } from './Views/Authentication/login/login.component'; +import { NgModule } from '@angular/core'; +import { NotFoundComponent } from './Common/components/not-found/not-found.component'; +import { PanelComponent } from './Views/Assessment/panel/panel.component'; +import { ReportSearchComponent } from './Views/Reports/report-search/report-search.component'; +import { RouterModule, Routes } from '@angular/router'; + +const routes: Routes = [ + { path: '', redirectTo: 'login', pathMatch: 'full' }, + { path: 'login', component: LoginComponent }, + { path: 'assessment', component: PanelComponent, canActivate: [AuthGuard] }, + { path: 'report-search', component: ReportSearchComponent, canActivate: [AuthGuard] }, + { path: 'companie-create', component: CompanieCreateComponent, canActivate: [AuthGuard] }, + { path: '**', component: NotFoundComponent } + +]; + +@NgModule({ + imports: [RouterModule.forRoot(routes)], + exports: [RouterModule] +}) +export class AppRoutingModule { } diff --git a/corporate_finances_ui_py/src/app/app.component.css b/corporate_finances_ui_py/src/app/app.component.css new file mode 100644 index 0000000..b70b7b3 --- /dev/null +++ b/corporate_finances_ui_py/src/app/app.component.css @@ -0,0 +1,5 @@ +body, +html { + height: 100%; + margin: 0; +} \ No newline at end of file diff --git a/corporate_finances_ui_py/src/app/app.component.html b/corporate_finances_ui_py/src/app/app.component.html new file mode 100644 index 0000000..3657192 --- /dev/null +++ b/corporate_finances_ui_py/src/app/app.component.html @@ -0,0 +1,9 @@ + + + + +
+ +
+ + \ No newline at end of file diff --git a/corporate_finances_ui_py/src/app/app.component.spec.ts b/corporate_finances_ui_py/src/app/app.component.spec.ts new file mode 100644 index 0000000..a7fc35d --- /dev/null +++ b/corporate_finances_ui_py/src/app/app.component.spec.ts @@ -0,0 +1,35 @@ +import { TestBed } from '@angular/core/testing'; +import { RouterTestingModule } from '@angular/router/testing'; +import { AppComponent } from './app.component'; + +describe('AppComponent', () => { + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ + RouterTestingModule + ], + declarations: [ + AppComponent + ], + }).compileComponents(); + }); + + it('should create the app', () => { + const fixture = TestBed.createComponent(AppComponent); + const app = fixture.componentInstance; + expect(app).toBeTruthy(); + }); + + it(`should have as title 'delta1'`, () => { + const fixture = TestBed.createComponent(AppComponent); + const app = fixture.componentInstance; + expect(app.title).toEqual('delta1'); + }); + + it('should render title', () => { + const fixture = TestBed.createComponent(AppComponent); + fixture.detectChanges(); + const compiled = fixture.nativeElement as HTMLElement; + expect(compiled.querySelector('.content span')?.textContent).toContain('delta1 app is running!'); + }); +}); diff --git a/corporate_finances_ui_py/src/app/app.component.ts b/corporate_finances_ui_py/src/app/app.component.ts new file mode 100644 index 0000000..bcecbdb --- /dev/null +++ b/corporate_finances_ui_py/src/app/app.component.ts @@ -0,0 +1,51 @@ +import { Component, OnInit } from '@angular/core'; +import { Router, NavigationStart, RouterEvent } from '@angular/router'; +import { filter } from 'rxjs'; +import { IdleService } from './Common/Services/Idle/Idle.service'; +import { AuthenticationService } from './Common/Services/Authentication/authentication.service'; + +@Component({ + selector: 'app-root', + templateUrl: './app.component.html', + styleUrls: ['./app.component.css'] +}) +export class AppComponent { + + showHead: boolean = false; + + constructor(private router: Router, private idleService: IdleService, private authenticationService: AuthenticationService) { + + this.validateHead() + this.validateIdle() + + } + + validateIdle() { + this.router.events.pipe(filter(e => e instanceof RouterEvent)).subscribe(e => { + + let isLoggedIn = this.authenticationService.isLoggedIn() + if (isLoggedIn != false) { + if (!this.idleService.isServiceRunning()) { + this.idleService.startIdleSvc(); + } + } else { + if (this.idleService.isServiceRunning()) { + this.idleService.stopIdleSvc(); + } + } + }) + } + + validateHead() { + this.router.events.forEach((event) => { + if (event instanceof NavigationStart) { + if (event['url'] == '/login' || event['url'] == '/recover-password' || event['url'] == '/' || event['url'] == '**') { + this.showHead = false; + } else { + this.showHead = true; + } + } + }); + } + +} diff --git a/corporate_finances_ui_py/src/app/app.module.ts b/corporate_finances_ui_py/src/app/app.module.ts new file mode 100644 index 0000000..c96112b --- /dev/null +++ b/corporate_finances_ui_py/src/app/app.module.ts @@ -0,0 +1,126 @@ +import { NgModule, CUSTOM_ELEMENTS_SCHEMA, LOCALE_ID } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; +import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; +import { AppRoutingModule } from './app-routing.module'; +import { AppComponent } from './app.component'; +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http'; +import { LoginComponent } from './Views/Authentication/login/login.component'; +import { PanelComponent } from './Views/Assessment/panel/panel.component'; +import { HeaderComponent } from './Common/pages/header/header.component'; +import { FooterComponent } from './Common/pages/footer/footer.component'; +import { NgbModule } from '@ng-bootstrap/ng-bootstrap'; +import { PvPreviewExcelComponent } from './Views/Assessment/beginning/modals/pv-preview-excel/pv-preview-excel.component'; +import { BeginningComponent } from './Views/Assessment/beginning/beginning.component'; +import { NgxBootstrapMultiselectModule } from 'ngx-bootstrap-multiselect'; +import { PvInitialSubaccountsComponent } from './Views/Assessment/beginning/modals/pv-initial-subaccounts/pv-initial-subaccounts.component'; +import { PvAccountCreationComponent } from './Views/Assessment/beginning/modals/pv-account-creation/pv-account-creation.component'; +import { PvFinalSubaccountsComponent } from './Views/Assessment/beginning/modals/pv-final-subaccounts/pv-final-subaccounts.component'; +import { NgxSpinnerModule } from 'ngx-spinner'; +import { InterceptorService } from './Common/Services/Spinner/interceptor.service'; +import { ClassificationComponent } from './Views/Assessment/classification/classification.component'; +import { PvClassificationSubaccountsComponent } from './Views/Assessment/classification/modals/pv-classification-subaccounts/pv-classification-subaccounts.component'; +import { PvSubaccountsChildComponent } from './Views/Assessment/classification/modals/pv-subaccounts-child/pv-subaccounts-child.component'; +import { CompanieCreateComponent } from './Views/Companies/companie-create/companie-create.component'; +import { ProfitLossComponent } from './Views/Assessment/profit-loss/profit-loss.component'; +import { ProfitLossService } from './Common/Services/Assessment/profit-loss.service'; +import { registerLocaleData } from '@angular/common'; +import localeEs from '@angular/common/locales/es'; +import { PvProjectionsComponent } from './Views/Assessment/profit-loss/modals/pv-projections/pv-projections.component'; +import { NotFoundComponent } from './Common/components/not-found/not-found.component'; +import { PvDatePucsComponent } from './Views/Assessment/classification/modals/pv-date-pucs/pv-date-pucs.component'; +import { NavsImplicitGrowthComponent } from './Views/Navs/navs-implicit-growth/navs-implicit-growth.component'; +import { NavsProjectionsComponent } from './Views/Navs/navs-projections/navs-projections.component'; +import { CashFlowComponent } from './Views/Assessment/cash-flow/cash-flow.component'; +import { PvWorkingCapitalComponent } from './Views/Assessment/cash-flow/modals/pv-working-capital/pv-working-capital.component'; +import { PvPatrimonyComponent } from './Views/Assessment/cash-flow/modals/pv-patrimony/pv-patrimony.component'; +import { PvOtherProjectionsComponent } from './Views/Assessment/cash-flow/modals/pv-other-projections/pv-other-projections.component'; +import { PvFinancialDebtComponent } from './Views/Assessment/cash-flow/modals/pv-financial-debt/pv-financial-debt.component'; +import { CapexComponent } from './Views/Assessment/capex/capex.component'; +import { ValuationComponent } from './Views/Assessment/valuation/valuation.component'; +import { NumberTransformPipe } from './Common/pipes/number.pipe'; +import { NgIdleKeepaliveModule } from '@ng-idle/keepalive'; +import { IPublicClientApplication, PublicClientApplication } from '@azure/msal-browser'; +import { MSAL_INSTANCE, MsalService } from '@azure/msal-angular'; +import { environment } from 'src/environments/environment'; +import { PvAssetDepreciationComponent } from './Views/Assessment/capex/modals/pv-asset-depreciation/pv-asset-depreciation.component'; +import { PvDepreciationNewCapexComponent } from './Views/Assessment/capex/modals/pv-depreciation-new-capex/pv-depreciation-new-capex.component'; +import { ReportSearchComponent } from './Views/Reports/report-search/report-search.component'; +import { PvParametricModelComponent } from './Views/Assessment/beginning/modals/pv-parametric-model/pv-parametric-model.component'; +import { PvInitValorationComponent } from './Views/Assessment/beginning/modals/pv-init-valoration/pv-init-valoration.component'; +import { NotificationComponent } from './Common/components/notification/notification.component'; +import { ValidateNegativePipe } from './Common/pipes/validateNegative.pipe'; + +const isIE = window.navigator.userAgent.indexOf('MSIE ') > -1 || window.navigator.userAgent.indexOf('Trident/') > -1; + +export function MSLAInstanceFactory(): IPublicClientApplication { + return new PublicClientApplication({ + auth: { + clientId: environment.azure.cliendId, + authority: environment.azure.authority, + }, + cache: { + cacheLocation: 'sessionStorage', + storeAuthStateInCookie: isIE, + } + }) +} + +@NgModule({ + declarations: [ + AppComponent, + LoginComponent, + PanelComponent, + HeaderComponent, + FooterComponent, + PvPreviewExcelComponent, + BeginningComponent, + PvInitialSubaccountsComponent, + PvAccountCreationComponent, + PvFinalSubaccountsComponent, + ClassificationComponent, + PvClassificationSubaccountsComponent, + PvSubaccountsChildComponent, + CompanieCreateComponent, + ProfitLossComponent, + PvProjectionsComponent, + NotFoundComponent, + PvDatePucsComponent, + NavsImplicitGrowthComponent, + NavsProjectionsComponent, + CashFlowComponent, + ValidateNegativePipe, + PvWorkingCapitalComponent, + PvPatrimonyComponent, + PvOtherProjectionsComponent, + PvFinancialDebtComponent, + CapexComponent, + ValuationComponent, + NumberTransformPipe, + PvAssetDepreciationComponent, + PvDepreciationNewCapexComponent, + ReportSearchComponent, + PvParametricModelComponent, + PvInitValorationComponent, + NotificationComponent, + ], + imports: [ + BrowserModule, + AppRoutingModule, + BrowserAnimationsModule, + FormsModule, + ReactiveFormsModule, + HttpClientModule, + NgbModule, + NgxBootstrapMultiselectModule, + NgxSpinnerModule, + NgIdleKeepaliveModule.forRoot(), + ], + schemas: [CUSTOM_ELEMENTS_SCHEMA], + providers: [ProfitLossService, { provide: LOCALE_ID, useValue: 'es' }, { provide: HTTP_INTERCEPTORS, useClass: InterceptorService, multi: true }, + { provide: MSAL_INSTANCE, useFactory: MSLAInstanceFactory }, MsalService], + bootstrap: [AppComponent], +}) +export class AppModule { } + +registerLocaleData(localeEs, 'es'); \ No newline at end of file diff --git a/corporate_finances_ui_py/src/assets/.gitkeep b/corporate_finances_ui_py/src/assets/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/corporate_finances_ui_py/src/assets/images/graphic.png b/corporate_finances_ui_py/src/assets/images/graphic.png new file mode 100644 index 0000000..88463ed Binary files /dev/null and b/corporate_finances_ui_py/src/assets/images/graphic.png differ diff --git a/corporate_finances_ui_py/src/assets/images/icon_precia.png b/corporate_finances_ui_py/src/assets/images/icon_precia.png new file mode 100644 index 0000000..e3e6690 Binary files /dev/null and b/corporate_finances_ui_py/src/assets/images/icon_precia.png differ diff --git a/corporate_finances_ui_py/src/assets/images/logo_board.png b/corporate_finances_ui_py/src/assets/images/logo_board.png new file mode 100644 index 0000000..57d1c78 Binary files /dev/null and b/corporate_finances_ui_py/src/assets/images/logo_board.png differ diff --git a/corporate_finances_ui_py/src/assets/images/precia_logo_naranja.png b/corporate_finances_ui_py/src/assets/images/precia_logo_naranja.png new file mode 100644 index 0000000..127f71c Binary files /dev/null and b/corporate_finances_ui_py/src/assets/images/precia_logo_naranja.png differ diff --git a/corporate_finances_ui_py/src/environments/environment.prod.ts b/corporate_finances_ui_py/src/environments/environment.prod.ts new file mode 100644 index 0000000..71fa3d5 --- /dev/null +++ b/corporate_finances_ui_py/src/environments/environment.prod.ts @@ -0,0 +1,11 @@ +export const environment = { + production: true, + apiKey: 'https://delta.precia.co/api/', + azure: { + cliendId: '68c42075-3c74-49bb-8271-f33a390367d8', + authority: 'https://login.microsoftonline.com/caa1dfbf-34d5-4061-9cdf-0ceaa516bf03' + }, + KEY_ID_ASSESSMENT: "idAssessment", + KEY_TOKEN: "token", + KEY_COMPANIE_INFORMATION: "compaInformation" +}; \ No newline at end of file diff --git a/corporate_finances_ui_py/src/environments/environment.qa.ts b/corporate_finances_ui_py/src/environments/environment.qa.ts new file mode 100644 index 0000000..ac4be3e --- /dev/null +++ b/corporate_finances_ui_py/src/environments/environment.qa.ts @@ -0,0 +1,11 @@ +export const environment = { + production: false, + apiKey: 'https://delta-qa.precia.co/api/', + azure: { + cliendId: '2865a844-edb7-4743-9436-4e7d72ae963c', + authority: 'https://login.microsoftonline.com/caa1dfbf-34d5-4061-9cdf-0ceaa516bf03' + }, + KEY_ID_ASSESSMENT: "idAssessment", + KEY_TOKEN: "token", + KEY_COMPANIE_INFORMATION: "compaInformation" +}; \ No newline at end of file diff --git a/corporate_finances_ui_py/src/environments/environment.ts b/corporate_finances_ui_py/src/environments/environment.ts new file mode 100644 index 0000000..5debeb9 --- /dev/null +++ b/corporate_finances_ui_py/src/environments/environment.ts @@ -0,0 +1,24 @@ +// This file can be replaced during build by using the `fileReplacements` array. +// `ng build` replaces `environment.ts` with `environment.prod.ts`. +// The list of file replacements can be found in `angular.json`. + +export const environment = { + production: false, + apiKey: 'https://ffkac914z7.execute-api.us-east-1.amazonaws.com/dev/', + azure: { + cliendId: 'dcd76a6c-30fe-4390-bf3c-dfefd29d304c', + authority: 'https://login.microsoftonline.com/caa1dfbf-34d5-4061-9cdf-0ceaa516bf03' + }, + KEY_ID_ASSESSMENT: "idAssessment", + KEY_TOKEN: "token", + KEY_COMPANIE_INFORMATION: "compaInformation" +}; + +/* + * For easier debugging in development mode, you can import the following file + * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`. + * + * This import should be commented out in production mode because it will have a negative impact + * on performance if an error is thrown. + */ +// import 'zone.js/plugins/zone-error'; // Included with Angular CLI. diff --git a/corporate_finances_ui_py/src/index.html b/corporate_finances_ui_py/src/index.html new file mode 100644 index 0000000..d4bdd7c --- /dev/null +++ b/corporate_finances_ui_py/src/index.html @@ -0,0 +1,16 @@ + + + + + + Delta + + + + + + + + + + \ No newline at end of file diff --git a/corporate_finances_ui_py/src/main.ts b/corporate_finances_ui_py/src/main.ts new file mode 100644 index 0000000..c7b673c --- /dev/null +++ b/corporate_finances_ui_py/src/main.ts @@ -0,0 +1,12 @@ +import { enableProdMode } from '@angular/core'; +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; + +import { AppModule } from './app/app.module'; +import { environment } from './environments/environment'; + +if (environment.production) { + enableProdMode(); +} + +platformBrowserDynamic().bootstrapModule(AppModule) + .catch(err => console.error(err)); diff --git a/corporate_finances_ui_py/src/polyfills.ts b/corporate_finances_ui_py/src/polyfills.ts new file mode 100644 index 0000000..4ceb58f --- /dev/null +++ b/corporate_finances_ui_py/src/polyfills.ts @@ -0,0 +1,58 @@ +/*************************************************************************************************** + * Load `$localize` onto the global scope - used if i18n tags appear in Angular templates. + */ +import '@angular/localize/init'; +/** + * This file includes polyfills needed by Angular and is loaded before the app. + * You can add your own extra polyfills to this file. + * + * This file is divided into 2 sections: + * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers. + * 2. Application imports. Files imported after ZoneJS that should be loaded before your main + * file. + * + * The current setup is for so-called "evergreen" browsers; the last versions of browsers that + * automatically update themselves. This includes recent versions of Safari, Chrome (including + * Opera), Edge on the desktop, and iOS and Chrome on mobile. + * + * Learn more in https://angular.io/guide/browser-support + */ + +/*************************************************************************************************** + * BROWSER POLYFILLS + */ + +/** + * By default, zone.js will patch all possible macroTask and DomEvents + * user can disable parts of macroTask/DomEvents patch by setting following flags + * because those flags need to be set before `zone.js` being loaded, and webpack + * will put import in the top of bundle, so user need to create a separate file + * in this directory (for example: zone-flags.ts), and put the following flags + * into that file, and then add the following code before importing zone.js. + * import './zone-flags'; + * + * The flags allowed in zone-flags.ts are listed here. + * + * The following flags will work for all browsers. + * + * (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame + * (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick + * (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames + * + * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js + * with the following flag, it will bypass `zone.js` patch for IE/Edge + * + * (window as any).__Zone_enable_cross_context_check = true; + * + */ + +/*************************************************************************************************** + * Zone JS is required by default for Angular itself. + */ + (window as any).global = window; + import 'zone.js'; // Included with Angular CLI. + (window as any).global = window; + +/*************************************************************************************************** + * APPLICATION IMPORTS + */ diff --git a/corporate_finances_ui_py/src/styles.css b/corporate_finances_ui_py/src/styles.css new file mode 100644 index 0000000..c0afdc0 --- /dev/null +++ b/corporate_finances_ui_py/src/styles.css @@ -0,0 +1,16 @@ +@import url('https://fonts.googleapis.com/css2?family=Inter&display=swap'); + +* { + font-family: "Inter" + , sans-serif !important; +} + +.bi { + vertical-align: -.125em !important; +} + +.wrapper { + display: flex; + flex-direction: column; + min-height: 100vh; +} \ No newline at end of file diff --git a/corporate_finances_ui_py/tsconfig.app.json b/corporate_finances_ui_py/tsconfig.app.json new file mode 100644 index 0000000..b120c1d --- /dev/null +++ b/corporate_finances_ui_py/tsconfig.app.json @@ -0,0 +1,15 @@ +/* To learn more about this file see: https://angular.io/config/tsconfig. */ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "./out-tsc/app", + "types": ["node"] + }, + "files": [ + "src/main.ts", + "src/polyfills.ts" + ], + "include": [ + "src/**/*.d.ts" + ] +} diff --git a/corporate_finances_ui_py/tsconfig.json b/corporate_finances_ui_py/tsconfig.json new file mode 100644 index 0000000..f96fb11 --- /dev/null +++ b/corporate_finances_ui_py/tsconfig.json @@ -0,0 +1,37 @@ +/* To learn more about this file see: https://angular.io/config/tsconfig. */ +{ + "compileOnSave": false, + "compilerOptions": { + "baseUrl": "./", + "outDir": "./dist/out-tsc", + "forceConsistentCasingInFileNames": true, + "strict": true, + "noImplicitOverride": true, + "noPropertyAccessFromIndexSignature": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true, + "sourceMap": true, + "declaration": false, + "downlevelIteration": true, + "experimentalDecorators": true, + "moduleResolution": "node", + "importHelpers": true, + "target": "ES2022", + "module": "ES2022", + "paths": { + "exceljs": [ + "node_modules/exceljs/dist/exceljs.min" + ] + }, + "lib": [ + "ES2022", + "dom" + ] + }, + "angularCompilerOptions": { + "enableI18nLegacyMessageIdFormat": false, + "strictInjectionParameters": true, + "strictInputAccessModifiers": true, + "strictTemplates": true + } +} \ No newline at end of file diff --git a/corporate_finances_ui_py/tsconfig.spec.json b/corporate_finances_ui_py/tsconfig.spec.json new file mode 100644 index 0000000..092345b --- /dev/null +++ b/corporate_finances_ui_py/tsconfig.spec.json @@ -0,0 +1,18 @@ +/* To learn more about this file see: https://angular.io/config/tsconfig. */ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "./out-tsc/spec", + "types": [ + "jasmine" + ] + }, + "files": [ + "src/test.ts", + "src/polyfills.ts" + ], + "include": [ + "src/**/*.spec.ts", + "src/**/*.d.ts" + ] +}