Using VimWiki as a distributed, encrypted lab notebook for programming

So what’s the most important coding tool for a software engineer in the long-term? There’s a pretty decent argument that it’s a lab notebook. I’ve kept one for years and it’s one of the more useful tools I have, but I found that my notebook, apart from not quite measuring up to how a lab notebook should be kept, wasn’t quite as useful as it could be because when you have five or six notebooks covering a bit over a decade’s worth of notes and no search function, then how do you use them daily?

I’ve been looking around for a while for a software version of a paper notebook without much success (this isn’t ludditism – we just don’t have very much that can match what paper and pen can do for this kind of task). I’ve used a simple text editor on a cron job for a few years as a way to track what I do during the day – every 30 minutes, up pops a vim window with a ready-inserted line listing the date and time, I scribble in what I’ve done since the last time the window popped up and I save and quit – it takes about 15 seconds and it gives me a file listing everything I’ve done at the end of the day/week/month/year which is handy for things like preparing reports, doing job reviews, that sort of thing. It’s simplicity itself to set up, just call a simple script using a simpler cronjob entry:

[cc escaped=”true” lang=”bash”]

#!/bin/bash

# Cron script for 30-min activity journal
#——————————————-

export DISPLAY=:0
echo -n -e “\n[” `date` “] :\n” >> ~/.journal
/usr/bin/gvim -U ~/.journal.gvimrc -geometry 100×40+512+400 + ~/.journal

[/cc]

[cc escaped=”true” lang=”bash”]

# m h dom mon dow command
0,30 8-20 * * mon-fri ~/.journal.sh

[/cc]

Simple and effective… but not a lab notebook. It does help test a few criteria for what I need that notebook program to do to fit in with my workflow though:

  • It has to be *fast* and familiar to use. ’nuff said, really. 
  • It has to be distributed. I work on lots of machines; I need it to be available on them, or else I’d have to have it on something like a netbook that I’d carry everywhere and that’s just not practical for me (besides, what if I forgot it or it got stolen?)
  • It has to be encrypted. Everything I work on is NDA’d at one level or another; and design/debugging notes would definitely be too sensitive to leave lying around in plaintext format. With a physical notebook, I keep it locked away; but this is supposed to be better than that option…

Colleagues have used various products for this over the years – mindmapping software; emacs in one mode or another; and various other software. But none of those really appealed. Mediawiki did seem to be as good a fit as I could find, but something that depends on an entire LAMP stack to run is hardly lightweight; and while I could host it somewhere public, that’s not really very secure (I’d spend more time making sure the full LAMP stack was up to date and mediawiki too than I want to). Besides, I’d rather this be console-accessible if possible (yes, some of us are still happier that way 🙂 ).

I’ve been using vim since around 1993 or so; at this point it’s wired into my fingers. So when I saw vimwiki, it seemed ideal. For those who’ve not encountered vimwiki before, it creates a directory, and then every file in that directory becomes part of a rudimentary text-based wiki (which it can turn into a set of HTML pages so it can handle images and so forth, but you can also navigate it from within vim). It also has a diary function which works in a sub-directory of the wiki directory.

It doesn’t have any support for encryption or distribution. But that’s quite solvable.

The encryption is easy enough – you could use the blowfish encryption in (post-v7.3) vim but that proved a bit awkward as you had to reenter the password every time you navigated down a link (and I don’t always have post-7.3 vim available). This password entering every minute or so broke up my workflow, so no thanks. My netbook and work laptops all have whole-disk-encryption, so I just left the vimwiki directory as normal on those laptops, and on the machines where I don’t have whole-disk-encryption, I use eCryptFS to create an encrypted directory and put the wiki under that. Very simple indeed, but quite effective. Now even theft of the physical hard drive isn’t a major concern.

The distribution was equally simple; you could use any DVCS, but I’m fond of mercurial, so I decided to use that. You have to tweak the vimwiki script ( .vim/ftplugin/vimwiki.vim ) to call it:

