lunes 18 de enero de 2010

Manila Dialup Enabler Disabler

Este post es para contar una cosa que me ha pasado este mes de enero que me ha sorprendido muchísimo. De hecho, ha superado con creces las espectativas que tenía sobre un pequeño programa al que únicamente he dedicado 4 o 5 horas.




En diciembre se me murió el teléfono móvil, y aproveché para comprar un HTC Touch HD2.



Es un teléfono alucinante. Tiene una pantalla de 4,3" (enorme), capacitiva (se maneja con los dedos, no tiene puntero), multitáctil, con mucha RAM, mucho procesador y mucho de todo. Me compré este modelo porque es el que más posibilidades tiene para actualizarse a Windows Mobile 7 el día que salga (creo que para noviembre de 2010).

Este teléfono utiliza como sistema operativo Windows Mobile 6.5, que no es un sistema operativo pensado para manejarse con los dedos. Está pensado para ser manejado con puntero, por lo que el fabricante ha tenido que hacer una capa que oculta prácticamente el 100% del sistema operativo ya que la principal característica del teléfono es precisamente esa: su pantalla capacitiva.

Esta capa que el fabricante pone encima del sistema operativo se llama HTC Sense, pero en terminología técnica se llama "Manila", y hace que se pueda manejar el sistema operativo con los dedos sin ningún problema.

El interface de usuario "Manila" es muy suave, bonito y está presente en prácticamente todas las tareas que se realizan de forma cotidiana con el teléfono.

Cuando quieres hacer algo no cotidiano, te puedes encontrar con que no hay "Manila" y es cuando recuerdas que hay un Windows Mobile (no apto a día de hoy para manejarse con dedos) por detrás.

Insisto mucho en el tema de manejar con dedos, porque las pantallas capacitivas no funcionan con punteros. Ya puedes intentarlo por activa o por pasiva: la pantalla capacitiva no detecta los punteros. Hay que utilizar el dedo y muy suave, nada de presionar como con las resistivas.


Es un teléfono pensado para estar todo el día conectado a Internet. Viene con muchísimos servicios que requieren conexión a internet. Por ejemplo la pantalla principal te informa del tiempo en la ubicación en la que estás. Un día me fui a casa de mis padres en Paracuellos del Jarama y el teléfono sabía perfectamente mi ubicación (el GPS estaba apagado, todo se estaba haciendo por internet) y el tiempo que hacía en esa ubicación.

Por lo tanto el mismo día que me lo compré activé un plan de datos para el movil. Tener un teléfono de estas características y no tener de plan de datos significaría desaprovechar casi al 100% su potencial.

El problema que tiene un teléfono como este con una pantalla tan grande y siempre conectado a internet es que la batería se agota rápidamente.



Se me ocurrió que finalizando la conexión de datos podría ahorrar algo de batería, pero rápidamente me di cuenta de que finalizar la conexión no sirve de nada, pues en cuanto algún programa o servicio se quiere conectar a internet, nada le impide establecer la conexión otra vez, lo que en la práctica significa que casi en el mismo momento en que finalizabas la conexión, el teléfono se volvía a conectar.

Me acordé de un programa antiguo que se llama Modaco NoData que servía para evitar que los programas establecieran conexiones a internet. Lo localicé y lo instalé, pero al ser un programa antiguo, no estaba pensado para utilizar con dedos y era muy complicado de manejar en mi teléfono, así que se me ocurrió:

¿Por qué no me lo programo yo?

Fase 1: Interface de usuario.

A lo largo de mi vida profesional he conocido a muchos programadores que opinan que el interface de usuario es secundario, que lo importante es que las cosas funcionen, que el usuario le da igual el interface de usuario siempre y cuando el programa funcione.

Pues bien, nada más lejos de la realidad.

"Para el usuario el interface de usuario es la aplicación".

Mientras más bonito sea el interface de usuario mas serio parece el programa y mas convence a los usuarios. El programa por supuesto que tiene que funcionar, pero no es lo mismo un programa feo que uno bonito. Así de claro. Tan solo hay que ver el éxito de Apple, el esfuerzo multimillonario que ha hecho Microsoft con Windows Presentation Foundation y con Silverlight, o el esfuerzo que habrá hecho Adobe con su Flex.


