Archivo de la categoría: Técnico

Adobe Air I – Tipos de ventanas y cómo hacer aplicaciones con nuestro propio chrome

Aprovechando que los últimos días me he metido de lleno a desarrollar una pequeña aplicación con Adobe Air, comienzo una serie de artículos dónde iré contando algunos de los entresijos de este sistema ya que parece muy sencillo pero cuando quieres hacer cosas concretas parece que se complica un poco.

Hoy veremos la parte fundamental de una aplicación, las ventanas en sí mismas. Se conoce como “chrome” al entorno sobre el que se crea la ventana. Habitualmente es el propio sistema operativo el que lo hace, son las ventanas clásicas de la mayoría de aplicaciones. En AIR se crean como “WindowedApplication” en la propia aplicación (veremos más adelante que éste es un detalle importante) y en el xml descriptor de la aplicación se configuran estos parámetros:

<initialwindow>
    <systemChrome>standard</systemChrome>
    <transparent>false</transparent>
</initialWindow>

El resultado, bajo Windows, sería la clásica ventana con la estética del sistema operativo.

Ventana Standard en Adobe Air

Vale, pero yo quiero crear mi ventana sin el chrome del sistema operativo.

La primera opción es configurar así los parámetros:

<initialwindow>
    <systemChrome>none</systemChrome>
    <transparent>true</transparent>
</initialWindow>

Y obtenemos una ventana con un chrome AIR.

Venatana none en Adobe Air

Queda muy bonita, pero yo lo que quiero es que no tenga nada de chrome, ni barra superior ni barra inferior, quiero definir yo toda la estética y funcionalidad de mi aplicación. Bienvenidos a la madre del cordero. Esto, que debería estar bien explicado en la documentación, no hay manera de entenderlo, de hecho creo que no se llega a explicar la manera concreta de conseguirlo.

La clave del problema es que, en este caso, la aplicación en el MXML no se definde como  “WindowedApplication” sino como “Application” estándar, el de cualquier aplicación Flex, y en el descriptor definimos:

<initialwindow>
    <systemChrome>none</systemChrome>
    <transparent>true</transparent>
    <visible>true</visible>
</initialWindow>

Y conseguimos el resultado esperado, sólo nuestra ventana sin adornos.

Ventana con chromless personal en Adobe Air

Es importante remarcar que en este caso hay que ponerle el parámetro visible=true dentro del xml ya que si no lo hacemos no se verá nada hasta que se ponga a true, perdí varias horas hasta averiguar porqué no veía nada.

Esto es todo por hoy. En el siguiente capítulo veremos cómo crear aplicaciones que se quedan como un icono al lado del reloj en Windows o en el Dock de Mac OSX.

Funciones útiles en XSLT

Una de las tecnologías que más utilizo en el desarrollo de proyectos para móviles son las transformaciones XSL (XSLT) ya que me dan la versatilidad adecuada para adaptar la capa de presentación a las compatibilidades del terminal del cliente (xHTML Mobile, WML, iMode…) o de la operadora (PML de Vodafone por ejemplo).

A lo largo de estos años he ido recopilando algunas funciones (en realidad templates) XSLT que me facilitan la vida a la hora preparar determinadas funcionalidades dentro de un portal wap. Os las dejo por si a alguien le vienen bien.

Capitalize

Un clásico. Convierte una cadena de texto de manera que devuelve el primer carácter en mayúsculas y el resto de la cadena en minúsculas.

<xsl:variable name="lcletters">abcdefghijklmnopqrstuvwxyz</xsl:variable>
<xsl:variable name="ucletters">ABCDEFGHIJKLMNOPQRSTUVWXYZ</xsl:variable>

<xsl:template name="capitalize">
    <xsl:param name="arg"/>
    <xsl:value-of select="concat(translate(substring($arg,1,1), $lcletters, $ucletters), substring($arg,2))"/>
</xsl:template>

Ejemplo de uso:

<xsl:call-template name="capitalize">
     <xsl:with-param name="arg" select="/ruta/al/texto"/>
</xsl:call-template>

 

URL-Encode

Lo que su propio nombre indica. Codifica una cadena de texto para ser enviada como parámetro de una URL. Muy útil en situaciones de integración con sistemas de billing.

<xsl:variable name="ascii"> !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~</xsl:variable>
<xsl:variable name="latin1"> ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ</xsl:variable>
<xsl:variable name="safe">!'()*-.0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz~</xsl:variable>
<xsl:variable name="hex" >0123456789ABCDEF</xsl:variable>
<xsl:variable name="thestring" select="null" />

<xsl:template name="url-encode">
    <xsl:param name="str"/>
    <xsl:if test="$str">
        <xsl:variable name="first-char" select="substring($str,1,1)"/>
        <xsl:choose>
            <xsl:when test="contains($safe,$first-char)">
                      <xsl:value-of select="$first-char"/>
           </xsl:when>
            <xsl:otherwise>
                <xsl:variable name="codepoint">
                    <xsl:choose>
                           <xsl:when test="contains($ascii,$first-char)">
                                 <xsl:value-of select="string-length(substring-before($ascii,$first-char)) + 32"/>
                           </xsl:when>
                           <xsl:when test="contains($latin1,$first-char)">
                               <xsl:value-of select="string-length(substring-before($latin1,$first-char)) + 160"/>
                           </xsl:when>
                           <xsl:otherwise>
                               <xsl:message terminate="no">Warning: string contains a character that is out of range! Substituting "?".</xsl:message>
                               <xsl:text>63</xsl:text>
                           </xsl:otherwise>
                       </xsl:choose>
                </xsl:variable>
                <xsl:variable name="hex-digit1" select="substring($hex,floor($codepoint div 16) + 1,1)"/>
                <xsl:variable name="hex-digit2" select="substring($hex,$codepoint mod 16 + 1,1)"/>
                <xsl:value-of select="concat('%',$hex-digit1,$hex-digit2)"/>
            </xsl:otherwise>
        </xsl:choose>
        <xsl:if test="string-length($str) > 1">
            <xsl:call-template name="url-encode">
                <xsl:with-param name="str" select="substring($str,2)"/>
            </xsl:call-template>
        </xsl:if>
    </xsl:if>