[cc escaped=”true” lang=”vim”]

augroup vimwiki
au! BufRead /home/mdennehy/vimwiki/index.wiki  !hg pull;hg update
au! BufWritePost /home/mdennehy/vimwiki/*  !hg add <afile>;hg commit -m ” “;hg push
augroup END

[/cc]

But that’s a simple tweak at best. And you want to have ssh setup with keys for the easiest workflow, but you have that already, right? 😀

Then just modify the crontab script:

[cc escaped=”true” lang=”bash”]

#!/bin/bash
# Cron script for 30-min activity journal
#——————————————-

export DISPLAY=:0
/usr/bin/gvim -U ~/.journal.gvimrc -geometry 100×40+512+400 -c “call vimwiki#diary#make_note(v:count1)” + -c “r !date +’\%n= \%H\%Mh =\%n'”[/cc]

And add an Awesome keybinding and menu entry:

[cc escaped=”true” lang=”lua”]

vimwiki_cmd = “/usr/bin/gvim -U /home/mdennehy/vimwiki/.gvimrc -c ‘call vimwiki#base#goto_index(v:count1)'”

mymainmenu = awful.menu({ items = { { “awesome”, myawesomemenu, beautiful.awesome_icon },


{ “VimWiki”,vimwiki_cmd }
}
})

awful.key({ modkey, }, “w”, function () awful.util.spawn(vimwiki_cmd) end),

[/cc]

And now whenever I hit <Mod4>-w from within Awesome, it pops up a gVim window open at the root of the wiki; every 30 minutes it pops up a gVim window in today’s diary page with the time inserted automatically for a log entry; and whenever I hit save or switch buffers, it syncs the files up to a central server’s encrypted area.

Distributed, encrypted, fast and useful. I’ve been using it in the job for the last few months now and it does almost everything I need. I do still keep around the paper notebook though – no matter how good the program, we still don’t have anything that can do everything paper can do (doodle, take cornell format notes, sketch diagrams easily for later capture, that sort of thing), but vimwiki’s search function alone is making it the day-to-day workhorse and it’s making my life a lot easier. Notes on development, patent ideas, job review reports, sysadmin notes, notes on papers I’m writing, and a daily log, all in one easy-to-use package. Damn useful tool.

Baselines

So the Coding Horror thread on boards.ie’s Development forum threw up an interesting post:

Originally Posted by COYW

[..] I was told not to comment my code, as it was a “waste of time”. Apparently, that is classic Agile!

A good code doesn’t need comments; a bad code doesn’t need comments either – it needs to be fixed! 

The responses were about as you’d expect, but in the course of answering, I made the following suggestion:

you still have your code from college exercises, right? No? You don’t keep a private archive of old code you wrote? So… how do you tell if you’re improving or getting worse without a baseline?

So I figured I’d take a peek again (last time I looked must have been before Calum was born) and compare it to what I’m writing today.

The really low-level stuff came off pretty well. Some code for programming a GAL chip for 3D2 (where you build a thin client from a 68008 chip and a handful of other chips and what feels like a mile of hand-wrapped wire):

[cc escaped=”true” lang=”asm” lines=”20″]
‘ GAL1 PLDASM
‘ Address Decoding

‘ 3D3 68008 Project

‘ Group 5 :
‘ Mark Dennehy 93369425
‘ Ellen Delaney

‘ This is the address decoding code for the board. It uses one
‘ GAL exclusively and the smallest selectable memory block is
‘ 1024 bytes. The CLK pin is attached to /AS via an inverter.

‘ INPUTS :
‘ A10..A19
‘ BOOT
‘ /AS
‘ OUTPUTS:
‘ EPROM1
‘ RAMROM1
‘ RAM1
‘ RAM2
‘ RAM3
‘ ACIA0
‘ ACIA1
‘ LCD
‘ SYSTEMBYTE
‘ TIMER

device 22v10

‘ Input pin definitions
as = 1
a19 = 2
a18 = 3
a17 = 4
a16 = 5
a15 = 6
a14 = 7
a13 = 8
a12 = 9
a11 = 10
a10 = 11
boot = 13

‘ Power & ground pin definitions
gnd = 12
vcc = 24

‘ Output pin definitions
/eprom1 = 14
/ramrom1 = 15
/ram1 = 16
/ram2 = 17
/acia0 = 18
/acia1 = 19
/lcd = 20
/sysbyte = 21
/timer = 22
/ram3 = 23

macro io a19*a18*a17*a16;
macro rom /a19*/a18*/a17*/a16;

