The blog

Blog Technology

The other day, I was asked on IRC what did this website run on.

Let's go from the bottom to the top. First, the hardware:

An Intel Atom (D945GCLF2) with just a power cord and an ethernet cable comming out of it, sitting on my home desk. A single 300GB disk, no raid, no backups, no SAI, the best setup ever. 2GB RAM. Since the fan is noisy, I have it set to never spin below 75°C.

Now, for the software:

  • Arch Linux using the LTS kernel. I update it when I feel like it.
  • Nginx, serving plain text files, and running a reverse proxy for:

Everything is started using systemd service files. The lisp server runs on sbcl, wrapped by rlwrap, inside in a tmux session, and is responsible for (please forgive me for letting an implementation detail inside an URL).

The cherrypy server runs as is (service Type=simple), and used to serve this blog directly. Right now I use it to preview things before generating the actual static files.

At the time of writing, the script I use to generate the static content looks like this:

#!/usr/bin/env python3
import os
import web
out_dir = "static"

root = web.Root()
blog =
redalien = root.redalien
tutorial = root.tutorial
pages = [
    ('index.html', root.index()),
    ('blog/index.html', blog.index()),
    ('blog/atom.xml', blog.atom()),
    ('redalien/index.html', redalien.index()),
    ('redalien/manual/index.html', redalien.manual()),
    #('tutorial/index.html', tutorial.index()),
    ('tutorial/fixing/index.html', tutorial.fixing()),
    ('bluespider/index.html', root.bluespider()),
    ('random/index.html', root.random()),
    ('dtops/index.html', root.dtops()),
    ] + [('blog/entry/{}'.format(i), blog.entry(i)) for i in range(1, 10)]

for path, page in pages:
    fullpath = os.path.join(out_dir, path)
    os.makedirs(os.path.dirname(fullpath), exist_ok=True)
    with open(fullpath, 'w') as f:

(gotta automate that range(1, 10))

As for the pages and entries themselves, I write them in either markdown or HTML, and they are rendered automatically inside a mako template. Mako! Mako! Everything runs on mako and these AVALANCHE terrorists won't stop me. All the code is in a nice <200 SLOC file.

I guess I could use something like pelican instead, but this system is already built, it works, and it's flexible.

- cosarara

Today I Solved/Broke ROM-Hacking

GBA Pokémon game ROM-Hacking is messy. It's done using tools like map editors, hex editors or image inserters directly on the ROM file, and the only safety measure are plain file backups.

Normal game or software development, on the other hand, usually keeps all the source data in separate, easily editable files, then provides some means of building the final product automatically.

Wouldn't it be great if ROM Hacking could be done like normal software development? We'd only need some kind of build system, with a linker that could set all the pointers where they belong... Then we'd press a button and all our data would be written on top of a stripped down ROM file, producing the final game.

But we have that! The script compiler does exactly what we need. You give it your code with a bunch of @-prefixed labels, it looks for free space and it links it all together. What we don't have, though, is non-script things in script source form. To start with, we'd need:

  • Map headers and data
  • Graphics
  • Trainer data
  • Pokemon data

Graphics can probably be compressed by grit. I can make Blue Spider output source files. Trainer data, pokémon data, etc. are similar structures - some work, but possible. The only thing left is some way to nicely edit tileset block data, which my map editor doesn't do. Music and ASM modifications are done by the means of binaries already. So, let's give it a go...

I added a script to Blue Spider named It takes the map bank list, the list of maps for every bank, and most of the data for every map (including events, but not the tile map itself yet), and outputs it as pks scripts in a directory named map_dump when called as:

$ ./ FR.gba

It also writes a file include_list.pks which has an #include line for every other file, so that running:

$ asc-cli c FR.gba map_dump/include_list.pks

Builds the whole thing (and, if nothing has been changed on the source files, changes nothing on the ROM). But wait! I hear you say, that's full of raw addresses, nobody could work with that! And that's true, which is why takes a --label option, which makes it spit out nice @labels instead of hex addresses:

$ ./ --label FR.gba

And so, map_dump/3/map_0.pks AKA Pallet Town will look more or less like this:

'map header
#org @map_3_0_map_header
#word @map_3_0_map_data_header 'map_data_ptr
#word @map_3_0_events_header 'event_data_ptr
#word @map_3_0_level_scripts 'level_script_ptr
#word 0x835276c 'connections_ptr
#hword 0x12c 'song_index
#hword 0x4e 'map_ptr_index
#byte 0x58 'label_index
#byte 0x0 'is_a_cave
#byte 0x2 'weather
#byte 0x1 'map_type
#hword 0x601 'null
#byte 0x0 'show_label
#byte 0x0 'battle_type

'map data header
#org @map_3_0_map_data_header
#word 0x18 'w
#word 0x14 'h
#word 0x82dd0f8 'border_ptr
#word 0x82dd100 'tilemap_ptr
#word @map_3_0_t1_header 'global_tileset_ptr
#word @map_3_0_t2_header 'local_tileset_ptr
#byte 0x2 'border_w
#byte 0x2 'border_h

't1 header
#org @map_3_0_t1_header
#byte 0x1 'is_compressed
#byte 0x0 'tileset_type
#hword 0x0 'null
#word 0x8ea1d68 'tileset_image_ptr
#word 0x8ea1b68 'palettes_ptr
#word 0x829f6c8 'block_data_ptr
[rest omitted]

