SQL Server Compact Edition, Buenas prácticas…

Desde el pasado mes de abril hasta hoy he realizado varias charlas y he mantenido algunas conversaciones acerca de SQL Server Compact 3.5. De todas ellas, lo que más me ha sorprendido es que aún se relaciona la edición Compact con la antigua SQL Server CE y por consiguiente se da por hecho que el uso de base de datos SQL Server Compact está únicamente restringida a plataformas Windows CE. Lo cierto es que una de las características que, bajo mi punto de vista, va a suponer un antes y un después es precisamente que éstas puedan ser utilizadas tanto en plataformas Windows Desktop y Windows CE desde su aparición «como tal» a partir de la versión 3.1 (codename Everywhere).


SQL Server Compact 3.5 es un gestor de base de datos relacional orientada específicamente para cliente ligeros (SmartClients) en sistemas ocasionalmente conectados. De hecho, los Servicios de Sincronización para ADO.NET (Sync Services for ADO.NET) fue presentado junto a las primeras betas como versión 1.0 (fuera del runtime de MSF). El objetivo era el de presentar una tecnología que, pese a que despunta por su alta -relativa a las tecnologías actuales- flexibilidad, pretende marcar un antes y un después en soluciones de sincronización para cliente ligeros con bases de datos Compact. ClickOnce es otra tecnología de despliegue específica para este tipo de clientes.


En realidad todo esto son piezas tecnológicas cuya sinergia conjunto derivan en un potente conjunto de herramientas de desarrollo que facilitan la creación de soluciones ocasionalmente conectadas junto con todos los aspectos, peculiaridades y características que presentan.


Probablemente la pieza angular esta situada en la propia base de datos, un «simple» archivo sdf del cual recae todo -o una parte muy importante- del peso de la solución. El modelo de desarrollo empleado para este tipo de bases de datos no es muy diferente al que utilizamos habitualmente en aplicaciones escritorio pero sí tiene su peculiaridades, de hecho, es una base de datos que puede ser utilizada en una aplicación para Windows Vista y Windows CE, o lo que es lo mismo .NET Framework y .NET Compact Framework, luego si existen estas peculiaridades y la madurez de la tecnología actual lo permite, ¿porque no crear componentes de acceso a datos multiplataforma genéricos?, esto es, para .NET Framework y .NET Compact Framework.


En realidad esto tiene sus pros y sus contras, evidentemente. .NET Compact Framework es aproximadamente la equivalencia del 30% de .NET Framework y afrontar el desarrollo de componentes multiplataforma es posible, con sus «peros«, pero posible. Un ejemplo lo tenemos en el uso de operaciones transaccionales, como novedad desde la versión 3.5 éstas pueden residir bajo ámbitos establecidos por el administrador de transacciones ligeras (Lightweight Transaction Manager) a través de las clases expuestas en System.Transaction, sin embargo, únicamente bajo plataformas Windows Desktop; he aquí un ejemplo de «peculiaridad para el código multiplataforma».


Pese a que SQL Server Compact no ha sido concebida como base de datos de gran capacidad de almacenaje y procesamiento no debemos descuidar la escalabilidad de la aplicación, conocer qué tipo de índices están disponibles y como sacar el máximo partido de ellos de cara a facilitar la tarea al optimizador de consultas, así como conocer, mínimamente, las diferencias de éste respecto su hermano mayor. Una característica que me gustaría destacar es que SQL Server Compact ofrece unas propiedades de gestión de excepciones, a través de las clases específicas distribuidas dentro de System.Data.SqlClientCE, basadas en códigos de errores nativos tipificados y errores HResults, propagados desde las capas más bajas de abstracción del Sistema Operativo, que bajo mi punto de vista son excepcionales si sabes cómo manejarlos.


Durante los más de 14 meses en los que estado inmerso en el estudio y búsqueda de modelos de desarrollo específico para SQL Server Compact, he tratado de sintetizar lo más importante para que el desarrollador iniciado con el este tipo de bases de datos parta con cierta ventaja antes de sus desarrollos, plasmándolo en un libro electrónico de poco más de 110 páginas y cuyo editor, SolidQ@Press, ha editado y ya está disponible.


Desarrollo de aplicaciones con SQL Server Compact Edition: Buenas Prácticas, no pretende ser un guía de referencia, sino un libro vertical, que trata todas y cada una de los aspectos más destacados que hay que tener en cuenta para la creación de aplicaciones consumidoras de la ‘mini’ de la familia SQL Server, de forma directa, llana y sin introducciones.

