Category Archives: Programación

Instalar módulos de CPAN como paquetes .deb automáticamente

En un sistema basado en paquetes .deb (Debian, ubuntu, etc…) es bastante común tener una gran cantidad de módulos perl ya empaquetados en los repositorios pertinentes. La traducción del nombre del módulo al nombre del paquete es inmediata, Nombre::Del::Paquete se convertiría a libnombre-del-paquete-perl. Si resulta que tienes la mala suerte de no tener el que buscas, no pasa nada, existe una maravillosa herramienta llamada dh-make-perl (# aptitude install dh-make-perl) que nos solucionará todo.

Tienes múltiples opciones de configuración, pero explicaré dos formas de usarla, la rápida, cómoda e instantánea (¡como el colacao!) y otra donde vas más paso a paso (es decir, que en vez de un comando, ejecutas dos, joooplis).

Forma 1: Directamente se descargará el código y generará un .deb listo para ser instalado.

Digamos que quieres instalarte el módulo Hola::Que::Tal, pues ejecutas:

$ dh-make-perl --build --cpan Hola::Que::Tal

Con eso estaremos descargando el código del paquete (si en cpan existe claro) y generando un .deb de forma automática. Si existen dependencias se te indicará qué módulos se requieren, en cuyo caso sería recomendable que mirases si los tienes en tus repositorios antes de generar un .deb para ellos también.

Por poner un ejemplo real:

$ dh-make-perl --build --cpan Gtk2::Sexy
(...)
$ ls
Gtk2-Sexy-0.05                     libgtk2-sexy-perl_0.05.orig.tar.gz
libgtk2-sexy-perl_0.05-1_i386.deb
$ sudo dpkg -i libgtk2-sexy-perl_0.05-1_i386.deb

Forma 2: Tenemos un .tar.gz descomprimido descargado de cpan, generaremos la estructura de ficheros necesaria para generar un .deb con las herramientas típicas de debian (con debuild, $ sudo aptitude install devscripts).

Por seguir el ejemplo anterior, si quisiéramos instalar el módulo Hola::Que::Tal versión 1.0, nos descargamos de cpan su tar.gz y lo descomprimimos, por lo que tendríamos un directorio con el nombre Hola-Que-Tal-1.0. Con dh-make-perl generaremos los ficheros necesarios para poder generar un paquete deb (es decir, se creará un directorio debian/ con ficheros varios, los cuales, si sabes para qué sirven y quieres complicarte la vida, puedes modificarlos a mano para personalizar el .deb generado). Después simplemente entramos en el directorio y generamos el .deb ejecutando debuild.

$ ls 
Hola-Que-Tal-1.0.tar.gz
$ tar xfz Hola-Que-Tal-1.0.tar.gz
$ dh-make-perl Hola-Que-Tal-1.0/
(...)
$ cd Hola-Que-Tal-1.0
$ debuild
(...)
$ ls .. | grep .deb
libhola-que-tal-perl_1.0-1_i386.deb

Festival del humor en CSI New York

La que habla al final, dice algo así como:

I’ll create a GUI interface in Visual Basic, see if I can track an IP address.

Crearé una GUI en Visual Basic, a ver si puedo rastrear una dirección IP.

Para la gente que no le haga gracia, que será mayoría, significará algo así como: blabla GUI blablabla IP blabla.

Vía reddit.

Paralelizando quicksort en Erlang

Haciendo pruebas con erlang, se me ocurrió que sería divertido probar a paralelizar algún algoritmo típico (sobretodo debido a que mi cpu es ahora un quadcore). Como mi imaginación no está muy avanzada, probé con el quicksort.

Su implementación en un lenguaje funcional suele ser bastante simple. Y en Erlang podría ser algo simplemente como:

qsort([]) ->
   [];
qsort([Pivot|T]) ->
   qsort([X || X <- T, X < Pivot])   ++
   [Pivot]                           ++
   qsort([X || X <- T, X >= Pivot]).

En un primer (y estúpido) intento por paralelizarlo, probé simplemente a que cada llamada recursiva fuese un nuevo proceso. El asunto terminó con el ordenador medio bloqueado al intentar crear millones de procesos (pues inicié erlang poniéndole explícitamente que no hubiese límite :P, por defecto tiene 216 como límite).

El asunto tiene simple solución. Si tenemos un problema por permitir un exceso de procesos, pues se pone un límite y arreglado, ¿no?. El esquema usado simplemente es que para cada llamada recursiva, se indicará el número máximo de procesos que puede crear el proceso en cuestión y todos sus hijos. Si las llamadas recursivas de un quicksort van a ser un árbol donde cada nodo tendrá dos hijos, simplemente vamos a podarlo para que finalmente las hojas de dicho árbol ejecuten el algoritmo quicksort normal y el resto, los nodos, realizarán el quicksort paralelo (p_qsort lo he llamado).

%%
%% Params: 
%%   - List to be sorted
%%
p_qsort(L) ->
   S   = self(),
   Ref = erlang:make_ref(),
 
   spawn(fun() -> 
            p_qsort(L, ?THREAD_LIMIT, S, Ref) 
         end),
 
   gather(Ref).
%%
%% Params: 
%%   - List to be sorted
%%   - Maximum number of processes can be created
%%   - Father process (the results will be sent to him)
%%   - Unique reference for knowing what position the results are in
p_qsort([], _, Father, Ref) ->
   Father ! {Ref, []};
p_qsort([Pivot|T], Limit, Father, Ref) when Limit > 2 ->
   S       = self(),
   R_right = erlang:make_ref(),
   R_left  = erlang:make_ref(),
 
   spawn(fun() -> 
            p_qsort( [X || X <- T, X <   Pivot], Limit div 2, S, R_left)
         end),
   spawn(fun() -> 
            p_qsort( [X || X <- T, X >=  Pivot], Limit div 2, S, R_right) 
         end),
 
   Father ! {Ref, gather(R_left) ++ [Pivot] ++ gather(R_right)};
p_qsort(L, _, Father, Ref) ->
   Father ! {Ref, qsort(L)}.

La función con un único parámetro es la función pública de entrada. Ésta, crea un proceso con la función de quicksort paralelo indicando un número, como segundo parámetro, que significa el número máximo de procesos que puede crear. En las funciones siguientes tenemos primero el caso de lista vacía, seguido de la función que ejecutarán los nodos (los que todavía pueden crear procesos hijos) y finalmente cuando no podemos crear más procesos se resolverá simplemente llamando a qsort(L) (los procesos hoja del árbol de llamadas).

Algunas aclaraciones adicionales por si no estas muy puesto en Erlang:

  • Con spawn estamos creando un nuevo proceso. En este caso le pasamos una referencia al actual proceso, tercer parámetro, para que nos “mande” sus resultados
  • Con Variable ! Algo se está mandando el mensaje ‘Algo’ al proceso ‘Variable’
  • Erlang llama a las funciones con un matching de los parámetros (similar a prolog), en este ejemplo es bastante importante la condición when Limit > 2 que condicionará si crearemos más procesos o no
  • La función gather es solo una función para “recolectar” un resultado que me he montado copié de Joe Amstrong:
    %%
    %% Purpose: Receive a response of a process which have sent {Ref, Something}
    %% Params :
    %%   - A erlang reference for matching the message
    %% Return : The second item inside the received message
    gather(Ref) ->
       receive
          {Ref, Ret} -> Ret
       end.

    Para hacer pruebas, me he creado un par de módulos erlang para facilitar la ejecución:

    • benchmark.erl: define do/1 y do_silent/1 a las cuales les pasamos una función y nos devolverá el tiempo en µs (e imprimiendo un mensaje por pantalla).
    • test_sorting.erl: define funciones para ejecutar algoritmos de ordenación generando listas de tamaño variable de forma aleatoria. Usa el modulo de benchmark anteriormente citado, para crear csv‘s con los resultados de las ejecuciones.

    Mientras se ejecutaban los algoritmos, me pareció que sería curioso capturar el consumo de cpu de ambos, te dejo que intentes adivinar cual se corresponde con el algoritmo “tradicional” y cual con el “paralelo” (no vale mirar el nombre :P).

    Los resultados detallados, los he copiado en esta hoja de cálculo para OpenOffice, y un resumen de ellos los podemos ver en esta gráfica creada con gruff en ruby leyendo los csv generados desde erlang.

    ejecución de un quicksort paralelo en erlang

    El algoritmo paralelo es el doble de rápido que el tradicional, con valores medianos o grandes. Con valores menores a 1000 elementos es más costoso (al crear procesos, aunque erlang es mucho erlang, estamos incorporando un coste adicional, principalmente por el envío de mensajes, no por la creación per-se), pero en tales casos no sé para qué narices estamos mirando formas de mejorar el rendimiento, pues mil elementos los ordena hasta MySQL mi vecino.

    Lo que hay que destacar es la mejora sustancial conseguida, prácticamente sin cambiar nada (el código paralelo es trivial una vez se tiene la versión “normal”).

    Algunas cosas interesantes de probar serían:

    • Intentar ésto mismo con un número de cpus mayor a 4, y encontrar la relación entre cpus y ganancia.
    • Crear algún “behaviour” para erlang para poder generalizar la paralelización de algoritmos de divide y vencerás (que son bastante comunes) y siguen este esquema con bastante homogeneidad.

    Si quieres obtener todos los ficheros para ojear o jugar por ti mismo, aquí lo tenemos.

    Have fun.

Bot personal jabber para twitter, RTwittBot

Desde hace ya un tiempo llevo usando twitter, y no, no tiene ninguna utilidad, pero me gusta hablar solo (¡está loco!). Twitter se cae cada dos por tres, pero era algo que se puede soportar (así siempre tienes algo que decir… y de lo que quejarte que a todos nos gusta quejarnos, ¡quejicas!), pero desde Mayo desactivaron el servicio que tenían de mensajería instantánea (¡como el colacao!) por jabber.

Mediante ese servicio de IM jabber teníamos el bot de twitter al cual podíamos:

  • Mandar mensajes para postear en nuestro twitter
  • Recibir mensajes de nuestro timeline de la gente que seguíamos y teníamos marcada como follow

Es decir, ahorrarnos el tener que entrar a la puta página y tener que estar dándole a f5 todo el rato. Para mi esto es un requisito para usar twitter. Si no es por IM, no lo usaría.

Estuve un tiempo en jaiku (más que nada porque era el único servicio similar que tenía el IM activado, plurk, que es molón, molón; también lo desactivó) pero ahora se ha vuelto tonto y empieza a funcionar mal. Así que pensé un poquito y dije, ¡leches, pero si te puedes montar un bot jabber en 4 pipas!, dicho y hecho, volví a twitter creándome un bot jabber, en ruby, que hace justo la misma funcionalidad que el de twitter “oficial” (aunque es solo para una persona obviamente, :P).

Lo he llamado RTwittBot (feo de cojones, lo sé), el código está en github, para hacerlo funcionar solo necesitas tener ruby y algunas gemas que he indicado en el README en github. Naturalmente, necesitarás una cuenta jabber para que sea usada por el bot (por ejemplo cualquier cuenta que tengas de gmail sirve) aparte de la tuya propia que ya usas, todo esto se encuentra explicado en github.

Por ahora lo llevo usando unos días y es bastante estable, e incluso si ocurre algún fallo en el propio bot (twitter caído, bug en el código, etc…) el bot no debería caerse sino que cambia su disponibilidad a away e indica en su estado el porqué, para volver a cambiarlo cuando todo vuelve a la normalidad :).

