Politonos gratis

— [ edit | raw ] migrated from node/921

Hasta las narices de que me quieran sajar por un minuto de canción más o menos lo mismo que por una canción completa (con una calidad ridícula), aquí tenéis un manual para reducir el tamaño y la calidad de vuestras canciones favoritas. Eso sí: siempre y cuando tengáis un “título de propiedad” de la canción…

Paso 0: A WAV

Lo primero que hago es obtener el wav. Como lo tengo en CD uso grip (paquetito debian y tal). Si lo tenéis ya en mp3, saltaros este paso.

Paso 1: Recortando

Pues yo uso mhwaveedit. Abre tanto el mp3 como el wav. Recortas, pruebas, recortas, pruebas, pruebas, recortas, pruebas, deshaces, recortas, pruebas… Ale, ya tienes el trocito que te gusta.

Paso 2: Calidad paupérrima

¿Vas a difrutar de la música? La respuesta es: NO. Un montón de investigación para obtener mejor calidad y al final lo que queremos es basura. ¿Qué se le va a hacer? Pero… ¡No hay problema!

$ lame -m m -b 56 ficherito.wav ficherito.mp3

Con esto conseguiréis una calidad regulera, pero un tamaño enano. Para un wav de 5Mb he conseguido un mp3 de 200Kb. Podéis jugar con el parámetro de -b hasta encontrar lo que queréis (si ponéis un valor inválido, os avisa de cuáles son los buenos).

Ironic mode: ON

Ale… a difrutar de la música

Ironic mode: OFF

20070522 – Añadida opción “-m m” para transformar a Mono. Gracias, Paco; se me había pasado al transcribirlo.

"Fallito" de seguridad en Debian.

— [ edit | raw ] migrated from node/920

Hola! supongo que ya os habréis enterado del DSA-1571 (aviso de seguridad de Debian), que viene a ser esto: el generador de números aleatorios de openssl que se emplea para generar las claves privadas y públicas de SSH es predecible, lo cual es un grave problema porque ahora, conocida una cable pública, se puede obtener su clave privada. Esto hace que desde el 17 de septiembre de 2006 las claves generadas con Debian (y similares) sean inseguras. Así que ya sabéis: revocad vuestras antiguas claves y generaros unas nuevas!.

Mercurial, por favor

— [ edit | raw ] migrated from node/919

Mercurial es otro sistema de control de versiones distribuido (otro más) que no tiene nada (o poco) que envidiar a git (en lo referente a prestaciones) pero casi tan fácil de usar como subversion. Esta recetilla incluye unas nociones de su uso básico y algunas buenas referencias.

Unas reflexiones sobre "sintactic sugar" y el goto

— [ edit | raw ] migrated from node/918

Pues la verdad es que viendo este articulo que me he encontrado buscando algunas cosas, me he sentido muy identificado (yo creo que hasta he sentido algo de nostalgia de cuando programaba con Visual Basic allá por los noventa…)

Comparaciones odiosas: git contra el mundo

— [ edit | raw ] migrated from node/915

Restaurar ficheros borrados:

  • svn: svn up
  • mercurial: hg reset --all
  • git: git ls-files -d | xargs git checkout --   #(no es broma)

Bindings Python de librerías C++, con SIP

— [ edit | raw ] migrated from node/914
Cómo crear fácilmente bindings de Python para una librería C++ usando SIP

Introducción

¿Tienes algunas librerías en C++ hechas y no sabes cómo utilizarlas en Python? ¿Estás "decepcionado" porque tu programa construído totalmente en Python no es tan rápido como esperabas?. La solución es "bien sencilla": te programas una librería en C/C++ (si no la tienes) que haga el trabajo, construyes un wrapper para utilizarla en Python y... ¡listo! Para el primer paso no hay, de momento, solución automática. Pero para el segundo existen diversas herramientas que ayudan a la construcción del wrapper, su compilación e instalación. Una de estas herramientas, la que vamos a utilizar en esta receta, se llama python-sip. Asiste a la creación de los wrappers para librerías C/C++, aunque los ejemplos que se mostrarán serán de C++. Para más información, consulta la sección de Enlaces.

Ingredientes

# apt-get install python-sip4 sip4

Ejemplo

Librería C++