Miguel Llopis en Igualada [CatDotNet]

¡Pues sí! El proximo viernes dia 5 de setiembre tendremos el placer de contar con Miguel Llopis, antes de que éste comience su andadura por tierras norte americanas y finalice sus mericidas vacaciones.


Para todos aquellos que les quede a «tiro de piedra» Igualada y que deseen escuchar de primera mano todo lo relacionado con OSLO, estaremos en el Centre Serveis d’Empreses a las 19h.


¡¡Salud!!


 

Mi primer libro: SQL Server Compact 2008

¡Al fín! Después de más de un año de trabajo, en la que de forma solitaria empecé a escribir una referencia, un tutorial o sencillamenteunas notas sobre la nueva versión de SQL Server Compact 3.5 que posteriormente ha acabado en un libro, con la editorial de referencia para tecnologías .NET, Krasis Press.


¿Que deciros del libro? Pues se trata de una referencia completa de SQL Server Compact 3.5, incluyendo las futuras características del SP1 que aparecerá junto al de Visual Studio .NET 2008. He tratado plasmar que es realmente una base de datos SQL Server Compact, cuáles son su características diferenciales que la hacen única en la plataforma .NET de Microsoft, qué la diferencia de otras ediciones cómo SQL Server Express así como todo lo referente a la sintaxis T-SQL y desarrollo de aplicaciones con ADO.NET y los mecanismos de sincronización existentes.


 Agradecer, por último, a todos los que me han ayudado en esta obra, de una forma u otra, empezando por Fernando Bocigas, Jefe de Producto SQL Server de Microsoft Ibérica, quién además ha enriquezido la obra con el prólogo. A José Manuel Alarcón, Paco Marín, Marino Posadas, Unai Zorrilla, Francisco Otero, Francisco Javier Buzón, Santi Balboa, Eladio Rincón, Cristina González [MVP Lead], Ramón Bosch, Lleonard del Río, Pep Lluis Baño y al equipo de desarrollo de SQL Server Compact. ¡Gracias a todos!


Aquí os dejo más info del libro:


SQL Server Compact 2008 SP1 Referencia Completa









Microsoft SQL Server Compact 2008 SP1: Referencia Completa


José Miguel Torres
(Device Aplication Development MVP)


Editorial Krasis Press
426 páginas
Tapa Blanda
17,50 x 24,80 cm.
ISBN: 978-84-935489-4-0


Esta obra pretende ser una referencia completa que dé a conocer al lector de una forma directa las muchas posibilidades que ofrece SQL Server Compact 3.5, ya sean para aplicaciones Windows como de dispositivos Windows Mobile o Tablet PC, desde los fundamentos de las bases de datos embebidas hasta su aplicación en entornos distribuidos y sistemas ocasionalmente conectados, además de:




  • Familiarizarse con los componentes que conforman SQL Server Compact 3.5 así como herramientas y utilidades relacionadas.


  • Conocer cómo funciona una base de datos SQL Server Compact y sus características diferenciales.


  • Crear, administrar y manipular bases de datos mediante herramientas de administración con el uso de formularios y asistentes así como una guía completa de la sintaxis T-SQL soportada.


  • Conocer los mecanismos de bloqueo y las nuevas aportaciones en contextos transaccionales.


  • Desarrollar aplicaciones para Windows Mobile y Windows Desktop con ADO.NET 3.5 de forma eficaz.


  • Describir las características de los mecanismos de sincronización compatibles; cuál utilizar y porqué.


  • Utilizar la réplica por mezcla y el acceso remoto a datos (RDA), desde sus fundamentos, paso a paso.


  • Incluye las novedades reciéntemente aparecidas en el Service Pack 1.

Técnicas de Test Extremo a la vieja usanza….

Dentro del ámbito industrial/empresarial el uso de dispositivos móviles o PDA requieren de unos requisitos que por naturaleza no llegan, ni de largo, los típicos dispositivos que llevamos, hoy en dia, en nuestro bolsillos, en términos de duración de bateria, soporte contra caídas, lluvia o ambientes «sucios» de partículas.


