jueves, 22 de mayo de 2008

Comentarios - control de versiones

Me encontré con este artículo que propone un formato bastate interesante para los comentarios en los commits, ya sea Subversion o CVS.
Me pareció interesante ya que suele suceder en los proyectos que debemos hacer un rollback de un cambio, o solucionar un bug y vamos al historial del repositorio ya que muchas veces ese cambio no lo hicimos nosotros.
El formato que se propone ayuda mucho a identificar que se realizó en cada commit.

En el artículo se proponen estos "tags" para agrupar la información del los comentarios:
  • ADDED - descripción de que se agregó
  • CHANGED - descripción de lo que se cambió
  • FIXED - bugs que se corrigieron (se propone poner un link al bug)
  • DELETED - lo que se borró

lunes, 12 de mayo de 2008

Trim sencillo en Javascript

Usando la propiedad prototype, en este caso para la clase String, podemos hacer una función de trim para los Strings.
String.prototype.trim = function() {
return(this.replace(/^\s+/,'').replace(/\s+$/,''));
}
Luego para cualquier String hacemos:
var texto = " He aquí un texto   ";
texto = texto.trim(); //retorna el texto sin espacios delante o detrás

viernes, 9 de mayo de 2008

Sphinx - mejorar búsquedas full-text en MySQL

Sphinx es un motor de búsquedas full-text open-source.

Llegué a él gracias a la pobre performance de MySQL (gracias!), ya que en una tabla de 2 millones de registros, hacer una búsqueda por keywords tardaba 10seg. Este tiempo para una aplicación online no era nada bueno.

Luego de intentar mejorar la performance de MySQL me rendí y me puse a buscar. Me acordaba que existía Lucene, pero para Java (aunque debe existir algún port a PHP). De ahí fue que llegué a Sphinx e investigando un poquito parecía que servía. ¿Siguiente paso? probarlo obviamente, nunca hay que quedarse con lo que dicen los blogs, incluyendo este :)


Los siguientes pasos los probé en un ubuntu dapper, pero debería ser similar para otras distribuciones.

Primero instalar dependecias para compilar Sphinx
$ sudo apt-get install build-essential libmysql++-dev


Bajar el .tar.gz y extraer:
$ tar -xf sphinx-0.9.8-rc2.tar.gz


Compilar
$ cd sphinx-0.9.8-rc2
$ sh ./configure
$ make
$ sudo make install


Listo. Sphinx está instalado, ahora a configurarlo.
Para este ejemplo (muy simple) sólo utilizaremos una tabla, que contiene entradas de un blog. Así sería la tabla:

CREATE TABLE Post (
id int(10) unsigned NOT NULL auto_increment,
titulo varchar(7) NOT NULL,
post varchar(256) NOT NULL,
PRIMARY KEY (id)
) ;


Creamos el archivo de configuración
$ sudo gedit /usr/local/etc/sphinx.conf


Primeramente vamos a crear una fuente de datos, en este caso MySQL pero tambíen soporta PostgreSQL, XML y otras hierbas.
source blog
{
type = mysql
sql_host = localhost
sql_user = blog_user
sql_pass = passwd
sql_db = blog

# indexer query
# document_id MUST be the very first field
# document_id MUST be positive (non-zero, non-negative)
# document_id MUST fit into 32 bits
# document_id MUST be unique

sql_query = \
SELECT \
id, titulo, post \
FROM \
Post;

# document info query
# ONLY used by search utility to display document information
# MUST be able to fetch document info by its id, therefore
# MUST contain '$id' macro
# Esta parte se utiliza para devolver los resultados de la busqueda
# a partir de la consulta. Por cada resultado encontrado, realiza esa
# consulta y retorna los datos de la misma.
sql_query_info = SELECT * FROM Post WHERE id=$id
}

Luego agregamos la definición de nuestro índice:

