Charla "Ser Freelance: Cómo trabajar en ojotas desde el living de tu casa"

El miércoles 15 de abril de 2009 participé como disertante en las 3º Jornadas Abiertas de Ingeniería en Computación que reune a estudiantes, profesores y profesionales invitados para dar charlas técnicas o de interés para la comunidad de la carrera.

En la anterior edición, diserté sobre Control de Versiones con Subversion. En esta oportunidad pretendí un tema menos técnico pero de interés para un vasto sector de mis compañeros: cómo animarse a dar los primeros pasos profesionalmente sin ser empleado.

La charla se basó en una presentación de Sebastián Desimone, publicada bajo Creative Commons by-nc-ar que escuché en las 7mas Jornadas Regionales de Software Libre, realizadas en Córdoba, en 2007.

Como corresponde ética y legalmente, este trabajo está bajo la misma licencia.

Bajar diapositivas "Ser Freelance: Cómo trabajar en ojotas desde el living de tu casa "

El documento ODP incluye notas y comentarios.

Video

Piccola Radiolina

Radiolina es a mi jornada laboral lo que la Spika a la de mi abuelo, en aquellas mañanas de viñas mendocinas.

Es un simple script bash que se vale del mágico mplayer para reproducir las radios más importantes de argentina (y otras mejores que esas).

Para bajar y empezar a disfrutar Radiolina puedes ejecutar los siguientes comandos desde tu consola.

wget http://radiolina.googlecode.com/svn/trunk/radiolina
chmod +x radiolina
./radiolina

Como frecuentemente lo actualizo, te recomiendo que utilices SVN para bajar el programa. En vez de la primer linea (wget...) utilizar

svn checkout https://radiolina.googlecode.com/svn/trunk/ ./

Backup selectivo de tablas Mysql

Un comando muy práctico para hacer backups de una base de datos MySQL es mysqldump.

mysqldump -h SERVIDOR -u USUARIO -pPASSWORD base_de_datos > backup.sql