Para ilustrar el funcionamiento de python-sip, ¡qué mejor que un ejemplo!. Supón que la librería consta de una clase construída en C++ y cuyo fichero de cabecera (Impresora.h) es el siguiente:
#include <iostream>
#include <set>

using namespace std;

class Impresora {
public:
  Impresora(const string&);
  ~Impresora();

  void imprimirLista(set<string>);

private:
  string nombre;
};
Y cuya implementación es la siguiente (Impresora.cpp):
#include <Impresora.h>

Impresora::Impresora(const string& name) {
  nombre = name;
  cout << nombre << endl;
}

Impresora::~Impresora()
{}

void
Impresora::imprimirLista(set<string> lista) {
  set<string>::iterator it;
  for ( it=lista.begin() ; it != lista.end(); it++ )
    cout << " " << *it;

  cout << "<--- Imprime " << nombre << endl;
}
Como se puede apreciar, la clase tiene poca historia: tiene un atributo privado ("nombre") y un método para imprimir una lista (conjunto) de strings ordenados alfabéticamente. Para compilar esta librería tenemos el siguiente Makefile:
CXXFLAGS = -I. -fPIC
LFLAGS = -shared

all: libImpresora.so

libImpresora.so: Impresora.o
	$(CC) $(CXXFLAGS) $(LFLAGS) $^ -o $@
En definitiva, partimos de un archivo "libImpresora.so" que contiene la librería en C++ ya compilada. Ahora comienza la construcción del wrapper con ayuda de python-sip4.

Construcción del wrapper

Comenzamos creando un archivo que, por convenio, llamaremos "Impresora.sip". En este fichero especificaremos la estructura del wrapper con sintaxis sip, muy parecida a C++. Una primera aproximación sería la siguiente:
%Module Ejemplos 0

class Impresora {
%TypeHeaderCode
#include < Impresora.h >
%End

public:
  Impresora(const char *);
  ~Impresora();

  void imprimirLista(SIP_PYLIST);
};
  • %Module especifica el módulo en el que va estar incluída la librería, junto con un número de versión. En el ejemplo, el módulo es "Ejemplo" en su versión "0".
  • %TypeHeaderCode es necesario para que sip pueda leer la información de la clase que se va a "wrappear". Todo lo encerrado en ese bloque, sip lo utilizará para construir el wrapper con los tipos adecuados.
  • Nótese que se ha modificado los tipos de los argumentos del constructor y del método "imprimirLista". Sip no soporta tipos como string (y no digamos sets de la STL de C++). Sin embargo, en el caso de string, basta con especificar de que se trata de un "char*" y C++ se encargará del cambio de tipo. El argumento de tipo set se ha sustituído por una constante de sip que representa una lista de Python. Existe una constante de este tipo para cada uno de los tipos de Python (SIP_PYDICT...). Consúltese las referencias para más información.
  • Como se puede apreciar, no está especificado el atributo privado "nombre". Sip no soporta atributos ni métodos privados para la construcción del wrapper.
SIP_PYLIST representa a una lista de Python pero, ¿cómo se hará la correspondecia set->PythonList?. ¿Sip se encargará de ello?. Pues no. La correspondencia entre tipos complejos (objetos propios, clases auxiliares...) debe hacerse de forma explícita. Para especificar la conversión de uno a otro utilizaremos la directiva %MethodCode:
%Module Ejemplos 0
class Impresora {
%TypeHeaderCode
#include <Impresora.h>
%End
public:
Impresora(const char *);
~Impresora();
void imprimirLista(SIP_PYLIST);
%MethodCode
set<std::string> arg;
for(int i = 0; i < PyList_Size(a0); ++i) {
     char* value = PyString_AsString(PyList_GetItem(a0,i));
      arg.insert(, value);
}
sipCpp->imprimirLista(arg);
%End
};
  • Declaramos una variable del mismo tipo que el argumento que espera el método, en nuestro caso un set de strings.
  • a0 es el argumento (SIP_PYLIST) de tipo PyObject* de la librería CPython. Por tanto, el bucle no sirve nada más que para guardar cada valor de la lista Python en el set.
  • sipCpp es un puntero al objeto de entorno, en nuestro caso, "Impresora*". Cuando tenemos el set completamente construído llamamos a "imprimirLista" con el parámetro convertido.

Construcción del Wrapper

Una vez tenemos la especificación del fichero .sip, es hora de construir el wrapper de forma automática. Para ello, es aconsejable utilizar un pequeño script en python que genera los archivos .cpp y el Makefile final. Un fichero básico sería el siguiente:
import os
import sipconfig

# The name of the SIP build file generated by SIP and used by the build
# system.
build_file = "impresora.sbf"

# Get the SIP configuration information.
config = sipconfig.Configuration()

# Run SIP to generate the code.
os.system(" ".join([config.sip_bin, "-c", ".", "-b", build_file, "Impresora.sip"]))

# Create the Makefile.
makefile = sipconfig.SIPModuleMakefile(config, build_file)

# Add the library we are wrapping.  The name doesn't include any platform
# specific prefixes or extensions (e.g. the "lib" prefix on UNIX, or the
# ".dll" extension on Windows).
makefile.extra_libs = ["Impresora"]
makefile.extra_lflags = ["-L."]
# Generate the Makefile itself.
makefile.generate()
El código de este script es "autocomentado". Supongamos que el fichero que contiene el código anterior se llama "configure.py":
$ python configure.py
El comando anterior genera el wrapper en C++ y el Makefile que construirá todo.
$ make
La compilación del wrapper generará un archivo "Ejemplos.so", que es la librería compartida que será utilizada por Python.

Probando

Tenemos 2 opciones:
  • Ejecutar "make install" y, por tanto, instalaremos el archivo "Ejemplos.so" en /usr/lib/pythonX.X/site-packages donde será accesible para cualquier programa Python que utilize el módulo Ejemplos.
  • Probar la librería con iPython, ejecutándolo en el directorio donde se encuentra el nuevo módulo
Cualquiera que sea el modo de prueba se debe modificar la variable de entorno LD_LIBRARY_PATH para que el intérprete de Python pueda localizar el "libImpresora.so". A continuación, un ejemplo utilizando iPython:
~/pruebas/python-sip$ export LD_LIBRARY_PATH=.
~/pruebas/python-sip$ ipython
In [1]: import Ejemplos
In [2]: imp = Ejemplos.Impresora("HAL9000")
In [4]: imp.imprimirLista(["Dave", "tengo", "miedo"])
 Dave miedo tengo<--- Imprime HAL9000

Referencias

  • Documentación de sip4 en /usr/share/doc/sip4/reference/sipref.html, incluída en el paquete sip4
  • CPyton Reference.

ZeroC Ice: Parseando un fichero Slice

— [ edit | raw ] migrated from node/913
Cómo parsear un archivo Slice (el lenguaje de especificación de interfaces de ICE) para obtener toda la información semántica que contiene utilizando libSlice (el Parser proporcionado por ZeroC)

Introducción

Los archivos slice todos sabemos lo que son: Archivos que proporcionan una descripción de las clases, módulos, interfaces y operaciones que implementará un sistema distribuido basado en ICE.
La gente de ZeroC proporciona el código fuente de su middleware, pero éste no está muy bien documentado (siendo generosos), así que la manera de parsear un archivo slice y obtener toda la semántica que se necesitaba, ha pasado por hacer un poco de ingenería inversa del código de una de las utilidades que da ZeroC (en concreto slice2cpp). Así que para evitar tener que repetir el trabajo, aquí dejo un poco documentado el funcionamiento del parser para Slice que la gente de ZeroC montó.

Prerequisitos

Antes de empezar, no estaría de mas conocer un poco el patrón de programación visitor, ya que se utilizará para acceder a la información proporcionada por el parser. También se supone que se tienen nociones básicas de C++.
Yo he utilizado ice-3.3-beta así que tampoco estará de mas que además de tener ice instalado, se instalen los fuentes:

javieralso@avalon:~$ apt-get source zeroc-ice33

Parseando que es gerundio…

Para parsear un archivo slice, necesitaremos utilizar la librería Slice/Parser proporcionada por ZeroC. Un ejemplo de función que llama al parser sería la siguiente:

#include <IceUtil/OutputUtil.h>
#include <IceUtil/Options.h>
#include <Slice/Parser.h>
#include <vector>

#include "OurParser.h"
#include "OurVisitor.h"

OurParser::OurParser(const string& path, const string& filename)
{
  vector<string> dummyArgs;
  _pp = new Preprocessor(path,filename,dummyArgs);
  FILE* cppHandle = _pp->preprocess(false);

  UnitPtr u = Unit::createUnit(false, true, true, true);
  int parseStatus = u->parse("", cppHandle, false);

  OurVisitor visitor;
  u->visit(&visitor, cppHandle);
}

OurParser::~OurParser()
{}

int
main(int argc, char* argv[])
{
  OurParser* sp = new OurParser("", argv[1]);
  return 0;
}

¿y como funciona esto? Bueno, la clase OurParser será quien realice todo el trabajo. Básicamente, su cometido consiste en crear una instancia del preprocesador pasándole el archivo a parsear y un conjunto de opciones (en nuestro caso, como no queremos pasarle nada, se le pasa un vector de cadenas vacío, dummyArgs). Después de instanciar el preprocesador, se preprocesa el archivo:

  vector<string> dummyArgs;
  _pp = new Preprocessor(path,filename,dummyArgs);
  FILE* cppHandle = _pp->preprocess(false);

Después se instancia el parser propiamente dicho, y se parsea el Slice

  UnitPtr u = Unit::createUnit(false, true, true, true);
  int parseStatus = u->parse("", cppHandle, false);

u es quien realiza todo el trabajo de parseado. Las opciones que se pasan cuando se crea se utilizan entre otras cosas para propósitos de depuración y las que se dan en el ejemplo son válidas en general. Si se quiere, se puede jugar con los valores a ver qué pasa o directamente echar un ojo al código de slice2cpp donde están un poco mas comentadas.
la variable parseStatus almacena el resultado del parseo.

Una vez que se ha terminado de parsear el archivo, ya se cuenta con toda la información semántica, así que solo nos resta obtener dicha información y procesarla a nuestro antojo. Como se ha intentando que el parser sea lo mas general posible, de modo que pueda ser reutilizado para lo que sea necesario (vamos, que haya buena separación entre frontend y backend), se ha hecho uso del patron de diseño visitor que se comentó anteriormente. En nuestro caso creamos una clase que contendrá una serie de métodos que serán llamados en determinados momentos, como por ejemplo cuando se inicie la declaración de un módulo, su finalización, cuando se declare una función, sus parámetros, metadatos, se defina una estructura de datos o una clase, etc….
En nuestro caso, después del parseo, “visitamos” al parser para pedirle toda la información:

  OurVisitor visitor;
  u->visit(&visitor, cppHandle);

visitor es una instancia de nuestra clase visitante, que implementará los métodos necesarios para procesar la información.
Ésta clase viene a ser algo como ésto:

#include <Slice/Parser.h>

using namespace Slice;

class OurVisitor: public ParserVisitor
{
public:
  OurVisitor(SymbolTable&);
  ~OurVisitor();

  virtual bool visitModuleStart(const ModulePtr&);
  virtual void visitModuleEnd(const ModulePtr&);
  virtual void visitClassDecl(const ClassDeclPtr&);
  virtual bool visitClassDefStart(const ClassDefPtr&);
  virtual void visitClassDefEnd(const ClassDefPtr&);
  virtual bool visitExceptionStart(const ExceptionPtr&);
  virtual void visitExceptionEnd(const ExceptionPtr&);
  virtual bool visitStructStart(const StructPtr&);
  virtual void visitStructEnd(const StructPtr&);
  virtual void visitOperation(const OperationPtr&);
  virtual void visitParamDecl(const ParamDeclPtr&);
  virtual void visitDataMember(const DataMemberPtr&);
  virtual void visitSequence(const SequencePtr&);
  virtual void visitDictionary(const DictionaryPtr&);
  virtual void visitEnum(const EnumPtr&);
  virtual void visitConst(const ConstPtr&);
}

Bueno, como se puede ver, nuestro “visitante” tiene que heredar de la clase ParserVisitor, además, debe implementar todos los métodos que se ven. Éstos métodos serán llamados por el parser y será en ellos en los que nosotros definamos el procesado que queremos hacer de la información.

“Extrayendo” información

Bueno, aquí voy a comentar qué he hecho yo para obtener cierta información que necesitaba del Slice. Si se necesitase otra información, pues nada, a mirar el código de los conversores de código que da ZeroC, que es muy entrentenido :-P …

Modulos

Cada vez que se inicia el parseado de un módulo, se invoca la función visitModuleStart de nuestro visitor. Entre otras cosas, la información que puede ser necesaria en este punto es el nombre del módulo y su ámbito de declaración. Para acceder a esa información, algo como esto:

bool
OurVisitor::visitModuleStart(const ModulePtr& p)
{
   cout "Nombre del modulo: " << p->name() << endl;
   cout "Ambito de declaracion: " << p->scope() <<endl;
   return true;
}

Cuando se abandona la declaración de un módulo, se invoca a visitModuleEnd, pasandole exactamente la misma información que a su homólogo de inicio de módulo.

Clases e Interfaces

Cuando se declara una clase o una interfaz en el Slice, el parser visita la misma función: visitClassDefStart para el inicio de la declaración y visitClassDefEnd para finalizar la declaración. Si la declaración se encuentra dentro de un módulo, estaremos en la declaración de una interfaz. En caso contrario, se tratará de una clase.
Aquí la información que leí fue la misma que en el módulo, así que el código es casi idéntico:

bool
OurVisitor::visitClassDefStart(const ClassDefPtr& p)
{
   cout "Nombre del interfaz: " << p->name() << endl;
   cout "Ambito de declaracion: " << p->scope() <<endl;
   return true;
}

Operaciones

Para el caso de las operaciones necesitaremos leer mas información aparte del nombre y el ámbito. Ésta información se refiere al tipo de retorno, tipo de la función (por ejemplo puede ser idempotent), y los argumentos (nombre, tipo y dirección).

El procedimiento encargado de obtener la información de las operaciones es VisitOperation y un ejemplo de implementación que simplemente imprime información sería el siguiente:

void
OurVisitor::visitOperation(const OperationPtr& p)
{

  size_t strIndex;
  string metadataName, metadataValue;
  StringList operationMetaData;

  cout "Nombre: " << p->name() << endl;
  cout "Ambito de declaracion: " << p->scope() << endl;
  TypePtr ret = p->returnType();
  string retS = returnTypeToString(ret, "", p->getMetaData());
  cout << "Tipo de retorno: " << retS << endl;

  if(p->mode() == Operation::Idempotent || p->mode() == Operation::Nonmutating){
    // Idempotent operation
    cout << "Funcion idempotente" << endl;
  }

  // Looking for metadata.
  operationMetaData = p->getMetaData();
  cout << "Metadatos:" << endl;
  for(StringList::iterator it = operationMetaData.begin(); it != operationMetaData.end(); it++) {
    cout << *it << endl;
    }
  }

  // Looking for parameters.
  ParamDeclList paramList = p->parameters();
  cout << "Parametros:" << endl;
  for(ParamDeclList::const_iterator q = paramList.begin();\
       q != paramList.end(); ++q){
    cout << "Nombre: " << (*q)->name();
    StringList metaData = (*q)->getMetaData();
    if (!(*q)->isOutParam()){
      cout << "Parametro de salida" << endl;
      typeString = inputTypeToString((*q)->type(), false, metaData);
      cout << "Tipo del  parametro: " << typeString << endl;
    }
}

Vayamos por partes: Lo primero que hemos obtenido, ha sido el nombre y el ámbito de declaración de la operación. Después de ésto, se obtiene el tipo de retorno. Éste tipo es un enumerado, por lo que deberemos transformarlo a una cadena con el nombre adecuado para poderlo imprimir (o hacer cualquier otro tipo de proceso que nos interese)

    string retS = returnTypeToString(ret, "", p->getMetaData());

Después se consulta el modo de la operación, que nos dirá si es o no idempotente.
A continuación yo necesitaba los metadatos de las operaciones. getMetaData() devuelve una lista de cadenas, cada una de las cuales es un metadato, así que con un iterador recorremos dicha lista y vamos imprimiendo todos los metadados de cada operación. Ésto también se puede hacer con módulos, clases, interfaces, etc….
Finalmente, se consultan los parámetros: parameters() devuelve una lista de parámetros. Una vez que se tiene esa lista, hay que iterar sobre ella e ir obteniendo toda la información sobre cada uno de los parámetros:


  • Nombre: (q)→name()

  • Dirección: (q)→isOutParam(), devuelve verdadero si el parametro es de salida.

  • Tipo: (*q)→type(), enumerado con el tipo del parametro.