Mi objetivo era hacer que el interface de usuario de la aplicación fuera idéntico al de Manila (que está muy bien pensado para utilizar con dedos), para que no hubiera ninguna diferencia entre las aplicaciones que vienen instaladas en el teléfono de fábrica y mi futura aplicación.

Últimamente estoy estudiando mucho WPF (Windows Presentation Foundation) y Silverlight, y es con Silverlight con lo que debería de hacerlo, pero a día de hoy (enero de 2010) todavía no existe Silverlight para Windows Mobile. Tengo clarísimo que hasta que no liberen Windows Mobile 7 no vamos a ver Silverlight para móviles.

Así que la única opción era programar una librería que me permitiera crear las ventanas con el aspecto del teléfono móvil, pero se me ocurrió buscar en el foro de XDA developers si existía ya alguna librería, y ¡eureka!, una tal Michele había programado justo lo que necesitaba: Manila Interface SDK.

Fase 2: Desarrollo




El objetivo de la primera versión era emular lo que hacía Modaco Nodata, que es una tontería, cambiar una cosa del registro, nada más, así que no iba a costar mucho programarlo. De hecho el programa era tan tonto que le añadí desde la primera versión más funciones que el Nodata, ya que desde la primera versión se podía finalizar la conexión de datos activar y no había que irse al gestor de conexiones del teléfono.

Descargué la librería Manila Interface SDK, la estudié y me puse manos a la obra.

¡En una hora tenía mi programa funcionando!

Lo programé en inglés como puedes ver en la captura de la derecha.

Fase 3: Hacerlo público a ver qué acogida tenía

Decidí llamarlo Manila GPRS Enabler/Disabler y se me ocurrió subirlo al mismo foro del cual había descargado la librería. Esta es la pagina del programa: http://forum.xda-developers.com/showthread.php?p=5269827.

El mismo momento en el que lo subí le dije a mi mujer que acababa de hacer mi primer programa para móviles y que estaría muy contento si lo bajara alguien (digamos una o dos personas) de esa página web.

Esto fué el día 3 de enero.

Para el día 5 ya lo habían descargado 777 veces.

La gente empezó a hacerme preguntas en el foro y decidí sacar una versión que lista todas las conexiones activas del teléfono (para saber contra que servidores estaba conectado) y cambiarle el nombre a Manila Dial-Up Enabler/Disabler, para no confundir a los usuarios con conexiones 3G y HSPDA.

Desde entonces he realizado alguna modificación al programa y para cuando subí la versión 5, la 4 llevaba 1066 descargas.

Cada vez que subes una versión a ese servidor el contador se resetea, de esa manera sabes el número de descargas que ha tenido cada versión.

A dia de hoy es imposible saber el número de descargas, porque ya hay "cocineros" que incluyen el programa en ROMs "cocinadas", así que cuando alguien actualiza la ROM de su teléfono, se encuentra el programa ya instalado.

Fase 4: Cuando te das cuenta de que lo utilizan en todo el globo

Se me ocurrió mirar en google a ver qué se decía del programa y me sorprendió ver foros en árabe, francés, checo, ... que hablaban y ¿recomendaban? mi programa.

Fase 5: Cuando pides ayuda para "localizarlo"


Se me ocurrió poner en el foro que lo quería traducir y que necesitaba ayuda.

Bueno, pues hoy es 28 de enero de 2010, todavía no ha pasado ni un mes y el programa está programado en:

1. Inglés
2. Español
3. Polaco
4. Rumano
5. Ruso
6. Alemán
7. Chino Tradicional
8. Checo
9. Portugués
10. Holandés

y me lo están traduciendo al Italiano, gracias a mucha gente que de forma altruista han traducido los recursos.

La traducción que más gracia me hizo fué la del Ruso y luego la del Chino que no he podido probar en mi teléfono ya que únicamente tiene instaladas las fuentes occidentales, pero el traductor me ha enviado capturas de pantalla de su móvil como puedes ver aquí.

La verdad es que estoy muy sorprendido por la acogida que ha tenido y por lo colaborativa que es la gente, y por haber hecho amigos en todo el mundo por este programa que, repito, entre pitos y flautas no me ha robado más de 4 o 5 horas.

jueves 19 de noviembre de 2009

Etiquetas en los códigos de Digi.Tab

