<?xml version="1.0" ?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" version="2.0">
	<channel>
		<title>Zeroflux</title>
		<link>http://www.zeroflux.org/</link>
		<description>Random musings of a jaded technocrat</description>
		<dc:date>2010-03-10T06:03:56Z</dc:date>
		<copyright>Judd Vinet</copyright>
		<generator>Pronto</generator>
		<dc:language>en</dc:language>
		<item>
			<title>Migrating to Android</title>
			<link>http://www.zeroflux.org/blog/post/256</link>
			<content:encoded xmlns="http://www.w3.org/1999/xhtml">&lt;p&gt;I went to Google I/O in San Francisco this year, and lo and behold, they started off the conference by giving all 4000 of us free, unlocked Android phones!  Not bad for a $300 conference.&lt;/p&gt;
&lt;p&gt;I do like the iPhone (my current ride) a lot.&amp;nbsp; The hardware is very sleek and the OS is pretty nice.&amp;nbsp; But, their development philosophy seems very closed to a Linux geek like myself.&amp;nbsp; First off, I have to live in the Apple world in order to build an iPhone app.&amp;nbsp; I don't actually own a Mac, which is apparently a bit of a barrier right there.&amp;nbsp; And if I actually want to geek out on my iPhone, I have to go around Apple's back and jailbreak it so I can run what I want.&lt;/p&gt;
&lt;p&gt;Not so with the egalitarian Android.&amp;nbsp; The SDK runs on Windows, Mac, or Linux.&amp;nbsp; As soon as I installed the SDK, I had an easy shell from my workstation to the USB-connected phone.&amp;nbsp; I'm not really a fan of Java, but this is already encouraging me to make some Android apps, a feeling I never really had from the iPhone.&lt;/p&gt;
&lt;p&gt;In terms of general usability, here are some things I've noticed in my short time with Android so far:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The virtual keyboard is slightly laggy when responding to my finger taps (compared to iPhone).&amp;nbsp; This can cause more typos that I don't register until I've already gone a few keys past, and so I find myself backspacing more often to fix mistakes.&amp;nbsp; This is mitigated by typing in landscape mode, as the keyboard itself is bigger.&lt;/li&gt;
&lt;li&gt;I &lt;em&gt;love&lt;/em&gt; the Back button! IMHO, this functionality should really be on iPhones as well.&amp;nbsp; If I open an email in Android, then click a URL inside, it will take me to the browser app.&amp;nbsp; If I then click the Back button, it takes me back to my email message.&amp;nbsp; With the iPhone, I have to click the Home button first and then load up the mail app again.&lt;/li&gt;
&lt;li&gt;No two-finger pinch/zoom stuff in the default Android kernel, though I'm told this can be enabled with a custom kernel.&amp;nbsp; Based on that, I'd guess that two-finger tricks will be arriving in an official capacity soon.&lt;/li&gt;
&lt;li&gt;Google integration is really nice to have.&amp;nbsp; If you already use Gmail et al. in your day-to-day life, then all this data is magically on your phone too.&amp;nbsp; I'm sure MobileMe is like this too, but I think more people use Gmail than MobileMe.&amp;nbsp; And Gmail is free.&lt;/li&gt;
&lt;li&gt;There's no 1/8&quot; headphone jack on this handset (HTC Magic), only a USB connection.&amp;nbsp; Of course, they do provide headsets (two!) with the phone, but it'd still be nice to have a standard stereo jack.&lt;/li&gt;
&lt;li&gt;In general, I find the app organization (or lack thereof) and both iPhone and Android to be annoying.&amp;nbsp; Both choose to lay out all apps in a single panel, so it becomes time-consuming to find an app if you have a lot of them installed.&amp;nbsp; I would prefer some sort of hierarchical system, so I could organize all my networking apps in one area, productivity apps in another, games in a third, etc.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;br /&gt;So despite my general happiness with the iPhone as an end-user, I'm giving Android a solid chance.&amp;nbsp; The first thing I had to do was get my contacts moved over to the new phone.&amp;nbsp; This, surprisingly enough, proved to be non-trivial.&amp;nbsp; You'd think it could be as simple as hitting an &quot;Export to SIM&quot; button on one phone and an &quot;Import from SIM&quot; on the other.&amp;nbsp; The problem is that neither phone provides an &quot;Export to SIM&quot; function.&amp;nbsp; They'll happily import contacts off a SIM, but I guess nobody has had a need to export yet.&amp;nbsp; And any sort of third-party app was conspicuously absent from the App Store.&amp;nbsp; Hmmm.&amp;nbsp; It smells a bit like data lock-in, but I'd never say that out loud.&lt;/p&gt;
&lt;p&gt;Eventually, I just SSH'ed into my iPhone and started poking around.&amp;nbsp; Turns out the contacts are all centralized in a SQLite database!&amp;nbsp; That made life a lot easier.&amp;nbsp; I copied it over to my workstation and wrote a little Python script that massaged the contact data into CSV format.&amp;nbsp; I imported the CSV file into my Gmail contacts and seconds later, they all showed up on my Android phone.&amp;nbsp; Cinch.&lt;/p&gt;
&lt;p&gt;If you're interested, the DB is in &lt;span class=&quot;code&quot;&gt;/var/mobile/Library/AddressBook/AddressBook.sqlitedb&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;Here's the Python as well.&amp;nbsp; It's a little rough around the edges -- I've been doing a lot of Javascript lately, and kept finding myself trying to do prototypal things in Python.&amp;nbsp; That didn't work.&lt;/p&gt;
&lt;pre&gt;#!/usr/bin/python&lt;br /&gt;import io, sys&lt;br /&gt;import sqlite3&lt;br /&gt;&lt;br /&gt;# get headers from CSV template&lt;br /&gt;#   &amp;lt;http://theregoesdave.com/wp-content/uploads/2008/10/gmail.csv&amp;gt;&lt;br /&gt;hdrs = io.open('gmail.csv', 'r').readline().strip().split(',')&lt;br /&gt;print '&quot;' + '&quot;,&quot;'.join(hdrs) + '&quot;'&lt;br /&gt;&lt;br /&gt;conn = sqlite3.connect('AddressBook.sqlitedb')&lt;br /&gt;conn.row_factory = sqlite3.Row&lt;br /&gt;&lt;br /&gt;cContact = conn.cursor();&lt;br /&gt;cContact.execute(&quot;SELECT * FROM ABPerson ORDER BY Last,First&quot;)&lt;br /&gt;&lt;br /&gt;# From the ABMultiValueLabel table&lt;br /&gt;Labels = (&quot;&quot;, &quot;Mobile&quot;, &quot;Work&quot;, &quot;Home&quot;, &quot;Other&quot;)&lt;br /&gt;&lt;br /&gt;for contact in cContact:&lt;br /&gt;	# get phone numbers&lt;br /&gt;	cPhone = conn.cursor();&lt;br /&gt;	cPhone.execute(&quot;SELECT value,label FROM ABMultiValue WHERE record_id=? AND property=3 ORDER BY label&quot;, (contact[&quot;ROWID&quot;],))&lt;br /&gt;	phones = {}&lt;br /&gt;	for p in cPhone: phones[Labels[p[&quot;label&quot;]]] = p[&quot;value&quot;]&lt;br /&gt;	if(len(phones) == 0): continue # skip people without phone numbers&lt;br /&gt;&lt;br /&gt;	# get email addresses&lt;br /&gt;	cEmail = conn.cursor();&lt;br /&gt;	cEmail.execute(&quot;SELECT value,label FROM ABMultiValue WHERE record_id=? AND property=4 ORDER BY label&quot;, (contact[&quot;ROWID&quot;],))&lt;br /&gt;	emails = {}&lt;br /&gt;	for p in cEmail: emails[Labels[p[&quot;label&quot;]]] = p[&quot;value&quot;]&lt;br /&gt;&lt;br /&gt;	# Use &quot;Section 1&quot; for home/mobile&lt;br /&gt;	# Use &quot;Section 2&quot; for work&lt;br /&gt;	rec = {&lt;br /&gt;		'Name': &quot;%s %s&quot; % (contact[&quot;First&quot;], contact[&quot;Last&quot;]),&lt;br /&gt;		'E-mail': emails[&quot;Home&quot;] if emails.has_key(&quot;Home&quot;) else emails[&quot;Work&quot;] if emails.has_key(&quot;Work&quot;) else &quot;&quot;,&lt;br /&gt;&lt;br /&gt;		'Section 1 - Description': 'Home',&lt;br /&gt;		'Section 1 - Email': emails[&quot;Home&quot;] if emails.has_key(&quot;Home&quot;) else &quot;&quot;,&lt;br /&gt;		'Section 1 - Phone': phones[&quot;Home&quot;] if phones.has_key(&quot;Home&quot;) else &quot;&quot;,&lt;br /&gt;		'Section 1 - Mobile': phones[&quot;Mobile&quot;] if phones.has_key(&quot;Mobile&quot;) else &quot;&quot;,&lt;br /&gt;&lt;br /&gt;		'Section 2 - Description': 'Work',&lt;br /&gt;		'Section 2 - Email': emails[&quot;Work&quot;] if emails.has_key(&quot;Work&quot;) else &quot;&quot;,&lt;br /&gt;		'Section 2 - Phone': phones[&quot;Work&quot;] if phones.has_key(&quot;Work&quot;) else &quot;&quot;,&lt;br /&gt;		'Section 2 - Company': contact[&quot;Organization&quot;] if contact[&quot;Organization&quot;] else &quot;&quot;&lt;br /&gt;	}&lt;br /&gt;&lt;br /&gt;	# prune empty fields and section descriptions&lt;br /&gt;	def prune(dict, key):&lt;br /&gt;		for k in dict.keys():&lt;br /&gt;			if len(dict[k]) == 0: del dict[k]&lt;br /&gt;		ct = 0&lt;br /&gt;		for k in dict:&lt;br /&gt;			if k.startswith(key): ct = ct + 1&lt;br /&gt;		if ct == 1: del dict[key+' - Description']&lt;br /&gt;&lt;br /&gt;	prune(rec, &quot;Section 1&quot;)&lt;br /&gt;	prune(rec, &quot;Section 2&quot;)&lt;br /&gt;&lt;br /&gt;	# write out as CSV&lt;br /&gt;	row = []&lt;br /&gt;	for h in hdrs:&lt;br /&gt;		row.append(rec[h] if rec.has_key(h) else &quot;&quot;)&lt;br /&gt;	print '&quot;' + '&quot;,&quot;'.join(row) + '&quot;'&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;
&lt;p&gt;Hope it helps.&amp;nbsp; Of course, you will need a jail-broken iPhone in order to SSH in and copy a raw file off it.&amp;nbsp; If you use Windows, you can probably just sync your contacts to Outlook and then export from there.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</content:encoded>
			<dc:date>2009-06-11T15:06:00Z</dc:date>
		</item>
		<item>
			<title>Rocket Stick on Arch Linux</title>
			<link>http://www.zeroflux.org/blog/post/255</link>
			<content:encoded xmlns="http://www.w3.org/1999/xhtml">&lt;p&gt;Well, thanks to a kind employer and an ill-timed server crash, I now have a free Rocket Stick.  It's an HSDPA USB modem from Rogers, a Canadian cellular carrier.&amp;nbsp; Download speeds &quot;up to&quot; 7.2 Mbps in 3.5G.&amp;nbsp; The downstream degrades steadily as I wander off into 3G and (gasp!) 2G.&lt;/p&gt;
