Bienvenidos a Iseries Venezuela

Las mejores prácticas, recursos, tips, enlaces, videos y artículos para informáticos relacionados con el Iseries y el As/400 lenguajes de programación RPG, ILE RPG y SQL.

The best practices, resources, tips, links, videoes and articles for computer related to the Iseries and the As/400 languages of programming RPG, ILE RPG and SQL.

Tuesday, December 22, 2009

Entrevista #2: Migración a EMV CHIP. Tarjetas de Crédito. Venezuela




Entrevista a: C. Gonzalez,
Directivo de System, Support Speed and Security

1. ¿Cuál cree usted ha sido la necesidad de migración de tecnología de banda magnética a EMV Chip, y por qué EMV cómo solución?

La necesidad a mi parecer, es por el factor Fraude ya que el cifrado es mas complejo que el usado en la banda magnética y la urgencia de prestar un buen servicio en los momentos en que el emisor no responde, el cual esta cubierto por la autorización OFFLINE, ya que el chip con información programada permitirá la autorización o no de la transacción.


2. ¿Qué impactos ha tenido este proceso de migración en cuanto a la emisión de las tarjetas de crédito?

El impacto radica en los costos que le traerá a la institución que tome esta tecnología, que va desde el cambio del plástico, pasando por las maquinas que troquelan, los Puntos de Venta, los ATM y por ultimo los programas Autorizadores, todo esto apuntando a un ente, luego viene el conjunto de todos ellos, ya que para poder operar 100%, todos los entes deben adoptar esta tecnología, y el ponerse de acuerdo, que no es fácil hacerlo, afecta el proceso de migración.


3. ¿Venezuela está lista para salir al mercado con tarjetas EMV Chip?
Actualmente no esta lista, aunque es una solicitud de las Franquicias, las instituciones se están preparando, desde el factor humano, hasta la compra de nuevos Hardware y Software, pero no para salir ya, tal vez existan instituciones con un 75% en el avance del cambio, pero que luego alcanzado el 100% el uso de las tarjetas se vera limitado por el cambio de los POS y ATM localmente, siendo la utilización máxima en el extranjero.

4. ¿Las entidades bancarias han contado con la información y el respaldo de las Franquicias, Proveedores, Estado, y otros entes, que les permita ganar la confianza necesaria para migrar sin temor al fracaso en este proyecto, y por qué?

Si han contado con el apoyo de todas esas instituciones, porque por ejemplo las Franquicias y el Estado coinciden en que debe ser obligatorio y por consiguiente existen los proveedores que han diseñado las herramientas necesarias para controlar esta nueva tecnología, la cual ya esta probada dando confianza para avanzar en este proyecto.


5. ¿Cuáles son los principales elementos que justifican los altos índices de inversión que deben hacerse para este propósito?
Los principales elementos que requieren un máximo de inversión son los cambios o adquisición de nuevo Hardware y Software que soporten el cambio del Chip y el cambio del Plástico viejo por el nuevo Plástico.


6. ¿Cuáles considera usted han sido los principales problemas que han generado el retraso en la implementación del proceso de migración y en la emisión de tarjetas de crédito con EMV Chip?
Los principales problemas son la actualización del Hardware para la generación y control de la nueva tarjeta y los cambios o adquisición de los equipos de Puntos de Venta y ATM para que soporten la lectura del Chip.


7. ¿Conoce usted qué tipo de estrategias se pretenden implementar para educar, consolidar y garantizar la permanencia de las tarjetas con tecnología EMV Chip, tanto en el sector comercial como en la población en general?

No actualmente no conozco la estrategia, pero cada institución se valdrá de los medios de comunicación actuales, así como la propaganda interna.


8. ¿Existen medidas a tomar en caso de que el proyecto fracase?
Con todos los cambios que se realizaran, inversión de tecnología y dinero, no hay vuelta atrás, y hay que recordar que la tarjeta con Chip, estará acompañada de la banda magnética, lo cual permitirá una transición controlada.

9. ¿Conoce usted para cuándo ha sido postergada la salida al mercado de tarjetas con tecnología EMV Chip?

No manejo esa información, pero estimo que para finales del año 2010, ya algunos bancos estarán informando su intención de salir con esta nueva tecnología.



Entrevista realizada por Marilys Montilva
Publicada por: Liliana Suárez


Si te pareció interesante el artículo reenvíalo a un amigo, haciendo
click en el sobrecito que está al final del artículo. El conocimiento es valioso, compártelo.

Thursday, December 10, 2009

Definiendo Las Claves en los Archivos












                                                                      (Haz Click en la imágen para agrandarla)

Un error muy común en aquellos centros de informática donde se utilizan sistemas que no se basan en DB2 sino en el manejo tradicional de archivos según la DDS definidas por los desarrolladores, consiste en confundir Clave con Índices de Acceso.


En la figura tenemos un diagrama donde se puede ver un encabezado de factura y sus tres campos que definen la clave. También podemos ver múltiples ocurrencias del archivo de detalle en el cual se especifica el artículo facturado al cliente.

En general es común creer que la clave del archivo de detalle es la que se ilustra en el diagrama, es decir, la misma clave que el encabezado de factura agregando además el artículo facturado. El concepto de clave implica además de su unicidad, su inmovilidad en el tiempo, es decir, es inmodificable. Si el cliente decide cambiar el artículo, no es posible desde un punto de vista conceptual, realizar el cambio. Para realizar el cambio en la factura, la aplicación debe permitir agregar artículos y eliminar artículos mas no modificar el código del artículo. El usuario de la aplicación debe entonces eliminar el artículo de la factura y agregar la información del nuevo artículo que desea el cliente.

En este punto algunos desarrolladores piensan que la solución entonces es colocar como campos claves del detalle del artículo los mismos campos claves de su cabecera. Con esta acción se pierde la clave del archivo puesto que deja de ser única y se repite tantas veces como artículos haya en la factura.

La solución ajustada a las reglas y normas de construcción de Base de Datos es generar un consecutivo. Es decir, cada vez que se crea un artículo, el programa genera un número de secuencia que identificaría en forma unívoca a cada registro dentro del archivo de detalles. Esto es particularmente útil cuando el inventario es más complicado y cada artículo se define a su vez por medidas, pesos, litros, láminas.

(Haz Click en "Más Información" para seguir leyendo)

Monday, December 7, 2009

Matrices en RPG









