Evaluación de un Programa de Mantenimiento de Aeronaves (AMP)

Vamos a ver cómo evaluar un Programa de Mantenimiento de Aeronaves, en adelante AMP (Aircraft Maintenance Program) conforme a la normativa EASA.

Básicamente se trata de comparar una a una cada tarea del Programa de Mantenimiento con la documentación de referencia del fabricante. Para ello usaremos Microsoft Office (Accesss, Excel) y VBA, y un par de técnicas matemáticas/informáticas. En particular veremos compararemos lo realmente importante, el intervalo y el threshold

Usaré un ejemplo inventado de AMP, y un ejemplo inventado de MPD para tratar de cubrir algunos casos, cuya extrapolación será sencilla.

Técnicas a usar

Para poder automatizar todo, vamos a usar dos técnicas matemáticas habituales y ampliamente conocidas, en su implementación informática:

  • Expresiones Regulares
  • Lógica Difusa, algoritmos de comparación y similitud de cadenas de texto

Las expresiones regulares nos permitirán extraer de nuestras tablas con los datos del AMP y MPD los valores de los intervalos y poder convertirlos para que sean los más parecidos posible. Por ejemplo, si el AMP indica como intervalo «I= 1095 Days» y el MPD «Interval: 3 YE«, podremos extraer el texto que nos interesa (1095 Days y 3 YE) y adicionalmente convertirlo a las mismas unidades (3 YE , 3 YE)

La Lógica Difusa y alguno de sus algoritmos de similitud de texto, nos va a permitir comparar los valores del AMP y MPD, pero no con los valores discretos Igual o Distinto (verdadero/falso), sino con un número (de 0 a 1) que indica el grado de similitud entre ambos. Esto nos va a permitir evitar realizar un trabajo casi imposible de tratar de convertir todos los valores del AMP y MPD de una manera idéntica.

Se trata de llegar a un punto en el que los valores del AMP y MPD sean comparables, por ejemplo, un intervalo del tipo «12 MO OR 1500 FH» puede ser comparable a otro del tipo «12 MTH OR 1500 FLH» , en este caso, la lógica discreta arrojaría un valor Falso o Distinto, mientras que la lógica difusa arrojaría una similitud de, digamos un 85%. Veremos a lo largo de este post lo sencillo que resulta comparar los intervalos de esta manera y detectar fácilmente aquellos que son distintos.

Nota: ver el post: https://abrazalaweb.net/2019/11/vba-ejecutar-cadena-de-texto-string-como-comandos-en-un-procedimiento-funcion-aplicacion-reemplazar-con-expresiones-regulares/

Proceso de evaluación

Los pasos que vamos a realizar son:

  1. Extraer los datos del AMP y del MPD a sendas tablas Excel. Tendremos varias columnas, donde las necesarias e imprescindibles son: Número de Tarea, Intervalo y Threshold . Podemos hacerlo con Adobe Acrobat o la herramienta Tabula
  2. Preprocesar con las expresiones regulares los campos Threshold e Intervalo, para extraer la información relevante: valores y unidades de medida de los mismos, teniendo en cuenta que buscamos que se parezcan, no tenemos que tardar mucho. Esto lo haremos con la herramienta en MS Access que indicaré a continuación. Nos ayudaremos para ello de un simulador tipo https://regexr.com/
  3. Crear una consulta de proyección en MS Access donde incluiremos ambas tablas, comparando los intervalos con el algoritmo de similitud de texto
  4. Exportar a Excel el resultado de la consulta, ordenar por el valor de solicitud y comprobar fácilmente los valores distintos

Herramienta

La herramienta (Toolkit for Evaluation of Maintenance Programs, TEMP) está realizada en Microsoft Acces usando formularios y VBA.

La herramienta tiene tres pestañas (que se abren a la vez con la macro Autoexec):

  1. Formulario RegExp, es el que vamos a usar, usa el módulo regexp, y consta de tres utilidades: limpiar campos (quita retornos de carro y varios espacions juntos), reemplazo de cadenas de texto usando expresiones regulares y con ellas también, extracción del texto que nos interese.
  2. Formulario MPD modificaciones, partiendo de un MPD de Airbus y el listado de modificaciones de un avión, comprueba la aplicabilidad de las tareas del MPD en el avión, basándose en las modificaciones de éste
  3. pdfSearch: búsqueda masiva en PDF, ya comentado en este blog, https://abrazalaweb.net/2019/03/busqueda-masiva-en-pdf-vba/, usa el módulo Clipboard (para pegar en Acrobat la cadena de texto buscada)

