jueves, 16 de abril de 2009

Ashton Kutcher vs CNN Breaking News

twitter_128x128De vez en cuando, el tedio habitual en que Internet se ha convertido para mi últimamente, se ve roto por algún video chorra o alguna polémica internetera. El pasado martes, me vi en una de esas situaciones.

Resulta, que el pasado lunes 13, al amigo Ashton Kutches (aplusk) no se le ocurrió otra cosa que grabar y publicar en youtube un video en el que reta a  CNN Breaking News (cnnbrk) de una manera muy particular. Si alcanza un millón de seguidores en Twitter antes que la CNN irá a casa de Ted Turnes (propietario de CNN) a todar el timbre y salir corriendo.


Al día sieguiente un video con el presentador de CNN Breaking News, Larry King,  contestaba al actor diciendole que no tenía nada que hacer, que la CNN era muy grande y que perdería, y aprovechó para invitarlo al programa para entrevistarlo.




El reto de Kutcher, se ha convertido en lo más entretenido de Internet últimamente. En el momento del reto CNN iba bastante por delante de él, y ayer le sacaba unos 8.000 seguidores por la mañana, aunque a la noche había conseguido recortar la distancia a 4000. Durante la noche del jueves al viernes (horario europeo) Kutcher ha tomado la delantera, y el resultado en el momento de escribir este artículo es:


Ashton Kutcher 995.251 - CNN Breaking News 994.249


¿Qué pasará en la lucha de David contra Goliath, Goliath contra Goliath?

miércoles, 25 de marzo de 2009

Codificación de los acentos en páginas web

file-html-128Generalmente cuando uno prepara una página web estática se limita a escribir "a saco" el texto que esta debe mostrar, incluyendo acentos y carácteres especiales. Esto no supone un problema si utilizamos un editor de páginas web que automáticamente fije la codificación del contenido, aunque lo lógico sería utilizar los tags de HTML para su correcta visualización. Por ejemplo, se deberá usar á (a aguda) para mostrar una á.

El problema se puede presentar al crear una página web dinámicamente, ya sea con ASP, jsp, php o cualquier otra tecnología en la que los textos que se deben mostrar se obtienen de una fuente de datos como una tabla de una base de datos y que han sido introducidos por terceros. En algunos casos, como sobre todo sucede con el navegador Firefox nos podemos encontrar con sorpresas, como ver unos rombitos en el lugar de alguna vocal acentuada. Ver un ejemplo (sólo firefox).

Para evitar este problema, deberemos incluir en la cabecera de la página el siguiente meta tag:

<meta content="text/html; charset=iso-8859-1" http-equiv="Content-Type"></meta>

Lo que informa al navegador de la codificación que debe utilizar para interpretar los carácteres de la página mostrada.

Otra opción es obligar al servidor a incluir dicho tag automáticamente. Esto se hace añadiendo al archivo .htaccess lo siguiente:

AddType text/html;charset=ISO-8859-1 .html

miércoles, 18 de marzo de 2009

Parámetros en línea de comandos en java

Una de las cosas más engorrosas a la hora de preparar una pequeña aplicación java en línea de comandos,al igual que en otros lenguajes de programación, es el tener que controlar todos los parámetros que se le pasan a la aplicación, el orden de los mismos, que vayan separados al estilo -s -l -r o -slr...

Existe un proyecto de Martian Software Inc. llamado JSAP, que será de gran ayuda para este tipo de cosas. Lo descubrí casi de casualidad y me parece una maravilla. Pero veamos un ejemplo: Imaginemos un programa que lee de un archivo una serie de datos, los procesa, y los escribe en un archivo de salida, exceptuando los datos que generan alguna incidencia que son grabados en un tercer archivo de errores, la aplicación además parará cuando se produzcan un número de errores igual al indicado en otro parámetro, es decir el clásico problema de metodología Warnier.

El programa debería ejecutarse con un comando del estilo de:

java com.trapallada.programa -i entrada.txt -o salida.txt -e errores.txt -n 500


donde los parámetros podrían ser aparecer en cualquier orden.