El formato del nuevo Digi.tab que se introdujo en Digi a partir de la versión 2007 es muy flexible ya que está basado en el standard XML, lo que permite añadir campos sin romper la compatibilidad.

En este ejercicio, vamos a modificar un Digi.tab automáticamente para añadirle un concepto que tiene la versión de Digi para MGCP/BTA y que tiene la futura version Digi3D 2010.

En estas versiones de Digi, los códigos pueden tener asociadas etiquetas. Cada código puede tener un número ilimitado de etiquetas, que no son más que nombres separados por comas.

Así pues, si un determinado código tiene el siguiente valor en el campo etiqueta: "Edificios,Edificios en construcción,1:1000" dicho código tendrá tres etiquetas:

a) Edificios
b) Edificios en construcción
c) 1:1000

¿Para que sirven las etiquetas?

Pues básicamente para agrupar códigos.

Si tenemos 10 códigos con la etiqueta "Edificios", podemos ejecutar cualquier orden que trabaje con etiquetas para trabajar con todos esos códigos a la vez.

Ej: En la versión 2010 de DigiNG, podemos ejecutar la orden: BORRA_COD=@Edificios L
para borrar todas las líneas cuyos códigos tengan la etiqueta "Edificios".

Cuando desarrollé el módulo de MGCP para DigiNG, no existía el concepto de etiquetas, sin embargo, era necesario agrupar de alguna manera códigos para hacer topologías. Esto lo hice en el archivo mgcp.xml.

Aquí tenemos un recorte del archivo mgcp.xml



<?xml version="1.0" ?>
<menuMGCP>

<bintop name="Terreno inundable">
BBH090
CBH090
</bintop>

<bintop name="Landcover Area Features">
L1
CZD020
CZD020
CBH030
CBH030
CBH020
CBH130
CBH080
CBH140
CBA040
CDB170
</bintop>

<bintop name="Isla">
BBA030
CBA030
</bintop>

<bintop name="Aeródromo">
BGB005
CGB005
</bintop>

</menuMGCP>


Luego pensé en el concepto de etiquetas para introducir esta tabla de códigos en el digi.tab y añadi la etiqueta "TAGS" a cada uno de los códigos en el digi.tab.

El problema es que luego había que insertar las etiquetas en el digi.tab de MGCP a partir del archivo mgcp.xml de más arriba.

Esta tarea podría haber llevado horas, así que he desarrollado una pequeña aplicación en el lenguaje de programación C# que va a hacer el proceso automáticamente.

Va a cargar el archivo mgcp.xml con los grupos de códigos (en la etiqueta "bintop"), luego va a cargar un digi.tab y va a ir añadiéndo a cada código las etiquetas que le correspondan.

Por último, va a guardar el digi.tab modificado con otro nombre.

Como es una aplicación que se va a ejecutar una única vez, no he dedicado tiempo a comprobar si un determinado código ya tenía una etiqueta o no, eso os lo dejo como tarea de programación.

Utiliza Linq, Xml y XPath.

Aquí está el código:



using System;
using System.Linq;
using System.Xml;
using System.Xml.XPath;

namespace AnadeEtiquetas
{
class Program
{
static void Main(string[] args)
{

XmlDocument digiTab = new XmlDocument();
digiTab.Load("digi.tab.xml");
XPathNavigator navegadorDigiTab = digiTab.CreateNavigator();

XmlReaderSettings settings = new XmlReaderSettings();
settings.ProhibitDtd = false;

using( XmlReader readerMGCP = XmlReader.Create("mgcp.xml", settings) )
{
XPathDocument mgcpXML = new XPathDocument(readerMGCP);

XPathNavigator navegadorMGCP = mgcpXML.CreateNavigator();

foreach(XPathNavigator tablaDeCodigos in navegadorMGCP.Select("/menuMGCP/bintop") )
{
string nombreTabla = tablaDeCodigos.GetAttribute("name", "");

Console.WriteLine("Insertando la tabla {0} en el digi.tab", nombreTabla);

var listaDeCodigos = from código in tablaDeCodigos.Value.Split('\n')
let códigoRecortado = código.Trim()
where códigoRecortado.Length > 0
select códigoRecortado;

foreach (string código in listaDeCodigos)
{
XPathNodeIterator nodosDigiTab = navegadorDigiTab.Select("/digitab/codes/code[@name=\"" + código + "\"]");

foreach (XPathNavigator nodo in nodosDigiTab)
{
if (nodo.MoveToAttribute("tags", ""))
{
nodo.SetValue(nodo.Value + "," + tablaDeCodigos.GetAttribute("name", "").ToString());
}
else
{
nodo.CreateAttribute("", "tags", "", tablaDeCodigos.GetAttribute("name", "").ToString());
}
}
}
}
}

navegadorDigiTab.MoveToRoot();
using (XmlWriter writter = XmlWriter.Create("digitabmodificado.tab.xml"))
{
writter.WriteNode(navegadorDigiTab, false);
writter.Flush();
}
}
}
}

