Friday, 30 January 2009

been a genchal week (+132h)

Kinda boring, but also very good practice for teaching myself to shut up, stop complaining and just do what needs doing. If that means writing unit tests and documentation, go write unit tests and documentation. Get it right. Sigh :-)

Time bank holding steady (was +131h last week). The model for Balance that I would like to experiment with is
  • try to meet your daily quota every day
  • do minimal darcs stuff every day
  • if you have exceeded your weekly quota (even by 15 minutes), you can take the rest of Friday afternoon off to go do more substantial darcs stuff once you've met your daily quota
  • if you have exceeded your weekly quota by a lot (say 2 hours), don't worry about making Friday's quota, just go do darcs stuff when you feel like it
So basically, darcs being the Friday afternoon treat for a week's work.

Friday, 23 January 2009

genchal (+21d)

More genchal scripting. My Perl abilities are still fairly limited, so I gave up and rewrote the darn thing in Haskell. I find it rather difficult to do fancy things, like write filters where you pass some XML in, do some stuff to it and spit XML out (things that are too difficult to do in XSLT). I can use the XML::Rules library to do some simple stuff, but when things get hairy (say I want to recursively process my output), I get stuck. It's just easier for me to think about the recursion in Haskell (plus I'm slightly more comfortable with the powerful combinator-based libraries like HaXml).

timebank approved

Also, my holiday-adjusted timebank metaphor has been "approved", so I feel at least somewhat redeemed for my recent darcs-related sins. For what it's worth, I'm now at -97h (old style), or +131h aka +21d (adjusted model). Since we're blessing the adjusted model as the right way to conceptualise time, I'll only be reporting numbers with that model.


In other words, from now on I'm only going to pay attention the blue line in the chart above. This means that instead of telling myself "OMG, I owe the university 97 hours of catch-up work" (the red line), I can simply say to myself "I have 21 days of holiday that I can still spend", which is a lot less depressing.

So now we need to think in terms of balance. From 2008-W30/2008-W46 I have been doing way too much darcs work and way too little University work. From 2008-W47/2009-W04 I have been doing a lot of University work (claw claw claw) at the expense of darcs. Now that I have given myself a sense of redemption (very guilt-driven creature, me), I need to find a way to achieve balance. To make sure that darcs gets the care it needs, while still making sure I am doing what is needed for work-work.

No more claw claw. It's time to find Balance.

Wednesday, 21 January 2009

another genchal day

I now have a reusable module for doing web-based, latin square, human intrinsic evaluations. It's mostly just refactoring previous work, cutting into pieces and learning how to do object oriented programming in Perl (it's easy: objects are just packages).

Working on some baselines next.

I have been reading The Pragmatic Programmer lately. Very easy to understand. Good advice... has clarified some of my inner debates, like what to do about errors and exceptions. Do not repeat yourself. Dead programs don't lie.

new template!

I've upgraded the template on this blog (because le star Djame was asking why you don't see the comments anymore). I've given the text a hundred more pixels (so that code samples don't overflow as much), and adopted the new hierarchical archive widget. Unfortunately, I did not a find a "most recent comments" widget, and would appreciate it if somebody could point me to one. Sorry, sorry for flooding your RSS reader unnecessarily (unless maybe Blogger was clever enough not to update the feed since this was only a template change), but it's for the greater good.

Sunday, 18 January 2009

mostly genchal

I've been spending the whole week working on genchal stuff (cleaning up last year's work: short cuts make long delays... JSON was quite helpful for this... if there is a next year, hopefully reuse and extension will be easier).

chartparser and packing


Just snuck in a few minutes of chartparser work. I've figured out my CKY problem. I'm not sure I can explain this right. So the point of the chartparser library is to make it ridiculously easy to write parsers, right? Not necessarily fast parsers, just parsers that are correct. It's a prototyping library. So to do this, I try to supply as many of the basic features in a generic, hopefully orthogonal, format. Part of this is for me to figure out what the heart of the chart parser is. Okay, so I've got a bit that removes items of an agenda (any data structure), combines them with the chart (any data structure), but is this logic part of the core chart parser?
  • if an agenda item already exists in the chart, remove it
  • if a chart item already exists, do not add it to the chart