Cualquier duda sobre su uso o lo que sea, deja un comentario ;).

Puertas lógicas con un dominó

Muy ingenioso, en este vídeo podemos ver cómo implementar puertas lógicas usando un dominó. La verdad que después de ver la primera puerta, el OR, no sabía como narices iba a “implementar” el AND. La última mejor que la veas…

Rails <2.1 con ruby 1.8.7, broken!

Es muy peligroso, de locos más bien (o aventureros), usar últimas versiones (aka debian testing/unstable) únicamente de ciertas “cosas” (llámese cosas a librerías, paquetes, lenguajes, etc…).

Me he encontrado con un problema curioso debido al uso del interprete de ruby en una de sus últimas versiones estables (1.8.7) con el framework rails en una versión que no es la última (2.0.2).

Habría que mencionar que rails 2.0.2 salió en diciembre del año pasado, mientras que ruby 1.8.7 es de apenas mes y medio por lo que es comprensible el fallo.

El problema está en que en ruby 1.8.7 se han añadido muchas cosas nuevas, como, por ejemplo, el método chars a la clase String:

$ ruby -v
ruby 1.8.7 (2008-05-31 patchlevel 0) [i486-linux]
$ irb
>> foo = "I love popcorns".chars
=> #<Enumerable::Enumerator:0xb7c0206c>
>> foo.first.class
=> String

