Recomenzando !!!
Despues de varios meses ( o fueron años ) sin postear, he vuelto con renovadas energias y con mas de alguna idea loca para poder compartir con mis colegas desarrolladores, algunas vienen de la mano de como enfrentar el diseño o la forma de la solucion que quiero entregar, ya comenze con las tipicas preguntas de fondo, ¿ Sera mi interfaz lo suficientemente limpia ?, ¿ Es rapida de usar ?, ¿Entrega la informacion necesaria ? etc. etc. y otras cosillas mas. Todo con el menor esfuerzo (ja ja, lo dudo) y con codigo limpio (obvio ).. bueno a la espera de poder repostear en algunos dias mas.
Saludos.
De Clientes y Usuarios !!!
A ver… la pregunta que me hice fue sencilla pero trajo consigo una infinidad de respuestas que me preocupare de exponer aquí. ( Lo mas probable es que Uds. tengan otras varias mas… en fin.. aquí vamos… )
¿ Para quién desarrollamos ?
Para mis clientes .
¿ Quien es mi Cliente ?
Bueno la persona que me contrato, el Sr. Bill, dueño de la tienda “El mas Bill” que distribuye repuestos de automóvil para 3 ciudades de la región.
Bueno el solicito un software con ciertas características y con un aire particular que debía registrar las compras, las ventas, controlar una bodega y 3 locales, y que permitiera traspasar datos entre los locales. Hasta ahí vamos muy bien, incluso se “atrevió” a darme unos bocetos muy coloridos de las características que debía tener la pantalla de venta y otras mas,.
Con su permiso y las ideas claras de lo que el quería procedí a entrevistar a los encargados de los diferentes departamentos para ver sus necesidades y la forma en que los podía ayudar, que cosas harían mas rico al sistema y me permitiría entregarles algo para que usaran a diario y les ayudara a su quehacer. Hasta ahí todo bien, con mi análisis en la mano, un buen aplomo y la seguridad de haber realizado “ ..y tantos” sistemas y programas, me presente en su oficina para que viera la maqueta del sistema y las características de ingreso, interfase, el generador de reportes y me apreste de antemano a un visto bueno para seguir con la programación que debería durar unos 2 meses, con algunas pruebas incluidas.
Pero, horror de horrores, no le pareció que incluyera características pedidas por los usuarios y confirmadas por mi, por creer que entregaba muchas herramientas a los vendedores y a otros cargos en la empresa y que debía restringir mi diseño a lo solicitado y con solo “LA MITAD” de los datos que ya había modelado. Trate muy cuidadosamente de hacerle ver que eran características muy buenas, que permitían tales o cuales cosas, que el podría comprobarlas, vigilarlas, cotejarlas, evaluarlas, restringirlas a su modo y algo pude aclararle.. sin embargo su molestia empezó por hacerme ver que el había solicitado
“ALGO” y que yo le quería vender
“OTRA COSA”, que los usuarios no tenían derecho de pedir cosas, ya que ellos no pagaban y que si no le programaba lo solicitado , era mejor buscar otro desarrollador.
Mis años de experiencia y una habilidad de palabra de la que hice gala me permitieron ofrecerle 2 versiones, la que había solicitado y otra con lo que “yo” creía le serviría. En un mes tenia lista las 2, era solo cosa de poner flags y habilitar o deshabilitar ciertos campos y folders y una buena cantidad de IF’s … ja ja ja
Los usuarios agradecieron las características, el dueño consiguió enchufarse con el modelo del sistema y ya llevan varios meses con el.
Pero la problemática del inicio de mi gestión con el, me ha hecho considerar varias situaciones que se presentaron durante la puesta en marcha y la marcha blanca en si.
Las opiniones de los usuarios con respecto al sistema eran que el sistema era deficiente, simple y que no cumpliría con su función, muchos incluso dijeron que era un desperdicio de tiempo y dinero el desarrollarlo, que era mejor el de una empresa Internacional con asiento en Chile, una tal SoftLand ( ja ja ja )…
Pero cuando puse la versión completa empezaron los elogios y las palmaditas en la espalda. Si hubiera seguido con el desarrollo tal cual me lo pidió mi
CLIENTE, los
USUARIOS me habrían boicoteado el sistema. Si lo hacia para los
USUARIOS, mi
CLIENTE no me habría comprado el sistema. Buena la problemática.
Después de mucho cavilar por la situación he llegado a una conclusión, debo programar para los Usuarios, ellos al fin y al cabo harán de mi sistema un éxito o un fracaso, ellos serán al fin de cuentas quienes lo usaran constantemente y mis clientes estarán contentos con los resultados, un par de informes y características avanzadas de control, supervisión y auditoria, le harán ver que la información es buena, que mucha no sobra y que poca no sirve, que la información en manos de los usuarios es buena, son herramientas para su quehacer, que bien administrada es una potente arma en la lucha por conseguir y mantener clientes, que solo mis mas leales y cercanos tendrán acceso a “lo misterioso y prohibido”.. ja ja ja ( generalmente son los costos… ) y asi una infinidad de voladas mentales.
Y si mi cliente es mi usuario… a veces tenemos la suerte que es asi.. otras no …
Y si mi cliente es mi jefe, y mis usuarios son mis colegas….bueno.. ese es otro cuento.. pero ya prepararemos la historia del desarrollo dentro de la empresa… según este humilde desarrollador en xHarbour.. ja ja ja .. Hasta la proxima.
MED y un Mini IDE !!!
Dentro de los documentos que tenia estaba esta ayuda para configurar el editor de textos MED como un mini IDE que te permite realizar varios procesos, yo lo utilizo sin problemas con xHarbour ( Comercial) y el Workshop, y construyo con el xBuild Project Builder. Como tiene mucha imagen les dejo el link para que lo bajen y disfruten.
La ayuda la pueden bajar desde aqui
http://200.72.140.34/privado/MED.docEl editor lo pueden descargar desde aqui
http://www.pfersdorff.de/de/downloadwin.html;-)
Bloqueos de Datos en RED
Este Documento tiene algun tiempo, pero he decidido publicarlo ya que aun hay muchos que se estan iniciando en xBASE ( Harbour o xHarbour ) y estan aprendiendo a realizar sus primeras aplicaciones en red, espero les sirva.
Consideraciones para el bloqueo de Archivos de bases de datos en RED.
El uso de plataformas de red y Bases de Datos Relacionales (RDBMS) para las aplicaciones de administración y manejo de datos es cada vez mas común y esta al alcance de todo tipo de organizaciones, aun de negocios catalogados de pequeños, los recursos necesarios para implementar una red son cada vez menores y la tecnología para su levantamiento es fácil de encontrar y conocer.
Con esto en mente los desarrolladores de aplicaciones se ven enfrentados a la necesidad de poder diseñar bloqueos al acceso de los datos de acuerdo a la realidad que presenta el múltiple acceso que permite el Software de Red o la Base de Datos. Por otro lado tenemos los accesos por WEB que cada vez se hacen mas comunes y donde podemos consultar nuestros datos desde cualquier parte del mundo que tenga un acceso a Internet.
Si programamos desde nuestro querido Clipper o actualmente xHarbour hasta Administradores de bases de datos tan poderosos como Oracle, MS-Sql, MySql y otros, debemos diseñar nuestro sistema para que permita un manejo transparente al usuario y que sea capaz de representar la realidad del flujo de información que queremos controlar.
EL problema comienza cuando pensamos que nuestra aplicación estará siendo utilizada por al menos dos estaciones al mismo tiempo y que cada una de ellas accederá a nuestras bolsas de datos en forma concurrente. Es utópico pensar que en ningún momento se producirán cruces de solicitudes de datos y en mas de alguna oportunidad los datos no podrán estar disponibles para una estación al estar ocupados por otra.
Para entender el enfoque a utilizar al momento de diseñar el flujo de información que administrara nuestra aplicación debemos recordar las características de uso, bloqueo y permisos necesarios para acceder a bases de datos.
Si bien es cierto que utilizaremos para ello los archivos .dbf ( específicamente aquellos administrados por los lenguajes xBase ) podemos traspasar sus características y requerimientos sin problema alguno a otro administrador de bases de datos como MySql, ya que la tecnología de uso y bloqueo de archivos, tablas, índices u ordenes es común para ambos salvo las instrucciones y comandos propios de cada uno. La solución de diseño implementada para uno es la misma que utilizaremos en la otra, solo cambiara la forma de programarla y controlarla.
¿Porqué son importantes los bloqueos?
Un bloqueo permite, por ejemplo, que un usuario de una maquina X pueda acceder en forma directa a un dato y modificarlo sin que otros usuarios en maquinas distintas puedan utilizar dicho dato hasta que este halla sido finalmente liberado y escrito en el medio de almacenamiento del cual proviene. Con esto aseguramos la integridad y pertinencia de los datos almacenados.
Si estamos en el proceso “cambio_de_precios” , tenemos la posibilidad de bloquear los registros ( filas ) de productos para que mientras escribimos el nuevo monto ningún usuario pueda utilizarlo y así asegurarnos que los datos se grabarán con éxito.
Ciertos usuarios de la aplicación tendrán más derechos que otros al momento de acceder a nuestra fuente de información, no podemos negar la opción al Gerente de la empresa de modificar un precio a su antojo porque un vendedor esta visualizando un dato del producto ( un usuario de menor jerarquía ). De la misma forma el contador de la empresa no podrá en cierto momento acceder a los datos de stock de un determinado producto porque en ese mismo instante se esta generando una venta ( un proceso de mayor jerarquía ).
Un factor importante al momento de pensar en un bloqueo ( sea de bases de datos, tabla, registro ) es el tiempo en que este estará inaccesible para el resto de los usuarios, el bloqueo deberá ser lo mas rápido posible y deberá entregarnos las opciones necesarias en caso de fallar o de estar momentáneamente ocupado.
Tipos de Bloqueos
Uso EXCLUSIVO de archivo : El uso exclusivo de un archivo permite que solo un usuario pueda tener acceso total a él. Cuando nos referimos a acceso total, nos referimos a la posibilidad de leer, modificar, eliminar y guardar datos al interior del archivo. Es el método mas restrictivo que existe ya que solo permite a un único usuario acceder a un archivo y evita que otros puedan inclusive leer o visualizar su contenido. Este tipo de uso exclusivo era el predeterminado en los viejos tiempos de DOS, aun alejados de los NOS ( Network Operating Systems o Sistemas Operativos de Red y de la WEB).
Su ventaja principal ( si la consideramos ventaja ) es la simplicidad al momento del diseño y programación ya que nos entrega poder absoluto sobre el archivo y no debemos preocuparnos de un posible doble acceso al archivo o su contenido.
Su desventaja principal radica en que si utilizamos este enfoque en un ambiente de red, el primer usuario que tome control del archivo se convierte en su dueño absoluto hasta que lo grabe y deje de utilizarlo, permitiendo en este momento que otro usuario pueda accederlo y nuevamente se transforme en su único dueño.
Para acceder a un archivo .dbf en modo exclusivo desde xBase lo haríamos de la siguiente forma, agregando la cláusula EXCLUSIVE al comando USE
Select 1 //Seleccionamos el área de Trabajo
Use Clientes EXCLUSIVE // Agregamos la Cláusula de uso Exclusivo
Si no queremos especificar el modo de apertura del archivo cada vez que deseemos utilizar un .dbf podemos utilizar en comando SET EXCLUSIVE al inicio de nuestra aplicación y así asegurarnos que TODOS los archivos se abrirán en modo exclusivo
SET EXCLUSIVE ON
Para cambiar el modo de apertura desde algún punto de la aplicación en adelante solo utilizamos su variante…
SET EXCLUSIVE OFF
Su uso no es aconsejable al momento de programar nuestras aplicaciones ya que es demasiado restrictivo.
Es aconsejable abrir los archivos en modo compartido e intentar un bloqueo al archivo si es que realmente necesitamos control sobre el archivo. En ocasiones de un borrado de mas de un registro ( fila ), reordenamiento, reemplazo de mas de un registro, copia desde otra fuente de datos y algunas que Uds. estimen pertinentes.
Bloqueo de Archivo (Tabla) : La contraparte del uso exclusivo de un archivo es el uso compartido, este permite que mas de un usuario o aplicación puedan acceder a una fuente de datos, sin embargo el usuario que obtenga el bloqueo de archivo podrá hacer modificaciones sobre el mientras que los demás solo podrán acceder a visualizar su contenido. Aún así solo un usuario tiene control absoluto sobre el archivo.
Como habíamos mencionado, si se requiere modificar mas de un registro desde una .dbf o tabla esta opción es la mas permisiva al facilitar a los demás usuarios a lo menos la posibilidad de visualizar el contenido del archivo.
Personalmente no lo recomiendo pues creo que si se necesita modificar más de algún registro no es necesario un bloqueo de archivo, es preferible escribir una rutina que se llame las veces que sea necesario y utilice bloqueos individuales antes que bloquear el archivo completo.
Para los procesos de mantenimiento de las estructuras de datos , sean bases de datos, tablas, archivos .dbf, índices u ordenes es preferible hacerlo “Off Duty”, fuera de los periodos de utilización de los archivos y así asegurarse de tener control absoluto para esas tareas.
Bloqueo de Registro (fila) : Este nivel de bloqueo de datos es el mas flexible y el que mas utilizaremos.
Un bloqueo de registro es una solicitud a la red o al RDBMS de bloquear una porción del archivo en uso. Si esta porción del archivo esta disponible nuestro bloqueo es exitoso y el Sistema Operativo de Red actualiza su tabla de bloqueos para reflejar que esa porción de archivo esta siendo utilizada, de esa manera si alguien mas intenta bloquear ese registro el “S.O.R.” devuelve FALSO y no realiza el bloqueo.
Aquí necesitamos entender que si el bloqueo se mantiene en el tiempo, el registro no estará accesible para ningún usuario hasta que el “dueño” lo libere. Es muy importante desarrollar una estrategia para que el bloqueo sea lo mas corto y efectivo posible. Eso lo veremos con detalle mas adelante.
El bloqueo de registro devuelve verdadero o falso dependiendo de si esta disponible o no para ser bloqueado, sin embargo no nos entrega mayor información de quien, que proceso o que maquina esta haciendo uso de el. Una alternativa a esas preguntas es el uso de Bloqueos por Semáforos.
Boqueos por semáforos : Este tipo de bloqueo es muy eficiente pero es mas difícil de implementar.
Si nuestro Sistema Operativo de Red o RDBMS permite el uso de Semáforos tenemos mas de la mitad del trabajo realizado, dependerá de las características de semáforos que utilice y su implementación dependerá de la cantidad de documentación con la que contemos. Personalmente he indagado un poco en el uso de los disponibles en Netware y he logrado buenos resultados.
El bloqueo por semáforos es un signo, señal entre dos procesos, usuarios que les indica como y si pueden o no operar. Un semáforo de red es una etiqueta o un numero indeterminado de caracteres utilizados para comunicar información. Junto con la etiqueta, el semáforo posee un valor numérico. Las aplicaciones deben coincidir en el uso de los semáforos para lograr consistencia. Si el semáforo no existe se crea, si el semáforo esta siendo utilizado se le incrementa un digito en el valor asociado, de esa forma se conoce cuando un dispositivo, tabla, registro o dato esta siendo utilizado o no.
Su implementación es bastante mas compleja y existen condiciones inherentes a cada Sistema Operativo de Red que no podemos discutir en extenso en este pequeño documento pero si le invitamos a investigar.
Sistema de Bloqueos de Lenguajes Xbase
Utilizaremos al Compilador Clipper como modelo para explicar un diseño de bloqueos eficiente en nuestras aplicaciones. Su estructura es identica a la utilizada por Harbour y xHarbour. Primero entenderemos sus caracteristicas y luego iremos al detalle.
Clipper es rápido debido a sus características y opciones de manejo de buffer de datos, en una maquina sin conexión a red veremos que las aplicaciones corren mas rápidas que si estuvieran en un servidor de archivos. Esto es debido a que Clipper no solo carga en memoria los datos del registro actual en uso sino que carga una cierta cantidad de registros ubicados antes y después del actual, un paseo por una .dbf es rápido y puede verse como la lectura de nuestro disco duro es cada cierto tiempo y no en forma continua.
Cuando una .dbf es abierta en modo exclusivo, el comando USE establece un buffer en memoria y lee cuantos registros es posible y los carga es ese espacio asignado. Si por el contrario el archivo .dbf es abierto en modo compartido, utilizado en red, solo el registro actual es incluido en el buffer, he aquí la explicación de porque se reduce la performance en un ambiente de red.
Si por otro lado tenemos un índice abierto llenar un buffer con datos es innecesario ya que si nos movemos al siguiente registro en el orden asignado por el índice puede que físicamente se encuentre al final del archivo .dbf y no necesariamente al lado.
Por otro lado existen los buffer de .ntx/.cdx, cuando un comando SET INDEX TO es usado, este llena un buffer de tamaño variable en un espacio especial de memoria o en memoria expandida, entonces la única manera de asegurarse que los datos van directamente al disco duro es mediante el uso del comando COMMIT, este vacía los buffer, escribe en el disco duro, verifica si el buffer del índice corresponde a la imagen o no del archivo .dbf y lo reescribe.
El uso de COMMIT es aconsejado cada ves que se requiera, no hay problema en usarlo indiscriminadamente ya que un switch interno se utiliza para verificar si el COMMIT es realmente necesario o no.
El proceso que inicia el comando COMMIT se traduce en el vaciado de los buffer desde Clipper a DOS y luego a disco duro, en el caso de una estación no conectada a red es de la siguiente forma :
Buffer Clipper -> Buffer DOS -> ( Cache de Disco Duro ) -> Disco Duro
Si por el contrario esta estación esta utilizando la aplicación en modo multiusuario en una red cualquiera se traduce asi :
Buffer Clipper -> Buffer DOS -> SOR ->Servidor de Archivos -> Disco Duro
Hay que hacer notar que el Sistema Operativo de Red obliga a escribir al Servidor de Archivos pero este puede o no vaciar directamente al disco duro, dependerá de los niveles de cache del servidor, Servidor de Archivos y del tipo del equipo utilizado.
Un consejo :
Si un archivo .dbf es procesado en forma secuencial, de inicio a fin, se recomienda cerrar los índices ya que cada movimiento en el archivo requiere de un bloqueo del índice traduciéndose en una demora innecesaria, para ello solo activar el orden natural del archivo .dbf con SET ORDER TO 0.
Diseño de Bloqueos
Para un buen diseño de los bloqueos al interior de nuestra aplicación debemos considerar dos cosas.
1.- Persistencia al bloquear
2.- Como solucionar bloqueos fallidos
1.- Persistencia al bloquear. Nuestra función de bloqueo ( de archivo o registro ) debe permitirnos insistir en el bloqueo por el tiempo o numero de veces que le asignemos. El enfoque de “intentar bloqueo -- fallo -- desistir del bloqueo” no es aconsejable, lo ideal es entregar al usuario la posibilidad de intentarlo hasta que el lo desee o hasta que cierta cantidad de tiempo se halla cumplido
2.- Como solucionar bloqueos fallidos. Por otro lado debemos implementar la solución al manejo de los registros que se intentaron bloquear y que no fueron obtenidos en forma exclusiva, si se trata de un proceso que intenta modificar varios registros en una tabla, nos quedamos pegados en el primero que esta siendo ocupado por otro usuario, continuamos con el siguiente, que hacemos con el que no pudo actualizarse, cuando y como volvemos a intentar su bloqueo y actualización… Son buenas interrogantes que lo mas seguro tengan una respuesta si lo piensas un poco.
Así como cual será el manejo del bloqueo también es importante la forma en que se realizara la actualización del registro. Para ello existen dos formas de realizarlo.
Bloquear -> Leer Datos -> Modificar Datos -> Escribir datos -> Desbloquear
Aquí encontramos nuestro registro, leemos los datos que contiene y realizamos las modificaciones estipuladas, luego vaciamos los buffer y escribimos en el disco duro y finalmente desbloqueamos el registro para que este disponible.
El problema con este enfoque es que si el usuario logra bloquear y leer el registro, comienza a modificarlo y repentinamente surge un imprevisto, como un accidente, es llamado por el jefe, recibe una llamada telefónica importante o etc.. y deja el registro tomado en pantalla, nadie podrá acceder a el hasta que el vuelva.
La solución es crear una función que administre la cantidad de tiempo que el registro esta bloqueado, si excede los limites establecidos, que automáticamente vacíe los buffer y desbloquee el registro. Aquí es necesario modificar la funciones capturadoras de datos en pantalla ( en Clipper los GET ) para añadir esa opción de control de tiempo.
Personalmente y a pesar de haber escrito dicha función, no es el enfoque que utilizo, prefiero el siguiente…
Leer Datos -> Editar Datos -> Bloquear -> Escribir Datos -> Desbloquear
Aquí lo que realizamos es una lectura del dato, modificamos una “imagen” del registro, cuando la modificación este terminada, solicitamos el bloqueo, escribimos los datos y desbloqueamos. Es el mas rápido y efectivo, el registro solo esta bloqueado lo que dura la escritura a disco ( algunos milisegundos ) y podemos demorarnos lo suficiente durante la edición.
Sin embargo aquí surge otro problema mas, que pasa si otro usuario también requiere una modificación del registro. Imaginemos la situación…
Pedro necesita modificar el precio de venta de un producto y Maria por su lado necesita escribir la descripción técnica del mismo producto.
Pedro fue el primero en iniciar la labor que le corresponde, lee el registro, carga la imagen del registro en pantalla y empieza la modificación, es llamado desde gerencia en forma urgente y deja su trabajo a medio terminar…
Maria por su lado toma otra imagen del registro, la modifica, escribe el campo del detalle técnico, bloquea, graba y desbloquea el registro…
Pedro vuelve de su reunión, retoma la modificación del registro en pantalla, finaliza, bloquea, graba y desbloquea…..¿?
Aquí se ha perdido el trabajo de Maria, ya que los últimos datos que se grabaron fueron los de Pedro, el tenia una imagen del registro sin los datos del detalle técnico, como se demoro en realizar su labor y escribió sus modificaciones después de su compañera, lo que hizo fue borrar el trabajo de ella.
Fácilmente se le puede acusar ( a ella ) de no haber realizado su labor… un descuido en este tipo de situaciones que puede llevar a problemas de tipo laboral, en el extremo de la situación.
Cuando fui requerido del desarrollo de una aplicación de control de Stock y Modulo de Ventas pense largamente en como enfrentar la actualización de los stocks, listas de precio y el primer recurso a mi haber era que no había diseño previo ni preconcepciones de ningún tipo al momento de diseñar y modelar.
La solución practica a mi problema, que era el archivo que contenía los datos de los productos y sus múltiples accesos por diferentes instancias de la empresa, fue dividirlo en cuantas instancias fuera necesario según los distintos procesos que lo requerían.
Así un monstruoso archivo .dbf de mas de 50 campos que diseñe al inicio de mi labor quedo reducido a 5 archivos .dbf con caracteristicas muy especificas cada uno.
Producto.dbf //Codigos, descripción del producto
Stocks.dbf // Stocks de los diferentes locales
Precios.dbf // Lista de Precio de los Productos
Cierres.dbf // Información del movimiento del Producto
Tecnico.dbf // Detalle y descripción técnica de cada producto
Así cada proceso y usuario bloquea el registro, archivo que requiere en un momento y minimice los “choques” de bloqueos en gran medida, el ordenamiento del sistema es mas fácil de llevar, y aunque tengo mas archivos abiertos en ciertos procesos no he tenido ninguna perdida “bruja” de datos.
“Dividir para conquistar” en mi caso esta premisa resulto, sin embargo como expuse al inicio de este documento instructivo, la intención del mismo es entregar algunas consideraciones al momento de diseñar instancias de bloqueo de archivos y datos al planear aplicaciones que corren en red.
Pretender mas que eso es inútil ya que existen libros y libros de diseño de aplicaciones y cada lenguaje en particular tiene mas o menos características en cuanto al manejo de datos, buen capitulo para empezar es ver los bloqueos en el lenguaje que utilizas, las posibilidades que brinda tu Sistema Operativo de Red y una imagen clara del flujo de información al interior de la empresa, la utilización de jerarquías ( tanto de procesos como de usuarios )
Por otro lado la utilizacion de los RDBMS esta tan difundida y tan accesible que es muy dificil no imaginarse a los herederos de Clipper (Harbour y xHarbour) no poder administrarlos, para ellos existen cientos de manuales y documentos tecnicos especificos sobre el uso de los bloqueos en casi todos los RDBMS que yo conozco, Ms-Sql, Oracle, Sybase, PostGress, MySql, Interbase, etc. Cuento aparte lo es ADS y Apollo que son la misma estructura de los DBF nos entregan un sistema Cliente Servidor muy potente.
Espero que te sirva
Adolfo Lagos Jimenez
Empezamos !!!
Bueno, este es mi primer post en mi recien creado Blog. En unos dias mas espero tener los primeros posts y algunos comentarios. Por mientras buscare los links de interes que deseo sean permanentes en mi Blog...
Desde Chile un saludo a todos...