RSS 2.0 Atom 1.0 CDF  
JASoft.org - Thursday, June 05, 2008
El blog de José Manuel Alarcón Aguín. Programación .NET y mucho más...
 

El protocolo HTTP es un protocolo sin estado. Esto quiere decir que no hay forma incluída en el protocolo para discernir una petición de otra. Por lo tanto cuando llegan dos peticiones al servidor no hay forma de saber si pertenecen al mismo usuario (ni siquiera la IP como alguna gente me dice a veces, ya que muchas personas pueden salir a Internet desde la misma dirección IP (mismo router y conexión). Además los identificacdores estáticos como ese no son fiables nunca).

Dicho esto, lo que está claro es que en la práctica sí que existe forma de distinguir que dos peticiones vienen del mismo usuario. Es el concepto que sostiene las sesiones de ASP.NET y otras tecnologías. ¿Cómo se consigue?. Bueno, existen muchas formas de hacerlo, pero la más habitual consiste en utilizar una cookie de sesión para almacenar un valor único que identifica de manera inequívoca a cada usuario. Estas cookies de sesión son realmente cabeceras HTTP que el navegador envía de vuelta al servidor en cada petición que hace al mismo. Un módulo especializado en el lado servidor lee estas cabeceras e inicializa en cada petición el contexto de la sesión correspondiente. Es por ello que luego podemos usar de manera natural el objeto Session (de la clase HttpSession), que nos da la ilusión de que disponemos de un ámbito de almacenamiento atado al usuario actual que se conserva entre peticiones. No voy a entrar en más detalles ya que cualquier programador experimentado con ASP.NET está familiarizado con este concepto.

Al trabajar con sesiones almacenamos en variables de sesión valores que queremos conservar entre peticiones para cada usuario. Para conservar los recursos del servidor estos valores se almacenan sólo durante un tiempo determindo tras el cual si no hay nuevas peticiones se eliminan. En cada nueva petición este tiempo de vida se prorroga pudiendo mantener la sesión "activa" mientras haya actividad. En ASP.NET/IIS, por defecto las sesiones tienen un tiempo de validez de 20 minutos. Si pasan más de 20 minutos desde la última petición de un usuario la sesión correspondiente a éste se termina, eliminándose de memoria toda la información acumulada.

Y ahí radica precisamente un problema muy habitual de muchos programadores, ya que al caducar la sesión de repente muchas cosas pueden dejar de funcionar, ya que información que necesitábamos deja de estar disponible. El problema no suele ser si está disponible o no, sino si no está disponible porque nunca se estableció o por que la sesión ha caducado eliminándola. Con toda seguridad cualquier programador experimentado de ASP o ASP.NET (o, incluso, otras tecnologías como PHP) se ha encontrado en una situación similar en mútliples ocasiones.

¿Existe alguna forma de determinar si la sesión actual ha caducado?

Pues sí. De hecho hay varios. Ahora voy a contar uno bastante obvio y rápido de implementar, si bien algo "pedrestre" y engorroso pues implica una coordinación entre dos partes de la aplicación.

Consiste en algo bastante obvio y que consiste en establecer una variable de sesión automáticamente al iniciar ésta (en el evento Session_Start que se lanza en ese momento). Más tarde basta con comprobar si esta variable única está establecida o no para saber si, en efecto, ésta sigue activa. Sería así:

    void Session_Start(object sender, EventArgs e) 
    {
      Session["Activa"] = true;
    }

Luego podemos comprobar si esta variable es nula o no para decidir si la sesión está activa, ya que la variable existirá siempre que exista la sesión. Muy fácil.

No obstante es un método algo "chapuzas" porque hay que acordarse de establecer la variable en el evento Session_Start en el archivo Global.asax, y luego estar leyéndola por ahi para comprobarlo.

Así que para remediarlo en el próximo post contaré la forma de averiguarlo de modo mucho más "profesional", en un método auto-contenido e independiente que para averiguarlo se basa en el funcionamiento del sistema de sesiones basado en cookies de sesión. En un siguiente post hablaré de (casi) lo contrario: cómo mantener la sesión abierta indefinidamente sin necesidad de aumentar el tiempo de sesión.

¡Hasta pronto!

Thursday, June 05, 2008 11:55:31 PM (Hora de verano romance, UTC+02:00)  #    Comments [1]   ASP.NET  |  Trackback