Eso hace un backup completo de la base base_de_datos (incluyendo la creación de todas las tablas.

Para restaurar ese backup se hace directamente inyectando el sql al interprete de mysql.

mysql -h SERVIDOR -u USUARIO -pPASSWORD base_de_datos

Respaldar sólo algunas tablas de la base

A menudo tenemos multiples sistemas instalados sobre la misma base de datos, Si sólo queremos respaldar algunas tablas bastaría enumerar las tablas luego del nombre de la base de datos

mysqldump -h SERVIDOR -u USUARIO -pPASSWORD base_de_datos  tabla1 tabla2 > backup.sql

Pero si estas tablas son muchas, es engorroso definirlas una por una. Por suerte, en general, un prefijo asocia todas las tablas de un sistema.

En ese caso, se puede usar el siguiente compando que respalda todas las tablas con un prefijo, En este ejemplo, las que comienzan con "spip_":

mysql -h SERVIDOR -u USUARIO -pPASSWORD base_de_datos  -e 'show tables like "spip_%"' | grep -v Tables_in | xargs mysqldump -h SERVIDOR -u USUARIO -pPASSWORD base_de_datos > backup.sql

Lorem Ipsum para Spip

Lorem ipsum es el texto que se usa habitualmente en diseño gráfico en demostraciones de tipografías o de borradores de diseño para probar el diseño visual antes de insertar el texto final.

Cuando estamos desarrollando necesitamos ver cómo quedará el contenido, y debemos recurrir a un copy & paste de caulquier cosa que tengamos a mano.

La ventaja de un Lorem Ipsum sobre otros textos, es que este tiene una distribución del largo de las palabras bastante natural de las palabras lo que en textos largos queda mucho mejor que repetir un mismo fragmento una y otra vez.

Hay muchos generadores de texto Lorem Ipsum en internet, pero lo podemos hacer aún más fácil.

Un Lorem Ipsum automático

Con la ayuda del plugin jQuery Lorem Ipsum de Sander Korve hice un modelo (instalable como plugin) que permite insertar un texto del tamaño que queramos (por omisión, de 4 párrafos).

Podés bajarlo desde acá:

|image1|
Lorem Ipsum Plugin version 0.2

O por SVN:

svn checkout svn://zone.spip.org/spip-zone/_plugins_/_test_/loremipsum

Instalación

La instalación es igual que con la de cualquier plugin: descomprimirlo en la carpeta /plugins y activarlo.

Requiere además que los esqueletos tengan la baliza #INSERT_HEAD dentro del header, ya que allí se incluirá el javascript necesario para su funcionamiento.

Funcionamiento básico

La inclusión de un Lorem Ipsum se basa en el modelo lorem.html incluído con el plugin, por lo que hay dos maneras de llamarlo:

- En el cuerpo (texto, descripción, etc) de un artículo: <lorem>

image3 Predefinido en un esqueleto: #MODELE{lorem}

¡y listo!

Parámetros

El modelo acepta algunos parámetros para configurar la longitud del texto. Por ejemplo <lorem5> creará 5 párrafos.

Pero también se puede especificar más datos:

image4type: permite especificar que tipo de resultado se quiere. Las opciones válidas son paragraphs, words o characters para párrafos, palabras o characteres. Así: creará un texto de 25 palabras. El valor por omisión es paragraphs.

image5amount: Es lo mismo que el ID pasado al modelo: es lo mismo que . Por ejemplo [(#MODELE{lorem}{amount=5})] [1].

image6ptags: Permite agregar las etiquetas <code<>P<>/code> alrededor de cada párrafo. Los valores aceptados son true o false. Por omisión es true.

Una astucia

Una forma de mostrar contenido en un artículo (o cualquier elemento) sin tener que editar cada artículo sólo para poner <lorem> es invocar el modelo siempre y cuando no exista contenido en la baliza

Por ejemplo [2]:

Auto Podcast

Efecto Tábano es el programa radial de mi amigo Fernando Barraza. Objetivamente, uno de los mejores programas radiales de Argentina.

Lamentablemente, desde que me vine a Córdoba tuve que conformarme con los fragmentos de entrevistas o especiales que Fernando subía a la web. Pero ahora que la Radio Calf-UNC está online, la alegría está completa.

El único problema que queda es que no todos los días tengo el tiempo de escucharlo de 16 a 18hs, Necesitaba grabarlo para escucharlo offline.

Bien podría haber hecho esto localmente pero como al sitio lo administro yo, dije... ¿por qué no grabar el programa directamente desde el servidor, y que cualquiera pueda bajarlo cuando quiera?

Aquí está mi podcaster automático para Efecto Tábano.

La idea

Todo se basa en el glorioso Mplayer, Mplayer es capaz de reproducir casi cualquier formato en streaming.

Por supuesto, no habrá sonido en esa "reproducción" sobre el servidor, pero lo que queremos es la info para grabarla.

En vez de enviarla a la placa de sonidos, la información cruda (el sonido WAV) lo enviamos a un archivo fifo desde donde lame obtendrá su fuente de datos para comprimir a MP3 on the fly.

Todo esto, claro, se ejecutará al horario del programa (y durante el tiempo que se indique, en este caso casi 2 horas) mediante una tarea cron

Instalando lo necesario

Como anticipé, hace falta mplayer y lame. Estos programas en general no se encuentran en el servidor (por ejemplo Dreamhost) así que hay que instalarlos. Como tampoco somos root (la gran mayoría de las veces) habrá que compilarlos desde las fuentes e instalarlos a nivel usuario.

primero crear, si no existiése, un directorio /bin donde irán nuestros programas.

mkdir bin
chmod 775 bin

Mplayer y mencoder

wget http://www3.mplayerhq.hu/MPlayer/releases/codecs/essential-20061022.tar.bz2
bunzip2 essential-20061022.tar.bz2
tar -xf essential-20061022.tar
mv essential-20061022 $HOME/lib
wget http://www3.mplayerhq.hu/MPlayer/releases/MPlayer-1.0rc1.tar.bz2
bunzip2 MPlayer-1.0rc1.tar.bz2
tar -xf MPlayer-1.0rc1.tar
cd MPlayer-1.0rc1
./configure --prefix=$HOME --codecsdir=$HOME/lib/essential-20061022
make
make install

LAME

wget http://nchc.dl.sourceforge.net/sourceforge/lame/lame-3.97.tar.gz
tar -zxvf lame-3.97.tar.gz
cd lame-3.97
./configure "--prefix=$HOME" "--enable-shared"
make
make install

Con eso ya tendríamos los programas necesarios en ./bin

El script podcaster-efectotabano.sh

#!/bin/sh
#
# recorder — wrapper to pull remote audio stream and convert contents
# to mp3

# Path and arguments to lame (mp3 encoder)
lame="$HOME/bin/lame -S -b 32 -m m"

# Path and arguments to mplayer (stream decoder)
mplayer="$HOME/bin/mplayer -quiet"

# Where to put the output files
odir="$HOME/efectotabano.com.ar/podcast"

showname="efectotabano-`date +%Y-%m-%d`"
duration="6660"
url="http://78.159.108.83:8690/"

fifo="${showname}_fifo"
ofile="$odir/${showname}.mp3"

#- end config ----------------------------------------------------

mkfifo $fifo
$lame $fifo $ofile &
$mplayer  -vc null -vo null -ao pcm:file=$fifo $url &

sleep 5
pids=`ps auxww | grep $fifo | awk '{print $duration}'`

sleep `echo ${duration} | bc`

kill $pids
rm $fifo

La primera parte permite configurar las rutas y parámetros de los programas a usar, así como el formato y destino del mp3 de salida.

En este caso los parámetros de lame indican que se grabará a 32kbps en mono.

Los mp3 de salida irán a este destino

Este script se ejecuta de lunes a viernes a las 12:09 hora del servidor (16:09 en argentina) y durante 6660 segundo, de modo que termina tentativamente junto con la finalización del programa.

Para configurar la tarea en cron ejecutar crontab -e. La tarea a agregar luce así:

09 12 * * 1-5 ~/bin/podcaster-efectotabano.sh

Eso es todo. Todos los días, de lunes a viernes tendré mi programa para descargar.

TO DO

Por supuesto, para que esto sea un podcast le falta la sindicación. Por lo tanto, habría que agregar la tarea de injectar información pertinente en una base de datos del cual generar el XML de sindicación.

Variar o no variar, esa es la cuestión

Hace algunos días, en spip-es se planteó la duda de cómo controlar una cabecera diferente para algunas secciones en particular.

Xabi aportó la solución canónica, que es crear esqueletos ad-hoc para cada sección difente, valiendose de los esqueletos con forma rubrique-X.html (donde X es el ID de la sección).

Esto se describe en el apartado "Para ir más lejos" de la documentación.

En este caso particular, sólo se quería mostrar el logo en la cabecera para algunas secciones. El problema es que las secciones "diferentes" serían iguales entre sí, pero invocando distintos esqueletos. Esto contradice el principio DRY siempre deseable en todo desarrollo de software.

Una forma sencilla, pero a la vez parcial de resolver esto, es hacer un enlace duro entre los esqueletos que son iguales.

Por ejemplo, la sección 2, la 4 y la 6, tendrán el mismo esqueleto. Entonces creamos el rubrique-2.html y definimos rubrique-4.html y rubrique-6.html como enlaces duros al primero. Desde la línea de comandos:

$ ln rubrique-2.html rubrique-4.html
$ ln rubrique-2.html rubrique-6.html

Esta solución funciona, pero es sólo para servidores *nix y teniendo acceso a la consola (por SSH, por ejemplo). Además, hay que documentar bien qué se está haciendo, porque da lugar a errores cuando dos esqueletos "linkeados" intentan ser iguales.

Por suerte, hay varias otras maneras de resolver esto,

Filtros de condición o filtro match

Esta solución, es la que aportó Juan Pablo Portugau.

Lo que plantea, es usar la baliza #ID_RUBRIQUE (que obviamente, devuelve el número de la sección) con filtros de comparación. Es, hablando en geek, un simple if: Si es la sección 2, mostrar el logo. Sino, nada:

En código SPIP:

[(#ID_RUBRIQUE|=={2}|?{'#LOGO_RUBRIQUE',''})]

La limitación de esta solución se da cuando son múltiples los valores posibles. En nuestro caso, se debe mostrar el logo cuando se trata de la sección 2, de la 4 o de la 6. Juan Pablo propone anidar esta estructura.

[(#ID_RUBRIQUE|=={2}|?{'#LOGO_RUBRIQUE',[(#ID_RUBRIQUE|=={4}|?{'#LOGO_RUBRIQUE',[(#ID_RUBRIQUE|=={6}|?{'#LOGO_RUBRIQUE',''})]})]})]

Aunque es sintácticamente correcto, el código resultante es bastante inmantenible para un ser humano con cerebro normal y el monito parseador de SPIP queda agitado.

Para eso existe el filtro match, que se vale de las expresiones regulares para que hagamos nuestro festín.

Lo de arriba, puede reducirse a esto:

[(#ID_RUBRIQUE|match{^(2|4|6)$}|?{'#LOGO_RUBRIQUE',''})]

El filtro devuelve VERDADERO si el valor de #ID_RUBRIQUE empieza con 2, 4 o 6 y termina con nada. Que es, dicho de otra manera, lo que queremos.

Y aún más claro: bucles como filtros

Las expresiones regulares no son moco de pavo, diría mi abuela. Super potentes, pero poco escalables en la curva complejidad-comprensibilidad.

Hay una solución que es muy útil, sencilla pero no trivial: usar un bucle como filtro.

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

Literal block expected; none found.

La explicación es de la lógica de conjuntos: los criterios de un bucle funcionan como condiciones AND. Deben cumplirse todas. En este caso, el primer criterio {id_rubrique IN (1,2,4)} exige que el id_rubrique sea 1, 2 o 4. En el segundo {id_rubrique}, se exige que sea el que viene en contexto. Por lo tanto, este bucle sólo funcionará (mostrará el logo) si el id_rubrique del contexto es 1, 2 o 4. En lógica, es una operación O exclusiva

Funciona, es más legible que cualquiera de las otras soluciones y además permite una clausula ELSE mucho más accesible, simplemente usando la estructura completa del bucle.

Una mejor manera de controlar los atributos en spip

Muchas balizas SPIP generan código HTML como salida (las balizas #LOGO_* y los filtros |image_* son los más notorios) y frecuentemente necesitamos o queremos modificar este código autogenerado en nuestros esqueletos. Hay diversos filtros para ayudarnos a esto (inserer_attribut para insertar atributos y extraire_attribut para extraer el valor de uno generado) pero son particularmente largos y tediosos de tipear.

Más allá de eso, aunque uso estos filtros bastantes seguido para implementar cosas como galerías de imágenes, todavía pienso lo difícil que es escribir las palabras en francés sin equivocarme. Por suerte, un pequeño wrapper, puede suavizar este inconveniente.

Cuando se trata de acceder y modificar atributos de valores de atributos nada, en mi opinión, llega tan lejos como la API de atributos de jQuery. El método de jQuery *attr* por sí solo, permite leer y escribir el valor de cualquier atributo en cualquier nodo. Recibe uno o dos parámetros, el nombre del atributo, y opcionalmente, el valor.

Si sólo se especifica el nombre, entonces attr extrae y devuelve el valor de ese atributo. Si ambos parámetros son pasados al método, entonces attr modifica el objeto configurando el atributo en cuestión con el valor dado. Es jerga de Programación Orientada a Objetos, es un estilo de interfaz "polimórfica" — cuando un solo método tiene dos comportamientos complementarios que son distinguidos por el número y/o el tipo de los argumentos dados — que está por todos lados en jQuery y es una de las razones por las que este framework es tan conciso y productivo.

Considerandola como la mejor estructura para este tipo de interfaces que conozco (y también, que uso diariamente), decidí ue mi wrapper tendría que copiarlo. Así fue como el attr nació.

Como el método de jQuery, el filtro attr de SPIP toma uno o dos parámetros (y un objeto "implícito", pero lo ignoraremos por el momento). Si sólo pasamos uno, este lo remite como entrada a extraire_attribut para obtener el valor correspondiente. Si se lo llama con dos parámetros, entonces llama a inserer_attribut para modificar el objeto.

Como la idea, el código es razonablemente sencillo; la únca

Like the idea, the code is reasonably straightforward; quizas lo único un poco inusual el uso de func_get_args para obtener el conjunto de los argumentos pasados a la función llamada. Con ese array podermos usar count para saber cuantos argumentos se pasaron y decidir qué se debe hacer. Esto es más seguro que especificar y evaluar valores por defecto (FALSE o NULL, por ejemplo) porque algunos usuarios genuinamente podrían querer usar esos valores (supongamos que NULL signifique eliminar el atributo en una futura versión).

include_spip("inc/filtres");

/**
 * The `attr` function allows the user to get and set the attributes of an HTML tag.
 * It is intended to be used as a SPIP filter and depends on existing SPIP functionality.
 *
 * @param $tag
 *     The HTML code.
 * @param $name
 *     The name of the attribute.
 * @param $val...
 *     The new value for the attribute $nom. Optional.
 * @return
 *     If $val was given, the code for tag with $name=$val
 *     Otherwise, the value for the $name attribute in $tag.
 */
function attr($tag, $name){
        $args = func_get_args();

        if (count($args) > 2) {
                // SET
                return  inserer_attribut($tag, $name, $args[2]);
        } else {
                // GET
                return extraire_attribut($tag, $name);
        }
}

Simplemente copia el código en mes_fonctions.php (Mira "Agregar funciones propias" en la documentación sobre filtros de spip) y luego usa el filtro attr en tus esqueletos:

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

Literal block expected; none found.

Hay algunos cambios que se puede hacer a esta función: pasar $args directamente a inserer_attribut y extraire_attribut en vez de las variables individuales, agregar un parámetro $value=FALSE que sólo sirva para la claridad de la documentación , y el mencionado, eliminar atributos cuando se pase por ejemplo NULL como parámetro.

Personalizar el texto de #INTRODUCTION

Desde la versión 1.4, SPIP tiene una baliza calculada #INTRODUCTION que como su nombre indica, sirve para presentar una introducción al artículo completo.

En la documentación explica

#INTRODUCTION: [SPIP 1.4] si el artículo contiene una descripción, esta se utiliza aquí; si no, SPIP muestra los 600 primeros caracteres del inicio del artículo (del epígrafe, y luego del texto).

En la versión 1.92 se incorporó otro atajo para indicar el largo del texto mostrado (sobrecargando los 600 caracteres por omisión).

Así, ``#INTRODUCTION{150} `` mostrará la descripción, si existe, o los primeros 150 caracteres del epigrafe y/o el texto.

System Message: WARNING/2 (<string>, line 15); backlink

Inline literal start-string without end-string.

Pero con la versión 2 llegó por fin un control más profundo para los redactores. Es posible definir cual es el texto que se mostrará con #INTRODUCTION encerrandolo entre la etiquetas <intro>...</intro> en el cuerpo del artículo. [1]

Así podemos redactar nuestro artículo con la siguiente estructura:

Esta oración es la introducción al articulo. Y acá sigue mi artículo completo.

Suponiendo que la baliza #INTRODUCTION se muestra en el esqueleto de seccion, allí se vería el texto

Esta oración es la introducción al articulo.

Y donde esté la baliza #TEXTE:

Esta oración es la introducción al articulo. Y acá sigue mi artículo completo.

Una introducción a python

Python es un lenguaje de programación interpretado, interactivo y multiplataforma, que con su facilidad y potencia hace las delicias de miles de programadores (y sin saberlo, también de los usuarios de los programas que estos desarrollan) alrededor del mundo.

La comunidad de Python Argentina es particularmente activa, solidaria y muy capaz técnicamente.

Esta charla fue dada por Facundo Batista, uno de los fundadores de PyAr, en las 7mas Jornada Regionales de Software Libre realizadas en Córdoba, Argentina, en 2007.

Aquí la presentación

© automático

Más por costumbre que utilidad solemos poner la antigüedad de un sitio web al pie de página, asociado al símbolo ©, o (cc) si usamos Creative Commons.

En el 2007 hicimos el sitio, y en este 2009 todavía muestra.

© 2007

¡Muy feo! Aunque no hayamos actualizado el sitio desde entonces, nuestro deber, como buenos mentirosos, es lograr que el visitante no se entere.

Así que podemos hacer que el año, o el período Año inicio - Año actual se actualice automáticamente.

Muy simple:

© <BOUCLE_yearbegin(ARTICLES){par date}{0,1}>
    #SET{year, #DATE|annee} #GET{year}
  </BOUCLE_yearbegin>
[(#GET{year}|=={#DATE|annee}|?{'' , - #DATE|annee} )]

Explicación

  • Por convención, asumimos que el año de inicio del sitio es el año del primer artículo publicado, lo cual a mi me suena bastante lógico.
  • Un bucle recupera esta información, la muestra y a la vez la guarda en una variable spip #SET{year, #DATE|annee}.
  • Fuera del bucle comparamos el año ya mostrado con el actual, obtenida de la baliza #DATE sin contexto. Si son iguales, no se muestra nada más (para que no quede algo como © 2009 - 2009, que quedaría bien feo). Pero si son distintos, se muestra el año actual

El resultado, será:

© 2007 - 2009

Y si la lógica o el reloj del servidor no fallan, en cada año nuevo se incrementará el año final del período sin que toquemos una línea de código.