Método inspirado en el activesupport de rails:

$ ruby -v
ruby 1.8.6 (2007-09-24 patchlevel 111) [i486-linux]
$ irb
>> "Hello world?".chars
NoMethodError: undefined method 'chars' for "Hello world?":String
$ cd /some/rails/project/ && script/console
Loading development environment (Rails 2.0.2)
>> "Hola hola".chars
=> #<ActiveSupport::Multibyte::Chars:0xb74d0050 @string="Hola hola">

Es decir, en rails se definía un método que devolvía un ActiveSupport::Multibyte::Chars, pero si ejecutamos en un interprete 1.8.7 nos encontraremos que al ejecutar el método chars de una String, nos devolverá un Enumerator por lo que ahí ya puede pasar de todo (mayormente porque son cosas diferentes y así mal asunto).

ActionView::TemplateError: undefined method '[]' for #<Enumerable::Enumerator:0xb6f3481c>

La solución, si queremos seguir usando rails 2.0.2, es realmente simple. Si no queremos pensar, podemos ver cómo lo han solucionado en el HEAD de rails. Y simplemente añadimos esta solución en algún initializer (por ejemplo en config/initializers/fixes.rb):

begin
 	String.class_eval { remove_method :chars }
rescue NameError
	# all Ok
end

De esta forma, nos eliminará el método chars de String y podemos usar el definido en ActiveSupport en la metaclase de String. Es decir, como si aquí no hubiera pasado nada.

Por cierto, hay otros temas similares en cuanto a compatibilidad con ruby 1.8.7, relacionados con String#start_with?/end_with? y Enumarable#group_by pero mucho más simples y no tan “graves”.