Hoy hace exactamente un mes que no publicaba nada en el blog. Me fastidia, y tengo muchas cosas interesantes en la recámara esperando a tener un rato para publicarlas, pero es que he tenido (y tengo) una temporada muy mala. O muy buena, según se mire.

Estoy trabajando "a dolor" en el nuevo catálogo de cursos de campusMVP, que verá la luz en làs próximas semanas. Espero que os guste, porque vamos a pegar el cambio más grande en el proyecto desde que nació. Un currazo. Ya os iréis enterando, pero os va a gustar :-) Iremos sacando varias cosas nuevas poco a poco, algunas creo que de gran interés.

Sobrecarga de trabajoTambién he estado muy liado preparando un curso de e-mail marketing que he impartido a varios clientes tanto presencialmente como en directo a través de Internet. Además he tardado más de lo normal porque he procurado ser muy ordenado y sistemático, ya que este curso constituye la base para un libro sobre el tema que hace un año que tengo en proyecto, y que espero que vea la luz antes de final de año (bastante antes espero, de hecho). Ya os lo contaré también aquí.

Además he hecho la beta de uno de los nuevos exámenes de certificación, he estado actualizando material para mis cursos on-line de campusMVP (me falta poquito para acabar), algún artículo para PC World y dotNetMania que estoy terminando también, escribiendo posts en inglés y castellano para TheEmailingExperience y otro blog que de momento es privado (y un día de estos se hará público, espero), coordinando nuevos libros de Krasis Press que verán la luz en los próximos meses, he asisitido (como alumno) un curso de 3 días sobre management en Madrid, me ha tocado el grupo de alumnos más demandante de la historia de campusMVP que me han tenido y me tienen contestando dudas duramente desde hace bastantes semanas (sois unos cracks, pero me alegraré cuando terminéis, jajaja), he estado de cumpleaños (y por lo tanto de juerga también)...

Y por supuesto tengo una empresa que dirigir y una familia a la que hacerle caso, así que como comprenderéis alguna cosa tenía que dejar un poco de lado. Y esta vez le ha tocado a este blog personal.

Desde aquí quiero pedirle disculpas también a mis trabajadores (mucho mejor dicho, mis compañeros de trabajo, sufridores de mi "hurañismo") porque no he podido hacerles apenas caso, mucho menos que de costumbre, que ya es decir. Sois unos "crases". Espero poder compensaros.

El la foto de este post no soy yo, pero podría serlo perfectamente :-)

A partir de hoy retomaré la actividad bloguera habitual (o casi) y procuraré publicar unas cuantas cosas interesantes como de costumbre.

¡Nos vemos!

JM.

Tuesday, June 03, 2008 12:17:54 AM (Hora de verano romance, UTC+02:00)  #    Comments [3]   Off-Topic  |  Trackback

Los sistemas Windows actuales son capaces de gestionar varias sesiones de trabajo simultáneas, para diferentes usuarios. Windows Xp o Vista sólo permiten una sesión interactiva al mismo tiempo pero es una simple cuestión de licencia, ya que en realidad internamente las gestionan de ese modo (de hecho existen programas en el mercado que desbloquean esta limitación). En Windows Server con terminal Services o en modo administrativo esto ya no es una limitación y se pueden tener tantas sesiones de usuario interactivas abiertas como soporte el hardware.

Puede que a nuestro programa le venga bien saber en un momento dado si un determinado usuario está con una sesión iniciada o no. O incluso obtener una lista de usuarios que están actualmente en el sistema.

La forma de conseguirlo es mediante una consulta WMI (Windows Management Instrumentation). En el siguiente fragmento se ve un método que, dado un nombre de dominio y un nombre de usuario comprueba si éste está "logueado" actualmente en el sistema:

    private static bool IsUserLoggedOn(string sDominio, string sNomUsuario)
    {
        string _dominio = "";
        string _usuario = "";
    
        ObjectQuery oQuery = new ObjectQuery("select * from win32_computersystem");
    
        ManagementObjectSearcher oSearcher = new ManagementObjectSearcher(oQuery);
    
        ManagementObjectCollection oReturnCollection = oSearcher.Get();
        if (oReturnCollection.Count >= 1)
        {
            foreach (ManagementObject oReturn in oReturnCollection)
            {
                string nombre = oReturn["UserName"].ToString();
                if (nombre.Length > 0)
                {
                    int index = nombre.IndexOf('\\');
                    _dominio = nombre.Substring(0, index).ToLower();
                    _usuario = nombre.Substring(index + 1).ToLower();
                    
                    if (sDominio.ToLower() == _dominio.ToLower() && sNomUsuario.ToLower() == _usuario.ToLower() )
                    return true;
                }
            } 
        }
        return false;
    }

