SIU-Toba Nivel inicial
Ing. Fernando Martínez Sistema de Información Universitaria Universitaria
[email protected] Septiembre 2014
¿Qué es Toba? •
•
Es un ambiente ambiente de de desarrollo Web, creado por el SIU con el objetivo de brindar una herramienta de desarrollo rápido, rápido, que posee una arquitectura basada en componentes para construir aplicaciones web transaccionales.. transaccionales Licencia software libre.
Ing. Fernando Martínez - SIU
2
¿Qué es Toba? •
•
Es un ambiente ambiente de de desarrollo Web, creado por el SIU con el objetivo de brindar una herramienta de desarrollo rápido, rápido, que posee una arquitectura basada en componentes para construir aplicaciones web transaccionales.. transaccionales Licencia software libre.
Ing. Fernando Martínez - SIU
2
Lo llamamos ambiente ambiente porque porque es una suite de distintas distintas utilidades: •
•
•
Un conjunto de librerías que librerías que son consumidas en ejecución. Un editor web destinado web destinado a la definición/configuración del proyecto, creación de operaciones y definición de sus comportamientos. Un conjunto de comandos de consola destinados consola destinados a administrar los proyectos creados con la herramienta. Ing. Fernando Martínez - SIU
3
Conceptos clave 1. 2. 3. 4.
INSTALACIÓN INSTANCIA PROYECTO PUNTO DE ACCESO
Ing. Fernando Martínez - SIU
4
1. Instalación •
•
Una instalación es una carpeta que contiene una versión de Toba. Una instalación puede correr una o más instancias de distintos proyectos.
Ing. Fernando Martínez - SIU
5
2. Instancia •
•
Una instancia es una abstracción que contiene los metadatos de un conjunto de proyectos. Físicamente es un esquema en la base de datos de Toba (por defecto llamado “desarrollo”).
Ing. Fernando Martínez - SIU
6
3. Proyecto •
•
Un proyecto en Toba se compone de archivos de código en PHP y definiciones en metadatos. Estos metadatos se almacenan temporalmente en la base de Toba, y se pueden volcar al sistema de archivos (al directorio “metadatos” del proyecto) mediante comandos de consola.
Ing. Fernando Martínez - SIU
7
4. Punto de acceso •
Durante la ejecución, el usuario ingresa la URL del proyecto en el navegador; allí se liga a una instalación, instancia y opciones específicas de ejecución.
Esta unión entre URL y entorno de ejecución es conocida como punto de acceso. Ing. Fernando Martínez - SIU
8
Flujo de trabajo 1
2 3
4 5
Ing. Fernando Martínez - SIU
9
Requisitos técnicos 1. Servidor web: Apache (2.2.x). 2. Lenguaje de programación: PHP (como módulo de Apache). 3. Servidor de base de datos: PostgreSQL. 4. Sistema de control de versiones: Subversion 5. Herramientas adicionales: Graphviz http://toba.siu.edu.ar/trac/toba/wiki/Instalacion Ing. Fernando Martínez - SIU
10
Configuración de PHP #Mínimos magic_quotes_gpc = Off magic_quotes_runtime = Off extension = php_pdo.dll extension = php_pdo_pgsql.dll extension = php_mbstring.dll • • • • •
#Recomendados error_reporting = E_ALL (*) display_errors = On (*) memory_limit = 128M post_max_size = 8 M upload_max_filesize = 8 M • • • • •
(*) #Solo para desarrollo Ing. Fernando Martínez - SIU
11
Instalación
•
•
•
En una consola en la ubicación c:\path_a_toba\bin, ejecutar instalar.bat y seguir las instrucciones. Al finalizar la instalación, no cerrar la ventana sin leer antes las instrucciones finales del instalador. Una vez completado, reiniciar Apache. Se recomienda mover el archivo entorno_toba_xx.bat de la carpeta de usuario a la de la instalación de Toba. Ing. Fernando Martínez - SIU
12
Distribución de carpetas - Toba •
•
•
•
•
bin: contiene los lanzadores de comandos de consola (ej: instalar , o el mas usado: toba). php: código fuente de Toba. proyectos: árbol de directorios de los
distintos proyectos. www : contiene archivos estáticos (imágenes, css, javascript, etc.) de Toba que son publicados en el servidor web. instalacion: contiene detalles de configuración de la instalación actual (alias, bases de datos, etc.). Ing. Fernando Martínez - SIU
13
Archivos de configuración •
Carpeta instalacion: localizada en el directorio raíz de Toba, contiene todas las configuraciones de la instalación, incluyendo la de las instancias contenidas. –
–
–
–
Qué instancias tiene definidas, determinado por carpetas i__nombre. Qué bases de datos se utilizan en la instalación por proyecto; se definen en el archivo bases.ini. Configuraciones varias, globales a toda la instalación, en el archivo instalacion.ini. Configuraciones para Apache: toba.conf Ing. Fernando Martínez - SIU
14
Creando un nuevo proyecto •
Ejecutar el comando: toba proyecto crear -p curso
•
•
•
Crea un sistema de archivos inicial, conteniendo metadatos básicos y los puntos de acceso por defecto. Carga en la instancia esos metadatos básicos. Se ejecuta una sola vez durante toda la historia del proyecto. Ing. Fernando Martínez - SIU
15
Distribución de carpetas – Proyecto •
id_proyecto php: carpeta que se incluye en el include_path de php, por lo que se recomienda usarlo para contener todas las clases particulares del proyecto. metadatos: directorio donde se almacenan los metadatos propios del proyecto, exportados mediante comandos. www : contiene el punto de acceso y los archivos estáticos publicados (imágenes, javascript, css), similares a los de Toba, pero propios del proyecto. –
–
–
Ing. Fernando Martínez - SIU
16
Editor Toba El editor de Toba cubre distintos aspectos de la implementación de una aplicación: –
–
–
–
Configuración global del proyecto. Creación y edición de operaciones. Definición de las distintas fuentes de datos, para conectarse transparentemente con las bases. Previsualización de la aplicación, con utilidades como edición contextual, visualización de logs, cronometrado de ejecución o consumo de memoria. Ing. Fernando Martínez - SIU
17
Primeros pasos en el editor Proyecto que se está editando
Edición de usuarios
Previsualización
Ayuda
Logger
Árbol de operaciones disponibles
Listado de componentes disponibles
Configuraciones de acceso a datos
Código PHP
Ing. Fernando Martínez - SIU
Configuración general del proyecto 18
Barra de desarrollo
Ing. Fernando Martínez - SIU
19
Barra de desarrollo
Ing. Fernando Martínez - SIU
20
Árbol de operaciones •
Si pensamos en la aplicación como un c atálogo de operaciones, a cada una de estas operaciones se la puede pensar como un ítem de este catálogo. Editar Nueva carpeta Nuevo componente hijo
Nuevo ítem Previsualizar operación
21
Ejemplos •
•
•
•
•
•
•
Creación de carpetas. Creación de un ítem – PHP plano. Previsualización. Visualización en el menú de la aplicación. Creación de un ítem – Esquema de componentes. Tipos de página. Reubicación de un ítem en el menú. Ing. Fernando Martínez - SIU
22
Base de negocio •
•
Los proyectos desarrollados en Toba contarán, casi con seguridad, al menos con una base de negocio. Al respecto, se puede: –
–
Instalar la base de negocio en la misma base que contiene la instancia Toba, en otro esquema de PostgreSQL… O bien definir una nueva base de datos, independiente de la Toba. Ing. Fernando Martínez SIU
23
Base de negocio
Ing. Fernando Martínez - SIU
24
Fuentes de datos •
•
•
Una fuente de datos encapsula un mecanismo de entrada/salida de datos, típicamente una base relacional. Un proyecto puede tener asociadas varias fuentes de datos, cada una representando una base distinta. Para administrar estas fuentes existe una sección en el Editor dentro de la sección “Datos”. Ing. Fernando Martínez - SIU
25
Fuentes de datos •
Allí se detalla cómo está formada: –
–
•
Identificador : es el nombre con el que esta fuente
puede ser referenciada desde Toba. Datos de conexión: motor, host, puerto, usuario, clave, base, encoding, esquema, etc.
Definiendo la fuente de datos en el editor, se genera o se actualiza la entrada correspondiente en el archivo bases.ini [instancia proyecto id_fuente] Ej: [desarrollo curso curso] Ing. Fernando Martínez - SIU
26
Fuente de datos •
Definiendo la fuente de datos en el editor, se genera una nueva entrada en el archivo bases.ini: [desarrollo motor = profile = puerto = usuario = clave = base = encoding = schema =
curso curso] postgres7 localhost 5432 postgres postgres curso_negocio LATIN1 public
Ing. Fernando Martínez - SIU
27
Fuente de Datos •
La fuente de datos nos permite acceder al objeto db, que cuenta con una API de consultas y comandos.
Ing. Fernando Martínez - SIU
28
Consultas y Comandos •
Consulta SQL: retorna un arreglo PHP asociativo. $sql = "SELECT id, nombre FROM tabla" $res = toba::db()->consultar($sql);
•
Ejecución de comandos dentro de una transacción: retorna la cantidad de registros afectados. $sql = "UPDATE tabla SET nombre = ‘toba’"; toba::db()->abrir_transaccion(); $cant = toba::db()->ejecutar($sql); ... toba::db()->cerrar_transaccion(); Ing. Fernando Martínez - SIU
29
Completando setup del proyecto 1. Crear el proyecto. 2. Configuración de parámetros de previsualización desde el editor. 3. Crear la base de datos (negocio). 4. Definir la fuente de datos. 5. Copiar la clase con las consultas SQL. 6. Crear un objeto “Consulta PHP” desde el Editor, vinculándola con el archivo copiado en el punto 5. Ing. Fernando Martínez - SIU
30
Creación de un ABM simple •
•
Una operación se determina en base a componentes, definidos mediante el editor. Estos cubren distintos aspectos de implementación de una operación, y se categorizan según su función: –
–
–
Control Interfaz Persistencia.
Ing. Fernando Martínez - SIU
31
Componentes •
El comportamiento de un componente se basa en: –
–
su definición (con el editor) su extensión en código PHP. Se da a través de la herencia, creando una subclase del componente en cuestión y asociándola al mismo desde el editor. La extensión no siempre es obligatoria.
Ing. Fernando Martínez - SIU
32
Extensión de componentes •
Se podrían definir tres objetivos distintos a la hora de hacer una extensión de un componente: –
Atender eventos: El componente notifica sucesos y en la extensión se “escuchan”.
–
–
Redefinir métodos propios del componente (por ejemplo, la salida HTML). Extender el componente en Javascript: Cada componente en PHP tiene su par en Javascript, por lo que en la extensión también es posible variar el comportamiento del componente en el lado cliente. Ing. Fernando Martínez - SIU
33
Controlador de Interfaz (CI) •
Es un componente de control, responsable de manejar: –
–
las pantallas elementos de interfaz contenidos, por ejemplo: •
•
•
•
•
Cuadros Filtros Formularios Formularios multilínea Etc…
Ing. Fernando Martínez - SIU
34
Pantallas •
•
La pantalla es la parte gráfica de una etapa del CI. Se encarga de graficar: –
–
–
Un conjunto de dependencias (componentes del CI asociadas a la pantalla actual). Un conjunto de tabs, que vinculan con otras pantallas (dependiendo del tipo de navegación). Un conjunto de eventos (en forma de botones).
Ing. Fernando Martínez - SIU
35
Pantallas •
Tipos de navegación: –
Definido por la subclase (CI) $this->set_pantalla('id_pantalla');
–
–
–
•
Tab horizontal Tab vertical Wizzard
Desde el CI, podemos acceder a las pantallas y sus funciones: $this->pantalla('id_pantalla')->... Ing. Fernando Martínez - SIU
36
Eventos •
•
En un ambiente web, la comunicación entre cliente y servidor no es continua, sino desconectada. El usuario trabaja en su browser modificando la información que se visualiza en la página actual, y cuando decide ir al servidor (ej. “Guardar”) todos los componentes de esa
pantalla notifican los distintos sucesos que acontecieron durante su estadía en el cliente. Ing. Fernando Martínez - SIU
37
Eventos •
•
Un evento representa la interacción del usuario (“El usuario presiona Guardar” ) a través de un componente de interfaz (botón). Sirve como medio de comunicación del cliente con el servidor, llevando los parámetros particulares del suceso.
Ing. Fernando Martínez - SIU
38
Eventos •
Un evento debe “escucharse” y atenderse en el
•
servidor. El Controlador de Interfaz (CI) está preparado para “escuchar” eventos (propios o de
componentes contenidos) y configurarlos, definiendo así el comportamiento de las operaciones.
Ing. Fernando Martínez - SIU
39
Listeners •
•
•
Escuchar un evento consiste en definir un método (listener) en el CI contenedor del componente. Este método será invocado junto con parámetros de contexto del evento. Cuando el evento pertenece al mismo CI, el listener se define de la siguiente manera: –
–
Prefijo evt__ (doble guión bajo) Nombre del evento. function evt__guardar () { … }
•
En caso de que este método no esté definido, el evento queda sin atrapar. Ing. Fernando Martínez - SIU
40
Cuadro •
•
Un ei_cuadro es un elemento de interfaz, que consiste en una grilla de registros pensados para visualización de información. Es común que cada uno de estos registros tenga identidad propia, por lo que el cuadro permite seleccionarlos individualmente a través de eventos a nivel fila.
Ing. Fernando Martínez - SIU
41
Listener de eventos de componentes •
El nombre de un listener de un componente se define de la siguiente manera en el CI controlador del componente: –
–
–
Prefijo evt__ (doble guión bajo) ID del objeto origen con el sufijo __ Nombre del evento.
function evt__cuadro__seleccion($seleccion) { …
} Ing. Fernando Martínez - SIU
42
Formulario •
•
Un ei_formulario es un elemento de interfaz que presenta una grilla de campos editables. A estos campos se los denominan Elementos de Formulario (efs).
Ing. Fernando Martínez - SIU
43
Elementos de Formulario (efs)
El usuario selecciona un elemento ef_checkbox ef_combo ef_radio
ef_popup
Ing. Fernando Martínez - SIU
44
Elementos de Formulario (efs)
El usuario selecciona varios elementos ef_multi_seleccion_lista ef_multi_seleccion_doble
ef_multi_seleccion_check
Ing. Fernando Martínez - SIU
45
Elementos de Formulario (efs)
El usuario edita ef_editable ef_editable_numero ef_editable_fecha ef_editable_textarea
ef_cuit
Otras acciones ef_upload ef_fijo
Ing. Fernando Martínez - SIU
46
Formulario •
•
Durante la configuración se lo carga con un conjunto de datos. Cuando vuelve al servidor informa a través de sus eventos el nuevo conjunto de datos editado por el usuario.
Ing. Fernando Martínez - SIU
47
Persistencia •
•
Los cambios efectuados durante una operación se deben transaccionar con una fuente de datos. Existen dos formas principales en que puede transaccionar una operación: –
–
Inmediatamente producidos los eventos, prácticamente en cada pedido de página. Luego de una confirmación explícita del usuario, por ejemplo, presionando un botón “Guardar”. Ing. Fernando Martínez - SIU
48
Transacción inmediata •
•
Es la forma más fácil y directa de programar una operación. En cada método que escucha un evento se ejecuta un comando SQL function evt__form__modificacion($datos) { $sql = "INSERT INTO ... "; toba::db()->ejecutar($sql); } Ing. Fernando Martínez - SIU
49
Transacción a nivel operación •
•
Transaccionando inmediatamente, si el usuario decide dejar la edición por la mitad, lo editado puede quedar en un estado inconsistente. Muchas veces es un requisito funcional que la edición se maneje como una única transacción, que se cierra con una acción explícita del usuario (Ej: presiona “Guardar”).
Ing. Fernando Martínez - SIU
50
Transacción a nivel operación •
Los componentes de persistencia brindan tres servicios a la aplicación: –
–
–
Cargar un conjunto de datos relacionados. Mantener en memoria los cambios realizados por el usuario a estos datos. Finalmente sincronizarlos con el medio de persistencia cuando sea solicitado.
Ing. Fernando Martínez - SIU
51
Datos Tabla (DT) •
Un datos_tabla es un componente de persistencia, que mantiene una estructura tabular (RecordSet) y brinda una interfaz para trabajar con ella.
Ing. Fernando Martínez - SIU
52
Datos Tabla 1. Carga los datos desde un medio de persistencia. –
Carga sin condiciones:
// … En el controlador del datos_tabla … $this->dep (‘dt_personas ’)->cargar(); –
Carga con condiciones:
$cond = array (‘persona’ => ‘10’); $this->dep (‘dt_personas ’)->cargar($cond);
Ing. Fernando Martínez - SIU
53
Datos Tabla 2. Una vez que tenemos los datos en memoria, existen primitivas para trabajar sobre estos.
get_fila($clave) nueva_fila($registro) modificar_fila($clave, $registro) eliminar_fila($clave) –
Cuando una tabla en la transacción puede tener a lo sumo un registro se simplifica la interfaz:
set($datos) get()
Ing. Fernando Martínez - SIU
54
Datos Tabla 3. Los datos y sus modificaciones son mantenidos automáticamente en sesión entre los distintos pedidos de página. Las modificaciones se retienen hasta el final de la transacción de negocios. 4. Una vez terminada la edición se efectúa la sincronización con la base de datos, a través del administrador de persistencia, marcando el final de la transacción de negocios.
$this->dep (‘dt_personas ’)->sincronizar();
Ing. Fernando Martínez - SIU
55
Mensajes y notificaciones 1. toba::notificacion()->agregar('Mensaje de ERROR'); 2. toba::notificacion()->agregar('Otra forma de mostrar un mensaje de ERROR', 'error'); 3. toba::notificacion()->agregar('Mensaje de ADVERTENCIA', 'warning'); 4. toba::notificacion()->agregar('Mensaje de INFORMACIÓN', 'info');
Ing. Fernando Martínez - SIU
56
Extensión JavaScript •
•
Todos los elementos de interfaz tienen asociado un objeto en JavaScript, encargado del comportamiento del componente en el cliente. La responsabilidad de estos objetos es manejar todo aspecto de la pantalla que no puede ser determinado estáticamente.
Ing. Fernando Martínez - SIU
57
Extensión JavaScript •
¿Cuándo realizar extensión JS? –
Validaciones en el lado cliente.
–
Comportamiento dinámico de EFs. Por ejemplo si un
combo necesita deshabilitarse en base al tilde de un checkbox. Es un comportamiento dinámico de pantalla en el cliente, ya que el servidor no puede introducir lógica de este tipo. •
¿Cuándo NO realizar extensión JS? –
Cuando la lógica de pantalla es estática al pedido actual . Por ejemplo, si en un ABM es necesario
deshabilitar un EF en la edición. Ing. Fernando Martínez - SIU
58
Extensión JavaScript •
•
Todo código JavaScript necesita ser parte de la salida PHP. Este concepto puede traer a confusión, ya que el código JavaScript necesita ser definido en PHP… pero lo mismo sucede con la salida
•
HTML!!! Para esto, primero se necesita tener una subclase en PHP del componente; allí se encuentra una ventana de extensión JavaScript: el método extender_objeto_js Ing. Fernando Martínez - SIU
59
Extensión JavaScript •
extender_objeto_js():
class ci_X extends toba_ci { function extender_objeto_js() { echo “
{$this->objeto_js}.evt__guardar = function() { return prompt(\"Desea Guardar?\"); }
”;
}
}
Ing. Fernando Martínez - SIU
60
Creación de un ABM complejo •
Propuesta: extender el ABM simple para permitir dar de alta personas y cargar una lista de allegados en una sola operación.
Ing. Fernando Martínez - SIU
61
Creación de un ABM Complejo
Ing. Fernando Martínez - SIU
62
Controlador de Negocio (CN) •
•
Los controladores de negocio son una herramienta útil para desacoplar la lógica de negocio de la presentación. Permite unificar la carga y entrega de datos y servicios a una jerarquía completa de componentes de interfaz (generalmente los CIs). // Ejemplo $this->cn()->get_datos(); Ing. Fernando Martínez - SIU
63
Controlador de Negocio (CN) •
Ventajas: –
–
•
Lograr una máxima independencia entre la lógica de pantalla y de negocio. Tener un lugar centralizado para brindar servicios comunes a una jerarquía de componentes.
Desventajas: –
Esta flexibilidad se consigue a expensas de una mayor burocracia y complejidad en el manejo de datos. Ing. Fernando Martínez - SIU
64
Datos Relación mdp_personas
persona
apellido nombres …
mdp_personas_allegados dato_allegado
persona tipo_allegado …
Un datos_relacion mantiene un conjunto relacionado de datos_tabla. datos_tabla. Brinda servicios para cargar y sincronizar este modelo de relación con algún medio de persistencia.
Ing. Fernando Martínez SIU
65
Datos Relación •
Carga –
–
La forma más común de cargar una relación es a partir de una restricción de las tablas raíces (aquellas que no tienen padres). Para esto se utiliza el método cargar: cargar:
$relacion->cargar(array('id' => 8));
Ing. Fernando Martínez - SIU
66
Datos Relación •
Trabajo en memoria –
–
El trabajo posterior a la carga generalmente se realiza realiza a través través de las tablas relacionadas. Para Para acceder a un componente tabla: $relacion->tabla('id_tabla')- >…
–
La principal diferencia radica radica en que las operaciones sobre las tablas ya no son aisladas, sino que trabajan en el contexto de la relación. Ing. Fernando Martínez - SIU
67
Datos Relación •
Sincronización –
La sincronización con el medio de persistencia: $relacion->sincronizar();
–
–
Sincroniza de manera transaccional y ordenada las tablas de la relación, comenzando por la cabecera y siguiendo por las tablas hijas. Si se trata de un alta, el ID de la tabla padre es serial y mediante ese campo se vincula con las tablas hijas, el ID se obtiene al sincronizar la tabla cabecera, y se utiliza ese valor para completar en las dependientes. Ing. Fernando Martínez - SIU
68
Formulario Multilínea •
Un ei_formulario_ml presenta una grilla de campos repetidos una cantidad dada de filas.
Ing. Fernando Martínez - SIU
69
Formulario Multilínea •
•
•
Permiten recrear la carga de distintos registros con la misma estructura. La definición y uso de la grilla de campos es similar al formulario simple, con el agregado de lógica para manejar un número arbitrario de filas. Se pueden agregar nuevas filas, y eliminar o modificar las existentes. Ing. Fernando Martínez - SIU
70
Formulario Multilínea •
•
Brinda un servicio que permite analizar lo acontecido con las filas enviadas al cliente. Si por ejemplo… se envían tres filas al cliente se modifican dos la otra se borra se agrega una nueva –
–
–
–
el método de análisis evita que el programador tenga que comparar el estado de las filas enviadas con el recibido. Ing. Fernando Martínez - SIU
71
Construcción de un reporte
Ing. Fernando Martínez - SIU
72
Filtro •
•
Un ei_filtro es un componente de interfaz que presenta una grilla donde es posible seleccionar criterios de búsqueda para las distintas columnas definidas. Según el tipo de columna (número, fecha, opciones…) se despliegan distintas condiciones de comparación (“es igual a”, “es mayor a”…).
•
El usuario indica un valor a comparar usando un elemento de formulario (ef). Ing. Fernando Martínez - SIU
73
Filtro •
Combinando: –
–
–
la condición seleccionada el valor ingresado por el usuario una expresión SQL para el campo definida con el editor
es posible obtener del filtro una expresión SQL para integrar en la cláusula WHERE de la consulta que obtiene los datos: // En el CI controlador del filtro $where = $this->dep('filtro')->get_sql_where(); Ing. Fernando Martínez - SIU
74
Propiedades en sesión •
•
•
A veces es necesario que el CI pueda recordar la información que va recolectando entre pedidos de página. Esto se logra gracias a las llamadas variables de sesión. La forma de indicar al framework que una propiedad sea mantenida en sesión es prefijando su nombre con s__ protected $s__seleccion; Ing. Fernando Martínez - SIU
75
Metadatos •
•
•
Cuando utilizamos el editor web de Toba, estamos definiendo un proyecto en base a metadatos, almacenados en una base de datos definida durante la instalación. Mientras estos metadatos no sean exportados al sistema de archivos, no podrán ser compartidos con un grupo de desarrollo, ni el proyecto podrá ser pasado a producción. Esta necesidad de importar - exportar metadatos se cubre usando comandos de consola. Ing. Fernando Martínez - SIU
76
Metadatos •
toba proyecto exportar Vuelca los metadatos del proyecto al sistema de archivos, y por seguridad exporta también información local de la instancia (usuarios, logs, etc.) que no forman parte de ningún proyecto en particular. toba proyecto regenerar Realiza la acción inversa a exportar: carga en la instancia (BD) los metadatos existentes en el sistema de archivos. Regenera únicamente los metadatos del proyecto, dejando intacta el resto de la instancia. –
•
–
–
Ing. Fernando Martínez - SIU
77
Metadatos
Ing. Fernando Martínez - SIU
78