domingo, 28 de diciembre de 2008

Crear demonios en ruby

Para crear un demonio hay que duplicar el proceso actual (hacer un fork) y distinguir a cada una de las instancias para la que instancia hija se encargue del trabajo en background que queremos realizar.

En ruby todo este proceso se puede realizar automáticamente utilizando el módulo ruby daemon de la siguiente forma.

require 'daemons'

class Demonio
def initialize
Daemons.daemonize
loop do
f = File.new('/tmp/timestamp', 'a')
f.write("#{Time.now}\n")
f.close
sleep(3)
end
end
end

Demonio.new

viernes, 26 de diciembre de 2008

Redefinir el método de comparación con expresiones regulares

Para mejorar la búsqueda en los datos de los objetos se puede aprovechar que en ruby se puede redefinir el método de comparación con expresiones regulares (=~).

Un ejemplo.

class Persona
attr_accessor :nombre, :apellidos, :direccion

def initialize(nombre, apellidos, direccion)
self.nombre = nombre
self.apellidos = apellidos
self.direccion = direccion
end

def =~(re)
"#{self.nombre} #{self.apellidos} #{self.direccion}" =~ re
end

def self.search(ciudad, input)
query = Regexp.new(input, 'i')
ciudad.select{|p| p =~ query}
end
end



p1 = Persona.new('Jose', 'Gonzalez', 'Sol')
p2 = Persona.new('Francisco', 'Martinez', 'Preciados')
p3 = Persona.new('Fernando', 'Solano', 'Serrano')

Madrid = [p1, p2, p3]

puts Persona.search(Madrid, 'sol').map(&:nombre)

El modificador 'i' del constructor de expresiones regulares hace que no distinga entre mayúsculas y minúsculas.
Concatenando los campos en los que queremos buscar se obtiene un matching más completo.

Con el map final se imprimen los nombres de las personas que hayan coincidido con la búsqueda.

domingo, 14 de diciembre de 2008

Recuperación automática de procesos erlang

La mayor ventaja que proporciona erlang es la gran potencia que tiene para la programación de procesos concurrentes.

Cuando se diseña software que va a ser programado en erlang suele dividirse el trabajo en múltiples procesos, además provee de mecanismos para comprobar fácilmente entre procesos si alguno se ha colgado y restaurarlo o ejecutar cualquier otra acción.

En el siguiente ejemplo.

-module(lib_misc).
-export([link_p/1, start/0, loop/0]).

start() ->
Pid = spawn(fun loop/0),
register(divisor, Pid),
spawn(lib_misc, link_p, [Pid]),
Pid.

loop() ->
receive
{A, B} ->
io:format("~nDivision: ~p", [A/B]),
loop()
end.


link_p(Pid) ->
process_flag(trap_exit, true),
link(Pid),
receive
{'EXIT', Pid, _} ->
NewPid = spawn_link(lib_misc, loop, []),
register(divisor, NewPid),
link_p(NewPid)
end.

Al compilar la librería y arrancarla se ejecutan dos procesos, el principal loop y otro llamado link_p.

El bucle principal simplemente recibe una tupla con dos números y los divide. Tiene al menos un error conocido y es que no comprueba cuando el divisor es cero.

El proceso link_p se enlaza al principal, la tarea de este proceso es esperar a que el principal se cuelgue (por ejemplo, división entre cero).
En el momento en el que el programa principal se ha colgado, recibe el mensaje de salida, restaura el proceso y se enlaza al nuevo.

Hay un detalle más, al iniciar un nuevo proceso el pid del antiguo no nos sirve para mandarle mensajes, así que se registra el átomo divisor para tener siempre una referencia global.

Registrar un nombre global estático no es la mejor solución, ya que no se pueden iniciar múltiples instancias del proceso divisor, debería ser un parámetro, lo he dejado así por que el ejemplo fuera más sencillo.

lunes, 8 de diciembre de 2008

Funciones anónimas recursivas en Erlang

En erlang se pueden definir funciones anónimas con la palabra reservada fun, aunque se pueden guardar en una variable para referenciarlas posteriormente.

La sintaxis es la siguiente:

IsZero = fun(0) -> 1; (N) -> 0 end.

Esta función devuelve 1 (verdad) si el parámetro es 0, falso en cualquier otro caso.

El problema es que de esta forma no se pueden definir funciones recursivas, ya que al no estar definida la función dentro de su definición, no podemos referenciarla, para solucionarlo se puede pasar un parámetro extra, que sea la propia función.

Factorial = fun(1, F) -> 1; (N, F) -> N * F(N-1, F) end.

En este último caso habría que llamar a la función como Factorial(número, Factorial), lo que queda poco intuitivo, se puede mejorar creando dos funciones en lugar de una.

Fact = fun(1, F) -> 1; (N, F) -> N * F(N-1, F) end.
Factorial = fun(N) -> Fact(N, Fact) end.

domingo, 30 de noviembre de 2008

Terminales virtuales en linux

Regularmente cuando administramos equipos unix necesitamos varios terminales, por ejemplo, en el caso de estar administrando un equipo linux remoto por ssh.

Para poder tener varios terminales podemos loguearnos varias veces y usar cada conexión como un terminal, sin embargo esto está lejos de ser óptimo, una sola conexión es más que suficiente para tener abiertas varios terminales.

El comando screen de linux permite crear terminales virtuales, por lo que este problema lo tendríamos resuelto, su funcionamiento es muy simple.

Ejecutando:

sreen bash, abrimos una instancia nueva de bash en otro terminal.

Ctrl+A ", muestra una lista de los terminales virtuales.

Ctr+A 2, va a la tercera consola virtual (numeradas desde 0).

Ctrl+A Ctrl+A, va a la consola mostrada anteriormente.

Ctrl+A d, deja ejecutando las tareas en background (detach).

Expiration time en fragment caching

Cuando se usa el sistema de caché de rails se pueden elegir donde guardar los items cacheados, la mejor opción es la mayoría de los casos es memcached, pero no siempre tenemos posibilidad de instalar un demonio en la máquina que da hosting.

Otra posibilidad es guardar los items en el sistema de ficheros, para ello hay que añadir en el environment.rb lo siguiente.

config.cache_store = :file_store, '/path_to_cache'

El problema que tiene usar el sistema de ficheros como soporte para la cache es que no soporta la opción de expiración por tiempo, sin embargo memcached sí que lo hace.

Se puede solucionar añadiendo el siguiente parche al environment.rb

module ActiveSupport
module Cache
class FileStore < Store
def read(name, options = nil)
super
timestamp = File.open("#{real_file_path(name)}.timestamp", 'rb') { |f| f.read } rescue nil
if !timestamp or (timestamp and timestamp.to_i > Time.now.to_i)
File.open(real_file_path(name), 'rb') { |f| f.read } rescue nil
else
nil
end
end

def write(name, value, options = nil)
super
ensure_cache_path(File.dirname(real_file_path(name)))
if options and options[:expires_in]
File.open("#{real_file_path(name)}.timestamp", "wb+") { |f| f.write(Time.now.to_i + options[:expires_in].to_i) }
end
File.open(real_file_path(name), "wb+") { |f| f.write(value) }
rescue => e
RAILS_DEFAULT_LOGGER.error "Couldn't create cache directory: #{name} (#{e.message})" if RAILS_DEFAULT_LOGGER
end

def delete(name, options = nil)
super
File.delete("#{real_file_path(name)}.timestamp") rescue nil
File.delete(real_file_path(name)) rescue nil
end
end
end
end

Se puede utilizar al igual que la opción expires_in en memcached.

<% cache 'something', :expires_in => 5.minutes do %>
Hello, just saying hello from cache
<% end %>

Lo he desarrollado teniendo en cuenta la implementación de rails 2.1.2, y solo soporta fragment caching.

miércoles, 26 de noviembre de 2008

Fragment caching en rails

Usando memcached y fragment caching se puede acelerar mucho la reconstrucción de las vistas en rails.

Para ello, una vez instalado memcached lo ejecutamos:

memcached -d

Por defecto estará en el puerto 11211.

En el environment.rb hay que configurar la caché para que utilice memcached.


config.cache_store = :mem_cache_store


Tras eso en las vistas podemos hacer lo siguiente:


<% cache 'key', :expires_in => 300 do %>
texto html...
<% end %>


300 es el número de segundos que este trozo estará vigente en caché, si no se indica nada el fragmento no expirará a no ser que lo indiquemos manualmente con expire_fragment.

key es la clave que tiene el fragmento dentro de la vista, es necesario para distinguir los distintos fragmentos.

sábado, 15 de noviembre de 2008

Memoization en ruby

La memoization es una técnica de optimización que consiste en recordar los resultados para anteriores llamadas a una función.

Si para una llamada anterior a una función se han pasado los parámetros x=2 e y=3, la próxima vez se devolverá el mismo resultado al obtenido, sin repetir cálculos.

La implementación es muy sencilla y se pueden obtener mejoras muy significativas en funciones con cálculos pesados, basta con tener una tabla en la que utilicemos los parámetros de entrada como índices y el resultado de la función como valor.

Si ya de por sí es sencillo implementar la memoization en ruby se puede usar también la gema que hay específica para ello, esta gema implementa la memoization automática, por lo que ni siquiera es necesario mantener una tabla para los valores, la gema se encarga de ello.

Es necesario recordar que en la memoization solo se tienen en cuenta los parámetros de entrada, por lo que a las funciones que produzcan resultados a partir de otras entradas (ficheros, hora actual...) no se les debe aplicar esta técnica.