&lt;p&gt;Not a bad toy to have in the summer months.&amp;nbsp; Now all I need is a really bright laptop screen and I can sit in parks all day, coding and yelling at hobos.&lt;/p&gt;
&lt;p&gt;The device is a ZTE MF636 USB modem.&amp;nbsp; Naturally, it's not supported under Linux.&amp;nbsp; I don't even know if Rogers knows what Linux is.&amp;nbsp; But the Internet came through, as it usually does, and within 45 minutes I had found all my answers on various forums and blogs.&amp;nbsp; So here's a consolidated contribution that should work for most Linux distributions. I've tested this on Arch Linux, but the tools used are generic.&lt;/p&gt;
&lt;p&gt;So the catch with this little device is that it has multiple personalities.&amp;nbsp; When you first plug it into a Linux machine, the OS will see it as a generic CD-ROM device (eg, /dev/sr1).&amp;nbsp; This is what the marketing boys call a &quot;Zero CD&quot; application install.&amp;nbsp; The Windows/Mac drivers and software are in a small ROM on the USB device itself, so no extra CD required.&amp;nbsp; If you're on a Windows machine, you simply plug the USB key into the computer and the computer will see it as a CD-ROM and fire up the Autorun executable.&amp;nbsp; Voila.&lt;/p&gt;
&lt;p&gt;What happens behind the scenes is this: The software runs off the CD-ROM and installs the drivers.&amp;nbsp; When the installation is complete, the driver issues a command to the device that tells it to switch personalities.&amp;nbsp; Now it's a USB modem, and has a new USB product ID associated with it.&lt;/p&gt;
&lt;p&gt;This mode switch is the part that I used Windows for.&amp;nbsp; I know, it sucks, but I had a Windows machine on hand so I took advantage.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1. Disable CD mode on the device.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Using a Windows machine, plug in the USB device and go through the short install wizard.&amp;nbsp; Once done, close the Rogers app that starts up, then head into the Device Manager (Control Panel -&amp;gt; System -&amp;gt; Device Manager).&amp;nbsp; Under the Ports section, find the COM port that's connected to the USB modem (ignore the Diagnostics one).&amp;nbsp; Connect to that COM port through Hyperterminal, found in the Accessories area of the Start Menu.&amp;nbsp; Connection parameters are&lt;/p&gt;
&lt;p style=&quot;padding-left: 30px;&quot;&gt;Bits per Second: 115200&lt;br /&gt;Data bits: 8&lt;br /&gt;Parity: None&lt;br /&gt;Stop bits: 1&lt;br /&gt;Flow Control: None&lt;/p&gt;
&lt;p&gt;Once connected, type the following commands:&lt;/p&gt;
&lt;pre class=&quot;code&quot;&gt;AT+ZOPRT=5&lt;br /&gt;AT+ZCDRUN=8&lt;/pre&gt;
&lt;p&gt;This tells the modem not to use CD mode when it's first plugged into a computer.&amp;nbsp; Now exit Hypterterminal and remove the USB modem.&amp;nbsp; You're done with Windows.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2. Setup udev rules.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Create a file /etc/udev/rules.d/90-zte.conf that contains the following:&lt;/p&gt;
&lt;pre class=&quot;code&quot;&gt;ACTION!=&quot;add&quot;, GOTO=&quot;ZTE_End&quot;&lt;br /&gt;SUBSYSTEM==&quot;usb&quot;, SYSFS{idProduct}==&quot;0031&quot;, SYSFS{idVendor}==&quot;19d2&quot;, GOTO=&quot;ZTE_Modem&quot;&lt;br /&gt;GOTO=&quot;ZTE_End&quot;&lt;br /&gt;&lt;br /&gt;LABEL=&quot;ZTE_Modem&quot;&lt;br /&gt;RUN+=&quot;/sbin/modprobe usbserial vendor=0x19d2 product=0x0031&quot;, MODE=&quot;660&quot;, GROUP=&quot;network&quot;&lt;br /&gt;LABEL=&quot;ZTE_End&quot;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3. Setup hal rules.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The current version of hal (that I have) doesn't know about the MF636, though it does acknowledge some earlier models.&amp;nbsp; To inform it, create a file /etc/hal/fdi/information/10-modem.fdi with the following:&lt;/p&gt;
&lt;pre class=&quot;code&quot;&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&amp;gt; &amp;lt;!-- -*- xml -*- --&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;deviceinfo version=&quot;0.2&quot;&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;lt;device&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;match key=&quot;info.category&quot; string=&quot;serial&quot;&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;!-- ZTE MF636 HSDPA USB dongle --&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;match key=&quot;@info.parent:usb.product_id&quot; int=&quot;0x0031&quot;&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;match key=&quot;@info.parent:usb.interface.number&quot; int=&quot;3&quot;&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;append key=&quot;modem.command_sets&quot; type=&quot;strlist&quot;&amp;gt;GSM-07.07&amp;lt;/append&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;append key=&quot;modem.command_sets&quot; type=&quot;strlist&quot;&amp;gt;GSM-07.05&amp;lt;/append&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/match&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/match&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/match&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;lt;/device&amp;gt;&lt;br /&gt;&amp;lt;/deviceinfo&amp;gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;4. Create a wvdial configuration.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Wvdial is an easy-to-use frontend to PPPd.&amp;nbsp; The configuration is fairly easy to comprehend.&amp;nbsp; This one is probably longer than it needs to be, but I'll include it all.&amp;nbsp; Make sure you replace the &lt;span class=&quot;code&quot;&gt;/dev/ttyUSB0&lt;/span&gt; line with the node that your USB modem is connected to.&lt;/p&gt;
&lt;pre class=&quot;code&quot;&gt;[Dialer Defaults]&lt;br /&gt;Modem = /dev/ttyUSB0&lt;br /&gt;ISDN = off&lt;br /&gt;Modem Type = USB Modem&lt;br /&gt;Baud = 7200000&lt;br /&gt;Init = ATZ&lt;br /&gt;Init2 = &lt;br /&gt;Init3 = &lt;br /&gt;Init4 = &lt;br /&gt;Init5 = &lt;br /&gt;Init6 = &lt;br /&gt;Init7 = &lt;br /&gt;Init8 = &lt;br /&gt;Init9 = &lt;br /&gt;Phone = *99#&lt;br /&gt;Phone1 = &lt;br /&gt;Phone2 = &lt;br /&gt;Phone3 = &lt;br /&gt;Phone4 = &lt;br /&gt;Dial Prefix = &lt;br /&gt;Dial Attempts = 1&lt;br /&gt;Dial Command = ATM1L3DT&lt;br /&gt;Ask Password = off&lt;br /&gt;Password = off&lt;br /&gt;Username = na&lt;br /&gt;Auto Reconnect = off&lt;br /&gt;Abort on Busy = off&lt;br /&gt;Carrier Check = off&lt;br /&gt;Check Def Route = off&lt;br /&gt;Abort on No Dialtone = off&lt;br /&gt;Stupid Mode = on&lt;br /&gt;Idle Seconds = 0&lt;br /&gt;Auto DNS = on&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;5. Dial up to the interwebs.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Now just run wvdial to connect!&lt;/p&gt;
&lt;pre class=&quot;code&quot;&gt;# wvdial -C /etc/wvdial.conf&lt;/pre&gt;
&lt;p&gt;If you see output reporting your PPP local and endpoint IP addresses, then you've won!&amp;nbsp; Crack a beer and troll some forums.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;6. Acknowledge the real heroes.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Thanks to the following webpages that gave me all this information:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://www.matt-barrett.com/?p=5&quot;&gt;http://www.matt-barrett.com/?p=5&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://ubuntuforums.org/showthread.php?t=1005910&quot;&gt;http://ubuntuforums.org/showthread.php?t=1005910&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://ubuntuforums.org/showthread.php?t=1065934&quot;&gt;http://ubuntuforums.org/showthread.php?t=1065934&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;strong&gt;&lt;em&gt;Update:&lt;/em&gt;&lt;/strong&gt; Fixed a bug in my udev rules.&lt;/p&gt;</content:encoded>
			<dc:date>2009-06-09T07:06:00Z</dc:date>
		</item>
		<item>
			<title>Phatso</title>
			<link>http://www.zeroflux.org/blog/post/254</link>
			<content:encoded xmlns="http://www.w3.org/1999/xhtml">&lt;p&gt;A while back I wrote a tiny little micro framework for a contract.&amp;nbsp; It's been sitting around on my hard drive for awhile, so I figured I should throw it up here in case anybody ever has need for such a thing.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/projects/phatso&quot;&gt;Meet Phatso&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The framework itself is only about 100 lines of code.&amp;nbsp; It handles basic dispatch and templating functionality, nothing more.&amp;nbsp; There is an auxiliary file included for PDO-based database access as well.&lt;/p&gt;
