Cuando dos robots se conocen

Si Turing levantase la cabeza…

El vídeo que os presento aquí es el resultado de poner a hablar dos instancias de cleverbot (www.cleverbot.com) hablando una con la otra. No tiene desperdicio:

Por cierto, me quedo con el momento epic-creepy del minuto ~2:48 (a no ser que yo me lo haya inventado y en realidad digan otra cosa)

him – Hahaha
her – What’s so funny?
him – You are
her – why am I funny?
him – Because you are
her – Why are you laughing?
him – I need blood

De las mejores declaraciones de amor de la historia. Saludos!

Instalar Jira tras nginx en un subdominio (Debian 7)

Bueno, digo debian pero bien vale cualquier distribución basada en ésta.

Hace ya algún tiempo se publicó en este blog un post largo y detallado sobre como instalar Confluence. Desde entonces la instalación ha cambiado MUCHO. De hecho, ayer instalé un Jira y un Confluence ejecutando directamente el fichero descargado (marvelous!).

La receta es la siguiente. Lo primero, vamos a suponer que poseemos un dominio (megacorp.com) y hemos apuntado el subdominio (jira.megacorp.com) a una máquina con un Debian recién instalado. Lo primero que debemos hacer es instalar un gestor de bases de datos (en nuestro caso MySQL), nginx y la máquina virtual de Java, así que como root ejecutaremos lo siguiente:

apt-get install openjdk-6-jre nginx-full mysql-server

Una vez instalados los paquetes, crearemos una base de datos para nuestro Jira con su propio usuario para que no haya problemas. Para ello, entraremos en la consola de MySQL (mysql -u root -p) y ejecutaremos los siguientes comandos:

CREATE DATABASE jira CHARACTER SET UTF8 COLLATE utf8_unicode_ci;
GRANT ALL on jira.* TO 'jira_user'@'localhost' IDENTIFIED BY 'powerpass';
FLUSH PRIVILEGES;
EXIT

Y la base de datos ya está. Ahora pasaremos a instalar Jira propiamente dicho. Para ello descargaremos la última versión (en nuestro caso la versión de 64 bits para Linux) y lo ejecutaremos, instalándolo como servicio para que, cuando se reinicie la máquina, se inicie también Jira.

$ wget http://www.atlassian.com/software/jira/downloads/binary/atlassian-jira-6.2-x64.bin
$ chmod u+x atlassian-jira-6.2-x64.bin
$ ./atlassian-jira-6.2-x64.bin

En el proceso, lo suyo es elegir las opciones que más nos convengan. Una vez finalizado, como hemos usado MySQL como gestor de bases de datos, deberemos bajarnos el driver de MySQL (que no viene incluido por temas de licencias en el paquete de Jira). Para ello, wget te elijo a ti!

$ wget http://dev.mysql.com/get/Downloads/Connector-J/mysql-connector-java-5.1.29.tar.gz
$ tar -zxvf mysql-connector-java-5.1.29.tar.gz
$ cp mysql-connector-java-5.1.29/mysql-connector-java-5.1.29-bin.jar /opt/atlassian/jira/atlassian-jira/WEB-INF/lib/

En este momento tenemos corriendo Jira en el puerto 8080 (si no hemos cambiado nada en la instalación). Ahora, lo que queremos es ponerlo bajo nuestro subdominio. Aquí es donde entra nginx al rescate. Primero crearemos un nuevo fichero de configuración:

$ touch /etc/nginx/sites-available/jira
$ ln -s /etc/nginx/sites-available/jira /etc/nginx/sites-enabled/jira

Y en él escribiremos la siguiente configuración:

server {
	listen 80;
	server_name jira.megacorp.com;

	location / {
		proxy_set_header X-Forwarded-Host $host;
		proxy_set_header X-Forwarded-Server $host;
		proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
		proxy_pass http://localhost:8080/;
		proxy_redirect off;
	}
}

Sólo nos queda un último cambio, esta vez en la configuración del servidor Tomcat que viene empotrado en Jira. Para ello, abriremos el fichero server.xml, el cual se encontrará en la ruta /opt/atlassian/jira/conf/server.xml si se ha elegido el valor por defecto y cambiaremos el conector del puerto 80 para que tenga este aspecto:

<connector port="8080"
           maxThreads="150"
           minSpareThreads="25"
           connectionTimeout="20000"
           scheme="http" proxyName="jira.megacorp.com" proxyPort="80"
           enableLookups="false"
           maxHttpHeaderSize="8192"
           protocol="HTTP/1.1"
           useBodyEncodingForURI="true"
           redirectPort="8443"
           acceptCount="100"
           disableUploadTimeout="true">
