Ir al contenido principal

TensorFlow con Python3

TensorFlow es una librería Open Source que Google ha liberado a principios de este mes. Permite de forma sencilla montar flujos de procesado y entrenamiento con elementos como redes neuronales, e incluso implementar nuevas operaciones sobre su arquitectura (tutorial y ejemplos).

Esta librería está escrita en C++, pero la arquitectura, los datos a tratar y las operaciones se declaran en Python. Esto está genial, ya que da un gran rendimiento sin tener que pelearse con Segmentation Faults, pero si pensabas utilizar Python3 para esto... quizá tengas que esperar un poco, resulta que aún no está soportado [issue #1 en el GitHub], aunque tienen intención de hacerlo en algún momento.

Mientras tanto, en este repo, en la rama python3 tenéis una forma de poder ir usándolo... no está totalmente actualizado y quedan cosas sin afinar, por ejemplo los checkpoints. Además hay que compilarlo a mano (no hay un paquete de pip ya preparado), pero ahora veremos que se puede hacer fácilmente.

Leer más…

El Julia set en un shader

Desde que empezó el tema de los smartphone, siempre sonó interesante la idea de programar desde el propio cacharro. Si bien ya se podía desde (casi?) el principio con SL4A, nunca fué algo demasiado cómodo.

Pues bien, resulta que en F-Droid (market de aplicaciones libres) tienen un entorno que permite programar Shaders en GLSL, programas que permiten generar gráficos desde la GPU, e incluso utilizarlos como fondo de pantalla, Shader Editor.

El programilla es bastante sencillo, y parece un buen método para aprender a hacer shaders, sabiendo por ejemplo C, y a partir de los ejemplos que incluye.

Pues bien, ahí va algo programado cacharreando con esto en el tren, dibuja el conjunto de Julia, moviendose en un par de dimensiones para que quede algo dinámico.

Leer más…

Un algoritmo de búsqueda de elementos similares

Es curioso, hay momentos en los que uno tiene que buscar una solución a un problema sencillo, por ejemplo, dadas varias listas de elementos, buscar la más parecida a otra nueva, y encontrar una solución (muy simple!). Pero esta solución no aparece en ningún otro sitio, a alguien se le tuvo que ocurrir! será tan simple (y tan inferior a otras), que no merece la pena documentarla?, simplemente uno no es capaz de encontrarla?... es probable :P...

Después de hacer alguna prueba más... resulta que no escala bien, y con grandes datos pierde ventaja rápidamente xD

Bueno, siendo como fuere, ahí va un algoritmo para buscar la lista (o listas), mas cercana a una dada, sin tener que comparar todos los elementos de todas.

La utilidad es bastante directa, en el campo de la IA (Inteligencia Artificial) hay una serie de algoritmos para hacer clasificación, dado un conjunto de entrenamiento etiquetado (con cada elemento asignado a una categoría) encuentra al conjunto al que pertenece un nuevo elemento.

Leer más…

Evolucionando decoders [1]: Brainfuck

Ya va casi un año desde el último post, como pasa el tiempo...

Esta época he estado liado con varios proyectos, he acabado mi Trabajo de Fin de Grado, del que intentaré hablar más adelante, y he participado en algún CTF. Algo que he notado es que en lo que se refiere a pruebas criptográficas suele haber dos tipos, en las que el algoritmo está claro desde el principio y hay que atacarlo. Y en las que se da un texto cifrado y se plantea el reto de obtener el flag que hay en el.

La idea detrás de este segundo tipo de pruebas (supongo) es determinar la capacidad de reconocer similitudes con cifrados ya existentes, de realizar un análisis de los datos (entropía, ...) y extraer conclusiones a partir de ahí. Hay gente que es muy buena haciendo esto...

Yo no.

Otra opción es hacer pruebas hasta que vaya apareciendo algo interesante, pero es un proceso largo y que no necesariamente da frutos, sería interesante poder automatizarlo, verdad?

Leer más…

Writeup de inBINcible [NcN CTF Quals]

Lleva un tiempo el blog parado, pero traigo algo interesante, veamos como reversear un binario de los presentados en las quals del CTF de la No Con Name.

Aviso: Soy bastante novato en esto, así que seguro que se podrían obviar muchos pasos o hacer más sencillo con los conocimientos y herramientas adecuadas. Si sabes algo de esto, mejor ve ya a la parte curiosa ;).