index posts
{
source = blog
# ruta donde se guarda el indice
path = /var/data/sphinx/catalog

# tamaño minimo de palabra para indexar
min_word_len = 3

}
Finalmente agregamos los datos para el demonio de sphinx (que vamos a necesitar cuando usemos algun API)
searchd
{
port = 3312
log = /var/log/searchd/searchd.log
query_log = /var/log/searchd/query.log
pid_file = /var/log/searchd/searchd.pid
}
Guardamos el archivo y creamos la carpeta para guardar los índices:
$ sudo mkdir -p /var/data/sphinx


Creamos el índice:
$ sudo /usr/local/bin/indexer --config /usr/local/etc/sphinx.conf --all
Probamos la búsqueda, en este ejemplo buscamos la palabra "Java":
$ /usr/local/bin/search --config /usr/local/etc/sphinx.conf Java

Esto sólamente es un ejemplo muy simple de lo que se puede hacer con Sphinx, para mas detalles de esta mágica aplicación, incluyendo integración con PHP o Rails: http://www.sphinxsearch.com/

¿Alguna otra experiencia con búsquedas fulltext?

jueves, 8 de mayo de 2008

Fechas en Java

Algunos snippets para el manejo de fechas en Java.


Date fecha = new Date();

//Fecha simple 01/12/2001
SimpleDateFormat formateadorFecha =
new SimpleDateFormat("dd/MM/yyyy");
String fechaSimple = formateadorFecha.format(fecha);
System.out.println("(dd/MM/yyyy) -> " + fechaSimple);

//Fecha con hora 01/12/2001 22:35 (formato 24hrs)
formateadorFecha = new SimpleDateFormat("dd/MM/yyyy HH:mm");
fechaSimple = formateadorFecha.format(fecha);
System.out.println("(dd/MM/yyyy) -> " + fechaSimple);

//Agregar dias a una fecha
Calendar cal = Calendar.getInstance();
cal.add(Calendar.DATE, 2); //se agregan 2 dias
fechaSimple = formateadorFecha.format(cal.getTime());
System.out.println("(+2 dias) -> " + fechaSimple);

//Substraer minutos
cal = Calendar.getInstance();
cal.add(Calendar.MINUTE, -20); //se quitan 20min
fechaSimple = formateadorFecha.format(cal.getTime());
System.out.println("(-10 min) -> " + fechaSimple);

Espero que sea útil.

miércoles, 7 de mayo de 2008

Mejorar rendimiento de firefox

Googleando por ahi me encontré con estos simples cambios que podemos hacerle a firefox para que aumente su rendimiento. Lo primero que hay que hacer es escribir about:config en la barra de direcciones y dar enter.
Se nos muestra un diálogo como el siguiente:
















En este diálogo se listan los parámetros de configuración del Firefox, vamos a ajustar los siguientes:


network.http.pipelining.maxrequests – 100
network.http.max-connections – 48
network.http.max-connections-per-server – 16
network.http.max-persistent-connections-per-proxy – 8
network.http.max-persistent-connections-per-server – 4
network.http.request.timeout – 300
network.http.pipelining – true
network.http.proxy.pipelining – true

Reiniciar Firefox y listo.

martes, 6 de mayo de 2008

Slicehost

Hace un tiempo, un cliente estaba necesitando un servidor VPS fuera del país (debido al pobrismo ancho de banda de salida a Internet). Me pidió una investigación de las opciones disponibles, fue ahí que me topé con Slicehost.
Slicehost es un proveedor de hosting VPS, lo que me gustó ni bien llegué al sitio, fue la simplicidad en las configuraciones que brindan. Ellos tratan a los servidores virtuales como "slices" que sería algo así como una "tajada".

El slice más barato ($20 x mes) viene con 256MB de RAM, 10GB de almacenamiento y 100GB de transferencia. El más caro viene con 4GB de RAM 160GB y 1600GB de transferencia por unos módicos $280. Te cobran los 3 primeros meses juntos y luego te cobran mes a mes, por lo que puedes cancelarlo cuando quieras y no quedar atado a un contrato.



