Deja que el servidor trabaje por tí con GNU Screen

Ya somos avispados usuarios de la línea de comandos y hacemos nuestros pinitos administrando un servidor: movemos, bajamos y hasta compilamos directamente en una maquina remota, muchas veces más potente y con más ancho de banda que la nuestra.

Nuestra terminal cliente sólo ejecuta OpenSSH (o Putty en Windows)

Pero cuando se trata de ejecutar un proceso largo y de nula interactividad no tiene mucho sentido seguir conectados ¿Para qué gastar tiempo y recursos (dejar la PC cliente prendida, por ejemplo) si el trabajo sólo se hace en el servidor?

Este caso se da muchas veces, sobre todo (y aquí lo que me interesa) cuando bajamos archivos muy pesados o hacer un mirror de un repositorio completo.

Y aquí cómo resolverlo: usa GNU Screen.

Screen es un multiplexor/virtualizador de terminales, y entre sus muchas e interesantes características incluye el desacople de su proceso padre.

Esto significa que se puede ejecutar una terminal virtual con screen (en una terminal remota por ssh, por ejemplo), ejecutar cualquier proceso en ese entorno y desacoplarlo, pudiendo entonces desloguearse y cerrar la conexión remota dejando el proceso en curso.

Receta paso a paso

  • ejecuta una consola virtual con screen

    $ screen
    
  • Ejecuta tu proceso largo. Por ejemplo, bajar la beta de Ubuntu Karmic Koala en DVD

    $ wget http://mirror.mcs.anl.gov/pub/ubuntu-iso/DVDs/ubuntu/9.10/beta/ubuntu-9.10-beta-dvd-i386.iso
    
  • Desacoplar el proceso con la combinación de teclas Control+A D

  • Desconectarse, tomar unos mates y volver cuando quieras

Para retomar el proceso

  • Conectarnos de nuevo al servidor mediante SSH

  • Listar las consolas virtuales para averiguar el PID

    $ screen -list
    
  • Traer a primer plano el proceso en cuestión con

    $ screen -r PID
    

y allí estará el proceso que dejamos corriendo (o al menos los rastros que dejó en su paso).

Digitalizando recuerdos con mencoder

Para el Mundial del 2006, compré, como tantos otros que no tenían televisor pero sí computadora, una plaquita sintonizadora de TV: una Kozumi con el chip sintonizador BT878, uno de los más genéricos y bastante bien soportado en linux.

Tuvo poca utilidad en aquel 2006, primero porque argentina no duró demasiado y segundo y principal porque un vecino reclamó potestad sobre la señal del cable coaxil que alimentaba mi chip y mis ilusiones mundialistas.

Quedó cajoneada en algun rincón, hasta que rescaté del olvido la videofilmadora de la familia, una vieja y noble JVC , con un montón de casetitos Compact VHS (que es el formato con el que funciona).

Así que después de mucho patear la tarea, decidí conectar los cables y encontrar la forma de convertir en bytes los recuerdos archivados en esos casettes polvorientos.

Lo que hice

Primero, configurar la placa. El chip bt878 se usa en muchísimas sintonizadoras que tienen configuraciones diferentes. Para asignarle los correctos, se pasa un código card que se obtiene de esta lista. En mi caso, para una Kozumi ktv-01c, el código es 151. El comando completo con el que configuro el módulo es:

sudo modprobe bttv card=151 pll=1 tuner=38 radio=1 bttv_verbose=1 gbuffers=4

Luego, el supercomando mencoder:

mencoder tv:// -tv driver=v4l2:device=/dev/video0:input=1:width=480:height=360:norm=ntsc:alsa:adevice=hw.0:amode=1:audiorate=44100:forceaudio:forcechan=1:buffersize=300 -oac mp3lame -lameopts cbr:br=96:mode=3 -af volume=-6:0,channels=1 -ovc lavc -lavcopts vcodec=mpeg4:vbitrate=5000:keyint=125:mbd=2 -vf yadif,crop=464:352:8:2  -o salida.avi

Algunos detalles:

-tv:// indica que se va a capturar video, y se le pasan paramétros luego del flag -tv: driver v4l2, un tamaño de 480x360 (aunque después se recorta), preconfigurado para ntsc (29.97 fps). image1 Un aspecto importante son los flags referidos al audio: se captura el audio alsa, indicando la placa de sonido, el modo y la calidad (mono a 44100hz de ancho de banda) image2 El audio se comprime con lame a mp3 de 96kps constante. image3 con -af volume le bajo el volumen 6db, porque de otra manera me salía saturado (estoy capturando desde el microfono). El parametro forceraudio fuerza la captura aunque la entrada esté silenciada en la mezcladora. También se fuerza a grabar un solo canal con forcechan=1. image4 Con -ovc lavc se usa libavcodec (ffmpeg), comprimiendo en mpeg4 a un bitrate de 5000. image5 Se aplican 2 filtros de video al vuelo: yadif que es el mejor filtro desentralazador (necesario para captura analógica) y un crop que recorta 8 pixeles de los costados, 2 de arriba y 6 de abajo, para evitar la distorción que producen los cabezales con las cintas viejas.

El resultado es un video de unos 250kb/s de calidad más que aceptable.

Por ejemplo, el casamiento de mi hermano Juan, en 1998:

Learning python, 4th Edition

image0Learning Python de Mark Lutz, ha sido, desde su primera versión en 1999, uno de los libros de cabecera para aprender Python.

Hace unos días salió la 4ta edición, adaptada a las versiones 2.6 y 3.1 de Python y ampliada en varios capítulos.

Lamentablemente, tardará mucho en llegar a la librerías argentinas, pero podés ir leyendo la versión en PDF.

Project Euler, Problema #2

El problema nº 2 pide obtener la suma de todos los números impares pertenencientes a la sucesión de Fibonacci menores a 4 millones.

El código con el que lo resolví es este:

def fibo(max):
        a, b = 0, 1
           n = a + b
           while n < max:
                yield n
                a, b = b, n
                n = a + b

sum([i for i in fibo(4000000) if i%2 == 0])

El resultado es 4613732.

Explicación

Fibonacci es el "hola mundo matemático" y Python luce su elegancia con este problema.

El aspecto interesante de la función fibo() definida en el código de arriba es que no se trata de una función común sino de un generador. Sintácticamente la diferencia está en que no utiliza la sentencia return sino `yield <http://docs.python.org/reference/simple_stmts.html#the-yield-statement>`_ .

La definición de `yield <http://www.wordreference.com/definition/yield>`_. en su acepción de verbo, dice «end resistance, especially under pressure or force;». Ceder, no oponer resistencia.

La diferencia sustancial entre un yield y un return es que el yield devuelve el resultado parcial de cada iteración y hace una "marca de entrada" desde donde se comenzará a ejecutar la próxima vez que la función (el generador) sea invocado.

Esto permite una recursividad con "evaluación perezosa", mucho más eficiente en términos computacionales.

Resolviendo Project Euler con python

A través del blog de Juanjo Conti descubrí Project Euler, una serie de desafíos matemáticos de enunciación sencilla para resolver con computadoras.

Juanjo estuvo resolviendo los primeros problemas, y yo quise hacer mi intento. El primero plantea obtener la suma de todos los multiplos de 3 o de 5 menores a 1000.

Lo resolví con esta pythonica (lo es?) línea:

sum([i for i in range(1000) if (i % 3 == 0 or i % 5==0)])

El resultado es 233168.

Breve explicación

Se basa en el uso de list comprehensions, una de las "joyas de la corona" de las características de Python.

Es una manera de generar listas de una manera concisa, compuesta por una expresión seguida de uno a más for y una condicionalidad al final

La lista ** [i for i in range(1000) if (i % 3 == 0 or i % 5==0)]** se lee así: crear una lista con todos los elementos (expresión i) en el rango de 0 a 999 (for) cuyo resto de dividirlo por 3 o 5 sea 0 (if).

Principios para un "freelancear" exitosamente

The principle of successful freelancing, de Miles Burke, es el libro (digital) que estoy leyendo.

This book is intended as a guide to approaching the decision to be your own boss, effecting a smooth transition into a freelance career, and making it a success once you’re there. The book’s holistic approach ensures that it not only covers how to make your freelancing journey a financial success, but also how to do it without risking your health and sanity.

Ser tu propio jefe. No está mal para este mundo donde ese rol tiene connotación negativa.

Quienes quieran chusmear, acá tienen.

Un spip para muchos sitios

Administrar muchos sitios SPIP tiene sus bemoles. Yo administro, fácil, unos 30. Cuando hay que actualizar la versión (por cuestiones de funcionalidad, o bien, como la semana pasada, por cuestiones de seguridad), es un trabajo engorroso y aburrido hacer 30 veces lo mismo. Y el trabajo se vuelve exponencial si hay que actualizar los plugins para cada uno

Para evitar eso existe la Mutualización, que desde la versión 2 es realmente muy fácil.