/*
* Por CNG (www.trapallada.com).
*/
public static void main(String[] args)
{
try
{
JSAP jsap = new JSAP();

// Se crean los diferentes parámetros:
// Parámetro del fichero de entrada
FlaggedOption optEntrada = new FlaggedOption("Fichero de Entrada")
.setStringParser(JSAP.STRING_PARSER)
.setRequired(true)
.setShortFlag('i')
.setLongFlag("input");

// Parámetro del fichero de salida
FlaggedOption optSalida = new FlaggedOption("Fichero de Salida")
.setStringParser(JSAP.STRING_PARSER)
.setRequired(true)
.setShortFlag('o')
.setLongFlag("output");

// Parámetro del fichero de errores
FlaggedOption optErrores = new FlaggedOption("Fichero de Errores")
.setStringParser(JSAP.STRING_PARSER)
.setRequired(true)
.setShortFlag('e')
.setLongFlag("errores");

// Parámetro del fichero de número de errores (no obligatorio)
FlaggedOption optNumeroErrores = new FlaggedOption("Número de Errores")
.setStringParser(JSAP.INTEGER_PARSER)
.setRequired(false)
.setShortFlag('n')
.setLongFlag("numErrores");

// Registramos los parámetros
jsap.registerParameter(optEntrada);
jsap.registerParameter(optSalida);
jsap.registerParameter(optErrores);
jsap.registerParameter(optNumeroErrores);

// Se procesan los argumentos de la línea de comandos
JSAPResult config = jsap.parse(args);

// Si se produce algún error generamos el mensaje de error con JSAP.
if (!config.success())
{
System.err.println();
System.err.println("Uso: java " + Lector.class.getName());
System.err.println(" " + jsap.getUsage());
System.err.println();
System.exit(1);
}

// Se recogen los datos del la configuración cargada desde los
// parámetros de la línea de comandos.
String entrada = config.getString(optEntrada.getID());
String salida = config.getString(optSalida.getID());
String errores = config.getString(optErrores.getID());
Integer numErrores = new Integer(config.getInt(optNumeroErrores.getID()));
}
catch (Exception e)
{
e.printStackTrace();
}
}

Esto sería lo que devolvería la ejecución de la clase en el caso de no poner nada a continuación de la llamada a la misma (sin parámetros).

Uso: java com.trapallada.programa
(-i|--input) <Fichero de Entrada> (-o|--output) <Fichero de Salida> (-e|--errores) <Fichero de Errores> [(-n|--numErrores) <Número de Errores>]

miércoles, 4 de marzo de 2009

Menos da una piedra

ppEso es lo que debe estar pensando "nuestro amiguito Marianico el Corto", y no, no me refiero al lamentable personaje de los programas de televisión tipo José Luis Moreno.

La verdad es que desde 2004 y el Rubalcabazo, es la primera vez que los Populares pueden presumir de haber ganado algo de verdad. Pero, si se ojean un poco los datos, sin necesidad de profundizar gran cosa podemos ver un par de datos que son como para que los dirigentes del PP se preocupen un poco, y claro, RuizGa, el superhéroe de las páginas interiores de El Pais se frote las manos y se dedique a preparar sus zapatos de la primera comunión para ponerselos al minuto de que se lleven los restos de "Marianico y sus peones".

En Galicia el PP ha sacado mayoría absoluta, pero en votos sólo ha subido 4000 (aún falta el voto de la inmigración), pero en el Pais Vasco, ha bajado la friolera de 65.000, lo que supone un neto de una pérdida de 61.000. ¿Es realmente esto como para sacar pecho? Sobre todo, teniendo en cuenta dos cosas: En Galicia, son muchos los que han apelado al voto útil para echar e los nacionalistas (esa corriente política que convierte en mierda todo lo que toca), y en el Pais Vasco, había 8 escaños más a repartir entre todos, y aún así, han perdido 2.

¿Qué pasará en las europeas cuando a la gente le importe "un huevo" su voto y decida castigar los bandazos de Marianico y demás con un voto de castigo a UPyD o la abstención? Lo veremos en junio.

lunes, 23 de febrero de 2009

Batman, el superheroe más cutre de entre los "Clásicos"

Batman me cae mal, siempre me ha caido mal, es algo irracional, es como lo de Peter Pan, no lo soporto, pero si bien Peter Pan me cae mal porque es un pijo chungo, Batman me cae mal símplemente por ser un quiero y no puedo, entre otras cosas en las que no entraré.

Realmente Batman no tiene poder alguno, es todo a base de cachibaches y artilugios con ganchos, cables y demás ferralla. No es como Superman que te puede congelar con su super-aliento o hacerte una radiografía sólo com mirarte. Si tienes un RPG y pillas a Batman un poquillo despistado, te lo cargas sin problemas, y si no lo pillas despistado, siempre puedes poner 4 o 5 RPGs y será carne de cañón.

Spiderman puede envolverte con sus telas de araña, subirse por las paredes, tiene un oido privilegiado, pero ¿Batman? Como no se ponga un Whisper XL amplificado va de culo. Robin podría llamar a Corrupción de Menores estando en la misma sala que él y Batman no se enteraría.

¿Qué te puede hacer Batman realmente? ¿Darte de hostias? ¿tirarte cosas?, ¿insultarte?, vale, él está entrenado y yo no ¿y qué? Se soluciona con los 4 o 5 RPG. Intenta cargarte a Superman con un lanzacohetes, le puede dar la risa. Y luego evidentemente preparate que vas a ir para casa con el culo calentito. Y hablando de culos: ¿Es mayor de edad Robin?

