triptico.com

Un naufragio personal

The 2019 log of achievements

Through my friend Víctor I learnt about a concept expanded by a blogger named Julia Evans in this document: it proposes the idea of creating, as a tool for self-awareness, warning to others like bosses and friends and pure onanism, a document enumerating every thing, action or project that you consider a personal or professional achievement. The original post suggest to write this brag document periodically. I'm going to do this exercise covering all this about-to-die year. Of course, I don't remember anything, but fortunately I have everything under version control so I can just ask the computer about it. So here they are: a list of awesome things I did on 2019, in no particular order:

  • As usual, work is hell, but I managed to develop a software suite for decrypting the images of the PAZ spanish satellite, a project requested by Hisdesat, the satellite operator. I worked on this by myself and didn't depend on work nor delays from others, so it was deployed on time and with better performance that the specification requested.
  • Also about my paying job, I collaborated on the CHEOPS exoplanet searching satellite by European and Swiss Space Agencies, manufactured here in Spain and scheduled to be launched on 17 December. It's a relatively-low budget equipment that looks like a humungous photo camera, detachable lens cover and all. My job here was on software for the platform simulator and for some parts of the launcher.
  • After trying several crappy tools to backup IMAP mail servers (i.e. my mail on Gmail) that failed miserably because they pretend to be frameworks or sync tools or other fucking nonsense I got sick of it and wrote my own tool, aov-imap-fetch. It just downloads the full content of an IMAP server for a specific user without touching anything and stores all messages into Maildirs. Messages repeated among several folders (very common in Gmail) are maintained as hardlinks instead of copies. Messages that are no longer on the server are moved to a special folder.
  • Though I don't write music with my band Ann Hell anymore, I managed to do a remash / remix of some old songs into something named The Triumph of Death than can be listened to on Youtube. As a trivia fact, these set of songs were originally conceived together, so this somewhat puts things back in order.
  • To do the previous one I developed ahxm-glue, a command-line tool that accepts a set of .wav files, does some operations on them (like cropping, overlapping or fading-out) and gives another .wav as a result. It was meant to be a part of my Ann Hell Ex Machina music making software (hence the name), but I released it separately instead because it lacks any library dependencies (it's pure ANSI C).
  • I wrote a software library to compress/decompress data using the Huffman algorithm for a web seminar I was the teacher of. Though it was learning material for my students, the implementation is functional enough to be used in production. It includes a command-line tool as well.
  • In August, the book Sturm un Drang, an anthology of texts inspired by early German romanticism that includes my short story Tasso, Lamento e Trionfo, was published. I haven't read any review from anyone yet, so maybe I should mark this as an under-achievement.
  • I worked much into my web/blogging CMS Gruta and its companion pygruta to implement a new series of social-network-related protocols like ActivityPub (used by Fediverse-affiliated software like Mastodon, Pleroma or Friendica), Indieweb's Webmention, Telegram and other unrelated things like calendaring and Twitter search imports.
  • Fed up of the complexity and lack of quality in personal encryption tools (specially in the field of assymmetric cryptography), I wrote my own, aov-sodium, which is mostly a wrapper to the ECDH and stream cyphering functions in libsodium. You can encrypt any file or archive with my tool without having to type any password, because it only needs the public key to do it (of course, you'll need the secret key to decrypt it, but it can live on another computer); this is great for unattended backups of remote servers.
  • From August to September I wrote a new 34000 words novel (in spanish) with the working title El chico que volvió (The Boy Who Came Back), about a set of old friends that lost contact after the years and have to reunite in the village they were grown after the death of one of them. Genre is realism.
  • I fixed some nasty errors in the 1993 3D shoot-em-up game Freaks 2.002 that made impossible to run it on recent Linux and MS Windows systems.
  • I wrote the prologue for a book of short stories inspired by the unfinished work by Edgar Allan Poe The Light-House. It won't get published until 2020, I think.
  • I wrote a new ad-hoc compiler for MPSL (Minimum Profit Scripting Language), the programming language I created to develop my Minimum Profit Text Editor. This new compiler coexists with the original (a Flex+Yacc version), but it's now the default one.
  • I re-licensed almost all my software from GPL to public domain. I'm not sure if I can call this an achievement.

Of course, a list of achievements should also contain a set of things that you tried but failed because you suck or because everyone is an asshole or because the universe is a motherfucker. Also unsorted, here they are:

  • I presented a small set of already-written short stories to several literary contests. None of them were accepted.
  • I presented my novel El legado del cornezuelo to two book publishers: the first one was contacted on January (almost a year ago!) and got no response from them (may be they died on a flood or something). The other publisher, who was contacted on September, was much faster and friendly in his response. He read the book up to the end and sent me a list of reasons why my work failed on us, suggesting several modifications (that I understood as an almost-complete rewrite). I'm a bonehead and a real artist and a complete moron and decided not to touch my manuscript, so it was rejected.
  • Probably my greatest non-achievement of the year was that I passed again through another valley in my depression curve, so I needed to spend a week or so in a psychiatric hospital after suffering from deep suicide ideas. My experience there was not as sad as it may sound; doctors and nurses were warm and friendly, met some sweet people that were suffering badly from internal desease or from bad luck or from other assholes and had time to keep my head busy in occupational therapy and group conversations. My meds were changed. Of course, I don't feel any better.
  • I wrote a short story on purpose for another literary contest that required material in a very special genre. Though they said winners would be known in December, I don't know yet if I failed again or not, but no news in cases like this are usually bad news.
  • I got absolutely no reviews on any of my literary work. Aside from my usual readers Paloma, Fernando, Ana, Manuel y Marisa, nobody ever read any of my novels or stories.

It's kind of disheartening to think back about all these things and how worthless they really are.

On HDMI things that don't exist

I'm the maintainer of several headless servers that very ocassionally need to have a screen attached to them for special cases like boot errors or BIOS tweaking or the like. For this, I need to keep around a fucking screen monitor that is cumbersome and heavy and tedious and serve no other purpose while idle. Instead, tablets (that usually have screens with acceptable size and quality) should include a HDMI input socket that, when plugged, made it to behave like a common monitor.

On the other hand, TV sets are no longer just gadgets that receive signals and convert them to pictures and sounds to be fed to couch potatos. Internally they are computers that also generate content via its internal apps like Netflix and Prime Video and whatever, so they should include a HDMI output socket to connect, for example, another TV in the other side of the room or a projector.

Computers should also have the HDMI input socket mentioned above, as well as reverse-USB connectors for using its keyboard and mouse to control external equipment. This way, a simple laptop could be used as a portable KVM without the stupidly expensive gadgets that are common in server farms.

I don't think any of these features would make equipment much more expensive nor complicated.

Build these things and I'll buy them.

Music that made my 2019

You may like these songs I enjoyed during 2019:

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 @angel@triptico.com from this network.

El sueño del niño en el pasillo

Hoy he soñado que aparecía un niño en mi casa (que no sé quien era) y que estaba aterrorizado porque había visto en la cocina a una señora que tenía «los ojos largos».

El chico que volvió — Lista de temas


Ver en Youtube
  • Gustav Mahler — Feierlich und gemessen (Sinfonía nº 1, III)
  • Supertramp — Take The Long Way Home
  • The Cure — Boys Don't Cry
  • New Order — True Faith
  • Siouxsie and the Banshees — Israel
  • Bauhaus — Bela Lugosi's Dead
  • The Scavengers — Violence
  • Severed Heads — Dead Eyes Opened
  • Warpaint — Elephants
  • Apollo Sunshine — We Are Born When We Die
  • The Bolshoi — A Way II
  • Ann Hell — The Triumph of Death
  • George McCrae — Rock You Baby
  • Joe Dassin — Et Si Tu N'Existais Pas
  • Counting Crows — Mr. Jones
  • Laura Branigan — Self Control
  • Plastic Bertrand — Ça Plane Pour Moi
  • The Rolling Stones — Sympathy for the Devil
  • The Cranberries — Promises
  • Skin — Kill Everything
  • Giacomo Puccini — Intermezzo (Manon Lescaut)

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;
    }
    else
    if (!*s && (c & 0xe0) == 0xc0) { /* 2 byte char */
        *w = (c & 0x1f) << 6; *s = 1;
    }
    else
    if (!*s && (c & 0xf0) == 0xe0) { /* 3 byte char */
        *w = (c & 0x0f) << 12; *s = 2;
    }
    else
    if (!*s && (c & 0xf8) == 0xf0) { /* 4 byte char */
        *w = (c & 0x07) << 18; *s = 3;
    }
    else
    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;
        }

        (*s)--;
    }
    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:

 https://api.telegram.org/botIDENTIFICADOR_DEL_BOT/sendMessage?chat_id=@CANAL&text=Hola%20caraculo

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 'https://api.telegram.org/botBLA_BLA_BLA/sendMessage?chat_id=@nutriguia&parse_mode=HTML&disable_web_page_preview=false&text=<b>Title</b>%0AThis is a <i>test</i>. <a href="https://triptico.com/img/mp.png">·</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á.