Take A Photo – Demo

Hace unos meses publiqué un plugin para tomar fotos instantáneas desde una página web, usando Flash y un plugin para Ruby on Rails.

Hoy me puse un rato a jugar y armé un demo donde se pueden tomar fotos (ojo que todo es público :D) : TAP.

Las fotos se borran una vez por día y acepta un máximo de 50 fotos por día (para evitar que me llenen el disco). Tengo algunos TODOs que iré viendo de resolver en los tiempos libres (como cambiar el tamaño de la foto, recortar, aplicar efectos, etc).

Necesita Flash 9 o superior y una web cam para que tenga sentido :). Todavía sigo peleando con el Flash player de Linux y la camarita, sorry :S.

Les recomiendo verlo en Firefox, no me gasté en ver si en IE el CSS no se rompe y no creo que lo haga nunca.

JoinPoint Language Definition

Luego de unos 15 días intensos sobre mi tesis ya tengo andando una pequeña parte andando de lo que será la nueva API, funcionando e integrada con el JIT.

Antes de comentar como funciona vamos por el primer ejemplo que consta de dos partes. Por un lado una clase común y corriente que simularía ser la aplicación :

using System;
public class Normal
{
    public Normal()
    {
        Metodo1(26);
    }

    public void Metodo1(int i)
    {
        Console.WriteLine("Aca");
    }

    static public void Main(string [] args)
    {
        new Normal();
    }
}

Y por otro una clase que solo tiene definiciones de JoinPoints (pueden estar mezcladas, no hace falta separarlo)

using System;
using Weaving;
public class Unused
{
     [RunBefore, JoinPoint("void", "Normal", "*", ParameterFlag.MATCH_ANY)]
     public void Logger(int i, Context c)
    {
        Console.WriteLine ("Called Before with param "+i.ToString());
    }
}

Lo importante de esta segunda clase son los Attributes que se le agregan a los métodos (en adelante los llamaremos callbacks). RunBefore lo que le indica es cuándo se debe correr el callback : en el ejemplo significa que debe ser antes de la ejecución del JoinPoint (sería el equivalente del BeforeAdvice de AspectJ).

El Attribute JoinPoint lo que hace es materializar el JoinPoint en el JIT, para que el RunBefore lo pueda encontrar. Los parámetros que recibe son (cualquiera de las regex soporta los wildcards ‘*’ y ‘?’) :

  • Return Type regex
  • Class Name regex
  • Method Name regex
  • Flags

Para completar el regex contra el que se matchea, el Weaver toma los argumentos del Callback, en este caso lo que se intenta es anticipar la llamada de cualquier método de la clase Normal que reciba un int como primer parámetro y cuyo return type sea void. El Flag MATCH_ANY indica que pueden haber otros parámetros, pero son ignorados por el callback. Si especificáramos MATCH_EXACT estaríamos buscando un método que tenga exactamente un argumento de tipo Integer.

El útimo parámetro (Context) no se usa para el matching y es donde el callback recibe información del contexto sobre donde se está ejecutando (instancia interceptada, método interceptado, etc).

Si compilamos y ejecutamos el ejemplo veríamos algo como lo que sigue :

[mono] ~/src/ejemplos @ gmcs -out:Normal.exe /r:Mono.Weaving.dll Normal.cs Unused.cs 
[mono] ~/src/ejemplos @ mono Normal.exe
(1) [JIT] class Weaver loaded
(2) [CS] ASSEMBLY LOADED: Normal, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
(3) [JIT] New pattern Defined : void Normal:* (int)
(4) [JIT] Matched void Normal:Metodo1 (int) with void Normal:* (int)
(5) [JIT] No instance object found. We need to create one
(6) [JIT] I'll run callback Unused:Logger (int,Weaving.Context) over instance pointed at 0x62f90
Called After with param 26
Aca

Como se puede apreciar, antes de ejecutar el método Metodo1 se ejecutó el callback y recibió correctamente el parámetro original. Cabe aclarar que el weaving se está haciendo a nivel del JIT, intercalando el assembler generado para la plataforma donde se ejecuta, como expliqué en el pasado.