En RPG no existe la estructura de Datos para almacenar Matrices como es concebida en otros lenguajes que indexan las matrices de la siguiente manera: Matriz(X,Y) = Valor  (click en la imágen para agrandarla)

Se puede utilizar un artificio declarando una DS en el programa que utilizamos para representar tantas filas como se requiera, a través de la palabra clave OCCURS.

Dentro de la DS se declara un arreglo para almacenar los valores de las columnas asociados a cada fila.

Declaración de la Matriz

D*******************************
dDSfilas DS occurs(100)
d Colum 10a dim(100)
d
dVariables para indexar la matriz.
d******************************
dFila s 3S 0
dCol s 3S 0

Para llenar el elemento ubicado en la fila 1 y columna 1
Se sigue el siguiente procedimiento:
c*
c Eval Fila = 1
c Eval Col = 1
c Fila Occur Dsfilas
c eval Colum(Col) = Valor

Tuesday, December 1, 2009

MIGRACIÓN DE TECNOLOGÍA DE BANDA MAGNÉTICA A EMV CHIP EN LA EMISIÓN DE TARJETAS DE CRÉDITO EN VENEZUELA.



En Venezuela, los desarrolladores que laboran en el área bancaria, deberán participar el año que viene en los procesos migratorios de tecnología de banda magnética a EMV Chip.

A continuación una entrevista con J.C.O. Gerente de Proyecto de una reconocida  institución financiera, a fin de familiarizarnos con las causas, efectos e impactos que puede acarrear este cambio tecnológico.


1. ¿Cuál cree usted ha sido la necesidad de migración de tecnología de banda magnética a EMV Chip, y por qué EMV cómo solución?


La principal razón para definir esta necesidad la podemos encontrar en el tema de la seguridad, debido al alto nivel de riesgo asociado a las tecnologías de tarjetas asociadas a banda magnética(facilidad de falsificación, copia, etc.), las franquicias que apoyan el negocio con tarjeta, y los mismos bancos, que son los que sufren con este tipo de delito, se han visto en la necesidad de realizar alianzas dirigidas a desarrollar una tecnología que, en palabras coloquiales, les haga más difícil a los delincuentes tecnológicos poder falsificar y autenticarse como dueño de una tarjeta de crédito que no le pertenezca, como todo lo mas importante es golpear primero, ya que la curva de aprendizaje del delincuente es muy rápida y podría pasar que cuando implantemos una versión X de esta tecnología, la misma no sea tan efectiva, como se dice en el negocio, la facilidad de delinquir que uno cierra, se migra inicialmente al del lado del que es mas débil.



Sunday, November 29, 2009

Preguntas y Respuestas Frecuentes












1.- ¿Cómo Chequear que se va a grabar clave duplicada?
C Monitor

C WRITE(E) FILENAME

C On-Error 01021

C EXSR $ERRROR

C EndMon


2.- ¿Es posible utilizar más de un subfile en pantalla?

Si es posible. La manera es de hacerlo es precisar el rango de columnas y filas en la pantalla asociado a cada subfile. En el programa, preguntas por la posición del cursor y vas a la rutina de avance o retroceso de un subfile o del otro dependiendo de la ubicación del cursor.

Wednesday, November 25, 2009

Aplicaciones Multi-idioma






Algunas veces queremos diseñar sistemas multi-idiomas, para realizar presentaciones del proyecto, mostrando la pantalla en español y en ingles. En la imagen que acompaña a este articulo podemos ver dos pantallas: una en ingles y la otra en español.

Haciendo Click en las imágenes las puedes ver ampliadas


Para realizar un sistema multi-idiomas, es necesario que los títulos en las pantallas no sean literales sino campos de salida. En el ejemplo tenemos los literales: usuario, producto, reclamo y monto, entre otros.

Lo primero que debemos hacer es crear dos archivos de mensajes con igual nombre pero en distintas bibliotecas. CRTMSGF. Supongamos que creamos el archivo de mensajes llamado TITULOS en la biblioteca: ESPANOL y otro archivo de mensajes llamado TITULOS en la biblioteca: INGLES. Un párrafo mas adelante explicaré su utilización.

El truco consiste en sustituir estos literales de pantalla por campos alfabéticos de salida.

Thursday, November 19, 2009

Botones en RPG


















Los Botones para seleccionar opciones son utilizados en diversas plataformas.

En RPG existe un mecanismo de emular los botones de selección como puede verse en la imagen adjunta a este artículo.

Haz click en la imagen para verla ampliada.

Es necesario declarar una variable numérica que sea de entrada y salida (bivalente)
2,0 bivalente, con atributo de desplazamiento de teclado: Y

Con F4 y luego 1 para seleccionar las propiedades del campo seleccionamos la ultima opción que vemos en pantalla titulada: Palabras claves de opción, colocando Y
(esta opción está antes del titulo que nos permite colocar palabras claves de texto).

Si no declaras el campo como está especificado esta opción de palabra claves de opción, no aparecerá en pantalla.

En la pantalla siguiente, especificamos que hay múltiples opciones con la palabra clave MLTCHCFLD = Multiple Choice field, luego elegimos seleccionar parámetros = Y; elegimos también definir las palabras claves de opción con Y
__________________________________________________________

Teclee opciones, pulse Intro.

Tipo de selección de opción . . . . . . . . 2 1=SNGCHCFLD 2=MLTCHCFLD

Seleccionar parámetros . . . . . . . . . Y                                                    
Opción de campo de selección . . . . . . . . CHOICE
Definir palabras clave de opción . . . . . Y _______________________________________________________________

Aparece la siguiente pantalla:

Donde dice número de opción colocamos el número de opción 1, 2, 3 definiendo el titulo de cada opción de botón en pantalla. Nuestro ejemplo es un botón con dos opciones. En este ejemplo se especifica para la segunda opción, pero debe especificarse para todas.

El campo de control es la variable que recogerá el valor 1 cuando el usuario elija esta opción con el Mouse. El Texto que titula la opción es ANUAL

__________________________________________________________________
Número de opción . . . . . . . . 2 Número, +/-, F4 para lista


Teclee opciones, pulse Intro.

Palabra clave Más

Opción de campo de selección . CHOICE Y Y=Sí

Indicadores . . . . . . . . . Nnn, +

Campo de texto . . . . . . . Nombre

Texto . . . . . . . . . . . . ANUAL

Espacio en blanco previo . . Y Y=Sí

Control de opción . . . . . . . CHCCTL Y