El binario en cuestión es “inbincible”, si lo ejecutamos produce el siguiente resultado:

1
2
3
$ ./inbincible
Nope!
$

Obviamente no es el que nos interesa, así que veamos lo que hace, abrimos con gdb y buscamos una función desde la que empezar

Leer más…

Extrayendo subtitulos de un .mkv

Realmente sobre esto ya había escrito pero se perdió en alguna migración... así que aquí está de nuevo

Todo el parseado y la extracción la implementa mkvtoolnix, así que habiéndolo instalado...

1
sudo apt-get install mkvtoolnix

A partir de ahí podemos ver las pistas que tiene un archivo

1
mkvinfo video.mkv

Leer más…

Haciendo MySQLdumps más amigables

Hace un tiempo había tenido que tratar con dumps de MySQL generados por mysqldump(1), a falta de una forma de control de versiones más específica (que por suerte no llegó a hacer falta) se utilizó git(7). Ahora bien, git permite hacer diff entre versiones, pero esto (al menos por defecto) se hace línea por línea, lo que produce que los diff entre dumps muestren grandes cambios aunque solo se produzcan en una fila de la base de datos, para solucionar ese inconveniente está este programa sqlsplit.c.

El programa no está muy pulido, tiene una función main que solo abre archivos y otra que (con la ayuda de dos macros *_*) simula algo parecido a un autómata de estados (realmente con una pila), la compilación es simple.

1
gcc sqlsplit.c -o sqlsplit

Por ejemplo, si la entrada fuera

1
2
3
4
5
set autocommit=0;
INSERT INTO `input_table` VALUES (1,'Title 1','File 1','Type','NULL','Date 1'),(2,'Another title','Another file, too','Type, you know','Language','9999'),(3,'A third title','File with \' too.heh','Some, types','NULL','Tomorrow');
/*!40000 ALTER TABLE `input_table` ENABLE KEYS */;
UNLOCK TABLES;
commit;

Haciendo esto...

1
./sqlsplit intput.sql output.sql

Conseguiríamos algo más legible

1
2
3
4
5
6
7
8
set autocommit=0;
INSERT INTO `input_table` VALUES
    (1,'Title 1','File 1','Type','NULL','Date 1'),
    (2,'Another title','Another file, too','Type, you know','Language','9999'),
    (3,'A third title','File with \' too.heh','Some, types','NULL','Tomorrow');
/*!40000 ALTER TABLE `input_table` ENABLE KEYS */;
UNLOCK TABLES;
commit;

Eso es todo, por supuesto si quisiéramos que aceptar o mostrar la salida por el terminal (por ejemplo para tomar o devolver archivos comprimidos) usaríamos /dev/stdin como entrada y/o /dev/stdout como salida.

Usando andEngine desde emacs

Hoy estaba hechando un vistazo a la programación de juegos en android, una librería con buena pinta para hacerlo es AndEngine, los tutoriales que he encontrado para hacerlo son para Eclipse, pero después de intentarlo y acabar un par de veces con un segfault ¡importando un proyecto! toca volver a los clásicos, vamos a ver como hacerlo con emacs.

Leer más…

Migrando ownCloud de MySQL a SQLite

En su momento realicé una instalación de ownCloud utilizando MySQL como base de datos, más tarde se hizo obvio que esta no era la opción correcta y que la necesidad de ahorrar toda la memoria RAM posible y el hecho de que no hubiera más accesos que los míos apuntaron a que debía haber optado por SQLite, el proceso es algo complicado la primera vez así que aquí queda explicado por si hay que repetirlo...

Lo primero es convertir la propia base de datos a SQlite, idealmente esto supondría sacar un mysqdump, pasárselo a SQLite y el estándar del lenguaje haría el resto...