El concepto es simple: un sólo núcleo de SPIP (/ecrire, /prive, /squelettes-dist, /plugins) se comparte para motorizar diferentes sitios, que tendrán los directorios con contenido propio (/squelettes, /config , /IMG, etc), separado del resto

Así, a la hora de actualizar SPIP sólo tenemos que actualizar una sola instalación, tarea que se vuelve trivial si además usamos svn.

Requisito

En general, la mutualización funciona sin muchos pormenores en un servidor LAMP, pero nuestro servidor de hospedaje debe permitir apuntar diferentes dominios a un mismo directorio publico.

Por ejemplo, mi sitio textosypretextos.com.ar apunta a /home/tin/public_html/spip y nqnwebs.com apunta también a /home/tin/public_html/spip.

Es una configuración simple, pero no todos los servicios de hosting lo permiten.

Puesta en marcha

|image1|
plugin mutualisation

La "mutualización fácil" funciona a través de este plugin, pero que particularmente debe ser instalado en la raiz del sitio y no en la carpeta /plugins

Al descomprimirlo crea una nueva carpeta, /mutualisation, en la raiz de nuestro SPIP mutualizado

Además, incluye un archivo mes_options.php de ejemplo, pero yo te propongo este, que debe ser instalado en /config

 true
     */
    # define ('_INSTALL_USER_DB_ROOT', 'mon_root');
    # define ('_INSTALL_PASS_DB_ROOT', '********');

    /*
     * Crear las bases de dato via un ping a una URL (metodo AlternC)
     *
     * Il suffit de renseigner l'option url_creer_base, en lui passant les bons parametres :
     * 'url_creer_base' => 'https://bureau.tld/admin/sql_doadd.php?username=USER&password=PASS&dbn='.prefixe_mutualisation($site)
     */


    /*
     * Transformar en las paginas publicas las URL de imagenes
     * /sites/mon_site/IMG/* -> /IMG/*
     * /sites/mon_site/local/* -> /local/*
     *
     * - Necesita el mod_rewrite (reescritura de url) de apache
     * - Sólo funciona con nombres de dominio mutualización
     * ('http_host' : http://mi_sitio_mutualizado.com)
     * (por lo tanto, no funciona con un subdirectorio - http://mi_sitio_mutualizado.com/misitio/)
     *
     * y añadir en la opción
     * 'url_img_courtes' => true
     *
     * Es posible generar los  .htaccess
     * automaticamente en /IMG y /local
     * gracias a ?var_mode=creer_htaccess_img
     *
     */

    /*
     * Indique aqui el nombre del sitio de administración de esta mutualización
     * (o varios, separados por oma)
     * (dpor ejemplo, 'scriibe.net' es el dominio de nivel maximo)
     * para autorizar todos los sitios no definir la constante ;
     * Si el propietario del sitio no se encuentra en los sites/ sino en la razi,
     * escriba '' y agregue 'mutualisation' en $dossier_squelettes
     */
    define ('_SITES_ADMIN_MUTUALISATION', 'nqnwebs.com');


    demarrer_site($site,
        array(
            'creer_site' => true,        // Creer ou non le site s'il n'existe pas (defaut: false)
            'creer_base' => false,        // Creer ou non la base de donnee si elle n'existe pas (false)
            'creer_user_base' => false,  // Creer ou non un utilisateur pour la nouvelle base de donnee (false)
            'mail' => '',                // Adresse mail pour recevoir un mail lors d'une creation de site mutualise ('')
            'code' => 'miclave',  // Code d'activation ('ecureuil')
            'table_prefix' => true,     // Definir automatiquement le prefixe de table (false) ... mettre true si tous les sites dans la meme base
            'cookie_prefix' => true,     // Definir automatiquement le prefixe de cookie (false)
            'repertoire' => 'sites',     // Nom du repertoire contenant les sites mutualises ('sites')
            'url_img_courtes' => true,   // Utiliser la redirection des URL d'images courtes dans la partie publique (false)
            # 'utiliser_panel' => false, // Utiliser une table externe pour recuperer des identifiants ... (code, user, pass) permettant a un utilisateur d'installer le site (false)
            'url_creer_base' => ''       // Creer la base de donnees via une URL (methode AlternC)
        )
    );


?>

Este mes_options.php (retocado por mi) permite que los sitios funcionen con o sin ’www’. También apunta a una única base de datos, donde se encargará de crear las tablas necesarias para cada sitio, diferenciadas por un prefijo.