Campo de control . . . . . . CAMPO1
___________________________________________________________


En este link pueden descargar el código del fuente que fue desarrollado a manera de ejemplo:

Fuentes Botones en RPG

Autor: Ing. Liliana Suárez.


Si te pareció interesante, reenvialo a un amigo haciendo click en el sobrecito que está al final del artículo. El conocimiento es valioso, compártelo.

Tuesday, November 17, 2009

Subfiles: aprovechando su funcionalidad












Otra funcionalidad muy útil puede ser aplicada para el uso de subfiles y consiste en guardar los resultados de las validaciones de los datos incluidos por el usuario.

En general es común presentar una pantalla y luego mediante una serie de validaciones encender tal o cual indicador y se asocia un mensaje de error que posiciona el cursor en el dato inválido y/o lo resalta en pantalla. Este proceso es secuencial, es decir se valida el primer dato y se da el mensaje de error aunque otros campos pueden tener errores en ese mismo momento. Las siguientes validaciones deben esperar por el siguiente ENTER del usuario. En un ejemplo extremo suponiendo veinte campos en pantalla y todos errados, el usuario debe presionar ENTER 20 veces para corregir el error en cada dato.

Una mejora que puede hacerse al procedimiento anteriormente descrito es dar el mensaje de error de uno de los campos y resaltar los demás datos errados para que el usuario se alerte de los errores detectados sin saber necesariamente de qué se tratan.

Sustituyendo el uso del registro de pantalla simple por un subfile, el proceso se hace mucho mas eficiente para la corrección de errores de carga.

Debe definirse el subfile de manera que solo muestre un registro por pantalla (aunque el subfile tenga 1000 registros por definición) el usuario verá una pantalla para cargar data que sería el registro de control. Los mensajes de error serán almacenados en las líneas del subfile. El usuario verá una sola línea del subfile en la pantalla con el primer mensaje de error detectado en el programa, pero haciendo rollup puede ver todos los mensajes de error que se generaron al presionar un solo ENTER. Los datos erróneos pueden ser resaltados todos y además el usuario puede ver de una vez de qué se tratan todos los errores que el sistema está reportando.

Optimizando los tiempos de procesamiento tanto en los procesos de carga asi como en procesos interactivos y en batch, se van reduciendo los tiempos de respuesta y aumentando la satisfacción de los usuarios del sistema.

Si te pareció interesante, reenvialo a un amigo haciendo click en el sobrecito que está al final del artículo. El conocimiento es valioso, compártelo.

Autor: Ing. Liliana Suárez

Saturday, November 14, 2009

Adefesios en RPG





San Pablo escribía a los Efesios cartas aconsejándoles sobre dejar ciertos hábitos o conductas extravagantes y escandalosas. Con el devenir del tiempo, se utiliza la frase ADEFESIO en recuerdo a las cartas de San Pablo a esa comunidad. De San Pablo a los Efesios se tomó: Ad-Efesios (A los efesios).

Un Adefesio según la real academia de la lengua es algo que se ve feo, extravagante o ridículo.

A continuación, una pequeña muestra de algunos adefesios en la programación en RPG.


ADEFESIO 1


C_________ENDIF
C_________ENDDO
C_________ ENDSR
0401.00 *---* *- - - - - - - - - - - - - - - - - - - - - - - - - -
0402.00 ** MENSAJES DE ERROR **
0403.00 POLIZA NO REGISTRADA, VERIFIQUE
0404.00 POLIZA NO EXISTE EN DTOGEN, VERIFIQUE
0405.00 CON F1 ACTUALIZA PLAN DEL CERTIFICADO
0406.00 PARA EMITIR POLIZA, DEBE SELECCIONAR ''G'' Y PULSAR CF08

Colocar mensajes de validación en una tabla al final del programa es feo.

Es recomendable un archivo contentivo de los mensajes de error del sistema o módulo porque unifica criterios y estandariza la programación.


ADEFESIO 2
____________________L E
CAÑOFIN COMP UYEAR 1122
CN11 22 MESFIN COMP UMONTH 2233
CN11N22 33DIAFIN COMP UDAY 3333
C11
COR 22
COR 33 DO
C ADD SUMASI BSFIN
C SETON 12
C END

Programar una comparación entre dos fecha de esta manera es feo y extravagante.

Es recomendable, crear dos DS en el programa para realizar la pregunta de la siguiente manera:

IF FECHAFINAL (AAAAMMDD) <= FECHAACTUAL(AAAAmmDD) ADD SUMASU BSFIN ENDIF


 ADEFESIO 3

C *IN60 IFEQ *ON
C *IN61 OREQ *ON
C *IN03 OREQ *ON
C *IN04 OREQ *ON
C *IN05 OREQ *ON
C *IN06 OREQ *ON
C *IN62 OREQ *ON
C *IN63 OREQ *ON
C *IN64 OREQ *ON
C *IN65 OREQ *ON
C *IN66 OREQ *ON
C *IN67 OREQ *ON
C *IN68 OREQ *ON
C *IN69 OREQ *ON
C *IN70 OREQ *ON
C *IN71 OREQ *ON
C *IN72 OREQ *ON
C *IN73 OREQ *ON
C *IN74 OREQ *ON
C *IN75 OREQ *ON
C *IN76 OREQ *ON
C *IN77 OREQ *ON
C *IN78 OREQ *ON
C *IN79 OREQ *ON
C *IN80 OREQ *ON
C *IN81 OREQ *ON
C *IN82 OREQ *ON
C *IN83 OREQ *ON
C *IN84 OREQ *ON
C *IN85 OREQ *ON
C *IN86 OREQ *ON
C *IN87 OREQ *ON
C SETON 11
C ENDIF

Feo, extravagante y ridículo.

La imagen de este articulo es: Medusa obra maestra de MiguelAngel

Si te pareció interesante, reenvialo a un amigo haciendo click en el sobrecito que está al final del artículo. El conocimiento es valioso, compártelo.

Autor: Ing. Liliana Suárez

Monday, November 9, 2009

Occur para actualizar archivos

      