Los dispositivos rugerizados se catalogan mediante el estándard IP (Ingress Protection) el cual:




  • evalúa de un 0 a un 6 el soporte a la dispersión de partículas sólidas (aka polvo), siendo 0 algo así como No Protección y 6 Dust Tight, el cual certifica que un dispositivo puede trabajar en ambientes muy cargados de partículas.


  • por otro lado, evalúa de un 0 a un 8 el soporte de agua, siendo 0 No Protección y 8 Protección a Inmersión completa. 

Para las PDAs industriales la típica certificación es IP54 o IP64, la cual permite la protección contra el polvo y las salpicaduras de agua. Además, estos dispositivos soportan la caída sobre hormigón desde 1,20 metros.


Por lo visto, además de la terminología y estandarización – hay más -, las pruebas que realizan los fabricantes están basadas en los principios de Pirron, al estilo empírico extremo, y si no mirad el siguiente video sobre el motorola (Symbol) MC9090 que he encontrado, (puestos a filosofar), causalmente.


 

Usando ActiveSync (& WDC) con Certificados de Seguridad de Exchange

Conectando con un emulador y configurarlo con Exchange a través de ActiveSync


Si configuramos un emulador de Windows Mobile 6 para conectarlo a través de ActiveSync (o Windows Device Center) a un servidor Microsoft Exchange, los típicos pasos a seguir serían:


1.       Abrir/Conectar Device Emulator Manager con el emulador deseado.


2.       Configurar ActiveSync o WDC para aceptar conexiones DMA.


3.       “Colocar en la base” [AKA Cradle] el emulador a través del Device Emulator Manager.


4.       En el asistente de configuración de la conexión, cuando nos pide la información de conectividad con Exchange indicar:


a.       Nombre del servidor Exchange en FQDN. (p.e. servidorEXCH.midominio.com)


b.      Uso de SSL


c.       Nombre de usuario/contraseña válida para el dominio activo.


d.      Elementos a sincronizar (correo, contactos, tareas…)


5.       Una vez configurado, si ante la primera sincronización obtenemos el siguiente error:



6.       Nos dirigimos al emulador, y en la información de estado (status) de ActiveSync de la última sincronización veremos el código de error en “View support code” dónde encontraremos el código de error exacto. En el caso que el error haga referencia a la ausencia de un certificado, el código será: 0x80072F17 cuya descripción es:
Unspported Digital Certificate installed. If you installed a digital certificate that supports wildcards from a certifying digital certificate provider, this certificate will install however using the certificate is not supported.

a.       NOTA: Otro tipo de error muy común en entornos corporativos (Sobre todo con ISA Server) es el 0x85010008:
Proxy authentication is required for HTTP communication or protocol to proceed.
En este caso se debe configurar el proxy a través de Configuration/ Connections / Proxy / HTTP -> Menu / Edit y probar hacer un ping al servidor en cuestión. (Para hacer un ping desde WinMobile utilizar la utilidad de
Alejandro Mezcua para hacer un ping desde .NET Compact Framework)


7.       Para solucionar el error del punto 6, deberemos crearnos un certificado digital, instalarlo en el emulador.


Creando certificados digitales en xml para Windows Mobile 5.0 y superior



SSLChainSaver 2.0 es una herramienta creada por Scott Yost, cuyo objetivo es el de diagnosticar y/o reparar problemas de conectividad vía SSL desde Windows Mobile.


Una vez nos descargamos SSLChainSaver y la instalamos, encontraremos el ejecutable SSLChainSaver.exe en C:Program FilesMicrosoft SSL ChainSaver, por defecto.


1-      Abrimos una sesión con la línea de comandos.


2-      Nos ubicamos en el path target: C:Program FilesMicrosoft SSL ChainSaver


3-      Ejecutamos lo siguiente:
C:Program FilesMicrosoft SSL ChainSaver>sslchainsaver mail.company.com




4-      Importante en el punto anterior:


a.       Conocer (obviamente) el servidor de Exchange y…


b.      Exponerlo en FQND, sin /Exchange. (Por ejemplo la que utilizamos para acceder mediante OWA).


5-      Esta instrucción (punto 4) genera 2 archivos y una carpeta:

a.       Carpeta C:Program FilesMicrosoft SSL ChainSavermail.company.com con el archivo root.cer.b.      Dos archivos en C:Program FilesMicrosoft SSL ChainSaver                                                               i.      mail.company.com.wm5.xml -> Para Windows Mobile 5                                                             ii.      mail.company.com.wm6.xml -> Para Windows Mobile 6 y 6.1

