jMonkeyEngine, motor 3D para desarrolladores java

Como dice su lema ‘serious monkyes. serious engine.’ nos encontramos ante una API de alto rendimiento para la generación de escenas gráficas en 3D realmente maduro. Sólo hay que echarle un vistazo a su sección de películas y demos que da cuenta de las posibilidades actuales de su motor gráfico. jMonkeyEngine es un proyecto de código abierto bajo licencia BSD que comenzo allá por el año 2003. Actualmente acaban de sacar la alpha de la versión 3 del engine.

Para poder empezar a desarrollar basta con descargase las librerías jar del proyecto. Actualmente lo mejor es hacerlo a través de las versiones nocturnas aunque puedas encontrarte con alguna versión más o menos estable el producto está bastante acabado.

Ahora sólo tienes que descomprimirlo (descarga .zip) he importar jMonkeyEngine3.jar y la carpeta lib que se encuentra en el zip dentro de tu proyecto. También tienes los javadoc y el código fuente en el archivo zip y en la página web de jMonkeyEngine puedes ver tutoriales explicativos para poder comenzar a hacer tus pinillos en el mundo 3D.

Happy coding!

Como cambiar la zona horaria de mysql por conexión

Mysql tiene asociadas dos horas horarias, una es global y otra por conexión. Su valor por defecto coincide con la zona horaria del servidor donde mysql esté en ejecución. Esto se corresponde con el valor de timezone SYSTEM. Para poder saber el valor de zonas horarias en una conexión basta con lanzar esta consulta:

mysql> SELECT @@global.time_zone,@@session.time_zone,NOW();

La primera columna es el time_zone de nuestro servidor y el segundo el de nuestra conexión. La tercera columna de la fecha y hora actuales de acuerdo con el valor de timezone de nuestra conexión (si, la 2ª columna)

Para poder modificarla según el manual online de mysql basta con ejecutar:

mysql> SET time_zone = timezone;

Siendo timezone una cadena que se debe corresponder con una zona horaria instalada en nuestro sistema. Sin embargo si ejecutas esta consulta es muy probable que te de un error, diciendo que desconoce esta zona horaria.

Por ejemplo

mysql> SET time_zone = ‘UTC’;
1298 Unknown or incorrect time zone: ‘UTC’

Como es esto posible, ¿mysql no sabe nada sobre esta zona horaria universal?. En mi sistema GNU/Linux (Debian). Las zonas horarias están a modo de archivo (filosofía UNIX) en /usr/share/zoneinfo. Y de un rápido vistazo se puede ver que, como no, UTC es una de las zonas horarias definidas.

Esto es porque a pesar de lo que dice el manual de mysql debemos introducir la zonas horarias que hay instaladas en nuestro sistema en mysql. Para hacer esto tenemos que ir a una shell y ejecutar:

mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql -u root -p mysql

¡Además sería preciso ejecutar periódicamente esta instrucción pues las zonas horarias pueden sufrir modificaciones!

Después de hacer esto ya podriamos ejecutar

mysql> SET time_zone = ‘UTC’;
Query OK, 0 rows affected (0.00 sec)

Ahora si que podemos ejecutar

mysql> SELECT @@global.time_zone,@@session.time_zone,NOW()\G

*************************** 1. row ***************************

@@global.time_zone: SYSTEM

@@session.time_zone: UTC

NOW(): 2010-05-24 15:24:31

1 row in set (0.00 sec)

Y podemos comprobar que la hora se ha modificado con la zona horaria seleccionada. Recuerda que esto es por conexión o sea que cuando vuelvas a conectarte a tu servidor mysql verás nuevamente la hora de la zona horaria del sistema

Para cambiar esto y tener de manera global esta configuración de zona horaria habría que arrancar el servidor mysql con la opción –default_timezone=timezone_name de mysqld_safe.

El servidor mysql también almacena además de las dos zonas horarias que comentamos (global y por conexión) la zona horaria del servidor donde se aloja. Lo almacena en la variable system_time_zone. También puedes modificar esto con la opción –timezone=timezone_name de mysqld_safe o con la variable de entorno TZ antes de lanzar el servidor myql. O en el archivo de configuración de mysql introducir la siguiente linea:

default-time-zone=’timezone’