En el siguiente ejemplo se implementa la función de fibonacci recursiva (fib1), la misma función aplicándole la memoization (fib2) y por último la memoization automática a fib1. En mi máquina para este ejemplo se obtienen ganancias de 30 a 40 veces en las versiones memoizadas.

require 'rubygems'
require 'memoize'

include Memoize

def fib1(n)
return n if n < 2
return fib1(n-1) + fib1(n-2)
end


@mm = {}
def fib2(n)
return @mm[n] if @mm[n]
return n if n < 2

@mm[n] = fib2(n-1) + fib2(n-2)
return @mm[n]
end

puts fib1(30)
puts fib2(30)

memoize(:fib1)
puts fib1(30)

domingo, 9 de noviembre de 2008

Ocultar parámetros del log de rails

Al igual que se suelen encriptar las contraseñas al guardarlas en las bases de datos de las aplicaciones con autentificación, también se deberían omitir este tipo de campos en el log de rails.

Cuando se despliega rails en un entorno en producción normalmente guarda el log de todas las peticiones en log/production.log, ahí se pueden ver todos los parámetros que se pasan a la aplicación, incluyendo contraseñas, números de tarjetas de crédito, etc.

Hay una forma de hacer que determinados parámetros no aparezcan, llamando a filter_parameter_logging en el controlador.

class AccountsController < ApplicationController
filter_parameter_logging :card_number

def index
@accounts = Account.find(:all)
end
end

En el log aparecerá algo así.

Parameters: {"card_number"=>"[FILTERED]"...

domingo, 2 de noviembre de 2008

Generacion dinámica de métodos en ruby

Una característica que puede añadir mucha potencia a los módulos que creamos en ruby es la generación automática de métodos.

Se usa intensivamente en rails, tanto en la implementación de ActiveRecord como de la mayoría de plugins.

Para definir métodos de forma dinámica tan solo hay que redefinir method_missing, este método se llama cada vez que se llama a una función no definida, recibe como primer parámetro el nombre del método y como segundo parámetro la lista de argumentos.

Dejo un ejemplo.

#!/usr/bin/ruby

def method_missing(method, *args)
if method.to_s =~ /saludo_(\w+)/
generar_saludo($1)
else
super(method, *args)
end
end

def generar_saludo(msg)
puts "hola #{msg}"
end


saludo_mundo

sábado, 1 de noviembre de 2008

Crear clases dinámicas en ruby

La sintaxis de ruby para crear clases u objetos es muy sencilla, pero lo es más aún para definirlos dinámicamente.

Para ello disponemos de la clase Struct, veamos un ejemplo en el siguiente código.

Clase = Struct.new :campo1, :campo2
objeto = Clase.new('valor1', 'valor2')
puts objeto.campo1
puts objeto.campo2
puts objeto.members
puts objeto.values

En la primera línea con Struct se crea la clase Clase con dos campos, esos campos ya están disponibles en los objetos que creemos a partir de la clase. Adicionalmente, Struct añade algunos métodos como members y values para inspeccionar el contenido de los objetos creados.

domingo, 26 de octubre de 2008

Metaprogramación en php

En php5 han entrado nuevas posibilidades en lo que a metaprogramación se refiere, revisando el siguiente trozo de código nos encontramos un ejemplo de que construcciones se pueden realizar.

<?php

function saludo(){
return "hello";
}

$cadena = "saludo";
$cadena_funcion = "cadena";
?>

<?= $cadena() ?>

<br/>

<?= $$cadena_funcion() ?>

Primero podemos ver que si guardamos en una cadena el nombre de una función, y luego llamamos a la cadena con una lista de parámetros (en este caso vacía), se invoca dicha función. Esto puede ser bastante útil para elegir que acción ejecutar ante una entrada por parámetro.

En segundo lugar se muestra como utilizar las variables con doble '$', es decir, las variables de variables. Por cada '$' delante del nombre de la variable se hace una evaluación de la variable.

$cadena_funcion contiene la cadena "cadena", si por el contrario se referencia a $$cadena_funcion, se evaluará la variable $cadena.

martes, 21 de octubre de 2008

Programación funcional con javascript

En programación funcional se usa las funciones map, filter y reduce para manipular colecciones.

En javascript se pueden implementar fácilmente de la siguiente manera.

function map(f, a){
var r=new Array();
for(var i=0;i<a.length;i++){
r.push(f(a[i]));
}
return r;
}

function filter(f, a){
var r=new Array();
for(var i=0;i<a.length;i++){
if(f(a[i])){
r.push(a[i])
}
}
return r;
}

function reduce(f, a){
if(a.length<1){
return a
}
else{
var r=a[0].__proto__;
for(var i=0;i<a.length;i++){
r=f(r, a[i])
}
return r;
}
}

domingo, 19 de octubre de 2008

Implementación de un memory pool

En aplicaciones en las que se reserva y libera memoria con mucha frecuencia se puede sufrir fragmentación de memoria. Cuando el rendimiento no es demasiado importante este comportamiento puede ser aceptable, en cambio, si esto se produce en una aplicación de tiempo real es necesario solucionarlo.

Para evitar la fragmentación de memoria existe una técnica llamada memory pool, básicamente consiste en crear un espacio fijo de memoria para que la aplicación lo administe.

En el siguiente ejemplo se crea un pool para un conjunto de threads que lo comparten.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>

#define BUF_SIZE 128
#define POOL_SIZE 36
#define NUM_THREADS 10

typedef struct dataStruct{
int id;
char cadena[BUF_SIZE];
} data;


pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

data **dataPool;
int next_data = 0;

int get_next_memory_position(){
pthread_mutex_lock(&mutex);
next_data = (next_data + 1) % POOL_SIZE;
pthread_mutex_unlock(&mutex);
return next_data;
}

data **allocate_pool(){
int i;
data **d = (data**) malloc(sizeof(data*) * POOL_SIZE);

for(i = 0;i < POOL_SIZE; i++){
d[i] = malloc(sizeof(data));
}

return d;
}

void *thread(){
data *param = dataPool[get_next_memory_position()];

param->id = next_data;
strcpy(param->cadena, "hello");

printf("%d: %s \n", param->id, param->cadena);
}

int main(){
pthread_t t[NUM_THREADS];
dataPool = allocate_pool();
int i;

for(i = 0;i < NUM_THREADS; i++){
pthread_create(&t[i], NULL, thread, NULL);
}

for(i = 0;i < NUM_THREADS; i++){
pthread_join(t[i], NULL);
}
}

En este ejemplo se asigna automáticamente memoria a los threads conforme la piden circularmente, este planteamiento no vale siempre, para cambiar la política de asignación de bloques libres solo hay que cambiar el método get_next_memory_position.

sábado, 18 de octubre de 2008

Simulando enlaces con javascript

En algunas ocasiones necesitamos poner un enlace en un elemento del DOM de una web que no acepta la propiedad href.

Normalmente ocurre cuando se quiere añadir un hipervínculo que no estaba previsto al realizar la maquetación.

Para esos casos se puede simular el comportamiento de un enlace mediante javascript.

Supongamos que el div con id 'texto' es el que queremos que tenga un enlace a otra página, con el evento onclick y cambiando el document.location podemos irnos a la página que queremos al pinchar en el elemento.

El problema es que al pasar por encima el ratón nada nos indica que es un enlace, con el evento onmouseover y cambiando la propiedad css cursor podemos hacer que parezca un enlace.

Un ejemplo de como quedaría.

<html><body>

<div id="texto" onclick="document.location='http://google.com'" onmouseover="this.style.cursor='pointer'">lorem ipsum</div>

</body></html>

domingo, 12 de octubre de 2008

Transacciones en rails

En esta entrada expliqué como usar las transacciones a nivel de base de datos (MySQL), ahora lo haré a nivel de aplicación con rails.

Si usamos MySQL debemos recordar que por ahora el único motor que soporta transacciones es InnoDB.

Los objetos que heredan de ActiveRecord tienen un método transaction que acepta un bloque, las operaciones que se ejecuten dentro se realizarán indivisiblemente.

Imaginemos que tenemos un modelo llamado Post, con los campos title y content, el campo title no puede ser nulo.

Si hacemos esto.

Post.transaction do
Post.create(:title => 'en la transaccion', :content => 'texto')
Post.create(:content => 'texto')
end

Como la segunda operación no es válida (el campo title es nulo) ninguna de las operaciones se reflejará en base de datos, por el contrario, si le asignamos un title a la segunda operación se ejecutarán normalmente y tendremos dos entradas nuevas en la tabla de posts.

sábado, 11 de octubre de 2008

Ejecutar comandos linux sobre múltiples ficheros

Para ejecutar comandos masivamente sobre una lista de ficheros en linux se pueden combinar los comandos find y xargs.

find es bastante conocido, básicamente lo que hace es buscar archivos según los criterios que le indiquemos.

xargs coge una lista y ejecuta el comando que le pasemos a cada elmento de esa lista.

La sintaxis es la siguiente.

find . -name "*.txt" | xargs echo

Con eso listaríamos los ficheros con extensión txt.

find . -name "*.php" | xargs -I fichero cat fichero >> acumulado.php

El parámetro -I hace que podamos darle un nombre a la entrada del comando que queremos ejecutar para realizar operaciones más complejas.

find . -name "*.cpp" | xargs -t -I fichero mv fichero fichero.old

Al realizar operaciones masivas con ficheros es posible que cometamos algún error, para comprobarlo se puede utilizar el parámetro -t que hace que se indiquen en la salida todos y cada uno de los comandos que xargs ejecuta.

lunes, 6 de octubre de 2008

Búsquedas fulltext en mysql

Las búsqueda fulltext son un tipo de búsqueda especial para los campos de texto, en MySQL solo está disponible para el motor MyISAM. Incluso los resultados se ordenan por relevancia.

Se pueden indexar en modo fulltext los campos de tipo char, varchar y text.

Para crear un índice fulltext la sintaxis es la siguiente.

alter table tabla add fulltext(campo);

Se pueden combinar varios campos para el índice.

alter table tabla add fulltext(campo1,campo2);

La sintaxis para las consultas fulltext.

select * from tabla where match(campo) against('contenido');

Hay que tener en cuenta ciertas condiciones al realizar búsquedas, las más importantes:

1) Si la consulta aparece en la mitad de los registros se toma como 'común', se ignoran los resultados
2) Se ignoran palabras demasiado cortas