start

‘ EPROM selection : $00000 -> $01FFF and boot
/eprom1 /= /as*/boot*&rom*/a15*/a14*/a13;

‘ RAM_ROM selection : $00000 -> $01FFF and not-boot
‘ $20000 -> $21FFF and boot
/ramrom1 /= /as*boot*&rom*/a15*/a14*/a13 + /as*/boot*/a19*/a18*a17*/a16*/a15*/a14*/a13;

‘ RAM 1 selection : $10000 -> $107FF
/ram1 /= /as*/a19*/a18*/a17*a16*/a15*/a14*/a13*/a12*/a11;

‘ RAM 2 selection : $10800 -> $10FFF
/ram2 /= /as*/a19*/a18*/a17*a16*/a15*/a14*/a13*/a12*a11;

‘ RAM 3 selection : $11000 -> $12FFF
/ram3 /= /as*/a19*/a18*/a17*a16*/a15*/a14*/a13*a12 + /a19*/a18*/a17*a16*/a15*/a14*a13*/a12;

‘ ACIA 0 selection : $F0000
/acia0 /= /as*&io*/a15*/a14*/a13*/a12*/a11*/a10;

‘ ACIA 1 selection : $F0400
/acia1 /= /as*&io*/a15*/a14*/a13*/a12*/a11*a10;

‘ LCD selection : $FE000
/lcd /= /as*&io*a15*a14*a13*/a12*/a11*/a10;

‘ SYSTEM_BYTE selection : $FF000
/sysbyte /= /as*&io*a15*a14*a13*a12*/a11*/a10;

‘ TIMER selection : $F1000
/timer /= /as*&io*/a15*/a14*/a13*a12*/a11*/a10;

end

[/cc]
And the assembler was about readable in most cases:

[cc escaped=”true” lang=”asm” lines=”20″]
;————————————————————
;
; Demonstration PICRAT program.
;
;————————————————————
; REVISION HISTORY :
;
; 13/10/97 First draft, preliminary modularisation
; of code.
;
;————————————————————

ERRORLEVEL 0
PROCESSOR PIC16C74A
LIST b=4
__CONFIG _BODEN_OFF & _CP_OFF & _PWRTE_OFF & _WDT_OFF & _XT_OSC
TITLE “Demonstration PICRAT program”
SUBTITLE “Version 1.00”

include

;————————————————————
; Context Saving registers

CONTEXT UDATA 0x20

int_w RES 1
int_status RES 1
int_pclath RES 1
int_fsr RES 1

CONTEXT2 UDATA 0xa0

int_w2 RES 1 ;Dummy Register

;————————————————————
; Variables used in Main Loop
Main UDATA

tmpChar RES 1

;————————————————————
;
; NAME : RESET_VECTOR
;
; FUNCTION : Executes reset interrupt service routine
;
;————————————————————

RESET_VECTOR CODE 0000
RESET_VECTOR
GLOBAL RESET_VECTOR

PAGESEL reset_isr
goto reset_isr

;——————–ROUTINE SPECIFICATION——————-
;
; NAME : INTERRUPT_VECTOR
;
; FUNCTION : Contect saving, correct ISR selection
;
; NOTES : Saves W, STATUS, PCLATH as per ex.14-1
; in datasheet
;
;————————————————————
; REVISION HISTORY :
;
;————————————————————