</connector>

Realmente ha sido modificado únicamente con la línea scheme="http" proxyName="jira.megacorp.com" proxyPort="80". De hecho, en la propia definición del conector viene una línea vacía en el lugar donde la hemos instalado nosotros.

Para terminar, reiniciaremos Jira y nginx para que hagan efecto los cambios realizados de la siguiente forma:

$ service jira stop && service jira start
$ service nginx restart

Y arreando. Si accedemos con el navegador a la url jira.megacorp.com tendremos el menú para instalar Jira. Es un wizard fácil y bien explicado. Destacar que al seleccionar la base de datos, deberemos especificar el usuario y la contraseña que hemos usado antes (en nuestro caso jira_user< code> y powerpass) y, muy importante, la cadena useUnicode=true&characterEncoding=utf8 en la query de conexión.

Espero que os vaya bien. Cualquier duda, ya sabéis, a comentar!

Por cierto! En el post de que antes enlacé, David Bonilla me apuntó que no era necesario instalar una JDK para correr Jira o Confluence. Por eso en este caso he instalado la jre. Sin embargo, en aquel entonces la máquina donde instalaba el confluence también llevaba un Jira y un Bamboo. Este último se encargaba de la integración continua de los proyectos con los que trabajábamos, principalmente con Java, y a la hora de lanzar una tarea, o teníamos el JDK o nos fallaba. Sólo quería dejaros la nota por si acaso. Más saludos!

export PS1 con colores no respeta el salto de línea

Muy buenas a todos,

Hoy me he levantado inspirado y he querido que la línea de comandos de algunas de las máquinas con las que trabajo tengan colorines adorables del estilo [EEPGLEECYCG], lo cual no es ningún nombre de primigenio ni de nada por el estilo, es símplemente el acrónimo para la expresión Esto Es Producción, Gañán, Los Experimentos En Casa Y Con Gaseosa.

Por ello, he decidido poner en estas máquinas el siguiente esquema:

[PROD] root@goku:~#

Para lograr este prompt, he cambiado la variable de sistema PS1 por la siguiente:

$ export PS1='e[0;31m[PROD]e[m e[0;32m${debian_chroot:+($debian_chroot)}u@h:w$e[m ';

Al margen de lo que quiere decir cada cosa (si estáis interesados, os hago una descripción en otro post) resulta que esta expresión en principio correcta causaba que los saltos de línea no se respetasen, y que todo lo escrito, en el momento que llegaba a la columna 80 producía un retorno de carro sin salto de línea. Lo más gracioso es que obviaba completamente la configuración de terminal. Por muy larga que fuese la línea configurada para el terminal, en la posición 80 volvía a la posición 0 :D.

La solución (porque la razón aún no he sido capaz de encontrarla) es poner alrededor de los caracteres no imprimibles los comandos [ y ]. Aún estoy buscando el por qué de esto, pero la nueva expresión queda como sigue:

$ export PS1='[e[0;31m[PROD]e[m e[0;32m${debian_chroot:+($debian_chroot)}u@h:w$e[m] ';

Establecerlo en cada sesión es lo de menos. O bien se pone en /etc/profile para que lo tengan todos los usuarios, o bien en el .bash_profile o .bashrc del usuario al que se le quiera modificar.

Si os ayuda, me alegro. Saludos a todos!

Python, los floats y el ==

Algo en lo que siempre acabo metiendo la pata es a la hora de comparar floats. Es como la división entera, que siempre está ahí, para hacer aparecer el error cuando menos te lo esperas.

No conozco ningún lenguaje que no lo haga, pero a la hora de comparar un par de números, como alguno de ellos sea un número de coma flotante, no hay que hacer uso del == (a no ser que de verdad queramos, pero a mí nunca se me ha dado el caso).

Por una serie de problemas que no vienen al caso (muchas operaciones son aproximaciones del valor real), cuando queremos comparar dos números de este tipo siempre tenemos que realizar dos pasos:

  1. Elegir precisión (un valor pequeño para definir el intervalo de comparación, llamémoslo «e»)
  2. Comprobar que la diferencia entre los dos valores cae en el intervalo (-e, e). Si sí, son iguales y si no, pues no.

A continuación os paso los fuentes, aunque vais a necesitar un tiempo para asimilarlos porque el flujo es muy complicado de seguir.