En mi caso concreto fuimos por el de 1GB de RAM. Luego de ingresar los datos de la tarjeta de crédito, en 2 minutos ya estaba el slice pronto (con su IP y todo).
Cuatro minutos después ya tenía instalado ubuntu a través del administrador de slices, desde donde se pueden ver estadísticas, reinstalar el SO e incluso reiniciar el slice, como si fuera un servidor dedicado. También ofrece una consola ajax para manejar el slice (obviamente la usé hasta instalar SSH).

El servicio es tan bueno que permite incluso hacer un "upgrade" del slice sin tener que borrar los datos y reconfigurar un server.
Si están buscando un servidor VPS, les recomiendo Slicehost.

domingo, 4 de mayo de 2008

JQuery - Eventos dinámicos

Un tiempo atrás me encontré haciendo una página PHP con el frontend bastante complejo, mucho AJAX y muchos cambios en la página.
En el proyecto estábamos utilizando JQuery, que es una librería javascript. Me topé con la funcionalidad de cambiar los eventos de un botón dinámicamente:

HTML:

<input type="button" name="botonDinamico" id="botonDinamico"
onclick="funcionInicial()">

Javascript:

$("#botonDinamico").unbind().click(function (){
funcionDos();
});
Al hacer "unbind()" se quitan los eventos a los que está enlazado. Luego se enlaza uno nuevo a través de la función "click()"

sábado, 3 de mayo de 2008

Screencast en Ubuntu

Varias veces he tenido que realizar alguna demo para un cliente y lo que más me ha resultado han sido los "screencasts". El impacto sobre el cliente es mucho mayor si la demo tiene "movimiento" y no son simplemente unas imágenes y una simple PPT.

A continuación un simple tutorial para crear nuestro screencast en ubuntu (probado en gutsy-7.10):
  • Bajar e instalar los paquetes .deb desde aquí
  • Luego de instalar nos queda un acceso directo en "Sound and Video"
  • Abrirlo y a disfrutar!!
Por defecto graba todo nuestro escritorio, pero tiene la opción de seleccionar una ventana para reducir el área de grabación, así como la calidad de audio y de video.
Nos deja un icono al lado del reloj de forma de poder parar la grabación(click derecho) o pausar la misma (click izquierdo).

La salida es en formato .ogg pero se puede convertir fácilmente con ffmpeg.

Por mas info sobre esta maravillosa app
http://recordmydesktop.iovar.org/about.php

viernes, 2 de mayo de 2008

Grabar video en J2ME

Snippet para grabar video en J2ME:

public void grabarVideo(){
//se inicializa un player
Player player = Manager.createPlayer("capture://video");
player.realize();

//se obtiene el control del video del player
VideoControl videoControl =
(VideoControl)(player.getControl("VideoControl"));
videoControl.initDisplayMode(
VideoControl.USE_DIRECT_VIDEO, this);
videoControl.setDisplayFullScreen(true);
videoControl.setVisible(true);
player.start(); //comienza la grabación

/* Se obtiene el control de grabación y se graba
por 10 segundos Los resultados son guardados en
un array de Bytes, pude guardarse también
en un archivo
*/
ByteArrayOutputStream output = new ByteArrayOutputStream();

RecordControl recordControl =
(RecordControl)(player.getControl("RecordControl"));
recordControl.setRecordStream(output);
recordControl.startRecord();
try {
Thread.sleep(10000);//graba durante 10 segundos
} catch (InterruptedException ex) {
//manejo de la excepción
}
try {
//se llama al commit para finalizar la grabación
recordControl.commit();
output.flush(); //flush de los datos dentro del buffer
} catch (IOException ex) {
//manejo de la excepción
}
//se cargan los bytes en el array video
byte[] video = output.toByteArray();
}
El problema con la grabación de video (y audio también) en J2ME es que hay que parar la grabación para poder obtener los datos de la misma. O sea, hasta no llamar al método commit(), no se cargan los bytes en el buffer, pero a su vez, éste método llama implícitamente al método stopRecording() por lo que la grabación se ve interrumpida.