Now, there's a couple things which must be done before this can be compiled. First, a suitable #dyn line must be added at the top of include_list.pks. And second, since Blue Spider doesn't know when to stop finding maps at the end of the last bank, all the bad maps must be removed from the definition of said bank. In the case of Fire Red, that means removing all maps but number 0 at map_dump/bank_42.pks.

And so, this is it for today. There is quite a bit of work ahead, but the future doesn't look bad.

- cosarara

Random Thoughts, part I

Go listen to 'go' by Delilah, remixed by Paralloyd & Too greezey
- cosarara

Fixing broken ROM Hacks the dirty way

People make ROM Hacks using buggy tools, and then one day they find their game freezing on a pokemon evolution, or battle, or whatever. Since the ROM file is just a big mess and they have no idea how to fix it, they either start over or give up. I sometimes fix other people's ROM hacks.

My usual method was going close to the point of failure (freeze, reboot, whatever), making vba-sdl-h start generating a trace, activating that failure and then looking at the 200+ MB trace file using split(1) and less(1) (basic gnu tools).

## Yesterday, this method was proving more ineficcient than usual, so Yesterday, this method proved more ineficcient than usual, so I came up with another one. I created 2 directories, a and b. In a I put a clean Pokemon ruby ROM and the broken hack, named r.gba and d.gba. In b I created the following script:

cp ../a/* .
dd if=r.gba of=d.gba skip=$OFFSET seek=$OFFSET count=$SIZE bs=1 conv=notrunc

What this does is basically to copy SIZE bytes from r.gba to d.gba starting from byte OFFSET, using dd(1). I would run it as (for example):

$ OFFSET=$((0x416000)) SIZE=$((0x1000)) ./

I had a savestate to run just before the crash, so I just had to change OFFSET and SIZE, run vba-sdl-h, press F1, and see if it worked.

Starting with 0x600000 bytes from the ROM start fixed the bug, as expected, but that would be replacing too many things from the hack with stuff from the original game. So I narrowed it down by halving and tweaking those values until I ended up with a that 0x1000 byte copy shown above - which fixes evolution in the hack and (hopefully) doesn't break anything important in doing so.

The result of all this is here: What would have been, after some more work, Pokemon Dark Blue's beta 2.

- cosarara

VNC over 2 SSH servers

Today I *needed* a graphical connection to my home desktop, from ~100 km away. That means VNC. At home I have 2 computers: a server and said desktop. The server has a port redirected from the router for ssh, and from the server I can access the desktop (ssh as well). Therefore, I need some kind of double tunnel to get from the laptop to the home machine. The final solution looked like this:

home $ x0vncserver -display :0 -passwordfile ~/.vnc/passwd
laptop $ ssh -L 5900:(Laptop local IP):5900 -N (Home IP)
laptop $ vncviewer DotWhenNoCursor=1 :0

All the ssh connections I did here used RSA keys. VNC uses a password, but it's not facing the public internet and the connection is encrypted (it isn't from the home server to the desktop, but I assume there are no rogues inside my house), so it's not actually needed.

Neither of those IP addresses have to be actual addresses here. In my case, the first one was the hostname of my desktop as written in the server's /etc/hosts. The second one was the name of a .ssh/config entry which uses a CNAME domain name, which points to a no-ip domain name (yay!).

That DotWhenNoCursor=1 thing was added because I had no mouse cursor without it (I'm not sure what to blame here). You can put that in ~/.vnc/default.tigervnc too.

Once the connection is open, you can press F8 to open the viewer's menu and use the fullscreen option or close the program, among other options.

- cosarara

Bye bye, database

This blog doesn't use a database any more. Instead, entries are saved in plain text files, and it's all put together using Mako templates.

Now I can have the blog contents under version control, I edit the entries the same way I edit the rest of the website (emacs and ssh), and the code has decreased in size quite a bit. It's also one less service running on the server.

This was my first application using a database, and I learnt a lot, but there is no point in keeping it any more.

- cosarara


Here it is, lads, a manual for Red Alien. I might or might not write a tutorial as well.

While doing it I realized that writing HTML using emacs with web-mode and evil is not bad at all. Also, I'll see if I can integrate that syntax highlighting I used in the document into the GUI's QScintilla editor.

- cosarara

Beep! Someone said my name

As an IRC client, I run weechat on my server, inside a tmux session, and connect to that using SSH. I had disabled the beep plugin, since I was begining to go crazy every time someone mentioned me. Still, I needed some way to get notified when someone mentioned or /query'ed me. Enter notify-send and twmnd. notify-send is a standard tool to send notifications to the notification server in a linux desktop. twmnd is a nice notification server that blends well with i3 and is not annoying. The first obvious step is to start running twmnd, then.

Now, how do you tell weechat to send your desktop a notify-send over ssh every time someone says your name? You write a plugin. Here's mine: pastebin. Actually, as you'll see, I didn't write all of that. I took a script named from the the weechat website, and modified it to my needs. If you want to use it, you'll have to replace "altair" on line 104 with whatever hostname or IP address your desktop has.

- cosarara


I'm so upset. jk.

I think the original UPS patcher had a command line interface already... Anyway, this was both easy and fun to do.

- cosarara

Here we go again

The server stopped working, like a week or two ago. The hard drives were too hot and died. Some info was lost, like everything on the database, but I saved the website code (yay!).
- cosarara