Sobre los tipos de retorno y de los parámetros

returnTypeToString, inputTypeToString y outputTypeToString son funciones que son llamadas para convertir los enumerados que determinan el tipo de una función o parámetro en la cadena que los representa textualmente. En la implementación que tenemos, éstas funciones se encuentran dentro de un módulo llamado Slice/CPlusPlusUtil que hay que incluir. Cuando se detecte un string, int o bool por ejemplo, nuestro programita responderá con algo como ::ICE::string o ::ICE::int pero ¿y si queremos que, por ejemplo, cuando detecte un entero nos diga “cacho entero” (por ejemplo ;-))? Bueno, pues tendremos que sobreescribir las funciones de las que hablé antes para que nos devuelva lo que nosotros queramos. Yo en mi caso, modifiqué las tres. Aquí muestro mi outputTypeToString:

string
Slice::outputTypeToString(const TypePtr& type, bool useWstring, const StringList& metaData)
{
    static const char* outputBuiltinTable[] =
    {
        "Byte",
        "bool",
        "Short",
        "Int",
        "Long",
        "Float",
        "Double",
        "string",
        "ObjectPtr",
        "ObjectPrx",
        "LocalObjectPtr"
    };

    BuiltinPtr builtin = BuiltinPtr::dynamicCast(type);
    if(builtin)
    {
        if(builtin->kind() == Builtin::KindString)
        {
            string strType = findMetaData(metaData, true);
            if(strType != "string" && (useWstring || strType == "wstring"))
            {
                if(featureProfile == IceE)
                {
                    return "Wstring&";
                }
                else
                {
                    return "wstring&";
                }
            }
        }
        return outputBuiltinTable[builtin->kind()];
    }

    ClassDeclPtr cl = ClassDeclPtr::dynamicCast(type);
    if(cl)
    {
        return fixKwd(cl->scoped() + "Ptr");
    }

    StructPtr st = StructPtr::dynamicCast(type);
    if(st)
    {
        if(findMetaData(st->getMetaData(), false) == "class")
        {
            return fixKwd(st->scoped() + "Ptr");
        }
        return fixKwd(st->scoped());
    }

    ProxyPtr proxy = ProxyPtr::dynamicCast(type);
    if(proxy)
    {
        return fixKwd(proxy->_class()->scoped() + "Prx");
    }

    SequencePtr seq = SequencePtr::dynamicCast(type);
    if(seq)
    {
        string seqType = findMetaData(metaData, false);
        if(!seqType.empty())
        {
	  return seqType;
        }
        else
        {
	  return fixKwd(seq->scoped());
        }
    }
    ContainedPtr contained = ContainedPtr::dynamicCast(type);
    if(contained)
    {
      return fixKwd(contained->scoped());
    }

    return "???";
}

Lo único que modifiqué fue la tabla de nombres del principio, dándole los que yo quise. Si los nombres que vamos a dar a los parámetros de entrada, de salida y al tipo de retorno van a ser los mismos (es decir, no vamos a distinguir por ejemplo un entero de salida, un entero de entrada y un tipo de retorno entero, llamandolos por el mismo nombre de forma interna en los tres casos) podemos utilizar solo una de éstas tres funciones y llamarla en todos los casos. En caso contrario, habrá que utilizar una función distinta para cada caso y llamarla cuando sea necesaria.

Concurso de Videotutoriales en Molinux

— [ edit | raw ] migrated from node/912
Con motivo de la apertura del canal en YouTube del CESLCAM y para celebrar el día de Internet el próximo 17 de mayo, el Centro ha puesto en marcha un concurso referido a la creación de videotutoriales en Molinux para premiar al mejor video formativo.

GladeWrapper, o cómo hacer una aplicación GTK con Python en 7 líneas

— [ edit | raw ] migrated from node/911

Esta receta explica cómo usar la clase GladeWrapper para hacer programas PyGTK + glade del modo más sencillo jamás visto.

Material para el taller de videojuegos

— [ edit | raw ] migrated from node/908

Aquí tenéis el material para el taller de videojuegos, aunque el material está disponible en repositorio con sus distintas trunks, para facilitar el uso y la comprensión, se han creado el “juego final” en 16 pasos.