lunes, 30 de diciembre de 2013

Banderas en el applet del teclado de Cinnamon

En mi trabajo uso un teclado con distribución de teclas para inglés, y esta es la configuración que uso la mayoría del tiempo, pero también tengo otra para español. El nombre que Cinnamon le da a la disposición de teclas para los teclados mexicanos es "Spanish (Latin American)".

Cuando tienes varias configuraciones de teclado, aparece un indicador en la barra de estado para que sepas cuál es la configuración activa:






El problema es que el indicador falla para mi otra configuración:




Esto sucede porque el applet trata de desplegar el ícono correspondiente al nombre del país, pero les faltó tomar en cuenta casos como latinoamérica.

Para arreglarlo, solo hay que crear una copia de tu ícono favorito en /usr/share/cinnamon/applets/keyboard@cinnamon.org/flags y renombrarlo a "latam.png".


domingo, 31 de marzo de 2013

GoPro Time-lapse

En mi cumpleaños pasado recibí una GoPro Hero 3. Es una excelente cámara de acción que además de grabar videos, puede tomar fotos a intervalos fijos que podemos después convertir en un video tipo "time-lapse". Convertir las fotos en un video es fácil. Primero hay que convertirlas al tamaño correcto y recortarlas para que quepan dentro de un cuadro de video. En este caso quiero crear un video de 1920x1080, por lo que ajustamos las imágenes respectivamente:

for i in *.JPG; do convert "$i" -gravity center -resize 1920x -crop "1920x1080+0+0" +repage "resized/$i"; done

El comando anterior hace los ajustes necesarios a todas las imágenes del directorio. Primero les cambia el tamaño a 1920px horizontales de forma proporcional, y después las recorta de forma centrada. Ahora que tenemos todas las imágenes en el tamaño correcto, es solo cuestión de unirlas para generar el video:

mencoder "mf://*.JPG" -mf fps=30 -o timelapse.avi -ovc x264


Actualización
El comando original para convertir el tamaño de las imágenes funciona, pero es muy tardado cuando estamos lidiando con cientos de fotos. Para mejorar la velocidad, podemos usar xargs para ejecutar la misma instrucción en paralelo:

find -name '*.JPG'| xargs --max-procs=10 -n1 -l -I file convert "file" -gravity center -resize 1920x -crop "1920x1080+0+0" +repage "resized/file"

Estoy limitando el número de procesos a 10, pero puedes incrementar ese número a lo que mejor te funcione. Si tienes instalado GNU Parallel, todavía mejor:

find . -name "*.JPG" | parallel -j+0 --bar convert {} -gravity center -resize 1920x -crop "1920x1080+0+0" +repage resized/{/}

lunes, 21 de enero de 2013

Como configurar el MX Revolution en Mint 14

Acabo de comprar un ejemplar más del fantástico Logitech MX Revolution. En mi opinión, es el mejor mouse que ha existido. No entiendo por qué fue descontinuado.

Anteriormente, usaba una aplicación llamada "btnx" que me permitía asignar funciones diferentes a cada uno de los 10 botones. Lamentablemente, esta aplicación ya no funciona correctamente con los kernels mas recientes. Sin embargo, logré configurarlo utilizando xbindkeys y hasta ahora me ha funcionado bien.

Éstos son los pasos a seguir:

  • Instalar xbindkeys:
    sudo apt-get install xbindkeys xautomation
  • Guardar la siguiente configuración en ~/.xbindkeysrc :
    # Increase Volume (Thumb Up)
    "/usr/bin/xte 'key XF86AudioRaiseVolume' &"
      b:13
    
    # Decrease Volume (Thumb Down)
    "/usr/bin/xte 'key XF86AudioLowerVolume' &"
      b:15
      
    # Mute (Thumb Press)
    "/usr/bin/xte 'key XF86AudioMute' &"
      b:17
    
    # Next song (Scroll right)
    "/usr/bin/xte 'key XF86AudioNext' &"
      b:7
    
    # Pause/Play (Scroll left)
    "/usr/bin/xte 'key XF86AudioPlay' &"
      b:6
      
    # Emulate middle mouse button when search button is pressed
    # Search button is keycode 225 = 0xE1
    # Remember to unassign existing keyboard shortcuts in the settings app
    "/usr/bin/xte 'mouseclick 2' &"
    c:0xe1
    
  • Agregar xbindkeys a las aplicaciones de inicio

Con eso queda listo. Si se hacen cambios en la configuración, es necesario reiniciar xbindkeys usando
killall -HUP xbindkeys

sábado, 8 de septiembre de 2012

SVN y Apache

Normalmente, cuando preparo el ambiente de desarrollo para un nuevo proyecto de PHP, me meto a mi servidor y creo un repositorio de SVN, al cual luego me conecto usando svn+ssh. Sin embargo, en este proyecto necesito trabajar con personas que usan Windows, y como era de esperarse, a TortoiseSVN no le gusta mucho svn+ssh. Tuve entonces que configurar el repositorio para poder acceder por http.