Para ello se usa la clase ObjectQuery, que sirve para definir consultas WMI, y la clase ManagementObjectSearcher, que es la encargada de realizar la consulta. Ambas están en el espacio de nombres System.Management.

Ahora podemos escribir por ejemplo:

Console.WriteLine(IsUserLoggedOn("Josecoreduo", "jose"));
Console.ReadLine();

Para averiguar si el usuario "josecoreduo\jose" está actualmente autenticado en el sistema.

La consulta lanzada en realidad nos permite obtener muchísima otra información sobre el equipo de modo similar al visto, a través de los miembros de la clase Win32_ComputerSystem, incluso de equipos remotos sobre los que tengamos permisos.

Espero que os resulte útil!

Friday, May 02, 2008 5:52:29 PM (Hora de verano romance, UTC+02:00)  #    Comments [0]   Programación  |  Trackback

Leo en Engadget esto y la verdad es que me llama la atención el experimento:

"Habíamos visto esas fotos de un MacBook Pro corriendo 150 aplicaciones en Mac OS X, pero con esto demostramos que Windows no se queda atrás... (aunque sí se queda atrás, porque son sólo 108 aplicaciones). Según vemos en el video (después del salto), el ordenador que usan debe ser muy bueno (sabemos que tiene 3,25GB de RAM), porque aún con todas esas aplicaciones, la velocidad sigue siendo aceptable."

Interesante...

Thursday, May 01, 2008 9:34:06 PM (Hora de verano romance, UTC+02:00)  #    Comments [0]   Sistemas operativos  |  Trackback

Una pregunta muy típica con la que me suelo encontrar es la de: "¿Cómo puedo hacer para proteger la información de mi cadena de conexión a la base de datos si ésta la pongo en mi web.config?".

Bueno, lo primero que he de decir es que siempre conviene usar mejor la seguridad integrada de Windows (cadena de conexión con "Integrated Security=SSPI;") que las cuentas propias de SQL Sever, por lo que en ese caso no sería necesario encriptar nada. Por otro lado existe un manejador de peticiones de IIS que impide que el contenido de los archivos web.config sea accedido mediante HTTP, por lo que sólo debería preocuparnos que alguien viera nuestra configuración en caso de tener un agujero de seguridad en el servidor o bien en nuestro código (por cierto, aprende a evitarlos), en cuyo caso tendríamos un problema mucho mayor que el hecho de que sepan las credenciales de un usuario de SQL Server, que ya de por si debería estar bastante limitado en cuanto a permisos.

No obstante es interesante saber que en ASP.NET 2.0 o 3.5 podemos encriptar cualquier sección de nuestro web.config de forma sencilla y transparente para nuestro código.

Podemos hacerlo por código, pero lo más sencillo y lo que usaremos casi todas las veces es la herramienta de línea de comandos aspnet_regiis.exe, ubicado en la carpeta "C:\Windows\Microsoft.NET\Framework\v2.0.50727". Sólo hay que pasarle el tipo de proveedor de cifrado que queremos usar (-prov), el modificador "-pef" para indicar que queremos cifrar una ruta física, la sección a encriptar, y la ruta en el disco duro donde está el web.config a cifrar.

Por ejemplo:

aspnet_regiis.exe -pef "connectionStrings" "C:\miRaizIIS\MisitioWeb" –prov "DataProtectionConfigurationProvider"

Que indica que queremos cifrar la sección "connectionStrings" del web.config ubicado en "C:\MiRaiz\MiStioWeb", usando para ello el proveedor de la DPAPI (más sobre esto ahora).

De este modo obtendremos una cadena del estilo de esta:

 <connectionStrings configProtectionProvider="DataProtectionConfigurationProvider">
  <EncryptedData>
   <CipherData>
      <CipherValue>AQAAANCMnd8BFdERjHoAwE/Cl+sBAAAAt ...... +hXziceYxOxY=</CipherValue>
   </CipherData>
  </EncryptedData>
 </connectionStrings>

