Articles in the hacks category

Zeller's Congruence

Here's one for your junkcode if you haven't already come across it (maybe I'm the only one). Zeller's Congruence (or rule, or algorithm, or ...) allows you to find the day of the week for any given date. Most people would probably use mktime(), but it recently came up on a glibc list where a guy was doing millions of calls; it can get pretty slow.

If you're keen, there is an explanation of how to derive (one version of) it. The most trouble free version I could find looks like

/* Zeller's Congruence to determine day of week */
int get_dayofweek(int date)
{

 int d = date % 100;
 int m = (date % 10000) / 100;
 int y = date / 10000;

 if (m < 3)
 {
     m = m + 12 ;
     y = y - 1;
 }

 return ((2 + d + (13*m-2)/5 + y + y/4 - y/100 + y/400) % 7);

}

int main(void)
{

    /* my birthday */
    int bday = get_dayofweek(19800110);
    char *d;

    switch(bday)
    {
    case 0:
        d = "Sunday";
        break;
    case 1:
        d = "Monday";
        break;
    case 2:
        d = "Tuesday";
        break;
    case 3:
        d = "Wednesday";
        break;
    case 4:
        d = "Thursday";
        break;
    case 5:
        d = "Friday";
        break;
    case 6:
        d = "Saturday";
        break;
    }

    printf("%s\n", d);
}

So it looks like I was born on a Thursday. Cool!

Super Co-Contributions

The Australian government has a scheme where they will contribute up to $1.50 for every dollar you save in superannunation.

The maximum amount they will match for your income goes down for 5c after every $1 over $28,000, and is capped at $1500. The official calculator annoyingly doesn't tell you the minimum amount you should invest to get the maximum return (the brochure shows it with less granularity). It's hardly rocket science but the below Python program should do that for you.

#figure out super co-contributions
import sys

def best_contribution(income):
    greatest_cocontribution = 1500 - ((income - 28000) * 0.05)
    print "$%7d | %5d | %5d " % (income,
                                 greatest_cocontribution / 1.5,
                                 greatest_cocontribution)

def header():
    print " %7s | %5s | %5s " % ("income", "you", "govt")
    print "---------+-------+-------"


if __name__ == '__main__':
    try:
        if sys.argv[1] == 'all':
            incomes = range(28000, 59000, 1000)
            header()
            for i in incomes:
                best_contribution(int(i))
        else:
            income = int(sys.argv[1])
            if (income < 28000 or income > 58000):
                print "income out of range"
                sys.exit(0)
            header()
            best_contribution(income)
    except:
        print "super.py [income|all]"

As an idea, here is the output for $1000 increments

  income |   you |  govt
---------+-------+-------
$  28000 |  1000 |  1500
$  29000 |   966 |  1450
$  30000 |   933 |  1400
$  31000 |   900 |  1350
$  32000 |   866 |  1300
$  33000 |   833 |  1250
$  34000 |   800 |  1200
$  35000 |   766 |  1150
$  36000 |   733 |  1100
$  37000 |   700 |  1050
$  38000 |   666 |  1000
$  39000 |   633 |   950
$  40000 |   600 |   900
$  41000 |   566 |   850
$  42000 |   533 |   800
$  43000 |   500 |   750
$  44000 |   466 |   700
$  45000 |   433 |   650
$  46000 |   400 |   600
$  47000 |   366 |   550
$  48000 |   333 |   500
$  49000 |   300 |   450
$  50000 |   266 |   400
$  51000 |   233 |   350
$  52000 |   200 |   300
$  53000 |   166 |   250
$  54000 |   133 |   200
$  55000 |   100 |   150
$  56000 |    66 |   100
$  57000 |    33 |    50
$  58000 |     0 |     0

bouncing via mutt

I seem to get messages like Unable to deliver message to the following recipients, because the message was forwarded more than the maximum allowed times when I try to bounce messages via mutt. This is because by the time an email to ianw@ieee.org gets to my inbox it has bounced around a bunch of places like the IEEE and UNSW.

What I would really like is a filter-and-bounce function in mutt to filter out the headers. This involves minimal work from me (as opposed to, say, resending the message). mutt doesn't have this so I have hacked my own.

Firstly, in .muttrc add

set pipe_decode=no
macro index "B" "python2.3 /home/bin/bounce.py"

The pipe decode is important, since otherwise mime messages will get scrambled on the bounce and attachments won't come, etc.

Then just do the bounce with this python script

SENDMAIL = "/usr/sbin/sendmail"
FROMMAIL = "ianw@ieee.org"
SMTPHOST = mail.internode.on.net

import email, sys, smtplib, os

m = email.message_from_file(sys.stdin)
del m['received']

if len(sys.argv) == 2 :
        email = sys.argv[1]
        print "Bouncing to %s" % email
else:
        newstdin = os.open("/dev/tty", os.O_RDONLY)
        os.dup2(newstdin, 0)

        print "Email to send to :",
        sys.stdout.flush()
        email = sys.stdin.readline()

server = smtplib.SMTP(SMTPHOST)
server.sendmail(FROMMAIL, email, m.as_string())
server.quit()

The only tricky bit is having to re-open stdin because mutt sets up a pipe between it and the pipe-message process. You can add your own X-Resent-From type headers if you want.

Death to trailing whitespace

Whitespace at the end of lines is farily annoying, and wastes space. It also generally annoys other developers if you send patches that introduce white space.

Luckily, emacs can show you with big red blocks where you've left whitespace behind. I think everyone (who hasn't already :) should add something like