INTERRUPT_VECTOR CODE 0004
INTERRUPT_VECTOR
GLOBAL INTERRUPT_VECTOR

EXTERN USART_Tx_isr
EXTERN USART_Rx_isr

;INTERRUPT_VECTOR
;
; Save the W,STATUS,PCLATH and FSR registers,

movwf int_w
swapf STATUS,W
clrf STATUS
movwf int_status
movf PCLATH,W
movwf int_pclath
movf FSR,W
movwf int_fsr

; Check to see what caused the interrupt,
; Byte received ?

BANKSEL PIR1
PAGESEL USART_Rx_isr
btfsc PIR1,RCIF

; Jump to USART Rx ISR

call USART_Rx_isr

; Ready to transmit byte ?

BANKSEL PIR1
PAGESEL USART_Tx_isr
btfsc PIR1,TXIF

; Jump to USART Tx ISR

call USART_Tx_isr

; Unknown interrupt ?
; Jump to exception handler

; PAGESEL Exception
; call Exception

; Restore registers and return from interrupt.

clrf STATUS
movf int_fsr,W
movwf FSR
movf int_pclath,W
movwf PCLATH
swapf int_status,W
movwf STATUS
swapf int_w,F
swapf int_w,W

retfie

;——————–ROUTINE SPECIFICATION——————-
;
; NAME : Exception
;
; FUNCTION : Called when an unhandled interrupt
; condition occours.
;
; NOTES :
;
;————————————————————
; REVISION HISTORY :
;
;————————————————————

;EXCEPTION
; Endless loop

Exception CODE
Exception

goto Exception

;——————–ROUTINE SPECIFICATION——————-
;
; NAME : reset_isr
;
; FUNCTION : Reset Interrupt service routine
; Determines correct action to perform
; on startup.
;
; NOTES :
;
;————————————————————
; REVISION HISTORY :
;
;————————————————————

reset_isr CODE
reset_isr
GLOBAL reset_isr

EXTERN MemoryTest
EXTERN USART_init
EXTERN USART_puts
EXTERN USART_putc
EXTERN USART_hi_msg_tmp
EXTERN USART_lo_msg_tmp
EXTERN Startup_screen
; EXTERN LCD_Initialise
; EXTERN LCD_PutChar
EXTERN USART_getc

PAGESEL MemoryTest
call MemoryTest

PAGESEL USART_init
call USART_init

; PAGESEL LCD_Initialise
; call LCD_Initialise

PAGESEL USART_putc
movlw A’.’
call USART_putc
movlw A’.’
call USART_putc
movlw A’.’
call USART_putc
movlw A’\r’
call USART_putc
movlw A’\n’
call USART_putc

; PAGESEL LCD_PutChar
; movlw A’T’
; call LCD_PutChar
; movlw A’e’
; call LCD_PutChar
; movlw A’s’
; call LCD_PutChar
; movlw A’t’
; call LCD_PutChar

; Enable perihiperal interrupts

BANKSEL INTCON
bsf INTCON,PEIE

; Enable all interrupts
bsf INTCON,GIE

; Print out startup message
PAGESEL USART_puts
movlw high Startup_screen
movwf USART_hi_msg_tmp
movlw low Startup_screen
movwf USART_lo_msg_tmp
call USART_puts

bcf OPTION_REG,7
BANKSEL PORTB
clrf PORTB
BANKSEL TRISB
movlw 0x00
movwf TRISB

BANKSEL PORTD
clrf PORTD
BANKSEL TRISD
movlw 0x7F
movwf TRISD

BANKSEL PORTE
clrf PORTE
BANKSEL TRISE
movlw 0x07
movwf TRISE

PAGESEL MainLoop
call MainLoop

;——————–ROUTINE SPECIFICATION——————-
;
; NAME : MainLoop
;
; FUNCTION : Main Control Interpreter
;
; NOTES : A Finite State Machine
;
;————————————————————
; REVISION HISTORY :
; 9/1/98 First Draft
;————————————————————