(he quitado la mayor parte de la cadena cifrada porque es muy larga).

Lo más estupendo de esto es que no tendremos que tocar ni una sola línea de nuestro código para que funcione, ya que ASP.NET descifra de manera transparente la cadena de conexión al leerla desde la configuración.

Con el parámetro -prov (opcional) podremos especificar el proveedor de cifrado que queremos utilizar. Por defecto se nos proporcionan dos: el mecionado "DataProtectionConfigurationProvider" que cifra usando la DPAPI (Data Protection API de Windows), o bien el "RsaProtectedConfigurationProvider", que usa una pareja de claves pública/privada para cifrar y descifrar, y es el que se usará por defecto si no especificamos ninguno. Si quisiésemos usar un cifrado propio podemos construir una clase proveedora y especificarla con -prov al usar esta herramienta.

Desde mi punto de vista es mejor usar siempre DPAPI, ya que es una criptogra´fia muy segura y está atada por completo al equipo en elq ue se ha realizado el cifrado. De este modo aunque alguien lograse leer el archivo web.config y llevárselo a otro equipo no podría descifrarlo. Por este mismo motivo, una nota de precaución: debes usar esta técnica directamente en el servidor en el que va a estar la aplicación funcionando, puesto que si por ejemplo cifras en tu equipo de desarrollo y luego lo mueves a un servidor de producción, no se podrá descifrar la sección una vez allí. Así que haz el cifrado en el equipo donde va a funcionar la aplicación.

Se puede cifrar cualquier sección del web.config, y no sólo la de las cadenas de conexión. Las únicas que nose pueden cifrar son estas:

    *  <processModel>
    * <runtime>
    * <mscorlib>
    * <startup>
    * <system.runtime.remoting>
    * <configProtectedData>
    * <satelliteassemblies>
    * <cryptographySettings>
    * <cryptoNameMapping>
    * <cryptoClasses>

Las demás no hay problema ninguno si las ciframos, y se usarán del mismo modo, siendo el descifrado transparente para el programador.

¿Y si me olvido de lo que ponía y necesito volver a tenerlas en claro?

No hay problema. Podemos usar el mismo ejecutable con la opción -pdf para descifrar:

aspnet_regiis.exe -pdf "connectionStrings" "D:\Logistia\Codigo\LogistiaWeb"

Con esto conseguiremos que la sección vuelva a mostrar su contenido en claro.

Espero que te sea útil :-)

Monday, April 28, 2008 5:35:27 PM (Hora de verano romance, UTC+02:00)  #    Comments [0]   ASP.NET | Seguridad  |  Trackback

Si hay una cosa que me revienta es que se me desordenen los accesos directos que tengo colocados en mi escritorio. Como tipo ordenado y rigoroso que soy, mis accesos directos no están colocados de cualquier forma, sino que los tengo agrupados de una manera lógica (para mi, claro), de forma que pueda encontrar rápidamente lo que busco. Lo que más tengo son accesos directos a Internet con direcciones de consulta, cosas de las que me quiero acordar, etc...

Por eso, cuando cambias la resolución, tienes un problema con los drivers de pantalla (como los que asistísteis a mi charla del lanzamiento de VS2008 recordaréis), o cualquier otra circunstancia, me paso media hora ordenandolos de nuevo. Y no estoy para perder el tiempo en chorradas. No sé cómo una cosa tan común como está no la incorpora Windows de serie. Parece mentira.

El caso es que me dió por ver si había forma de conseguirlo. Y efectivamente la hay, como era de esperar. Resulta que, nada más y nada menos que en el kit de recursos de Windows NT (ojo, NT, no ha llovido ni nada), se incluye una DLL llamada layout.dll que sirve precisamente para eso, y que aún hoy en día, tantos años después, sigue funcionando en XP o Vista sin problema. La he metido en un ZIP que puedes descargar aquí: layout.zip (4 kB). Creo que esta DLL se le atribuye al mítico Jeffrey Richter que la escribió como ejemplo de uno de sus libros.

El caso es que te bajas el ZIP, lo sdecomprimes y tienes dentro dos archivos: layout.dll y layout.reg.