Además, no ireis a comparar a los enemigos de Batman con los de Superman por no ir más lejos. El Joker no deja de ser un pirado, una especie de Emilio Aragón traumatizado por la cancelación de los Payasos de la Tele. ¿El Pinguino? Le pones la mno en la frente y no es capaz de tocarte, y así todos. Si Lex Luthor se metiera con Batman sí que iba a "cagar masilla".

Y ahora una selección de los mejores Batman de la red:



Y el grandioso y único disfráz de Batman, el que realmente nos dice: "Tú podrías ser Batman" es:

jueves, 19 de febrero de 2009

Evitar inicialización accidental de Informix

En mi opinión, una de las cosas que los señores de IBM debería corregir, cuando publiquen el esperado Infomix Cheetah, es el tema de la opción de inicialiación de las bases de datos con la opción -i del comando oninit.

Es relativamente fácil lanzar el comando oninit –i accidentalmente y perder las bases de datos, por lo que es recomendable enmascarar el programa oninit. Para esto renombraremos el comando oninit de $INFORMIXDIR/bin/oninit a $INFORMIXDIR/bin/oninit.cmd.

Luego creamos un script oninit que filtre el uso de la opción –i

# oninit
# Por CNG (www.trapallada.com).
#
# Script que enmascara el oninit de informix para
# evitar el oninit -i que inicializa la base de datos

ARGUMENTOS=""
LANZAR=1

while getopts ivyI opcion
do
case $opcion in
i) echo -e "\n   La opcion -i esta bloqueada para evitar inicializaciones"
echo "   accidentales de la base de datos. Utilice la opcion -I"
echo -e "   i mayuscula para inicializar la base de datos.\n"
LANZAR=0;;
v) ARGUMENTOS=v${ARGUMENTOS};;
y) ARGUMENTOS=y${ARGUMENTOS};;
I) ARGUMENTOS=i${ARGUMENTOS};;
esac
done

if ( test $LANZAR -eq 1 ) then
oninit.cmd -${ARGUMENTOS}
fi

Ordenar mis fotos por carpetas

Siempre he tenido un serio problema a la hora de organizar las fotografías en mi disco duro. Al principio volcaba todo en una misma carpeta, cosa que en cuestión de pocas descargas de la cámara, convertía la carpeta en algo totalmente invisitable. El segundo paso fue el crear carpetas con nombres descriptivos y guardar en ellas las fotografías, pero aún así la cosa era un infierno.

Las aplicaciones como Picasa, ACD See, PhotoMesa permiten gestionar bastante bien las fotografías, pero a mi, como buen usuario proviniente del MS-DOS al que le gusta saber dónde están las cosas en mi disco duro, y no perder el control sobre él, no acababan de convencerme.

Tras una breve incursión en el mundo del Linux, descubrí la aplicación f-Spot, que realizaba una clasificación en carpetas de las fotografías en función de los datos Exif de los archivos JPG.

Ya de vuelta al mundo Windows, y tras decantarme por Picasa, principalmente por su facilidad de uso (no para mi, sino para mi mujer), me encontré con mi eterno problema de clasificar las fotografías. Por lo que en ese momento me decidí a crear mi propio programita Java que clasifique en carpetas las fotografías a partir de sus datos Exif.

Lo primero de todo es obtener las fotografías de origen a partir de una ruta:

/*
* Por CNG (www.trapallada.com).
*/

/**
* Devuelve una colección con todos los ficheros JPG de una carpeta.
* Para obtener esa colección recorre recursivamente todo el árbol de
* directorios bajo la carpeta indicada.
* @param f File indicando la carpeta en la que realizar la búsqueda recursiva.
* @return Una Colección con todos los ficheros baja la carpeta pasada al método.
*/
private static Collection getFiles( File f ) {
Collection c = new ArrayList();
if ( f.isDirectory() ) {
File[] listOfFiles = f.listFiles();
for (int i = 0; i < listOfFiles.length; i++) {
c.addAll( getFiles( listOfFiles[i]) );
}
} else {
JFileChooser chooser = new JFileChooser();
if ( chooser.getTypeDescription(f).equals("Archivo JPG") ) c.add(f);
}
return c;
}

A partir de la colección de ficheros JPG, y mediante la librería metadata-extractor, yo he usado la versión 2.3.1, podemos generar un nuevo nombre de fichero y mover el archivo original de la colección obtenida a su destino definitivo.