En el siguiente código de programación vemos el uso del Occur para actualizar un archivo. Puede apreciarse que ya no es necesario el uso de variables de trabajo utilizadas como campos en la pantalla para guardar los valores modificados por el usuario. 


     f*************************************************************
     f*************************************************************
     fArchivo   uf   e           k Disk
     FArchidsp  cf   e             WORKSTN
     d*************************************************************
     d* Variables, Estructuras, Arreglos                          *
     d*************************************************************
     dDSARCHIVO      E DS                  EXTNAME(ARCHIVO)
     d                                                        Occurs(2)
     dINDICE           s              1s 0
     c*************************************************************
     c* Rutina Principal                                          *
     c*************************************************************
     c
     c*
     c                   Eval      Indice  = 1
     C     Indice        occur     DSARCHIVO
     c     Clave      chain(n)  archivo
     c                   Exfmt     FMT1
     c*                  Exsr      validar
     c*
     c*                  if        okey
     c                   Eval      Indice = 2
     C     Indice        occur     DSARCHIVO
     c     Clave     chain     archivo
     c*
     c                   if        %found
     c                   Eval      Indice = 1
     C     Indice        occur     DSARCHIVO
     c                   update    rarchi
     c*                  endif
     c*
     c                   endif
     c
     c                   Seton                                        Lr



Si declaramos dos ocurrencias sobre una DS que está asociada a la descripción externa del archivo que queremos actualizar, se hace innecesario declarar tantas variables auxiliares como campos tiene el archivo.
Cuando nos posicionamos en el indice = 1, inicialamente cargamos, en esta ocurrencia, los valores del archivo. Luego  el usuario altera los campos de pantalla con los valores que desea modificar. Con este procedimiento podemos declarar los campos en pantalla con los mismos nombres que tienen los campos en el archivo.Como seguimos posicionados en el Indice = 1, los cambios son realizados sobre esta ocurrencia de la DS del archivo.  Antes de  hacer un segundo chain sobre el archivo, nos posicionamos en la segunda ocurrencia con Indice = 2, para que los valores  leídos del archivo se carguen sobre esta ocurrencia de la DS y no altere los cambios que el usuario realizó en pantalla. Finalmente antes de realizar el UPDATE, nos volvemos a posicionar en el Occur con indice = 1 a fin de  rescatar los valores que queremos grabar y  realizar los cambios que el usuario está solicitando.


Si te pareció interesante, reenvialo a un amigo haciendo click en el sobrecito que está al final del artículo. El conocimiento es valioso, compártelo.

Autor: Ing. Liliana Suárez

Thursday, November 5, 2009

Sql para eliminar registros duplicados
















Eliminar registros con clave duplicada de un archivo utilizando SQL.



DELETE FROM LIBRERIA1/ARCHIVO1 where RRN(F1) > (Select MIN(RRN(F2)) From LIBRERIA1/ARCHIVO1 F2 WHERE F2.CLAVE = F1.CLAVE)



Debe leerse el comando de derecha a izquierda como las escrituras árabes. En este caso comenzando con el Select.

Este comando trabaja con el Record Number (Número de registro físico) con el que trabaja el Iseries al grabar los registros en un archivo. La palabra clave es: RRN.

El comando selecciona el menor record Number entre registros del mismo archivo con claves coincidentes. F1 y F2 son artificios usados por Sql para identificar rapidamente un archivo de otro archivo. El resultado de un select es una tabla interna subconjunto del archivo original,  cuyos registros coinciden con F1 (que tambien es el archivo original)  pero seleccionando el  registro con menor Record Number. Seguidamente, el comando procede a eliminar (DELETE) del archivo original el registro duplicado con mayor Record Number.




Si te pareció interesante, reenvialo a un amigo haciendo click en el sobrecito que está al final del artículo. El conocimiento es valioso, compártelo.

Autor: Ing. Liliana Suárez

Wednesday, November 4, 2009

SQLRPG para Eliminar Registros de un Archivo















 Con el fin de optimizar nuestros programas y el tiempo de respuesta de nuestros procesos, vamos a publicar una series de tips y articulos relacionados con el SQL en sus distintas presentaciones, hoy comenzamos con algo sencillo enmarcado en el RPG como lenguaje anfitrion de SQL. Borramos los registros de un archivo que cumplen con una condición. En este ejemplo queremos eliminar los registros cuya fecha de proceso sea menor a una fecha enviada por parámetro al programa SQLRPG



Código SQLRPG

C *Entry PList
C Parm varfec 80 (variable numérica de 8 posiciones y cero decimales)
C*
C/Exec Sql
C+ DELETE FROM ARCHIVO
C+ WHERE FECPRO <= :VARFEC
C/end-Exec


Para archivos de más de 4000.000 de registros esta instrucción puede tardar hasta 10 minutos. Con un RPG que utiliza un Read y un IF dentro del lazo de lectura, el proceso tarda hasta 1 hora y 20 minutos. Para compilar este programa, debe colocarse *NONE en el parámetro que corresponde al control de compromiso COMMIT, si no hemos creado un Journal sobre el archivo. Crear un Journal sobre el archivo le da al sistema operativo la posibilidad de revertir en forma automática el borrado de los archivos en caso de que así se requiera. Si el programa no compila revisa si colocaste correctamente este parámetro.

Crear o no un Journal a los archivos queda a criterio a las normativas de la Gerencia de Sistemas.

A continuación el parámetro de compilación.

 Crear objeto RPG ILE SQL (CRTSQLRPGI)

Teclee elecciones, pulse Intro.
 Objeto . . . . . . . . . . . . . . . . . . . . PROGRAMA
 Nombre Biblioteca . . . . . . . . . . . .LIBRERIA Nombre, *CURLIB
 Archivo fuente . . . . . . . . . . . . . . QRPGLESRC Nombre, QRPGLESRC

 Biblioteca . . . . . . . . . . . . . . . .  . .LIBFTES Nombre, *LIBL, *CURLIB
 Miembro fuente . . . . . . . . . . . . . .PROGRAMA Nombre, *OBJ
 Control de compromiso . . . . . . . .*NONE *CHG, *ALL, *CS, *NONE...
 Base de datos relacional . . . .  . . . *LOCAL
 Tipo de compilación . . . . . .  . . . .*PGM *PGM, *SRVPGM, *MODULE
 Salida del listado . . . . . . . . . . . . . *NONE *NONE, *PRINT
Texto descriptivo . . . . . . . . . . . . *SRCMBRTXT

En el próximo articulos continuaremos optimizando los tiempos de respuesta de de programación con SQL.

Si te pareció interesante, reenvialo a un amigo haciendo click en el sobrecito que está al final del artículo. El conocimiento es valioso, compártelo.


Autor: Ing. Liliana Suárez