Paso entonces a describir un poco como funciona. Para empezar hay 2 partes, una en código manejado y otra en el JIT (CS y JIT en el output). La parte manejada se usa solamente para detectar cuando un nuevo Assembly es cargado, via AppDomain.CurrentDomain.AssemblyLoad, y ahí por Reflection se leen todas las clases que hay en el Assembly, se escanean los metodos buscando los joinpoints y se llama un método interno del JIT que es quién finalmente define el nuevo joinpoint en la VM.

Esto esta así porque averiguando como hacerlo directo en C encontré varias referencias en la lista de Mono de que el loader en C es muy complejo (haciendo un trace pasé como por 20 funciones).

Como el weaver debe existir antes de ejecutar la aplicacion, el JIT carga el Assembly Weaving.dll desde el GAC antes de cargar el .exe que se va a ejecutar y justo después de cargar el corlib (que debe ser cargada primero que nadie). Luego una instancia de Weaving.Weaver y la mantiene viva por el resto del ciclo de vida de la aplicación.

Cuando el Loader detecta el Attribute de JoinPoint se llama a Weaver.DefineMethod que se mapea a una
función en C. Ésta es la que emite el mensaje (2) creando la regex y guardando toda la metadata necesaria para ejecutar el matcher después.

Otra tarea del loader es detectar si la sintaxis del callback es correcta, por ahora se valida lo siguiente :

  • Context no definido : Advice need at least one parameter of type Weaving.Context
  • Context de tipo inválido : Advice last parameter type XXXXX. Expected Weaving.Context
  • Callback no puede ser abstracto : Abstract Method can’t be advices
  • Callback no puede ser un constructor : Constructors can’t be advices

Cabe destacar que estas exceptions no pueden ser capturadas en un try/catch y hacen que el programa aborte con un backtrace en la consola.

Una vez inicializado y detectados los JoinPoint, a medida que la aplicación es ejecutada, para cada método ejecutado se hace un scan de los patterns definidos y se testea contra la regex de cada uno, si alguna matchea arma la lista de parametros para el callback (tomando los valores originales con los que fue llamada la función interceptada).

El callback tiene 2 comportamientos, dependiendo si el metodo es static o no. Si es STATIC, se ejecuta como STATIC de manera que es el mismo callback para cualquier match. Esto da un comportamiento similar al Singleton de AspectJ (ideal para un logger por ejemplo).

Ahora, si el callback no es STATIC (como en el ejempo) por cada Signature que matchea se crea una instancia diferentes sobre la cual llamar el callback (ideal para un profiler, para saber cuantas llamadas tiene cada método, cada uno con su counter propio).

Obviamente en los callbacks aplican las mismas restricciones que lo métodos comunes : los statics solo pueden acceder a miembros statics de la clase y los no statics los miembros de esa instancia.

Y más o menos de eso se trata mi tesis :). Aún quedan muchas cosas por pulir, mejorar y documentar. La extracción de parámetros desde el stack no es trivial aunque por suerte el profiler de Mono hace algo parecido y calculo que basándome en ese código pueda sacarlo fácil.

Migración de Zimbra

Este fin de semana me puse como objetivo migrar el mail server de la empresa que ya estaba haciendo agua. Corría sobre un server con un disco que daba errores de lectura, no había RAID y la última semana hubo un 90% de uso de CPU en I/O :).

Arranqué el sábado al medio día y fue un día perdido. Tuve la loca idea de respetar la arquitectura del nodo para crear la VM y montar Zimbra en 64bits. Resulta que migrar el mail server a un nuevo servidor requiere de mucho matching entre el origen y el destino, por lo que fue prácticamente imposible hacerlo. Recapacité por la noche y el domingo fui por un aproach más conservador :).

Lo primero a tener en cuenta para migrar este productor (que es all-in-one-fucking-package) es aceptar que hay que usar una de las distros soportadas, y no tratar de hacer magia (al menos para no sufrir y que salga andando).