Si no nos viene bien la regla 1), podemos hacer las búsquedas en 'modo booleano' aunque en este caso los resultados no se ordenan por relevancia.

select * from tabla where match(campo) against('contenido' in boolean mode);

En 'modo booleano' se pueden aplicar también modificadores, por ejemplo, si queremos las tuplas con contenido 'texto' y sin 'basura'.

select * from tabla where match(campo) against('+texto -basura' in boolean mode);

También se puede utilizar el wildcard '*'.

select * from tabla where match(campo) against('text*' in boolean mode);

lunes, 29 de septiembre de 2008

Transacciones en MySQL

Las operaciones de escritura en MySQL (inserciones, actualizaciones y borrados) se realizan por defecto en modo autocommit, es decir, se actualizan automáticamente en la base de datos.

Este comportamiento es bueno para la mayoría de aplicaciones ya que los cambios se propagan muy rápido, sin embargo no son todo ventajas.

Si queremos realizar una operación compleja en la que actualizamos varios campos o tablas y falla alguna de las operaciones, la base de datos puede quedar en un estado inconsistente o no deseado.

En este caso resultaría útil poder deshacer los cambios, decirle de alguna forma que todas esas operaciones van 'unidas', o se ejecutan todas, o ninguna.

Existe una forma de hacer lo anterior, crear una transacción, los cambios se guardarán en la base de datos si todo ha ido bien, si no, volveremos al estado anterior.

MySQL soporta transacciones, pero no con todos los motores, MyISAM por ejemplo no lo soporta, InnoDB sí.

Un ejemplo de como funcionan las transacciones.

mysql> create table tabla (name char(20), unique(name)) engine = InnoDB;
Query OK, 0 rows affected (0.01 sec)

mysql> insert into tabla set name = 'primero';
Query OK, 1 row affected (0.01 sec)

mysql> insert into tabla set name = 'segundo';
Query OK, 1 row affected (0.01 sec)

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> insert into tabla set name = 'tercero';
Query OK, 1 row affected (0.00 sec)

mysql> select * from tabla;
+---------+
| name |
+---------+
| primero |
| segundo |
| tercero |
+---------+
3 rows in set (0.00 sec)

mysql> insert into tabla set name = 'segundo';
ERROR 1062 (23000): Duplicate entry 'segundo' for key 1
mysql> rollback;
Query OK, 0 rows affected (0.01 sec)

mysql> select * from tabla;
+---------+
| name |
+---------+
| primero |
| segundo |
+---------+
2 rows in set (0.00 sec)

Como se puede ver al hacer rollback volvemos al estado anterior de la base de datos, si hubiésemos querido guardar los cambios tendríamos que haber ejecutado commit.

Durante la transacción los resultados que se muestran están en memoria, pero no físicamente guardados en la base de datos, si abrimos otra sesión de mysql esos cambios no los veremos hasta que se realice un commit.

domingo, 28 de septiembre de 2008

Lector RSS en ruby

Para crear un lector RSS tan solo es necesario crear una conexión http hasta el sitio que queramos suscribirnos y después parsear el archivo xml que nos devuelve el servidor.

En ruby se puede hacer todo esto en unas pocas líneas.

#!/usr/bin/ruby
require 'net/http'
require 'rexml/document'

http = Net::HTTP.new 'servidor.com'
http.start

response = http.get('/path_to_rss')
xml = REXML::Document.new(response.body)
xml.each_element('rss/channel/item') do |elem|
puts elem.elements['title'].text
puts elem.elements['link'].text
puts "----------------"
end

jueves, 25 de septiembre de 2008

Capturar y redirigir tráfico con netcat

Cuando estamos comprobando el estado de la red o depurando el funcionamiento de un protocolo viene muy bien el comando netcat.

Una redirección de un puerto a otro con netcat se hace de la siguiente forma.

nc -l -p 5000 | nc localhost 5001

De esa forma se reenvía lo que llegue al puerto 5000 hasta el 5001.

Si agregamos el parámetro -o además podemos registrar el tráfico saliente.

nc -l -p 5000 -o log.txt | nc localhost 5001

La respuesta saldrá por consola, si tenemos una aplicación que se conecta a un host remoto y queremos saber que envía y que recibe de ese host lo podemos hacer de la siguiente forma.

iptables -t nat -A OUTPUT -p tcp -d host_remoto -j DNAT --to-destination 127.0.0.1:5000

nc -l -p 5000 -o log.txt | nc host_remoto puerto_remoto

Con esto redirigiremos todo el tráfico saliente a host_remoto a nuestro puerto 5000, guardaremos la petición en log.txt y volveremos a enviarlo a host_remoto, la respuesta a la petición nos aparecerá por consola.

domingo, 21 de septiembre de 2008

Guardar datos comprimidos en base de datos con rails

En ciertas ocasiones es posible que queramos tratar los datos que vienen de una aplicación rails antes de guardarlos en base de datos. Para ello podemos sobrecargar los métodos nombre_parametro y nombre_parametro= en el modelo correspondiente.

Si, por ejemplo, tenemos un campo de la base de datos que preveemos que ocupe mucho espacio y no va a leerse frecuentemente se puede comprimir de la siguiente forma.

class Post < ActiveRecord::Base

def text
Zlib::Inflate.inflate(read_attribute(:text))
end

def text=(new_text)
old_text=read_attribute(:text)
new_compress_text=Zlib::Deflate.deflate(new_text)
write_attribute(:text, new_compress_text) if old_text!=new_compress_text
end
end

Para comprimir/descomprimir los datos se usa la librería zlib así que es necesario hacer require 'zlib'.

Además es necesario que el campo de la base de datos esté marcado como binario.

sábado, 20 de septiembre de 2008

Decoradores en python

Para entender fácilmente los que son los decoradores en python podemos pensar que son una especie de filtros que se ejecutan antes de la llamada a una función.

Realmente un decorador se ejecuta antes de la función decorada (realizando cualquier tipo de acción) y devuelve la función a ejecutar (posiblemente la función decorada). Es más fácil de entender con un ejemplo.

#!/usr/bin/python

def filtro(f):
def permiso_denegado(*args):
print '%s no tiene permisos para realizar esa accion' % args[0]

def comprobacion(*args):
if args[0] == 'admin':
return f(*args)
else:
return permiso_denegado(*args)

return comprobacion


@filtro
def accion(usuario):
print 'Accion realizada por %s' % usuario

accion('guest')

En este caso se intenta realizar una acción pero si el usuario pasado como parámetro no es 'admin' no puede realizarla, en lugar de devolver una referencia a la función original, se devuelve la función de permiso denegado, filtro es el decorador.

También existe la posibilidad de combinar decoradores, lo importante es tener en cuenta cuando se programa un decorador que no tiene porqué ser el único (cuidado lo que se hace con los parámetros) y el orden, en el ejemplo debug(filtro(debug(accion))).

#!/usr/bin/python

_MODO_DEBUG = True

def debug(f):
if _MODO_DEBUG:
print 'Se ejecuta la funcion: %s' % f.__name__
return f

def filtro(f):
def permiso_denegado(*args):
print '%s no tiene permisos para realizar esa accion' % args[0]

def comprobacion(*args):
if args[0] == 'admin':
return f(*args)
else:
return permiso_denegado(*args)

return comprobacion

@debug
@filtro
@debug
def accion(usuario):
print 'Accion realizada por %s' % usuario

accion('guest')

Medir el rendimiento de una aplicación web

Es importante medir el rendimiento de todas las aplicaciones que creamos, en el caso de las aplicaciones web podemos usar una herramienta de hp llamada httperf.

Para ejecutarlo de la forma más sencilla se puede hacer.

httperf --server servidor_web --port puerto --num-conns numero_conexiones

servidor_web y puerto apuntan a la aplicación web que queramos probar y numero_conexiones es el número de intentos totales, entre 200 y 1000 suelen dar unos buenos resultados sin tests demasiado largos.

Si queremos probar alguna página que no sea el index se puede hacer incluyendo el parámetro --uri direccion.

Si la página que queremos probar necesita de registro también se puede solucionar con esta herramienta, primero necesitamos loguearnos con el navegador, observar la cookie que se nos ha creado y entonces añadir el parámetro --add-header='Cookie: nombre=valor', donde nombre y valor son los que hemos obtenido de la cookie del navegador.

miércoles, 17 de septiembre de 2008

Seleccionar parte de una imagen con javascript