Thursday, October 29, 2009

Mejores Prácticas de Programacion RPG












Aunque nos suministren miles de herramientas en el Iseries para desarrollar mejores programas, tendemos a arrastrar viejos hábitos que aprendimos en RPG II y RPG III. Con la incorporación de RPG4 y de Ile-Rpg es fundamental desarrollar códigos "limpios" que a su vez reduzcan tiempos de respuesta en los procesos.

A manera de ejemplo, supongamos que tenemos tres analistas en una competencia. El reto es optimizar el siguiente código en RPG III. Lo dejamos en esta versión de RPG porque muchas veces es utilizado como excusa el hecho de no tener experiencia en RPG4, Free RPG o IleRpg para generar un código engorroso y con un tiempo de ejecución innecesariamente alto.


En un ejercicio de imaginación supongamos los siguientes Costos:
- Cada IF cuesta: un segundo.
- Encender o apagar un indicador: 1 segundo
- Cada Z-add cuesta dos segundos:
son dos instrucciones en una: primero mover cero y luego sumar.
-Cada comparación: 1 segundo
-Llamar a la rutina: 1 segundo

Tuesday, October 27, 2009

Trabajar con Fechas en RPG










Aunque es muy cómodo permanecer en el campo de lo conocido, es importante en el mundo de la tecnología incorporar herramientas, codigos y mecanismos mas actualizados para desarrollar programas. Todavía se encuentran programas que para validar fechas recurren a aquellos famosos arreglos contenidos al final del programa
donde se definía cual mes del año tiene 28,29 30 o 31 dias. Tambien vemos aquel famoso operador mvr utilizado para saber si un año es o no bisiesto. Con rpg 400 y rpg free, existen nuevas funciones proporcionadas por el sistema operativo que ahorran tiempo de programación y lo mas importante: tiempo de respuesta.
Por ejemplo para saber si una fecha es correcta o incorrecta puedes recurrir a la
función test. Declara previamente la fecha que quieres evaluar y si la fecha es erronea el sistema operativo te devuelve el valor de %error en true (verdadero).
Para evaluar Fecnac. (fecha de nacimiento)

d ds
d Fecnac 1 8 0
d Ano 1 4 0
d Mes 5 6 0
d dia 7 8 0


test(de) *iso Fecnac;
if %error;
enviar mensaje al usuario
endif;
………………………………………………………

En el siguiente ejemplo la función %diff nos da la diferencia de en dias
hemos declarado las fechas julianas pero pueden ser declaradas en formato
*iso u otro que resulte cómodo. En el manual de Rpg Reference pueden ver mas detalles
del formato de fechas

dfecha1 s d datfmt(*jul)
dfeccha2 s d datfmt(*jul)

dias = %diff(fecha1:fecha2:*days);

En la variable dias tenemos la diferencia en dias de ambas fechas,
si queremos la diferencia en meses colocamos en el tercer parámetro
de %diff *months
…………………………………………………

Por último, pero no menos importante, podemos realizar operaciones con fechas con las funciones subdur y adddur.

d fechahoy s d datfmt(*eur)
d fechapago s d datfmt(*eur)
d fechafinal s d datfmt(*eur)
d dias s 5 0

fechahoy subdur 3:*m fechafinal

fechahoy subdur fechapago dias :*d


En la primera instrucción restamos 3 meses a la fecha de hoy y obtenemos una fecha resultante.
En la segunda instrucciñon restamos dos fecha y obtenemos el resultado en terminos de dias.
La función Adddur es similar pero en lugar de restar suma los tiempos o fechas
que le indiquemos.

Estas funciones son muy importantes para el cálculo de fechas de vencimientos de pago, intereses, terminos de contratos, entregas de pedidos y miles de transacciones comerciales que se definen en costo y ganancia por el tiempo transcurrido. Ya no se hace necesario desarrollar un programa o diseñar un procedimiento que se encargue de devolvernos el resultado de la operación que requerimos ejecutar con las fechas.

Continuamente se realizan avances en el RPG es nuestro deber mantenernos actualizados.

Si te pareció interesante, reenvialo a un amigo haciendo click en el sobrecito que está al final del artículo. El conocimiento es valioso, compártelo.

Autor: Ing. Liliana Suárez

Sunday, October 25, 2009

No puedo ver el listado del Debug.











Cuando un programa falla y respondemos con ´D´ esperamos que se genere un listado
que nos facilite conseguir el origen del problema. Este listado puede generarse en el spool del usuario o en una cola de spool predeterminada por el sistema llamada QEZDEBUG. Sin embargo, puede suceder que buscamos el listado por todas partes y no lo conseguimos. El nivel de autoridad puede estar implicado en este problema. Para solucionarlo, colocas WRKSPLF y luego presionas SHIFT-F9. Seguidamente te aparece una pantalla que dice: Nivel de Autoridad. Colócalo en 2, pulsas Enter y al presionar F5 para hacer un refrescamiento de la pantalla del WRKSPLF verás el listado que estabas buscando

Si te pareció interesante, reenvialo a un amigo haciendo click en el sobrecito que está al final del artículo. El conocimiento es valioso, compártelo.


Autor: Ing. Liliana Suárez

Saturday, October 17, 2009

Frases Célebres

















“La prueba del software puede ser muy efectivo para mostrar la presencia de errores, pero absolutamente inadecuado para demostrar su ausencia”
Edsger Dijkstra

“Cuando se está depurando, el programador novato introduce código correctivo; el experto elimina el código defectuoso”
Richard Pattis

“Unas buenas especificaciones incrementará la productividad del programador mucho más de lo que puede hacerlo cualquier herramienta o técnica”
Milt Bryce

“Programar sin una arquitectura o diseño en mente es como explorar una gruta sólo con una linterna: no sabes dónde estás, dónde has estado ni hacia dónde vas”
Danny Thorpe

“Ley de Alzheimer de la programación: si lees un código que escribiste hace más de dos semanas es como si lo vieras por primera vez”
Via Dan Hurvitz

“Está bien investigar y resolver misteriosos asesinatos, pero no deberías necesitar hacerlo con el código. Simplemente deberías poder leerlo”
Steve McConnell

“En el mundo del software, los activos más importantes de la compañía se van a casa todas las noches. Si no se les trata bien, pueden no volver al día siguiente”
Peter Chang

Si te pareció interesante, reenvialo a un amigo haciendo click en el sobrecito que está al final del artículo. El conocimiento es valioso, compártelo.