6-      Renombramos  el archivo “mail.company.com.wm?.xml” (? -> según nuestra versión) a “_setup.xml”.


7-      Seguidamente lo empaquetamos en un CAB, por ejemplo, utilizando makecab utility:
C:Program FilesMicrosoft SSL ChainSaver>makecab /d compress=off _setup.xml correo.cab


8-      Copiamos el archivo cab, en este caso correo.cab, al dispositivo móvil  y lo ejecutamos.


9-      Nos aseguramos que en Configuration / Security / Certificates / Root aparece el certificado que hace referencia al servidor Exchange.


10-   Ahora ‘Quitamos de la base’ [Uncradle] y volvemos a ‘Colocar en la base’ el emulador a través de Device Emulator Manager.


11-   Tras sincronizar ya tendremos acceso al servidor Exchange a través de ActiveSync.


  

 

Uso de RAISERROR desde SQL y gestión de errores desde ADO.NET

Existen multitud de formas de manipular los errores o excepciones desde llamadas en código administrado a procedimientos almacenados (SP en adelante) a través de ADO.NET. Quizás la peculiaridad reside en la responsabilidad que le otorguemos a los SPs.


Desde la versión SQL Server  2005, y con el uso de TRY…CATCH podemos capturar y tratar un error de la siguiente forma.

BEGIN TRY

END TRY
BEGIN CATCH
 

END CATCH


Sin embargo la no debemos olvidar el cómo devolvemos/notificamos un error desde el TRY…CATCH a la llamada realizada desde código administrado.


Devolver el error como resultado


Una opción sería la de retornar la descripción de las propiedades del error producido como resultado como sigue:

BEGIN TRY

END TRY
BEGIN CATCH

SELECT  ERROR_NUMBER()  AS ErrorNumber,     
      ERROR_SEVERITY()  AS ErrorSeverity,
      ERROR_STATE()     AS ErrorState,
      ERROR_PROCEDURE() AS ErrorProcedure,
      ERROR_LINE()      AS ErrorLine,
      ERROR_MESSAGE()   AS ErrorMessage;
END CATCH

Esta forma devolverá una fila de 6 columnas. El principal problema reside en que para la clase que realiza la llamada al SP le constará como que se ha ejecutado correctamente. Además si la llamada se realiza mediante un DbCommand mediante ExecuteScalar únicamente se obtendrá el número de error (primera columna). Por otro lado si el objetivo del SP es el de insertar, eliminar o modificar un conjunto de datos lo único que deberíamos esperar del SP es que nos dijera, en el caso que ha ido correcto, el número de filas afectadas, si se da el caso. En mi opinión, esta es una mala opción y se debería obviar. Además su detección desde la aplicación cliente es confusa.


Devolver el error como mensaje y generar excepción


La opción más correcta elegante es mediante el uso de RAISERROR dentro del CATCH. Sin embargo, para comprender el funcionamiento de esta función deberíamos, en primer lugar, conocer la anatomía de un error en SQL Server.


Anatomía de un error


La información que obtenemos a través del SQL Server Management Studio, en forma de texto es la interpretación que  éste hace de la información enviada por SQL Server a través de varios componentes que establecen sus propiedades.


Message number – Cada error tiene un número identificativo. Los mensajes producidos por el usuario a través de RAISERROR tienen un valor por defecto de 50000. A partir de 50001 en adelante se pueden configurar mensajes de error específicos en sys.messages.

USE master
GO 
EXEC sp_addmessage @msgnum = 600001,
      @severity = 15,
      @msgtext =  ‘Indicated time %s is not allowed.
                        Transports services are only available from
                        09:00AM until 05:00PM.’
      , @lang =         ‘us_english’
      , @with_log =     ‘FALSE’
GO 
EXEC sp_addmessage @msgnum = 600001,
      @severity = 15,
      @msgtext =  ‘La hora %s indicada no es válida.
                        Los servicios únicamente estan disponibles
                        desde las 9h hasta las 17h.’
      , @lang =         ‘Spanish’
      , @with_log =     ‘FALSE’
GO 

Severity level – Importante pues determinará el comportamiento del sistema en base a la severidad del error.



