</xsl:template>

Ejemplo de uso:

<xsl:call-template name="url-encode">
    <xsl:with-param name="str" select="/ruta/al/texto"/>
</xsl:call-template>

 

Search and Replace

Otra vez lo que su propio nombre indica. Reemplaza un texto por otro dentro de una cadena.

<xsl:template name="SEARCH-AND-REPLACE">
	<xsl:param name="string" />
	<xsl:param name="search-for" />
	<xsl:param name="replace-with" />
	<xsl:choose>
		<xsl:when test='contains($string,$search-for)'>
			<xsl:value-of select="substring-before($string,$search-for)"/>
			<xsl:value-of select="$replace-with"/>
			<xsl:call-template name="SEARCH-AND-REPLACE">
				<xsl:with-param name="string" select="substring-after($string,$search-for)" />
				<xsl:with-param name="search-for" select="$search-for" />
				<xsl:with-param name="replace-with" select="$replace-with" />
			</xsl:call-template>
		</xsl:when>
		<xsl:otherwise>
			<xsl:value-of select="$string" />
		</xsl:otherwise>
	</xsl:choose>
</xsl:template>

Ejemplo:

<xsl:call-template name="url-encode">
    <xsl:with-param name="string" select="/ruta/al/texto/original"/>
    <xsl:with-param name="search-for" select="texto a buscar"/>
    <xsl:with-param name="replace-with" select="texto por el que se reemplaza"/>
</xsl:call-template>

Si habéis utilizado XSLT en alguna ocasión os habréis dado cuenta de que se echan en falta ciertas funciones “habituales” y que, tal cual, estás muy limitado. Sin embargo XSLT tienes las funcionalidades básicas a partir de las cuales se puede generar casi cualquier otra cosa que se te ocurra, sólo tienes que tener muy claro con lo que cuentas y qué quieres hacer.

Quiero aclarar que estas funciones NO las he hecho yo, las he ido recopilando los últimos años googleando un poco, a veces algo más que un poco, lástima no recordar de donde las fui sacando.

De momento estas tres son las que he localizado. Tengo otra más que suelo utilizar en integración con sistemas de billing para convertir a Base64, pero no la encuentro por ningún lado.

Acelera tus scripts PHP con eAccelerator

Como ya sabréis la mayoría, PHP es un lenguaje de programación de script, es decir, el código fuente no se compila generando un binario o un bytecode sino que el intérprete de PHP lo lee, compila y ejecuta cada vez que se llama a ese script. No hay que ser muy espabilado para darse cuenta de que este proceso de compilación permanente tiene que tener penalizaciones en cuanto a rendimiento, supongo que se compensa con la facilidad de desarrollo al no tener que compilar cada prueba que se quiere hacer.

Hace ya unos años descubrí eAccelerator, fork del conocido Turck MMCache. La primera vez que lo probé e hice tests de rendimiento no me creía la diferencia que había entre el antes y el después, poco a poco y a base de más pruebas me fui convenciendo y hoy en día es parte fundamental de todos los servidores a los que tengo que meter mano. eAccelerator trabaja compilando los scripts PHP y cacheando esta compilación de manera que la siguiente vez que se solicita está ya compilado y no hay que volver a hacerlo. Es importante hacer notar que maneja automáticamente los cambios de versiones a través de la fecha de modificacion (mtime). Si el script es más nuevo que el que tiene cacheado, lo vuelve a compilar, con lo que, de cara al desarrollador, el sistema sigue teniendo la ventaja de no necesitar compilados ni empaquetados.

La instalación es muy sencilla, descargamos el código fuente desde la web oficial y lo compilamos.

phpize
./configure
make
make install

Ya está el módulo instalado, ahora tendremos que activarlo. En mi CentOS es muy sencillo, simplemente debo añadir un nuevo archivo a /etc/php.d y será leído automáticamente en el siguiente reinicio de Apache. El contenido del archivo será algo así:

[osus@servidor ~]# cat /etc/php.d/eacclerator.ini
zend_extension="/usr/lib/php/modules/eaccelerator.so"
eaccelerator.shm_size="16"
eaccelerator.cache_dir="/tmp/eaccelerator"
eaccelerator.enable="1"
eaccelerator.optimizer="1"
eaccelerator.check_mtime="1"
eaccelerator.debug="0"
eaccelerator.filter=""
eaccelerator.shm_max="0"
eaccelerator.shm_ttl="0"
eaccelerator.shm_prune_period="0"
eaccelerator.shm_only="0"
eaccelerator.compress="1"
eaccelerator.compress_level="9"
eaccelerator.allowed_admin_path="/ruta/a/tu/servidor/de/control"

Todos los parámetros están bien explicados en la documentación oficial. El más importante es el último ya que, como veremos más adelante, indica una ruta dentro de tu servidor web desde donde podrás ver un pequeño panel de control de eAccelerator.

Ahora reinicia Apache y comprueba si funciona de verdad:

[osus@servidor ~]# php -v
PHP 5.1.6 (cli) (built: Nov 12 2008 11:22:34)
Copyright (c) 1997-2006 The PHP Group
Zend Engine v2.1.0, Copyright (c) 1998-2006 Zend Technologies
    with eAccelerator v0.9.5.2, Copyright (c) 2004-2006 eAccelerator, by eAccelerator

Parece que sí. Aprovecharemos para configurar la interfaz web que comentaba que nos permite controlar algunas funcionalidades. Para ello copiamos desde la carpeta con el código fuente el archivo control.php a la ruta indicada anteriormente y configuramos los parámetros de autenticación que nos pedirá, usuario y clave, al principio de este archivo.

if (!function_exists('eaccelerator_info')) {
    die('eAccelerator isn't installed or isn't compiled with info support!');
}

/** config **/
$user = "osus";
$pw = "bombona";
/** /config **/

Ya está, sólo queda acceder a esta ruta web para ver algo semejante a esta imagen: información del estado de la caché, posibilidad de desactivar el cacheo, limpiar caché…

Eaccelerator admin

Analizando el rendimiento

Todo esto está muy bien y suena muy bonito, pero ¿mejora de verdad el rendimiento? ¿qué beneficios reales obtenemos? La pregunta del millón.

Utilizaremos Apache Benchmark para hacer pequeñas pruebas de carga sobre el servidor. Esta utilidad viene siempre con Apache, con lo que no tendrás que instalar ningún software adicional. La sintaxis es muy sencilla:

ab -n 100 -c 5 http://dominioentuservidor.com/script.php

Con esto estaremos diciendo a “ab” que lance 100 peticiones contra la url indicada con una concurrencia máxima de 5 solicitudes. El resultado seria algo similar a esto:

[osus@servidor ~]# ab -n 100 -c 5 http://tudominio.com/
This is ApacheBench, Version 2.0.40-dev <$Revision: 1.146 $> apache-2.0
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Copyright 2006 The Apache Software Foundation, http://www.apache.org/

Benchmarking tudominio.com (be patient).....done

Server Software:        Apache
Server Hostname:        tudominio.com
Server Port:            80

Document Path:          /
Document Length:        125397 bytes