&lt;p&gt;Phatso is intended for small web applications that could still benefit from a bit of framework-y structure.&amp;nbsp; A typical web app could probably reside in one or two PHP files.&amp;nbsp; It's not designed to be a full-fledged framework, only to provide the basic stuff (clean URLs, templates) a little web app might like to have.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</content:encoded>
			<dc:date>2009-04-29T10:04:00Z</dc:date>
		</item>
		<item>
			<title>Clean Switch Blocks</title>
			<link>http://www.zeroflux.org/blog/post/252</link>
			<content:encoded xmlns="http://www.w3.org/1999/xhtml">&lt;p&gt;There's a time and a place for &lt;span class=&quot;code&quot;&gt;switch&lt;/span&gt; blocks in programming.&amp;nbsp; Normally you &lt;span class=&quot;code&quot;&gt;switch&lt;/span&gt; on a variable, then provide a number of &lt;span class=&quot;code&quot;&gt;case&lt;/span&gt; blocks that provide a (hopefully succinct) chunk of code to be executed if the &lt;span class=&quot;code&quot;&gt;switch&lt;/span&gt; variable matches the &lt;span class=&quot;code&quot;&gt;case&lt;/span&gt; value.&lt;/p&gt;
&lt;pre&gt;&amp;lt;?php&lt;br /&gt;switch($pizza) {&lt;br /&gt;  case 'italian':&lt;br /&gt;    $ingredients = array('ham','pepperoni','onions','peppers');&lt;br /&gt;    break;&lt;br /&gt;  case 'mediterranean':&lt;br /&gt;    $ingredients = array('garlic','feta','tomatoes','spinach','olives');&lt;br /&gt;    break;&lt;br /&gt;  case 'hawaiian':&lt;br /&gt;    $ingredients = array('ham','pineapple');&lt;br /&gt;    break;&lt;br /&gt;  default:&lt;br /&gt;    // plain ol' cheese - borrrrrring&lt;br /&gt;    $ingredients = array();&lt;br /&gt;}&lt;br /&gt;?&amp;gt;&lt;br /&gt;&lt;/pre&gt;
&lt;p&gt;Simple, right?&amp;nbsp; But there are often times when you'll find yourself building a long, kinda ugly-looking &lt;span class=&quot;code&quot;&gt;if/elseif/else&lt;/span&gt; block simply because you need to evaluate something more complicated than the value of a variable.&lt;/p&gt;
&lt;pre&gt;&amp;lt;?php&lt;br /&gt;if($a &amp;&amp; $b) {&lt;br /&gt;  func1();&lt;br /&gt;} else if($a &amp;&amp; $c) {&lt;br /&gt;  func2();&lt;br /&gt;} else if($b &amp;&amp; $c) {&lt;br /&gt;  func3();&lt;br /&gt;} else if($c) {&lt;br /&gt;  func4();&lt;br /&gt;} else {&lt;br /&gt;  func5();&lt;br /&gt;}&lt;br /&gt;?&amp;gt;&lt;br /&gt;&lt;/pre&gt;
&lt;p&gt;Those happen all the time and there's nothing wrong with them.&amp;nbsp; Well, except for my contrived example.&amp;nbsp; Forgiveness, please.&lt;/p&gt;
&lt;p&gt;But you can often improve readability by putting blocks like this into a &lt;span class=&quot;code&quot;&gt;switch&lt;/span&gt; statement.&amp;nbsp; The trick is to invert the placement of the &lt;span class=&quot;code&quot;&gt;switch&lt;/span&gt; variable and the &lt;span class=&quot;code&quot;&gt;case&lt;/span&gt; values.&amp;nbsp; A &lt;span class=&quot;code&quot;&gt;switch&lt;/span&gt; operator can take any value statement and compare it to a number of other values (cases), so it follows that we can use a static value at the top.&lt;/p&gt;
&lt;p&gt;Try this:&lt;/p&gt;
&lt;pre&gt;&amp;lt;?php&lt;br /&gt;switch(true) {&lt;br /&gt;  case $a &amp;&amp; $b: func1(); break;&lt;br /&gt;  case $a &amp;&amp; $c: func2(); break;&lt;br /&gt;  case $b &amp;&amp; $c: func3(); break;&lt;br /&gt;  case $c:       func4(); break;&lt;br /&gt;  default:       func5();&lt;br /&gt;}&lt;br /&gt;?&amp;gt;&lt;br /&gt;&lt;/pre&gt;
&lt;p&gt;This does the same thing as the &lt;span class=&quot;code&quot;&gt;if/elseif/else&lt;/span&gt; block above, but it's more compact without sacrificing readability.&amp;nbsp; But, like &lt;span class=&quot;code&quot;&gt;switch&lt;/span&gt; statements, there's a time and a place for them.&amp;nbsp; If you have a lot of code that needs to go in each &lt;span class=&quot;code&quot;&gt;case&lt;/span&gt; block, then it's probably better to put the code in functions, or failing that, in a normal &lt;span class=&quot;code&quot;&gt;if/else&lt;/span&gt; block.&amp;nbsp; Big bulky &lt;span class=&quot;code&quot;&gt;case&lt;/span&gt; statements can be tough to read, since they don't have the normal block delimiters.&lt;/p&gt;
&lt;p&gt;Have any other useful programming idioms to save time or space?&lt;/p&gt;</content:encoded>
			<dc:date>2009-03-31T09:03:00Z</dc:date>
		</item>
		<item>
			<title>Working Backwards: New Pronto Data Models</title>
			<link>http://www.zeroflux.org/blog/post/251</link>
			<content:encoded xmlns="http://www.w3.org/1999/xhtml">&lt;p&gt;For a long time, I've been wanting to redesign the data models in Pronto.&amp;nbsp; They serve their purpose fairly well, but I've always found myself writing small methods in the model classes that don't really need to be written.&amp;nbsp; They were simply enough that it was a waste of time to even have to write them.&lt;/p&gt;
&lt;p&gt;A simple example:&lt;/p&gt;
&lt;pre&gt;&amp;lt;?php&lt;br /&gt;  function get_active_users()&lt;br /&gt;  {&lt;br /&gt;    return $this-&amp;gt;db-&amp;gt;get_all(&quot;SELECT * FROM users WHERE status='active'&quot;);&lt;br /&gt;  }&lt;br /&gt;?&amp;gt;&lt;/pre&gt;
&lt;p&gt;My primary intent for doing this sort of stuff was to keep any SQL out of the controllers that might be requesting data like this.&amp;nbsp; Of course, I ended up with a ton of little methods littering my data models.&amp;nbsp; It wasn't ideal.&lt;/p&gt;
&lt;p&gt;I also had a bunch of methods in the base model class that were more-or-less convenience methods to avoid some of these &lt;span class=&quot;code&quot;&gt;get_whatever()&lt;/span&gt; methods, stuff like &lt;span class=&quot;code&quot;&gt;Model::get_all()&lt;/span&gt;, &lt;span class=&quot;code&quot;&gt;Model::get_by()&lt;/span&gt;, etc.&amp;nbsp; It was clear that there was some room for improvement here.&lt;/p&gt;
&lt;p&gt;I had been struggling to come up with a very simple and robust API to replace this stuff, but I always got hung up on the details before I'd even get to how the API itself was going to work.&amp;nbsp; I was trying to envision the internals and then move on to the actual API once I had the internals figured out.&lt;/p&gt;
&lt;p&gt;So a couple nights ago I tried the reverse.&amp;nbsp; I started with the API, ignoring (for now) how the whole thing would actually work under the hood.&amp;nbsp; I started up vim and just wrote out a bunch of example method calls, just as I would want them to look.&amp;nbsp; I ended up with a fairly small and fluent model API, and it actually proved to be pretty easy to work backwards into the internals.&lt;/p&gt;
&lt;p&gt;The big change was adding an auxiliary model class, RecordSelector.&amp;nbsp; This guy builds result sets of zero or more matching records.&amp;nbsp; The matching rows can then be operated on with a few different primitive data manipulation calls (get, set, load, etc.).&lt;/p&gt;
&lt;p&gt;Here's a few examples:&lt;/p&gt;
&lt;pre&gt;&amp;lt;?php&lt;br /&gt;  // get first 3 users from Romania&lt;br /&gt;  $users = $m-&amp;gt;find(&quot;country='Romania'&quot;)-&amp;gt;order('name')-&amp;gt;limit(3)-&amp;gt;load();&lt;br /&gt;&lt;br /&gt;  // set column for one record&lt;br /&gt;  $m-&amp;gt;find('id=12')-&amp;gt;set('country', 'United States');&lt;br /&gt;&lt;br /&gt;  // delete people from Latvia (sorry Latvia)&lt;br /&gt;  $m-&amp;gt;find(&quot;country='Latvia'&quot;)-&amp;gt;delete();&lt;br /&gt;?&amp;gt;&lt;/pre&gt;
&lt;p&gt;So far I've been able to rip out a lot of app-level model code, while still keeping the code fairly concise and readable.&amp;nbsp; Win.&lt;/p&gt;
&lt;p&gt;I'm hoping to make a new Pronto release soon, but it still might be a few weeks.&amp;nbsp; If you'd like to take a peek, you can grab the latest n' greatest through git:&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;code&quot;&gt;$ git clone http://zeroflux.org/pronto.git&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</content:encoded>
			<dc:date>2009-03-25T06:03:00Z</dc:date>
		</item>
		<item>
			<title>Small and Fun Project Seeks New Home</title>
			<link>http://www.zeroflux.org/blog/post/250</link>
			<content:encoded xmlns="http://www.w3.org/1999/xhtml">&lt;p&gt;
Are there any C hackers out there who'd like to take on a new project?
&lt;/p&gt;
&lt;p&gt;
I wrote &lt;a href=&quot;http://www.zeroflux.org/knock/&quot;&gt;knockd&lt;/a&gt; in my final year (2004) of university as a proof-of-concept. &amp;nbsp;It was featured on Slashdot and generated a fair amount of interest, including some neat contributions from other port-knocker people out there.
&lt;/p&gt;
&lt;p&gt;
I don't really use the program anymore, and so I'm probably not the best person to be maintaining it. &amp;nbsp;If you are (or know of anyone who is) interested in adopting the project, please contact me. &amp;nbsp;jvinet at zeroflux dot org.
&lt;/p&gt;
&lt;p&gt;
&amp;nbsp;
&lt;/p&gt;
</content:encoded>
			<dc:date>2008-10-12T06:10:48Z</dc:date>
		</item>
		<item>
			<title>HTPC For The Rest Of Us</title>
			<link>http://www.zeroflux.org/blog/post/249</link>
			<content:encoded xmlns="http://www.w3.org/1999/xhtml">&lt;p&gt;
Bec and I have an old, beer-stained laptop that we use as our media player.&amp;nbsp; It's a tank and the power button is broken, which can make things a bit tricky.&amp;nbsp; But all in all, it works.
&lt;/p&gt;
&lt;p&gt;
I also have an &lt;a href=&quot;http://www.mythtv.org/wiki/images/5/5c/Remotewonder1.jpg&quot;&gt;ATI Remote Wonder&lt;/a&gt; that we use with mplayer.&amp;nbsp; So the only thing left is some sort of navigable menu system so I don't have to get off my lazy ass to pick a new show each time.
&lt;/p&gt;
&lt;p&gt;
We used to use &lt;a href=&quot;http://www.geexbox.org&quot;&gt;Geexbox&lt;/a&gt;, which is a great little home theatre PC (HTPC) setup.&amp;nbsp; But Geexbox is a standalone system that boots off a CD into its own minimal flavour of Linux.&amp;nbsp; Problem is that this tank of a laptop doesn't have built-in wireless, and the USB wifi adapter we're using requires a windows driver (via ndiswrapper) to work properly, and Geexbox doesn't have this, to the best of my knowledge.
&lt;/p&gt;
&lt;p&gt;
So I installed Arch on the machine, got everything working, and started looking at other HTPC software.&amp;nbsp; I tried Freevo and Elisa.&amp;nbsp; They needed more setup and configuration than the plug-and-play Geexbox I was used to.&amp;nbsp; I also tried a few smaller pieces of software that did the bare essential - just show a directory of files and let the user select one to watch.&amp;nbsp; They all kinda worked, but not really.&amp;nbsp; I think they were proof-of-concepts that never really got finished.
&lt;/p&gt;
&lt;p&gt;
After the 19th segfault of one, I decided to write my own little guy.&amp;nbsp; Hadn't used python in awhile, so it would be good for me.
&lt;/p&gt;
&lt;p&gt;
So here it is, 188 lines with comments.&amp;nbsp; It does only the basic file navigation stuff, using either the keyboard or an LIRC-compatible remote control.&amp;nbsp; Once a file is selected, everything else is handled by mplayer.
&lt;/p&gt;
&lt;ul&gt;
				
			
		
	&lt;li&gt;&lt;a href=&quot;http://www.zeroflux.org/proj/htpc/htpc.txt&quot;&gt;Download the main script&lt;/a&gt;&lt;/li&gt;
				
			
		
	&lt;li&gt;&lt;a href=&quot;http://www.zeroflux.org/proj/htpc/darkwood.jpg&quot;&gt;Download the background image&amp;nbsp;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
If you want to use a remote, then you'll have to setup your LIRC configuration file to map your remote buttons to the correct functions in the HTPC menu.&amp;nbsp; Here's an excerpt from my &lt;span class=&quot;code&quot;&gt;~/.lircrc&lt;/span&gt; file:
&lt;/p&gt;
&lt;p&gt;
&lt;span class=&quot;code&quot;&gt;begin&lt;br /&gt;
&amp;nbsp; button = UP&lt;br /&gt;
&amp;nbsp; prog = pyhtpc&lt;br /&gt;
&amp;nbsp; config = UP&lt;br /&gt;
&amp;nbsp; repeat = 5&lt;br /&gt;
end&lt;br /&gt;
begin&lt;br /&gt;
&amp;nbsp; button = DOWN&lt;br /&gt;
&amp;nbsp; prog = pyhtpc&lt;br /&gt;
&amp;nbsp; config = DOWN&lt;br /&gt;
&amp;nbsp; repeat = 5&lt;br /&gt;
end&lt;br /&gt;
begin&lt;br /&gt;
&amp;nbsp; button = LEFT&lt;br /&gt;
&amp;nbsp; prog = pyhtpc&lt;br /&gt;
&amp;nbsp; config = BACK&lt;br /&gt;
end&lt;br /&gt;
begin&lt;br /&gt;
&amp;nbsp; button = RIGHT&lt;br /&gt;
&amp;nbsp; prog = pyhtpc&lt;br /&gt;
&amp;nbsp; config = SELECT&lt;br /&gt;
end&lt;br /&gt;
begin&lt;br /&gt;
&amp;nbsp; button = OK&lt;br /&gt;
&amp;nbsp; prog = pyhtpc&lt;br /&gt;
&amp;nbsp; config = SELECT&lt;br /&gt;
end&lt;br /&gt;
begin&lt;br /&gt;
&amp;nbsp; button = POWER&lt;br /&gt;
&amp;nbsp; prog = pyhtpc&lt;br /&gt;
&amp;nbsp; config = QUIT&lt;br /&gt;
end&lt;/span&gt;&lt;br /&gt;
&lt;/p&gt;
&lt;p&gt;
There will be bugs.&amp;nbsp; If you find some, please fix them so I can take credit. 
&lt;/p&gt;
</content:encoded>
			<dc:date>2008-10-05T10:10:06Z</dc:date>
		</item>
		<item>
			<title>Bootstrap your i18n with Pronto</title>
			<link>http://www.zeroflux.org/blog/post/248</link>
			<content:encoded xmlns="http://www.w3.org/1999/xhtml">&lt;p&gt;
I've been steadily working at rounding out some areas of Pronto lately, and one has been the i18n support.&amp;nbsp; Pronto supported multiple languages and UTF-8 before now, but that functionality didn't extend to application modules, and my little hack to translate message files via Google Translate was only partially complete.
&lt;/p&gt;
&lt;p&gt;
With the next release, however, this stuff will be actually usable.&amp;nbsp; Google Translate supports all the major languages, so in a couple commands, you can now do this:
&lt;/p&gt;
&lt;ol&gt;
				
			
		
	&lt;li&gt;Scan your entire application codebase (including modules) and compile all strings into a messages file; and&lt;/li&gt;
				
			
		
	&lt;li&gt;Automatically translate that messages file into the following languages:&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
				
			
		
	&lt;ul&gt;
								
						
				
		&lt;li&gt;Arabic&lt;/li&gt;
								
						
				
		&lt;li&gt;Chinese Simplified&lt;/li&gt;
								
						
				
		&lt;li&gt;Chinese Traditional&lt;/li&gt;
								
						
				
		&lt;li&gt;Dutch&lt;/li&gt;
								
						
				
		&lt;li&gt;French&lt;/li&gt;
								
						
				
		&lt;li&gt;German&lt;/li&gt;
								
						
				
		&lt;li&gt;Greek&lt;/li&gt;
								
						
				
		&lt;li&gt;Italian&lt;/li&gt;
								
						
				
		&lt;li&gt;Japanese&lt;/li&gt;
								
						
				
		&lt;li&gt;Korean&lt;/li&gt;
								
						
				
		&lt;li&gt;Portuguese&lt;/li&gt;
								
						
				
		&lt;li&gt;Russian&lt;/li&gt;
								
						
				
		&lt;li&gt;Spanish&lt;/li&gt;
							
					
			
	&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;
Of course, Google Translate is far from perfect, so this only really serves as a &amp;quot;good enough for now&amp;quot; solution.&amp;nbsp; Once your application is production quality, so should your translations, and that means getting translations from real human beings.
&lt;/p&gt;
&lt;p&gt;
Here's a quick excerpt showing how I build my initial messages file and then translate them:
&lt;/p&gt;
&lt;p&gt;
&lt;span class=&quot;code&quot;&gt;[jvinet@neptune site]$ php pronto/bin/i18n_scan.php en English&lt;br /&gt;
Scanning app/bin&lt;br /&gt;
Scanning app/config&lt;br /&gt;
Scanning app/core&lt;br /&gt;
Scanning app/models&lt;br /&gt;
Scanning app/pages&lt;br /&gt;
Scanning app/plugins&lt;br /&gt;
Scanning app/profiles&lt;br /&gt;
Scanning app/templates&lt;br /&gt;
Scanning pronto/core&lt;br /&gt;
Scanning pronto/plugins&lt;br /&gt;
Scanning pronto/profiles&lt;br /&gt;
&lt;br /&gt;
Successfully updated app/config/i18n/en/messages.php&lt;br /&gt;
&lt;br /&gt;
[jvinet@neptune site]$ cd app/config/i18n&lt;br /&gt;
&lt;br /&gt;
 [jvinet@neptune i18n]$ php ../../../pronto/bin/translate_all.php &lt;br /&gt;
Translating English to Arabic...&lt;br /&gt;
Translating English to Chinese Simplified...&lt;br /&gt;
Translating English to Chinese Traditional...&lt;br /&gt;
Translating English to Dutch...&lt;br /&gt;
Translating English to French...&lt;br /&gt;
Translating English to German...&lt;br /&gt;
Translating English to Greek...&lt;br /&gt;
Translating English to Italian...&lt;br /&gt;
Translating English to Japanese...&lt;br /&gt;
Translating English to Korean...&lt;br /&gt;
Translating English to Portuguese...&lt;br /&gt;
Translating English to Russian...&lt;br /&gt;
Translating English to Spanish...&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
Yep, that's it. Stay tuned for the next release.
&lt;/p&gt;
&lt;p&gt;
&lt;a href=&quot;http://www.prontoproject.com&quot;&gt;http://www.prontoproject.com&lt;/a&gt; 
&lt;/p&gt;
</content:encoded>
			<dc:date>2008-09-29T06:09:02Z</dc:date>
		</item>
		<item>
			<title>Wikipedia Strikes Again</title>
			<link>http://www.zeroflux.org/blog/post/247</link>
			<content:encoded xmlns="http://www.w3.org/1999/xhtml">&lt;p&gt;
I had aspirations of getting a lot of work done today.&amp;nbsp; But instead, I lost over two hours to Wikipedia. 
&lt;/p&gt;
&lt;p&gt;
It's happened before.&amp;nbsp; I started out on the page for the &lt;a href=&quot;http://en.wikipedia.org/wiki/Halifax_Explosion&quot;&gt;Halifax Explosion&lt;/a&gt;, as we live near the memorial park for the event.&amp;nbsp; The Explosion is touted as the largest manmade explosion until the Atomic Bomb.
&lt;/p&gt;
&lt;p&gt;
So of course, I ended up following through and reading up on the A-Bomb, which then led me to the &lt;a href=&quot;http://en.wikipedia.org/wiki/Little_Boy&quot;&gt;Little Boy&lt;/a&gt; and the &lt;a href=&quot;http://en.wikipedia.org/wiki/Fat_Man&quot;&gt;Fat Man&lt;/a&gt;, and the gunshot-style design versus the implosion-style design.&amp;nbsp; This led me to the properties of &lt;a href=&quot;http://en.wikipedia.org/wiki/Uranium_235&quot;&gt;Uranium-235&lt;/a&gt; and &lt;a href=&quot;http://en.wikipedia.org/wiki/Plutonium-239&quot;&gt;Plutonium-239&lt;/a&gt;, which then led me to the &lt;a href=&quot;http://en.wikipedia.org/wiki/Strong_interaction&quot;&gt;strong&lt;/a&gt; and &lt;a href=&quot;http://en.wikipedia.org/wiki/Weak_interaction&quot;&gt;weak&lt;/a&gt; nuclear forces, which then led me to &lt;a href=&quot;http://en.wikipedia.org/wiki/Ionizing_radiation&quot;&gt;ionizing radiation&lt;/a&gt;, which led me to the &lt;a href=&quot;http://en.wikipedia.org/wiki/Marie_Curie&quot;&gt;Curies&lt;/a&gt; and &lt;a href=&quot;http://en.wikipedia.org/wiki/Henri_Becquerel&quot;&gt;Becquerel&lt;/a&gt;, which led me to &lt;a href=&quot;http://en.wikipedia.org/wiki/Quark&quot;&gt;quarks&lt;/a&gt; and &lt;a href=&quot;http://en.wikipedia.org/wiki/Gluon&quot;&gt;gluons&lt;/a&gt;, which led me to...
&lt;/p&gt;
&lt;p&gt;
You get the picture.&amp;nbsp; I'll never get that morning back.
&lt;/p&gt;
&lt;p&gt;
I'm not even sure I actually learned anything.&amp;nbsp; Stupid hyperlinks.
&lt;/p&gt;
</content:encoded>
			<dc:date>2008-09-23T16:09:38Z</dc:date>
		</item>
		<item>
			<title>X-Canada: Halifax!</title>
			<link>http://www.zeroflux.org/blog/post/246</link>
			<content:encoded xmlns="http://www.w3.org/1999/xhtml">&lt;p&gt;
We are now Haligonians.
&lt;/p&gt;
&lt;p&gt;
&lt;img src=&quot;../img/content/canada_trip_-_halifax.jpg&quot; alt=&quot;Nova Scotia&quot; width=&quot;480&quot; height=&quot;360&quot; /&gt; 
&lt;/p&gt;
&lt;p&gt;
Got here on Sunday, and we're finally starting to feel like we're getting set up here, at least a bit.&amp;nbsp; It's been a long week, with many dollars spent, but I can now sit at a table with a computer, on the internet, with clean clothes, and even food.&amp;nbsp; That's pretty good. 
&lt;/p&gt;
&lt;p&gt;
The trip across Canada was very cool.&amp;nbsp; I'm actually in a bit of withdrawal about it, to tell the truth.&amp;nbsp; I kinda liked the nomadic lifestyle of travelling 500km and camping on the shores of Lake Superior.&amp;nbsp; Our only real concerns were gas, finding a campsite, and buying beer.&amp;nbsp; We took a ton of pictures, and will post them up here or on FB once we sort through them all. 
&lt;/p&gt;
&lt;p&gt;
Bec and I are both feeling pretty homesick for Victoria, but that's not really surprising.&amp;nbsp; We know nobody here, the road system is arguably worse than Victoria (streets intersect themselves and change names frequently), and the entire city seems fairly anti-parking in general.&amp;nbsp; Also, the number of sushi joints is disconcertingly low.&amp;nbsp; Speaking of disconcertingly-low, the microbrewery representation here is, while present, not comparable to BC. 
&lt;/p&gt;
&lt;p&gt;
We're currently living in a 100+ year-old house, one of the few in this area that survived the Halifax explosion back in 1917.&amp;nbsp; It's not the worst, but we're definitely not looking forward to the heating bill this winter, so we may have to look for new digs in a couple months.
&lt;/p&gt;
&lt;p&gt;
But there are good things too.&amp;nbsp; Bec is really stoked about her new program, and the people here seem really friendly.&amp;nbsp; Since I work from home, it's going to be a bit tricky to get out and make a social network here, so I've been considering the idea of a &amp;quot;real&amp;quot; job.&amp;nbsp; Too soon to act on it, due to other obligations, but I might start looking in a month or two.
&lt;/p&gt;
&lt;p&gt;
Also picking up the guitar daily so I can get back into a jamming circle.&amp;nbsp; I've been missing that a lot, and apparently Halifax has a really rich music scene. It's Wintersleep's home city, so that's a good sign. 
&lt;/p&gt;
&lt;p&gt;
To friends and family back home - we miss you tons.&amp;nbsp; Please visit us someday. Bring sushi.
&lt;/p&gt;
&lt;p&gt;
&amp;nbsp;
&lt;/p&gt;
</content:encoded>
			<dc:date>2008-09-06T07:09:34Z</dc:date>
		</item>
	</channel>
</rss>