En las redes sociales que permite etiquetar imágenes se suele elegir una sección de la imagen que representa la parte ocupada por cada usuario.

El problema es que a la mayoría (facebook, tuenti...) solo nos dejan seleccionar una sección cuadrada fija y muchas veces no se corresponde con lo que queremos.

Con jQuery y Jcrop podemos realizar selecciones más precisas de la siguiente manera.

<html>
<head>
<script src="jquery.pack.js"></script>
<script src="jquery.Jcrop.pack.js"></script>
<link rel="stylesheet" href="/css/jquery.Jcrop.css" type="text/css" />

<script language="Javascript">
jQuery(function(){ jQuery('#cropbox').Jcrop(); });
jQuery('#cropbox').Jcrop({
aspectRatio: 1,
onSelect: updateCoords
});
function updateCoords(c){
jQuery('#x').val(c.x);
jQuery('#y').val(c.y);
jQuery('#w').val(c.w);
jQuery('#h').val(c.h);
};
</script>
</head>

<body>
<img src="flowers.jpg" id="cropbox" />
</body>
</html>

En c.x y c.y tendremos las coordenadas dónde comienza la selección y en c.w y c.h el ancho y el alto.

Una vez que sabemos exactamente la selección del usuario se puede recortar la imagen o etiquetar cada zona.

domingo, 14 de septiembre de 2008

Implementación caché para minimizar cálculos

Una de las reglas de optimización más importantes es la de no repetir cálculos innecesariamente.

Guardando resultados intermedios y reutilizándolos cuando sea posible se mejora el rendimiento espectacularmente, en el ejemplo se consigue una ganancia casi lineal.

La clase NoCache sería la forma tradicional de implementar esta clase, a continuación la clase Cache optimizada para lecturas sucesivas sin repetir el cálculo si no es necesario.

#!/usr/bin/python

class NoCache:
def __init__(self):
self.lista = range(1,900000)

def getLista(self):
return self.lista

def setLista(self,value):
lista.append(self.value)

def getMedia(self):
return reduce((lambda n,m:n+m),self.lista) / len(self.lista)


class Cache:
def __init__(self):
self.lista = range(1,900000)
self.__actualizado = False

def getLista(self):
return self.lista

def setLista(self,value):
self.__actualizado = False
lista.append(self.value)

def getMedia(self):
if self.__actualizado:
return self.__sumaCache
else:
self.__sumaCache = reduce((lambda n,m:n+m),self.lista) / len(self.lista)
self.__actualizado = True
return self.__sumaCache


n = NoCache()
for i in range(5):
print n.getMedia()


c = Cache()
for i in range(5):
print c.getMedia()

El mismo ejemplo en ruby.

#!/usr/bin/ruby

class NoCache
def initialize
@lista = Array.new(900000){|i| i+1}
end

def getLista
return @lista
end

def setLista(value)
@lista << value
end

def getMedia
@lista.inject{|sum, n| sum+n} / @lista.size
end
end

class Cache
def initialize
@lista = Array.new(900000){|i| i+1}
@actualizado = false
end

def getLista
return @lista
end

def setLista(value)
@actualizado = false
@lista << value
end

def getMedia
if @actualizado
@sumaCache
else
@sumaCache = @lista.inject{|sum, n| sum+n} / @lista.size
@actualizado = true
@sumaCache
end
end
end

n = NoCache.new
5.times{puts n.getMedia}

c = Cache.new
5.times{puts c.getMedia}

Otro resultado inesperado en este ejemplo es la gran diferencia de velocidad entre estos dos lenguajes.

En python en mi máquina este ejemplo tarda en ejecutarse 7 segundos, en ruby 1 minuto y 28 segundos. Para este ejemplo python es ¡12 veces más rápido que ruby!.

sábado, 13 de septiembre de 2008

Variables de solo lectura en python

Hay algunos tipos de variables, como pueden ser variables de estado, que no interesa que se modifiquen desde fuera de los métodos de una clase, aunque sí que se pueda leer su valor.

Al intentar modificar el valor de una variable de un objeto se llama a la función __setattr__, si sobrescribimos esta función se puede variar el comportamiendo habitual. Lo mismo podemos hacer con __delattr__.

Así se podría mantener una distinción en una clase entre variables de solo lectura y lectura/escritura.

#!/usr/bin/python

class Clase:
__onlyReadVars=['x', 'y']

def __init__(self):
self.__dict__['x'] = 8
self.__dict__['y'] = 1
self.a = 2

def __setattr__(self, nombre, valor):
if nombre in self.__onlyReadVars:
raise Exception('No se puede sobrescribir %s' % nombre)
else:
self.__dict__[nombre] = valor

def __delattr__(self, nombre):
if nombre in self.__onlyReadVars:
raise Exception('No se puede eliminar %s' % nombre)
else:
del self.__dict__[nombre]

De esta forma si intentamos eliminar o sobrescribir alguna de las variables de solo lectura se lanzará una excepción.

Aun así, hay una manera de saltarse el filtro si hacemos lo siguiente.

c = Clase()
c.__dict__['x'] = 30


__dict__ es un diccionario con todas las variables del objeto y sus valores, al modificarlo no se llama a la función __setattr__, __getattr__ ni __delattr__.

jueves, 11 de septiembre de 2008

Trucos para bash

Hay ciertas situaciones al trabajar en consola que se hacen un poco pesadas y se pueden evitar con algunas combinaciones de teclas disponibles en bash.

Cuando necesitamos ir a un directorio y volver al que estábamos anteriormente se puede ejecutar.

cd -

Para ver todas las variables definidas en la shel simplemente escribiendo $ y pulsando dos veces al tabulador deberían aparecer.

Cuando ejecutamos un comando muy largo repetidas veces se puede hacer una búsqueda incremental en el historial pulsando Ctrl+R.

Una de las cosas más molestas de trabajar con consola es editar comandos muy largos, se puede hacer fácilmente con estos atajos de teclado.

Ctrl+A: pone el cursor al principio de la línea
Ctrl+E: pone el cursor al final de la línea
Ctrl+K: borra desde el cursor hasta el final de la línea
Ctrl+U: borra desde el principio hasta el cursor
Ctrl+Y: pega el texto que cortaste con Ctrl+K o Ctrl+U

martes, 9 de septiembre de 2008

Medir el tiempo de cada funcion en python

Cuando vamos a optimizar código lo primero en lo que pensamos es en medir el tiempo que tarda cada función de nuestro programa para ver donde se puede mejorar más (Ley de Amdahl).

En python el módulo timeit nos facilita mucho esta tarea, se puede usar de la siguiente manera.

import timeit
t = timeit.Timer("funcion()", "from __main__ import funcion")
t.timeit()


t.timeit() ejecuta múltiples veces la función y devuelve el tiempo transcurrido, si se le pasa un parámetro ejecutará la función ese número de veces.

También se puede ejecutar varias veces el test anterior para asegurarnos que no influye ningún otro proceso en la medida del tiempo, para ello se puede ejecutar t.repeat(numero_de_veces) y devolverá un array con los tiempos transcurridos.

domingo, 7 de septiembre de 2008

MapReduce

MapReduce es una técnica popularizada por Google (aquí el documento original) para el tratamiento de grandes cantidades de información en un tiempo razonable.

El nombre proviene de las funciones propias de la programación funcional map y reduce.

En python estas dos funciones se pueden combinar de la siguiente forma para contar el número de números impares de una lista:

reduce(lambda n,m: n+m, map(lambda n: n%2, [1,2,3,4,5,6,7,8,9]))

Primero, map aplica la función n%2 a toda la lista original y cambiandola de dominio (de números naturales a [0,1]), después reduce suma la nueva lista obteniendo el número de elementos impares.

¿Qué ventaja tiene esta manera de hacerlo el recuento a la tradicional?
Lo primero que se nos hubiera ocurrido tradicionalmente sería recorrer la lista en aumentando un contador si un número es impar.
Con MapReduce hacemos un procedimiento intermedio (cambiar la lista de dominio) pero a cambio es un diseño muy sencillo de paralelizar.

Por definición map aplica una función a cada elemento de una lista, implicitamente no hay relación entre cada cálculo realizado por map, así que cada operación la puede realizar un nodo.

Tras eso se necesita almacenar todos los resultados en un nodo central para obtener el resultado final, mayor eficiencia obtendremos en este algoritmo cuanto más porcentaje del cálculo lo hagamos mediante map y menos mediante reduce.

Crear un disco virtual usando la memoria RAM

En muchas ocasiones se trabaja intensivamente con un conjunto no demasiado grande de ficheros, se puede acelerar mucho el acceso a estos ficheros si se almacenan en la memoria RAM.

Para ello, en linux se puede crear un nuevo punto de montaje que acceda a la RAM, tan solo es necesario hacer lo siguiente.

mkdir /mnt/ramdisk
mount tmpfs /mnt/ramdisk -t tmpfs


Ya podemos trabajar en el directorio ramdisk, eso sí, la memoria RAM es volátil, si queremos guardar los cambios antes de apagar el pc es necesario copiarlo a cualquier otro directorio del disco duro.

sábado, 6 de septiembre de 2008

Leer los parámetros de la lista de comandos en python

La mayoría de programas que se usan mediante la línea de comandos aceptan parámetros y eso es lo que le da a estos programas mayor flexibilidad que a los que se usan mediante interfaz gráfica.

Para leer los parámetros de un programa en python nos puede servir la librería optparse.