Concurrency Level:      5
Time taken for tests:   52.549041 seconds
Complete requests:      100
Failed requests:        0
Write errors:           0
Total transferred:      12559900 bytes
HTML transferred:       12539700 bytes
Requests per second:    1.90 [#/sec] (mean)
Time per request:       2627.452 [ms] (mean)
Time per request:       525.490 [ms] (mean, across all concurrent requests)
Transfer rate:          233.40 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:      195  232  45.7    211     417
Processing:  1687 2356 401.0   2257    3609
Waiting:      342  620 240.6    546    1756
Total:       1933 2589 400.7   2487    3815

Percentage of the requests served within a certain time (ms)
  50%   2487
  66%   2611
  75%   2798
  80%   2903
  90%   3090
  95%   3475
  98%   3791
  99%   3815
 100%   3815 (longest request)

Bien, pues a partir de esta información he hecho un pequeño estudio estadístico para valorar el cambio de rendimiento.  Se hicieron dos baterías de pruebas, primero con eAccelerator desactivado y después activado. En cada grupo se lanzaron diez tests utilizando “ab” con 100 peticiones. Vale, sí, la muestra es pequeña, pero veréis que suficiente para ver el cambio. Estos fueron los resultados.

eaceleratorstats.gif

La última fila establece los porcentajes de las pruebas con eAcclerator respecto de no utilizarlo. Interpretemos los resultados:

  • Tiempo total: utilizando el acelerador las pruebas se han ejecutado en el 73% del tiempo empleado al no utilizarlo. Eso supone un 27% menos de tiempo, una cifra nada despreciable.
  • Peticiones por segundo: con eAccelerator se ejecuta un 36% más de peticiones por segundo que sin él. Sobran más comentarios.
  • Tiempo mínimo: El tiempo mínimo empleado para atender una petición desciende un 22% al utilizar eAccelerator.
  • Tiempo máximo: este valor es sumamente llamativo, con eAccelerator se necesita un 42% menos de tiempo en el peor de los casos.

¿Necesitas más argumentos? 😛 . Otro día hablaremos de memcached.

Reiniciar el router automáticamente

Tengo un problema con mi router ADSL de casa. Cada 3 o 4 días se cuelga por alguna extraña razón (¿será saturación? 😛 ) y hay que resetearlo para que vuelva a funcionar. Cansado de estos cuelgues decidí solucionarlo con un pequeño script que mi máquina Linux ejecuta cada dos días de madrugada, así no me entero. Ya no me he vuelto a dar cuenta de los cuelges.
Lo primero que hay que hacer es habilitar el acceso telnet al router desde dentro de la red local, nunca desde el exterior 😛 .

expect es una herramienta que permite automatizar aplicaciones interactivas tipo telnet o ftp, donde tienes que introducir tu usuario y tu clave y alguien tiene que estar ahí para teclearlas. Expect lo que hace es, como su propio nombre indica, esperar determinadas cadenas de texto e introducir los datos que se hayan programado. Pongamos un ejemplo práctico. Cuando haces un telnet tienes la siguiente secuencia de eventos:

[osus@servidor ~]# telnet 192.168.0.100
Trying 192.168.0.100...
Connected to 192.168.0.100.
Escape character is '^]'.

Username:

Password:

Es decir, cuando haces un telnet “esperas” la cadena “Username:” para introducir tu usuario y después introduces tu clave cuando recibes “Password:“.

Esto es exactamente lo que automatiza expect. Veamos cómo con un script práctico.

[osus@servidor scripts]# cat router.sh
#!/usr/bin/expect -f
set force_conservative 1 ;
if {$force_conservative} {
        set send_slow {1 .010}
        proc send {ignore arg} {
                sleep .2
                exp_send -s -- $arg
        }
}
spawn telnet 192.168.0.100
expect "Username :*"
send -- "USUARIOr"
expect "Password :*"
send -- "CLAVEr"
expect "ROOT :>*"
send -- "rebootr"
expect "figuration(y/n) ? :*"
send -- "yr"
expect -gl "\[*]$*"
exit

Creo que habla por sí sólo el script. Esperamos a recibir cada cadena de texto para enviarle nuestros datos. Una vez estamos logueados esperamos la cadena inicial que nos devuelve el router, en mim caso “ROOT :>“. Ahí es cuando le pedimos el reboot y lo confirmamos. Ya está, el router se reinicia sólo. Obviamente todas las cadenas que esperas recibir deben coincidir con las de tu router, las aquí indico son las del mío.

Creando enlaces punto a punto entre servidores Linux con OpenVPN

Si hace unas semanas veíamos como crear un servidor VPN, hoy veremos como crear un túnel seguro dedicado entre dos servidores que esté permanentemente levantado y que se cree automáticamente al reiniciar alguna de las máquinas. ¿La utilidad? Tener una conexión directa con la máquina de backups, con un servidor de bases de datos, con la oficina, con otro centro de datos… seguro que se te ocurren más 😛 .

Como comentábamos entonces, PPTP no es el paradigma de la seguridad, pero la ventaja que tiene es la facilidad con que un cliente se conecta contra el servidor sin apenas conociemientos.  El ejemplo de hoy no nos servirá para crear túneles bajo demanda, pero veremos lo sencillo que puede ser crear un túnel dedicado. Siempre que se habla de VPN se termina en IPSec, pero ¿quién no se vuelto loco con la instalación de un túnel de este tipo? ¿Es realmente necesario utilizar IPSec para cualquier túnel? Yo creo que no, cada cosa para lo que está. Igual que con el primer artículo creábamos un sistema de VPN sencillo para el usuario, ahora que simplemente queremos conectar máquinas entre sí recurrimos a otro software que lo hace sin quebraderos de cabeza.

Necesitaremos, obviamente, máquinas Linux (aunque también se pueden emplear Windows) y el software que utilizaremos en este artículo: OpenVPN.

Tal y como reza en la home de OpenVPN:

Starting with the fundamental premise that complexity is the enemy of security, OpenVPN offers a cost-effective, lightweight alternative to other VPN technologies that is well-targeted for the SME and enterprise markets.

Y además lo cumple, ligero y sencillo.

Configuración

Lo primero será instalar el software. En mi CentOS no tendremos más que hacer

yum install openvpn lzo

Lzo nos proporcionará la compresión a través del túnel.

Aunque no lo parezca, ya queda poco 🙂 . Ahora debemos generar la clave SSL  que asegurará las comunicaciones a través del tunel. Muy sencillo, sólo necesitaremos un comando:

openvpn --genkey --secret clave.key

Esta clave debemos copiarla a /etc/openvpn de los dos servidores que se quieren conectar. Para copiarla al segundo lo puedes hacer con scp:

scp clave.key tuservidor.com:/etc/openvpn

Finalmente sólo nos queda el archivo de configuración. En el primer servidor creo un archivo con el nombre del segundo para identificar fácilmente qué conexión es puesto que podemos haber definido varios túneles.

[osus@servidor1 openvpn]# cat servidor2.conf
port 1194
proto udp
remote servidor2.com 1194
dev tun
ifconfig 192.168.2.2 192.168.2.1
secret clave.key
comp-lzo
keepalive 10 60
ping-timer-rem
persist-tun
persist-key
log /var/log/vpn.log

Como se puede ver, la configuración es muy sencilla, no necesita apenas explicación. En servidor2.com pones la IP del servidor al que se va a conectar, defines el puerto, las IPs privadas del servidor y del cliente y voilà, ya tienes la primera máquina preparada.

Vamos ahora con el segundo servidor.

[osus@servidor2 openvpn]# cat servidor1.conf
port 1194
proto udp
remote servidor1.com
dev tun
ifconfig 192.168.2.1 192.168.2.2
secret clave.key
comp-lzo
keepalive 10 60
ping-timer-rem
persist-tun
persist-key
log /var/log/vpn.log

Casi lo mismo que en el caso del servidor, sólo cambiamos la IP del servidor remoto y el orden de las IP’s privadas.

¡Ya está!

Sólo nos queda probarlo. Lanzamos el servicio en las dos máquinas y veremos si todo ha ido bien:

[osus@servidor1 ~]# service openvpn start
Starting openvpn:                                          [  OK  ]

[osus@servidor1 ~]# ifconfig tun0
tun0      Link encap:UNSPEC  HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00
          inet addr:192.168.2.1  P-t-P:192.168.2.2  Mask:255.255.255.255
          UP POINTOPOINT RUNNING NOARP MULTICAST  MTU:1500  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:100
          RX bytes:0 (0.0 b)  TX bytes:0 (0.0 b)

Parece que sí. Para verificar que, en efecto nos hemos conectado satisfactoriamente revisaremos el log.

[osus@servidor1 ~]# tail -f /var/log/vpn.log
Mon Feb  2 20:36:11 2009 NOTE: the current --script-security setting may allow this configuration to call user-defined scripts
Mon Feb  2 20:36:11 2009 LZO compression initialized
Mon Feb  2 20:36:11 2009 TUN/TAP device tun0 opened
Mon Feb  2 20:36:11 2009 /sbin/ip link set dev tun0 up mtu 1500
Mon Feb  2 20:36:11 2009 /sbin/ip addr add dev tun0 local 192.168.2.1 peer 192.168.2.2
Mon Feb  2 20:36:11 2009 UDPv4 link local (bound): [undef]:1194
Mon Feb  2 20:36:11 2009 UDPv4 link remote: servidor2.com:1194
Mon Feb  2 20:36:16 2009 Peer Connection Initiated with servidor2.com:1194
Mon Feb  2 20:36:16 2009 Initialization Sequence Completed

Parece que sí, que ha funcionado. ¿Veremos la segunda máquina desde la primera?

[osus@servidor1 ~]# ping 192.168.2.2
PING 192.168.2.2 (192.168.2.2) 56(84) bytes of data.
64 bytes from 192.168.2.2: icmp_seq=1 ttl=64 time=276 ms
64 bytes from 192.168.2.2: icmp_seq=2 ttl=64 time=197 ms

Eso es un sí ¿no? 😛 .

Consideraciones adicionales

Obviamente habrá que abrir el puerto que hemos configurado para el túnel en el router (si lo hubiese) y verificar que el firewall no está bloqueando el tráfico desde o hacia ese puerto, suele ser el principal problema a la hora de conectarse, si tu firewall está bien configurado bloqueará automáticamente todo el tráfico que no sea el permitido (http, smtp, dns…).

Si queremos que el túnel se inicie automáticamente al reiniciar las máquinas habrá que añadirlo a los servicios de arranque. En el caso de CentOS/RHEL sería:

chkconfig --level 2345 openvpn on

Finalmente nos queda un comentario. Supongamos que la primera máquina es nuestro servidor remoto y el segundo está en nuestra oficina y que queremos poder llegar desde el primero a otros servidores de la oficina. Supongamos también que la red de la oficina es del rango 192.168.0.0/24 (el túnel, como hemos visto, está en la red 192.168.2.0). En el servidor enrutamos el tráfico a las IP’s de la oficina a través del túnel añadiendo esta línea al archivo de configuración de la VPN, OpenVPN añadirá la ruta cada vez que se levante el túnel.

route-up "route add -net 192.168.0.0/24 tun0"

Ya sólo te queda añadir en el servidor cliente las reglas iptables adecuadas para que el tráfico se diriga hacia donde tú quieres que lo haga.

Éso es todo. Como os prometí, es un sistema muy sencillo a la vez que potente y ligero.

Copias de seguridad de bases de datos

A través de Pensamientos Ágiles llego a un artículo donde explican una interesante manera de hacer backups de bases de datos Mysql utilizando subversion. La idea es excelente, pero me plantea una serie de dudas si se trata de bases de datos de gran tamaño. Creo que es genial para mantener la estructura de la base de datos de un proyecto y tener controlados los cambios que se realizan sobre ella, pero mantener también los datos… no acabo de verlo.

En uno de mis proyectos tengo una base cuyo dump ocupa alrededor de 1Gb. Yo, sinceramente, no veo coherente mantener semejante archivo en svn. La idea es excelente y para bases de datos “pequeñas” creo que sí es útil, habría que decidir, en todo caso, qué entendemos por “pequeñas“. Pero insisto, no lo veo para archivos grandes, y 1Gb, tengamos el criterio de grande/pequeño que tengamos, es un archivo grande.

Normalmente lo que hago para hacer los backups es sacar un dump de cada base de datos, de manera que pueda recuperar cualquiera de ellas, y comprimir el resultado con bzip2. ¿Por qué bzip2 y no gzip? Simplemente por el nivel de compresión. En su día hicimos pruebas con ámbos sistemas y bzip2 salía mejor parado. Éstos son los resultados que obtendríamos hoy en día con la compresión estándar de ámbos sistemas:

-rw-r--r--   1 osus   users  1023246033 Feb  2 01:50 bbdd.sql
-rw-r--r--   1 osus   users   141481434 Feb  2 01:50 bbdd.sql.bz2
-rw-r--r--   1 osus   users   190733372 Feb  2 01:50 bbdd.sql.gz

Con bzip2 el backup pesa unos 50mb menos.

El script que utilizo para hacer backups de base de datos es más o menos lo que suele hacer la mayoría de la gente:

#!/bin/sh
dia=`date +%w`
for i in ` /usr/bin/mysql -N --execute='show databases;' `
do
echo "Haciendo backup de $i"
/usr/bin/mysqldump -C --opt $i > /backup/bbdd/$dia/$i.sql
bzip2 -fz /backup/bbdd/$dia/$i.sql
done

En otras palabras, mantengo las copias completas de los últimos siete días, semanalmente se se reemplazan por las del día en que nos encontramos. En la carpeta del día correspondiente genero los dumps comprimidos de todas las bases de datos.

El último paso es copiar los dumps del día a otra máquina. La tarea que se ejecuta diariamente lanza el proceso una vez termina de crear los backups. Esto lo hacemos a dos máquinas distintas. La primera es una máquina externa y se envían por ssh desatendido, utilizando claves públicas, de manera que la máquina remota no solicita la clave del usuario. La segunda es una máquina de nuestra oficina con la que tenemos una vpn que se levanta antes del backup, se copia con ssh destendido también y se cierra al terminar. En ésta máquina de la oficina hay otra tarea que diariamente restaura el backup de ciertas bases de datos en su Mysql local matando así dos pájaros de un tiro: por un lado tenemos la base de datos de desarrollo casi idéntica a la de producción, faltarían sólamente los últimos datos del día, y por otro lado nos aseguramosn de que los backups que se realizan son correctos ya que en caso contrario fallaría la restauración.

Hasta ahora nos ha funcionado bien el sistema. En alguna ocasión hemos tenido que recuperar alguna tabla de ciertas bases de datos y no hemos tenido excesivos problemas, todo ha funcionado a la perfección.

Vuelvo a repetir que esto no es una crítica al sistema del subversion, todo lo contrario, la idea me parece cojonuda, pero creo que habría que puntualizar o estudiar bien la viavilidad en ciertos escenarios.

Primeros accesorios para mi LG X110

Ya me han llegado los primeros accesorios para mi LG X110 que, como comentaba hace un par de semanas, me regalaron estas navidades. Los he comprado en Dealextreme, la misma tienda online de Hong Kong donde había comprado las tarjetas para desbloquear teléfonos móviles ya que, además de unos precios muy competitivos, los gastos de envío son ¡GRATIS!, sí, envío internacional completamente GRATIS. Me he comprado una funda de neopreno que se ajusta como un guante al cacharrillo y una batería de 6 celdas 🙂 . La funda es muy necesaria. Hasta ahora lo estaba transportando en un bolso de bandolera, muy cómodo, pero me he dado cuenta de que roza el portatil con una cremallera interior y se está comenzando a rallar, con el guante de neopreno no habrá más roces.

Ésta es la funda (4,27 euros) y ésta la batería (37,08 euros al cambio), precios inmejorables. Como habéis comprobado, la batería es la del MSI Wind U100 y la funda la del Asus Eee PC1000. En el primer caso el modelo es el mismo, en el segundo el tamaño es casi idéntico.

Veamos cómo ha salido el pedido y cómo se comportan las nuevas adquisiciones. Hice dos pedidos, primero la funda y unos días después la batería, no me decidía 😛 . La funda llegó perfectamente alojada en un sobre de burbujas, a fin de cuentas es una funda, no se va a romper 😛 . La batería por su parte llegó también en un sobre acolchado pero dentro de una caja y rodeada de espuma, mejor imposible. Aquí tenéis la prueba viviente de que el empaquetado es inmejorable… para ser gratis el envío 😛 .

Batería 6 celdas LG X110

Y aquí mis dos nuevos accesorios.

Batería de 6 celdas y funda de neopreno para LG X110

Analicemos ahora la batería, lo más importante para un ultraportátil. Ya sabemos todos que la de 3 celdas que traen de serie no llega para nada, sin embargo casi nadie se espera el tamaño que tiene la nueva batería y el efecto que tendrá al colocarla en tu LG X110. En esta imagen podéis ver que la nueva es considerablemente mayor, añade toda la “pata” redondeada que se ve en la foto al tamaño de la original. En peso también se nota la diferencia, pero vamos, buscamos una batería más grande a costa de que pese un poco mas ¿no? 😛 .

Batería 6 celdas LG X110

Ahora vemos cómo queda el portatil con la batería original y con la nueva, ¿veis lo que comentaba de la “pata” redonda?. Fijáos hasta donde suben las patitas originales del netbook. Esta elevación que parece una tontería hace perder estabilidad al portátil si lo colocamos sobre una mesa. Si abro la pantalla lo que suelo abrirla, el X110 cae hacia atrás, con esta inclinación pesa mas la pantalla que el cuerpo.

 Diferencia de altura del LG X110 con batería de 6 celdas

Hablemos ahora de la batería en sí misma. Obviamente no es igual que la original, ni siquiera es del mismo material. En la foto se puede apreciar levemente como ni el color ni la textura son iguales. La original es blanco nuclear brillante, muy parecida al hardware de Apple, la nueva es un blanco “sucio”, tirando a grisáceo, y totalmente áspera y mate. Vale, ess una batería, va debajo del netbook y no se ve, no tiene importancia, pero quería aclararlo para los más pijos 😛 .

 Diferencia de color en batería de 6 celdas LG X110

¿Qué nos falta por decir de la batería? Ah! lo más importante. La original duraba 1h45′. Las dos primeras pruebas de la nueva llegaron a las 4 horas y media con el bluetooth apagado y el wifi conectado y descargando cosillas. Si se mantiene en esa duración me daría con un canto en los dientes. Ojalá tarde en reducirse 🙂 . De momento me quedo con esa idea y la esperanza.

Quería comentar también que he visto por ahí (sobre todo en Ebay), baterías de 7 y 9 celdas. Investigando un poco encontré gente que decía que duraban lo mismo que la de 6 y que lo más probable es que fuesen las mismas remarcadas, así que fui directamente a por la de 6 celdas.

Sólo me queda enseñaros cómo queda el netbook con la batería de 6 celdas en su nueva funda. Perfecto, como un guante con un poco de holgura para poder meterlo y sacarlo fácilmente y añadir algún accesorio como un modem 3G.

 Funda de neopreno para LG X110

Por cierto y hablando de modems 3G. Escribí a LG preguntando si habría opción en algún momento de añadir el que se acopla al X110, porque sí, trae la ranura para meter la SIM pero al otro lado no hay nada 😛 . Esta fue la respuesta:

Estimado cliente,

En respuesta a su consulta lamentamos inidcarle que por el momento no es posible instalar el modem 3G en su equipo X110. Para saber cuando sera posible instalarlo le sugerimos visite con frecuencia nuestra web http://es.lge.com ya que cuando sea posible instalar el 3G aparece indicado en dicha web. En caso de duda, por favor, contacte con nuestro teléfono 902500234, que presta atención de lunes a viernes de 9 a 20 horas.

Atentamente,
Servicio de atención al cliente LG Electronics
Tel 902500234 de 9 a 20 horas de lunes a viernes
http://es.lge.com

¿Simple respuesta para quitarte de encima o futura posibilidad real? Ahí queda eso.

El pasado de las redes sociales

Hace unas semanas quedé a tomar unas cañas con un viejo conocido de la Red, el señor Juanma Evaristo. Nos conocimos allá por el año 2000 en Madrid, en una cena organizada por Metropoli2000, hoy MetropoliGlobal, el origen de muchos de los webmasters de este país (Yonkis o ElOtroLado por ejemplo), por aquél entonces no era fácil ni barato acceder a un hosting. Nos sentamos juntos y dió la casualidad que era de Valencia. En aquella época era aficcionado al atletismo y llevaba la web CorreryTirar.com, hoy desaparecida. A pesar de vivir en la misma ciudad no nos habíamos vuelto a ver desde entonces, sí que habíamos mantenido el contacto durante estos años, bien por email bien por “redes sociales”, pero todos los intentos de quedar se quedaban en pura palabrería. Al final lo conseguimos y su primer comentario nada más vernos fue

Tío, con la movida de las redes sociales hoy en día, creía que ya serías millonario. Vosotros fuisteis los primeros.

Ojalá, le dije 😛 . Las cosas me van muy bien, pero no tanto 🙂 .

La verdad es que tenía razón. Hoy que se habla tanto de Facebook y de Tuenti  (los líderes), me hace gracia pensar que nosotros tuvimos un dia la potencia que hoy tienen ellos. Cuando aún nadie había acuñado el término “redes sociales”, antes de que existiese ningún otro portal ni “social” ni de “contactos”, existió GenteIRC.com (hoy GenteLive.com). Así éramos en diciembre de 2000.

Fué en abril del año 2000 cuando mi socio Marcos y yo decidimos crear un portal donde la gente pudiese publicar su perfil, sus gustos, sus preferencias y, sobre todo, su foto. Ya en aquellos tiempos vimos que para las personas era muy importante publicar sus fotos y hacerse ver a los demás. Eran tiempos sin “messengers” ni webcams (¿quién no recuerda los horrores de intentar utilizar el NetMeeting?). De hecho comenzaba a aparecer la banda ancha y las tarifas planas.

En dos años generábamos 30 millones de páginas mensuales (auditadas por OJD) y teníamos un contrato de exclusividad con lo que entonces era Eresmas (después Wanadoo y ahora Orange). Como se puede ver en el siguiente gráfico, en abril de 2002 rondábamos el millón de páginas diario.

daily_usage_200204.png

Crecimos todo lo que pudimos por nuestra cuenta. En Eresmas no daban crédito a la fuerza que tenía GenteIRC, cómo devoraba páginas y se recibían cientos y cientos de registros nuevos cada día. Eran tiempos donde sólo interesaban las páginas vistas, el valor de una web eran las páginas que podía generar. Pero el apoyo que esperábamos que ellos nos diesen y nos ayudase a impulsar nuestro proyecto nunca llegó y nos quedamos sólos. Hubo acuerdos, promesas, estudios, proyectos de lanzamiento a nivel internacional del producto y mil y una situaciones más, pero la burbuja estalló y todo quedó en el aire, y un producto que necesitaba pasta para crecer quedó aparcado, y la única manera de continuarlo era con medios propios.  Obviamente eso no nos frenó, seguimos hacia adelante con ilusión y confianza en nuestra idea, pero llegó un momento en que aparecieron los grandes competidores a nivel mundial completando nuestro producto, con capital para invertir y desarrollar su negocio. Ahí no podíamos pelear, no era nuestra batalla. Nos quedamos en nuestro nicho, que nos funciona bien todavía, pero vemos con resignación cómo una idea que tuvimos nosotros antes que nadie, una idea que llegó en el momento adecuado, se ha quedado en el camino por no sé si falta de contactos, de interés o de compromiso por parte de quien tiene la pasta. Siempre pensamos aquello de “¿no se me podía haber ocurrido esto a mi?”, y cuando te ocurre no puedes aprovecharlo como se debería.

Según el informe 10 años de Internet España y el mundo de la consultora Tatum, ésta ha sido la evolución de la penetración de Internet en la población española hasta 2006. En 2008 se sitúa alrededor del 50%.

 penetracion_internet.gif

Según las estadísticas, la población española a principios de 2002 se situaba en torno a los 41 millones de habitantes. En 2008 éramos 46. Combinando esta información tendríamos unos 8 millones de internautas en 2001. En 2008 llegábamos a 23 millones, un 287%.

Otro dato más. Según Tatum, en 2003 el tiempo medio de conexión mensual era de 24horas. Hoy en día, según el EIAA (European Interactive Advertising Association),  Internet ha desplazado a la televisión como medio de entretenimiento más utilizado con 48 horas de conexión mensuales (12 semanales según el estudio).

Añadamos un último dato. En 2002 éramos unos privilegiados los que disponíamos de banda ancha (128k), la mayoría utilizaba un modem de 54k, hoy nos parecen lentos 3Mb 😐 . Antes, ver fotos era “lento“, hoy es como comer pipas.

En un país con el índice de bares por metro cuadro que tenemos y vistos los datos de penetración de Internet ¿alguien dudaba del éxito que tendrían las “redes sociales” tarde o temprano?. Ah, sí, los bares, aunque te tomes una caña, son un fenómeno de comunicación social al que no renunciaremos nunca, por mucho que se diga que Internet nos encierra, los bares siguen abriéndonos. Quedamos en un bar, charlamos, pasamos el rato, conocemos gente y nos relajamos después de un duro día de trabajo.

De todos modos ahí estamos todavía. El año que viene cumplimos ¡10 años! generando beneficios, ¿cuántos pueden decirlo mismo? 😀 .

Cajas con esquinas redondeadas con CSS y sin tablas

Uno de los problemas más importantes a los que se ha tenido que enfrentar un maquetador web en los últimos años ha sido el de crear cajas con bordes redondeados sólo con CSS, sin utilizar tablas. Puede parecer algo muy simple, pero sabemos que no lo es. Con tablas era extremadamente sencillo, pero con CSS se complica bastante hacer algo así:

redondo.jpg

La verdad es que hay muchísima literatura al respecto, pero la cosa sigue siendo bastante complicada. Aquí tienen un tutorial muy descriptivo, la idea queda clara, pero la práctica…

Al final dí con un sitio que es perfecto para estos momentos, de hecho lo he utilizado bastante los últimos años: roundedcornr.com.

roundedcornr.com

Desde roundedcornr.com puedes generar directamente el código html, css y las imágenes necesarias para tus cajas. Tienen hasta tres tipos completamente configurables, normales, con borde y con degradado, increíblemente completo todo, sólo tienes que indicar grosores en píxeles y colores y te lo genera todo. ¿El resto? copiar y pegar.

Buscar en tu web desde el buscador integrado de los navegadores

Hoy veremos cómo añadir una nueva opción a los motores de búsqueda integrados de los navegadores, los que aparecen habitualmente arriba a la derecha. La utilidad puede ser dudosa y discutible teniendo en cuenta que la mayoría de usuarios “normales” ni utiliza la caja de buscar de su navegador ni sabe cambiar de motor de búsqueda, pero la opción está ahí. Obviamente el objetivo no es añadirlo nosotros únicamente sino proveer el mecanismo para que nuestros visitantes puedan automáticamente buscar en nuestro site y añadir la opción permanentemente. Si despliegas los motores disponibles al visitar este artículo verás que te sale una nueva opción. Si añades el motor tendrás este resultado.

buscar_firefox.gif

Ahora que sabemos qué es lo que queremos hacer, veamos cómo hacerlo. Los dos navegadores mayoritarios, Internet Explorer y Firefox, basan su caja de búsqueda en el proyecto OpenSearch con lo que el mismo método nos sirve para los dos.

Lo primeroque tendremos que hacer será crear un archivo XML con los datos de nuestro site y guardarlo en nuestro servidor. Yo lo he guardado en el directorio raíz, /opensearch.xml.

<?xml version="1.0" encoding="UTF-8"?>
<OpenSearchDescription xmlns="http://a9.com/-/spec/opensearch/1.1/">
    <ShortName>Buscar en Cerebro en la Sombra</ShortName>
    <Description>Búsqueda de artículos en el blog Cerebro en la Sombra</Description>
    <Tags>php flex linux viajes</Tags>
    <Image height="16" width="16" type="image/gif">http://blog.osusnet.com/favicon.ico</Image>
    <Url type="text/html" method="GET" template="http://blog.osusnet.com/?s={searchTerms}" />
    <InputEncoding>UTF-8</InputEncoding>
    <AdultContent>false</AdultContent>
    <Language>es-es</Language>
</OpenSearchDescription>

Todos los parámetros son claramente explicativos y no creo que sean necesarias más aclaraciones excepto con <Url>. En este parámetro debemos añadir la URL que nuestra web utiliza para buscar. Por ejemplo. WordPress utiliza algo como

http://tudominio.com/?s=loquebuscas

En Google sería algo así

http://www.google.es/search?q=casa

Cómo se puede ver, el formato es similar, una URL con un parámetro y las palabras clave sobre las que se busca. Éso es exactamente lo que debemos poner en el parámetro <Url> sustituyendo las palabras clave del ejemplo por {searchTerms}, que será reemplazado en el momento de buscar por las palabras que el usuario haya introducido en la caja de búsqueda.

Si todo ha ido bien ya tienes la parte más complicada terminada. Ahora habrá que indicarle a nuestra web que ése es nuestro motor de búsqueda OpenSearch. Esto lo haremos añadiendo un nuevo tag html en la cabecera de nuestra web.

<head>
...
<link rel="search" href="http://blog.osusnet.com/opensearch.xml" type="application/opensearchdescription+xml" title="Buscar en Cerebro en la Sombra"/>
...
</head>

Siendo href la URL al archivo XML que creamos antes. Ya está todo hecho. Si ahora visitas tu web con Firefox y despliegas la lista de buscadores verás algo como esto.

buscar_add_firefox.gif

De manera que automáticamente puedes añadir tu motor de búsqueda a la lista de motores disponibles.

Si visitas tu web con Explorer verás esto otro.

buscar_explorer.gif

Explorer da, además,  la opción de usar el buscador directamente sin añadirlo a la lista.

Como véis es un proceso muy sencillo el de automatizar la agregación de proveedores a los buscadores integrados de los navegadores. Como decía al principio, lo dudoso es su utilidad real ya que ¿cuantos usuarios lo saben utilizar? 😉 .