(mapc (lambda (hook)
      (add-hook hook (lambda ()
          (setq show-trailing-whitespace t))))
      '(text-mode-hook
      c-mode-hook
      emacs-lisp-mode-hook
      java-mode-hook
      python-mode-hook
      shell-script-mode-hook))

to their .emacs file right now.

Finding the parent function in emacs

Have you ever been in the middle of a really long function and wondered just exactly what it was called? Angus Lees came up with

(defun print-defun-name ()
  (interactive)
  (save-excursion
    (beginning-of-defun)
    (beginning-of-line 0)
    (let ((start (point))
          string)
      (end-of-line 2)
      (setq string (buffer-substring start (point)))
      (message "%s" (replace-regexp-in-string "[ \t\n]" " " string)))))

I came up with a slightly different version that works a little better for C code

(defun c-print-defun-name ()
  (interactive)
  (save-excursion
    (c-beginning-of-defun)
    (end-of-line 0)
    (let ((end (point)))
      (c-beginning-of-statement)
      (let ((start (point)))
        (setq string (buffer-substring start end))
        (message "%s" (replace-regexp-in-string "[ \t\n]+" " " string))))))

Add it to your .emacs and if you really want, bind it to a key.

Python gallery generator

It's so hard to find a good gallery generator these days :) All I wanted was something really simple that could show a few photos in a slide-show style interface. Should use static HTML and leave the important configuration upto a style sheet.

All the ones on the market seemed to be a bit of an overkill, so I wrote my own. Of course, a sample is worth a thousand words.

Decoding binary objects

bindecode is a little app I wrote to decode a bunch of bits into something more human friendly. Currently it supports most important IA64 registers and a few other things, though if someone wants to send me patches for other architectures that is cool.

A screenshot should suffice

ianw@lime:~/programs/junkcode/code/bindecode$ python ./bindecode.py

Bitmap Decoder
--------------
Tab shows bitmaps to complete, quit or Ctrl-D to exit

Input Bitmap Type >
386_pte           ia64_itir         ia64_psr          ia64_rr           to_32bit_binary   unix_permissions
ia64_ifa          ia64_pkr          ia64_pte          ia64_tlb_gr       to_64bit_binary

Input Bitmap Type > to_32bit_binary

to_32bit_binary value > 0xff
Decoded output for a Convert to a 32 bit binary
Bits | 0000 0000 0000 0000 0000 0000 1111 1111

to_32bit_binary value > o123
Decoded output for a Convert to a 32 bit binary
Bits | 0000 0000 0000 0000 0000 0000 0101 0011

to_32bit_binary value > b101010101010
Decoded output for a Convert to a 32 bit binary
Bits | 0000 0000 0000 0000 0000 1010 1010 1010

to_32bit_binary value > q

Input Bitmap Type > ia64_pte

ia64_pte value > 0x0210000005be01e1

Decoded output for a IA64 PTE Entry
           Present | True
          Reserved | 0
 Memory Attributes | 0x0
     Page Accessed | True
        Page Dirty | True
   Privilege Level | 0x3
     Access Rights | . . .
               PFN | 0x5be0
Exception Deferral | True
           Ignored | 0x10

ia64_pte value > q

Input Bitmap Type > q

The real thing is a bit more colourful with some ANSI colours.

xchat notifier plugin

I previously mentioned that there must be a better way to make xchat pop up a dialog box, and of course there is, the plugin!

It's so easy; though finding the text command to match is a bit obscure. Here it is

__module_name__ = "gnome-notifier-plugin"
__module_version__ = "1.0"
__module_description__ = "notify of channel events via gnome-notify"

import xchat
import os

def channel_message(word, word_eol, userdata):

    err = os.system("/usr/bin/gnome-notify " +
                    "\'<font color=\"red\">New channel message</font></br>" +
                    "<b>"+word[0]+"</b><br>"+word[1]+"\'")
    if (err != 0):
        print("Failed to launch gnome-notify!")
    return xchat.EAT_NONE

xchat.hook_print("Channel Msg Hilight", channel_message)

you just put that in your .xchat2 directory and next thing you know you should have screenshots like that below!

gnome-notifier xchat plugin