Ya en tiempo de ejecución puedes modificar la zona horaria global del servidor. Pero si reinicias el servidor perdería estos cambios. Basta ejecutar con el usuario root la siguiente consulta:

mysql> SET GLOBAL time_zone = timezone;

Microformatos, noticias

Los microformatos se emplean para añadir información adicional dentro de un documento html o xhmtl. Existen multitud de microformatos y se emplean para muy diferentes tipos de información, como por ejemplo: definir eventos de calendario hCalendar, tarjetas de presentación de personas, compañias, lugares y organizaciones hCard o para indicar el tipo de licencia que aplica a determinado contenido rel=”license”.

En este pequeño artículo hablaremos del microformato para noticias, hNews. Este microformato esta en estado de borrador, lo que significa que podría no ser definitivo y sufrir cambios. Con este microformato para noticias podemos especificar la siguiente información:

Organización fuente de la noticia (source-org, Source organization), en hCard (otro microformato)
El lugar donde la noticia tiene lugar (dateline, empleando texto a microformato hCard)
Coordenadas geográficas donde situar la noticia (empleando microformato geo)
La licencia de la noticia (license, empleando Licensing que ni si quiera esta en estado de borrador)
Principios (y ética) empleados por la organización que produce esta historia (principles, empleando microformato rel-principles)

Además hNews debe ser codificado como una hentry de hAtom. Realmente ya veremos que sólo hNews, hentry y source-org son los campos obligatorios. Para aclarar esto hAtom es un microformato que se emplea para especificar posts dentro de un blog o de una manera más genérica en cualquier sitio donde se pueda emplear el formato Atom de sindicación. El formato hAtom (que también está en estado borrador como hNews) incluye los siguientes elementos:

hfeed
feed-category
hentry
entry-title \*
entry-content
entry-summary
updated \*
published
author \*
bookmark
tags

El significado de cada elemento es análogo al que tiene el formato de sindicación Atom. Recordad que en hNews sólo se debe codificar hentry, ni hfeed ni feed-category tienen sentido aquí. Además dentro de hentry sólo es obligatorio, además de él mismo, los que aparecen en la lista de arriba marcados con un asterisco (entry-title, updated y author).

La organización fuente de la noticia debe ser codificada como hcard. hcard tiene muchos campos posibles para definir una persona, una compañía o un evento. Pero el único realmente obligatorio es fn

Veamos un ejemplo de noticia en microformato:

<div class="hNews">
  <div class="hentry">
    <h1 class="entry-title">Volcán continúa arrojando ceniza y obstaculiza vuelos</h1>
    <abbr class="updated" title="2010-04-18T23:00:00+01:00">18-04-2010 23:00</abbr> por <strong class="author">Fulanito</strong>,
    <span class="source-org vcard"><a class="url org fn" 
        href="http://espanol.news.yahoo.com/">Yahoo news España</a></span>
    <div class="entry-content>
      <p>La agencia europea de seguridad aérea Eurocontrol dijo que habrá unos 5.000 vuelos el sábado, siendo la cifra normal de 22.000…</p>
    </div>
  </div>
</div>

En el aparecen reflejados todos los campos obligatorios en el microformato hNews a saber: hNwes, hentry, (enty-title, updated y author obligatorios para hentry) y source-org (vcard y fn obligatorios de hCard para especificar source-org).

Analizar XML con Java

Aunque el formato de datos XML alardea de características como: extensibilidad, legibilidad, jerarquización, estandarización y capacidad de adaptación a multitud de formatos. A la hora de analizarlo y extraer información de él es, computacionalmente, un formato que presenta algunas dificultades con respecto a otros. Si bien es verdad que existen librerías/APIs dedicadas a superar este pequeño handicap. A continuación veremos ejemplos de dos tipos de librerías para analizar un documente XML desde java. Uno de ellos es el DOM (Document Object Model) y otro es el SAX (Simple API from XML).

Las diferencias principales entre DOM y SAX es que DOM genera un arból de objetos con sus dependencias en memoria. Esto permite acceder a cualquier elemento en cualquier posición una y otra vez, atrás y adelante sin problemas. El problema es que consume mucha memoria y no sería una opción recomendable para XMLs muy grandes. SAX por otro lado no almacena información en memoria y lee el fichero secuencialmente hasta encontrar el elemento y la información que necesitas en un proceso en donde se registran métodos callback cada vez que se detecta determinados patrones en el documento (apertura de etiquetas XML por ejemplo). SAX podría manejar con mayor facilidad grandes ficheros XML pero sin la libertad del DOM.