Estos son los pasos para habilitar SVN por http:

  1. sudo apt-get install libapache2-svn
  2. Usar a2enmod para habilitar los siguientes modulos de apache:
    • dav_module
    • fs_module
    • dav_svn_module
    • authz_svn_module
  3. Crear el repositorio
    svnadmin create /var/svn
  4. Agregar esto a la configuración de apache (Yo lo puse en /etc/apache2/sites-available/svn):
    <Location /svn>
    DAV svn
    SVNPath /var/svn
    AuthType Basic
    AuthName "SVN Repository"
    AuthUserFile security/svnpasswd
    Require valid-user
    </Location>
    

  5. Crear un directorio para guardar el archivo de las contraseñas
    sudo mkdir /etc/apache2/security 


  6. Agregar usuarios:
    sudo htpasswd svnpasswd usuario



Algunos puntos importantes a considerar:
  • NO poner el repositorio dentro del DocumentRoot de Apache. Esto crea conflictos.
  • Para crear el working copy dentro del servidor, usar file:// para el URL, no http://. De lo contrario, saldrán errores como este:

    svn: Commit failed (details follow):
    svn: Processing MERGE request response failed: Element type "http:" must be followed by either attribute specifications, ">" or "/>". (/svn/proyecto/trunk/) 
    svn: MERGE request failed on '/svn/proyecto/trunk'
    

sábado, 4 de agosto de 2012

Cómo configurar el fetchMode de Zend_Db

Por alguna razón, en ningún lugar esta documentado como establecer el "fetch mode" del adaptador de Zend_Db usando el archivo de configuración application.ini. En todos lados explican como configurarlo en el bootstrap, o incluso sugieren manualmente configurar el objeto cada vez que lo usas. Pues despues de andar analizando la clase Zend_Db_Adapter_Abstract, descubrí que esto es lo que hay que agregar al application.ini:

resources.db.params.options.fetchMode = obj

Con esto, toda la configuración se queda dentro del archivo, sin necesidad de agregar código extra en el bootstrap ni andar manipulando el adaptador cada vez que lo necesitas.

domingo, 15 de julio de 2012

Problemas con la codificación de caracteres en MySQL

Recientemente me topé con un problema en donde no lograba hacer que los caracteres especiales se guardaran y extrayeran correctamente de una base de datos en MySQL.

Después de investigar un rato, encontré que la configuración del servidor estaba un poco errática:

mysql> show variables LIKE '%character%';
+--------------------------+----------------------------+
| Variable_name            | Value                      |
+--------------------------+----------------------------+
| character_set_client     | latin1                     | 
| character_set_connection | latin1                     | 
| character_set_database   | latin1                     | 
| character_set_filesystem | binary                     | 
| character_set_results    | latin1                     | 
| character_set_server     | utf8                       | 
| character_set_system     | utf8                       | 
| character_sets_dir       | /usr/share/mysql/charsets/ | 
+--------------------------+----------------------------+
8 rows in set (0.00 sec)


Mi intención era guardar todos los datos usando UTF8, no latin1. En este caso, mi configuración estaba causando que las conexiones al servidor se crearan esperando un tipo de codificación, pero guardando los datos en otro. Podría pelearme con la configuración de MySQL, pero este servidor ya esta muy viejo y cada vez que cambio algo se rompen otras 10 cosas. Para solucionarlo rápidamente, mejor usamos PHP para cambiar la configuración de forma dinámica. Esto lo ponemos en el bootstrap de la aplicación:

$db_charset = $db->fetchRow("SHOW VARIABLES LIKE 'character_set_database'");
$db->query("SET NAMES '" . $db_charset->Value . "'"); 
$db->query("SET SESSION character_set_server = '$db_charset->Value'"); 

Sigue existiendo el problema con los datos que ya estaban guardados, pero de ahora en adelante los datos nuevos funcionarán sin problema.

martes, 5 de junio de 2012

Alineando las particiones de un volumen RAID 5

"DISK FAILURE IS IMMINENT!"

Este es el mensaje que me apareció recientemente mientras me encontraba trabajando tranquilamente en mi computadora. El mensaje apareció no una, sino en repetidas ocasiones en ventanas emergentes que poco ayudaban a controlar el pánico. Además de llenarnos de terror, este mensaje es un buen recordatorio de porqué debemos tener un buen sistema de respaldo. En mi caso, utilizo un conjunto de 4 discos de 1TB configurados en RAID 5. Esto me permite tener un nivel aceptable de redundancia, donde mis datos quedan intactos siempre y cuando solo falle un disco a la vez.

Después de cerrar todas las ventanas y desactivar futuras amenazas de muerte de datos, me puse a investigar el supuesto daño.

$ sudo smartctl --health /dev/sdb

smartctl 5.41 2011-06-09 r3365 [x86_64-linux-3.0.0-19-generic] (local build)
Copyright (C) 2002-11 by Bruce Allen, http://smartmontools.sourceforge.net