Herramienta «limpia», sin hacer nada aún, con algunos valores por defecto:

Enlace de descarga: TEMP.accdb

Tablas Excel

Estas son las tablas excel que voy a usar para este ejemplo, extraídas de los pdf del AMP y del MPD

Tabla MPD:

RevTask referenceDescriptionThreshold/Internal/SampleOtros
Rxxxxx-xx-001Descripción 1I: 2 AOtros 1
xxxxx-xx-002Descripción 2I: 2 COtros 2
xxxxx-xx-003Descripción 3I:  COtros 3
xxxxx-xx-004Descripción 4I:  COtros 4
Rxxxxx-xx-005Descripción 5I: 4 AOtros 5
xxxxx-xx-006Descripción 6I: 2 COtros 6
xxxxx-xx-007Descripción 7I: 2 COtros 7
xxxxx-xx-008Descripción 8I: 2 COtros 8
xxxxx-xx-009Descripción 9I:  YEOtros 9
xxxxx-xx-010Descripción 10I: 3 MO
OR
I: 600 LD
Otros 10
Rxxxxx-xx-011Descripción 11I: 500 FHOtros 11
xxxxx-xx-012Descripción 12I: 3 MO
OR
I: 600 LD
Otros 12
xxxxx-xx-013Descripción 13I: 3 MO
OR
I: 600 LD
Otros 13
Rxxxxx-xx-014Descripción 14I: 500 FHOtros 14
xxxxx-xx-015Descripción 15I: 3 MO
OR
I: 600 LD
Otros 15
xxxxx-xx-016Descripción 16T: 4 YE
I: 2 YE
Otros 16
xxxxx-xx-017Descripción 17T: 4 YE
I: 2 YE
Otros 17
xxxxx-xx-018Descripción 18T: 36000 FL
I: 12000 F
Otros 18
xxxxx-xx-019Descripción 19T: 36000 FL
I: 12000 FL
Otros 19
xxxxx-xx-020Descripción 20T: 4 YE
I: 4 YE
Otros 20
xxxxx-xx-021Descripción 21I:  COtros 21
Rxxxxx-xx-022Descripción 22I: 4 AOtros 22
Rxxxxx-xx-023Descripción 23I: 2000 FHOtros 23
Rxxxxx-xx-024Descripción 24I: 4 AOtros 24
Rxxxxx-xx-025Descripción 25I: 4 AOtros 25
xxxxx-xx-026Descripción 26I:  COtros 26
xxxxx-xx-027Descripción 27I:  COtros 27
xxxxx-xx-028Descripción 28I:  COtros 28
xxxxx-xx-029Descripción 29I:  COtros 29
Dyyyyy-yy-030Descripción 30I: 2000 FHOtros 30
xxxxx-xx-031Descripción 31I:  COtros 31
xxxxx-xx-032Descripción 32I:  COtros 32
xxxxx-xx-033Descripción 33I:  COtros 33
xxxxx-xx-034Descripción 34I:  WYOtros 34
xxxxx-xx-035Descripción 35I:  YEOtros 35
xxxxx-xx-036Descripción 36I:  NOTEOtros 36
xxxxx-xx-037Descripción 37I: 4 C
OR
I: 8 YE
Otros 37
xxxxx-xx-038Descripción 38I: 4 C
OR
I: 8 YE
Otros 38

Tabla AMP