Sólo resta crear la carpeta /sites en la raiz del sitio, donde irán nuestros diferentes sitios mutualizados.

Al acceder via web a un dominio de un sitio sobre esta mutualización, lo primero que aparecerá es una solicitud de contraseña, definida en array de configuración de mes_options.php (en el ejemplo, la contraseña es miclave)

System Message: WARNING/2 (<string>, line 134)

Explicit markup ends without a blank line; unexpected unindent.

Luego siguen dos etapas que nos crean la estructura de directorios para este sitio dentro de /sites y las tablas para este sitio en la base de datos compartida. Lo que sigue es el proceso de instalación estándar de SPIP.

¡Listo!

Hay que tener en cuenta que ahora los archivos para nuestro sitio estarán dentro de /sites/dominio/ y es allí donde deberán subirse los esqueletos y demás.

Mutualizar un sitio en producción

¿Qué pasa si el sitio que quiero mutualizar ya está funcionando sobre un spip propio? No problem.

Basta indicar (desde el panel, o solicitando al administrador del hosting) que nuestro dominio debe apuntar ahora a la carpeta donde tenemos el spip mutualizado (en mi ejemplo /home/tin/public_html/spip ), crear el directorio /sites/dominio (donde dominio es la url del sitio que queremos migrar) y mover alli las carpetas /config, /IMG, /squelettes, /local y /tmp (o crear una /tmp nueva) del SPIP en uso al nuevo directorio. [[Estas carpetas, bien podrian ser link simbólicos]. Magia!

Conclusión

Limitar la cantidad de caracteres de los comentarios

Si Twitter funciona con 140 caracteres los comentarios a nuestros artículos podrían tener 200, ¿no?

Hay una forma fácil de limitar el largo permitido en un campo de texto mediante jQuery, que vaya mostrando de manera interactiva la cantidad de caracteres restantes.

Por ejemplo, esto limita el tamaño de un comentario en SPIP.

 $(document).ready(function () {

     $("#texte").before("<div id='chars' style='float:right;font-weigth:strong;margin-right:5px;'></div>");

$(function(){
    $('#texte').keyup(function(){
        limitChars('texte', 200, 'chars');
    })
    });
 });

function limitChars(textid, limit, infodiv) {
     var text = $('#'+textid).val();
     var textlength = text.length;
     if(textlength > limit) {
         $('#' + infodiv).html('No puede ingresar m&aacute;s de '+limit+' caracteres');
         $('#'+textid).val(text.substr(0,limit));
         return false;
     } else {
         $('#' + infodiv).html('Restan '+ (limit - textlength) +' caracteres.');
         return true;
     }
}

Intrucciones para SPIP

  1. Copiar el código
  2. Pegarlo luego de la baliza #INSERT_HEAD de tu cabecera
  3. (opcional) Cambiarle el límite (el número 200),

¡Listo!

Intrucciones generales

Es igual al anterior, sólo debes asegurarte que tiene en jquery en la página. Luego cambia el selector #texte por el que corresponda al campo que querés limitar.

Ejemplo

Ultima versión de Spip por SVN

Como sabemos, el desarrollo de SPIP se realiza a través del sistema de control de versiones Subversion.

A través de Subversion, podemos obtener la ultima version de desarrollo considerada estable

svn checkout svn://trac.rezo.net/spip/branches/spip-2.0/  carpeta_destino

Una de las ventajas de obtener SPIP a través de SVN, es que luego es muy fácil de actualizar.

cd  carpeta_destino
svn update

Subversion asigna un numero de revision a cada cambio realizado al conjunto de archivos. Así, cuando los desarrolladores lo evaluan pertinente, en un determinado momento del desarrollo se empaqueta una nueva version "oficial"

Por ejemplo, la revisión 13982 es la version 2.08 de Spip.

Podemos obtener una revision específica con el parámetro -r. Por ejemplo, el siguiente comando obtendría una copia de SPIP 2.08

svn -r 13982 checkout svn://trac.rezo.net/spip/branches/spip-2.0/  carpeta_destino

Genial, pero para para asegurarnos estar en una revision que se corresponda con una "version oficial" tenemos que saber el número de ID.

En el Trac de Spip se mantiene una tabla donde se especifica esta correspondencia para cada nueva version, pero a decir verdad, es un engorro tener que ingresar sólo para averiguar un número. Mejor hagámoslo automático!

Automatizando la obtención de un SPIP oficial por SVN

#!/bin/bash
#script para una instalacion de spip a traves de svn

if [ $# -lt 1 ]
then
echo "Debe indicar al menos un parametro:"
echo "$0 destino [rev]"
echo
exit 1
fi


if [ $# -eq 2 ]
then
REV=$2
else
echo "Averiguando revision de la ultima release..."
REV=$(svn info svn://trac.rezo.net/spip/archivelist.txt | sed -n '9p' | cut -d' ' -f5)
fi


echo "Recuperando la version $REV de SPIP"
svn checkout -r `echo $REV` svn://trac.rezo.net/spip/branches/spip-2.0/ $1 1>/dev/null
echo "Configurando permisos..."
cd $1
chmod 657 IMG local tmp config
echo "Lanzando el navegador para continuar la instalacion..."
firefox http://localhost/~tin/$1/ecrire

Este script hace el trabajo aburrido por nosotros. Averigua cuál fue la última modificación de archivelist.txt que es un archivo que se modifica en cada nuevo lanzamiento de paquete. ¡Es el dato que nos hacía falta!

Una solución más genuina

Atención: Ya me hicieron caso. Ver actualización

Aunque el hacking (como este) es sano y divertido (y a veces también útil), la solución más genuina sería que los desarrolladores de SPIP mantengan un tag por cada nuevo empaquetamiento y uno que apunte siempre al último.

Por ejemplo, con el siguiente comando deberiamos obtener la version 2.05 (sin saber a qué numero de revision corresponde)

svn checkout svn://trac.rezo.net/spip/tags/2.05

y con este otro obtener la última versión

svn checkout svn://trac.rezo.net/spip/tags/lastest-version

Esto, por ahora, no está implementado, pero ya hice llegar mi propuesta a l’equipe de SPIP, y lo están discutiendo

Actualización

Gracias a Gilles el Dev Team adoptó mi propuesta y ahora existen Tags en el arbol SVN de spip. En particular,

svn co svn://trac.rezo.net/spip/tags/spip-2-stable

El Número, mi primer juego

Para suscribirse a la lista de Pyar, una de las tareas (opcional, pero muy bienvenida) es enviar tu "Hola Mundo".

El 17 de enero de 2007 yo me suscribí y mandé el siguiente mensaje.

Estimada gente:

Cumpliendo solemnemente con el paso 2 de las indicaciones de suscripción a la lista, haciendo alarde de mi nerdismo, les dejo mi "hola mundo" (mi primero programa en python!). Se trata de humilde juego via consola que implemento en cada lenguaje en el que intento incursionar. Hete aqui:

Dicha sea la verdad: vengo con muchas ganas de aprender, y por ahora muy poco que aportar (pago solidaridad con sinceridad).

Decidir aprender un nuevo lenguaje es una gran decisión y creo que no me he equivocado con mi elección. Es que son mis primeros pinitos en la programación orientada a objetos, y aunque la facu exige Java (pero no enseña Java), creo que Python es una herramienta mucho mas versatil, accesible y apropiada para el nivel de software que tengo intención/necesidad de desarrollar.

Ahora la parte aburrida. Me llamo Martin, soy de Neuquen y estudio Ingenieria en computacion en Cordoba. Soy programador PHP (uno del montón, que bah) y en particular laburo con un CMS/framework llamado SPIP, que me da de comer y beber. Tengo un weblog, aunque no sobre cuestiones técnicas. www.textosypretextos.com.ar . Y lo más importante: soy hincha de boca.

saludos desde Neuquén a 32ºC. (quien dijo que en el sur hace frio?)

Martín

Mi "Hola Mundo" fue El Número.

Mi primer juego

El Número es un juego de lógica y habilidad mental. Consiste en encontrar el número escondido (generado aleatoriamente) a través de la información

que brinda la máquina en cada intento. El número escondido tiene 4 cifras no repetidas.

- Un digito ’bien’ significa que el hay un acierto en número y posición.

image1 Un digito ’regular’ significa que el digito existe en el número incógnita, pero no está en la posición correcta.

Por ejemplo si el numero incógnita fuese el 1234 y se arriesga el 2031 el resultado será de dos dígitos regulares (el 2 y el 1) y 1 dígito bien (el 3).

Descarga e instrucciones

|image3|
El Número Martín Gaitán - Enero de 2007

Sobre Linux podés copiar y pegar este listado de comandos en la consola:

wget http://nqnwebs.com/IMG/zip/elnumero.py-3.zip
unzip elnumero.py-3.zip
chmod +x ./elnumero.py
./elnumero.py

Sobre Windows, asegurate tener instalado Python (cualquier versión elnumero.py