def feq(x, y, e=0.00001):
  return abs(x - y) >= e

Feliz noche del lunes!

Restaurar Android y la verificación en dos pasos de Google

204px-Android_Update_ScreenComo buenos programadores deberíamos probar nuestro código, ya sea con pruebas unitarias, tests varios, a mano, o como queramos. Y para probar bien hay que probar los límites. Muchos programadores mediocres testean su código en los puntos intermedios: es decir, cuando una lista está parcialmente llena, cuando hay datos, cuando la configuración es correcta, cuando todo va como la seda… Lo que comúnmente se conoce como: lo que ve la suegra. Pero los buenos programadores van a los extremos. ¿Qué pasa si falta el fichero? ¿Qué sucede si el resultado que me devuelve está vacío? ¿Cómo se comporta con una base de datos sin datos? ¿Y si intento acceder si estar correctamente autenticado?

Pues ahora mismo estoy con la sensación de que alguien no ha hecho esas pruebas en Google. Estoy restaurando mi móvil Android, ya que haciendo pruebas a veces le meto mucha porquería. Tengo activada la verificación de cuenta en dos pasos que, primero te pide la contraseña y, si es correcta, envía un código al móvil para poder hacer login. Pero ¿y si lo que estoy restaurando es el mismo móvil? Meeeeeeeeeeeeeec!

¿Cómo voy a recibir el código si lo primero que hace Android es pedirme que inicie sesión en Google? Muy avispados. Tampoco aparece la notificación, ni tengo acceso al menú de programas porque ¡Estoy en la configuración inicial! Fantabuloso…

¿La solución? Hacer la configuración inicial parcialmente hasta que envíe el código. Cuando no podamos seguir, salimos y cuando nos pregunte si tenemos una cuenta de Google decirle que no, obviar la integración del dispositivo con Google y finalizar sin ninguna cuenta configurada. Entonces nos llegará la notificación con el código y ¡Tendremos que repetir todo de nuevo!

No sé, me resisto a pensar que en Google no prueben los extremos, así que pensaré que la torpe soy yo.
Que conste que a la hora de publicar esto ya tengo el móvil instalado, pero habiendo hecho esa chapuza de la que he hablado. ¿Alguien tiene una solución menos mala? Mi reino por algo menos cutre. Y quitar la verificación por código no es una opción viable para mí.

Péndulo invertido en cuadricóptero

El péndulo invertido es un problema de la teoría de control muy fácilmente solucionable con un controlador difuso de pocas reglas.

En el problema clásico, el objetivo es mantener en vertical un palo sostenido en un carrito que se mueve en una dimensión. Sin embargo, el siguiente vídeo muestra una variación del problema en tres dimensiones y es una pasada.

Disfrutadlo mucho!!

Entrada atípica #1

Casi fallo! Las horas pasan voladas durante las mañanas y aunque me he propuesto dedicar un mínimo por las tardes al blog, lo cierto es que la de hoy ha sido dura y no me he visto con tiempo (ni ganas) de ponerme con el ordenador.

Sin embargo, no tengo más narices, así que primero me acercaré al blog y en lugar de poner algo relacionado con la informática, voy a compartir con vosotros una canción que me apetece escuchar.

http://www.youtube.com/watch?v=pDMjgckNlz0

Saludos!

Coches evolucionados para circular por un escenario generado aleatoriamente

Este tipo de vídeos me hipnotizan, y hoy he acabado llegando a uno que me encanta:

Espero que lo disfrutéis tanto como yo.

Por cierto, acabo de descubrir que poniendo el link del vídeo en una línea para él sólo se incrusta. Me parto, lo he visto mil veces en otros blogs y hasta ahora no me había preocupado de ello.

Simulación de movimiento de bípedos

Hace unas semanas, mi amigo @denis (un crack en todo lo que se pone) me envió unos enlaces sobre un estudio de simulación de movimiento en bípedos.

El enlace al pdf del artículo es http://www.cs.ubc.ca/~van/papers/2013-TOG-MuscleBasedBipeds/2013-TOG-MuscleBasedBipeds.pdf, aunque es bastante arduo. Sin embargo, el siguiente vídeo es una simulación de lo explicado en el paper y me parece genial.

Os recomiendo verlo, sobre todo el final (las tomas falsas), donde el aprendizaje de la red neuronal que controla los músculos cae en mínimos locales y deja situaciones bastante cómicas.

¡Saludos a tod@s!