martes 13 de octubre de 2009

MDTop 2010

El otro día, en la feria de usuarios de Esri en España, José Juan vino a ayudarnos.
En uno de esos pocos momentos de relax que tuvimos, me enseñó el prototipo de lo que va a ser MDTop 2010.

Si MDTop ya era fácil de manejar, ni te imaginas lo intuitivo que va a ser MDTop 2010.

El interface de usuario ha cambiado completamente. Ahora está basado en el famoso interface Ribbon que Microsoft incorporó en Office 2007.



La barra ribbon está llena de botones con unos iconos increiblemente bien dibujados y además disponen de texto para saber el significado de cada botón.

El resultado: Ha desaparecido el menú del programa, ya que el menú ahora es una super barra de herramientas.

Pero eso no es todo: Ahora MDTop 2010 utiliza como motor de presentación OpenGL, lo que significa que los vectores se dibujan rapidísimo. Esto es porque MDTop 2010 está preparado para trabajar con conjuntos enormes de datos de Lidar. Con una tarjeta gráfica adecuada, se pueden dibujar millones de vértices por grame.

Además VirtuaLand desaparece como programa independiente y se incorpora en MDTop 2010, así tenemos un único programa que hará las dos cosas (si se dispone de la licencia correspondiente para hacer las dos cosas).

De Ferias con Esri España

Tengo que agradecer muchoa Esri España, y personalmente a Alfonso Rubio por darnos la oportunidad de presentar la extensión "Digi3D para ArcGIS" en la Conferencia de Usuarios ESRI España 2009.



Allí dispusimos de un stand para presentar el producto (que aún está en desarrollo, pero suficientemente avanzado para poderlo mostrar al público en general).

Lo que mostramos en esa feria era tan nuevo, que hasta el driver de las gafas estereoscópicas que llevamos, lo habían publicado los de nVidia ¡un día antes!.

Menuda semana para preparar el programa, documentación, las diapositivas de la ponencia (gracias José Juan), la tarjeta gráfica, el monitor estereoscópico...



Además dispusimos de media hora para dar una charla en una sala de conferencias y explicar las características de Digi3D para ArcGIS.

En uno de los pocos momentos de relax pude asistir a una conferencia super interesante de José M. García y Pablo Ramos sobre migración de una aplicación de escritorio con ArcObjects en .NET al servidor de ArcGis, y no pude asistir a dos conferencias super interesantes de SilverLight, pero otra vez será. No se puede estar en dos sitios a la vez.

Todo funcionó como un Reloj, cómo se nota que Esri es un gigante.

La feria terminó un viernes y el domingo estábamos volando Manuel y yo a Bogotá.



Hemos conocido gente de Chile, Argentina, Bolivia, Perú, Ecuador, Colombia, Venezuela, Costa Rica, Puerto Rico, México, USA, ... y hemos hecho muchos amigos. Ni os imaginais lo divertidos que son los Mexicanos.

El lunes conocimos al staff de Procálculo Prosis (Esri Colombia), y realizamos una serie de pruebas para montar dos monitores estereoscópicos (el de ellos y el que llevaba Manuel en su maleta).

Al final resulta que nuestra tarjeta nVidia Quadro FX 3800, no puede (creo que por el momento) sacar una frecuencia de 120Hz por sus conectores DisplayPort, así que probamos con la tarjeta que tenían en uno de sus ordenadores, una Quadro FX 3700, con dos conectores DVI y pudimos trabajar en estéreo con los dos monitores.

La feria comenzó el miércoles, pero el martes presentamos Digi3D para ArcGIS y todas nuestras aplicaciones a los distribuidores.

El resto de días, no salimos de nuestro stand porque no nos dejaban, teníamos visitas constantemente.