Copia la DLL a C:\Windows\System32\ o la carpeta quivalente en tu sistema. Luego haz doble click sobre el archivo de registro y cuando te pregunte acepta que la información se pueda agregar al registro.

A partir de ese momento dispones de dos nuevas opciones en el menú contextual del elemento "Equipo" (o "Computer" en ingles) de tu menú de inicio, y sólo hay. Con ellos podrás guardar y posteriormente restaurar la posición de los elementos que tengas en el escritorio.

Ten la precaución de usar la opción de guardar cada vez que hagas un cambio sustancial en la disposición de elementos del escritorio o cuando añadas nuevos accesos directos.

No funciona en 64 bits

La pega de esta DLL es que sólo funciona en versiones de 32 bits de Windows. Si estás utilizando una versión de 64 bits no te servirá de nada. Por suerte un programador ¿ruso? llamado Serge Baranov, ha desarrollado una versión de esta utilidad que funciona en 64 bits, y que es la alternativa que tienes en este caso. La puedes descargar desde la página de AMIP Tools.

Espero que te resulte de utilidad.

Saturday, April 26, 2008 5:59:57 PM (Hora de verano romance, UTC+02:00)  #    Comments [1]   Sistemas operativos  |  Trackback

Hace ya un montón de tiempo (en septiembre de 2004), escribí un post, creo que interesante, sobre cómo obtener los roles a los que pertenecía un usuario de Windows.

El caso es que entonces la única manera de conseguirlo era mediante reflexión saltarse las normas de acceso a miembros para llamar a un método interno de la clase WindowsIdentity que devolvía esa información. El caso es que desde entonces no lo había vuelto a revisar (ni falta que me hizo), pero hoy uno de los alumnos de nuestro curso 70-536 de fundamentos de desarrollo en .NET para certificación, me ha hecho notar que en -NEt 2.0 y superiores ya no funciona, y además me ha sugerido la forma de hacerlo con las nuevas versiones (muchas gracias Miguel Ángel, vero que el curso te está cundiendo mucho, jeje), que sería así:

        private static string[] ListaDeRolesNET2(WindowsIdentity wId)
        {
        List<string> roles = new List<string>();
        
        foreach (IdentityReference idGrupo in wId.Groups)
        roles.Add(idGrupo.Translate(typeof(NTAccount)).Value);
        
        return roles.ToArray();
        }

Ahora está plenamente soportado por la plataforma, ofreciéndose una colección Groups que permite obtener los roles/grupos a los que pertenece un usuario en el equipo local o en un Directorio Activo.

Muy interesante. Espero que os sirva.

Monday, April 21, 2008 9:26:46 PM (Hora de verano romance, UTC+02:00)  #    Comments [0]   Programación  |  Trackback

Sin paños calientes: el sistema de Backup que trae Vista no vale para nada. Bueno, sí, vale para usuarios domésticos que no quieren ni pueden complicarse la vida. Pero en entonos profesionales es otra cosa. Parece mentira que un Vista Enterprise o Ultimate no meta otro sistema diferente.

El caso es que el sistema que trae Vista es muy sencillo d eusar pero no te deja obtener un buen control sobre lo que archivas, excluye ciertos tipos de archivos y, si no tienes instalado el Service Pack 1, no te guarda archivos cifrados con EFS (Sistema de archivos Encriptado), algo que por ejemplo yo uso cantidad, y muchos profesionales que manejan datos confidenciales (abogados, médicos, etc...) también.

La ayuda del sistema dice en concreto lo que pone la imagen del lateral.

Total, que lo que he hecho es instalar en mi Vista una copia del programa de Backup de toda la vida que venía con Windows 2000 y superiores. NtBackup.exe, vamos.

Para conseguirlo debes buscar tres archivos en la carpeta C:\Windows\System32 oo equivalente en tu XP o Windows Server 2003, en concreto:

Ntbackup.exe
Ntmsapi.dll
Vssapi.dll

Copialos a tu sistema Vista en cualquier carpeta y añade un acceso directo al EXE en tu menú de inicio.

Además hay que asegurarse de que tenemos activado el servicio "Removable Storage Management" (en castellano debe de ser "gestión de almacenamiento extraible", pero no lo tengo en castellano a mano para comprobarlo). Para ello te vas a Panel de Control·Programas·Activar desactivar componentes de Windows, y lo activas en la lista que te aparece. Es necesario hacerlo para usar cintas y otros medios extraibles, y además si no lo activas te dará una advertencia cuando arranques NTBackup.