=== START OF READ SMART DATA SECTION ===
SMART overall-health self-assessment test result: FAILED!
Drive failure expected in less than 24 hours. SAVE ALL DATA.
Failed Attributes:
ID# ATTRIBUTE_NAME          FLAG     VALUE WORST THRESH TYPE      UPDATED  WHEN_FAILED RAW_VALUE
  5 Reallocated_Sector_Ct   0x0033   023   023   036    Pre-fail  Always   FAILING_NOW 3168


Basado en mi experiencia, puedo decir que en este punto al disco le queda un lapso de vida de un día hasta 3 meses. Si, así de poco confiable es SMART, y así de impredecibles son los discos duros. Podría jugármela y esperar a que ese "Pre-fail" se convierta en muerte total, pero decidí mejor comprar un disco nuevo y quitarme este pendiente de una vez.

La conveniencia de tener un sistema RAID 5 también trae consigo algunas complicaciones, y fue con este nuevo disco que encontré una de ellas. Poco sabía que dentro del mundo de los discos duros existe un nuevo concepto llamado Advanced Formatting. En realidad el concepto solo es nuevo para mi, ya existía desde hace muchos años, pero fue hasta el 2011 cuando los fabricantes comenzaron a mudar la mayoría de sus discos a este formato. Básicamente, se trata de que antes se usaban discos duros con sectores de 512 bytes, y ahora se usan de 4096 para mayor eficiencia. Si te interesa conocer a detalle como funciona y las ventajas que Advanced Formatting otorga, este pdf de Hitachi es ampliamente recomendable.

Como era de esperarse, los discos que ya tenía, aunque los compré en el 2011, son de sectores 512 bytes. Por lo tanto, cuando intenté agregar el disco a mi arreglo usando Ubuntu Disk Utility, me tocó lidiar con mensajes como este:

WARNING: The partition is misaligned by 1024 bytes. This may result in very poor performance. Repartitioning is suggested.

¿Mal desempeño? ¡A nadie le gusta eso! Comprobé que efectivamente mi disco era uno de los nuevos:

$ cat /sys/block/sdd/queue/physical_block_size
4096

$ cat /sys/block/sdd/queue/logical_block_size
512

Al hacer la misma prueba con mis otros discos, el tamaño fue 512 en los dos casos. Esto empezó a preocuparme. Una alternativa era devolver este disco a Amazon y buscar alguna reliquia que funcionara con el tamaño antiguo, pero la realidad es que iba a tener que actualizarme eventualmente. ¿Sería posible agregar un disco con sectores de diferente tamaño a un volumen RAID existente?

La respuesta es que si, es posible, y la verdad es que esto poco tiene que ver con el problema de la partición mal alineada. El asunto aquí es que el Disk Utility esta intentando crear una partición basándose en los discos existentes, que tienen sectores de diferente tamaño. La solución es simplemente crear la partición manualmente utilizando gparted. Dado que RAID utiliza bloques mucho mas grandes (en mi caso de 64KB), lo único que importa es que el tamaño del bloque sea un múltiplo del tamaño de los sectores.

$ sudo gparted

Esta aplicación nos permite crear una nueva partición en el disco, y además alinearla por megabyte, no por cilindro como lo esta haciendo Disk Utility. Simplemente le ponemos que inicie en 1MB y termine en el máximo espacio disponible. Después nos vamos a "Manage Flags" y habilitamos la bandera de RAID. Con esto queda preparada nuestra partición para agregarla al arreglo utilizando mdadm:

$ sudo mdadm --add /dev/md0 /dev/sdd
$ sudo mdadm --detail /dev/md0
$ cat /proc/mdstat
md0 : active raid5 sdd[3](S) sdc1[0] sdb1[2] sde1[1]
      1953519872 blocks level 5, 64k chunk, algorithm 2 [3/3] [UUU]

Como podemos ver, nuestro nuevo disco ahora esta marcado como disco de reserva ([S]pare), y estamos listos para desactivar el disco moribundo:

$ sudo mdadm --manage /dev/md0 --fail /dev/sdb1
$ cat /proc/mdstat
md0 : active raid5 sdd[3] sdc1[0] sdb1[4](F) sde1[1]
      1953519872 blocks level 5, 64k chunk, algorithm 2 [3/2] [UU_]
      [>....................]  recovery =  0.0% (155976/976759936) finish=208.6min speed=77988K/sec

Parece que todo va muy bien. El disco viejo ya esta marcado como [F]ailed y mdadm ya comenzó a usar el nuevo para regenerar el arreglo. Ahora si podemos quitar el disco viejo por completo:

$ sudo mdadm --manage /dev/md0 --remove /dev/sdb1

$ cat /proc/mdstat
md0 : active raid5 sdd[3] sdc1[0] sde1[1]
      1953519872 blocks level 5, 64k chunk, algorithm 2 [3/2] [UU_]
      [>....................]  recovery =  1.7% (16652688/976759936) finish=226.0min speed=70789K/sec


Le tomará un buen rato regenerar el arreglo, pero una vez mas, RAID salvó el día.