Tiene bastantes opciones e incluso genera la ayuda de forma automática al llamar al programa con -h.
Un ejemplo de como se utiliza.

#!/usr/bin/python

from optparse import OptionParser

parser=OptionParser()
parser.add_option("-a", "--all", dest="todos", action="store_true", default=False,
help="afecta a todos los elementos")
parser.add_option("-f", action="store_false", dest="todos",
help="affecta solo al primer elemento")
parser.add_option("--without-output", action="store_false", dest="output", default=True,
help="sin mostrar salida")
parser.add_option("-i", "--insert", action="store", dest="newValue",
help="inserta un elemento al final de la lista")

(options, args)=parser.parse_args()

lista=[1,2,3,4,5,6,7,8,9];
nuevaLista=lista

if options.todos:
nuevaLista=map(lambda n: n*2, lista)
else:
nuevaLista[0]=lista[0]*2

if options.newValue:
nuevaLista.append(int(options.newValue))

if options.output:
print nuevaLista

Se pueden combinar parámetros, agrupar, hacerlos excluyentes... casi todo lo que se ocurra, si necesitas algo más específico mira en el enlace anterior.

domingo, 31 de agosto de 2008

Convertir fichero .nrg a .iso

Para convertir un fichero .nrg al formato .iso en linux sin necesidad de ningún programa adicional tan solo hay que ejecutar el siguiente comando.

dd bs=1k if=imagen.nrg of=imagen.iso skip=300

La explicación, con este comando lo que hacemos es copiar el fichero quitando los primeros 300kB (skip indica el número de bloques que no queremos copiar y bs es el block size).

En realidad un fichero .nrg y uno .iso se diferencian simplemente en eso, nero añade esa cabecera con información propia.

Hay un programa que hace esta misma conversión en linux, nrg2iso.
Este programa está hecho en c, la conversión la realiza de esta manera.

fseek (nrgFile, 307200, SEEK_SET);

El resto del programa es básicamente una copia de ficheros, al igual que hace el comando dd, en este caso salta 307200 bytes, que en realidad corresponde a los 300kB mencionados arriba (300*1024).

sábado, 30 de agosto de 2008

Ficheros abiertos por un proceso

Para localizar los procesos que están usando un fichero en linux tenemos el comando fuser. En concreto ejecutando lo siguiente.

fuser -va fichero (fichero también puede ser un directorio).

fuser -km fichero (mata todos los procesos que acceden al fichero).

Una funcionalidad similar se puede obtener con lsof, además lsof también permite ver los sockets abiertos.

lsof fichero

Ejecutando simplemente lsof se muestran todos los fichero abiertos así que podemos filtrar mejor con grep.

lsof | grep fichero
lsof | grep UDP (sockets udp abiertos).

miércoles, 27 de agosto de 2008

Hacer copia de seguridad del MBR

Si instalamos y reinstalamos frecuentemente distintos sistemas operativos en el mismo disco duro es frecuente perder el MBR (Master Boot Record).

Cuando ya tenemos un MBR que nos sirve y no lo queremos perder en ninguna reinstalación podemos hacer una copia de seguridad, para ello hay que ejecutar el siguiente comando.

dd if=/dev/sda of=/mbr.bak bs=512 count=1

Donde /dev/sda es el disco duro y /mbr.bak la copia de seguridad, para reestablecer la copia de seguridad tan solo hay que hacer.

dd if=/mbr.bak of=/dev/sda bs=512 count=1

El problema al hacerlo así es que también estamos sobreescribiendo la tabla de particiones, para no afectar a la tabla de particiones sobreescribiendo el gestor de arranque hay que escribir solo los primeros 446 bytes.

dd if=/dev/sda of=/mbr.bak bs=446 count=1
dd if=/mbr.bak of=/dev/sda bs=446 count=1

martes, 26 de agosto de 2008

Matar procesos selectivamente en linux

Para terminar (matar) procesos en linux se suele usar la orden kill pid o killall programa pero hay otra forma de hacerlo más potente.

El comando en cuestión es pkill, dejo una guía rápida de las opciones que permite, siempre se pueden combinar varias.

pkill -u usuario mata todos los procesos de un usuario.

pkill patron mata todos los procesos en los que el patrón esté incluído en el nombre.

pkill -n patron mata al proceso más nuevo de los que coinciden con el patrón.

pkill -o patron mata al proceso más antiguo de los que coinciden con el patrón.

pkill -x patron mata los procesos en los que el nombre coincide exactamente con el patrón.

pkill -v -u usuario mata todos los procesos que no son del usuario (-v invierte el efecto de la acción).

Hay algunas opciones más, para verlas todas man pkill.

domingo, 24 de agosto de 2008

Número de argumentos variables en C

Para crear un método que acepte un número de argumentos variables en C hay que incluir la cabecera stdarg, una vez incluída podremos acceder a las macros va_start, va_arg y va_end.

va_start acepta como parámetro el último parámetro antes de la lista variable.
va_arg necesita el tipo del parámetro que hay que devolver.
va_end libera los recursos usados para la lectura de parámetros.

#include <stdio.h>
#include <stdarg.h>

int sumatorio(int howmany, ...){
int i;
int total = 0;
va_list ap;

va_start(ap, howmany);

for (i=0; i<howmany; i++)
total+=va_arg(ap, int);

va_end(ap);

return total;
}

int main(){
printf("%d\n", sumatorio(4, 1,2,3,4));
}

Comprobaciones numéricas en C

Es conocido que C es un lenguaje muy potente pero a muy bajo nivel, esto tiene algunas consecuencias al trabajar con valores numéricos que con otros lenguajes ni nos plantearíamos.

En primer lugar, ¿qué devuelven las funciones matemáticas en caso de que no exista un resultado a su operación?

Hay algunas funciones matemáticas como la raíz cuadrada y el logaritmo que no siempre tienen solución, en estos casos se devuelve nan (Not A Number) y se puede comprobar con la función isnan.

Otra situación posible es llegar a un valor infinito, ¿qué ocurre entonces? pues se devuelve inf y se puede comprobar con isinf.

Aquí un ejemplo de como se puede llegar a estas situaciones, para compilar gcc prog.c -o prog -lm.

#include <stdio.h>
#include <math.h>

int main(){
float dividendo=999999999;
float divisor=0.000000000000000000000000000000001;
float num=dividendo/divisor;

if(isinf(num)) printf("Infinito\n");
printf("%f\n",num);

num=sqrt(-num);
if(isnan(num)) printf("Not a number\n");

printf("%f\n",num);
}

viernes, 22 de agosto de 2008

Threads en ruby

El manejo de threads en ruby es muy sencillo, la creación de threads se basa en pasar un bloque a la creación de un objeto de la clase thread.

#!/usr/bin/ruby

t1 = Thread.new do
10.times do
puts "hello from thread 1"
sleep(0.2)
end
end

t2 = Thread.new do
10.times do
puts "hello from thread 2"
sleep(0.2)
end
end

t1.join
t2.join

Para pasar parámetros se hace de la siguiente forma.

#!/usr/bin/ruby

t1 = Thread.new(1) do |id|
10.times do
puts "hello from thread #{id}"
sleep(0.2)
end
end

t2 = Thread.new(2) do |id|
10.times do
puts "hello from thread #{id}"
sleep(0.2)
end
end

t1.join
t2.join

Para controlar las secciones criticas tan solo hay que cambiar la variable de clase critical a true.

#!/usr/bin/ruby

counter = 0;

t1 = Thread.new do
100000.times do
Thread.critical = true
counter += 1
Thread.critical = false
end
end

t2 = Thread.new do
100000.times do
Thread.critical = true
counter -= 1
Thread.critical = false
end
end

t1.join
t2.join

puts counter

Se pueden consultar los demás métodos de la clase Thread en la documentación oficial.

jueves, 21 de agosto de 2008

Resaltado de expresiones regulares

A veces cuando estamos trabajando con expresiones regulares nos podemos perder un poco, para hacer más fácil la tarea se puede realizar un resaltado del matching de la siguiente forma.

#!/usr/bin/ruby

pre = "\033[7m"
post = "\033[m"

print "Cadena> "
STDOUT.flush
str = gets.chop!

while true
print "Expresion regular> "
STDOUT.flush
re = Regexp.new(gets.chop!)
puts str.gsub(re, "#{pre}\\&#{post}")
end


Un ejemplo de uso.

domingo, 17 de agosto de 2008

Patrón singleton en ruby

Singleton es un patrón de diseño en ingeniería del software, un singleton es una clase de la que solo se puede obtener un objeto. Se suele utilizar en ocasiones en las que un objeto se utiliza de forma global o por lo que sea existe la restricción de no poder crear más de un objeto de una determinada clase.

Su implementación en ruby sería la siguiente.

#!/usr/bin/ruby

class Singleton
@@instance = nil
@contador = nil

def Singleton.createInstance
@@instance ||= new
end

def Singleton.getInstance
@@instance
end


def aumentarContador
@contador = (@contador || 0) + 1
end

private_class_method :new
end

Se declara como privado el método new para evitar crear objetos de la clase.
Como se puede ver instance es una variable de clase y por lo tanto compartida, pero contador es una variable de instancia, sin embargo, si ejecutamos lo siguiente.

s = Singleton.createInstance
s2 = Singleton.createInstance
s3 = Singleton.getInstance

puts s.aumentarContador
puts s2.aumentarContador
puts s3.aumentarContador

Podemos ver que tan solo hay un objeto de la clase Singleton.

sábado, 16 de agosto de 2008

