Factlet for the day …

Since the start of March my spamassassin filter has caught over 14,500 instances of spam.

Firefox as Emacs

Interesting Firefox extension (although it’s more of a complete mod): Conkeror. This adds a complete new chrome that makes Firefox look and feel like emacs. There’s even Vi bindings too if you feel that way.

New Usyd vacancies RSS feed

The university recently moved to a new positions-vacant system so I’ve rewritten the RSS generator for the feeds. Rather than generate different feeds based on position type they’re all in one this time around:

http://people.vislab.usyd.edu.au/~ssmith/rss/Usyd-Vacancies.xml

Bencoding and Erlang

Included in the Bittorrent protocol is a simple text-based data-serialisation format referred to as bencoding. This is useful outside the context of Bittorrent for producing quick line-based network protocols (the original version of the AG replacement project used it for a simplified form of RPC).

My language to learn this year is Erlang, and as a back-to-basics exercise I spent a bit of time this weekend implementing the decoder part of a bencoding module. To resulting code turns out to be surprisingly terse, due in part to Erlang’s declarative nature: matching, guards and recursion can perform much of the functionality of more verbose loops, ifs and cases:

-module(bencode).

-export([bdecode/1]).

-import(string, [substr/2, substr/3, to_integer/1, chr/2]).

bdecode([Char | _Rest] = Str) when Char >= $0, Char =< $9 ->
    ColIdx = chr(Str, $:),
    IntStr = substr(Str, 1, ColIdx-1),
    {Len, _} = to_integer(IntStr),
    Result = substr(Str, ColIdx+1, Len),
    Rest = substr(Str, ColIdx+Len+1),
    {{string, Result}, Rest};

bdecode([Char | Rest]) when Char == $i ->
    End = chr(Rest, $e),
    {Result, _} = to_integer(substr(Rest, 1, End-1)),
    {{int, Result}, substr(Rest, End+1)};

bdecode([Char | Rest]) when Char == $l ->
    {List, Rem} = dolist(Rest),
    {{list, List}, Rem};

bdecode([Char | Rest]) when Char == $d ->
    {Dict, Rem} = dodict(Rest),
    {{dict, Dict}, Rem}.

dolist(Str) ->
    dolist(Str, []).

dolist([Char | Rest], List) when Char == $e ->
    {List, Rest};

dolist(Str, List) ->
    {Result, Rest} = bdecode(Str),
    dolist(Rest, lists:append(List, [Result])).

dodict(Str) ->
    dodict(Str, dict:new()).

dodict([Char | Rest], Dict) when Char == $e ->
    {Dict, Rest};

dodict(Str, Dict) ->
    {{string, Key}, Rest} = bdecode(Str),
    {Val, Rest2} = bdecode(Rest),
    dodict(Rest2, dict:store(Key, Val, Dict)).
  1. Archives

  2. Categories

  3. Twitter

    • Just got pictures of the earthquake damage from my sister in Kaiapoi. Real "the ground opened up" stuff. 28 minutes ago
    • Ooo, the beta of Angry Birds is out on Android. 17 hours ago
    • Released a new version of my Android Internode widget; fixes the problem with Internode's new SSL cert. 22 hours ago
    • @wangjammer5: Cool, here's something to get you started: http://is.gd/eT33b :) 1 day ago
    • So, if iTune Ping is Apple's social network will the perpetual Apple tweet circle-jerk move there now? 1 day ago
  4. RSS Google Reader Shared Items