Funcionó todo, hicimos cosas arriesgadas en una demostración "en vivo", como correlar un modelo de objeto cercano (la famosa Capilla que muchos conocéis) y salió perfecto. Cámbios automáticos de modelos, orientaciones, vamos, que en esa semana enseñamos todas nuestras armas y todo funcionó a la perfeccion.

lunes 14 de septiembre de 2009

Actualización de E-Mail File Attachment Using MIME (with HTML support)

Lo prometido es deuda y, después de una semana, han publicado mi artículo en la siguiente dirección: http://www.codeguru.com/cpp/i-n/internet/email/article.php/c16401/

Es una lástima, pero todo lo que puse en el post anterior no me sirvió de nada, porque resulta que no me di cuenta de que Digi3D está encriptado, por lo que las capturas de MiniDump no me sirven de nada, pero al menos me divertí mucho programándolo.

viernes 28 de agosto de 2009

Detección de excepciones no controladas



Ayer estuve en una empresa y ocurrió algo que suele pasar de vez en cuando:

Un operador me dijo que Digi3D a veces se le salía inesperadamente al ejecutar una determinada orden. El único inconveniente es que no sabía provocar el fallo, lo que hace que sea muy complicado reproducirlo y por lo tanto corregirlo.

En este tipo de situaciones, la única posibilidad que tenía es irme a la empresa en cuestión con un ordenador portatil, instalarle un módulo denominado Visual Studio Remote Debugger, copiar una versión especial de Digi3D, ejecutarla y cruzar los dedos esperando que el usuario consiga reproducir el error.

La mayoría de las veces, únicamente necesito que se reproduzca el error una vez. En cuanto veo lo que está pasando, tardo un milisegundo en saber cómo arreglarlo. Otras veces, es más complicado y necesito reproducirlo una y otra vez.

Pero el principal inconveniente es que tiene que suceder cuando estoy allí utilizando el depurador remoto. Si no, no me sirve de nada que me digan "Se me sale de vez en cuando".

En este caso particular, el problema es que el operador pulsaba Esc mientras se estaba destruyendo un cuadro de diálogo y Digi capturaba la pulsación de tecla destruyendo la orden que había desencadenado que saliera dicho cuadro de diálogo. Yo no he sido capaz de reproducirlo, y ayer estuve toda la tarde intentándolo. Saqué ese cuadro de diálogo unas mil veces, y nada de nada.

Así que me puse a pensar cómo puedo hacer para poder copiar el estado de la máquina del cliente justo cuando se detecta que el programa va a finalizar inesperadamente, y me acordé de un programa que venía en Windows XP denominado Dr. Watson.

Este programa genera un archivo "mini-dump" que es justo lo que necesito para poder reproducir el problema en el ordenador que tengo en la oficina de Digi21.

Buscando por la web, dí con un vídeo de Microsoft que demuestra cómo utilizar este archivo de Mini Dump.

El único inconveniente es que era necesario que el usuario active Dr. Watson, así como que el usuario copiara manualmente los archivos de dump generador y me los enviara por correo electrónico, sueño que sé que nunca se iba a cumplir.

Así que tenía dos problemas:

a) No quiero que el usuario tenga que activar Dr. Watson manualmente.
b) Quiero que los archivos de MiniDump se envíen automáticamente a mi servidor para poder corregir el error que ha desencadenado la generación de dicho archivo MiniDump tan pronto como sea posible.

Para solucionar el primer problema, busqué APIs en MSDN hasta que dí con la API que utiliza DrWatson, que se llama MiniDumpWriteDump. Esta API me permite generar el archivo sin necesidad de activar DrWatson ni nada de nada.

Digi3D utiliza las librerías MFC. La aplicación está representada por una clase que hereda de la clase CWinApp.

CWinApp a su vez, tiene un método virtual denominado CWinApp::Run que es el método que ejecuta todo el programa. Así que únicamente tenía que sobrecargar dicho método y llamar al de la clase base dentro de un try catch:

__try {
__super::Run();
}
__catch(...)
{
// Procesar la excepción
}


En este punto lo único que tengo que hacer es generar un archivo de MiniDump de forma automática además de mostrarle al usuario un cuadro de diálogo indicándole que se ha producido un error inesperado, que se ha generado el archivo de MiniDump para ayudar al desarrollador a localizar y corregir el error y que se va a proceder a enviar dicho archivo al servidor de Digi21.

Aquí comienza el segundo problema: ¿Cómo envío el archivo al servidor?

La primera solución que se me ocurrió fué crear un servicio en nuestro servidor, tal y como ya tenemos servicios para generar licencias de Júpiter para proyectos del estilo Grafcan o Geomadrid, pero no estaba muy convencido porque no me apetece cargar el servidor con servicios cada vez que se me ocurra algo nuevo.

La siguiente idea que me surgió fué enviarla por correo electrónico. Si el programa que ha fallado es Digi3D, que se me envíe un email a mí, y si ha sido por ejemplo MDTop, que se le envíe a José Juan.

Pero aquí surge otro problema: Puede que el usuario no tenga programa cliente de correo electrónico. Yo por ejemplo utilizo a diario tres ordenadores, y sólo tengo Outlook en uno de ellos. Con los otros dos utilizo correo web.

Así que no me quedaba más remedio que ponerme a programar una clase que me permita enviar correo sin necesidad de tener un programa cliente de correo electrónico.

Los correos electrónicos se envían mediante el protocolo SMTP (Simple Mail Transfer Protocol), que como su nombre indica, es muy simple.

Sin embargo la cosa se complica un poco cuando queremos enviar un archivo adjunto ya que además hay que utilizar Mime (Multipurpose Internet Mail Extensions) y eso ya es un poco más complicado, que no imposible, así que decidí buscar a ver si alguien ya lo había hecho.

Existen dos fuentes de código en internet que solemos utilizar los programadores: TheCodeProject y CodeGuru.

En estos sitios puedes buscar un componente y, si tienes suerte, alguien ya lo ha programado antes y lo ha subido a cualquiera de los dos servicios.

Hay dos tipos de personas en el mundo: Creativas y No creativas. Las no creativas únicamente utilizan estos servicios y nunca aportan nada a la comunidad. No envían mensajes de feedback, no corrigen errores y por supuesto, nunca comparten nada.

Las creativas sin embargo actúan al revés.

Yo me considero creativo, y tengo varios artículos en TheCodeProject y hoy voy a subir un artículo a CodeGuru.

Resulta que he localizado en CodeGuru un proyecto que es exáctamente lo que quiero:
E-Mail File Attachment Using MIME (with HTML support), programado por Wes Clyburn.

Lo descargo, lo modifico para que funcione con el servidor de correo de Digi21.net y descubro que no funciona, no porque esté mal programado, sino porque el servidor de correo Digi21 requiere autenticación, y éste componente no está programado con autenticación.

Así que me he puesto a estudiar el protocolo SMTP Service Extension for Authentication y he modificado el código fuente del proyecto que he descargado de CodeGuru.

Ahora este componente admite autenticación, así que esta misma tarde voy a enviar el proyecto a CodeGuru modificado para que cualquiera pueda utilizarlo.

Lo siguiente ha sido añadir este componente a Digi3D y ya tengo el servicio de envío de archivos MiniDump automatizados a mi cuenta de correo electrónico.

Por ahora lo he hecho en la verión Digi3D 2007 MGCP y la semana que viene lo haré para la versión 2007 y 2010 Beta.

Así que a partir de ahora es como si estuviera depurando remotamente en todos los equipos con Digi3D que se ejecutan en el mundo.

Si se produce algún error, me llegará dicho informe y podré corregirlo. Así de simple.

martes 25 de agosto de 2009

Vectores estereoscópicos en Digi3D para ArcMAP

El complemento de Digi3D para ArcMAP sigue creciendo poco a poco.

Ya he conseguido mostrar vectores estereoscópicos con los colores y grosores que utiliza ArcMAP para dibujar en la ventana de mapa.



Por ahora dibujo capas de tipo polilínea y capas compuestas, como la de la captura de pantalla que es una capa CAD.

El único inconveniente por ahora es que la combinación ArcMAP/Digi3D no es tán rápida como la combinación DigiNG/Digi3D, por lo que un modelo que Digi3D regenera en décimas de segundo, pasa a ser casi un segundo en Arc/Digi3D.

No estoy utilizando aceleración gráfica en todo el proceso. Mañana añadiré más aceleración gráfica y espero acercarme a la velocidad de DigiNG.