Con esto estará listo y podrás hacer copias mejores desde Vista.

Otro detalle: Si no instalas el programa en C:\Windows\System32, cuando programes una tarea de backup periódica te fallará. El motivo es que el programa mete la tarea programada partiendo de la base de que está en la carpeta de sistema, y tendrías que cambiar la ruta a mano. Un fallo tonto de los programadores, que no les costaba nada usar la carpeta en la que se encuentre el ejecutable.

Friday, April 18, 2008 11:41:53 AM (Hora de verano romance, UTC+02:00)  #    Comments [0]   Sistemas operativos  |  Trackback

Esto va a ser polémico, como no... pero un informe que acaba de sacar (ayer) la prestigiosa empresa de investigación Forrester Research concluye que Vista es el único S.O. viable para implantar en grandes empresas, y que todas deberían ir migrando hacia él pronto, dejando de lado a Mac y a Linux.

El inform se titula "Building The Business Case For Windows Vista, Five Reasons To Start Your Company's Migration Soon" estudia las formas de implantar los distintos SO en las empresas, sus pros, sus contras, etc.. y lega a la conclusión de que, por muchas razones, las grandes empresas deben migrar hacia Vista cuanto antes. Por ejemplo, dicen cosas ta directas como esta:

"Para grandes emrpesas no hay otra opción viable"

Dicen que con el SP1 de Vista las migraciones están empezando a acelerarse. Con respecto a Mac y Linux dicen:

"Estos SO han encontrado su nicho en ciertas industrias Por ejemplo Apple en marketing e investigación científica así como en el sector sanitario y retail. Novel (Suse), Red Hat y Ubuntu se usan mucho en servicios financieros y agencias gubernamentales. Pero cambiar miles de usuarios de golpe de Windows a uno de estas plataformas es simple y llanamente inviable."

No se meten en cuestiones de características, si es bonito o menos bonito, etc, sino en cuál es más viable tener instalado y funcionando en entornos grandes, donde una configuración o migración "de uno en uno" no es una opción.

Este siempre ha sido uno de los grandes problemas de Linux y otras aplicaciones Open Source, como Firefox u Open Office: no se trata de que sean mejores o peores (yo soy un enamorado de FireFox, uso algo Ubuntu Linux, y me horroriza Open Office), sino de sí ofrecen el nivel de gestión y operaciones que una empresa mediana/grande necesita.

Desde mi punto de vista eso es en lo que más deben trabajar, antes que en cualquier otra cosa.

Thursday, April 17, 2008 8:10:01 PM (Hora de verano romance, UTC+02:00)  #    Comments [2]   Sistemas operativos  |  Trackback

Se trata este de un truco sencillo, pero aún así interesante ya que mucha gente tarda en darse cuenta de cómo solucionarlo.

El problema surge cuando usas un control DataSource del tipo que sea (ObjectDataSource, SqlDataSource, LinqDataSource, etc...) y lo enlazas con un DropDownList para mostrar una lista de valores para elegir, por ejemplo, la categoría de productos a mostrar en otro control GridView. El origen de datos te devuelve sólo los diferentes valores de categorías disponibles en la base de datos, pero lo habitual es que además de una categoría (o lo que sea) concreta, desees dar una opción o dos por defecto, por ejemplo "Ver todas" y "Ninguna". Pero claro el control de origen de datos no tiene esas categorías inexistentes contempladas, así que ¿cómo haces?

Pues muy fácil, pero hay que saber un truquillo: la propiedad AppendDataBoundItems del control DropDownList.

Si la estableces a True lo que consigues es que cualquier elemento que coloques en lalista en tiempo de diseño se conserve (en los primeros lugares además) aunque le añadas dinámicamente otros en tiempo de ejecución con el control de origen de datos. Así, basta con que añadas un par de elementos como los del ejemplo, según tus necesidades, para tener disponibles más opciones adicionales en la lista desplegable.

Sencillo pero útil :-)

Tuesday, April 15, 2008 4:54:18 PM (Hora de verano romance, UTC+02:00)  #    Comments [1]   ASP.NET  |  Trackback
Copyright © 2008 José Manuel Alarcón Aguín. All rights reserved.