Definir métodos dinámicamente en ruby

Ruby permite la definición dinámica de métodos, para ello hay varios métodos en Class que nos ayudan.

#!/usr/bin/ruby

class Clase
end

objeto = Clase.new

Clase.send :define_method, :saludo do
puts "Hola mundo"
end

objeto.saludo if Clase.method_defined?(:saludo)

Clase.send :undef_method, :saludo

# Tambien puede usarse:
# Clase.send :remove_method, :saludo

objeto.saludo if Clase.method_defined?(:saludo)

Mediante :define_method se define dinámicamente el método saludo y luego vemos como mediante :undef_method lo podemos eliminar. Con method_defined? consultamos si el método está definido en ese momento o no.

Lo de ejecutar los métodos :define_method y :undef_method mediante send es porque son privados.

¿Qué ventajas puede tener definir los métodos dinámicamente? Pues la primera es que se puede elegir el nombre de los métodos añadidos dinámicamente ya que en lugar de símbolos como nombres también aceptan cadenas. No es una gran ventaja, pero puede ser útil en algún caso.

Además de eso donde si puede resultar muy útil la definición automática de métodos es en programas en los que las acciones posibles a ejecutar evolucionen con el tiempo.

Puede parecer que son situaciones muy rebuscadas, pero no lo son tanto, sería útil en la gran mayoría de juegos de rol, según la ocasión el protagonista puede realizar unas acciones y no otras.

viernes, 15 de agosto de 2008

Generación dinámica de javascript y css con php

El lenguaje php es usado normalmente para generar html dinámicamente según los parámetros de entrada correspondientes.

Sin embargo, no es tan conocido que con php no solo se puede generar html sino cualquier tipo de fichero, los más interesantes en diseño web son javascript y css.

Para generar distintos tipos de ficheros simplemente hay que cambiar el content-type, dejo un ejemplo de como se puede generar un fichero javascript dinámicamente.

En el fichero principal.

<html>
<script type='text/javascript' src='jscripts.php'></script>

<body>
<h1>Usando php...</h1>

<?php
echo 'hola mundo <br/>';
?>
<a href=# onclick="saludo()">Haz click</a>

</body>
</html>

En el fichero jscripts.php.

<?php 
header('Content-Type: text/javascript; charset=utf-8');
echo "function saludo(){alert('hello');}";
?>

Editar texto 'in place'

Hay un efecto muy útil que tienen muchas webs para editar texto, el texto aparece como normalmente pero si hacemos click en él aparece una caja de texto para editarlo.

Ese efecto se puede conseguir de varias formas, una de ellas es mantener dos div's con el mismo texto, uno con el texto en sí y otro con una caja de texto, luego haciendo uso del evento onclick mostrar el que queramos.

En cualquier caso podemos hacerlo también con jquery y un plugin llamado jedit.

Un ejemplo de como queda.

<html>
<head>
<script src="jquery.js" type="text/javascript"></script>
<script src="jquery.jeditable.js" type="text/javascript"></script>

<script>
$(document).ready(function() {
$(".edit").editable("edit.php");
});
</script>

</head>

<body>
<div class="edit">Texto texto texto texto texto texto texto texto texto texto texto texto texto texto texto texto texto texto texto
texto texto texto texto texto texto texto texto texto texto texto texto texto texto texto texto texto texto texto texto texto
texto texto texto texto texto texto </div>
</body>
</html>

En la web de jedit hay más ejemplos de lo que se puede hacer con este plugin.

martes, 12 de agosto de 2008

Operaciones vectoriales en C++

Una de las mejoras que tienen los nuevos procesadores sobre los antiguos es la inclusión de operaciones vectoriales o SIMD (Single Instruction Multiple Data).

Estas instrucciones básicamente operan bajo un conjunto de datos (normalmente un vector) en paralelo reduciendo brutalmente el tiempo de ejecución.

En la web de gcc sobre operaciones vectoriales se explica como se pueden usar.

Para compilarlo con gcc se pueden pasar las opciones -mmmx, -msse, -msse2, -msse3 o -m3dnow, según el procesador será mejor una u otra.

En el siguiente ejemplo se consigue una mejora de entre 5 o 6 veces usando las instrucciones SIMD en mi Pentium IV.

#include <iostream>

#define SIZE 8

using namespace std;

typedef int vectorSIMD __attribute__ ((vector_size(SIZE*4)));

int main() {
long int start, end, tiempo1, tiempo2;
int repeticiones = 9999999;

int total[] = {0, 0, 0, 0, 0, 0, 0, 0};
int sumando[] = {1, 4, 3, 7, 2, 4, 5, 6};

vectorSIMD totalV = {0, 0, 0, 0, 0, 0, 0, 0};
vectorSIMD sumandoV = {1, 4, 3, 7, 2, 4, 5, 6};

cout << "Empezando suma de vectores" << endl;
start=clock();
for (int i=0;i<repeticiones;i++){
for(int j=0;j<SIZE;j++){
total[j]+=sumando[j];
}
}
end=clock();
tiempo1=end-start;
cout << "Suma de vectores realizada en " << tiempo1 << " tics de reloj" << endl;

cout << "Empezando suma vectorial" << endl;
start=clock();
for (int i=0;i<repeticiones;i++){
totalV+=sumandoV;
}
end=clock();
tiempo2=end-start;
cout << "Suma vectorial realizada en " << tiempo2 << " tics de reloj" << endl;

cout << "Se ejecuta " << tiempo1/((float)tiempo2) << " veces mas rapido con las instrucciones SIMD" << endl;
}

sábado, 9 de agosto de 2008

Haciendo capturas de pantalla en linux

Hay algunos programas para hacer capturas de pantalla en linux, el más versátil es import que viene incluído en ImageMagick.

Para crear una captura tan solo hay que ejecutar el comando.

import captura.png (Y después seleccionar la parte de la pantalla que se quiera capturar).

import -window ventana captura.png (Para capturar la ventana 'ventana').

import -window root captura.png (Para hacer una captura de pantalla completa).

sleep 5; import -window root captura.png (Para hacer una captura completa después de 5 segundos).

Maquetación web básica con CSS

La maquetación CSS puede parecer compleja al principio pero simplifica bastante el proceso de diseño web.

Aquí dejo un boceto de como se divide una página en secciones, cada una la he dejado de un color para distinguirlas mejor.

En el fichero html.

<html>
<head>
<link rel="stylesheet" type="text/css" href="styles.css" />
<title>Titulo</title>
</head>

<body>
<div id="page">
<div id="top"></div>
<div id="leftContent"></div>
<div id="centerContent"></div>
<div id="rightContent"></div>
<div id="foot"></div>
</div>
</body>
</html>

En el fichero CSS.

#page{
width: 800px;
height: 550px;
}

#top{
width: 800px;
height: 100px;
background-color: blue;
}

#leftContent{
width: 200px;
height: 350px;
background-color: yellow;
float:left;
}

#centerContent{
width: 400px;
height: 350px;
background-color: green;
float:left;
}

#rightContent{
width: 200px;
height: 350px;
background-color: red;
float:left;
}

#foot{
width: 800px;
height: 100px;
background-color: blue;
float: left;
}

Y el resultado en el navegador.

viernes, 8 de agosto de 2008

SVN fácil y rápido

Para administrar el código de proyectos con algo de dimensión se suelen/deben usar sistemas de control de versiones. El más usado seguramente es Subversion (svn).

Dejo una lista de los comandos más habituales.


svnadmin create "path al repositorio" (Crea un repositorio)

svn checkout "path al repositorio" (Copia un repositorio localmente)

svn update fichero (Actualiza el fichero a la última versión)

svn update -rV fichero (Actualiza el fichero a la versión V)

svn add fichero (Añade el fichero al repositorio)

svn delete fichero (Elimina el fichero del repositorio)

svn copy fichero1 fichero2 (Copia el fichero en el repositorio)

svn move fichero1 fichero2 (Mueve el fichero en el repositorio)

svn revert fichero (Elimina los cambios hechos al fichero localmente)

svn diff fichero (Muestra las diferencias creadas localmente con la última versión)

svn diff fichero@1 fichero@2 (Muestra las diferencias entre la versión 1 y la 2)

svn commit fichero (Sube el fichero al repositorio)

svn resolve fichero
(Resuelve los conflictos del fichero, lo deja listo para poder subirlo)

domingo, 3 de agosto de 2008

Cambiando la apariencia de las webs con Greasemonkey

Greasemonkey es una extensión para firefox que permite aplicar automáticamente nuestro código javascript al entrar en una web.

Hay miles de scripts en internet pero lo interesante es que resulta muy fácil crear uno desde cero en muy poco tiempo para cambiar lo que no nos gusta de los sitios que visitamos. Incluso se pueden añadir nuevas funcionalidades.

Aquí dejo un ejemplo de como se puede convertir con Greasemonkey la portada de google.es a "irish google".

// ==UserScript==
// @name firstscript
// @namespace http://javiyu.es
// @include http://www.google.es*
// ==/UserScript==

//Cambia el color de fondo
document.body.bgColor="448844";

//Quita la barra de arriba si has accedido con tu cuenta
var guser=document.getElementById('guser');
if(guser){
guser.parentNode.removeChild(guser);
}

var gbar=document.getElementById('gbar');
if(gbar){
gbar.parentNode.removeChild(gbar);
}

var gbhs=document.getElementsByClassName('gbh');
while(gbhs.length>0){
gbhs[0].parentNode.removeChild(gbhs[0]);
}