Pero esto no es tan sencillo, resulta que hay incompatibilidades entre estos dos dialectos y resolverlas a mano requeriría un tiempo del que probablemente no dispongamos, para esto podemos recurrir a sequel, con Ruby y las librerías de desarrollo de los clientes de MySQL y SQLite instaladas podemos conseguirlo haciendo

1
2
3
gem sqlite3
gem mysql
gem sequel

Una vez instalado para convertir la base de datos solo habría que hacer

1
sequel 'mysql://db_username:db_pass@db_host/db_name' -C "sqlite://db.sqlite"

Y tendremos la base de daños migrada a SQLite en db.sqlite, solo falta la configuración.

En el directorio de instalación de ownCloud hay uno llamado config, dentro, el archivo a editar para pasar a la nueva base de datos es config.php, el significado de cada línea se puede ver en config.sample.php, concretamente habría que cambiar las líneas "dbtype" de mysql a sqlite.

Por último queda añadir la nueva base de datos a la carpeta data con el nombre que tomaba la base de datos y la extensión .db y listo, tras asignar los permisos para que ownCloud pueda acceder y modificar el archivo ya podemos usar de nuevo la plataforma.

Escribiendo un port de Erlang

Resulta que este cuatrimestre ha habido una asignatura cuya práctica se ha desarrollado en Erlang, un lenguaje funcional que favorece la programación concurrente y la comunicación de los procesos usando paso de mensajes. El resultado de la práctica es un crawler donde cada dominio tiene asignado un “hilo” que tendrá que hacer las peticiones al servidor web, más otro que se encargará de descargar imágenes e indexarlas utilizando pHash, el programa se compone de más partes pero ahora nos centraremos en esto.

(Por cierto, el proyecto se ha desarrollado en abierto, tenéis el código en su repositorio de GitHub, EPC).

Al principio cada hilo simplemente hacía una llamada a httpc:request, que es la forma que ofrece la libería estándar del lenguaje de hacer estas peticiones, pero parece que la concurrencia que ofrece deja que desear, esto producía inanicción en el proceso de indexación.

Más abajo la especificación muestra una posible solución:

Detalles de Option (option()):
sync
    La petición debe ser síncrona o asíncrona.
    Por defecto true.

En su momento no se comprobó si esta era una solución, sinó que se implementaron otras dos, una fué el uso de un proceso que se encargara de realizar las descargas dándole prioridad al indexer y que los crawler no le produjeran inanicción ya que toma un tiempo para obtener las características de la imágen (no mucho pero algo), esto está implementado en Erlang puro y fué el que se tomó en la rama master.

Otra opción fué implementar la descarga como un port, un programa externo escrito en este caso en C y que sería llamado desde un proceso de Erlang, esta posibilidad quedó registrada en la rama GET-by-port.

Comunicación C - Erlang

El port tiene dos componentes, la parte en C y la parte en Erlang, la comunicación se puede hacer de varios tipos, y se define con PortSettings en open_port, las posibilidades son

  • {packet, N}

    Los mensajes son precedidos por su longitud, enviada en N bytes, con el más significativo primero, los valores válidos de N son 1, 2 y 4.

  • stream

    Los mensajes son enviados sin longitud de paquete. Debe establecerse un protocolo definido por el usuario entre el proceso Erlang y el objeto externo.

  • {line, L}

    Los mensajes son enviados por líneas. Cada línea (delimitada por una secuencia de fin de línea dependiente del SO) se envía en un solo mensaje is. El formato del mensaje es {Flag, Línea}. Donde Flag es o eol o noeol y Línea son los datos realmente enviados (sin la sequencia de salto de línea).

    L especifica la lóngitud máxima de la línea en bytes. Las línea mayores que estas serán enviadas en más de un mensaje Lines, con el Flag noeol para todos los mensajes menos el último. Si el fin de archivo se encuentra en cualquier otro lugar a parte de inmediatamente siguiendo un salto de línea, la última línea también será enviada con el Flag noeol. En el resto de casos, las líneas son enviadas con el Flag eol.

    Las opciones {packet, N} y {line, L} son mútuamente exclusivas.

En este caso elegiremos {packet, 4}, suficiente para enviar páginas enteras de vuelta.

Comunicación - El lado de C