It seems like a simple question, but then what happens when you add a generic backpointer mechanism? I like the generic backpointer mechanism because it means you can generate a derivation tree for any parsing algorithm. But then what makes an item unique? Should it just be the "essence" of the item that we compare, or should we compare the full item, including backpointer?

Let's see how this interacts: given the sentence "somebody hacks something somewhere", I ought to be getting 2 derivations. My "minimal" chart data structure was only paying attention to the essence of a chart item (in the CKY case, left, right and symbol). As a result, it was filtering out one of the two ways for generating the VP (hacks something somewhere). Now, at this time, I didn't realise that was the cause of the error, so what I did was to disable the uniqueness criterion... and by doing that, I got 4 derivations and not two. Until I discovered the bug, I was flipping back and forth between too many derivations and too few.

So now I have the two derivations I want, but I have a sneaking suspicion that I'm not really allowed to call the resulting algorithm CKY because now I have two VP chart items, when I should really have one. This leads me to wonder if I need to revise my backpointer mechanism so that the generic chart parser can merge two items which belong to an equivalence class (i.e. that have the same essence)... But this makes me a little nervous because I want to preserve a sort of orthogonality. I don't want to force people to use packing, if for whatever their reasons, their algorithms do not support it.

But I dunno. Maybe this generic packing mechanism is harmless. And people could also rig things so that the essence of a chart item is the chart item itself (define essence as id)... which would mean no packing.

Hmm... well, thanks, rubber duckie. I think I've just talked myself into a solution.

I need to be more patient, though. I'm being a bit too eager to release this library and get the Haskell NLP community started. Slowly and surely.

Tuesday, 13 January 2009

genchal half-day

Been doing genchal stuff all week.

Seem to have come down with a cold, so I'm heading home early to de-headache myself. I suppose it's mild enough that I can just hack my way through it (as I have been this morning), but eh.

haskell nlp sneak preview

The Haskell NLP project on the {code,projects}.haskell.org has been created! So far, we have two darcs repositories (chartparser and hs-giza-pp), a mailing list and a trac instance, but no static webpage, nor wiki content nor users.

The goal of Haskell-NLP is to make Haskell a more attractive language for natural language processing (research and teaching) by putting together tools and libraries for general use.

The mailing list and wiki will be used to build up an eventually community of Haskell-using NLP folks. The directory http://code.haskell.org/nlp will serve as an incubator for any small projects or libraries that are too small to stand on their own. The issue tracker will for proposing new haskell-nlp projects, and also to serve as a tracker for any projects hosted under the incubator.

genchal JSON

The Pragmatic Programmer book reminds us that "short cuts lead to long delays"... something I'm experiencing now adapting some work from last year's genchal stuff to this year. So instead of carrying on business as usual (prolonging the pain and ugliness), I'm going to be experimenting with JSON as an intermediary format between various bits of my evaluation toolchain. No more making stuff up quick and dirty... let's aim for something slightly more extensible.

Friday, 9 January 2009

genchal day (-113h, +115h or 19d)

parser