El proceso básico está en este post y no parece complicado, pero hay varios obstáculos que pasar. Lo primero, es que hay que hacer una instalación dummy de zimbra con la misma versión que teníamos antes. Mi problema era que tenía una versión muy vieja de Zimbra y solo había paquetes para Debian y Ubuntu 6.06, pero yo quería al menos Ubuntu 8.04.

El truco que usé fue editar /etc/debian_version y ponerle lo que espera y pasó sin problemas (calculo que por mero azar :D).

Una vez eso el resto fue copiar con rsync de un server a otro (25Gb tardan MUCHO, pero MUCHO!) y ejecutar el installer de la nueva versión, que tardó también como 6 hs en actualizar las tablas de MySQL. Esto último creo que fue causa de que el logger en el server viejo no estaba limpiando después de procesar, por lo que había muchos logs y eso hizo que demore tanto.

La migración fue perfecta, sin errores, pero teniendo problemas con el LDAP. Confieso que  odio ldap e iba a decir “hasta acá llegué, lo dejo” pero apareció rápidamente en el wiki la solución : regenerar los certificados. Anduvo en el primer intento.

Cosas a tener muy en cuenta por si les toca :

  • El nuevo server debe tener el mismo Domain Name y MX record a puntados (la ip puede cambiar, pero el DNS debe estar actualizado)
  • Bloquear el puerto 25 mientras se migra, asi en el nuevo server no empiezan a entrar mails hasta que no estemos seguros de que anda
  • Hacer backup antes de borrar algo 🙂
  • Usar solo las distros/versiones soportadas, ahorra miles de dolores de cabeza
  • Planificar con tiempo la copia de archivos, puede tardar más de lo que uno cree 🙂

Un tiempo después

No, no voy a comerntar sobre el aburrido programa de “Solita” :D, solo que hoy estuve arreglando unos bugs de Oregano y me di cuenta que habían pasado ya unos 18 meses desde el último commit que hice!

En fin, mucho tiempo, pero ya tengo un lindo TODO de cosas a ir haciendo, con muy baja prioridad por la Tesis, pero que quizás para mi cumple esté para hacer otro release, esperemos no colgarme de nuevo.

Mientras tanto se arreglaron dos bugs molestos :

  • Se arregló el export a PNG con fondo transparente
  • Se implementó finalmente la opción de exportar en escala de grises

oregano_grayscale

Nueva Casa (x2)

Si están leyendo esto significa que los DNS ya se actualizaron world-wide (o al menos el que usen :D) ya que después de casi 3 años finalmente le liberé a Sebas la máquina que me tenía rackeada en mi viejo trabajo :).

En estos día seguramente me ponga a migrar a WordPress 2.7 con la esperanza que no se rompa nada, pero quedan avisados (sobre todo los planets, espero que no floodee por algun bug en las feeds como pasó otra veces).

La otra noticia es que ya conseguí casa en el sur y a fin de mes me voy a firmar el contrato de alquiler. Un pasito más hacia mi emigración de Capital.

El diario Escondido

Luego de muchos meses de mucho trabajo, remasterización, ajustes, pruebas y demás, finalmente pudimos terminar y poner online una de las campañas más ambiciosas que hemos hecho hasta ahora : El diario Escondido.

httpv://www.youtube.com/watch?v=MUI7FbMoNDw

Hasta el día del lanzamiento solo podrán ver el trailer, si lo juegan me gustaría que después se pasen y dejen opiniones sobre qué les pareció :).

PD: No, no estoy autorizado a decirles como pasar, sumarles puntos extra o hacerlos subir de ranking :D.

Expo2009 @ LugMen

El fin de semana que viene voy a estar en Mendoza para participar de la Expo2009. Cada vez que he ido a esa ciudad la pasé muy bien y estoy seguro que será así, más aún cuando está de por medio el cumpleaños de Vita y Boris trae Pisco desde chile :).

Por mi parte voy a estar dando una charla bien careta “1, 2, 3 Probando. Acercando BDD a las masas.” sobre testing y metodologías. Hay que seguir robando y Mono ya no daba para mas :).

En el programa no hay demasiadas cosas que me interesen pero como siempre voy a copartir con la gente mas que para aprender algo, ver amigos, tomar mucha cerveza y compartir un finde distinto.