MainLoop CODE
MainLoop
GLOBAL MainLoop
EXTERN USART_getc
EXTERN USART_putc
EXTERN AnalogRoot
ExTERN DigitalRoot
EXTERN CounterRoot
EXTERN PWMRoot
EXTERN MotorControlRoot
EXTERN TimerRoot

PAGESEL USART_getc
call USART_getc
BANKSEL tmpChar
movwf tmpChar
PAGESEL MainLoop
movf tmpChar,W
xorlw A’.’
btfss STATUS,Z
goto MainLoop

;————————————————————

ServiceSelect
PAGESEL USART_putc
movlw ‘-‘
call USART_putc
movlw ‘-‘
call USART_putc
movlw ‘\r’
call USART_putc
movlw ‘\n’
call USART_putc

PAGESEL USART_getc
call USART_getc
movwf tmpChar

PAGESEL AnalogRoot
movf tmpChar,W
xorlw A’a’
btfsc STATUS,Z
goto AnalogRoot

PAGESEL DigitalRoot
movf tmpChar,W
xorlw A’d’
btfsc STATUS,Z
goto DigitalRoot

PAGESEL DigitalRoot
movf tmpChar,W
xorlw A’c’
btfsc STATUS,Z
goto CounterRoot

PAGESEL PWMRoot
movf tmpChar,W
xorlw A’p’
btfsc STATUS,Z
goto PWMRoot

PAGESEL MotorControlRoot
movf tmpChar,W
xorlw A’m’
btfsc STATUS,Z
goto MotorControlRoot

PAGESEL TimerRoot
movf tmpChar,W
xorlw A’t’
btfsc STATUS,Z
goto TimerRoot

;————————————————————
; Error

PAGESEL USART_putc
movlw ‘*’
call USART_putc

goto MainLoop

END
[/cc]

Okay, so that’s not quite as good as it could be, but the libraries were better. What about the Java code?

[cc escaped=”true” lang=”java” lines=”20″]
/////////////////////////////////////////////////////////////////////
//
// TACAN – TeleAutonomous Control And Navigation
//
// Mark Dennehy, 93369425
// S.S. C.Eng.
// Final Year Project 1996/7
//
//////////////////////////////////////////////////////////////////////
//
// PolarHistogram.java
// implements the polar histogram
// —————–
// $Date: 1997/04/03 21:49:54 $
// $Revision: 2.0 $
// $State: Stable $
//
//////////////////////////////////////////////////////////////////////

package Tacan.RLC;

import Tacan.util.LogFile;
import Tacan.util.MathUtil;
import java.util.*;
import java.io.*;
import java.awt.event.*;

/**
* The Polar Histogram of the Certainty value grid. This is effectively a
* polar graph of obstacle density.
*
*@author
*@version
*@see Tacan.RLC.CVGrid
*@see java.util.Observer
*@see java.awt.event.ActionListener
**/
class PolarHistogram extends Observable implements Observer, ActionListener
{
private final static double A = 22;
private final static double B = 1;
private final static int maxFreeSectorSize = 18;

private int tmpPH[];
private RLC rlc_;
private int no_of_segments_;
private LogFile log_;
private LogFile data_;
private Vector segment_terms_[];

/**
* The current Polar Histogram values
**/
protected int PH_[];

/**
* The Local Autonomy Control graph values
**/
protected double LAC_[];

/**
* The current maximum value in the Polar Histogram (for normalisation)
**/
protected int PH_max = 0;

/**
* The current maximum value in the Local Autonomy Control graph (for normalisation)
*@see
**/
protected double LAC_max = 0.0;

/**
* The threshold value for deciding what path is free and what is not
**/
protected int PH_threshold = 100;

/**
* The maximum network lag permitted before full local autonomy is granted (in seconds)
**/
public final static double maxNetLag = 10;

/**
* Constructor
*
*@param rlc The Robot Local controller instance associated with this graph
**/
protected PolarHistogram(RLC rlc)
{
rlc_ = rlc;
PH_max = 0;
segment_terms_ = new Vector[rlc.robot_config.PH_RES];
no_of_segments_ = rlc.robot_config.PH_RES;
PH_ = new int[no_of_segments_];
tmpPH = new int[no_of_segments_];
LAC_ = new double[no_of_segments_];
log_ = new LogFile(“Polar.log”);
data_ = new LogFile(“Polar.dat”);

for (int i = 0; i PH_max) ? sum : PH_max;
}
}