// Por CNG (www.trapallada.com).
try {
String salida = "D:/Mis documentos/Mis imágenes/preImportado";
String entrada = "D:/CarpetaOrigen";

Collection files = getFiles( new File(entrada) );

Iterator itFiles = files.iterator();
while ( itFiles.hasNext() ) {
File ficheroJpg = (File) itFiles.next();
try {
Metadata metadata = JpegMetadataReader.readMetadata( ficheroJpg );
Directory exif = metadata.getDirectory( Class.forName("com.drew.metadata.exif.ExifDirectory") );

Calendar fecha = Calendar.getInstance();
try {
fecha.setTime( exif.getDate( ExifDirectory.TAG_DATETIME_ORIGINAL ) );
File toFile = new File( salida + "/" + fecha.get( Calendar.YEAR ) + "-" +
Formateador.fill( new Integer( fecha.get( Calendar.MONTH ) + 1 ).toString(),
'0', 2, Formateador.IZQUIERDA ) + "/" +
ficheroJpg.getName() );
Ficheros.moveFile( ficheroJpg, toFile);
}
catch ( MetadataException j ) {
System.out.println("ERROR: " + ficheroJpg.getName() );
}
} catch ( JpegProcessingException e ) {
e.printStackTrace();
}
}
}
catch ( Exception e )
{
e.printStackTrace();
}
}

Nota: El método Formateador.fill tiene el siguiente javadoc:
/**
* M&amp;amp;amp;amp;eacute;todo que devuelve la cadena rellena con el caracter "caracterRelleno", hasta
* ocupar "longitud" posiciones, desde el lado indicado.
*
* @param cadena: Cadena a ser formateada
* @param caracterRelleno: Caracter con el que se va a rellenar
* @param longitud: Indica la longitud de la cadena resultante
* @param lado: nos indica en que lado situar los caracteres de Relleno
* @return Cadena rellena
*/
Nota 2: No creo que haga falta explicar lo que hace el método Ficheros.moveFile.

miércoles, 18 de febrero de 2009

Cargador de móvil universal... ¡Por fin!

En un cajón de mi casa, almaceno un montón de cables de cargadores, ¿y por qué los almaceno? Pues no lo se. La verdad es que en contadas ocasiones he podido reutilizar un cargador de móviles. Que si los extraños conectores de Ericsson, los de patilla gorda de Nokia, los planos de Siemens, los de Motorola, similares a los de Nokia pero incompatibles, los de patilla fina de Nokia... y así hasta el infinito.

Pero por suerte, para todos los que sufren el mismo problema que sufro yo, parece que al podremos ver la luz al final de túnel. Al parecer una asociación de diferentes fabricantes de teléfonos móviles, ha decidido implantar un único modelo de conector de carga para todos sus productos. El conector elegido es el Micro-USB, aunque el artículo de la GSM Association no especifica si será el Micro-USB AB o el Micro-USB B. En cualquier caso la noticia es buena, ya que GSMA engloba el 84% del mercado de las comunicaciones móviles.

Curiosamente, una de las "estrellas" de los últimos tiempos en el mundo de la telefonía móvil el iPhone de Apple, en principio queda fuera de este acuerdo, y es que al parecer no tienen intención ninguna de unirse al grupo de empresas que implantarán el conector único. Otra razón más para incrementar la tiña que le tengo a empresa de la manzanita.

En cualquier caso la noticila la teneis en el portal de GSMA.

jueves, 12 de febrero de 2009

Obtener los campos SERIAL de Informix tras un INSERT



Problema:

Tras hacer un INSERT en una tabla de Informix que contiene campos del tipo SERIAL nos encontramos con que tras realizarlo, tenemos todos los datos del registro excepto los autogenerados por la base de dato.

Solución:

// Por CNG (www.trapallada.com).
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;

String queryString = "INSERT INTO " + TABLA + " (" + CAMPOS +
") VALUES ( ?,?,?,? )";
preparedStatement = conn.prepareStatement(queryString,
Statement.RETURN_GENERATED_KEYS);

int i = 1;
// El primer campo de la tabla es SERIAL
preparedStatement.setInt(i++, 0);
preparedStatement.setString( i++, vo.getCampo2() );
preparedStatement.setString(i++, vo.getCampo3() );
preparedStatement.setString(i++, vo.getCampo4() );

int insertedRows = preparedStatement.executeUpdate();
resultSet = preparedStatement.getGeneratedKeys();

resultSet.next();
vo.setCampo1( resultSet.getInt(1) );

En el momento de crear el PreparedStatement incluimos el parámetro Statement.RETURN_GENERATED_KEYS para indicarle a la aplicación que recupere los valores de los SERIAL generados por la base de datos.

Tras ejecutar el INSERT, se recupera un ResultSet con los campos SERIAL generados con el método getGeneratedKeys() del PreparedStatement.

Tras eso, accedemos al ResultSet para obtener los valores.