//Quita el logo de google
var divs=document.getElementsByTagName('div');
for(i=0;i<divs.length;i++){
if(divs[i].title=="Google"){
divs[i].style.background="url(http://www.garmentrecoverysystems.com/images/irish_flag.jpg)";
divs[i].style.width="500px";
divs[i].style.height="150px";

divs[i].textContent="";
}
}

//Cambia el texto de los botones
var inputs=document.getElementsByTagName('input');
for(i=0;i<inputs.length;i++){
if(inputs[i].value=="Voy a tener suerte")
inputs[i].value="Soy un suertudo";

if(inputs[i].value=="Buscar con Google")
inputs[i].value="Busca leprechaun!";
}

Aquí el resultado

viernes, 1 de agosto de 2008

Efectos javascript con script.aculo.us

Para crear webs atractivas con multitud de efectos en javascript sin perder demasiado tiempo hay muchas librerías, a mi la que mas me gusta es script.aculo.us.

La instalación consiste en los siguientes pasos:

1) Bajar el fichero con la última versión de la web.

2) Descomprimir el fichero.

3) Copiar fichero prototype.js (directorio lib) y builder.js, controls.js, dragdrop.js, effects.js, scriptaculous.js, slider.js, sound.js y unittest.js (directorio src) en nuestra carpeta de javascripts.

4) Añadir las siguientes líneas a nuestra página web.

<script src="javascripts/prototype.js" type="text/javascript"></script>
<script src="javascripts/scriptaculous.js" type="text/javascript"></script>

En la documentación oficial se pueden encontrar detalladas todas las posiblidades, aquí os dejo un ejemplo con algunos efectos.

<html>
<head>
<script src="javascripts/prototype.js" type="text/javascript"></script>
<script src="javascripts/scriptaculous.js" type="text/javascript"></script>
<title></title>
</head>

<body>
<p id="texto">TextoTextoTextoTexto TextoTextoTextoTexto <br/>
TextoTextoTextoTexto TextoTextoTextoTexto TextoTextoTextoTexto</p>

<button type="button" onclick="new Effect.Highlight($('texto'));">Highlight</button>

<button type="button" onclick="$('texto').morph('background:#00ffff; width:300px;');">Morph</button>

<button type="button" onclick="$('texto').morph('background:#ffffff; width:600px;');">UnMorph</button>

<button type="button" onclick="new Effect.Move($('texto'),{x:60, y:60 });">Move</button>

<button type="button" onclick="new Effect.Scale($('texto'),200);">Scale</button>

<button type="button" onclick="new Draggable($('texto'));">Draggable</button>
</body>
</html>

domingo, 27 de julio de 2008

Atributos virtuales en Ruby

Los métodos set y get de las clases se usan supuestamente para encapsular la información y ocultar la implementación de esa clase.

Lo que ocurre es que muchas veces no se aprovecha adecuadamente esta última posibilidad, donde hay getAtributo debería haber getInformacion, que no siempre es exactamente lo mismo. No se oculta la implementación de la clase (que haría más fácil futuros cambios) sino que prácticamente se nos están diciendo los atributos.

En ruby se pueden usar atributos virtuales para realmente separar entre la información útil de la clase y los atributos que se necesitan para almacenarla.

#!/usr/bin/ruby

class Tiempo
attr_accessor :segundos;

def minutos=(new_minutos)
@segundos = new_minutos*60;
end

def minutos
@segundos/60
end

def horas=(new_horas)
@segundos = new_horas*60*60;
end

def horas
@segundos/(60*60)
end
end

t = Tiempo.new
t.segundos = 3;
puts t.segundos

t.minutos = 3;
puts "#{t.minutos} #{t.segundos}"

t.horas = 1;
puts t.minutos

Nos es totalmente indiferente como se guarde la información (en este caso en segundos), se convierte dinámicamente entre unidades sin ningún problema, tanto para obtener información como para grabarla.

Se hace pues la distinción entre información(horas, minutos, segundos) y los atributos(segundos). Aquí hay un ejemplo de lo que no hay que hacer, por dos motivos:

1) Dejar la interfaz de la clase de forma no intuitiva, hay que convertir a milisegundos para guardar una fecha.

2) Dejar todos los métodos útiles para obtener información sin mantener (deprecated) al haber cambiado la implementación de la clase.

sábado, 19 de julio de 2008

Python en Symbian

Desde hace un tiempo es posible programar en python para esta plataforma sin muchas dificultades, yo estoy usando PyS60 que es libre y se puede descargar gratuitamente.

Para acceder a la documentación de la API específica estoy usando esta página de Nokia.

Como editor de textos uso LightNotepad que se puede descargar también gratuitamente aquí, aunque es más cómodo programar en un ordenador y luego pasar el programa al teléfono.

Os dejo con un Hello world.

import appuifw

appuifw.note(u'Hello world!', 'info')

Busqueda incremental haciendo peticiones al servidor

Con búsqueda incremental me refiero a la misma que me refería en este otro post, la diferencia es que en esta ocasión mostraré la manera de hacer la búsqueda haciendo peticiones al servidor.

Lo primero que necesitamos es poder hacer consultas al servidor sobre algo, así que en lugar de crear una base de datos vamos a simular el comportamiento mediante un programa php muy simple.

<?php
if($_GET['q']){
$consulta=$_GET['q'];
$coche[0]="seat ibiza";
$coche[1]="opel corsa";
$coche[2]="ford fiesta";
$coche[3]="citroen ax";
$coche[4]="seat leon";

for($i=0;$i<5;$i++){
$devolver=1;
for($j=0;$j<strlen($consulta);$j++){
if($consulta[$j]!=$coche[$i][$j]){$devolver=0;}
}
if($devolver==1){echo $coche[$i] . "<br>";}
}
}
?>

De la consulta que reciba va a devolver los elementos del array coincidentes.

Para el código de autocompletado vamos a usar la librería de javascript prototype, tan solo hay que bajarla de la web oficial e incluirla como fuente en nuestra página.

<html>
<head>
<script src="prototype.js" type="text/javascript"></script>
</head>

<body>
<form method="get">
<input type="text" onkeyup="new Ajax.Updater('coches', 'query.php?q='+this.value, {method: 'get' })">
</form>
<br>

<div id="coches"></div>
</body>
</html>

Con el método Ajax.Updater vamos creando consultas conforme vamos escribiendo en la caja de texto y se añaden al div que hemos dejado para que vayan apareciendo.

domingo, 13 de julio de 2008

Incluir email en la web sin sufrir spam

Es de sobra conocido que hay programas rastreando las web intentando conseguir direcciones de email para después enviarles spam.

La solución para evitarlo es colocar una imagen con la dirección de email escrita, ya que estos programas solo pueden buscar en texto, sin embargo, esta imagen no es seleccionable, por lo que se pierde usabilidad.

Hay una forma de incluir tu email en texto en una web sin que los robots de los spammers puedan leerlos, es incluir el siguiente javascript.

<script language="javascript">
user="milogin";
server="miservidor.com";
at="@"
document.write('<a href="mailto:'+user+at+server+'">');
document.write("Mi email es: "+user+at+server);
document.write("</a>");
</script>

Simplemente escribe la direccion de email en la página, xo los rastreadores no pueden ejecutar el código fuente en javascript, al menos todavía no.

Para los navegadores que no soporten javascript se puede utilizar la etiqueta noscript e incluir una imagen.

domingo, 6 de julio de 2008

Búsqueda en el historial de bash

Después de ejecutar una serie de comandos en la shell de linux es bastante probable que necesitemos repetir alguno anterior. Puede pasar además que sea largo o que tenga una mezcla de caracteres no muy cómoda de escribir.

Para esos casos existe en bash lo que se llama reverse-i-search, para probarlo hay que hacer lo siguiente.

- Ejecutar unos cuantos comandos largos en una shell de linux (si son largos mejor para el ejemplo).