public synchronized void LACupdate(int t,int desired_sector)
{
double b = (t LAC_max) ? LAC_[i] : LAC_max;
}
}

public int clearPath(int bearing)
{
int res = (int)360.0/no_of_segments_;
int desired_sector = (int)(bearing/res);
int b;
int l_centre =1;
int l_width = 1;
int r_centre =1;
int r_width = 1;

LACupdate(3,desired_sector);

if ((PH_[desired_sector] * LAC_[desired_sector]) < PH_threshold) return bearing; else { //Scan Left for(int a = 1; a < (no_of_segments_/2) ; a++) //Start of first free sector if ((PH_[(a+desired_sector)%no_of_segments_] * LAC_[(a+desired_sector)%no_of_segments_]) < PH_threshold) { //For up to maximum sector width for (l_width = 1; l_width <= maxFreeSectorSize; l_width++) //Look for end of free Sector if ((PH_[(a+l_width+desired_sector)%no_of_segments_] * LAC_[(a+l_width+desired_sector)%no_of_segments_]) > PH_threshold)
{
//Set centre of sector
l_centre = a+(int)(l_width/2);
break;
}
break;
}

//Scan Right
for(int a = no_of_segments_-1; a > (no_of_segments_/2) ; a–)
//Start of first free sector
if ((PH_[(a+desired_sector)%no_of_segments_] * LAC_[(a+desired_sector)%no_of_segments_]) < PH_threshold) { //For up to maximum sector width for (r_width = 1; r_width <= maxFreeSectorSize; r_width++) //Look for end of free Sector if ((PH_[a-r_width] * LAC_[a-r_width]) > PH_threshold)
{
//Set centre of sector
r_centre = a-(int)(r_width/2);
break;
}
break;
}

//Choose left or right, weighing size of sector with deflection
b = ((l_width/l_centre) > (r_width/(no_of_segments_ – r_centre))) ? l_centre : r_centre ;
b += desired_sector;
b %= no_of_segments_;
b *= res;

return b;
}
}

