Un naufragio personal

New ActivityPub support in Gruta

I have implemented partial ActivityPub support in pygruta, the Python port of my decades-old web CMS software Gruta. It has been implemented as two big blocks; the first one is a daemon process that, getting queries redirected from the web server,

  • Answers to webfinger GET method requests,
  • Answers to ActivityPub actor (user) GET method requests,
  • Accepts (and confirms) follow commands from POST method requests and registers the follower,
  • Accepts un-following commands from POST method requests and de-registers the follower,
  • Accepts messages (direct or public) from any ActivityPub user from POST method requests and stores them in a special topic as Gruta stories.

On the other hand, a command-line tool (triggered by cron) does the following:

  • Collects a story feed (the same set of stories that would be used in an ATOM or RSS feed) and sends it to all registered followers as public ActivityPub notes.

As of now, you cannot answer to a message sent from this network. I've yet to find a way of doing it, but most probably it would be by writing a standard story and using a special destination field or searching for a mention inside the story content matching the @user@host standard way of mentioning.

It has been a very tedious work, as the documentation is poor and confusing and you never get helpful feedback from errors. I did the development against different software (Mastodon, Friendica and Pleroma), but only got it working for the first one (it's the most common out there, though).

You can follow my id from this network.

A function to decode utf-8 in streaming mode

This is my C language function to decode utf-8 into wide characters, a byte at a time. It also detects encoding errors.

 * mpdm_utf8_to_wc - Converts from utf8 to wchar (streaming).
 * @w: convert wide char
 * @s: temporal state
 * @c: char read from stream
 * Converts a stream of utf8 characters to wide char ones. The input
 * stream is read one byte at a time from @c and composed into @w
 * until a Unicode codepoint is ready. The @s integer keeps an internal
 * state change and must be set to 0 before the stream is read. It
 * detects encoding errors; in this case, the special Unicode
 * char U+FFFD is returned.
 * When 0 is returned, a new wide char is available into @w. If
 * the stream is interrupted in the middle of a multibyte character,
 * the @s state variable will not be 0.
int mpdm_utf8_to_wc(wchar_t *w, int *s, char c)
    if (!*s && (c & 0x80) == 0) { /* 1 byte char */
        *w = c;
    if (!*s && (c & 0xe0) == 0xc0) { /* 2 byte char */
        *w = (c & 0x1f) << 6; *s = 1;
    if (!*s && (c & 0xf0) == 0xe0) { /* 3 byte char */
        *w = (c & 0x0f) << 12; *s = 2;
    if (!*s && (c & 0xf8) == 0xf0) { /* 4 byte char */
        *w = (c & 0x07) << 18; *s = 3;
    if (*s && (c & 0xc0) == 0x80) { /* continuation byte */
        switch (*s) {
        case 3: *w |= (c & 0x3f) << 12; break;
        case 2: *w |= (c & 0x3f) << 6;  break;
        case 1: *w |= (c & 0x3f);       break;

    else {
        *w = L'\xfffd';
        *s = 0;

    return *s;

Sobre la creación de canales de Telegram

Hace unos días investigué para un amigo cómo crear y usar canales de Telegram y le envié este email contándole lo que he averiguado. Lo adjunto aquí para que no se pierda:

Hola. He investigado sobre los canales de Telegram y cómo automatizarlo. Como siempre todo es complicado y confuso. Te lo cuento aquí porque mañana seguro que se me ha olvidado.

Lo primero es crear un canal. Eso ya lo has hecho.

Lo segundo es crear un bot. Es una especie de usuario de Telegram que no es un usuario pero que puede postear en canales. Para crearlo hay que hablar con otro bot que se llama BotFather. Ahí hay que darle comandos tipo IRC para crear tu bot (sí, es así de confuso). Hay que mandarle el mensaje /newbot y él (como en un chat robótico) te pide el nombre del bot y el nombre del usuario del bot (no sé muy bien cuál es la diferencia ni por qué hacen falta dos nombres y por qué no puedes ponerle el mismo). Después de esto te da una cadena de texto mágica que es un identificador autenticado del bot para poder postear desde fuera.

Luego tienes que ir al canal y añadir al bot como administrador. Solo funciona si lo haces desde el móvil, desde el ordenador no lo he conseguido. Tienes que buscar el nombre del bot desde la lupa porque no te sale automáticamente tu lista de bots.

Una vez hecho esto un par de veces (a la primera no me ha funcionado), ya le puedes mandar comandos al bot por HTTP para postear en aquellos canales en los que está autorizado. Esto se hace con una query como la que sigue:

Esto se puede hacer directamente con el comando curl del Linux o desde algún programa, es una petición HTTP normal.

Eso publica en modo texto. Hay un modo especial HTML que es MUY limitado y solo acepta negrilla, cursiva, enlaces y poco más. Con eso hay que montárselo todo. En concreto, NO acepta <p> para separar líneas ni títulos <h1>, <h2>, etc ni nada de eso, así que hay que hacer una especie de conversión (no es que ignore los tags, es que casca y te rechaza el envío).

Leyendo por ahí he descubierto que el modo HTML sí acepta cortes de párrafo pero hay que meterlos a pelo, es decir, metiendo %0A (ascii del line feed). Para añadir imágenes hay otro truco, que es ponerlas como enlaces (NO como imágenes). Si dejas el texto del enlace vacío o con un espacio lo ignora. La gente dice que le pone un carácter Unicode especial que es el "separador que no ocupa espacio" pero a mí me lo rechaza.

Este comando funciona y genera una entrada más o menos bonita:

 curl '<b>Title</b>%0AThis is a <i>test</i>. <a href="">·</a>'

Así que se podría hacer un programita que instalado en un cron coja, por ejemplo, el feed ATOM o RSS de Nutriguía, magree un poco las entradas, las deje aceptables para el Telegram y las envíe con sendas peticiones HTTP como las que te he comentado arriba.

Quizá alguien ha hecho ya ese programa, no he investigado más allá.

On selecting text in the Minimum Profit Text Editor

As this is a question I have to answer periodically here are my final words on it.

The Minimum Profit Text Editor has three selection modes: "movement", "block" and "vertical".

The "movement" one is the way of selecting text that is implemented everywhere and is somewhat of a standard: by pressing the shift key and using any of the movement actions (left, right, word left, word right, up, down, page up, page down, beginning of line, end of line, beginning of document or end of document) or by left clicking and dragging with the mouse. Additionally, you can right-click and drag to extend the selection. Once the block is marked any movement key deselects it. Typing something replaces the selection. Hitting del or backspace erases the selected text. Though this mode is what new users expect, it works weakly on non-GUI interfaces because of lacking or defective support in the underlying libraries and systems.

The "block" selection mode is an older style one (and the first one that MP had): by pressing a key (f9 by default) you mark the beginning or end of the marked text. The selection survives any movement (indeed, it's the only way block selection can be done, by moving to another place and marking the other end) and you can extend the block above or below whenever you want. Replacing and erasing works as expected. Additionally, most operations like search, replace, etc. only apply to the marked text if there is one (this is very useful). The selection only disappears when copying, erasing, replacing, mouse-clicking or unmarking (by pressing the f8 key). This is the way I copy and paste; I never use the standard way (I know you don't care).

The "vertical" selection mode also works by marking the beginning or the end of the block, but the selection forms a square shape (x, y to x', y') instead of a line-flow one. By default it's done by hitting ctrl-b. The selection can also be extended repeatedly. As in "block" mode, marked text is disabled after copying or by pressing f8. I never use this option and never did (it was implemented by a fellow programmer).

I agree that the "movement", "block" and "vertical" terms are a sloppy way to describe the operations they do.

Why the Minimum Profit Text Editor is not part of Debian

Yesterday I received three different emails asking me why the Minimum Profit text editor is not included in the Debian linux distribution, a question most probably arised due to the recent release of Debian 10. One of the messages even mentioned that it was called mped there, so he must be a very long time user. Anyway, this is a briefing I gave to a user many years ago (2011):

"And regarding linux distrubutions, I know for sure that it's at least part of Gentoo, Puppy Linux and there is even a *BSD port. It also used to be part of Debian, but I had very bad luck there: someone picked it up and became its maintainer, for later forgetting about it and not following version updates. It happened that when the first stable distribution that became UTF-8-enabled by default (don't remember what was its name, maybe sarge), "Upstream" MP was already at its 5.x version, but Debian got still a 3.x, which had the very nasty habit of destroying UTF-8 files. I posted an RC bug regarding this, but it went released anyway, probably mangling every user file that tried it and most probably losing users. Later, the maintainer was considered as Missing-in-action and the package orphaned; another time later the QA equipment took control and updated it to the latest 5.x version, what made me happy for a time; but just on the verge of the release of current stable version the package was deleted with the message "few users; alternatives exist" and disappeared from their database. This last version is still what got migrated to Ubuntu, where it still exists, but probably unmaintained and forgotten."

Those "latest stable versions" of Minimum Profit and Debian I talked about in that paragraph were the ones back on 2011 (whichever they were). MP is no longer on Ubuntu and I don't know nor care if Gentoo or Puppy Linux even still exist (they were popular distributions those days).

Anyway, the Minimum Profit text editor is alive and well and having periodic updates. It's public domain software and can be built from source code for virtually any platform. Portable (i.e. no installation needed) binaries exist for MS Windows (32 or 64 bits, GUI or console versions). It's probably better that the text editor you are using now.

I also think that few users, alternatives exist is a reason can be given for the deletion of most of us.

MP: Not only for text-editing but also for pipe-turning.

Disk partitions and UDF formatting on MS Windows

Partition manager

Open cmd.exe and run


Formatting a disk as UDF

 format x: /fs:UDF

Using the UDF filesystem in USB sticks

The best way of using USB sticks for sharing information between Linux and MS Windows systems is to have them formatted with the UDF filesystem. On MS Windows it's fully supported (read-only on XP, though) while on Linux is much better that FAT monstrosities because permissions and owners are preserved.

To format an USB stick, use the mkudffs program:

 mkudffs -b 512 --media-type=hd /dev/{full disk device}

You also probably want to delete all partitions in the stick to avoid it being wrongly detected.

Someone said these UDF-formatted sticks also work correctly on MacOS (didn't try).

Doorway - interesante efecto óptico

Esto lo vi hace muchos años y por fin he vuelto a encontrarlo.

La siguiente imagen logra un efecto sorprendente. No es inmediato, necesitas fijar la vista en la puerta que aparece al fondo durante un rato. No tengo ni idea de cómo lo han conseguido: no parece ser un estereograma ni nada parecido. Desenfocar un poco la vista parece que favorece el efecto.

🔗 ...

Filtración 0-day: los números PIN más comunes

Recientemente se ha filtrado la lista de los números PIN más usados. Estos números son cadenas de cuatro dígitos que sirven como contraseña para teléfonos móviles, tarjetas de crédito y otros dispositivos que potencialmente contienen información sensible. Si tu número está en esta lista, se considera vulnerable y deberías cambiarlo inmediatamente.

🔗 ...

Cómo ponerle una radio normal a un Jeep KJ / Liberty / Cherokee

Hace falta lo siguiente:

  1. Un adaptador ISO para alimentación y altavoces (10,03 €)
  2. Un adaptador para la antena (7,99 $)
  3. Un adaptador/carcasa para encajar la radio (11,98 $)
  4. Una radio (35,63 €)

La radio vale cualquiera siempre que lleve doble conector ISO. Como yo no quería CDs ni mierdas, compré la más barata, que tuviera radio, tarjeta SD y USB. Ya que los Jeep llevan el reloj en la radio y la vamos a sustituir, también conviene que la radio tenga reloj.

Además de lo mencionado arriba tuve que comprar cuatro tornillos para enganchar la radio a la nueva carcasa. En casa siempre tengo un millón de tornillos pero como era de esperar no me valía ninguno.

Para cambiarla hay que seguir los pasos obvios:

  • Montar la radio en la nueva carcasa.
  • Enchufar el nº 1 y el nº 2 en la radio.
  • Quitar el cenicero de al lado de los cargadores de mechero y sacar el tornillo que hay ahí.
  • Tirar para sacar todo el frontal.
  • Sacar la radio quitando los cuatro tornillos de las esquinas (que nos valdrán luego para poner la nueva carcasa).
  • Quitar el cable de datos y el de antena.
  • Conectar el nº 2 al cable de la antena.
  • Conectar el nº 1 al cable de la radio.
  • Meter con cuidado, atornillar y volver a colocar el frontal.

La única contrapartida es que los mandos del volante ya no sirven, pero puedo sobrevivir sin ellos.

El calendario de la revolución francesa

A contar desde el equinoccio de otoño.

Mes Comienzo
vendimiario 22, 23 ó 24 de septiembre
brumario 22, 23 ó 24 de octubre
frimario 22, 22 ó 23 de noviembre
nivoso 21, 22 ó 23 de diciembre
pluvioso 20, 21 ó 22 de enero
ventoso 19, 20 ó 21 de febrero
germinal 20 ó 21 de marzo
floreal 20 ó 21 de abril
pradeal 20 ó 21 de mayo
mesidor 19 ó 20 de junio
termidor 19 ó 20 de julio
frutidor 18 ó 19 de agosto

HOWTO Enter Android Engineer Mode



Es un bittorrent personal, que hace que puedas compartir archivos que se sincronizan en todos tus ordenadores, a la forma de Dropbox o Google Drive. Una de las diferencias es que, al no depender de una «nube» externa, no tienes ninguna limitación de espacio de almacenamiento ni nadie puede mirar lo que guardas.

Está basado en «secretos»; cada vez que se instala el programa en un equipo, pregunta si ya tienes un secreto (proporcionado por instalaciones previas) o si crea uno nuevo. Todos los equipos que compartan un secreto comparten los archivos asociados. Un secreto es sólo una cadena larga de caracteres.

No se limita a un directorio; puedes tener todos los que quieras con sus correspondientes secretos, así que puedes compartir con diferente gente diferentes directorios, incluso con permisos limitados (es decir, por ejemplo, puedes compartir conmigo tu carpeta de MP3 en modo sólo lectura, de forma que yo no pueda borrarte ni añadir nada).

Este es el secreto (sólo lectura) para mi colección de imprescindibles de música clásica, que siempre mantengo por debajo de 1GB y que cambio a menudo:


Para usarlo, instala BtSync, créate una carpeta y dile al BtSync que la añada dándole este secreto.

Existen versiones para MS Windows, Mac y Linux (no es software libre).

Este equipo no está ejecutando una copia de windows original

Desactivar la actualización de Windows KB971033:

  • Panel de control / programas / Programas y características, ver actualizaciones instaladas
  • Seleccionar KB971033 y desinstalar
  • Ir a Windows Update, buscar actualizaciones
  • Sobre KB971033, botón derecho y ocultar actualización

HOWTO ssh persistence, redux


 Host *
 ControlMaster auto
 ControlPath ~/.ssh/%r@%h:%p
 ControlPersist 1h

HOWTO install Linux from grub with an USB pendrive

I had a fucked up installation where only GRUB2 survived. The machine CD drive is broken and the BIOS is so old that it doesn't allow booting from USB.

  1. Install an ISO onto an USB drive using
  2. Insert the USB into the fucked linux and switch it on.
  3. On the grub> prompt, type ls (hd and press the tab key to auto-expand until you find the USB drive (it's most probably (hd1,msdos1)).
  4. Type set root=(hd1,msdos1).
  5. Type chainloader +1.
  6. Type boot.

An algorithm to play random music

Are you playing your huge music library in random mode for hours or days and fed up of listening the same fucking songs all over again, while never hearing others? So do I.

Regardless of what Steve Jobs and other morons think, their music players are fucked up, specially their shuffle functions. Music players running in random mode should keep the last time a song was played into account.

This is the algorithm to select which song to play next:

  1. Sort all songs by the last time they were played, in ascending order (never played ones fall at the beginning of the list, recently played songs fall at the end).
  2. Pick a given set from the beginning of the list (like, say, the 10% of them).
  3. Pick one song from this set at random.
  4. Get the author of this song and test if another song by the same author was played recently (like, say, the 10% of the last played songs). If it is, jump back to previous step.
  5. store current time as its playing time, and play it.

This way, new songs added to the set have the higher chance of being played soon, as they are at the top. Songs played a long time ago will follow. And the song that have just played won't be heard for a long time.

Implement this in your music players, scumbags.

Update: I've improved the algorithm by adding a step that spreads the authors.

HOWTO check passwords without sending them on the clear

There is a simple method to check for a valid secret among two parts without sending it on the clear. This note explains how.

  1. The server accepts a connection from the client and builds a random token (a text string). This string is sent to the client.
  2. The client concatenates the random token to the password and feeds the resulting string to a cryptographically-secure hashing function like, for example, sha1. The client sends the hash to the server.
  3. The server does the same operation (concatenating the random token to the password and hashing it) and compares the resulting hash with the one the client sent.
  4. If they match, the password is accepted and the connection goes on, otherwise is dropped.

This algorithm is related to the "salt" in UNIX passwords and to the Diffie-Hellman algorithm.


The server will only accept connections from clients that know that the password is seeKriT.

A connection is started. The server creates a random token and sends it to the client:

 OK 42d4df05

The client takes that, concatenates the password and feeds it to the sha1 hash engine:

 sha1("42d4df05seeKriT") = b0f3bd621ba92f5c26261d36a8ffb9cb3b7b399d

That monstrosity is sent to the server:


The server then does the same concatenation + hashing:

 sha1("42d4df05seeKriT") = b0f3bd621ba92f5c26261d36a8ffb9cb3b7b399d

and tests for the result. As they are the same, it assumes the connection is valid and returns


or otherwise, if the hashes do not match, returns


and closes the connection.

Reformatting / indenting a Cascade Style Sheet file

If you need to compare two CSS files, the freestyle formatting can drive you crazy. You can use this little Perl script to reformat / reindent them. Or if you just want a tidier file.

  1. Formats a CSS file from STDIN
  2. Angel Ortega <>
  3. Public domain
 my $css = join('', <STDIN>);
 $css =~ s/\s+/ /g;
 my $in = 0;
 foreach my $c (split(/(\s*\{\s*)|(\s*\}\s*)/, $css)) {
 	if ($c =~ /\{/) {
 		print " {\n";
 		$in = 1;
 	elsif ($c =~ /\}/) {
 		print "}\n";
 		$in = 0;
 	else {
 		if ($in) {
 			foreach my $sc (split(/\s*;\s*/, $c)) {
 				print "\t$sc;\n";
 		else {
 			print $c;

I agree that, if comparing two CSS files is the aim, sorting the entries alphabetically would also be great; I left that as an exercise for the reader.

Distribution rights for Antichthon Universalis

It seems that Pavel has gotten permission from the source to reproduce Antichthon Universalis. He is searching for publishers like crazy, but I'm afraid they won't find the document as interesting as he does (provided that he can find anybody not on holidays these days).

He says he doesn't have the technical knowledge to do it; maybe I'll help him. Who knows, it's not impossible that I even become the editor...

There are still no words from the language teacher on the subject.

On my part, I've finished taking a look at the book itself. I'm almost sure it's a forgery like the Oera Linda, but funny to look at anyway.