Publicado por: Ing. Liliana Suárez

Thursday, October 15, 2009

Migración




El proceso de migracion de un sistema a otro o de una plataforma tecnológica hacia otra suele ser traumático.

En general la situación se complica cuando existen dos grupos separados que conocen lo que hay dentro de sus fronteras pero desconocen el territorio desde o hacia el cual hay que convertir la data.

Es importante una estrategia bien definida que sea aplicable a la situación en particular y es neceario no quedarse anclados en formulas pre-establecidas que no encajan con la situación particular que se está enfrentando.

En general hay tres estrategias para migrar datos.

1.-Convertir data comenzando por las tablas básicas del sistema e ir haciendo pruebas paralelas por submódulos y módulos.
Esto requiere, tiempo, recursos de personal adicionales y jornadas laborales extras no solo para el área de Sistemas sino para lo usuarios del la empresa.

2.-Convertir la data comenzando por la contabilidad. Es decir, ir en sentido inverso. Como todos los sistemas terminan en la contabilidad, comenzar realizando paralelos en el area de contabilidad e ir convirtiendo cada modulo progresivamente hasta llegar a las cargas iniciales de datos.

3.-Una combinación de las anteriores.


En particular prefiero comenzar con la segunda estrategia, porque el proceso de generar la contabilidad progresivamente e ir haciendo paralelos en este módulo en particular develará la necesidad de crear tablas intemerdias de conversión que nadie imaginaba que eran necesarias para poder contabilizar con el nuevo sistema.

En esta estrategia, se descubren manejos inesperados de data que no fueron considerados por los analistas en las fase iniciales de la planificación del proceso de migración.

Cada vez que un módulo contabiliza correctamente en el nuevo sistema puede irse "despegando" progresivamente del sistema viejo hasta el proceso final que integra todo el sistema nuevo y sus componentes.

El monitoreo constante de la situación es un mecanismo indispensable para girar la dirección del barco en la vía correcta e ir variando de estrategia en caso de que por alguna eventualidad inesperada sea necesario combinar ambas estrategias o aplicar una por encima de la otra. Lo importante es la flexibilidad y apegarse a la REALIDAD de lo que está sucediendo, dejando a un lado los academicismos rígidos que pueden entorpecer el desarrollo exitoso del proceso.


Si te pareció interesante, reenvialo a un amigo haciendo click en el sobrecito que está al final del artículo. El conocimiento es valioso, compártelo.


Autor:  Ing. Liliana Suárez

Sunday, September 6, 2009

CONTROL DE PROCESOS










Control de Procesos.

Un proceso tiene la misión de producir un resultado único, tangible, medible y distinguible del resultado que otro proceso pueda producir.

Los programas, módulo y sistemas que se alimentan o actualizan una determinada información y que conllevan a producir un impacto específico dentro de una secuencia de ejecución corresponden generalmente a un proceso que los engloba.

Es importante, para los analistas, establecer en un contexto mas general las relaciones de los programas módulos y sistema que han sido desarrollados en la empresa.

El Arquitecto de Procesos en una empresa tiene una gran responsabilidad puesto que debe determinar el alcance del proceso y los mecanismos de ejecución, reverso, backup,
Re-ejecución y contingencia que deben disponerse para cada proceso.

En un contexto de ISERIES si bien se ha desarrollado recientemente el concepto de módulos en ILE y de Procedures estáticos y dinámicos, esto no corresponde en ningún modo al concepto de PROCESO, corresponde a la importación desde otras plataformas, de lo que se llama programación modular. Esto le ha dado una nueva visión a la eficacia en el desarrollo de programas mas allá de la programación estructurada tradicional.

El proceso se define por la FUNCIONALIDAD es decir por el resultado que un conjunto de ejecutables producen basados en LOS PROCESOS DEL NEGOCIO.

En el contexto del ISERIES es, en general, difícil conseguir un control de procesos efectivo. Lo tradicional ha sido generar una serie de Backups en varias partes de los procesos para asegurar el reproceso en caso de caída del sistema, error de ejecución o falla operativa. Esto hace que el operador tenga que intervenir y en ocasiones tomar decisiones mas allá de su conocimiento y alcance de sus funciones.

Es necesario establecer archivos de control de procesos o mecanismos de control a través de áreas de datos (data-areas) que permitan al sistema automáticamente retomar el proceso donde había quedado si la intervención recurrente del operador. El monitoreos de errores tanto en los CLP como en el RPG, es un mecanismo muy efectivo que hay que aprovechar para tomar una decisión en forma automática y no solo para evitar a los ojos del usuario que se vea la falla de programación.


Podemos definir un archivo de control con los siguientes campos:

Nombre del proceso
Secuencia
Status actual
Ultima fecha de ejecución
Resultado de la ejecución (exitosa, incompleta, fallida)
Acción a tomar en caso de falla.
Siguiente secuencia o proceso a ejecutar en caso de falla.
Siguiente secuencia a ejecutar si todo okey.
Plan de contingencia operativo
Plan de contingencia procedimental.

Si construimos un CLP de procesos, a manera de ejemplo,

PGM

Verificar el status del PROCESO 1. (call programa rpg parm(siguiente etiqueta a ejecutar))



Goto etiqueta a ejecutar (Label 1, o Label 2 o la que corresponda, según lo que haya devuelto el progrma RPG)

Label 1 : PROCESO 1

Verificar el status del proceso 1. (call programa rpg parm(siguiente etiqueta a ejecutar))

Verificar el status del proceso 2. (call programa rpg parm(siguiente etiqueta a ejecutar))

Label 2: PROCESO 2

Verificar el status del proceso 2. (call programa rpg parm(siguiente etiqueta a ejecutar))





ENDPGM


Se verifican los status del proceso antes y después de ejecutarse porque no sabemos si se trata de un reproceso por una falla anterior. Esto nos permite saber si hay que re-ejecutar el proceso o si por el contrario la falla fue posterior y podemos saltarnos ese paso esta vez. En el registro de control de procesos, que es el archivo de control que presenté anteriormente debe residir la información veraz que permita establecer una acción correcta en forma automática.

Hay muchas maneras de establecer mecanismos de control. Lo importante es tener
Claro el alcance y la definición de los procesos y además los mecanismos automáticos y procedimentales que deben implementarse en caso de una situación imprevista.