STATUSTASK REFERENCEDESCRIPTIONTHINTERVAL
xxxxx-xx-001Descripción 14 A4 A
xxxxx-xx-002Descripción 224 FH24 FH
xxxxx-xx-003Descripción 32 A2 A
xxxxx-xx-004Descripción 42 C2 C
xxxxx-xx-005Descripción 51 C1 C
xxxxx-xx-006Descripción 61 C1 C
xxxxx-xx-007Descripción 74 A4 A
xxxxx-xx-008Descripción 82 C2 C
Rxxxxx-xx-009Descripción 92 C2 C
Rxxxxx-xx-010Descripción 102 C2 C
Rxxxxx-xx-011Descripción 116 MO6 MO
xxxxx-xx-012Descripción 123 MO
OR
600 FC
3 MO
OR
600 FC
Rxxxxx-xx-013Descripción 13500 FH500 FH
xxxxx-xx-014Descripción 143 MO
OR
600 FC
3 MO
OR
600 FC
xxxxx-xx-015Descripción 153 MO
OR
600 FC
3 MO
OR
600 FC
Rxxxxx-xx-016Descripción 16500 FH500 FH
xxxxx-xx-017Descripción 17183 DY
OR
600 FC
3 MO
OR
600 FC
xxxxx-xx-018Descripción 183600 FH1200 FC
xxxxx-xx-019Descripción 193600 FH1200 FC
xxxxx-xx-020Descripción 201 C1 C
xxxxx-xx-021Descripción 211 C1 C
Rxxxxx-xx-022Descripción 221 C1 C
xxxxx-xx-023Descripción 231 C1 C
xxxxx-xx-024Descripción 244 A
Rxxxxx-xx-025Descripción 252000 FH2000 FH
Rxxxxx-xx-026Descripción 264 A4 A
xxxxx-xx-027Descripción 274 A4 A
xxxxx-xx-028Descripción 281 C1 C
Rxxxxx-xx-029Descripción 291 C1 C
Rxxxxx-xx-030Descripción 301 C1 C
xxxxx-xx-031Descripción 311 C1 C
Rxxxxx-xx-032Descripción 322000 FH2000 FH
xxxxx-xx-033Descripción 331 C1 C
xxxxx-xx-034Descripción 341 C1 C
xxxxx-xx-035Descripción 351 C1 C
xxxxx-xx-036Descripción 364 A4 A
xxxxx-xx-037Descripción 37LCLC
xxxxx-xx-038Descripción 381 YE1 YE
xxxxx-xx-039Descripción 398 YE
OR
4 C
8 YE
OR
4 C
xxxxx-xx-040Descripción 408 YE
OR
4 C
8 YE
OR
4 C

Ahora las importamos a Access, en el asistente de importación tenemos que indicarle que la primera fila contiene los encabezados de columna y permitimos que agrege la clave principal

Y las tenemos ya en nuestra herramienta:

Después de esto, guardamos y cerramos Access y lo volvemos a abrir (no está muy depurada la herramienta de momento, y para que se cargen todas las tablas en los desplegables del formulario no queda otra que cerrar/abrir)

Primeros pasos, limpiar y pre-procesar las tablas

Antes nada, vamos a limpiar y a preparar las tablas de AMP y MPD para poder compararlas fácilmente. Para ello tenemos que estudiar un poco los datos de cada una de ellas, para poder inferir las expresiones regulares que necesitaremos (siempre con la ayuda de páginas del tipo https://regexr.com/ para comprobar que las expresiones regulares que usamos están bien)

Limpiar las tablas

En el formulario Access, lo primero que tenemos que hacer es seleccionar la tabla y el campo sobre el que vamos a ejecutar las herramientas del mismo A) y B).

Por tanto, empezamos con la tabla MPD, la seleccionamos en el combo, y luego seleccionamos el campo Threshold/Interval (el combo campos se actualiza con la selección de la tabla)

LImpiar tablas

Al pulsar limpiar saltos de línea, se crea una nueva columna (campo) añadiendo al nombre de la columna que hayamos seleccionado el sufijo «_limpio«. Comprobamos cómo se homogeneizan los valores

intervalo limpio

Hacemos lo mismo con la tabla AMP, esta vez, lo hacemos dos veces, una para la columna Threshold y otra para la columna Interval, al final tenemos nuevos campos «limpios»

Intervalo y Thrshold limpios

Herramienta A) Reemplazar algunos valores para preparar algo más en las tablas

Ahora, estudiando un poco los valores de cada tabla, usando expresiones regulares, podemos cambiar algunos para aproximarlos. Es un buscar/reemplazar avanzado, donde podemos incluso convertir valores numéricos. Para ello, podemos usar algunos de los valores de ejemplo, de la tabla «Biblioteca de Reemplazos»

Reemplazar