TABLA 1: RAISERROR Severity Categories
Severity Range Error Number Info @@ERROR Logged As
1 hasta 9 In black NOT SET Informational
10 Not provided NOT SET Informational
11 hasta 14 In red SET Informational
15 In red SET Warning
16 In red SET Error
 

State – Los valores son de 1 a 127.  Se sabe que cada mensaje tiene un estado determinado pero Microsoft no lo ha documentado. Un estado 127 significa que el cliente se ha desconectado sin embargo esa información es trivial puesto que una severidad superior a 18 implica el mismo comportamiento nosotros.


Procedure – En qué objeto (contenedor del T-SQL) se ha producido.


Line – La línea en que se ha producido.


Message text – La descripción del error o mensaje.


Volvamos a la captura del error pero ahora utilizando RAISERROR:

BEGIN TRY     
   SELECT 1/0
END TRY
BEGIN CATCH

— Snippet de los BOL de SQL Server.
DECLARE @ErrorMessage NVARCHAR(4000);
DECLARE @ErrorSeverity INT;
DECLARE @ErrorState INT; 
SELECT     @ErrorMessage = ERROR_MESSAGE(),
    @ErrorSeverity = ERROR_SEVERITY(),
    @ErrorState = ERROR_STATE(); 
RAISERROR (@ErrorMessage, — Message text.
           @ErrorSeverity, — Severity.
           @ErrorState — State.
           ); 
END CATCH

Este es un ejemplo de control de error no esperado mediante RAISERROR. La peculiaridad reside que en desconocemos la severidad del mismo. Según la Tabal 1, si la severidad es inferior o igual a 10, desde la llamada cliente NO se producirá ninguna Excepcion. Sin embargo si es superior sí; ejemplo:

try
{   
   //lanzamos el SP
   
   res = dbCommand.ExecuteNonQuery();
}
catch (SqlException sqlex)
{   
   
//la severidad es superior a 10, luego entra aquí.
}
catch (Exception ex)
{
    //otra excepción no controlada a nivel de aplicación.
} 

El problema está que ante un error de severidad leve (10), como por ejemplo, un error 718 producido por:

708         No hay suficiente espacio de direcciones virtuales en el servidor o no hay suficiente memoria virtual en el equipo. Se ha usado la memoria reservada %1! veces desde el inicio. Cancele la consulta y vuelva a ejecutarla, reduzca la carga del servidor o cancele otras aplicaciones.

El SP se ejecutará correctamente sin embargo la única forma de obtener ese mensaje desde  ADO.NET es suscribiéndonos al evento InfoMessage del objeto DbConnection.