Si te pareció interesante, reenvialo a un amigo haciendo click en el sobrecito que está al final del artículo. El conocimiento es valioso, compártelo.


Autor:  Ing. Liliana Suárez

Saturday, September 5, 2009

ARCHIVO DDM









Archivos DDM. (Data Distributed Management)


Un archivo DDM es un archivo que contiene información sobre otro archivo que reside en un servidor Iseries remoto. Esto es particularmente útil para traernos información desde el ISERIES de producción al ISERIES de Desarrollo o para traernos el fuente correcto a modificar o la data que necesitamos para hacer pruebas.

Por ejemplo, supongamos que queremos copiar data o un fuente desde un ISERIES hacia nuestro ISERIES.

Primero, definimos un DDM en el ISERIES donde estamos trabajando especificando en los parámetros del DDM, el nombre del sistema (SNA) y el nombre del archivo que se encuentra en el ISERIES remoto. (Esto si queremos copiar los archivo vía SNA. También puede crearse el DDM con la dirección IP del ISERIES remoto)

Una manera rápida para saber el nombre del sistema de un ISERIES es entrar en el ISERIES y hacer un DSPJOB en la línea de comandos de su sesión interactiva y en la parte superior derecha de la pantalla conseguirá un código que generalmente comienza con la letra ‘S’, por ejemplo: S1029093.
Una vez que tiene el nombre del sistema remoto aplicando el procedimiento descrito, (en el ISERIES remoto) proceda a realizar el siguiente comando:(en el ISERIES local)

CRTDDMF FILE(MILIBRERIA/DDM1)
RMTFILE(LIBRERIA/ARCHIVO)
RMTLOCNAME(‘S1029344’ *SNA)



MILIBRERIA se refiere a la librería donde estamos creando el DDM en nuestro ISERIES de trabajo. (local)
DDM1 puede ser cualquier nombre.
RMTFILE especifica la librería y el archivo que queremos traernos a nuestro equipo.
RMTLOCNAME: especifica el nombre del sistema remoto.

Podemos hacer un CPYF en nuestro ISERIES local para traernos la data desde el ISERIES remoto. Supongamos que queremos guardar el archivo remoto en nuestro ISERIES local en la Librería denominada: LDESTINO y que el objeto copiado se llame: OBJETOC

CPYF FROMFILE(MILIBRERIA/DDM1) TOFILE(LDESTINO/OBJETOC) MBROPT(*REPLACE)
CRTFILE(*YES)


De esta manera traemos a nuestro ISERIES data almacenada en El ISERIES remoto.

Podemos hacer CHGDDMF para cambiar la DDM y traernos otro archivo de otras librerías o incluso de otros ISERIES.

Podemos trabajar con la dirección IP como en este comando:

CRTDDMF FILE(LIBRERIA/DDM2)
RMTFILE(PAGOS)
RMTLOCNAME('9.5.36.17' *IP) PORT(5021)


El archivo remoto puede ser un archivo fuente como QCLSRC, QRPGSRC, o un archivo de data.

Para mayor información pueden remitirse al link de IBM:

http://publib.boulder.ibm.com/iseries/v5r2/ic2928/index.htm?info/cl/crtddmf.htm



Si te pareció interesante, reenvialo a un amigo haciendo click en el sobrecito que está al final del artículo. El conocimiento es valioso, compártelo.


Autor:  Ing. Liliana Suárez

Wednesday, August 19, 2009

Barra de Progreso




















No es usual encontrar en RPG algunas pantallas que den en forma de "Barra de progreso" el avance en la ejecución de un requerimiento solicitado por el usuario interactivamente.

Las Barras de Progreso son típicas de Windows y otras plataformas que muestran al usuario una barra horizontal seguida de un porcentaje que indica cuanto falta para que el software o el proceso que esta ejecutándose termine.
En la figura pueden ver la barra de progreso.

En RPG, si queremos hacer una barra de progreso, podemos declarar en la pantalla del SDA una variable alfabética por ejemplo de 50 posiciones. Llamemos a esta variable: GRAFICA. Es decir, declaramos GRAFICA A 50 En el programa RPG declaramos una variable llamada BARRA de 50 posiciones que la inicializamos con algún carácter de relleno, por ejemplo, asterisco (*).

Move '*' *all BARRA.

Si tenemos contabilizado el total de procesos que deben ejecutarse para que termine todo el proceso inicializamos la variable TOTAL con ese valor. Supongamos: move 1000 TOTAL. De manera que, se requiere que se ejecuten 1000 procesos para que la solicitud del usuario sea completada.

Si la barra de avance fue declarada de 50 posiciones y tenemos 1000 procesos hay dos preguntas básicas a responder:

1.- ¿Cómo reflejar el porcentaje de 1000 ejecuciones en una barra de avance de 50?

2.- ¿Cómo actualizar la barra de progreso en la pantalla a medida que más proceso se estén ejecutando?


Para responder estas preguntas, es necesario disponer de una variable que vaya acumulando los procesos ejecutados.
Iniciamos la variable con valor cero: Ejecutados = 0, e incrementamos su valor a medida que un proceso culmine.

Supongamos que han culminado 80 procesos. Queremos reflejar ese valor en la barra de progreso que esta en la pantalla. En nuestro ejemplo, es la variable llamada GRAFICA que es mostrada en la pantalla.

Cantidad de asteriscos que debe contener la barra de progreso en pantalla =
(EJECUTADOS/TOTAL) x 50

Sustituyendo los valores: (80/1000)* 50 = 4 asteriscos, lo guardamos en la variable ASTERISCOS (numérica sin decimales, el programador puede elegir aplicar redondeo en la operación si así lo desea)

Colocamos la siguiente instrucción: ASTERISCOS SUBST BARRA GRAFICA P

Esta instrucción extrae los primero 4 asteriscos de la variable BARRA y los coloca en la variable GRAFICA y rellena con blancos la parte que queda de la variable GRAFICA. Este relleno en blanco lo realiza colocando la letra P en la instrucción, (en la misma columna de la hoja C donde se especifica si hay redondeo de números en la operación aritmética.)

Colocando un lazo de ejecución hasta que el proceso termine y que en ese lazo ademas se incrementen adecuadamente los valores de las variables involucradas en cada iteración, queda actualizar la barra de progreso de acuerdo a las formulas presentadas, y el usuario tendrá una representación grafica en RPG del avance de su solicitud.