El funcionamiento es el siguiente:

  • Vamos a actuar sobre la tabla y columna/campo indicados en el inicio del formulario (1 y 2) NOTA: El campo que hemos limpiado previamente
  • Escribimos el patrón (expresión regular) que queremos modificar, es decir, lo que vamos a buscar (3)
  • Escribimos el patrón (expresión regular) por el que vamos a cambiar el anterior (4)
  • Si es necesario alguna conversión (ejecutar código VBA), seleccionamos la casilla Código Exe
  • Por último pulsamos el botón reemplazar (5)

En este ejemplo vamos ver dos tipos de reemplazos en la tabla AMP:

  1. Cambiar y convertir un valor
Reemplazar Conversión
reemplazar y convertir valores numéricos
  1. Cambiar el orden de los valores
reemplazar cambiar orden
cambiar el orden

En el primer caso, tenemos en la tabla «Biblioteca de reemplazos» la expresión regular

reemplazarpordescripción
(\d+)( Days)CStr(Round(Matches(0).SubMatches(0) / 30.5, 0)) & » MO»Pasar a MO (string codigoexe)

La expresión regular es sencilla: un primer grupo (los grupos se delimitan e identifican entre paréntesis) que representa un número, formado uno o más dígitos (\d+), seguidos de otro grupo formado por un «espacio» y la palabra «Days«. Eso lo reemplazamos por el código VBA que convierte el primer grupo (SubMatches(0)) a meses (dividiendo por 30.5), y le añade una cadena de texto formada por un «espacio» y la palabra «MO» . Como tenemos que ejecutar código VBA, tenemos que marcar la casilla código Exe

En el ejemplo tendremos que modificar el patrón, pues en lugar de Days tenemos DY

Lo vemos:

Ejecución del reemplazo

Al pulsar el botón Reemplazar, se ejecutará el cambio en la columna seleccionada (TH_limpio), y en nuestro caso el valor «183 DY» se convertirá en «6 MO»

Reemplazo efectuado
reemplazo y conversión efectuado correctamente

En el segundo caso, tenemos en la tabla «Biblioteca de reemplazos» la expresión regular

reempazarpordescripcion
(.*) OR (.*)$2 OR $1cambiar orden 100FH OR 1YE -> 1YE OR 100FH

Esta expresión regular es sencilla, un grupo de caracteres, seguido de «espacio» seguido de «OR» y de otro «espacio» y otro grupo de texto, simplemente se permuta el orden de los grupos. Ahora no se ejecuta código VBA en el reemplazo

Vamos a hacerlo en el campo «Intervalo_limpio», pero en este ejemplo no queremos cambiar el orden en todos los intervalos, sólo los que el primer valor estáen años, por tanto nuestro primer grupo será un grupo de caracteres, seguidos de un espacio y YE.

cambiar el orden

Al pulsar reemplazar, se habrá permutado el orden

ejecutado el cambio de orden

Herramienta B) Extraer Intervalos con expresiones regulares

Ahora vamos a extraer los valores que realmente nos interesan. Para ello usaremos expresiones regulares.

Lo que hace la aplicación es, a partir de una única columna donde se encuentran los intervalos y thresholds, separalos en dos columnas distintas (llamadas ‘_Int’ y ‘_Th’) y recorrer toda la tabla de tareas buscando para cada una de ellas qué valor de expresión regular de la lista RegExp es aplicable.