conexion.InfoMessageConnection += new System.Data.SqlClient.SqlInfoMessageEventHandler
                                                          (conexion_InfoMessageConnection);
 void conexion_InfoMessageConnection(object sender, System.Data.SqlClient.SqlInfoMessageEventArgs e){
{
      //aquí obtenemos el mensaje
      string res = e.Message;
} 

Para los errores de severidad 19 o mayor se exige que:


          En la llamada a RAISERROR se especifique la opción WITH LOG.


          Los autores pertenecen la función sysadmin.


Un ejemplo:


Esta  sentencia no dará error pero no guardará LOG en el visor de sucesos.


RAISERROR(‘esto es una prueba’,15,217)


Esta otra guardará una entrada en el visor de sucesos como Warning (TABLA 1)


RAISERROR(‘esto es una prueba’,15,217) WITH LOG


Esta es idéntica a las anteriores pero se procesa como Error no como Warning.


RAISERROR(‘esto es una prueba’,16,217)


RAISERROR(‘esto es una prueba’,16,217) WITH LOG


La siguiente sentencia NO funcionará:


RAISERROR(‘esto es una prueba’,19,217)

Sin embargo la siguiente si

RAISERROR(‘esto es una prueba’,19,217) WITH LOG


Los resultados en el visor de sucesos:

Error      08/05/2008 12:09:55       MSSQL$$$$$$$$$            17063    (2)
Advertencia       08/05/2008 12:05:46       MSSQL$$$$$$$$$            17063    (2)
Error      08/05/2008 12:05:12       MSSQL$$$$$$$$$            17063    (2)


 

Cliente SQL Server Express para Sync Services para ADO.NET


Acaban de anunciar, en el blog del equipo de desarrollo de MS Sync Framework, un ejemplo (en CodePlex) de cómo utilizar SQL Server Express para a sincronización mediante Sync Services for ADO.NET.


 Pese a que muestra una clase que imementa de ClientSyncProvider, el ejemplo nos permite ver toda las complejidad ( y consiguiente flexibilidad ) que esconde el proveedor local de sincronización. Hasta ahora el único cliente específico que incorporan los servicios de sincronizción es para la edición Compact de SQL Server a través de la clase SqlCeClientSyncProvider, la cual nos resuelve toda la complejidad. De todas formas, la especificación del proveedor para SQL Server Express nos puede servir de guía para el desarrollo de otros tipos de proveedores.


 Por último, recordad que la RC0 de los servicios de sincronización se presentan con el RC0 de SQL Server 2008.

[OT]: Como la ignorancia hace echar al trasto un test de horas…

Ayer por la mañana, depués de ensamblar todas «las piezas» de un conjunto de servicios y «procesos» que llevávamos desarrollando una semanas, nos dispusimos a realizar una prueba de rendimiento (sobre colas Service Broker), mis coleguitas de oficina Santi y Pablo. Después de unas horas, a eso de mediodia, Santi salió a fumar y yo aproveché para tomarme un cafelito (el tercero del dia). Al volver al puesto de trabajo me encuentro en el ordenador dónde estábamos realizando las pruebas, un pantallazo «azul de la muerte» o como se llame. Pablo y yo quedamos boquiabiertos; además el equipo se reiniciaba automáticamente y justo antes del login,,, pantallazo azul…


 


Lo cojonudo es que tratamos de mover el ratón pero no tocamos ninguna tecla, con lo que decidimos apagar el PC directamente al ver que no respondía.


Cuando volvió Santi y le explicamos lo ocurrido no se le ocurrió otra cosa que partirse lo que viene siendo la caja el mu ca…. Evidentemente todo el proceso (que llevaba horas) se había ido a tomar concurso, con lo que su actitud nos desconcertó del todo. Cuando acabo, (con lágrimas en los ojos) nos dijo que era un protector de pantalla, que lo único que teníamos que hacer era tocar una tecla y ya está….


Pues ni tocamos ninguna tecla, ni nos dimos cuenta que para apagar el PC tuvimos que presionar el botón de apagado durante unos segundo y lo más grave, que cuando aparece un pantallazo azul, el PC no se reinicializa solo. Ay que ser jili… (con j)


Maldita la gracia y viva nuestra estupidez…


Moraleja: No se perdió ni un solo mensaje del SB. Prueba de carga y recuperación ante catástrofe: todo un éxito.

Liberado Microsoft Sync Framework RC0

Liam Cavanagh ha anunciado el blog oficial del equipo de desarrollo la presentación de MS Sync Framework en la RC0 del SQL Server 2008 que ya está disponible para suscripciones MSDN.


Durante la instalación de SQL Server 2008, se nos da la opción de instalar MS Sync Framework. La versión que se presenta es, asismiso, una Release Candidate 0 de MS Sync Framework 1.0 y Sync Services for ADO.NET 2.0.


 Pues nada, esto parece que empiezar a tomar forma y posiciones. Hay que estar al tanto a esta tecnología; la verdad es que promete 😉



 

El alegre bandolero….

Muy buenas a todos, me presento,


Me llamo José Miguel y trabajo en el dept. Tecnologias de la Información de M R W en la Central de Barcelona. Llevo escribiendo en diversos medios desde el 2001 primero en SoloProgramadores y luego en AlgorimoDigital y dotNetMania además de llevar el sitio desarrolloMobile.NET y un viejo blog, tengo un par de libros (un eBook y otro paperback) en el horno.


En lo personal, soy de Igualada y me gusta dedicar dos horas diarias en desplazamientos al curro en mi coche [atascos incluidos]. Digo me gusta pues es el único momento de reflexión en todo el día, con una cajetilla de Winston(1) y la voz del Jeros de fondo. Paso de la política, la pestañí pulisia y de cualquier forma de hipocresía. Me gusta la aeronáutica, la tecnología, la cerveza y las mujeres (2); hago milagros, convierto el agua en vino y me resucito si me hago un ….


un saludo a todos!!!!


(1) Estoy en camino de dejarlo por decimosexta segunda vez, el ultimo intento en el pasado Summit de Seattle. ¿La excusa? éste y éste, malas influencias… 😉


(2) Bajo mi punto de vista esta todo relacionado.