Veamos como podemos analizar este fragmento de XML


<?xml version="1.0" encoding="UTF-8"?>
<personas>
 <persona sexo="masculino">
  <nombre>Pepe</nombre>
  <apellidos>Gracia Perez</apellidos>
 </persona>
 <persona sexo="femenino">
  <nombre>María</nombre>
  <apellidos>Suarez Martinez</apellidos>
 </persona>
</personas>

Primero hay que crear un objeto Document (org.w3c.dom.Document) empleando otros dos objetos DocumentBuilder (javax.xml.parsers.DocumentBuilder) y DocumentBuilderFactory (javax.xml.parsers.DocumentBuilderFactory). Si por ejemplo el fichero que contiene nuestro xml se llama test.xml

Podríamos poner para cargar el dom el siguiente fragmento de código

(Dejando los namespaces completos)


org.w3c.dom.Document dom;
javax.xml.parsers.DocumentBuilderFactory dbf;
javax.xml.parsers.DocumentBuilder db;

dbf = javax.xml.parsers.DocumentBuilderFactory.newInstance();

try
{
  db = dbf.newDocumentBuilder();
  dom = db.parse("test.xml");
}
catch(Exception ex) {}

Ahora dom contiene toda la información y estructura de nuestro documento en memoria. Veamos como extraer la información que necesitamos

Para obtener el nodo raiz, en este caso personas, llamamos a:


org.w3c.dom.Element rootElement = dom.getDocumentElement();

rootElement es el objeto que ahora debemos interrogar. Por ejemplo si llamamos al método getElementsByTagName(String etiqueta) obtendremos un objeto de tipo NodeList (org.w3c.dom.NodeList) que contiene a su vez todos los posibles elementos incluidos dentro de la etiqueta. Para obtener por ejemplo el contenido de las etiquetas persona podríamos hacer


org.w3c.dom.NodeList nodeList = rootElement.getElementsByTagName("persona");

Para iterar sobre nodeList podriamos hacer