En el Access usamos la tabla RegExp, donde vamos a ir poniendo las que vayamos obteniendo para un MPD o AMP concreto (para eso tenemos el campo doc.

Lo que es de vital importancia es que tenemos que ponerlas en orden de la más larga o compleja a la más sencilla, ya que el programa va recorriendo la lista desde el principio, y cuando encuentra una coincidencia para (por eso si ponemos la primera una sencilla, se ejecutará la coincidencia a pesar de que cumpla una más completa si está debajo en la lista)

Lo primero que tenemos que hacer es ver cómo son las tablas que tenemos y qué podemos hacer, es decir buscar una estrategia. En el caso del ejemplo, vamos a trabajar sólo en la Tabla MPD, pues tiene ambos valores de Threshold en Intervalo en una misma columna y fácilmente identificables, todos ellos están precedidos por «T: « o «I: «, y entonces separaremos cada uno de ellos en dos columnas distintas, para hacerlo coincidir con el formato del AMP.

Explicación de la tabla RegExp

El ejemplo muestra esta tabla:

Tabla RegExp

Los campos son:

  • regExp: es la expresión regular que vamos a buscar, los patrones que hemos construido para sacar los valores que nos interesan. Ordenados siempre del más complejo al más sencillo. Es decir, un valor tiene que cuadrar primero en la regla más larga. Entre paréntesis los grupos que vamos a extraer.
  • SepararTh-Int: es un valor Sí/No en función de si es necesario crear dos columnas, en la primera el primer grupo y en la segunda el segundo.
  • numeroItems: es el número de elementos a extraer en una misma columna, se añadirá OR para concatenarlos.
  • saltoIndice: un valor que indica el número del grupo que se usará para los segundos valores extraidos. En general ‘1’ (siendo ‘0’ el primer grupo, pero en grupos más comlpejos hay que cambiarlo. Lo siguiente trata de explicarlo (ojo que los índices cuentas desde 1.., en tanto que en VBA hay que hacerlo desde 0)
  • descripción: escribimos una descripción de la regla más legible
  • doc: Para clasificar todas las reglas que hemos encontrado para un tipo determinado de tabla, en este caso el MPD de este fabricante de prueba.

Lo mejor es mirar el código VBA para ver cómo se usan, y cómo se puede modificar para contemplar y adaptarlo a más casos.

Ejecutamos la herramienta para nuestra tabla MPD

Teniendo en cuenta lo hecho hasta ahora:

Al hacer click en el botón Extraer Th/Int la tabla MPD queda modificada con las dos columnas nuevas, y preparada ya para poder comparar con el AMP

Nuevas columnas creadas, separando y extrayendo los Threshold e Intervalos

Evaluación del AMP vs MPD

Ahora ya estamos en condiciones de comparar las tablas.

Vamos a ver tres pasos:

  • Buscar tareas del MPD que no están en el AMP
  • Buscar tareas del AMP que no están en el MPD
  • Comparar intervalos/Threshold de las tareas comunes en ambos

Buscar tareas que faltan en AMP y MPD

Simplemente con el asistente de consultas de no coincidentes de Access podemos ver las tareas del MPD que faltan en el AMP y viceversa:

Asistente de consultas de Access

Seleccionamos la tabla inicial (MPD), la tabla donde vamos a buscar (AMP), el valor del campo

El resultado de la consulta nos muestra las tareas del MPD que no están en el AMP (una creada a propósito en este ejemplo)

Haciendo los mismos pasos, pero con el orden de las tablas al revés, tenemos las tareas del AMP que no están contempladas en el MPD

Comparar Threshold e Intervalos: algoritmo de similitud

Explicación: El algoritmo de similitud nos va a permitir comparar la similitud sintáctica de los campos (intervalos/threshold), si el resultado es 1, entonces son idénticos (el valor disminuye según van siendo más distintos, se va comparando el número de caracteres distintos, etc). Ordenar la lista por orden de mayor a menor del valor de similitud, permite un estudio y análisis «visual» muy sencillo y rápido.

No obstante existen dos problemas que no podemos obviar, relacionados con la semántica de los intervalos :

  • un intervalo de 100 FH es muy distinto a uno de 100 FC, a pesar de que el algoritmo de similitud indicará que son muy parecidos
  • un intervalo de 200 FH también es muy distinto a uno de 100 FH y el algoritmo también nos dirá que son muy parecidos.

El primer problema se soluciona muy fácilmente reemplazando en ambas tablas, en los campos Intervalo (o threshold) cualquiera de los dos, por ejemplo, podemos reemplazar FC por CYC y ya penalizamos el hecho de usar unidades distintas

Para el segundo problema, he implementado una función de penalización muy simple, que para cada intervalo extrae los números que aparecen en él (con expresiones regulares) y los compara, calculando una penalización p (número entero, valor inicial ‘0’) que aumenta según los números van siendo distintos, dividiendo entonces el resultado del algoritmo de similitud por esa penalización.

Por ejemplo, en la comparación 100 FH y 200 FH, calcularía una penalización p=2 y la similitud la dividiría por la mitad, evitando así pasar por un falso positivo

En el Access las funciones que hay son:

  • Similarity(string1,string2)
  • Similitud_adpt(string1,string2) Algoritmo Similarity anterior que incluye la penalización por números distintos
  • JaroWinkler(string1,string2, prefijo, tipo_comparación)
  • JaroWinkler(string1,string2,prefijo,tipo_comparación) Incluye la penalización

(JaroWinkler es otro algoritmo de comparación de cadenas que tiene en cuenta los comienzos de las cadenas), pero el resultado es similar, da valores más altos que Similarity

https://blog.developpez.com/philben/p12207/vba-access/vba-distance-de-jaro-winkler

Ahora creamos una consulta en modo diseño con las dos tablas, añadiendo una relación entre los campos con el número de tarea (inner join o proyección), incluimos los campos que nos interesan y la función similitud con los campos Threshold (y otra consulta con los campos Interval)

Diseño de consulta con las dos tablas

Establecemos la relación (con el ratón pinchamos en un campo Task Reference y lo arrastramos al equivalente en la otra tabla) y seleccionamos los campos que queremos en la consulta (lo más sencillo posible), los que hemos limpiado y extraido:

Creamos un nuevo campo de consulta con la herramienta generar código y seleccionamos la función similarity, con los parámetros a comparar: ‘_TH’ y ‘TH_limpio’


Es mejor usar la función Similitud_adpt (no aparece en la captura porque es previa a la modificación para penalizar intervalos muy parecidos pero con valores numéricos distintos 100FH vs 200FH)

Asistente

Al hacer click en la función vamos completando (idem con Similitud_adpt ):

Usaremos la función comparando los dos valores sólo:

Similarity( [MPDTasks]![_Th] , [TAREAS_AMP]![TH_limpio] ) 
Similitud_adpt( [MPDTasks]![_Th] , [TAREAS_AMP]![TH_limpio] )  

Guardamos la consulta y la ejecutamos, y obtenemos la tabla con las comparaciones. Exportamos la tabla a excel para poder estudiarla un poco mejor. En este caso, resulta que el AMP repite los valores de los intervalos en el campo threshold cuando en el MPD están vacíos (la similitud es 0). Al ordenar el Excel por el valor de la expresión similaridad descendente, es muy fácil comprobar los valores realmente distintos (simlaridad = 1 se corresponde a igualdad)

RevTask reference_ThTH_limpioExpr1
xxxxx-xx-01836000 FL3600 FH0.75
xxxxx-xx-01936000 FL3600 FH0.75
xxxxx-xx-0204 YE1 C0.25
xxxxx-xx-0164 YE500 FH0.166666672
xxxxx-xx-0174 YE6 MO OR 600 FC0.071428575
Rxxxxx-xx-0014 A0
xxxxx-xx-00224 FH0
xxxxx-xx-0032 A0

Repetimos exactamente lo mismo, pero ahora para los intervalos. Creamos una nueva consulta.

RevTask reference_IntINTERVAL_limpioExpr1
xxxxx-xx-0082 C2 C1
xxxxx-xx-0123 MO OR 600 LD3 MO OR 600 FC0.857142866
xxxxx-xx-0153 MO OR 600 LD3 MO OR 600 FC0.857142866
xxxxx-xx-01812000 F1200 FC0.857142866
xxxxx-xx-01912000 FL1200 FC0.75
Rxxxxx-xx-0012 A4 A0.666666687

A pesar de que este ejemplo no es muy bueno, es fácil comprobar que al ojo humano, con la tabla ordenada así, le resulta muy sencillo ver los intervalos que son iguales (casi iguales) y los distintos.

Para ello, esta tabla, extraída de un caso real lo muestra:

Lo más fácil es filtrar las filas con similaridad = 1 e ir recorriendo al tabla con la mirada, pues resulta muy sencillo detectar los cambios que se corresponden con valores correctos e incorrectos. El hecho de ordenar por el valor de similaridad facilita enormemente la labor.

2 Comments

  1. Evaluación de un Programa de Mantenimiento de Aeronaves (AMP): Tareas aplicables a un avión AIRBUS según su configuración de moficaciones – Abraza la Web · domingo, 31 mayo, 2020 Reply

    […] Evaluación de un Programa de Mantenimiento de Aeronaves (AMP) TEMP: Toolkit for Evaluation of Maintenance Programs […]

  2. Comparar tablas excel (con access) – Abraza la Web · domingo, 15 noviembre, 2020 Reply

    […] Evaluación de un Programa de Mantenimiento de Aeronaves (AMP) […]

Leave a Reply

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.