Centrémonos ahora en lo que ocurre en el programa escrito en C cuando recibe los datos, la función que maneja esto es char* read_url()

El proceso es sencillo, lee 4 bytes de stdin y los guarda como un uint32_t

1
2
3
4
uint32_t length;
if (fread(&length, 4, 1, stdin) != 1){
    return NULL;
}

Después convierte los datos de big-endian a la codificación del host, esto se hace con la función ntohl()

1
length = ntohl(length);

El resto es simplemente leer la cadena de stdin, sin ninguna transformación y conociendo su longitud

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
char *url = malloc(sizeof(char) * (length + 1));
if (url == NULL){
    return NULL;
}

unsigned int already_read = 0;
while (already_read < length){
    already_read += fread(&url[already_read], sizeof(uint8_t),
                          length - already_read, stdin);
}
url[length] = '\0';

El devolver los datos a Erlang no supone mucho más esfuerzo, como se puede ver en el procedimiento void show_result(headers, body). Los datos se mandan en dos grupos, primero las cabeceras y después el cuerpo del resultado, enviar las cabeceras supone convertir su tamaño a big-endian usando htonl y escribirlo a stdout, para después escribir toda la cadena directamente

1
2
3
4
5
6
7
8
9
/* Pueden pasar cosas muy extrañas si olvidamos esto */
uint32_t headers_size = htonl(headers.size);
fwrite(&headers_size, 4, 1, stdout);

unsigned int written_head = 0;
while (written_head < headers.size){
    written_head += fwrite(&(headers.memory[written_head]), sizeof(uint8_t),
                           headers.size - written_head, stdout);
}

... repetiríamos lo mismo para el cuerpo de la respuesta

1
2
3
4
5
6
7
8
uint32_t body_size = htonl(body.size);
fwrite(&body_size, 4, 1, stdout);

unsigned int written_body = 0;
while (written_body < body.size){
    written_body += fwrite(&(body.memory[written_body]), sizeof(uint8_t),
                           body.size - written_body, stdout);
}

Y eso es todo lo que hay que hacer para completar la interfaz con Erlang, el resto es lógica común de C, en este caso sería hacer peticiones HTTP, algo que usando cURL no supone un gran problema y cada vez que quisieramos tomar una url solo habría que llamar a read_url(), y por supuesto la compilación se hace de la forma habitual.

Comunicación - El lado de Erlang

La lógica que debe manejar el proceso Erlang no es tampoco complicada, simplemente habría que utilizar open_port, que devolvería el PID con el que comunicarse, suponiendo que hayamos definido HTTP_GET_BINARY_PATH con la ruta al binario compilado que complete el port

1
Port = open_port({spawn, ?HTTP_GET_BINARY_PATH}, [{packet, 4}])

Cuando hubiera que enviar datos al binario se enviarían a través de ese PID, enviando una tupla

1
{Pid_del_proceso_actual, {command, Mensaje}}

Por ejemplo

1
Port ! {self(), {command, Msg}},

Esto se convierte en los datos que recibe el binario, de la misma forma cuando este envíe datos se recibirán en un mensaje con la forma

1
{Pid_del_port, {data, Mensaje_recibido}}

Como se reciben dos, las cabeceras y el cuerpo del mensaje...

1
2
3
4
5
6
7
8
9
receive
    {Port, {data, Headers}} ->
        receive
            {Port, {data, Body}} ->
                From ! {self(), {http_get, {ok, {200,
                                                 process_headers(Headers),
                                                 Body}}}}
        end
end,

Se puede ver que el resultado se muestra en un mensaje, esto es por que está pensado para correr dentro de un bucle y mantener el port activo en un proceso aislado hasta que el proceso que lo haya creado se cierre, pero no es necesario que se maneje de esta forma, no hay ningún motivo por el que no debiera devolver el resultado directamente como una función “normal”, aunque ¿quizá? dé problemas al coordinar el acceso al input/output si hay varios procesos dándole uso.

... y eso es todo, ya tenemos nuestro trozo de código en C ejecutandose desde Erlang, por supuesto al ser stdin/stdout la interfaz cualquier lenguaje puede ser usado, es una estrategia que da bastante juego :)