Still plugging away at the parser. Fixed some bugs in the debugger (hehe). My dead-simple CKY is getting 4 derivations for "somebody hacks something somewhere", which seems to be because it's generating two identical S 0 4 nodes... not sure if that's normal and why this is happening. Each S chart item expands to two derivations (somebody hacks (something somewhere) vs (somebody ((hacks something) somewhere)), which I am expecting.

genchal

Playing with festival! It has a REPL! Found and reported a small redirection bug in one of its scripts.

Thursday, 8 January 2009

full day

Managed to get in early today. I think it helped.

profiling

I'm getting a little bit more comfortable with the GHC profiler, actually managing to use it somewhat successfully to track down a stack overflow in my code (also learned a little bit more about laziness, thunks, tail recursion on the Haskell wiki).

The 6 columns of numbers you see can be a bit overwhelming at first, but there's really nothing to it... just think of it as pairs: (no, entries) (raw time, raw mem) (total time, total mem). The manual calls it "inherited" which can be a bit confusing, because what it really means is the time including your kids... backwards inheritence.

Haskell NLP releases in the pipeline

I have received authorisation to release my Haskell stuff. So I hope to have three packages out soonish:
  • hs-gizapp - a Haskell wrapper around GIZA++ (now released)
  • chartparser - generic chart parsing library with debugger and parse tree generation
  • scfgtools - decoder, parser and rule extractor (no stats yet, sorry... also, parser still broken)
I have also requested a project called "nlp" on code.haskell.org as an umbrella for the Haskell NLP community, which I intend to start at some point if nobody else does... because dangit, Haskell is useful and stuff.

packing and debugging

I've extended NLP.ChartParser with (a) some notion of packing and (b) some notion of unpacking :-)... well rather I've made it so that every chart item must have a list of backpointers. The library provides a generic parse tree extractor. Here is the fragment of a derivation tree using dotted CKY:
[complete] VP -> V NP ⦁ (1,3)
|
+- [complete] VP -> V ⦁ NP (1,2)
| |
| +- [axiom] VP -> ⦁ V NP (1,1)
| |
| `- [scan] V -> hacks ⦁ (1,2)
| |
| `- [axiom] V -> ⦁ hacks (1,1)
|
`- [scan] NP -> something ⦁ (2,3)
|
`- [axiom] NP -> ⦁ something (2,2)
The idea is that if you want to produce a derived tree, maybe having the derivation tree will be useful (I'm using derivation tree here not necessarily in the TAG sense, but to mean the relationship between chart items via their backpointers).

Heh... one trick I want to add to the debugger is a command that prints out the derivation tree for a given chart item. Should be easy. Just need to assign an id to each chart item and let the user type in something like "tree 43"

I have to be careful not to get too deep into extend NLP.ChartParser (patches welcome! especially now I think the debugger is usable enough for people to get the idea and start extending it). I'm just trying to make it useful enough for me to do my SCFG stuff, and also something that I can release. I do hope that I manage to pull this off... and that it actually turns out to be useful for somebody.

Wednesday, 7 January 2009

practical tips for confused erics

Some of this is stuff I only figured out this year.

Yes, it is highly prescriptive and rigid. That's the whole point. Bordelique people like me need a system with hard (but ridiculously easy to follow) rules. It may not work for you. People like me need to think about these things deliberately. The goal is to have something that's reproducible and that you can use without further thought. The moment you have to think about where to put something, your system is broken.

Space

  • Five things to have within reach
    1. inbox - to be emptied daily
    2. meetings tray - very few things: meetings book, folder for upcoming meeting(s)
    3. thematic folders - scientific GTD project support, e.g. SCFGs, SMT, SDRT, content representation, etc
    4. scrap paper - hoard this stuff, I go through reams of scrap paper (learned this trick from Carlos and Claire)
    5. big stack of empty folders - for creating thematic folders
  • When no longer likely to need an article, file in cabinet: alphabetical order by first author's surname
  • Date each piece of scrap paper on the top-right corner as you are using it; a little label may be useful too (the point is to simplify the questions "wtf is this? can I chuck it?")
  • Have a log book dedicated to meetings - date each meeting
  • If you want to store something long-term, consider putting it on a computer (e.g. re-do back-on-envelope sketches in inkscape) and ditching the scrap paper

Time

  • Use brain-dead time to do stupid-but-useful things
  • Only do stupid things (e.g. re-arranging office, writing blog entries) when brain-dead (rule I am currently violating... then again, when am I not brain-dead?)

Stuff

  • folders
    1. long term storage - simple manila if possible, hanging if you really have to
    2. thematic folders - simple manila
    3. meetings folder - pochettes, basically fancy folders
    4. projects folder - pochettes
    5. super-important (immigration papers) - plastic pochettes
  • music - keep a Speechless playlist for things you can listen to whilst reading

Tuesday, 6 January 2009

pretty brain-dead

I've gone stupid(er) today.

earley-ish algorithm

I'm pretty sure my algorithm from yesterday is wrong (plus it has lots of typos, below is a slightly more typo-free version, plus a little extra work with indices to try to minimise the wrong-ness).


The parser can be wrong for two reasons: it accepts too few things and/or it accepts too many. I think the latter is true. I suspect you can fool my algorithm into accepting pairs of strings where one side of the grammar accepts the left string, and one side of the grammar accepts the right string, but the pair of strings should not be accepted together. There are some choices I need to make here:
  • pore over the WASP and Joshua source code - look for references to algorithm used
  • ask on the Joshua mailing list
  • ask a local grown-up - this may be a great option since there are some local grown-ups who are sure to be able to give me good advice, but I'm... err... feeling shy
  • decide that I don't care if my parser is too liberal (and just be sure not to advertise this as a working SCFG parser, but something works enough for me).

fancier debugger

Following the theme of doing stupid but useful things, I seem to be re-inventing the GenI debugger (because I'm trying to figure some stuff out about SCFG parsing). Rather, I've taken my SCFG-specific debugger from a couple of days ago, and moved some code around so that it's generic to anything that uses NLP.ChartParser. (By the way, If you want to teach a parsing course, I think my debugger could be useful for you (although at this stage, you're probably better off with NLTK).

The new debugger is text mode for now. You type in commands to it.

example step

--- chart 5 --- (9 items)
ChartItem {symbol = "VP", beforeDot1 = fromList ["x2"], afterDot1 = [], indices1 = (1,2), beforeDot2 = fromList [], afterDot2 = ["y2"], mIndices2 = Just (0,0)}
ChartItem {symbol = "S", beforeDot1 = fromList ["NP","VP"], afterDot1 = [], indices1 = (0,2), beforeDot2 = fromList [], afterDot2 = ["VP","NP"], mIndices2 = Just (0,0)}
ChartItem {symbol = "S", beforeDot1 = fromList ["NP","VP"], afterDot1 = [], indices1 = (0,2), beforeDot2 = fromList [], afterDot2 = ["VP","NP"], mIndices2 = Nothing}
...

--- agenda 5 --- (1 items)
ChartItem {symbol = "VP", beforeDot1 = fromList ["x2"], afterDot1 = [], indices1 = (1,2), beforeDot2 = fromList ["y2"], afterDot2 = [], mIndices2 = Just (0,1)}


Hit enter for next step or type 'help'

the command set so far

help
Display commands
----------------
help : print this help
agenda : show the full agenda
chart : show the full chart
filter P T value : P = {agenda,chart}, T={symbol}

Navigation commands
-------------------
last : jump to the very last step
quit : (self explanatory)
next INT : (self explanatory)
start over : (self explanatory)

Hit enter for next step or type 'help'

trying out a filter

filter chart symbol S
--- requested filter --- (4 items)
ChartItem {symbol = "S", beforeDot1 = fromList ["NP","VP"], afterDot1 = [], indices1 = (0,2), beforeDot2 = fromList [], afterDot2 = ["VP","NP"], mIndices2 = Just (0,0)}
ChartItem {symbol = "S", beforeDot1 = fromList ["NP","VP"], afterDot1 = [], indices1 = (0,2), beforeDot2 = fromList [], afterDot2 = ["VP","NP"], mIndices2 = Nothing}
ChartItem {symbol = "S", beforeDot1 = fromList ["NP"], afterDot1 = ["VP"], indices1 = (0,1), beforeDot2 = fromList [], afterDot2 = ["VP","NP"], mIndices2 = Nothing}
ChartItem {symbol = "S", beforeDot1 = fromList [], afterDot1 = ["NP","VP"], indices1 = (0,0), beforeDot2 = fromList [], afterDot2 = ["VP","NP"], mIndices2 = Nothing}
Hit enter for next step or type 'help'
I could go crazy with the filter and write a fancy parser for things so that you can say things like "show me the chart items with symbol S and whose left indices are between, etc etc"... which I may end up deciding I need to do.

code more?

Maybe the key for me is to understand that I understand things through the process of coding. So if I want to do or to wrap my head around anything, I should try to frame it in terms of "what code can I write?"... I dunno if that's going to send me on a lot of wild goose chases, though, the kind of thing where I think I'm productive because I'm doing lots of stuff, but in reality, not actually accomplishing anything.

Monday, 5 January 2009

scfg parser, lazy evaluation

wanted: scfg parser

Ok, parsers exist (there's Joshua and WASP to choose from, both in Java), but what I want is a parser recipe, i.e. an general algorithm for parsing SCFGs (none of this normal form crap) as a deductive proof system. And yes, on further thought, of course my proposed algorithm from yesterday was wrong (what else would it be).

my second attempt

Here's my second attempt at making a straightforward adaptation of the Earley algorithm from CFGs. It's probably wrong, this being something that's best left to the experts, but I guess it was fun to try. It seems to be working on some examples I have, for example, of a backwards grammar ("one two three" vs "trois deux un"). Note that dash means 'unset' and question mark means 'don't care':



It doesn't exactly match my implementation (which is why it was useful to specify the thing twice, once in Haskell and once in LaTeX). I've highlighted the bits where I think something special happens, i.e. not just business as usual.

why lazy evaluation rocks

It helps you write simpler, more orthogonal code, i.e. keeping unrelated bits of logic separate from each other.

Here's the (text) debugger for my chart parser:
debugger :: Scfg -> String -> String -> IO ()
debugger gram s1 s2 =
forM_ steps $ \s -> do
putStr . unlines . map show . chart $ s
putStrLn "Hit Ctrl-C or press enter for next step"
getLine
where
steps = iterate (chartStep config) initSt
(config, initSt) = initStuff gram (s1,s2)


Get it? The key is the iterate function. steps is an infinite list of chart steps... it's what you get if you keep applying the chartStep function to the previous element in the list (getting a new chart step). Once you have an infinite list (lazily generate), you can generate bits and pieces of it as you go, for example, on each "press enter to continue".

And here are the interactions:
Hit Ctrl-C or press enter for next step


Followed by:
ChartItem {symbol = "S", beforeDot = fromList [], afterDot = ["NP","VP"], bSide = False, left = 0, right = 0}
Hit Ctrl-C or press enter for next step


And then...
ChartItem {symbol = "NP", beforeDot = fromList [], afterDot = ["Det","N"], bSide = False, left = 0, right = 0}
ChartItem {symbol = "S", beforeDot = fromList [], afterDot = ["NP","VP"], bSide = False, left = 0, right = 0}
Hit Ctrl-C or press enter for next step


Etc...

Sunday, 4 January 2009

three minor ah-hahs

chart parser

Rather than asking each chart parser to supply separate rules which make a chart item interact with an agenda item, (and then a separate set of rules to extend agenda items by themselves, e.g. Earley predict or scan rules), we should just ask them to supply rules which take a chart and an agenda item, and then select whatever items it wants from the chart. This also makes it possible to generalise CKY to non-binary rules (which yes is very inefficient if you don't have dots... but useful for reducing code footprint)

scfg parsing

I need not only to have an SCFG decoder (from source language string to target language string), but a bona fide parser (parses string pairs). I guess you can implement one with a modest extension to Earley's algorithm. Just add an extra boolean field to the chart item denoting which side of the SCFG rule you are processing. The idea is that once you complete the rule on the left side, you push the dot over to the beginning of the target side (and flip your bside bit). Only when you have completed both sides do you consider the rule complete. So it's exactly Earley's algorithm except (a) your scan rules need to distinguish between scanning the source side and scanning the target side (b) you need to introduce a "hop" rule which flips the bside bit when you have half-completed. Surely somebody else has this written up somewhere. Or maybe my proposed algorithm is dead-wrong for some reason.

applicative functors ftw?

I've been wishing for a while that I had a better way to do something like concatMap (\x -> map (f x) ys) xs (i.e. I want crossProductMap).

Then I realised that this was the same thing as
do x <- xs
y <- ys
return $ f x y

Then I realised that this was the same as liftM2 f xs ys

... which is the same as f `liftM` xs `ap` ys (I guess)

... which is the same as f <$> xs <*> ys

I'm guessing about the second-to-last one (I've only glanced at uses of ap without understanding them fully.). Anyway, I still don't know what all the applicative functors fuss is all about, but at least now I have a small inkling about how it could be relevant to my life as a programmer (so I'll see how far I go with the f <$> xs <*> ys version. The second-to-last version (with ap, which I figured out after the last version) uses monads, not applicative functors, so I don't really see what the big deal is except for maybe a nicer operator. I'm sure I'll work it out sometime in the far future. Yay, abstractions! in any case.

Saturday, 3 January 2009

SCFG decoder

Once I had a toy implementation of dotted CKY, making a toy implementation of Earley was easy (just add a predict rule, and change the axioms to be a bit more conservative). And once I had a toy implementation of Earley, implementing an SCFG decoder was... well not quite so easy, but doable.

*NLP.ScfgEarley> putStrLn $ go toyGram "the boy hacks some ugly code"
S(NP(Det(the) N(boy)) VP(V(hacks) NP(Det(some) Adj(ugly) N(code))))
S(NP(Det(le) N(garcon)) VP(V(hacke) NP(Det(du) N(code) Adj(moche))))


I'm doing things in the most naive possible way, which is to apply CFG Earley to the source rhs of the SCFG to obtain a derivation and then re-run the derivation on the other side. It's the re-running bit that gets a bit tricky for me, because the target rhs isn't in the same order as the source rhs (that's the whole point of an SCFG after all) and it may have different set of terminal symbols.

Here's the core of my ugly-ass solution:

type ForestPair a = ([Tree a],[Tree a])

nodesFor :: ForestPair String -> String -> [ForestPair String]
nodesFor (gs, ns) s =
do let matches = filter (match s) ns
-- no matches means terminal symbol, which is fine
g <- if null matches then return (Node s []) else matches
return (g:gs, delete g ns)
match x1 (Node x2 _) = x1 == x2


I'm probably not going to succeed in explaining this, but that's ok. The tree unpacking algorithm does recursion twice, once to obtain the list of kids, and once to obtain the list of siblings. (Keep in mind that the chart only stores a single CFG derivation). The whole idea is that you recursively obtain the list of kids for both the source and target side (rhs1 and rhs2). The list of kids for the target side will be in the incorrect order, that of the source side, but it will contain the correct subtrees. How do you re-arrange these trees in the target order? By selecting a rule from the SCFG whose source rhs corresponds to the right hand side of the current chart item. Rather, you use the nodesFor function defined above to traverse the target rhs (rhs2) of the rule. At each non-terminal symbol you select the appropriate sub-tree from the list of incorrectly ordered nodes. At each terminal symbol, you generate a leaf.

helper :: String -> [String] -> Int -> Int -> [ForestPair String]
helper c1 cs1 l r =
do -- boring details elided...
(kids1,kids2u) <- case tiKids1 of
[] -> return ([],[])
(kc:kcs) -> helper kc kcs l rti
-- boring details elided...
rule <- if null tiKids1
then return $ ScfgRule c1 [] [] -- terminal only
else filter (\x -> scfgRhs1 x == tiKids1) rulez
kids2 <- (reverse . fst) `fmap` foldM nodesFor ([],kids2u) rKids2
-- boring details elided...
(sibs1,sibs2) <- case cs1 of
[] -> return ([],[])
(c1b:cs1b) -> helper c1b cs1b rti r
let node1 = Node c1 kids1
node2 = Node c1 kids2
return (node1:sibs1, node2:sibs2)


Sorry if that didn't make any sense. It probably won't make much sense to me next month, and the complicatedness of it probably means that I haven't deeply understood things yet.

Thankfully, I now know about useful tricks like (a) using the list monad to handle non-determinism Prolog-style and (b) using fmap to promote functions into a monad (which avoids a lot of boilterplate let x = ). Tricks like this make the code a bit cleaner, with fewer moving parts. (I like to use the idea of moving parts, because lines of code is not always relevant, a moving part is an ill-defined "conceptual" line of code, some "thing" happening... there must be an official word for this).

An interesting thing I notice about my lack of Haskell-fu is that whenever I have trouble understanding how to do something, I will tend to use a lot of explicit recursion. I need to grasp the moving parts as a sort of handrail. Once I've got things down as a solution, or have had some time to get a bit of recul wrt the problem, I may eventually realise that actually these 12 lines of code (or whatever) can be replaced by a single higher order function and a little bit of business logic. But to begin with, at least, I'll code like a newbie.

Friday, 2 January 2009

timebank update (-123h, +102h or +17d)

So I've done a little bit of work over the holidays. Not as much as I would have liked, not even a full week, alas. I'm still far enough behind that the brute calculation of hours spent is a useful approximation of work done. Overall, in the past month and a half, I have put in around 60 hours of overtime desperately trying to claw my out of the hole.

Now my time bank balance is at -123 hours.


Note that this number is worse and more depressing than my previous number. The reason is that I have decided to do away with the notion of "retroactive holidays" which I find rather opaque and arbitrary. In place of the retroactive holidays, I'm introducing the notion of the (holiday-)adjusted timebank, in which I treat every day of my holiday budget as 6 hours of quota being potentially forgiven. So while my actual time bank is at -123 hours, my adjusted time bank is at the less suicide-inducing +102 hours. If I'm a good boy, this means I can afford to take a fortnight off to go see family, and maybe a couple days to do darcs stuff.

Summing up:
  • a 37 hour work week (arbitrary number, but useful)
  • at 20% time this puts me at 30 hours a week, or a 6 hour per week day production quota
  • I treat each holiday as 6 hours of quota... fungible time, i.e. every 6 hours overtime I work == 1 day of leave, or 1 day of leave == 6 hours of sin forgiven
  • school year (and hence infusion of adjusted-time bank hours) starts on 01 Sep
  • reliable timesheet data only available from 2008-11-03 (timebank starts from 2008-07-28 and is slowly being reconstructed from mail and IRC evidence; it's all wild guessing in between)
My housemates don't understand why I'm being so religious about these numbers. There's two answers.

One: this is how I function. Dealing with these numbers and obsessively tracking things gives me a reassuring sense of control (however illusory) over myself... so best to turn these sort of obsessive tendencies to my and to the University's advantage.

Two: 37 hours a week plus a handful of holiday looks like a pretty sane approximation of how much time I should be putting into work plus hobby-hacking. It's a question of sustainability. I'm tired and cracking, and try as I might, I cannot work two jobs, even if one of them is for "fun". Geez, I'm only 29 and I'm whining about burnout and complaining about needing a holiday. Moan moan moan. I ought to get some upper lip reinforcement surgery from the NHS.

Just need to figure out how to get stuff done within 30 hours of University time and 7 hours of darcs time (and no, I do not consider blogging to be part of University time or darcs time... except for notes-for-work and official darcs communication, of course). I'm embarrassed to say that this is probably going to involve me becoming one of their European, academia holidays, and I'm just going to have to live with it (and besides, don't I keep saying that the Europeans probably have the right idea about this kind of thing?).

All that obsessive darcs work in the past few months was due to a sense of urgency, Vigorous Intervention Required. Now that the Vigorous Intervention phase is over, I need to get a handle on things, re-assess the situation, and find a sustainable way to continue doing what needs to get done. And maybe this will involve me literally pulling some weeds for a couple hours a week.

Of course, I'll have to negotiate with the University and also a bit with the darcs community to make sure that all three of us have the same understanding of how Eric-allocation is going to work.

Happy New Year!