Boletín Pascal #13
Los ejemplos completos de código fuente de este número están disponibles para descargar.
![]() |
![]() |
Boletín Pascal #13 - 24-DEC-2000 INDICE 1. UNAS PALABRAS DEL EDITOR 2. FORMAS NO RECTANGULARES - Parte I 3. APLICACIONES OPENGL CON DELPHI 5.0 - PRIMEROS PASOS 4. ABRIENDO UNA BASE DE DATOS DE MICROSOFT ACCESS (.MDB) CON DELPHI - ADO - BDE - BDE + ODBC 5. LISTANDO LAS TABLAS Y CONSULTAS EN UNA BASE DE DATOS 6. ENLACES ________________________________________________________________________ 1. UNAS PALABRAS DEL EDITOR En este número Alirio Gavidia nos mostrará con dos ejemplos cuán fácil es hacer formularios no rectangulares. Leopold Minikus, de Minais - Individual Cad Software, nos presenta su juego de componentes OpenGL para ayudarlo a construir aplicaciones 3D con Delphi 5. Puede descargar gratuitamente la colección de componentes MNOgl del sitio de minais: http://www.minais.at El archivo viene con proyectos de ejemplo (incluyendo el que se describe en el artículo). Si necesita ayuda o tiene preguntas acerca de los artículos presentados en este boletín, puede enviarlas a nuestro foro/lista de correo. Sus problemas y dudas pueden ser los problemas y dudas de otros miembros del foro que también se beneficiarán de leer las preguntas y respuestas. Para suscribirse, simplemente envíe un email en blanco a: delphi-intermedio-subscribe@gruposyahoo.com Este foro / lista de correo es un servicio gratuito provisto por Yahoo! Grupos ( http://espanol.groups.yahoo.com ) y no hacen "spam", aunque incluyen una pequeña publicidad en cada mensaje (de la cual aclaro que yo veo ni un centavo). Si desea más información, por favor visite: http://www.latiumsoftware.com/es/forums.html Saludos, Ernesto De Spirito eds2004 @ latiumsoftware.com ________________________________________________________________________ JfControls Lib. Multilenguaje. Multiapariencia. Skins. Privilegios. Más de 40 componentes integrados y personalizables. Múltiples problemas de programación resueltos. Administración centralizada de recursos. Para Delphi 3-7 y C++ Builder 3-6. http://www.jfactivesoft.com/spindex.htm ________________________________________________________________________ 2. FORMAS NO RECTANGULARES - Parte I Copyright (c) 2000 Alirio Gavidia <alirio@gavidia.org> Para ver más de mis artículos visite: Programación Orientada en Delphi http://www.gavidia.org/pod/ Introducción. ============= El presente ensayo pretende demostrar las posibilidades de usos de las formas no rectangulares bajo Windows. El uso es simple pero las posibilidades parecen ser interesantes. Adicionalmente, en particular en esta primera parte, se hará uso de dos elementos importantes: "Canvas" (lienzo) y "Timer" (temporizador). El primer ejemplo. ================== En el artículo anterior (ver "POST-IT". VENTANAS AJUSTABLES SIN BORDE NI TITULO en http://www.latiumsoftware.com/es/pascal/0010.php ) hice referencia a la posibilidad de crear un reloj analógico redondo como lo hace el "PowerToys" de Windows. Hacer un formulario redondo es simple y se limita a llamar a dos procedimientos. El reloj debe además dibujar agujas (lo que requiere cierto cálculo matemático) y actualizarse unas 60 veces por minuto (para ello el "TTimer"). Nota: Reloj Analógico por contraposición a Digital. El término NO es correcto porque el reloj que aquí creamos aún cuando tenga agujas es digital. Para que el reloj imitara un comportamiento realmente analógico tendría que tener un movimiento continuo, el que aquí creamos se mueve de segundo en segundo por lo que tiene un número de estados definidos y finitos eso lo califica de digital. Parece ser que el término más adecuado es "reloj de agujas". Sin título. =========== El reloj se basa en un formulario simple sin borde; con ello se elimina la barra de título, que resulta en un estorbo al tener un formulario redondo. Este genera adicionalmente el problema de traslado del formulario. Por este motivo la operación de arrastre debe ser atendida desde el área cliente del formulario. Para resolver este inconveniente hay varios métodos. Opto por el aplicado en el artículo anterior (uso del wm_Syscommand $f012): procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin ReleaseCapture; Perform(wm_Syscommand, $f012, 0) end; Otra técnica es responder al "Wm_NcHitTest" y retornar como resultado "htCaption". Esto simplemente es comunicarle a Windows que se hizo clic sobre el área de título. Me parece que hay al menos otra técnica más pero no es objetivo de este ensayo. El "timer". =========== En el formulario se incluye un control "TTimer". Este control dispara un evento de manera aproximada cada cierto intervalo (por la propiedad "interval" dada en milisegundos). Esta bien documentado su uso en Delphi, pero debo agregar algo: no es exacto. El evento asociado al timer ejecuta tres acciones: eliminar agujas de posición anterior, tomar la hora del sistema y colocar agujas en una nueva posición. El "Canvas". ============ El "Canvas" provee capacidades gráficas para controles gráficos y formularios. Brinda posibilidades para dibujar líneas, elipses, polígonos, textos y otros. Su manejo es simple y práctico. Hacemos uso de los siguientes elementos del "Canvas": * "Pen", para establecer color y modo de trazado de línea. * "MoveTo", para establecer el punto inicial de trazado de una línea. * "LineTo", para trazar una línea desde la última posición a la nueva. * "Rectangle", para trazar un rectángulo según los parámetros especificados. Es de notar particularmente la propiedad "Canvas.Pen.Mode" que nos permite utilizar valores como "pmXor" o "pmCopy" (entre muchos otros). Nota: El uso del "Xor" como operador lógico tiene una propiedad interesante y es que aplicada dos veces se obtiene el valor original, esto es: "x xor y" resulta en "z" si a "z" se le aplica "xor y" nuevamente resulta en "x". Esto es muy útil para cifrados simples donde queremos aplicar una clave para cifrar y la misma clave y el mismo algoritmo para descifrar. También es muy útil para casos donde queremos dibujar algo y luego borrarlo porque para borrarlo sólo se requiere volver a dibujar aplicando "xor" entre el fondo y el pixel a dibujar. El evento "Paint" del formulario ciertamente hace uso de la propiedad "Mode" y "Color" de la plumilla obteniendo un curioso efecto. El resultado, al menos para mi, no fue el esperado, sin embargo fue agradable. Todo ello parece ser consecuencia de la manera en que se crea un rectángulo, el mismo es rellenado y luego se trazan los bordes superior e izquierdo, que bajo el operador "Xor" generan un color blanco, la imagen resultante genera un efecto 3D. Sugiero al lector comentar las lineas de "Mode" y "Color" para obtener sus propias conclusiones. Como comentario adicional "Pen.Color" sólo afecta al borde del rectángulo. El relleno es definido por la propiedad "Brush" del "Canvas" la cual, en este caso, permanece con su valor por defecto. procedure TForm1.FormPaint(Sender: TObject); Var X1, Y1, i : integer; Angle : double; begin Canvas.Pen.Mode := pmXor; Canvas.Pen.Color := clBtnFace; for i:=1 to 12 do begin Angle := i * 2 * Pi / 12; X1 := trunc(X0 + Len * Sin(Angle)); Y1 := trunc(Y0 - Len * Cos(Angle)); Canvas.Rectangle(X1-4,Y1-4,X1+4,Y1+4) end; Canvas.Pen.Mode := pmCopy; Canvas.Pen.Color := clBlack; end; De aritmética. ============== El sistema de coordenadas tiene el punto cero en la esquina superior izquierda. Para determinar la posición de la aguja necesitamos el centro y el extremo. El centro es la mitad del ancho y la altura. Para la longitud de las agujas tomamos una fracción del mínimo entre el ancho y la altura. Conocido el centro y largo de la aguja sólo resta conocer la posición de su extremo, para ello se determina el ángulo. Aquí terminamos recurriendo a la trigonometría. El ángulo es determinado con cero en el 12, 90 grados a las 3, 180 grados a las 6 hasta 360 a las 12. El seno del referido ángulo nos da la apertura en la coordenada "X", el coseno la apertura en la coordenada "Y". Como nota adicional el sistema de coordenadas en el eje "Y" esta invertido con respecto a los sistemas trigonométricos usuales. Todos los ángulos deben ser expresados como Radianes para efectos de la función seno y coseno. El procedimiento "DrawWatchHand" efectúa los cálculos (también en "FormPaint") procedure Tform1.DrawWatchHand; : : // Now draw Second Canvas.MoveTo(X0, Y0); Angle := S * 2 * Pi / 60; X1 := trunc(X0 + 9*Len * Sin(Angle)/10); Y1 := trunc(Y0 - 9*Len * Cos(Angle)/10); Canvas.LineTo(X1, Y1); : : Nótese que cada aguja utiliza una proporción del valor de Len. Así los segundos son 9/10 de Len, los minutos 3/4 y las horas 1/2. Redondo. ======== Hasta ahora se ha utilizado el "Canvas" para dibujar, se ha eliminado el título y sustituido su funcionalidad, se ha efectuado cierta aritmética y se ha hecho uso de un "timer". El punto central que da título a este artículo es crear una forma no rectangular. Bien esto es tremendamente simple y se resuelve con dos llamadas a Windows en el "FormCreate" del formulario principal: hRegion := CreateEllipticRgnIndirect(R); SetWindowRgn(handle, hRegion, true); "CreateEllipticRgnIndirect" es una versión de "CreateEllipticRgn" con los parámetros (un rectángulo) empaquetados en una sola estructura. Esta rutina retorna un "handle" (manejador) a una región elíptica circuns- crita al rectángulo dado. Si se quiere se pueden definir regiones no circulares usando "CreatePolygonRgn" para polígonos, "CreateRectRgn" para rectángulos (sin sentido en el caso que nos atañe, pero es posible), "CreateRoundRectRgn" para rectángulos de esquina redondeadas, o "CombineRgn" para combinar los resultados de otras regiones. "SetWindowRgn" define el área en la cual es visible una ventana. Es interesante que bajo este concepto la ventana rectangular sigue existiendo y sólo hemos definido algo así como un agujero por donde verla. Un "Bug", un segundo ejemplo. ============================= Mi primer intento de forma no rectangular fue hace un par de años en Delphi 3. Fue una travesura motivado a que conozco personas que detestan terriblemente a las cucarachas (y aquí en el trópico las hay espectacu- lares). Así que creé una cucaracha que se pasea por el escritorio de Windows. La forma de la misma es elíptica y yo fundamentalmente creé unos dibujos para distintos ángulos (cuatro: dos verticales y dos horizontales). El resultado es algo tosco pero disfruté al crear este "bicho". Sé sobradamente que hay mejores maneras de hacer esto pero viene al caso por el tema de este artículo. Lo siguiente. ============= Bien, esto abre posibilidades de uso interesantes (como ya antes mencioné). Creo que la que más adecuada parece ser la de "Skins" como los de algunas aplicaciones. Para referencia están "Winamp", "NeoPlanet", "Windows Media Player" (versión nueva). La técnica que permite formas no rectangulares es aplicable a botones y otros controles. Bibliografía: * Delphi Developer's Handbook, Marco Cantù, Tim Gooch, John F. Lam SYBEX ISBN: 0-7821-1987-5 1.998 * La Biblia de Delphi 5 Marco Cantù ANAYA ISBN: 84-415-0994-8 2.000 -------------------------- El código fuente que acompaña este artículo puede descargarse desde: http://www.latiumsoftware.com/descarga/p0013.zip ________________________________________________________________________ 3. APLICACIONES OPENGL CON DELPHI 5.0 - PRIMEROS PASOS Copyright (c) 2000 Leopold Minikus <info@minais.at> Traducido por Ernesto De Spirito Cuando usa la colección de componentes MNOgl de minais tiene dos formas diferentes de construir aplicaciones de ese tipo. Primero quiero describir la forma fácil: Antes que nada asegúrese de instalar el archivo de paquete MNOgl mnogl.bpl bajo Delphi (Menú Component - Install packages - botón Add - buscar MNOgl.bpl y darle Open). El resultado es que tendrá una nueva carpeta de componentes llamada MNOgl dentro de la cual encontrará un montón de componentes útiles para diseñar un aplicación OpenGL. Permítanos comenzar con un nuevo proyecto. Selecciones un componente TMNOglControl y suéltelo sobre el formulario. Cambie el tamaño del control como quiera o permita alinearlo. Luego seleccione un componente TMNOglCanvas y suéltelo en el formulario. Asigne el MNOglControl1 a la propiedad llamada WinControl. Ahora se generará un contexto de renderizado (el MNOglControl cambia a color de fondo negro). Permítanos ahora ver como podemos dibujar una caja en este lienzo (canvas). Tome un componente TMNOglScene de la carpeta MNOgl y suéltelo en el formulario. Asigne MNOglCanvas1 a la propiedad MNOglCanvas. Ahora permítanos elegir un componente TMNOglBox y soltarlo en el formulario. Asigne MNOglScene1 a la propiedad Scene. Ahora puede ver la forma en modo de diseño. Intente cambiar el tamaño de la cada cambiando las propiedades Length (largo), Width (ancho) y Height (altura). Si desea tener su figura centrada entonces establezca la propiedad TransformBy a (-Length/2, -Width/2, -Height/2). Segundo quiero describir la forma cuando no desea instalar el paquete MNOgl: Permítanos comenzar con un nuevo proyecto. Modifique la lista uses y agregue las unidades _mnoglcanvas, _mnogltools a su lista, por ejemplo: uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, _mnoglcanvas, _mnogltools; Agregue las siguientes variables a su formulario: TForm1 = class(TForm) ... private { Private declarations } MNOglControl1: TMNOglControl; MNOglCanvas1: TMNOglCanvas; MNOglScene1: TMNOglScene; MNOglBox1: TMNOglBox; public { Public declarations } end; Luego entre al método FormShow y crearemos los componentes que necesi- tamos: procedure TForm1.FormShow(Sender: TObject); begin // Crea el WinControl para el contexto de renderizado de OpenGL // donde se "ejecutarán" sus formas MNOglControl1 := TMNOglControl.Create(Self); MNOglControl1.Align := alClient; MNOglControl1.Parent := Self; // Crea el MNOglCanvas MNOglCanvas1 := TMNOglCanvas.Create(Self); // Asigna el WinControl --> y se crea el contexto de renderizado MNOglCanvas1.WinControl := MNOglControl1; // Crea la escena (OpenGL la llama DisplayList) MNOglScene1 := TMNOglScene.Create(Self); // y le dice a la escena en que Canvas se ejecutará MNOglScene1.MnOglCanvas := MNOglCanvas1; // Crea la caja MNOglBox1 := TMNOglBox.Create(Self); // y le dice a la caja a que escena pertenecerá MNOglBox1.Scene := MNOglScene1; // Cambia las propiedades de la caja with MNOglBox1 do begin Length := 4; Width := 3; Height := 2; end; end; Si quiere que la escena rote entonces sólo agregue un TMNOglNav (un navegador) a su formulario y establezca la propiedad MNOglCanvas a MNOglCanvas1. Cuando ejecute su programa puede presionar el botón izquierdo del ratón en el componente MNOglNav y mover el ratón. Con doble-clic se restablecerá la vista. ________________________________________________________________________ 4. ABRIENDO UNA BASE DE DATOS DE MICROSOFT ACCESS (.MDB) CON DELPHI ADO === Si tiene Delphi 5 Enterprise o Delphi 5 Profesional con ADO Express, entonces puede usar una ADOTable y en la propiedad ConnectionString del control ADOConnection asociado puede usar el editor de propiedades para construir la cadena de conexión correcta. Por ejemplo: Provider=Microsoft.Jet.OLEDB.4.0; User ID=Admin; Password=Password; Data Source=D:\Path\dbname.mdb; Mode=ReadWrite; Extended Properties=""; Persist Security Info=False; Jet OLEDB:System database=""; Jet OLEDB:Registry Path=""; Jet OLEDB:Database Password=""; Jet OLEDB:Engine Type=5; Jet OLEDB:Database Locking Mode=1; Jet OLEDB:Global Partial Bulk Ops=2; Jet OLEDB:Global Bulk Transactions=1; Jet OLEDB:New Database Password=""; Jet OLEDB:Create System Database=False; Jet OLEDB:Encrypt Database=False; Jet OLEDB:Don't Copy Locale on Compact=False; Jet OLEDB:Compact Without Replica Repair=True; Jet OLEDB:SFP=False NOTA: Va todo junto en la misma línea. Esta cadena de conexión abrirá la base de datos D:\Path\dbname.mdb usando el controlador ADO para bases de datos Access (Microsoft.Jet.OLEDB.4.0). El nombre de usuario sería Admin sin contraseña (los valores por omisión cuando se crea una base de datos Access). Si ha establecido una contraseña para su base de datos, deberá proveerla en la propiedad Jet OLEDB:Database Password. Si ha establecido seguridad, entonces debe indicar su archivo .MDW o .MDA de grupos de trabajo en la propiedad Jet OLEDB:System database. BDE === Si como la mayoría de nosotros, usted no tiene ADO, puede usar la BDE que provee un controlador nativo (MSACCESS). En un componente Database, establezca las siguientes propiedades: DatabaseName = cualquier_nombre (o nombre_de_alias) DriverName = MSACCESS LoginPrompt = False Params = PATH=d:\camino DATABASE NAME=d:\camino\nomarch.mdb TRACE MODE=0 LANGDRIVER=Access General USER NAME=su_nombre_usuario PASSWORD=su_contraseña OPEN/MODE=READ/WRITE SQLPASSTHRU MODE=NOT SHARED El valor de la propiedad DatabaseName de un objeto Database es el que debe usar en la propiedad DatabaseName de los componentes Table y Query que representen tablas y consultas en esa base de datos (esta es la forma de "vincularlos" al objeto Database). BDE + ODBC ========== En el caso de bases de datos Access, la BDE provee un controlador nativo, pero hay muchos formatos de bases de datos para los cuales no hay un controlador BDE, aunque tal vez pueda encontrar un controlador ODBC. ODBC ofrece lo que yo llamaría "accesso de compatibilidad" (para aplicaciones con apenas mínimos requerimientos de acceso a base de datos, o aplicaciones que sólo necesitan realizar operaciones de importación/exportación), aunque algunas veces es todo lo que tenemos... He aquí un ejemplo de cómo usar un controlador ODBC con la BDE para abrir una base de datos Access: * Cree un DSN (Data Source Name = Nombre de Origen de Datos) para su base de datos (usando la applet ODBC Data Sources del Panel de Control de Windows). 1) Haga clic en la solapa "System DSN" o "User DSN" 2) Haga clic en el botón "Add..." (Agregar) 3) Seleccione el controlador "Microsoft Access Driver (*.mdb)" y presione ENTER. Aparecerá el diálogo "ODBC Microsoft Access Setup". 4) Provea un nombre en el cuadro de texto "Data Source Name" (sin espacios ni caracteres especiales). 5) Haga clic en "Select..." (seleccionar) para especificar su base de datos .MDB. 6) Si ha establecido un esquema de seguridad tiene que seleccionar el botón de radio "Database" en el cuadro "System Database" y hacer clic en el botón "System database..." para especificar su archivo de grupos de trabajo .MDW o .MDA. 7) Haga clic en el botón "Advanced..." (avanzado) para establecer el nombre de usuario y la contraseña predeterminada. Esto es para acceso de baja seguridad porque cualquiera con acceso a su equipo puede ver las propiedades del DSN. Si necesita una seguridad más alta debe proveer el nombre de usuario y la contraseña al abrir la base de datos (vea más abajo). 8) Finalmente haga clic en el botón "OK" para guardar su DSN. * En Delphi establezca las propiedades del componente TDatabase: 1) Establezca DatabaseName con el nombre que le dio al DSN. 2) Si desea que el usuario provea un nombre de login y una contraseña, entonces deje LoginPrompt en True. 3) Si no le gusta el cuadro de diálogo de login estándar (o si quiere proveer el nombre y la contraseña por código), puede establecer LoginPrompt en False y usar su propio cuadro de diálogo (o un nombre nombre de usuario y contraseña que tenga guardados en su aplicación) y establezca la propiedad Params con los datos del login: USER NAME=su_nombre_de_usuario PASSWORD=su_contraseña * Asocie sus componentes TTable o TQuery con el componente TDatabase mencionado arriba simplemente proveyendo el mismo nombre de DSN en su propiedad DatabaseName correspondiende. ________________________________________________________________________ 5. LISTANDO LAS TABLAS Y CONSULTAS EN UNA BASE DE DATOS Si necesita conocer los nombres de todas las tablas y/o consultas (vistas) en una base de datos abierta con la BDE, puede usar DbiOpenTableList para crear un cursor* con todos los nombres de tablas y consultas, y luego puede leerlo llamando a DbiGetNextRecord como se muestra en el ejemplo de abajo que guarda los nombres en un cuadro de lista (ListBox), indicando si corresponden a una tabla o a una consulta. (*) Un cursor, para quienes no están al día en la terminología de las bases de datos, es una "tabla lógica". Por ejemplo cuando abrimos una tabla o consulta, lo que obtenemos es un cursor, es decir, un conjunto de datos distribuidos en filas o en columnas, independientemente que esos datos provengan de una tabla física, de parte de una tabla, de muchas tablas o de cualquier otra fuente de datos. Para probar el ejemplo, simplemente coloque un ListBox y un Button (botón) en un formulario, y genere el manejador del evento OnClick del botón: uses db, dbtables, bde; // No se olvide de incluir la unidad BDE! procedure TForm1.Button1Click(Sender: TObject); var db1: TDatabase; hCursor: hDBICur; // Cursor con los nombres de tablas y // consultas ListDesc: TBLBaseDesc; // Registro del cursor begin ListBox1.Clear; db1 := nil; try db1 := TDatabase.Create(nil); // Establezca las propiedades necesarias para abrir su base de // datos db1.DatabaseName := 'Access_ODBC_Test'; db1.LoginPrompt := False; db1.Connected := True; // Generar el cursor con los nombres de tablas y consultas Check(DbiOpenTableList(db1.Handle, False, False, '*', hCursor)); // Moverse por los registros del cursor para obtener los nombres while (DbiGetNextRecord(hCursor, dbiNOLOCK, @ListDesc, nil) = dbiErr_None) do if ListDesc.bView then // ¿Es una consulta? ListBox1.Items.Add(ListDesc.szName + ' (Consulta)') else ListBox1.Items.Add(ListDesc.szName + ' (Tabla)'); // Cerrar el cursor dbiCloseCursor(hCursor); db1.Connected := False; except db1.Free; raise; end; db1.Free; end; En lugar de una variable de tipo TDatabase creada para el propósito, puede usar un control TDatabase colocado en un formulario, o la propiedad Database de un control TTable o TQuery. ________________________________________________________________________ 6. ENLACES EN INGLES ========= * Top 100 Borland - Resources for Borland Developers http://www.top100borland.com EN ESPAÑOL ========== * Creación de controles Delphi y ActiveX con Delphi 3.0 Un artículo para principiantes en la creación de componentes http://www.hispan.com/eltaller/ControlDelphi.html ________________________________________________________________________ Si no has recibido el archivo con el código fuente completo de los ejemplos que se presentan en este boletín, puedes descargarlo de la siguiente dirección: http://www.latiumsoftware.com/descarga/p0013.zip ________________________________________________________________________ Página principal: http://www.latiumsoftware.com/es/pascal/index.php Página del grupo: http://espanol.groups.yahoo.com/group/boletin-pascal/ Para suscribirse / apuntarse: boletin-pascal-subscribe@gruposyahoo.com Para cancelar / removerse: boletin-pascal-unsubscribe@gruposyahoo.com Para reportar problemas con la suscripción: eds2004 @ latiumsoftware.com ________________________________________________________________________ Este boletín se provee "TAL Y COMO ESTA", sin garantía de ninguna clase. Su uso implica la aceptación de nuestros términos de licencia y de la ausencia de garantía que puedes leer en nuestro sitio web. Allí también encontrarás una nota sobre marcas registradas. Te animamos a que redis- tribuyas este boletín, siempre y cuando lo hagas en forma completa (incluyendo la información de copyright), sin modificaciones y de manera gratuita. Los artículos son copyright de sus respectivos autores y se reproducen aquí con el permiso de los mismos. ________________________________________________________________________ Latium Software http://www.latiumsoftware.com/es/index.php Copyright (c) 2000 por Ernesto De Spirito. Todos los derechos reservados ________________________________________________________________________ |
Los ejemplos completos de código fuente de este número están disponibles para descargar.
![]() |
¿Errores? ¿Omisiones? ¿Comentarios? Por favor contáctanos!