if(nodeList != null && nodeList.getLength()>0
{
  for(int i=0;i<nodeList.getLength();i++)
  {
    org.w3c.dom.Element element = (Element)nodeList.item(i);
    if(element.hasAttribute("sexo")) System.out.println(element.getAttribute("sexo"));
    org.w3c.dom.NodeList nodeList2 = element.getElementsByTagName("nombre");
    if(nodeList2 != null && nodeList2.getLength()>0
    {
      org.w3c.dom.Element el = (Element)nodeList2.item(0);
      System.out.println("Nombre: " + el.getFirstChild().getNodeValue());
    }
  }
}

Importante saber los métodos de nodeList:

– getLength() devolviendo el tamaño de la lista de nodos
– item(i) devuelve el nodo (objeto Node) de índice i

Y los métodos de Element

– getElementsByTagName(String nombreTag) devolviendo un NodeList
– getFirstChild() primer elemento inferior del nodo
– getAttribute(String atributo) valor del atributo
– hasAttribute(String atributo) si el nodo tiene o no este atributo

¿Garzón a juicio?

Hola Abraham

Tras las últimas noticias al respecto, te enviamos este mensaje para informarte de la postura de Amnistía Internacional ante la acusación al Juez Baltasar Garzón por investigar los crímenes franquistas.

Amnistía Internacional considera insólito que el juez Garzón pueda ser juzgado por investigar las desapariciones de más de 100.000 personas ocurridas durante la Guerra Civil y la dictadura franquista.

La “Ley de Amnistía de 1977” ha sido invocada para perseguir al único juez que ha intentado dar respuesta a víctimas de desaparición forzada y sus familias. Si este juicio se produce, será la primera vez en todo el mundo – al menos que tengamos constancia en Amnistía Internacional – que un magistrado, en democracia, es sentado en el banquillo por intentar conseguir verdad, justicia y reparación para las víctimas de crímenes internacionales. Además, enviará un mensaje tremendamente negativo para otros jueces que lo intenten, tanto en España, como en el resto del mundo.

Las normas internacionales de derechos humanos dicen claramente que el crimen de desaparición forzada NO prescribe y entorpecer su investigación es un delito, por tanto ninguna “Ley de Amnistía” puede contradecirlas.

Te animamos a que entres en nuestra página de facebook, dejes tus comentarios en el muro y compartas en tu perfil esta noticia.

Por favor, reenvía este mensaje a todos tus contactos.

Recibe un cordial saludo,

Esteban Beltrán
Director Amnistía Internacional

Wikileaks revela más datos sobre operaciones de EEUU en Irak

Posiblemente la inmensa mayoría de las atrocidades de la guerra de Irak (y de todas las guerras) permanezcan en el anonimato. De vez en cuando algunas de ellas salen a la luz y este pequeño artículo habla de una de ellas. Simplemente para que lo que pasó aquí sea más conocido. Nuevamente a wikileaks ha llegado este importante documento (un vídeo de una operación militar grabado desde un helicóptero) que han hecho inmediatamente público. Wikileaks permite que la gente envíe anonimamente documentos comprometedores para grandes empresas, gobiernos u otros agentes especialmente poderosos y que ellos hacen públicos. El anonimato de la fuente original está garantizado por ellos.

Bueno, no me quiero enrollar más. La historia y el vídeo lo podéis ver en collateralmurder.org/. A grandes pinceladas un ataque americano en Iraq causa muertos y heridos entre hombres y niños en un pequeño barrio marginal en la ciudad de Nueva Bagdad. Antes de sacar el vídeo la versión oficial del ejercito y del gobierno americano era de operaciones de combate contra insurgentes. El vídeo ha salido a la opinión pública hoy mismo 5 de abril del 2010, como ellos mismos comentan.

Pongo abajo el vídeo de youtube pero aconsejo que leáis la versión de wikileaks de todo el incidente. AVISO ANTES DE QUE LE DEIS AL PLAY: El vídeo contiene imágenes que pueden herir la sensibilidad si eres menor de edad no lo veas.

Convertir String a int en Java y viceversa

A continuación unas pequeñas recetas de java para pasar de cadena a entero o de entero a cadena.

Para convertir un String (cadena) a int (entero) hay que emplear el método estático de la clase Integer, parseInt

Ejemplo:


String enteroString = "5";
int entero = Integer.parseInt(enteroString);

Para convertir int(entero) a String sólo debemos hacer una llamada al método estático de la clase Integer, toString

Ejemplo:


int entero = 1;
String enteroString = Integer.toString(entero);

Análogamente para pasar de cadena a double tenemos el método Double.parseDouble

Ejemplo:


double aDouble = Double.parseDouble(aString);

o al revés (double a string) llamamos al método Double.toString

Ejemplo:


double d = 8342342;
System.out.println(Double.toString(d));

Tanto la clase Integer con la clase Double se encuentran en el package java.lang. Atención int y double son tipos primitivos del lenguaje java. Integer y Double son clases que representan estos tipos primitivos y le añaden más funcionalidades. Como por ejemplo las que acabamos de ver.

Matt Cutts entrevistado por Eric Enge

Escribo en este post un pequeño resumen con los puntos más interesantes de una entrevista del 14 de Marzo del 2010 realizada por Eric Enge presidente de Stone Temple Consulting y consultor SEO a Matt Cutts, ingeniero de Google (que supongo que no necesita más presentaciones). Enumero los datos y afirmaciones que me han parecido más interesantes

No existe un límite en el número de páginas indexadas por parte de google de un sitio web. El número de páginas que rastreamos es proporcional al PageRank. Las páginas con más enlaces entrantes son descubiertas y rastreadas por google más rapidamente.

Existe el concepto por parte de googlebot del “host load” (carga del servidor). La carga del servidor es esencialmente el número máximo de conexiones simultaneas que un servidor web en particular puede manejar.

Hay dos factores principales que determinan el rastreo de un sitio por parte de googlebot. Uno es el page rank y otro es la carga del servidor. Page rank y otros factores determinan lo profundamente que googlebot rastreará dentro de un sitio web. Sin embargo es posible que también la carga del servidor influya en este rastreo. Pero también el contenido duplicado. Si google lo encuentra descarta las duplicadas y se queda sólo con una. Además googlebot podría tender a rastrear con menor frecuencia un sitio donde haya mucho contenido duplicado.

Con enlaces procedentes de páginas marcadas como contenido duplicado google intenta mezclar estas páginas como si fueran una sóla (a efectos de link juice que envían) en lugar de eliminarlas completamente. Estos enlaces no necesariamente se pierden.

Evitar identificadores de sessión en URLS. También desde un punto de vista de usabilidad los usuarios tienden a recordar enlaces que son más bonitos y sencillos.

Ahora google tiene la habilidad a través de google webmasters tools de ignorar completamente un parámetro en la URL.

Existe riesgo de que estos identificadores de sesión sean vistos como contenido duplicado. También los enlaces de afiliación con parámetros de seguimiento.

Navegación “faceted” al estilo de Zappos no es muy positivo para googlebot y para los usuarios.

Existe alguna perdida de page rank al emplear redirecciones 301

Es preferible reducir el contenido duplicado que usar rel=canonical. Las páginas que combines mediante el rel canonical no tienen porqué ser completos duplicados, pero deberían ser duplicados conceptuales del mimso producto o estar muy relacionados. Desde diciembre ya se puede hacer rel canonical entre dominios.

Es perfectamente válido tener un rel canonical que apunte a la misma página y también tenerlo implementado para todas las páginas de tu sitio.

Empleamos peticiones HEAD para recoger información sobre imágenes pero no para el resto de recursos.

Javascript: googlebot puede ejecutar algo de Javascript

No emplees page rank sculpting en tu sitio emplea tu tiempo en obtener enlaces valiosos o mejorar el contenido de tu web.

Esta es la entrevista completa (en inglés): Entrevista a Matt Cutts

Instalar linux desde un USB

Hoy en día la instalación de una distro de linux a través de un USB con las BIOS actuales es bastante sencilla. Existen herramientas que te ayudan a hacerlo de manera automática o semi-automática como portable linux,live USB creator o unetbootin. Algunos de estos programas tiene versiones para windows. Existen tutoriales aquí y allá por internet con instrucciones de como hacer esta instalación. Por ejemplo el que nos encontramos en ubuntu sobre instalación a través de usb.

Para hacerlo de una manera más casera y controlada y sobre todo por si todos los método anteriores os han fallado probad esto. Es un ejemplo de una instalación de debian a través de usb (recordad que.. debian rules!):

Primero debes tener un sistema GNU/linux completamente funcional. Un live CD de knoppix es más que suficiente. Ahora basta con descargarte una imagen boot.img.gz, para arrancar tu usb. Puedes buscar otros arranques para otras versiones debian navegando en los mirros de debian, por ejemplo http://http.us.debian.org/debian/dists/

A continuación debes introducir tu USB (tiene que tener al menos 256 Mb de capacidad). Si tu kernel actual reconoce el dispositivo debes de buscar que nombre le ha asignado (tipo /dev/sda, /dev/sdb, /dev/sdc /dev/sdd etc). Usualmente empleando dmesg

$ dmesg | tail

o simplemente revisando la salida de mount (muchos sitemas actual montan automáticamente los discos usb en cuanto los conectas)

$ mount

Ahora debes grabar el arranque en tu usb ejecutando como root la siguiente instrucción (debes sustituir /dev/sdX por el nombre de dispositivo que acabas de encontrar)

# zcat boot.img.gz > /dev/sdX

Esto creará una nueva particion/estructura de tu usb. Es mejor que retires y lo vuelvas a insertar para que tu sistema sea capaz de reconocerla bien. Después de volver a insertarla (cuidado el nombre del dispositivo puedo haber cambiado, vuelve a utilizar dmesg o mount para averiguarlo).

Si no tienes el dispositivo montado hazlo ejecutando:

# mount /dev/sdX /mnt

El USB no tiene ahora número de partición, no es necesario montar /dev/sdX1 o /dev/sdX2. Basicamente el USB ahora no tiene particiones y se comporta como un disco.

Ahora sólo tienes que grabar una imagen iso de la distribución que quieras en el USB por ejemplo una de debian 😉

instalación en red de debian

Emplea la adecuada para tu arquitectura (i386 si no sabes de que estoy hablando)

Descargate la iso y grabala en el raiz del usb. Instrucciones completas:

# umount /dev/sdX
# mount /dev/sdX /mnt
# cp /mnt
# umount /dev/sdX

Ahora ya puedes retirar el usb. Reiniciar/enceder el equipo en donde quieras instalar tu nuevo linux. Arrancar la BIOS y configurandola para que inicia la secuencia de Boot con USB. Introducir tu USB. Y ejecutar de nuevo el arranque del equipo. El proceso de instalación que debes tener ahora en tu equipo es el mismo que el del CD de instalación.

JQuery y Ajax

Cualquier librería actual que se precie debe tener un soporte completo de ajax, de la facilidad con la que maneje este importante y vital tarea vendrá buena parte de su éxito. Vamos a estudiar el soporte que tiene JQuery de ajax y como se desenvuelve en esta tarea.

Veamos como podemos lanzar una petición ajax directamente empleando sólo javascript

Para iniciar nuestro objeto ajax debemos emplear este código


var ajax;
if(window.XMLHttpRequest)
{
ajax = new XMLHttpRequest();
}
else if (window.ActiveXObject)
{
ajax = new ActiveXObject("Msxml2.XMLHTTP");
}
else
{
throw new Error("Este navegador no soporta ajax");
}

Es más complejo de lo que debería debido al soporte no estandar que le dio Microsoft es un navegador. A fin de cuentas Microsoft fue quien primero desarrollo esta tecnología.

Después de que la instancia ajax haya sido creada esta tiene una serie de métodos y propiedades que la dotan de funcionalidad. Todos los navegadores que soportan este objeto ajax tiene todos estos métodos/propiedades:

Métodos:

abort()
getAllResponseHeaders()
getResponseHeader(name)
open(method, url, async, username, password)
send(content)
setRequestHeader(name,value)

Propiedades:

onreadystatechange
readyState
reponseText
responseXML
status
statusText

Para lanzar una petición ajax debemos indicar el método a utilizar get o post, la URL a la que lanzar la petición, el cuerpo del mensaje si se trata de una petición POST (en el POST la información a enviar no viaja en la cabecera HTTP como con el método GET), si deseamos que la petición sea sincrona o no, autentificación si la URL lo precisa y una función callback para informar del progreso de la petición ajax.

el método open nos permite informar de la mayor parte de estos parámetros

ajax.open(‘GET’,’/url’);

Este método no lanza la petición, sólo la prepara

open(metodo,url,asincrono,usuario,password);

metodo – HTTP empleado, GET o POST, indica el tipo de formato empleado en la petición.
url – La url a solicitar.
asincrono – La petición debe ser asincrona, valor por defecto true, (no detiene la ejecución, básico en ajax) o sincrona (detiene ejecución hasta que se completa la tarea) valor a false.
usuario – Proporciona el usuario si es necesaria la autentificación.
password – Propociona un password si es necesaria la autentificación.

Ahora necesitamos informar cual será la función que se debe llamar cuando nuestra petición cambie de estado a través de la propiedad onreadystatechange. Debemos proporcionar una función para esta propiedad que será llamada varias veces después a medida que la petición ajax se vaya resolviendo para bien o para mal.

Podriamos definir esta función de esta manera

ajax.onreadystatechange = function ()
{
if(ajax.readyState == 4) //Estado terminado
{
if(ajax.status >= 200 && ajax.status < 300) //Sólo peticiones exitosas { // Código OK aquí } else //Peticiones que fallan { // Código de error aquí } } } Una cosa interesante, y muy desagradable, a tener en cuenta a la vista de este código es que la variable ajax es la del alcance global pero no es la variable pasada al controlador. Esto puede ser un problema si tenemos varias llamadas ajax activas simultáneamente. Tras hacer esto el último paso es lanzar la petición. Para ello llamamos al método send(content), cuyo parámetro es el contenido de la petición. Si es una petición GET no es preciso enviar nada
ajax.send(null);

En el caso de petición tipo POST debemos enviarle el contenido de la información que queremos enviar al servidor de manera debidamente formateada y URI-encoded, por ejemplo:

ajax.send(‘a=1&b=2&c=3’);

Como obtener la respuesta de la llamada