Si te pareció interesante, reenvialo a un amigo haciendo click en el sobrecito que está al final del artículo. El conocimiento es valioso, compártelo.


Autor:  Ing. Liliana Suárez

Friday, July 31, 2009

¿Cómo saber cual versión tengo?












¿Cómo puedo saber cual release (versión) tengo instalada en mi As/400?

1.-Coloca go licpgm.
2.-Selecciona la opción 10
2.-Pulsa F11 y verás la lista de programas del sistema operativo que tienes instalados en tu As/400 y las versiones de cada uno de ellos.



Si te pareció interesante, reenvialo a un amigo haciendo click en el sobrecito que está al final del artículo. El conocimiento es valioso, compártelo.


Autor:  Ing. Liliana Suárez

Uso de arreglos para actualizar campos de un archivo.










Es común encontrar archivos que contienen montos acumulados por mes y año cuando desea conservarse la historia de consumos de clientes, inventarios de productos o deudas y cuentas por pagar.

Generalmente los programas deben sumar las cantidades según el mes en cada campo del archivo esto produce una cantidad de instrucciones engorrosas para modificar los saldos según el mes o el periodo de tiempo que debe actualizarse.

Supongamos por ejemplo que tenemos el siguiente archivo:

A R RSALDOS
A SALDO1 15S 2
A SALDO2 15S 2
A SALDO3 15S 2
A SALDO4 15S 2
A SALDO5 15S 2
A SALDO6 15S 2
A SALDO7 15S 2
A SALDO8 15S 2
A SALDO9 15S 2
A SALDO10 15S 2
A SALDO11 15S 2
A SALDO12 15S 2


Los doce campos almacenan el saldo de cada mes del año.

Sunday, July 19, 2009

Mejorando los tiempos de procesamiento.










1.-Algunas sugerencias para mejorar el tiempo de respuesta en el uso del comando CPYF:

a.-No coloque claves al archivo físico. Utilice archivos lógicos para ese fin, las claves en los archivos físicos retrasan la copia y la recuperación de data.

b.-.Realice la copia del archivo desde el registro 1. Por omisión el comando CPYF coloca desde el registro *START, cuando coloca el registro 1, el sistema operativo es mucho mas rápido porque reproduce la misma secuencia de registros en el archivo destino.

c.- Si debe utilizar las opciones *map *drop, es mas rápido hacer la copia del archivo vía programa.

d.-El uso de SQL es mas efectivo para copiar de un archivo a otro.


2.-Usar el Reorganize para sus archivos.

Si los archivos no fueron creados con el atributo reuse delete = *yes, los registros eliminados quedaran como parte del archivo aunque no contengan data. Este almacenamiento extra innecesario ocasiona un mayor tiempo de respuesta en procesos de lectura y salvado. Periódicamente haga un RGZPFM para comprimir el espacio asignado al archivo.


3.-Crear sus archivos físicos con reuse delete = *yes hace innecesario un reorganize periódico para recuperar espacio.


4.-Aproveche el poder del SQL.

Por ejemplo si requiere eliminar masivamente información de un archivo según ciertos criterios, realice un programa SQLRPG o un programa QMQRY basado en commandos SQL. Esto es mucho más rápido que un programa RPG.


Si te pareció interesante, reenvialo a un amigo haciendo click en el sobrecito que está al final del artículo. El conocimiento es valioso, compártelo.


Autor:  Ing. Liliana Suárez

¿Qué es un Trigger?






Un trigger es un atributo de un archivo físico que permite al manejador de Base de datos del AS400 ejecutar un programa en el mismo instante que se haga algún cambio sobre ese archivo. El comando para agregar un trigger es: ADDPFTRG.

Podemos especificar que queremos que se ejecute un programa antes o después de añadir, eliminar o modificar un registro en el archivo físico sobre el cual estamos ejecutando el trigger. Este programa es desarrollado por nosotros como programadores del sistema.

El programa que se “dispara” al ejecutar una actualización del archivo debe ser especificado en el comando ADDPFTRG. Este programa debe recibir dos parámetros el primero de los cuales comprende el encabezado o “header” de la información que el manejador de base de datos devuelve sobre el cambio que se ha realizado sobre el archivo. El segundo parámetro contiene especificaciones mas detalladas sobre el cambio que se realizó en los campos del registro que fue alterado.

Cabe destacar que el Trigger no es un Journal. No devuelve trazas de auditoria que indique quien hizo el cambio ni que programa realizó el cambio, simplemente ejecuta el programa que le indicamos debe ejecutar.

A manera de prueba he declarado dos parametros de 5000 posiciones carácter cada uno y me han funcionado las pruebas de trigger.

Sin embargo, para detalles bien precisos sobre el contenido y las longitudes que nuestro programa debe tener para capturar la información del cambio de la base de datos pueden acceder a este link:

http://www.help400.es/asp/scripts/nwart.asp?Num=78&Pag=34&Tip=U


¿Para qué sirve un trigger?

Un trigger puede utilizarse por ejemplo para capturar data entre dos sistemas o módulos completamente distintos. Supongamos que tenemos un Sistema Autorizador de Tarjeta de Crédito que verifica el pin del cliente, su limite de crédito y que no esté bloqueada la tarjeta. El sistema autorizador puede aprobar el crédito y dejar un registro que sea parte de un archivo histórico de la solicitud de consumo recibida, sin embargo el sistema autorizador no tiene la capacidad de detectar un consumo “atípico” relacionado con el comportamiento del cliente que pueda detectar un fraude por usurpación de identidad o robo de tarjeta. Este proceso de detección de fraude le corresponde al Sistema de Monitoreo de Fraude. Si añadimos un trigger en el archivo histórico del autorizador y hacemos que este trigger disparé un programa que ingrese esta información de consumo en forma automática al Sistema de Monitoreo entonces la detección del fraude puede ser prácticamente inmediata y puede procederse preventivamente a un bloqueo de tarjeta para proteger al cliente y al banco de un proceso fraudulento.

El trigger puede ahorrarnos el hacer muchos programas que actualicen archivos de auditoria, y archivos para consulta en línea. Además para procesos nocturnos de largo tiempo de procesamiento el trigger es mas rápido que invocar varios programas que graben información sobre la actualización de la data u otra traza de auditoría que desee almacenarse.


Si te pareció interesante, reenvialo a un amigo haciendo click en el sobrecito que está al final del artículo. El conocimiento es valioso, compártelo.


Autor:  Ing. Liliana Suárez