public String toString()
{
String s = “[ “;
for (int i = 0;iOh dear. That’s very much a curate’s egg. Some parts are okay, but some… well, I wouldn’t give them an okay in a code review session today. Still, I suppose that’s a good thing – remind yourself that you were just not as hot as a teenage coder as you thought you were, and that you’ve gotten better in the interim.

What about the C++ though?

[cc escaped=”true” lang=”cpp” lines=”20″]
/****************************************************************
* *
* TCD Robocup Project 1996/7 *
* Intelligent Agents Group *
* (Artifical Intelligence Group) *
* *
****************************************************************
RCS Block :

$Author: mdennehy $
$Date: 1996/09/07 15:57:18 $
$RCSfile: main.cc,v $
$Revision: 1.6 $
****************************************************************
$Log: main.cc,v $
// Revision 1.6 1996/09/07 15:57:18 mdennehy
// Final version by mdennehy.
// Now knows how to locate itself on the field and
// can determine the error in this measurement.
//
// Revision 1.5 1996/09/04 14:03:22 mdennehy
// Visual and Audio parsing working.
// Minor bug : if more than 5/6 agents connected, Bus errors/segmentation faufollow
//
// Revision 1.4 1996/08/30 17:31:38 mdennehy
// First Working Version
//
// Revision 1.3 1996/08/26 15:10:49 mdennehy
// *** empty log message ***
//
// Revision 1.2 1996/08/24 16:25:08 mdennehy
// Added Threads
//
// Revision 1.1 1996/08/22 14:34:30 mdennehy
// Initial revision
//
****************************************************************/

/***** RCS Program Information *****/
char RCS_revision[]=”$Revision: 1.6 $”;
char RCS_state[]=”$State: Exp $”;

/***** Header Files *****/

#include #include
#include #include
#include
#include
#include
#include

#include
#include
#include
#include
#include
#include
#include
#include

#include “udpif.h”
#include “posdata.h”
#include “communications.h”
#include “dmalloc.h”

/***** Main Comms Socket *****/
UDPSocket comm;

#ifdef DEBUG
/***** Debugging Log file streams *****/
extern ofstream commlog;
extern ofstream datalog;
extern ofstream intsyslog;
#endif

/***** Function prototypes *****/
void usage();
void SignalHandler(int signal, siginfo_t *SignalInfo, void *ContextInfo);

/***** MAIN() *****/
int main(int argc, char **argv)
{
#ifdef DEBUG
print_statistics();
init_debugging_logfiles();
system_check();
intsyslog << "int main(int argc,char **argv)" << endl; struct sigaction h; // Install Signal handlers h.sa_flags = SA_SIGINFO; h.sa_sigaction = SignalHandler; sigaction(SIGBUS,&h,NULL); sigaction(SIGSEGV,&h,NULL); #endif int option_char ; char *serverhost = "localhost"; int serverport = 6000; //Get command-line options GetOpt opt(argc,argv,"?h:p:") ; while (option_char = opt(), option_char != EOF) switch (option_char) { case 'h': #ifdef DEBUG intsyslog << "Hostname CLI option : "; intsyslog << opt.optarg << endl; #endif serverhost = opt.optarg; break; case 'p': #ifdef DEBUG intsyslog << "Port CLI option : "; intsyslog << opt.optarg << endl; #endif serverport = atoi(opt.optarg); break; case '?': #ifdef DEBUG intsyslog << "Help CLI option selected" << endl; #endif usage(); exit(-1); }; //Setup socket connection to server #ifdef DEBUG intsyslog << "Attempting to open socket connection" << endl; intsyslog << "Hostname : " << serverhost << endl; intsyslog << " Port : " << serverport << endl; #endif comm.init_connection(serverhost,serverport); //Player Initialisation sequence #ifdef DEBUG intsyslog << "Sending Team Init" << endl; #endif leda_string s("(init TCD)"); leda_string side,playmode; int unum,err; comm << s; comm >> s;

// parse returned initialisation message from server
err = sscanf(s,”(init %[lr] %i %[^)]”,side.cstring(),&unum,playmode.cstring());

#ifdef DEBUG
if (err == 3)
{
intsyslog << "Side : " << side << endl; intsyslog << "Uniform Number : " << unum << endl; intsyslog << "Play Mode : " << playmode << endl; } else { intsyslog << "Initialisation response parse failure" << endl; intsyslog << "Errno : " << err << endl; exit (-1); } #endif //Start main threads thread_t main_thread_id; thread_t communications; //thread_t planning; //thread_t execution; thr_create(NULL,0,(void *)Communications,NULL,NULL,&communications); //thr_create(); //thr_create(); main_thread_id = thr_self(); #ifdef DEBUG intsyslog << "Main thread ID : " << main_thread_id << endl; intsyslog << "Communications thread ID : " << communications << endl; //intsyslog << "Planner thread ID : " << planning << endl; //intsyslog << "Executer thread ID : " << execution << endl; #endif wait(2); comm.send_message("(say -A1T1.PA.0000.0000.PB.1234.4321.PO2.5678.0123)",comm.S); wait(3); comm.send_message("(move 12 12)",comm.S); wait(5); while (1) // Just moves the agent about a bit to demonstrate the self-location system // Is an infinite loop so the rest of the code isn't much use here for now { comm.send_message("(turn 20)",comm.S); wait(2); comm.send_message("(dash 50)",comm.S); wait(3); } while (thr_join(communications,NULL,NULL) == 0); // Wait for other threads to finish #ifdef DEBUG intsyslog << "Shutting Down" << endl; commlog.close(); datalog.close(); intsyslog.close(); #endif } void usage() // Prints out correct command-line format via STDERR { #ifdef DEBUG intsyslog << "void usage()" << endl; #endif cerr << "Usage:\n"; cerr << " % agent [options] TEAMNAME\n"; cerr << " options: \n"; cerr << " -h HOSTNAME \n"; cerr << " -p PORTNUMBER\n"; cerr << endl; } #ifdef DEBUG void SignalHandler(int signal, siginfo_t *SignalInfo, void *ContextInfo) // this is UNIX-specific code to handle a signal sent to the agent to signal a system-level error, // such as a bus error or a Segmentation fault. These are the only two such signals currently specially // processed { dmalloc_log_heap_map(); dmalloc_log_stats(); dmalloc_log_unfreed(); perror ("Last Error "); if (SignalInfo->si_code <= 0) { intsyslog << "User Generated Signal" << endl; intsyslog << "User ID : " << SignalInfo->si_uid << endl; intsyslog << "Process ID : " << SignalInfo->si_pid << endl; } switch(signal) { case SIGBUS: { intsyslog << "********** ERROR : Bus Error **********" << endl; cerr << "********** ERROR : Bus Error **********" << endl; if (SignalInfo->si_code == SI_NOINFO)
{
intsyslog << "No Debugging information given by system" << endl; exit(-1); } switch (SignalInfo->si_code)
{
case BUS_ADRALN:
{
intsyslog << "Errno : " << SignalInfo->si_errno << endl; intsyslog << "Invalid Address Alignment" << endl; intsyslog << "Address : " ; intsyslog << (unsigned long)SignalInfo->si_addr;
intsyslog << endl; break; } case BUS_ADRERR: { intsyslog << "Errno : " << SignalInfo->si_errno << endl; intsyslog << "NonExistant physical address" << endl; intsyslog << "Address : "; intsyslog << (unsigned long)SignalInfo->si_addr;
intsyslog << endl; break; } case BUS_OBJERR: { intsyslog << "Errno : " << SignalInfo->si_errno << endl; intsyslog << "Object Specific Hardware Error" << endl; intsyslog << "Address : " ; intsyslog << (unsigned long)SignalInfo->si_addr;
intsyslog << endl; break; } } } break; case SIGSEGV: { intsyslog << "********** ERROR : Segmentation Fault **********" << endl; cerr << "********** ERROR : Segmentation Fault **********" << endl; if (SignalInfo->si_code == SI_NOINFO)
{
intsyslog << "No Debugging information given by system" << endl; exit(-1); } else switch(SignalInfo->si_code)
{
case SEGV_MAPERR:
{
intsyslog << "Errno : " << SignalInfo->si_errno << endl; intsyslog << "Address not mapped to object" << endl; intsyslog << "Address : "; intsyslog << (unsigned long)SignalInfo->si_addr;
intsyslog << endl; break; } case SEGV_ACCERR: { intsyslog << "Errno : " << SignalInfo->si_errno << endl; intsyslog << "Invalid Permissions for mapped object" << endl; intsyslog << "Address : "; intsyslog << (unsigned long)SignalInfo->si_addr;
intsyslog << endl; break; } } } break; } exit(-1); } #endif [/cc]

Erm. Yikes. I did get better though 😀

What about you? Do you check back over long periods to see how your standard of code is actually doing, rather than through the hazy pink-spectacled fog of old memories?

Stochastic Geometry is Stephen Fry proof thanks to caching by WP Super Cache

%d bloggers like this: