Burradas de programadores: ¿la clave de licencia, por favor? Aquí está. De nada…

Esta es otra de esas buenísimas que cuando las veo no me puedo resistir a contar aquí, para que veamos que siempre hay quien supera al resto en algo 😀


Resulta que un programa cuya licencia había caducado, al arrancar le mostraba al usuario un mensaje de error sin permitirle continuar y ni siquiera recuperar algunos datos que tenía dentro.


Investigando un poco en la carpeta de archivos del programa con la esperanza de encontrar la base de datos del programa e intentar extraer la información de allí con un poco de esfuerzo se encontró un archivo llamado Licence.key. Como es de esperar (yo hubiera hecho lo mismo) abrió el archivo -que era de texto- y encontró el siguiente contenido:



! Legalese Pro License File – Do Not Modify
! Generated Mon Jan 24 21:17:47 EST 2001
expiration-date = 07-31-2005
key = 78c52ab4f6244475fb7ebefb21b7111c


«¡Oye!, vamos a cambiar esa fecha a ver qué pasa! A lo mejor me deja continuar usándolo un rato más», pensó el interfecto…


Obviamente esto no podía funcionar ya que como es de esperar la clave especificada tendrá una relación directa con la fecha de caducidad pues es el único dato que hay en el archivo ¿no?. En efecto, así es… pero cual sería la sorpresa cuando al ejecutar de nuevo el programa conla fecha modificada le aparece el siguiente mensaje:



¡Le está mostrando cual es la clave de licencia correcta para esa fecha!. Impresionante. El amigo sólo tuvo que ir al archivo, cambiar la clave y a disfrutar por la jeta del programa para toda la vida. Increible.


Después de ver esto no me dirás que algunos programadores no merecían ser atados en la plaza pública para que la gente les tire verduras 😀


Realmente buenísimo.


Esto está sacado de The daily WTF.

Evítate problemas: pon SIEMPRE un nombre de aplicación en Web.config

El bueno de Scott Guthrie (del equipo de desarrollo de ASp.NET) puso ya hace tiempo un post muy bueno sobre porqué era muy recomendable (si no casi indispensable) poner un nombre dentro de web.config dentro de la configuración de los proveedores (tanto de Membership como de Roles, etc…).


El motivo es que si no lo hacemos, al mover la aplicación no seremos capaces de acceder a los datos que hay en la base de datos pues casi seguro que hemos cambiado la ruta de la aplicación respecto al servidor de desarrollo, y es muy desagradable 🙁


Hoy me ha surgido una pregunta relacionada con esto y aprovecho la ocasión para recordarlo a todos los lectores de este blog desde aquí. Así que léete el post completo de Scott y ya sabes: que no se te olvidé nunca más 🙂

AJAX con ASP.NET 2.0 (The "a pelo" series): Script Callbacks (yIII): Un ejemplo completo

Para finalizar las «the a-pelo series» sobre AJAX dedicadas a los Script Callbacks en ASP.NET 2.0 vamos a realizar un ejemplo completo que muestre todo lo que comentamos en los post precedentes.


Nuestro ejemplo será muy sencillo pero suficiente para comprender todo lo explicado hasta ahora. Crearemos una página con una lista de categorías y un botón que, al ser pulsado, mostrará debajo (sin hacer postback) los contenidos de dicha categoría (sin florituras). La siguiente figura muestra la idea:



Un poco cutre ¿no? Pero de esta forma obviaremos otro código que nos pueda descentrar de nuestro objetivo que es entender los Script Callback.


Los preparativos


Crea un nuevo proyecto de Visual Web Developer. En la página por defecto (Default.aspx) arrastra un control DropDownList y llámale ‘ddlCategorías‘. Asígnale una lista de elementos (Empresas, Libros, Blogs, Revistas…). No marques su opción de AutoPostBack.


Ahora añade un botón. Pero ojo, muy importante, no nos sirve un botón de ASP.NET (control Web) ya que este tipode control siempre se renderiza como un botón de envío de formulario (submit) y es precisamente eso lo que queremos evitar. Debes utilizar un botón de HTML (o sea un INPUT de toda la vida) arrastrándolo desde la categoría HTML de los controles de ASP.NET. Una vez en el formulario pulsa sobre él con el botón derecho y escoge la opción de ejecutar en el servidor. Llámale ‘cmdVer’.


Para finalizar añade debajo y desde el mismo sitio un a capa (DIV) con el nombre ‘divResultados’ con un estilo que permita que crezca adaptándose a su contenido.


Con todo ello tendrás un código como este para tu página:




Ya tenemos todo lo necesario para crear nuestro ejemplo. Ahora vamos a la «chicha» de verdad.


1.- Realizar las peticiones al servidor.


Lo primero en el orden lógico es pensar cómo vamos a enviar las peticiones al servidor. En nuestro ejemplo lo haremos cuando se pulse el botón, aunque podría ser al cambiar la selección de la lista o con cualquier otro evento de JavaScript que se nos ocurra. es obvio que tendremos que escribir un manejador para el evento ‘onClick’ del botón. El código que debemos incluir para conseguirlo nos lo da el método GetCallbackEventReference estudiado antes. Por lo tanto lo único que debemos hacer es asociarlo al botón en el evento Load de la página. Para ello necesitaremos decidir qué valor se le pasará al servidor durante la llamada, qué función de JavaScript se va a llamar como respuesta final al Callback (resultado), un dato de contexto (no lo usaremos) y el nombre de la función JavaScript que se llama´ra en caso de producirse un error. Por todo ello en nuestro caso escribiremos el siguiente código:



Lo que se hace es en realidad muy sencillo: obtenemos el identificador para la lista desplegable que se usará en el HTML resultante (no tiene porqué coincidir en general con el que le hemos dado en la página ASPX) y con eso construimos una cadena JaVaScript que simplemente sirve para obtener el valor del elemento que esté seleccionado en ésta (este código JavaScript lo almacenamos en la variable jsItem).


A continuación generamos el código JavaScript que va a provocar la llamada al servidor con el método GetCallbackEventReference. Como parámetros se le pasan el control que gestionará el Callback (la propia página, this en C# o Me en VB), el código JavaScript que nos da el valor a enviar al servidor (el elemento seleccionado en la lista), el nombre de la función a llamar tras terminar la petición al servidor (‘ActualziaVista’), el dato de contexto (en este caso un nulo), el nombre de la función JavaScript que se llamará si hay un error en la comunicación, y un booleano que indica si queremos que la llamada sea asíncrona o no (en el listado se ha dejado como síncrona, debería ser true para ser AJAX de verdad).


Por fin se asigna ese código JavaScript al evento ‘onClick’ del botón (que no deja de ser un atributo), con lo que al final, al ejecutar la página obtendremos el siguietne HTMlo para el botón:


<input name=»cmdVer» type=»button» id=»cmdVer» value=»Ver listado» onClick=»javascript:WebForm_DoCallback(‘__Page’,document.getElementById(‘ddlCategorias’).value,ActualizaVista,null,MuestraError,false)» />


2.- Definir la interfaz ICallbackEventHandler


Ahora que ya estamos provocando las peticiones al servidor vamos a definir los métodos que se ejcutarán en éste como resultado de la llamada y que son los que obtienen el resultado a devolver. Como recordarás hay que implementar dos. En nuestro ejemplo el código sería:



Si nos fijamos el código es muy sencillo. Hemos eliminado acceso a datos y otras cuestiones para centrarnos en lo que nos ocupa, así que según el valor que se pasa al método (la selección de la lista desplegable) anotamos una u otra lista de elementos separados por comas en una variable. El contenido de ésta es lo que se devuelve en el método GetCallbackResult y por lo tanto lo que se le pasa al cliente como resultado. Listo.


3.- Implementar las funciones de recepción de resultados en el cliente


Por fin sólo nos resta una cosa y es decidir qué hacemos con los resultados una vez que se termine la llamada. En nuestro caso haremos algo muy sencillo: separaremos los elementos recibidos como resultado sustituyendo las comas por retornos de carro (<BR/> en HTML) y esta cadena resultante la introduciremos directamente en el <DIV> de resultados que hemos incluido. El código JavaScript es muy sencillo:



Fijémosos en las funciones. La primera de ellas es general y se usa desde las otras dos simplemente para introducir el HTML que queramos dentro del DIV. Las otras dos funciones son la implementación de los métodos de resultado y de error y que deben tener exactamente los mismos nombres que escogimos en el paso 1, al general la llamada al servidor. En el primer caso se sustituyen las comas por un retorno de carro y en el caso del error se muestra el mensaje de error en el DIV en lugar de los resultados. Así de sencillo.


En ejemplos reales podríamos hacer cosas mucho más complejas con HTML dinámico, todo dependerá de nuestro dominio de JavaScrpit.


Una última cosa: para simular un error hemos incluido un elemento en la lista (el último) que cuando se elige provoca un código de estado HTTP 500 en el servidor (código estándar para errores en el servidor), de modo que en el navegador se interpreta como si fuese un error en nuestra página ASPX y se fuerza así la llamada a la función de error para así poder verificarla.


En definitiva


Espero que todo esto te haya resultado interesante. Puedes descargarte el código de ejemplo para probarlo sin tener que escribirlo pulsando aquí (3,12 Kb).


Esta técnica tiene muchas aplicaciones, aunque la verdad es que queda un poco deslucida si la comparamos con las posibilidades que nos da Atlas para ASP.NET. Ahora bien, para muchos casos sencillos en los que no queramos (o no podamos) instalar Atlas o que no se justifique la carga adicional relacionada resultará una opción más simple y segura que usar AJAX «super-a-pelo» como hemos visto hace tiempo 🙂

AJAX con ASP.NET 2.0 (The "a pelo" series): Script Callbacks (II): La interfaz ICallbackEventHandler

Bueno, en el anterior post, ya hemos visto que para poder hacer uso de la característica de Callback nativa de ASP.NET 2.0 sólo hay que implementar la interfaz ICallbackEventHandler.


Ésta sólo tiene dos miembros:




  • Método RaiseCallbackEvent: Es llamado automáticamente cuando se produce un Callback al servidor mediante Script. Se le pasa como parámetro una cadena que se genera en el lado de cliente (en el navegador) antes del envío. Enseguida veremos la manera de hacerlo. Dentro de este método hacemos el procesamiento que necesitemos, por ejemplo, recibimos un identificador y vamos a una base de datos para obtener los datos de detalle de una entidad asociada. Cualquier cosa. Su definición es la siguiente:

void ICallbackEventHandler.RaiseCallbackEvent(string eventArgument)




  • Método GetCallbackResult: este es el método que se llama automáticamente para devolver los resultados al cliente. Dichos resultados se devuelven en forma de cadena (es el tipo devuelto por el método) y se pasan a una función JavaScript en el cliente. Es decir, en esta cadena podemos meter cualquier cosa en el formato que deseemos: valores separados por comas, XML, JSON, etc… Su definición es esta:

string ICallbackEventHandler.GetCallbackResult()


En la mayor parte de los artículos que hay en Internet sobre este tema viene documentado el funcionamiento de esta característica en las primeras betas de ASP.NET y eso ahora no funciona. Antes sólo había que implementar una función, que ya devolvía el resultado. Ahora son dos, por lo que os vemos obligados a usar una variable de clase, común a ambas, para devolver el resultado al cliente. Como ventaja tenemos que separamos el procesamiento de la llamda de su resultado de modo que, aunque se produzca un error en el evento, se sigue llamando igualmente a GetCallbackResult para devolver el resultado, y podemos jugar con eso.


Generar la llamada desde el cliente


Bien, ahora que ya sabemos cómo proceder en el servidor hay que proceder a provocar la llamada desde el cliente. Para ello hay que usar obviamente JavaScript, sólo que en esta ocasión no tendremos que «currárnoslo» nosotros, sino que ASP.NET proporciona todo lo necesario de manera automática. Para provocar la llamada al servidor hay que usar una función JavaScript llamada WebForm_DoCallback que toma unos determinados parámetros. Ésta está definida en uno de los manejadores AXD que ASP.NET incluye de manerta automática por nosotros y que genera JavaScript.


Eso sí, no debemos hacer uso de ella directamente. El hecho de que sepamos como se llama e incluso podamos averiguar para qué se usan sus parámetros no es motivo para que la usemos directamente. En versiones posteriores o revisiones de ASP.NET podría cambiar de nombre o de parámetros. Por eso, para evitarnos este problema, dentro de la clase ClientScript hay un método llamado GetCallbackEventReference que sirve precisamente para generar una llamada javaScript con el nombre y parámetros adecuados a esta función, obteniendo algo análogo a este código:


WebForm_DoCallback(‘__Page’,document.getElementById(‘ddlCategorias’).value,ActualizaVista,null,MuestraError,false)


Una nota importante respecto a esta función: en la mayor parte de los artículos que hay en Internet pone que GetCallbackEventReference es un método de la clase Page, cuando no es así. Desde la beta 1 de ASP.NET 2.0 esto cambió y pasó a formar parte (con muy buen criterio) de ClienteScript que sí es una propiedad de Page.


GetCallbackEventReference tiene tres versiones sobrecargadas que se pueden llamar. A la más común se le pasan los siguientes parámetros:




  • Control: una referencia al control ASP.NET que implementa la interfaz ICallbackEvetnHandler, y que obviamente puede ser la propia página actual (que hereda de Control).


  • Argumento JavaScript: la expresión JavaScript que se evaluará antes de enviar al servidor la petición y cuyo resultado es precisamente lo que recibiremos en el método RaiseCallBackEvent visto antes. Puede ser una simple cadena o número, o bien una expresión JavaScript completa que devuelva algún resultado.


  • Nombre de función JavaScript de retorno: el nombre de una función JavaScript que se llamará en el cliente cuando se devuelva la llamada del servidor. A ésta se le pasará el resultado devuelto por GetCallbackResult (una cadena), así como una variable de cadena para marcar el contexto de la llamada (información auxiliar opcional para saber desde donde se llama, como se explica en el siguiente parámetro).


  • Contexto: se trata de un identificador de contexto (puede ser una cadena cualquiera o un número, etc…) que servirá para identificar el contexto de la llamada. De este modo podemos reutilizar la misma función de cliente o de servidor (se recibe en ambas) pero tratarla de forma diferente según el contexto. Lo más habitual es pasarle un nulo.

JAX: ¡esto es SÍNCRONO por defecto!


Un momento la ‘A’ de ‘AJAX’ no es por ‘Asíncrono’. Sí. Sin embargo, por defecto, con los parámetros pasados en el método anterior, WebForm_DoCallback, hace una llamada síncrona al servidor. No pasa nada, normalmente no notaremos diferencia, pero claro, en caso de tener conexión lenta (o fallar) podríamos notar una cierta paralización de la interfaz del navegador. Por ello es recomendable utilizar una forma sobrecargada del método que nos permite especificar que sean lamadas cliente-servidor asíncronas, y que añade dos parçametros más a los cuatro que acabamos de ver:




  • Función JavaScript para errores: el nombre de una función JavaScript que se llamará de forma automática en caso de producirse cualquier error en la llamada al servidor. Toma los mismos parámetros que en el caso de la función JavaScript de retorno.


  • ¿La llamada es asíncrona?: si ponemos true será asíncrona (AJAX) y si ponemos false (valor por defecto) será síncrona.

Personalmente esta es la versión del método que uso generalmente y la que recomiendo.


Recapitulemos


Aunque todo lo explicado puede resultar un tanto lioso en realidad es muy fácil. Si lo exponemos de nuevo punto por punto lo veremos con más claridad y en el próximo post veremos un caso práctico de aplicación que lo acabará por aclarar:




  1. Definimos en el código HTML de nuestra página una función JavaScript en el cliente, que toma como parámetros una cadena con los resultados de la llamada al servidor que queremos realizar, y una variable de contexto (normalmente no utilizada). Opcionalmente


  2. Definimos un atributo para un control que, respondiendo a un evento de HTML, hará una llamada al servidor que será la que nos devuelva los resultados. Puede ser un clic, un cambio de selección, etc… Para saber qué código JavaScript debemos usar para la llamada usamos el método GetCallbackEventReference.


  3. En el servidor en uno de nuestros controles o en la propia página implementamos la interfaz ICallbackEventHandler cuyos métodos serán llamados automáticamente cuando se realice la llamada desde el cliente al servidor.

¡Listo!. Como veremos esto es más fácil de lo que parece.


Sólo dos notas antes de terminar por hoy:


· Esta técnica funciona con cualquier navegador moderno como fireFox, Safari u Opera, no sólo con Internet Explorer, como afirman algunos artículos por ahí.


· Para distinguir si una llamada al servidor (por ejemplo en Page_Load, que obviamente se llama siempre junto con los demás eventos de la página) se corresponde con una llamada AJAX cliente.servidor, la clase Page define una propiedad IsCallback que permite distinguirlo y funciona del mismo modo que el IsPostBack al que todos estamos acostumbrados.


En el próximo post haremos un ejemplo completo y proporcionaré el código fuente, dejando el tema completamente cerrado. Hasta pronto.

AJAX con ASP.NET 2.0 (The "a pelo" series): Script Callbacks (I)

Seguro que recuerdas que no hace mucho estuve haciendo en el blog una serie sobre AJAX (1, 2, 3, 4, 5, 67) «super-a-pelo», es decir, usando sólo JavaScipt y tu imaginación, nada de Atlas y compañía. La verdad es que tuvo bastante éxito y muchas visitas, referencias, trackbacks, etc…


Viendo que el tema suscita interés voy a continuarlo un poco pero esta vez haciéndolo con una nueva característica que es nativa a ASP.NET 2.0 y que se denomina Script Callbacks. Esto facilita bastante el trabajo con AJAX respecto a hacerlo todo uno mismo, pero aún así sigue siendo más complicado que usar una biblioteca estilo AJAX.NET o la propia Atlas de Microsoft que ahora está en beta. Por este motivo y dado que sigue siendo una técnica algo rupestre denominaré a esta nueva serie como AJAX con .NET: The «a pelo» series 😉


Bueno, veamos primero un poquito de teoría y en los siguientes post pasaremos ya a la práctica de esta técnica nativa de .NET a la que podremos sacar bastante partido.


La filosofía de los Script Callbacks es la que ya hemos visto con AJAX, es decir: desde el cliente se provoca una llamada al servidor (realizada con XMLHTTPRequest), el cual procesa la petición y devuelve al cliente un resultado textual que es procesado por un método JavaScript construido a tal efecto.


La diferencia principal entre la técnica que nos ocupa y lo que hemos visto hasta ahora es que nos podemos despreocupar totalmente de la complejidad inherente al manejo de XMLHTTPRequest y demás cuestiones, pues se encarga la infraestructura de .NET por nosotros de manera transparente de todo. Además en lugar de llamar a otra página del servidor llamaremos a la misma página (como si fuera un Postback) o incluso sólo a determinadas partes de ésta si implementamos la técnica en un control en lugar de en la página entera. De hecho ya hemos estudiado un caso real de uso de estas técnicas en el artículo «Funcionalidad AJAX en el control GridView de ASP.NET 2.0«, en el que se mostraban ya algunos rudimentos de la técnica viendo el código desensamblado del control GridView.


Cómo usar los Script Callbacks


Lo primero que debemos saber es que para sacar partido a esta nueva característica el control o la página que queramos convertir a AJAX debe implementar la interfaz ICallbackEventHandler. Para ello podemos incluir una etiqueta <%@ Implements interface=»System.Web.UI.ICallbackEventHandler» %> en el código HTML de nuestra página, o bien mejor (creo yo), hacer que la clase «code-beside» de nuestra página implemente explícitamente dicha interfaz:


Implementar la interfaz


Al escribir el nombre de la interfaz tras la definición de la clase veremos que en «Smart tag» asociado se ofrece la posibilidad de que se escriban las definiciones de los elementos de la misma en nuestro código para que podamos implmentarlos (tanto implícita como explícitamente).


Antes de pasar a ver con detalle esta interfaz es preciso señalar que no sólo podremos implementarla en una página que contenga controlos cuyo uso provocará llamadas asíncronas al servidor, sino que podemos crear nuestros propios controles de usuario o controles Web que implmeneten dichas interfaz y que al ser colocados sobre una página provocarán la ejecución en el servidor de sus propias llamadas, diferentes a las de la página, lo cual nos permite un gran nivel de encapsulación.


Mañana hablaré de los miembros de esta interfaz y cómo debemos usarlos en el servidor. Luego veremos la parte de cliente y un ejemplo de uso completo que se podrá descargar desde aquí.

Excelente libro: SPAM

Estos días he estado leyendo un libro que, la verdad, me ha resultado de lo más interesante y por eso lo reseño aquí. Se trata de ‘SPAM’, ISBN:84-415-1864-5 de Anaya Multimedia y autor anónimo (firma como spammer-X).


El libro habla con todo lujo de detalles y sin demasiados escrúpulos sobre el oscuro mundo del Spam y todo lo que lo rodea. Además está escrito de primera mano ya que su desconocido autor se reconoce como un experto spammer de toda la vida. Y la verdad es que es bastante verosimil ya que todo lo que cuenta se ajusta muy bien a la realidad y parece conocer perfectamente las técnicas existentes.


Se trata de un libro que explica muy bien qué es el spam, cómo se hace para ser un spammer y cómo es la economía que hay debajo de ello. Pero sobre todo es muy útil para comprender lo que hay debajo y ayuda a luchar contra él. Hay explicaciones bastante «light» con otras cuestiones mucho más técnicas pero aún así comprensibles para todo el mundo. En un apéndice final explica como defenderse del spam en Microsoft Exchange.


Hay que reconocer que el autor del libro hace bastante apología del spam, lo cual no me ha gustado, pero lo compensa con la calidad de los contenidos. En concreto el capítulo 12 qu ehabla sobre los gastos que provoca el spam no me ha gustado porque creo que está bastante alejado de la realidad y es muy sesgado, tratando de minimizar el impacto económico del mismo (por no mencionar que el mismo se contradice con sus números si éstos se escalaran a los usuarios de correo electrónico que hay en EEUU, pero bueno…)


Aunque se editó hace poco en España y en español el libro tiene ya un par de años en su edición original estadounidense, pero todo lo que cuenta sigue estando vigente.


En cualquier caso se trata de un estupendo libro que recomiendo a todos aquellos que tengan algo que ver con el negocio del correo electrónico. Yo lo he disfrutado mucho.

Esta es muy buena: producto "milagroso" que usa sin problemas Oracle y SQL Sever

¡Esta es buenísima!


La acabo de leer en los foros de The daily WTF (no me puedo quedar de Rodríguez que me vuelvo más friki que de costumbre).


Resulta que hay una empresa llamada Initech (no sé cual de las miles que aparecen en Google será porque no lo dicen) que tiene una serie de productos que trabajan sobre Oracle. La empresa sin embargo dice que soporta sin problemas SQL Server y que encima no tienes que hacer absolutamente nada para que el cambio funcione.


Uno, que ya sabe de que va esto, se imagina que lo que hará será detectar que gestor estás usando y lanzar las consultas pertinentes según sean para uno u otro, aparte de que tengan una capa de abstracción del proveedor de datos, claro..


Pues no. Resulta que tienen algo llamado «Oracle Transparent Gateway for SQL Server» que independiza todo sin problemas. Lo que pasa es que tiene ciertos «problemillas»:


– Coste:




  • Tienes que comprar el producto milgroso este que cuesta unos 15.000 dólares por cada servidor.


  • Tienes que comprar igual una licencia de Oracle (que como todo el mundo sabe si lo lees al revés dice «el caro»).

– Rendimiento (y aquí viene lo mejor): El producto lo que hace es lanzar un SELECT * contra las tablas de SQL Server que tiene que usar, y luego proceso localmente los datos para devolverlos a la aplicación que los necesita, todo ello sin índices o cachés que valgan. Una virguería…


En fin, para que veais que burradas hacemos todo el mundo de vez en cuando, pero normalmente no las cobras tan caras :-DDD


Si alguien se entera de la URL de la empresa esta que me lo haga llegar, por favor.

Acojonante: los pasaportes RFID de los EEUU pueden servir para explotar bombas

Leo en el Blog de George Ou que durante el pasado BlackHat 2006 (la mundialmente famosa y virguera conferencia de seguridad) la empresa Flexilis Inc demostró una protección inadecuada de los nuevos pasaportes basados en tecnología RFID propuestos por el gobierno de los EEUU pueden ser empleados para activar artefactos explosivos que encima sólo se activarían para ciudadanos de determinadas nacionalidades. El vídeo no tiene desperdicio:





Tanta seguridad y tanta cosa y luego resulta que pasan cosas como esta. Los que legislan no saben mucho de tecnología generalmente…

Refréscate con Windows Vista

Aunque falta bastante para que aparezca definitivamente en el mercado Windows Vista, pero el gigante de Redmond ha alcanzado un acuerdo con el fabricante de refrescos Talking Rain para incluir en sus latas el logotipo de «Windows Vista». Bajo éste se encuentra la URL de información del futuro Windows.


Mola ¿eh? 🙂


Si algún friki se hace con una que me mande un mensaje :-DD