- Pulsar ctrl + r, la shell cambiara y pondrá algo similar a (reverse-i-search)`':.

- Escribir las primeras letras de uno de los comandos.

Cuando te acostumbras es la mejor forma de acceder al historial de órdenes, mejor incluso que las flechas de arriba y abajo para ir recorriéndolo.

sábado, 5 de julio de 2008

Búsqueda incremental con javascript

Últimamente se ha puesto de moda en la mayoría de redes sociales y en otros servicios web un tipo de búsqueda incremental.

Esto quiere decir que si quieres buscar "blog", cuando llevas puesto "bl" ya te sale "blog" como sugerencia.

¿Cómo se puede implementar esto?
Seguramente la forma más sencilla y rápida es la siguiente. Como queremos una respuesta inmediata debermos procurar exigir lo mínimo posible al servidor y tener todos los datos en el cliente.

Así pues, para dominios reducidos (ej. tus amigos en tuenti) se hace que el servidor al generar la página genere un script en javascript dinámicamente con un vector que contenga los nombres de todos los elementos a buscar, así cuando empecemos a introducir letras la búsqueda se puede realizar rápidamente.

Para dominios mayores no se debería utilizar esta técnica, primero porque javascript no destaca por su velocidad y segundo porque el tamaño de la página generada puede ser excesivamente grande.

viernes, 27 de junio de 2008

Crear la base de datos de una red social

Crear la base de datos de una red social puede parecer en principio muy complicado, nada más lejos de la realidad, lo que seguramente sea más difícil es optimizar los accesos en caso de que obtenga un gran número de usuarios.

Suponiendo que usamos el modelo relacional, deberíamos crear una tabla de usuarios tal como:

id | datos

Dónde id es un identificador único para cada usuario y datos son los datos específicos que queremos guardar, nombre, apellidos, email, etc.

No todos los datos personales como tales pueden/deben ir ahí, si por ejemplo queremos guardar las aficiones y poder estudiarlas más tarde deberíamos tener una tabla aficiones.

id | aficion


Al igual que podemos crear grupos de usuarios de una forma similar.

id | grupo

Y otra tabla propia a la información de cada grupo.

grupo | informacion_relevante

Con unas consultas simples podemos reconstruir toda la información relativa a estos datos.

La mayor utilidad de las redes sociales es el enlace entre usuarios, así que también necesitaremos guardar esta información en una tabla llamada enlaces o amigos.

id1 | id2

Podemos tener otras si tenemos varios tipos de relaciones (por cierto no me ha parecido ver esto implementado en ninguna red social, tan solo amistad).

Una de las utilidades más usadas de las redes sociales es la de etiquetar a gente en las fotos.
Se me ocurren dos formas de implementarlo, teniendo una tabla global de fotografías (grandísima) o creando una tabla por fotografía (muchísimas tablas). Creo que la segunda escalaría peor que la primera, pero es cuestión de probarlo en un DBMS concreto.

Las otras aplicaciones como tablón, envío de mensajes, solicitudes pendientes de amigos...no difieren demasiado de estas.

Como se puede ver conceptualmente la base de datos de una red social no es nada complicada comparada con otras aplicaciones, sin embargo hay que tener en cuenta que optimizarla para soportar 80 millones de usuarios que tiene facebook debe ser algo más complicado.

miércoles, 25 de junio de 2008

Otra visión de top

Hay varias formas de mostrar los procesos que están ejecutándose en linux, ps, top, pstree...pero hay otro comando menos popular y quizá más útil, htop.

Aquí os dejo una captura de pantalla.



Aparte de estar la información mejor organizada en la pantalla se pueden organizar los procesos por CPU gastada, memoria entre otras cosas, además se puede cambiar la prioridad de procesos, organizarlos en árbol e incluso matarlos.
Todo ello con una tecla.

Modificar cookies

La mayoría de webs en las que hay que registrarse nos mandan cookies con información necesaria para comprobar que somos nosotros. Es posible que nosotros también lo necesitemos para crear nuestras propias webs.

Para depurar, se puede ver cual es el valor actual de las cookies mandada por la página actual usando el siguiente script en la barra de navegación.

javascript:void(document.cookie=prompt("Cambiar cookie",document.cookie).split(";"))

Si queremos, podemos mostrar las cookies separadas por campos para que resulte más claro. Simplemente necesitamos iterar sobre el script anterior.

javascript:for(var g in document.cookie.split(";"))void(prompt("Cambiar cookie "+document.cookie.split(";")[g].split("=")[0],document.cookie.split(";")[g].split("=")[1]));alert("Cookies:\n"+document.cookie.replacer(/;/,"\r\n"));

martes, 24 de junio de 2008

Descomprimir ficheros en python

Para descomprimir ficheros en python podemos usar la librería gzip. Puede resultar muy útil para guardar de forma eficiente el estado de nuestros programas y posteriormente recuperarlo.

Aquí un ejemplo.

#!/usr/bin/python

import gzip;

f=open("prueba.txt", "r");
texto=f.read();
print texto;

print "----------------";

comprimido=gzip.open("prueba.gz", "r");
descomprimido=comprimido.read();

print descomprimido;

Como se puede ver tan solo es necesario llamar al método open del módulo gzip y ya podemos tratarlo como un fichero descomprimido.

Expresiones regulares en python

Uno de los módulos mas interesantes en python es el que se encarga de proporcionarnos las funcionalidades de las expresiones regulares. Este módulo se llama re.

Veamos un ejemplo de uso.

#!/usr/bin/python

import re;

cadena_larga="esto es una cadena muy larga";

if(re.search("cadena", cadena_larga)):
print "caso 1: presente";
else:
print "caso 1: ausente";

if(re.search("ca.ena", cadena_larga)):
print "caso 2: presente";
else:
print "caso 2: ausente";

if(re.search("\s.\s|\s..\s", cadena_larga)):
print "caso 3: presente";
else:
print "caso 3: ausente";

if(re.search("[0-9]", cadena_larga)):
print "caso 4: presente";
else:
print "caso 4: ausente";

if(re.search("[^0-9]", cadena_larga)):
print "caso 5: presente";
else:
print "caso 5: ausente";

if(re.search("ga$", cadena_larga)):
print "caso 6: presente";
else:
print "caso 6: ausente";

En estos ejemplos se está usando el método search, search busca coincidencias en toda la cadena. También existe match que tan solo busca coincidencias desde el principio de la cadena.

El primer ejemplo es el más sencillo, se busca la subcadena "cadena" dentro del texto.

En el segundo se introduce el uso del operador ".", que equivale a cualquier carácter.

En el tercer ejemplo se reúne el OR de dos consultas, palabras de un carácter con espacios a los dos lados y palabras con dos caracteres.

En el cuarto se busca cualquier número que haya en la cadena.

En el quinto justo lo contrario que en el cuarto, la ausencia de números.

En el sexto ejemplo se comprueba si la cadena termina con los caracteres "ga", para comprobar el comienzo de la cadena se usa "^".

Las expresiones regulares no son muy útiles si no podemos recuperar subcadenas de los textos que tratamos, se hace de la siguiente forma.

#!/usr/bin/python

import re;

cadena_larga="esto es una cadena muy larga";

parsed=re.search("(\S+)\s",cadena_larga);
print parsed.groups();

print re.findall("(\S+)\s",cadena_larga);

En el caso de usar search buscamos las primera palabra seguida de espacio, en el caso de findall se devuelve una lista con todas las coincidencias.

sábado, 7 de junio de 2008

Leyendo correo POP3 desde python

Acceder a una dirección de correo electrónico desde python es muy sencillo si se tiene habilitado POP3.

Para ello se puede usar la librería poplib. Para los ejemplos usaré gmail, si queréis probarlo acordaros de habilitar POP3 en la web de gmail.

#!/usr/bin/python

import poplib;

p=poplib.POP3_SSL("pop.gmail.com");
p.user("usuario@gmail.com");
p.pass_("pass");

mensajes=p.list()[1];

lastmsg=mensajes[-1].split()[0];

print p.retr(lastmsg);

p.quit();

Primero creamos un objeto POP3_SSL, (gmail funciona con SSL), metemos usuario y contraseña.
A partir de entonces ya podemos administrar el correo con las funciones que nos provee la librería poplib.

En el ejemplo se obtiene la lista de mensajes con list(), se elige de la respuesta el último mensaje y se le pide al servidor mediante retr(msgid). Es necesario parsear la salida puesto que lo que tenemos hasta el momento es la respuesta en bruto del servidor, pero si leéis en pantalla ya podeis distinguir de que mensaje se trata.

Usando esto podemos crear muy fácilmente un programa que revise nuestro buzón de correo y nos avise cuando nos llega un nuevo mensaje.

#!/usr/bin/python

import poplib;
import time;

oldmensajes=0;
nmensajes=0;
first=1;

while(1):
p=poplib.POP3_SSL("pop.gmail.com");
p.user("usuario@gmail.com");
p.pass_("pass");

nmensajes=p.stat()[0];
print nmensajes;

p.quit();

if(first==1):
oldmensajes=nmensajes;
first=0;


if(nmensajes!=oldmensajes):
print "Se ha recibido " + str(nmensajes-oldmensajes) + " mensaje(s) nuevos";
nmensajes=oldmensajes;

time.sleep(300);

El script no está probado, solo es un ejemplo de como se podría crear algo útil con esta librería.

Importación de módulos en python

En python hay varias formas de importar módulos, la primera de ellas es la siguiente.

#!/usr/bin/python

import math

print math.sqrt(80)

Se importa la librería math pero después para hacer uso de la función sqrt es necesario especificar que viene de esta librería en concreto.

Se hace así para diferenciar que funciones vienen de cada librería y que no haya confusión de a que función estamos llamando.
Si por ejemplo disponemos de una librería matemática más rapida pero menos completa, para sustituir esta llamada se podría hacer math2.sqrt(80) sin ningún problema.

La segunda manera de importar módulos es como sigue.

#!/usr/bin/python

from math import sqrt

print sqrt(80)

En esta ocasión nos ahorramos especificar en la llamada de donde viene la función sqrt pero debe especificarse en la importación.
Esta forma de importar funciones de los módulos hace que quede muy claro que funciones se usan y de donde provienen, además simplifica la sintaxis en la llamada pero tiene un problema; si tenemos en cuenta el ejemplo de antes, debemos saber de antemano que llamadas vamos a usar de math y de math2 y no podríamos usar sqrt de las dos en el mismo programa.

La tercera forma es la siguiente.

#!/usr/bin/python

from math import *

print sqrt(80)

Es igual a la primera pero sin necesidad de indicar el espacio de nombres en cada llamada, tiene el mismo problema de la segunda y en general es considerado un mal hábito de programación. Se están importando multitud de nombres que pueden colisionar con los del programa y no provee ninguna utilidad especial.

En conclusión, para scripts pequeños de unas cuantas líneas me quedaría con la segunda o la tercera por sencillez, pero si se pretende hacer algo más grande y serio la primera opción es la adecuada.