<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"><title>Digital Ambulation</title><link href="http://alanbriolat.co.uk/" rel="alternate"></link><link href="http://alanbriolat.co.uk/feeds/all.atom.xml" rel="self"></link><id>http://alanbriolat.co.uk/</id><updated>2016-12-30T00:00:00+00:00</updated><entry><title>EdgeRouter + Dynamic DNS + Cloudflare</title><link href="http://alanbriolat.co.uk/edgerouter-dynamic-dns-cloudflare.html" rel="alternate"></link><published>2016-12-30T00:00:00+00:00</published><updated>2016-12-30T00:00:00+00:00</updated><author><name>Alan Briolat</name></author><id>tag:alanbriolat.co.uk,2016-12-30:edgerouter-dynamic-dns-cloudflare.html</id><summary type="html">&lt;div class="admonition note"&gt;
&lt;p class="first admonition-title"&gt;Note&lt;/p&gt;
&lt;p class="last"&gt;This no longer works. The version of &lt;tt class="docutils literal"&gt;ddclient&lt;/tt&gt; in EdgeOS uses the CloudFlare v1 API, which
was &lt;a class="reference external" href="https://blog.cloudflare.com/sunsetting-api-v1-in-favor-of-cloudflares-current-client-api-api-v4/"&gt;deprecated November 2016&lt;/a&gt;
and finally retired June 2018. I now use &lt;a class="reference external" href="https://github.com/ethaligan/cloudflare-ddns"&gt;cloudflare-ddns&lt;/a&gt; running on a server inside my network.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;My home network sits on a fast internet connection behind an Ubiquiti Networks &lt;a class="reference external" href="https://www.ubnt.com/edgemax/edgerouter-x/"&gt;EdgeRouter X&lt;/a&gt; but
doesn't have the benefit of a static IP address.  I've been meaning to set up a dynamic DNS entry
for it for a while, but really wanted to make use of the fact I already manage my DNS with
Cloudflare, which has a very capable API.  Ubiquiti's EdgeOS has support for dynamic DNS by
generating &lt;tt class="docutils literal"&gt;ddclient&lt;/tt&gt; configurations and running them when the IP address changes, however the web
GUI doesn't support everything that is possible with its &lt;tt class="docutils literal"&gt;ddclient&lt;/tt&gt; version.&lt;/p&gt;
&lt;p&gt;There are existing solutions to this problem, for example this &lt;a class="reference external" href="https://help.ubnt.com/hc/en-us/articles/204976324-EdgeMAX-Custom-Dynamic-DNS-with-Cloudflare"&gt;support article&lt;/a&gt;
easily found through a search engine.  However, the solutions I've found are clunky hacks that will
be missed by configuration backups, and therefore more confusing to reproduce in the future if
necessary.  I wanted something that would exist properly within the EdgeOS configuration system.&lt;/p&gt;
&lt;p&gt;Through trial and error, I found there are only two small things preventing Cloudflare support from
working, and both can be easily sidestepped.&lt;/p&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;The web GUI doesn't provide the &lt;tt class="docutils literal"&gt;cloudflare&lt;/tt&gt; protocol in the drop-down.  Using the EdgeOS
configuration CLI allows this value to be specified manually.&lt;/li&gt;
&lt;li&gt;The EdgeOS configuration schema doesn't allow for the &lt;tt class="docutils literal"&gt;zone&lt;/tt&gt; setting required by the
&lt;tt class="docutils literal"&gt;cloudflare&lt;/tt&gt; protocol.  Because &lt;tt class="docutils literal"&gt;ddclient&lt;/tt&gt; configuration is basically a comma-separated
list of &lt;tt class="docutils literal"&gt;option=value&lt;/tt&gt; pairs, the setting can be injected as part of another setting, as long
as the schema validation doesn't prevent it.  The &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;host-name&lt;/span&gt;&lt;/tt&gt; setting currently allows it, e.g.
&lt;tt class="docutils literal"&gt;home.example.com&lt;/tt&gt; becomes &lt;tt class="docutils literal"&gt;zone=example.com,home.example.com&lt;/tt&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Armed with this knowledge, the dynamic DNS client can be configured with the following commands:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
configure
set service dns dynamic interface eth0 service custom-cloudflare login {{EMAIL}}
set service dns dynamic interface eth0 service custom-cloudflare password {{API_KEY}}
set service dns dynamic interface eth0 service custom-cloudflare protocol cloudflare
set service dns dynamic interface eth0 service custom-cloudflare server www.cloudflare.com
set service dns dynamic interface eth0 service custom-cloudflare host-name zone={{DNS_ZONE}},{{HOSTNAME}}
commit
save
exit
&lt;/pre&gt;
&lt;dl class="docutils"&gt;
&lt;dt&gt;&lt;tt class="docutils literal"&gt;eth0&lt;/tt&gt;&lt;/dt&gt;
&lt;dd&gt;On my EdgeRouter X, &lt;tt class="docutils literal"&gt;eth0&lt;/tt&gt; is configured as the WAN link.  Replace as appropriate on other
setups, this should be the interface that will have your external public IP address.&lt;/dd&gt;
&lt;dt&gt;&lt;tt class="docutils literal"&gt;{{EMAIL}}&lt;/tt&gt;&lt;/dt&gt;
&lt;dd&gt;The email address you use to login to Cloudflare.&lt;/dd&gt;
&lt;dt&gt;&lt;tt class="docutils literal"&gt;{{API_KEY}}&lt;/tt&gt;&lt;/dt&gt;
&lt;dd&gt;Your Cloudflare &amp;quot;Global API Key&amp;quot;, which you can get at &lt;a class="reference external" href="https://www.cloudflare.com/a/account/my-account"&gt;https://www.cloudflare.com/a/account/my-account&lt;/a&gt;.&lt;/dd&gt;
&lt;dt&gt;&lt;tt class="docutils literal"&gt;{{DNS_ZONE}}&lt;/tt&gt;&lt;/dt&gt;
&lt;dd&gt;The Cloudflare-managed domain that the desired DNS entry exists under, e.g. &lt;tt class="docutils literal"&gt;example.com&lt;/tt&gt;.&lt;/dd&gt;
&lt;dt&gt;&lt;tt class="docutils literal"&gt;{{HOSTNAME}}&lt;/tt&gt;&lt;/dt&gt;
&lt;dd&gt;The DNS entry that should be modified, e.g. &lt;tt class="docutils literal"&gt;home.example.com&lt;/tt&gt;.&lt;/dd&gt;
&lt;/dl&gt;
&lt;div class="admonition note"&gt;
&lt;p class="first admonition-title"&gt;Note&lt;/p&gt;
&lt;p class="last"&gt;This article is based on my experience with an EdgeRouter X running EdgeOS 1.9.0.  The
instructions may work with older versions of EdgeOS and should work on other EdgeRouter models,
but I haven't tested those other possibilities.&lt;/p&gt;
&lt;/div&gt;
</summary></entry><entry><title>(X)ubuntu Linux 14.04 on Asus N550JK laptop</title><link href="http://alanbriolat.co.uk/xubuntu-on-asus-n550jk.html" rel="alternate"></link><published>2015-07-24T00:00:00+01:00</published><updated>2015-07-24T00:00:00+01:00</updated><author><name>Alan Briolat</name></author><id>tag:alanbriolat.co.uk,2015-07-24:xubuntu-on-asus-n550jk.html</id><summary type="html">&lt;p&gt;I've just acquired a new work laptop (Asus N550JK-CM604H) and for my job the first step was getting
my preferred Linux distro (Xubuntu 14.04 LTS) up and running on it. However, the laptop is newer
than the distro release, so I didn't expect it to all be smooth sailing...&lt;/p&gt;
&lt;div class="section" id="the-hardware"&gt;
&lt;h2&gt;The hardware&lt;/h2&gt;
&lt;dl class="docutils"&gt;
&lt;dt&gt;CPU&lt;/dt&gt;
&lt;dd&gt;&lt;a class="reference external" href="http://ark.intel.com/products/78934/"&gt;Intel i7-4720HQ&lt;/a&gt;: 2.6 GHz (3.6 GHz turbo), 4 cores, 8
threads, 6MB cache&lt;/dd&gt;
&lt;dt&gt;RAM&lt;/dt&gt;
&lt;dd&gt;2x4GB DDR3 1600 MHz (&lt;a class="reference external" href="http://uk.crucial.com/gbr/en/n550jk/CT5826612"&gt;replaced with 2x8GB&lt;/a&gt;)&lt;/dd&gt;
&lt;dt&gt;GPU&lt;/dt&gt;
&lt;dd&gt;&lt;p class="first"&gt;NVIDIA Optimus dual GPU setup:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://ark.intel.com/products/78934/"&gt;Intel HD 4600&lt;/a&gt;, by default using 64MB of system
memory as VRAM.&lt;/li&gt;
&lt;li&gt;NVIDIA GeForce 850M, 2GB dedicated VRAM&lt;/li&gt;
&lt;/ul&gt;
&lt;p class="last"&gt;HDMI and mini-DisplayPort external outputs. By default everything goes through Intel GPU; see
below for NVIDIA Optimus support.&lt;/p&gt;
&lt;/dd&gt;
&lt;dt&gt;Display&lt;/dt&gt;
&lt;dd&gt;15.6&amp;quot; LED-backlit 1080p IPS&lt;/dd&gt;
&lt;dt&gt;Hard drive&lt;/dt&gt;
&lt;dd&gt;Seagate Momentus ST1000LM024: 1TB SATA-II 5400rpm (replaced with Samsung 850 EVO 500GB)&lt;/dd&gt;
&lt;dt&gt;Wired network&lt;/dt&gt;
&lt;dd&gt;Realtek RTL8111/8168/8411 PCI Express Gigabit Ethernet Controller; supported by &lt;tt class="docutils literal"&gt;r8169&lt;/tt&gt; driver
without intervention&lt;/dd&gt;
&lt;dt&gt;Wireless network&lt;/dt&gt;
&lt;dd&gt;Intel 7260; supported by &lt;tt class="docutils literal"&gt;iwlwifi&lt;/tt&gt; driver without intervention&lt;/dd&gt;
&lt;dt&gt;Touchpad&lt;/dt&gt;
&lt;dd&gt;FocalTech touchpad; see below&lt;/dd&gt;
&lt;dt&gt;Touchscreen&lt;/dt&gt;
&lt;dd&gt;Atmel maXTouch Digitizer; using &lt;tt class="docutils literal"&gt;evdev&lt;/tt&gt; without intervention&lt;/dd&gt;
&lt;dt&gt;Keyboard&lt;/dt&gt;
&lt;dd&gt;It's a keyboard; see below for details of function keys&lt;/dd&gt;
&lt;dt&gt;Webcam&lt;/dt&gt;
&lt;dd&gt;Generic USB video class (UVC) 720p webcam; works without intervention (tested in &lt;tt class="docutils literal"&gt;camorama&lt;/tt&gt;)&lt;/dd&gt;
&lt;dt&gt;Audio/microphone&lt;/dt&gt;
&lt;dd&gt;Intel High-Definition Audio; using &lt;tt class="docutils literal"&gt;snd_hda_intel&lt;/tt&gt; without intervention&lt;/dd&gt;
&lt;/dl&gt;
&lt;/div&gt;
&lt;div class="section" id="lts-hardware-enablement-stack-hwe"&gt;
&lt;h2&gt;LTS Hardware Enablement Stack (HWE)&lt;/h2&gt;
&lt;p&gt;When using an older Linux distro release on a brand new machine, it's likely that some things won't
be very well supported by whichever kernel and Xorg versions that release froze on. Ubuntu's answer
to the problem is the &lt;a class="reference external" href="https://wiki.ubuntu.com/Kernel/LTSEnablementStack"&gt;LTS Hardware Enablement Stack&lt;/a&gt;. At the time of writing, the stack based on
15.04 (Vivid) was the latest, so the following command was used:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
sudo apt-get install --install-recommends \
    linux-generic-lts-vivid xserver-xorg-core-lts-vivid xserver-xorg-lts-vivid \
    xserver-xorg-video-all-lts-vivid xserver-xorg-input-all-lts-vivid \
    libwayland-egl1-mesa-lts-vivid
&lt;/pre&gt;
&lt;p&gt;The only problem with this is that some packages might not be able to build drivers against the new
kernel. I found this to be the case for VirtualBox, but using the latest version available from the
VirtualBox site gets around this.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="suspend"&gt;
&lt;h2&gt;Suspend&lt;/h2&gt;
&lt;p&gt;I decided to try out suspend and resume early on, since historically it's been a fairly quirky area
of hardware support. In this case, the &lt;tt class="docutils literal"&gt;nouveau&lt;/tt&gt; driver barfed into the logs and prevented sleep.
Blacklisting it seems to fix the problem: add &lt;tt class="docutils literal"&gt;blacklist nouveau&lt;/tt&gt; to
&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;/etc/modprobe.d/blacklist-nouveau.conf&lt;/span&gt;&lt;/tt&gt;. This was no big deal, since I'm either using the Intel
GPU or the proprietary NVIDIA drivers.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="graphics-driver"&gt;
&lt;h2&gt;Graphics driver&lt;/h2&gt;
&lt;p&gt;Like a lot of decent modern laptops, this one has a dual-GPU setup: the Intel HD 4600 as part of the
CPU, and an NVIDIA 850M.&lt;/p&gt;
&lt;p&gt;As is to be expected, the Intel GPU just works. The HWE upgrade enabled DisplayPort 1.2 Multi-Stream
Transport (MST) support, which allowed me to daisy-chain my &lt;a class="reference external" href="http://www1.euro.dell.com/uk/en/home/Peripherals/dell-u2515h-monitor/pd.aspx"&gt;Dell U2515H&lt;/a&gt; monitors which
support this feature. (Note: the monitors ship with this feature disabled, you need to enable it in
the OSD on each monitor.)&lt;/p&gt;
&lt;p&gt;The NVIDIA GPU was less straightforward: at the time of installing, the latest NVIDIA drivers in the
Ubuntu 14.04 repos would not build against the 3.19 kernel from 15.04. Luckily, the backported newer
drivers were added within a couple of weeks.&lt;/p&gt;
&lt;p&gt;There are two ways to enable NVIDIA support on a laptop like this: using &amp;quot;Bumblebee&amp;quot; to allow
per-application use of the NVIDIA GPU, or using &amp;quot;NVIDIA Prime&amp;quot; to switch the entire desktop
environment between GPUs (requires logging out and back in again). Because I don't intend to make
much use of the NVIDIA GPU, I opted for the latter:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
sudo apt-get install nvidia-346-updates nvidia-prime
&lt;/pre&gt;
&lt;p&gt;By default the Intel GPU should remain selected. The GPU can be switched from the
&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;nvidia-settings&lt;/span&gt;&lt;/tt&gt; control panel.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="touchpad-driver"&gt;
&lt;h2&gt;Touchpad driver&lt;/h2&gt;
&lt;p&gt;The laptop has a FocalTech touchpad, which I hadn't heard of before, and which isn't handled
properly even in the 3.19 kernel from Ubuntu 15.04. Luckily, these touchpads seem to be used in
multiple Asus laptops now, and Ask Ubuntu had an answer: &lt;a class="reference external" href="http://askubuntu.com/a/611936/12021"&gt;Asus X750JA and Ubuntu Gnome 14.04&lt;/a&gt;.  Following those instructions and rebooting, the touchpad
had gained two-finger vertical scrolling, edge scrolling, and also the ability to use &lt;tt class="docutils literal"&gt;synclient&lt;/tt&gt;
to tweak the settings.&lt;/p&gt;
&lt;p&gt;In terms of customising the touchpad behaviour, I put the following in my &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;~/.xprofile&lt;/span&gt;&lt;/tt&gt;:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
synclient HorizTwoFingerScroll=1 \
          VertEdgeScroll=0 \
          TapButton3=2 \
          PalmDetect=1
&lt;/pre&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Enable 2-finger scrolling horizontally (vertical 2-finger scroll is enabled by default)&lt;/li&gt;
&lt;li&gt;Disable vertical edge scrolling, since I'm just going to be using 2-finger scrolling all the time&lt;/li&gt;
&lt;li&gt;Turn 3-finger taps into a &amp;quot;middle button&amp;quot; click (2-finger taps are &amp;quot;right click&amp;quot; by default)&lt;/li&gt;
&lt;li&gt;Enable palm detection, to try and get rid of spurious inputs when typing&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="keyboard"&gt;
&lt;h2&gt;Keyboard&lt;/h2&gt;
&lt;p&gt;It's a keyboard. It generally works as well as you'd expect for one of the oldest standard bits of
computer hardware. What tends to vary these days is of course the special/&amp;quot;fn&amp;quot; keys on the keyboard.
This one has several. Going left-to-right, top-to-bottom:&lt;/p&gt;
&lt;dl class="docutils"&gt;
&lt;dt&gt;Sleep key&lt;/dt&gt;
&lt;dd&gt;Is recognised by power management functionality: if you have it set to suspend when the sleep
button is pressed, pressing this key will suspend the same as via any other route.&lt;/dd&gt;
&lt;dt&gt;Wireless toggle&lt;/dt&gt;
&lt;dd&gt;Not registered at all; see below for fix.&lt;/dd&gt;
&lt;dt&gt;Decrease/increase display brightness&lt;/dt&gt;
&lt;dd&gt;Not registered at all; see below for fix.&lt;/dd&gt;
&lt;dt&gt;Toggle display&lt;/dt&gt;
&lt;dd&gt;Seems to switch the laptop screen off and on, not sure where this is handled.&lt;/dd&gt;
&lt;dt&gt;Select display mode&lt;/dt&gt;
&lt;dd&gt;This key is horrible. Really really horrible. So horrible it needs its own subsection (see
below).  Needless to say, it doesn't work properly.&lt;/dd&gt;
&lt;dt&gt;Toggle touchpad&lt;/dt&gt;
&lt;dd&gt;Recognised as &lt;tt class="docutils literal"&gt;XF86TouchpadToggle&lt;/tt&gt;, but nothing actually uses it.&lt;/dd&gt;
&lt;dt&gt;Mute/increase/decrease volume&lt;/dt&gt;
&lt;dd&gt;Recognised and behave as expected.&lt;/dd&gt;
&lt;dt&gt;Box with an &amp;quot;S&amp;quot; in it?&lt;/dt&gt;
&lt;dd&gt;Recognised as &lt;tt class="docutils literal"&gt;XF86Launch1&lt;/tt&gt;.&lt;/dd&gt;
&lt;dt&gt;Camera&lt;/dt&gt;
&lt;dd&gt;Recognised as &lt;tt class="docutils literal"&gt;XF86WebCam&lt;/tt&gt;.&lt;/dd&gt;
&lt;dt&gt;Running person?&lt;/dt&gt;
&lt;dd&gt;Recognised as &lt;tt class="docutils literal"&gt;XF86Launch6&lt;/tt&gt;.&lt;/dd&gt;
&lt;dt&gt;Stop/prev/play-pause/next&lt;/dt&gt;
&lt;dd&gt;Recognised as &lt;tt class="docutils literal"&gt;XF86AudioStop&lt;/tt&gt;, &lt;tt class="docutils literal"&gt;XF86AudioPrev&lt;/tt&gt;, &lt;tt class="docutils literal"&gt;XF86AudioPlay&lt;/tt&gt; and &lt;tt class="docutils literal"&gt;XF86AudioNext&lt;/tt&gt;.&lt;/dd&gt;
&lt;dt&gt;Calculator&lt;/dt&gt;
&lt;dd&gt;Launches calculator.&lt;/dd&gt;
&lt;/dl&gt;
&lt;div class="section" id="wireless-toggle-and-display-brightness"&gt;
&lt;h3&gt;Wireless toggle and display brightness&lt;/h3&gt;
&lt;p&gt;Out of the box, the display brightness and wireless toggle keys are completely unrecognised and
generate no events. It seems that this is a bit of ACPI quirkiness that is documented here: &lt;a class="reference external" href="http://blog.yjwong.name/fixing-display-backlight-hotkeys-on-asus-n550jk/"&gt;Fixing
Display Backlight Hotkeys on ASUS N550JK&lt;/a&gt;. The TL;DR is:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;add &lt;tt class="docutils literal"&gt;acpi_osi=&lt;/tt&gt; to your &lt;tt class="docutils literal"&gt;GRUB_CMDLINE_LINUX_DEFAULT&lt;/tt&gt; in &lt;tt class="docutils literal"&gt;/etc/default/grub&lt;/tt&gt;&lt;/li&gt;
&lt;li&gt;run &lt;tt class="docutils literal"&gt;sudo &lt;span class="pre"&gt;update-grub&lt;/span&gt;&lt;/tt&gt;&lt;/li&gt;
&lt;li&gt;reboot&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="that-horrible-select-display-mode-key"&gt;
&lt;h3&gt;That horrible &amp;quot;Select display mode&amp;quot; key&lt;/h3&gt;
&lt;p&gt;In Windows, there is a &lt;tt class="docutils literal"&gt;Win + P&lt;/tt&gt; combination that opens a quick display selector (for handling an
external monitor).  This key seems to try and emulate pressing this key combination. When you press
&lt;tt class="docutils literal"&gt;Fn + F8&lt;/tt&gt; to use this function, it seems to emit the following keycode events:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;133 down&lt;/li&gt;
&lt;li&gt;33 down&lt;/li&gt;
&lt;li&gt;33 up&lt;/li&gt;
&lt;li&gt;133 up&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Keycode 133 is known as &lt;tt class="docutils literal"&gt;Super_L&lt;/tt&gt; in Linux, or the left Windows key in common parlance. Keycode 33
is the &lt;tt class="docutils literal"&gt;P&lt;/tt&gt; key. But those are keycode events, which means if you use an alternative keyboard
layout (e.g. Dvorak) you get a different effect (e.g. &lt;tt class="docutils literal"&gt;Win+L&lt;/tt&gt;). I give up on doing anything useful
with this key.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="final-words"&gt;
&lt;h2&gt;Final words&lt;/h2&gt;
&lt;p&gt;The laptop makes a pretty adequate desktop replacement, and all of the hardware should be
well-supported by an up-to-date Linux distro. However, for those that opt for a long-term stable
releases, I hope documenting the quirks I encountered will help somebody in a similar situation.&lt;/p&gt;
&lt;/div&gt;
</summary></entry><entry><title>Odd-numbered Days</title><link href="http://alanbriolat.co.uk/odd-numbered-days.html" rel="alternate"></link><published>2013-01-25T00:00:00+00:00</published><updated>2013-01-25T00:00:00+00:00</updated><author><name>Alan Briolat</name></author><id>tag:alanbriolat.co.uk,2013-01-25:odd-numbered-days.html</id><summary type="html">&lt;p&gt;Whilst chatting on the &lt;a class="reference external" href="irc://chat.freenode.net/minecraft"&gt;#minecraft channel on freenode&lt;/a&gt;,
somebody comes out with:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
&amp;lt;Dinnerbone&amp;gt; I love that 50% of thursdays are odd-numbered days
&amp;lt;Dinnerbone&amp;gt; Makes the near-end-of-week that much more interesting
&lt;/pre&gt;
&lt;p&gt;Which got me thinking...  Are 50% of Thursdays on odd-numbered days?  Probably not, at least not in
every year.  Some hacky Python code ensues...&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="ch"&gt;#!/usr/bin/env python3&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;sys&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;datetime&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;collections&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;defaultdict&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;generate_year&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;year&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;delta&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;timedelta&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;days&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;date&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;year&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;year&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;year&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="n"&gt;date&lt;/span&gt;
        &lt;span class="n"&gt;date&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;date&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;delta&lt;/span&gt;

&lt;span class="n"&gt;day_numbers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;defaultdict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;date&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;generate_year&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])):&lt;/span&gt;
    &lt;span class="n"&gt;day_numbers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isoweekday&lt;/span&gt;&lt;span class="p"&gt;()]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;strftime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;%m&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;

&lt;span class="n"&gt;day_odd_prob&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;day&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;nums&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;day_numbers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;odd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="n"&gt;even&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;even&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;odd&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="n"&gt;day_odd_prob&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;day&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;odd&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;odd&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;even&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;DAYS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Mon&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Tues&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Wed&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Thurs&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Fri&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Sat&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Sun&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;day&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;sorted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;day_odd_prob&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;()):&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;{}&lt;/span&gt;&lt;span class="se"&gt;\t&lt;/span&gt;&lt;span class="s1"&gt;{}&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DAYS&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;day&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;day_odd_prob&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;day&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now if for some bizarre reason you really want to know what proportion of Thursdays (or any other
day) fall on odd-numbered days in any given year, you can find out:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ python3 odd_days.py 2012
Mon     0.49056603773584906
Tues    0.5192307692307693
Wed     0.4807692307692308
Thurs   0.5192307692307693
Fri     0.5
Sat     0.5
Sun     0.5094339622641509

$ python3 odd_days.py 2013
Mon     0.5
Tues    0.49056603773584906
Wed     0.5192307692307693
Thurs   0.5
Fri     0.5192307692307693
Sat     0.5
Sun     0.5
&lt;/pre&gt;
</summary><category term="python"></category></entry><entry><title>Optional Positional Arguments with argparse</title><link href="http://alanbriolat.co.uk/optional-positional-arguments-with-argparse.html" rel="alternate"></link><published>2012-05-29T00:00:00+01:00</published><updated>2012-05-29T00:00:00+01:00</updated><author><name>Alan Briolat</name></author><id>tag:alanbriolat.co.uk,2012-05-29:optional-positional-arguments-with-argparse.html</id><summary type="html">&lt;p&gt;Today I helped somebody in the Python IRC channel with a question about
combining required, optional and multi-value positional arguments in Python's
&lt;a class="reference external" href="http://docs.python.org/library/argparse.html"&gt;argparse&lt;/a&gt; module.  This is actually pretty easy to do, but not immediately
obvious, so here's the example I put together.  I took hints from the first
example in the &lt;a class="reference external" href="http://docs.python.org/library/argparse.html"&gt;argparse&lt;/a&gt; documentation, and also &lt;a class="reference external" href="http://stackoverflow.com/a/4480202/373258"&gt;this StackOverflow answer&lt;/a&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;argparse&lt;/span&gt;

&lt;span class="n"&gt;parser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;argparse&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ArgumentParser&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_argument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;foo&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;a&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_argument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;bar&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;b&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;nargs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;?&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_argument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;baz&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="n"&gt;nargs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;*&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parse_args&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And does it work?  Apparently so.  Some example output from running this
script:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ python test.py
usage: test.py [-h] foo [bar] [baz [baz ...]]
test.py: error: too few arguments

$ python test.py x
Namespace(bar='b', baz=[], foo='x')

$ python test.py x y
Namespace(bar='y', baz=[], foo='x')

$ python test.py x y z
Namespace(bar='y', baz=['z'], foo='x')

$ python test.py x y z a
Namespace(bar='y', baz=['z', 'a'], foo='x')
&lt;/pre&gt;
</summary><category term="python"></category></entry><entry><title>Using Nautilus in Xubuntu 11.10</title><link href="http://alanbriolat.co.uk/using-nautilus-in-xubuntu-11-10.html" rel="alternate"></link><published>2012-01-09T00:00:00+00:00</published><updated>2012-01-09T00:00:00+00:00</updated><author><name>Alan Briolat</name></author><id>tag:alanbriolat.co.uk,2012-01-09:using-nautilus-in-xubuntu-11-10.html</id><summary type="html">&lt;p&gt;Like many people, I've found the new things in the Linux desktop environment world - i.e. GNOME 3
and Unity - to be more of a hindrance than a help. For this reason I've switched to Xubuntu, which
allows me to stick to my previous multi-window multi-desktop multi-monitor workflow.&lt;/p&gt;
&lt;p&gt;People making this transition might not find themselves too comfortable with XFCE's file manager,
Thunar. Switching the default file manager to Nautilus (GNOME's file manager) is actually pretty
simple, however there are a few issues with correctly handling the desktop background and icons. The
setup described here will switch the default file manager to Nautilus, but leave XFCE and Thunar in
control of the desktop. This is because Nautilus, if allowed to control the desktop icons, will also
try and set the desktop background. Complete control of its background settings  is only possible by
manually editing dconf settings, or using &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;gnome-control-center&lt;/span&gt;&lt;/tt&gt; which depends on the whole of
GNOME being installed. Of course if you already have desktop icons disabled you won't notice any
change in desktop handling at all.&lt;/p&gt;
&lt;p&gt;So on with the show.  Obviously, you first need to install Nautilus:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
sudo apt-get install nautilus
&lt;/pre&gt;
&lt;p&gt;Next, you need to tell XFCE to use Nautilus as the default file manager. This can be done through:
XFCE menu -&amp;gt; Settings -&amp;gt; Settings Manager -&amp;gt; Preferred Applications -&amp;gt; &amp;quot;Utilities&amp;quot; tab -&amp;gt; &amp;quot;File
Manager&amp;quot; drop-down.&lt;/p&gt;
&lt;p&gt;Now any time you open a folder you should get Nautilus instead of Thunar. Unfortunately the first
time you do this Nautilus will realise it isn't managing the desktop and will try to do so. This
behaviour can be disabled by setting the appropriate dconf entry:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
sudo apt-get install dconf-tools
dconf write /org/gnome/desktop/background/show-desktop-icons false
&lt;/pre&gt;
&lt;p&gt;If you have desktop icons enabled in XFCE what you have is an instance of Thunar displaying the
contents of &lt;tt class="docutils literal"&gt;~/Desktop&lt;/tt&gt;, which means any directory you double-click on will also launch in Thunar.
This probably isn't what we want, but unfortunately we can't change this default behaviour.  What we
can do is make it easier to launch the directory in Nautilus by adding a &amp;quot;custom action&amp;quot; - the end
result will be a &amp;quot;Open in Nautilus&amp;quot; item in the context menu when you right click directories on the
desktop.&lt;/p&gt;
&lt;p&gt;Launch Thunar and open the &amp;quot;Custom Actions&amp;quot; dialog (Edit -&amp;gt; Configure custom actions...). Add a new
action, setting the command to &lt;tt class="docutils literal"&gt;nautilus %F&lt;/tt&gt; and making sure only &amp;quot;Directories&amp;quot; is checked on the
&amp;quot;Appearance Conditions&amp;quot; tab. Also check &amp;quot;Startup notification&amp;quot; and set the icon to be the correct
one for Nautilus.&lt;/p&gt;
&lt;p&gt;Of course the nicest result would have been to have Nautilus managing the desktop instead. At first
glance this looks like it should be possible, since there is a
&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;/org/gnome/desktop/background/draw-background&lt;/span&gt;&lt;/tt&gt;
setting in dconf, however changing this setting has no effect on Nautilus' behaviour.&lt;/p&gt;
</summary><category term="ubuntu"></category><category term="xubuntu"></category><category term="xfce"></category><category term="nautilus"></category></entry><entry><title>Spoofing MAC address on Ubuntu Maverick</title><link href="http://alanbriolat.co.uk/spoofing-mac-address-on-ubuntu-maverick.html" rel="alternate"></link><published>2010-10-12T00:00:00+01:00</published><updated>2010-10-12T00:00:00+01:00</updated><author><name>Alan Briolat</name></author><id>tag:alanbriolat.co.uk,2010-10-12:spoofing-mac-address-on-ubuntu-maverick.html</id><summary type="html">&lt;p&gt;Continuing the trend of accidentally disabling hacks that people rely on, it now no longer appears
to be possible to set your network card's MAC by adding a line like the following to
&lt;tt class="docutils literal"&gt;/etc/rc.local&lt;/tt&gt;:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
ifconfig eth0 hw ether 00:0C:xx:xx:xx:xx
&lt;/pre&gt;
&lt;p&gt;It seems that for some reason something (presumably NetworkManager) is resetting the device's MAC
address when the computer wakes from suspend.  However, at the same time, the &amp;quot;Cloned MAC address&amp;quot;
field has been added to NetworkManager's &amp;quot;Edit connection&amp;quot; dialog, and this is where your desired
MAC address should be entered.&lt;/p&gt;
</summary><category term="ubuntu"></category><category term="networkmanager"></category></entry><entry><title>Batch Re-tabbing Files with Vim</title><link href="http://alanbriolat.co.uk/batch-re-tabbing-files-with-vim.html" rel="alternate"></link><published>2010-05-23T00:00:00+01:00</published><updated>2010-05-23T00:00:00+01:00</updated><author><name>Alan Briolat</name></author><id>tag:alanbriolat.co.uk,2010-05-23:batch-re-tabbing-files-with-vim.html</id><summary type="html">&lt;p&gt;So you have your favourite tabbing convention, but you've ended up with some files in some other
convention, for example tabs instead of 4 spaces.  If you use Vim and already have it set up to your
liking, the &lt;tt class="docutils literal"&gt;:retab&lt;/tt&gt; command will replace indents in the current buffer with those matching your
convention.  It's a bit tedious to do this manually for each file, so if you trust Vim not to make a
mistake (or you're using version control) you can use a bit of scripting-fu to make it easier:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt; F in *.&lt;span class="o"&gt;{&lt;/span&gt;c,h&lt;span class="o"&gt;}&lt;/span&gt;pp &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; vim -c &lt;span class="s2"&gt;&amp;quot;:retab&amp;quot;&lt;/span&gt; -c &lt;span class="s2"&gt;&amp;quot;:wq&amp;quot;&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$F&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;done&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
</summary><category term="vim"></category><category term="bash"></category></entry><entry><title>Remapping Mouse Buttons on Ubuntu Lucid</title><link href="http://alanbriolat.co.uk/remapping-mouse-buttons-on-ubuntu-lucid.html" rel="alternate"></link><published>2010-04-23T00:00:00+01:00</published><updated>2010-04-23T00:00:00+01:00</updated><author><name>Alan Briolat</name></author><id>tag:alanbriolat.co.uk,2010-04-23:remapping-mouse-buttons-on-ubuntu-lucid.html</id><summary type="html">&lt;p&gt;For ergonomic reasons &lt;a class="reference external" href="http://alanbriolat.co.uk/mouse-button-remapping-with-hal.html"&gt;(discussed previously)&lt;/a&gt; I like a side button on my
mouse to act as a middle button instead.  Unfortunately there still doesn't seem to be an &amp;quot;easy&amp;quot; way
to remap mouse buttons in Linux, and what's more the method of changing such settings seems to keep
changing.  To achieve the same results in Ubuntu Lucid, I added an Xorg configuration fragment at
&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;/usr/lib/X11/xorg.conf.d/20-logitech-mx1100.conf&lt;/span&gt;&lt;/tt&gt;:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
Section &amp;quot;InputClass&amp;quot;
        Identifier &amp;quot;Logitech MX1100 button remap&amp;quot;
        MatchProduct &amp;quot;Logitech USB Receiver&amp;quot;
        MatchDevicePath &amp;quot;/dev/input/event*&amp;quot;
        Option &amp;quot;ButtonMapping&amp;quot; &amp;quot;1 2 3 4 5 6 7 2 9 10&amp;quot;
EndSection
&lt;/pre&gt;
&lt;p&gt;As with the previous method, &lt;tt class="docutils literal"&gt;xinput list&lt;/tt&gt; should give you the product string to use for
&lt;tt class="docutils literal"&gt;MatchProduct&lt;/tt&gt;.&lt;/p&gt;
&lt;div class="admonition note"&gt;
&lt;p class="first admonition-title"&gt;Note&lt;/p&gt;
&lt;p class="last"&gt;In Ubuntu 10.10 &lt;tt class="docutils literal"&gt;/usr/lib/X11/xorg.conf.d/&lt;/tt&gt; became &lt;tt class="docutils literal"&gt;/usr/share/X11/xorg.conf.d/&lt;/tt&gt;.  Since at
least 11.04 &lt;tt class="docutils literal"&gt;/etc/X11/xorg.conf.d/&lt;/tt&gt; is read in the same way, if it exists, and preferably this
configuration snippet should live there.&lt;/p&gt;
&lt;/div&gt;
</summary><category term="ubuntu"></category><category term="xorg"></category></entry><entry><title>Fixing ugly Qt fonts in GNOME</title><link href="http://alanbriolat.co.uk/fixing-ugly-qt-fonts-in-gnome.html" rel="alternate"></link><published>2010-04-17T00:00:00+01:00</published><updated>2010-04-17T00:00:00+01:00</updated><author><name>Alan Briolat</name></author><id>tag:alanbriolat.co.uk,2010-04-17:fixing-ugly-qt-fonts-in-gnome.html</id><summary type="html">&lt;p&gt;So far every time I've used Qt applications under GNOME, especially VirtualBox, I've found the Qt
font rendering to be appalling.  See this screenshot of VirtualBox alongside the GNOME appearance
dialog:&lt;/p&gt;
&lt;a class="reference external image-reference" href="http://alanbriolat.co.uk/static/images/virtualbox_fonts_1.png"&gt;&lt;img alt="|filename|/images/virtualbox_fonts_1.png" src="http://alanbriolat.co.uk/static/images/virtualbox_fonts_1.png" style="width: 100%;" /&gt;&lt;/a&gt;
&lt;p&gt;As you can see, most of my font settings are at the default &amp;quot;Sans&amp;quot; font.  The &amp;quot;Sans&amp;quot; and &amp;quot;Sans
serif&amp;quot; fonts, at least in recent Ubuntu releases, refer to the corresponding DejaVu font variants
(previously it was Bitstream Vera).  However as I found out through experimentation, whilst Qt is
obeying my font settings, the generic &amp;quot;Sans&amp;quot; font seems to mean something completely different (at
least to Qt4).  If I instead specify the DejaVu fonts directly in my font settings, the correct font
rendering is used:&lt;/p&gt;
&lt;a class="reference external image-reference" href="http://alanbriolat.co.uk/static/images/virtualbox_fonts_2.png"&gt;&lt;img alt="|filename|/images/virtualbox_fonts_2.png" src="http://alanbriolat.co.uk/static/images/virtualbox_fonts_2.png" style="width: 100%;" /&gt;&lt;/a&gt;
&lt;p&gt;So that's it: if you're using GNOME and you seem to get a Qt font rendering that doesn't match your
GTK font rendering, try using a more specific font.  (I haven't got a clue what &amp;quot;Sans&amp;quot; &lt;em&gt;actually&lt;/em&gt;
means to GNOME, but it doesn't appear to be a font in it's own right.)&lt;/p&gt;
</summary><category term="gnome"></category><category term="qt"></category><category term="fonts"></category></entry><entry><title>When Dynamic Typing Goes Wrong</title><link href="http://alanbriolat.co.uk/when-dynamic-typing-goes-wrong.html" rel="alternate"></link><published>2009-07-08T00:00:00+01:00</published><updated>2009-07-08T00:00:00+01:00</updated><author><name>Alan Briolat</name></author><id>tag:alanbriolat.co.uk,2009-07-08:when-dynamic-typing-goes-wrong.html</id><summary type="html">&lt;p&gt;Yesterday I found out first-hand how using a dynamically typed language can get you into trouble in
unexpected ways whilst writing unit tests for &lt;a class="reference external" href="http://codescape.net/csf/"&gt;CSF&lt;/a&gt; (my PHP framework).&lt;/p&gt;
&lt;p&gt;Take a look at this code---what do you think it should do?&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="x"&gt;$foo = &amp;#39;bar&amp;#39;;&lt;/span&gt;
&lt;span class="x"&gt;var_dump(isset($foo[&amp;#39;xyz&amp;#39;]));&lt;/span&gt;
&lt;span class="x"&gt;var_dump($foo[&amp;#39;xyz&amp;#39;]);&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Most people would assume that indexing a string on another string is nonsensical, and they would be
right---in PHP you can only index a string with an integer.  The logical extension would be that
&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;isset($foo['xyz']&lt;/span&gt;&lt;/tt&gt;) would be false and/or any attempt to index using a string would raise an
error.  And that is where they would be wrong.  In fact, &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;isset($foo['xyz'])&lt;/span&gt;&lt;/tt&gt; is &lt;tt class="docutils literal"&gt;true&lt;/tt&gt;, and
&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;$foo['xyz']&lt;/span&gt;&lt;/tt&gt; is &lt;tt class="docutils literal"&gt;&amp;quot;b&amp;quot;&lt;/tt&gt;.&lt;/p&gt;
&lt;p&gt;PHP is &lt;a class="reference external" href="http://en.wikipedia.org/wiki/Weak_typing"&gt;weakly typed&lt;/a&gt;, which generally means there is a lot of implicit casting between types going
on.  In this case, while indexing a string can only be done with an integer, there is an implicit
cast from a string to an integer, so this cast is performed and the result used as the index.
However, the usual way of converting from a string to an integer is to use digits (0--9) up until
the first non-digit character (after taking the minus sign into account if there is one).  This
means the integer value of 'xyz' is 0, since there are no digits to add up.&lt;/p&gt;
&lt;p&gt;When explained, this may seem like sensible behaviour, but let's think about the effect this has
when coding and debugging: if you accidentally index a string with another string somewhere, you
won't know about it straight away.  Instead, you'll just be getting &amp;quot;wrong&amp;quot; values and scratching
your head over where they could be coming from.  I'm of the opinion that if you can only index a
string on an integer, then indexing it on a string should be at the very least a warning.  Silently
doing something completely different isn't very helpful.&lt;/p&gt;
&lt;p&gt;And so that this doesn't seem like a nonsensical contrived example, here's a reduced version of the
code that raised the issue:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="x"&gt;function get_item($array, $path, $default)&lt;/span&gt;
&lt;span class="x"&gt;{&lt;/span&gt;
&lt;span class="x"&gt;    $item = $array;&lt;/span&gt;
&lt;span class="x"&gt;    foreach (explode(&amp;#39;.&amp;#39;, $path) as $p)&lt;/span&gt;
&lt;span class="x"&gt;    {&lt;/span&gt;
&lt;span class="x"&gt;        if (!isset($item[$p]))&lt;/span&gt;
&lt;span class="x"&gt;        {&lt;/span&gt;
&lt;span class="x"&gt;            if (func_num_args() &amp;lt; 3)&lt;/span&gt;
&lt;span class="x"&gt;                throw new ItemNotFound($path);&lt;/span&gt;
&lt;span class="x"&gt;            else&lt;/span&gt;
&lt;span class="x"&gt;                return $default;&lt;/span&gt;
&lt;span class="x"&gt;        }&lt;/span&gt;
&lt;span class="x"&gt;        else&lt;/span&gt;
&lt;span class="x"&gt;        {&lt;/span&gt;
&lt;span class="x"&gt;            $item = $item[$p];&lt;/span&gt;
&lt;span class="x"&gt;        }&lt;/span&gt;
&lt;span class="x"&gt;    }&lt;/span&gt;
&lt;span class="x"&gt;    return $item;&lt;/span&gt;
&lt;span class="x"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;What this function does is traverse a multi-dimensional array with a &amp;quot;key path&amp;quot;, i.e.
&lt;tt class="docutils literal"&gt;&amp;quot;key1.key2&amp;quot;&lt;/tt&gt; gets &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;$array['key1']['key2']&lt;/span&gt;&lt;/tt&gt;.  Since &lt;tt class="docutils literal"&gt;isset()&lt;/tt&gt; is the most common way people
check the existence of an array, this is what I used here.  However, things break down in this
example:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="x"&gt;$array = array(&amp;#39;foo&amp;#39; =&amp;gt; &amp;#39;bar&amp;#39;);&lt;/span&gt;
&lt;span class="x"&gt;$x = get_item($array, &amp;#39;foo.xyz&amp;#39;);&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The expected behaviour is that the exception should be thrown, since &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;$array['foo']&lt;/span&gt;&lt;/tt&gt; is not an
array with a &lt;tt class="docutils literal"&gt;&amp;quot;xyz&amp;quot;&lt;/tt&gt; key, but the issue described above instead leads this to return &lt;tt class="docutils literal"&gt;&amp;quot;b&amp;quot;&lt;/tt&gt;.&lt;/p&gt;
&lt;p&gt;In this case, there is a way around it: what I really should have been using is the following check:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="x"&gt;if (is_array($item) &amp;amp;&amp;amp; array_key_exists($p, $item))&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This has more interesting consequences---it means that a very very large number of people are using
&lt;tt class="docutils literal"&gt;isset()&lt;/tt&gt; where they mean &lt;tt class="docutils literal"&gt;is_array() &amp;amp;&amp;amp; array_key_exists()&lt;/tt&gt;.  As for me, I just fixed a bug in
my code exposed by a unit test, so I'm happy (even if a little bewildered by PHP).&lt;/p&gt;
</summary><category term="php"></category></entry><entry><title>Why .NET Won't Beat Java (Yet)</title><link href="http://alanbriolat.co.uk/why-net-wont-beat-java-yet.html" rel="alternate"></link><published>2009-06-23T00:00:00+01:00</published><updated>2009-06-23T00:00:00+01:00</updated><author><name>Alan Briolat</name></author><id>tag:alanbriolat.co.uk,2009-06-23:why-net-wont-beat-java-yet.html</id><summary type="html">&lt;p&gt;It's been no real secret that the .NET CLR (Common Language Runtime) has been Microsoft's answer to
Java.  Garbage collection, bytecode compilation, large set of core libraries, it's all there.  But
there is a problem that I've encountered recently: distribution size and install base.&lt;/p&gt;
&lt;p&gt;A fairly clean Windows XP machine is fairly certain to not have anything higher than .NET 1.x
installed.  Anything really compelling in the .NET framework requires 3.5.  This means somehow you
need to get version 3.5 onto the machine somehow.  This isn't a problem in Windows Vista and later,
which include the framework.  Microsoft's answer to simple deployment is it's &amp;quot;ClickOnce&amp;quot; system,
where an application automatically installs .NET from the Internet (if necessary) before installing
itself.  Sure, it's a 60MB download, but it only needs to be done once.&lt;/p&gt;
&lt;p&gt;The real issue is when you can't guarantee an Internet connection or a working .NET 3.5
installation.  At this point you must resort to the offline installation, and this is where .NET and
Java are very different.  For Java 1.6 SE, the offline installer is 16MB for Windows 32-bit.  For
.NET 3.5, the offline installer is a &lt;em&gt;200MB&lt;/em&gt; universal package, with no way to cut out the parts you
don't need.  Java in fact is so small relatively speaking that many applications actually include
the JRE in their package (for example OpenOffice - 148MB with JRE vs. 134MB without), whereas .NET
can turn a 10MB application into a 210MB monstrosity.&lt;/p&gt;
&lt;p&gt;Now in my particular situation, I'm embarassed to have chosen to use C#/.NET/WPF for a simple tool
at work.  For programming the tool itself, it was certainly the fastest option - other kinds of
Windows programming, e.g. MFC or Forms, just look painful, and I thought the barrier to entry would
be lower than Java.  However this 1MB tool requires the 200MB .NET offline installer to be carted
around with it because the network it's used on is completely separate from the Internet.&lt;/p&gt;
&lt;p&gt;.NET will only be &lt;em&gt;really&lt;/em&gt; appealing once it's ubiquitous, but then &amp;quot;critical mass&amp;quot; is one of the
big problems for lots of software. For now, I think I'm going to try Java next time...&lt;/p&gt;
</summary><category term=".net"></category><category term="java"></category></entry><entry><title>Mouse Button Remapping with HAL</title><link href="http://alanbriolat.co.uk/mouse-button-remapping-with-hal.html" rel="alternate"></link><published>2009-06-13T00:00:00+01:00</published><updated>2009-06-13T00:00:00+01:00</updated><author><name>Alan Briolat</name></author><id>tag:alanbriolat.co.uk,2009-06-13:mouse-button-remapping-with-hal.html</id><summary type="html">&lt;p&gt;I've had a Logitech MX1000 mouse for a few years now, and the two most important features for me
have been the ergonomic build and the few extra buttons.  Something I've always found with
many-buttoned mice is that the side button closest to the thumb is a much more ergonomic way to
&amp;quot;middle click&amp;quot; than the actual middle mouse button---it's a much more natural motion.  Middle clicks
are quite useful these days, especially with them being a standard way of closing tabs (and opening
them in browsers), and having such a popular button perched on a rocking and rolling peak is far
from ideal.&lt;/p&gt;
&lt;p&gt;Since I'm primarily a Linux user, I don't have Logitech's own SetPoint software at my disposal, so
I've always had to find a way to get this functionality in some other way.  When I first got the
mouse, this method involved deliberately using a &amp;quot;basic&amp;quot; mouse driver (referred to in &lt;tt class="docutils literal"&gt;xorg.conf&lt;/tt&gt;
as &amp;quot;IMPS/2&amp;quot;), which didn't support many mouse buttons.  The effect was that the button mappings
wrapped around, leaving button 8, my preferred &amp;quot;middle click&amp;quot;, mapped to button 2 (8 mod 3), the
real middle button.&lt;/p&gt;
&lt;p&gt;Unfortunately, newer Xorg versions became smarter and better capable of handling more buttons, and
this workaround ceased to function.  For the next while, I used something even more hackish:
&lt;a class="reference external" href="http://freshmeat.net/projects/xbindkeys/"&gt;xbindkeys&lt;/a&gt; combined with &lt;a class="reference external" href="http://xmacro.sourceforge.net/"&gt;xmacroplay&lt;/a&gt; to simulate a middle click with the following part of my
.xbindkeysrc:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
&amp;quot;echo ButtonRelease 8 ButtonPress 2 ButtonRelease 2 | xmacroplay -d 0 :0.0 &amp;amp;&amp;quot;
    b:8
&lt;/pre&gt;
&lt;p&gt;The downside to this solution is that there are some cases where the button events don't work
correctly, one of them being open-in-tab from a bookmark menu in Firefox.  It seemed the best
solution would be to get Xorg to remap the buttons in such a way that button 8 really was just an
extra button 2.  The &amp;quot;xinput&amp;quot; utility lets you set button maps in this way---&lt;a class="reference external" href="https://wiki.ubuntu.com/X/Config/Input#Example:_Disabling_middle-mouse_button_paste_on_a_scrollwheel_mouse"&gt;this wiki entry&lt;/a&gt;
shows how to remap mouse buttons (even if for a different purpose).&lt;/p&gt;
&lt;p&gt;This method worked fine, and I put it in my startup programs for GNOME, but it didn't persist after
suspend/resume.  It appears that when resuming, USB devices get &amp;quot;reattached&amp;quot;, and therefore don't
keep the settings applied to them the last time they were attached.  The workaround for this is to
set a policy using a HAL (Hardware Abstraction Layer) &lt;tt class="docutils literal"&gt;.fdi&lt;/tt&gt; file.  These files live in
&lt;tt class="docutils literal"&gt;/etc/hal/fdi/policy&lt;/tt&gt; (at least they do on Ubuntu) and allow you to set various properties on
input devices.  &lt;a class="reference external" href="https://help.ubuntu.com/community/Logitech_Marblemouse_USB"&gt;This page on the Ubuntu wiki&lt;/a&gt; gave me the recipe I needed to remap buttons based
on the device name.  I ended up with the following &lt;tt class="docutils literal"&gt;.fdi&lt;/tt&gt; file (which I saved at
&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;/etc/hal/fdi/policy/logitech-mx1000.fdi&lt;/span&gt;&lt;/tt&gt;):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;deviceinfo&lt;/span&gt; &lt;span class="na"&gt;version=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;0.2&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;&amp;lt;!-- Remap Logitech MX1000 buttons so that the most accessible side button&lt;/span&gt;
&lt;span class="c"&gt;     acts as a middle button --&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;device&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;match&lt;/span&gt; &lt;span class="na"&gt;key=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;info.product&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;string=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Logitech USB RECEIVER&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;merge&lt;/span&gt; &lt;span class="na"&gt;key=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;input.x11_options.ButtonMapping&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;string&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;1 2 3 4 5 6 7 2&lt;span class="nt"&gt;&amp;lt;/merge&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/match&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/device&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;/deviceinfo&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now, whenever my Logitech mouse is connected, it gets the buttons remapped---this includes when
resuming from suspend.  Problem solved... until things are changed again of course!&lt;/p&gt;
</summary><category term="ubuntu"></category><category term="xorg"></category><category term="hal"></category></entry><entry><title>The Rise and Fail of Facebook</title><link href="http://alanbriolat.co.uk/the-rise-and-fail-of-facebook.html" rel="alternate"></link><published>2009-06-10T00:00:00+01:00</published><updated>2009-06-10T00:00:00+01:00</updated><author><name>Alan Briolat</name></author><id>tag:alanbriolat.co.uk,2009-06-10:the-rise-and-fail-of-facebook.html</id><summary type="html">&lt;p&gt;A recent &lt;a class="reference external" href="http://lifehacker.com/5284511/facebook-purity-removes-eye+gouging-quiz-updates"&gt;Lifehacker story&lt;/a&gt; about a Greasemonkey script to remove quiz stuff from &lt;a class="reference external" href="http://www.facebook.com/"&gt;Facebook&lt;/a&gt; made me
realise something: &lt;em&gt;you know your site is too &amp;quot;web 2.0&amp;quot; when users are going out of their way to
remove features.&lt;/em&gt; A quick &lt;a class="reference external" href="http://userscripts.org/scripts/search?q=facebook&amp;amp;amp;sort=rating"&gt;search on Userscripts.org&lt;/a&gt; reveals that a substantial proportion of the
Facebook-related scripts are either for removing features or auto-playing game applications.&lt;/p&gt;
&lt;p&gt;I feel that Facebook started off pretty well.  The initial target audience seemed to be students,
and that's what most of the users were.  It was friendly and uncluttered, compared to other social
networking sites like MySpace.  This spread to a wider audience, first sucking in kids and then
adults.  This was less than ideal for some, the idea of their parents on a social networking site
being horrifying, but still not a disaster.&lt;/p&gt;
&lt;p&gt;But in the midst of all this, the apocalypse happened: a powerful API which allowed other people to
extend the functionality of Facebook by creating applications that people could add to their
account.  Gradually users became inundated with an unstoppable torrent of application requests,
caused by application developers making the &amp;quot;tell all your friends&amp;quot; step seem (or be) necessary to
using their application.  The average user's profile became a mess of applications competing for
screen space.  The target audience became those who have the time to play endless Flash games,
answer endless quizzes, and generally clutter the &amp;quot;requests&amp;quot; page of their friends.&lt;/p&gt;
&lt;p&gt;And so Facebook became &lt;a class="reference external" href="http://myspace.com/"&gt;MySpace&lt;/a&gt; 2.0---gaudy and cluttered, with infinite ability to add more
clutter.  Maybe the lesson learned is that the moment you allow anything &amp;quot;shiny&amp;quot; in a social
networking site, your demographic will degenerate to schoolkids who want to fill their profiles with
as much of it as possible.&lt;/p&gt;
&lt;p&gt;Personally, I've reduced my Facebook interaction for the past 2 years to having the site email me
when anybody says something directly to me either via message or on my &amp;quot;wall&amp;quot;.  There is just too
much clutter now for me to wade through the endless application requests, friend requests from
people I don't know, and news feed items generated by the latest viral quiz.  And maybe pictures of
friends getting drunk have lost their novelty value...&lt;/p&gt;
</summary><category term="facebook"></category><category term="myspace"></category></entry><entry><title>Spectacular IE7 CSS box model failure</title><link href="http://alanbriolat.co.uk/spectacular-ie7-css-box-model-failure.html" rel="alternate"></link><published>2009-05-17T00:00:00+01:00</published><updated>2009-05-17T00:00:00+01:00</updated><author><name>Alan Briolat</name></author><id>tag:alanbriolat.co.uk,2009-05-17:spectacular-ie7-css-box-model-failure.html</id><summary type="html">&lt;p&gt;When re-theming &lt;a class="reference external" href="http://dokuwiki.org/"&gt;DokuWiki&lt;/a&gt; to fit in with the general look-and-feel of my blog, I thought it would
look good to have buttons with images relevant to what they did.  Having created the necessary, CSS,
I subjected it to my &lt;a class="reference external" href="http://iris.codescape.net/~alan/IE-rendering-fail-3.png"&gt;multi-browser test bed&lt;/a&gt; (actually a Windows XP virtual machine with the
latest versions of the top 5 browsers running in it).  The CSS I used was along the lines of this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="nc"&gt;.dokuwiki&lt;/span&gt; &lt;span class="nt"&gt;form&lt;/span&gt;&lt;span class="nc"&gt;.btn_show&lt;/span&gt; &lt;span class="nc"&gt;.button&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nb"&gt;padding&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1px&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;1px&lt;/span&gt; &lt;span class="m"&gt;16px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nb"&gt;background&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;transparent&lt;/span&gt; &lt;span class="sx"&gt;url(images/page.png)&lt;/span&gt; &lt;span class="m"&gt;0px&lt;/span&gt; &lt;span class="m"&gt;1px&lt;/span&gt; &lt;span class="nb"&gt;no-repeat&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nb"&gt;border&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;none&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;One thing that became apparent is that IE7 has absolutely no idea how to render this.  The correct
rendering (as produced by Firefox 3 and all the other browsers) is this:&lt;/p&gt;
&lt;img alt="|filename|/images/button-background-image-ff3.png" class="align-center" src="http://alanbriolat.co.uk/static/images/button-background-image-ff3.png" /&gt;
&lt;p&gt;IE7's take on rendering this looked more like this:&lt;/p&gt;
&lt;img alt="|filename|/images/button-background-image-ie7.png" class="align-center" src="http://alanbriolat.co.uk/static/images/button-background-image-ie7.png" /&gt;
&lt;p&gt;After a bit more experimentation, I came up with the following illustration which roughly shows what
is happening:&lt;/p&gt;
&lt;img alt="|filename|/images/IE7-button-rendering.png" class="align-center" src="http://alanbriolat.co.uk/static/images/IE7-button-rendering.png" /&gt;
&lt;p&gt;The nice thing is that this is fixed in the upcoming IE8, so I've taken the stress-free approach;
since it's a relatively &amp;quot;minor&amp;quot; visual bug, there's no sense it tearing my hair out trying to make
it render correctly everywhere.  On this occasion I've decided that people can either deal with the
fact their browser is behind the times, or upgrade, or wait for the upgrade to happen for them.&lt;/p&gt;
</summary><category term="css"></category><category term="internet explorer"></category></entry><entry><title>Quick and dirty screen scraping of UK MP expenses data</title><link href="http://alanbriolat.co.uk/quick-and-dirty-screen-scraping-of-uk-mp-expenses-data.html" rel="alternate"></link><published>2009-05-13T00:00:00+01:00</published><updated>2009-05-13T00:00:00+01:00</updated><author><name>Alan Briolat</name></author><id>tag:alanbriolat.co.uk,2009-05-13:quick-and-dirty-screen-scraping-of-uk-mp-expenses-data.html</id><summary type="html">&lt;p&gt;A dominating story in the news recently has been that of UK Members of Parliament &amp;quot;abusing&amp;quot; the
expenses system.  As part of this, expense claims data has been released to the public, but
unsurprisingly not in a simple CSV format that just anybody can play with.  All I could find were
PDF files and news sites representing the data in their own way.&lt;/p&gt;
&lt;p&gt;This led me to wonder how easy it would be to &amp;quot;scrape&amp;quot; the data from one of these sites.  Having
heard about &lt;a class="reference external" href="http://www.crummy.com/software/BeautifulSoup/"&gt;BeautifulSoup&lt;/a&gt;, a Python HTML &amp;quot;tag soup&amp;quot; parser, I opened up an interactive Python
session and started to play with the data from &lt;a class="reference external" href="http://news.bbc.co.uk/1/hi/uk_politics/8044207.stm"&gt;this BBC News page&lt;/a&gt;.  Luckily for me, the BBC
page's HTML isn't &lt;em&gt;too&lt;/em&gt; ugly, so figuring out how to get the data rows wasn't that hard.&lt;/p&gt;
&lt;p&gt;The end result is the following Python script which scrapes the data from the BBC News page and
saves it in both CSV and JSON formats&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://alanbriolat.co.uk/static/downloads/mp-expenses-extract.py"&gt;mp-expenses-extract.py&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://alanbriolat.co.uk/static/downloads/mp-expenses.csv"&gt;mp-expenses.csv&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://alanbriolat.co.uk/static/downloads/mp-expenses.json"&gt;mp-expenses.json&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</summary><category term="python"></category></entry><entry><title>Mozilla/1.22 (compatible; MSIE 2.0; Windows 95)</title><link href="http://alanbriolat.co.uk/mozilla122-compatible-msie-20-windows-95.html" rel="alternate"></link><published>2009-05-11T00:00:00+01:00</published><updated>2009-05-11T00:00:00+01:00</updated><author><name>Alan Briolat</name></author><id>tag:alanbriolat.co.uk,2009-05-11:mozilla122-compatible-msie-20-windows-95.html</id><summary type="html">&lt;p&gt;Browsing the visitor stats today, I found this little gem:&lt;/p&gt;
&lt;img alt="|filename|/images/ancient-browser1.png" class="align-center" src="http://alanbriolat.co.uk/static/images/ancient-browser1.png" /&gt;
&lt;p&gt;&amp;quot;Mozilla/1.22 (compatible; MSIE 2.0; Windows 95)&amp;quot;?  Who uses such a browser?  My bet is on it being
a zombie machine that somebody has completely forgotten about, which would explain the several other
hits I have from versions of IE before 5.0...  These visitors turn up, hit the same page repeatedly,
and then leave.  Unfortunately I deleted my spam before seeing this, otherwise I'd be able to verify
this theory.  Maybe I'll look more closely next time.&lt;/p&gt;
</summary><category term="internet explorer"></category></entry><entry><title>Tpl - A tiny PHP template engine</title><link href="http://alanbriolat.co.uk/tpl-a-tiny-php-template-engine.html" rel="alternate"></link><published>2009-04-30T00:00:00+01:00</published><updated>2009-04-30T00:00:00+01:00</updated><author><name>Alan Briolat</name></author><id>tag:alanbriolat.co.uk,2009-04-30:tpl-a-tiny-php-template-engine.html</id><summary type="html">&lt;p&gt;While developing &lt;a class="reference external" href="http://codescape.net/csf/"&gt;CodeScape Framework&lt;/a&gt; I came up with a simple template engine that instead of
implementing it's own language just provided some structure-related hooks, and I've now got around
to separating out and releasing &lt;a class="reference external" href="http://codescape.net/tpl/"&gt;Tpl&lt;/a&gt;, a simple, self-contained, hierarchical template engine for
PHP.&lt;/p&gt;
&lt;p&gt;Tpl's role is centred around template structure, not content---it's not a huge library of helper
functions for creating links, displaying images, etc.  Like any template engine, the aim is to
separate presentation logic from application logic, but it doesn't attempt this by creating a
template language.  PHP is &lt;a class="reference external" href="http://php.net/manual/en/history.php.php"&gt;designed&lt;/a&gt; to be interleaved with &amp;quot;static&amp;quot; output, which means it's
already a template language.  Trying to replace it for the purpose of templating rarely adds
anything useful, incurs hefty performance overheads (which you then have to mitigate with caching)
and usually is more restrictive than PHP.  To me, that doesn't seem like a sensible application of
effort.  Instead Tpl provides its functionality in the form of hooks---functions which are called
from within the template to specify the structure.  Instead of PHP being replaced, it is extended.&lt;/p&gt;
&lt;p&gt;The main motivating factor for creating Tpl is that all PHP template engines seem to be centred
around &lt;em&gt;inclusion&lt;/em&gt; rather than &lt;em&gt;inheritance&lt;/em&gt;, something I only noticed after spending time working
with &lt;a class="reference external" href="http://www.djangoproject.com/"&gt;Django&lt;/a&gt;.  For example, a typical PHP template might look like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="x"&gt;&amp;lt;!-- header.php --&amp;gt;&lt;/span&gt;
&lt;span class="x"&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
&lt;span class="x"&gt;    &amp;lt;head&amp;gt;&amp;lt;title&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;&amp;lt;?&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$title&lt;/span&gt;&lt;span class="cp"&gt;?&amp;gt;&lt;/span&gt;&lt;span class="x"&gt;&amp;lt;/title&amp;gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;span class="x"&gt;    &amp;lt;body&amp;gt;&lt;/span&gt;
&lt;span class="x"&gt;        &amp;lt;div id=&amp;quot;header&amp;quot;&amp;gt;Website Name&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="x"&gt;&amp;lt;!-- footer.php --&amp;gt;&lt;/span&gt;
&lt;span class="x"&gt;        &amp;lt;div id=&amp;quot;footer&amp;quot;&amp;gt;Some footer text&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="x"&gt;    &amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="x"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="x"&gt;&amp;lt;!-- content.php --&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;&amp;lt;?&lt;/span&gt; &lt;span class="k"&gt;include&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;header.php&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="cp"&gt;?&amp;gt;&lt;/span&gt;&lt;span class="x"&gt;&lt;/span&gt;

&lt;span class="x"&gt;&amp;lt;div id=&amp;quot;content&amp;quot;&amp;gt;&lt;/span&gt;
&lt;span class="x"&gt;    Some content&lt;/span&gt;
&lt;span class="x"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

&lt;span class="cp"&gt;&amp;lt;?&lt;/span&gt; &lt;span class="k"&gt;include&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;footer.php&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="cp"&gt;?&amp;gt;&lt;/span&gt;&lt;span class="x"&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The main problem with this is that it bears no real relation to the logical structure of the page,
just the order in which stuff should appear in the HTML.  If you modify something in the header, you
need to make sure you've updated the footer too.  The equivalent Django template would look like
this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c"&gt;{# base.html #}&lt;/span&gt;&lt;span class="x"&gt;&lt;/span&gt;
&lt;span class="x"&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
&lt;span class="x"&gt;    &amp;lt;head&amp;gt;&amp;lt;title&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;title&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="x"&gt;&amp;lt;/title&amp;gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;span class="x"&gt;    &amp;lt;body&amp;gt;&lt;/span&gt;
&lt;span class="x"&gt;        &amp;lt;div id=&amp;quot;header&amp;quot;&amp;gt;Website Name&amp;lt;/div&amp;gt;&lt;/span&gt;

&lt;span class="x"&gt;        &lt;/span&gt;&lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;block&lt;/span&gt; &lt;span class="nv"&gt;content&lt;/span&gt; &lt;span class="cp"&gt;%}{%&lt;/span&gt; &lt;span class="k"&gt;endblock&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;&lt;span class="x"&gt;&lt;/span&gt;

&lt;span class="x"&gt;        &amp;lt;div id=&amp;quot;footer&amp;quot;&amp;gt;Some footer text&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="x"&gt;    &amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="x"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c"&gt;{# content.html #}&lt;/span&gt;&lt;span class="x"&gt;&lt;/span&gt;
&lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;extends&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;base.html&amp;quot;&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;&lt;span class="x"&gt;&lt;/span&gt;

&lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;block&lt;/span&gt; &lt;span class="nv"&gt;content&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;&lt;span class="x"&gt;&lt;/span&gt;
&lt;span class="x"&gt;&amp;lt;div id=&amp;quot;content&amp;quot;&amp;gt;&lt;/span&gt;
&lt;span class="x"&gt;    Some content&lt;/span&gt;
&lt;span class="x"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;endblock&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;&lt;span class="x"&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The point to note is that the structure is coherent and in one place, and the parts that change are
defined as logical blocks which can be replaced.  This is the method I've adopted in Tpl---the
equivalent template would look like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="x"&gt;&amp;lt;!-- base.php --&amp;gt;&lt;/span&gt;
&lt;span class="x"&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
&lt;span class="x"&gt;    &amp;lt;head&amp;gt;&amp;lt;title&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;&amp;lt;?&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$C&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;title&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="cp"&gt;?&amp;gt;&lt;/span&gt;&lt;span class="x"&gt;&amp;lt;/title&amp;gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;span class="x"&gt;    &amp;lt;body&amp;gt;&lt;/span&gt;
&lt;span class="x"&gt;        &amp;lt;div id=&amp;quot;header&amp;quot;&amp;gt;Website Name&amp;lt;/div&amp;gt;&lt;/span&gt;

&lt;span class="x"&gt;        &lt;/span&gt;&lt;span class="cp"&gt;&amp;lt;?&lt;/span&gt; &lt;span class="nx"&gt;Tpl&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;block&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;content&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="cp"&gt;?&amp;gt;&amp;lt;?&lt;/span&gt; &lt;span class="nx"&gt;Tpl&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;endblock&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="cp"&gt;?&amp;gt;&lt;/span&gt;&lt;span class="x"&gt;&lt;/span&gt;

&lt;span class="x"&gt;        &amp;lt;div id=&amp;quot;footer&amp;quot;&amp;gt;Some footer text&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="x"&gt;    &amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="x"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="x"&gt;&amp;lt;!-- content.php --&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;&amp;lt;?&lt;/span&gt; &lt;span class="nx"&gt;Tpl&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;inherit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;base.php&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="cp"&gt;?&amp;gt;&lt;/span&gt;&lt;span class="x"&gt;&lt;/span&gt;

&lt;span class="cp"&gt;&amp;lt;?&lt;/span&gt; &lt;span class="nx"&gt;Tpl&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;block&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;content&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="cp"&gt;?&amp;gt;&lt;/span&gt;&lt;span class="x"&gt;&lt;/span&gt;
&lt;span class="x"&gt;&amp;lt;div id=&amp;quot;content&amp;quot;&amp;gt;&lt;/span&gt;
&lt;span class="x"&gt;    Some content&lt;/span&gt;
&lt;span class="x"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;&amp;lt;?&lt;/span&gt; &lt;span class="nx"&gt;Tpl&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;endblock&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="cp"&gt;?&amp;gt;&lt;/span&gt;&lt;span class="x"&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;More information about Tpl and how to download it can be found at the &lt;a class="reference external" href="http://codescape.net/tpl/"&gt;Tpl project page&lt;/a&gt;.&lt;/p&gt;
</summary><category term="php"></category></entry><entry><title>Enable Bitmap Fonts on Ubuntu Jaunty</title><link href="http://alanbriolat.co.uk/enable-bitmap-fonts-on-ubuntu-jaunty.html" rel="alternate"></link><published>2009-04-11T00:00:00+01:00</published><updated>2009-04-11T00:00:00+01:00</updated><author><name>Alan Briolat</name></author><id>tag:alanbriolat.co.uk,2009-04-11:enable-bitmap-fonts-on-ubuntu-jaunty.html</id><summary type="html">&lt;p&gt;I like to use tiny bitmap fonts like &lt;a class="reference external" href="http://www.bok.net/MonteCarlo/"&gt;MonteCarlo&lt;/a&gt; for programming, but by default Ubuntu has bitmap
font support turned off.  From (at least) Gutsy through to Intrepid, &lt;a class="reference external" href="http://www.nazgum.com/2007/12/09/ubuntu-pcf-fonts/"&gt;this method&lt;/a&gt; worked for
enabling bitmap font support, but after installing the Jaunty beta I found this no longer works.&lt;/p&gt;
&lt;p&gt;Luckily, after a brief look in &lt;tt class="docutils literal"&gt;/etc/fonts&lt;/tt&gt;, I found that font configuration now follows the nice
pattern of a &lt;tt class="docutils literal"&gt;conf.avail&lt;/tt&gt; directory containing all the available configuration parts, and
&lt;tt class="docutils literal"&gt;conf.d&lt;/tt&gt; containing symlinks to these parts.  This makes enabling bitmap fonts even simpler now:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;# &amp;quot;Un-disable&amp;quot; bitmap fonts&lt;/span&gt;
sudo rm /etc/fonts/conf.d/70-no-bitmaps.conf
&lt;span class="c1"&gt;# Clear the font cache&lt;/span&gt;
sudo fc-cache -f -v
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now you should be able to drop bitmap (i.e. PCF) fonts into &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;~/.fonts&lt;/span&gt;&lt;/tt&gt; as you would with TTF fonts
and be able to use them with no extra hassle.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; Andreas asked in the comments if there was a way to do this that doesn't require root
access.  In fact there is!  If you copy &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;/etc/fonts/conf.avail/70-force-bitmaps.conf&lt;/span&gt;&lt;/tt&gt; to
&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;~/.fonts.conf&lt;/span&gt;&lt;/tt&gt; then it has the same effect.  (If you already have a &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;~/.fonts.conf&lt;/span&gt;&lt;/tt&gt; then you'll
want to merge them together; copy everything inside &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;&amp;lt;fontconfig&amp;gt;...&amp;lt;/fontconfig&amp;gt;&lt;/span&gt;&lt;/tt&gt; from
&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;70-force-bitmaps.conf&lt;/span&gt;&lt;/tt&gt; and put it just before &lt;tt class="docutils literal"&gt;&amp;lt;/fontconfig&amp;gt;&lt;/tt&gt; in &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;~/.fonts.conf&lt;/span&gt;&lt;/tt&gt;.)&lt;/p&gt;
</summary><category term="ubuntu"></category><category term="fonts"></category></entry><entry><title>VDB 0.1.0 (alpha) Released</title><link href="http://alanbriolat.co.uk/vdb-0-1-0-alpha-released.html" rel="alternate"></link><published>2009-04-01T00:00:00+01:00</published><updated>2009-04-01T00:00:00+01:00</updated><author><name>Alan Briolat</name></author><id>tag:alanbriolat.co.uk,2009-04-01:vdb-0-1-0-alpha-released.html</id><summary type="html">&lt;p&gt;Recently I've been working on a program that will let me do a full-text search of my 1500-file
digital video library.  The result is something I've unimaginatively called &amp;quot;VDB&amp;quot;, short for &amp;quot;Video
Database&amp;quot;.&lt;/p&gt;
&lt;p&gt;This release doesn't do much; you can add your library of video files, and it will let you do a
full-text search on the filename.  You can double-click an item in the list to launch the video with
&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;gnome-open&lt;/span&gt;&lt;/tt&gt; (which should honour user settings for preferred applications).&lt;/p&gt;
&lt;p&gt;Feel free to download it, mess around with it, and send me any feedback you have.  I have plenty of
future plans for it, including &amp;quot;watch folders&amp;quot;, tagging, metadata, fetching information from IMDB,
and being able to search on all of this information.  (Think queries like &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;actor:'johnny&lt;/span&gt; depp'
tag:crime&lt;/tt&gt;.)&lt;/p&gt;
&lt;img alt="images/vdb-010.png" src="images/vdb-010.png" style="width: 100%;" /&gt;
&lt;p&gt;&lt;a class="reference external" href="http://codescape.net/vdb/"&gt;Visit the VDB project page.&lt;/a&gt;&lt;/p&gt;
</summary><category term="linux"></category></entry><entry><title>C is not MATLAB</title><link href="http://alanbriolat.co.uk/c-is-not-matlab.html" rel="alternate"></link><published>2009-03-30T00:00:00+01:00</published><updated>2009-03-30T00:00:00+01:00</updated><author><name>Alan Briolat</name></author><id>tag:alanbriolat.co.uk,2009-03-30:c-is-not-matlab.html</id><summary type="html">&lt;p&gt;Refactoring some code at work today, I came across a classic example of somebody attempting to use
one language like another.  The project in question is a port from MATLAB to C, and the purpose of
the function is to see if a square matrix is symmetrical within a certain tolerance.&lt;/p&gt;
&lt;p&gt;The implementation I replaced worked somewhat like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;check_symmetry&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;mtx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;tolerance&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cm"&gt;/* Allocate memory to work in */&lt;/span&gt;
    &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;mtx_trans&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;malloc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;double&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;mtx_diff&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;malloc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;double&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

    &lt;span class="cm"&gt;/* Matrix transpose */&lt;/span&gt;
    &lt;span class="n"&gt;matxtrans&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mtx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mtx_trans&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="cm"&gt;/* Matrix subtract */&lt;/span&gt;
    &lt;span class="n"&gt;matxsub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mtx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mtx_trans&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mtx_sub&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="cm"&gt;/* Assume matrix is symmetric to start with */&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;symmetric&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;TRUE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="cm"&gt;/* Iterate through rows */&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="cm"&gt;/* Iterate through columns */&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="cm"&gt;/* Was the difference greater than the tolerance? */&lt;/span&gt;
            &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mtx_sub&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fabs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;tolerance&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="cm"&gt;/* Exception found: matrix not symmetric&lt;/span&gt;
&lt;span class="cm"&gt;                 * (but notice that we keep looping...) */&lt;/span&gt;
                &lt;span class="n"&gt;symmetric&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;FALSE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="cm"&gt;/* Clean up memory allocations */&lt;/span&gt;
    &lt;span class="n"&gt;free&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mtx_trans&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;free&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mtx_diff&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="cm"&gt;/* ... and return the result */&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;symmetric&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now, what this is really doing is the equivalent to the following line of MATLAB:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="n"&gt;symmetric&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mtx&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;mtx&lt;/span&gt;&lt;span class="o"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;tol&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This in itself highlights the massive differences between MATLAB, where matrix operations are
fundamental, and C, where they are not.  While the above C code gets the correct answer, it's far
from efficient.  What should be obvious is that the programmer translated the code, not the meaning.&lt;/p&gt;
&lt;p&gt;To analyse this simple case: a symmetric matrix is reflected in the diagonal---the lower triangle is
the same as the upper.  What we really are trying to find out is if any elements violate this
constraint.  More verbosely: &amp;quot;does any element in the upper triangle differ from it's corresponding
element in the lower triangle (by more than a certain value)?&amp;quot;  Once we've figured this out, the
operation in C is much, much shorter:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;check_symmetry&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;mtx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;tolerance&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cm"&gt;/* Iterate through upper triangle only */&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="cm"&gt;/* Compare to lower triangle */&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fabs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mtx&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;tolerance&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="cm"&gt;/* Exception found: matrix not symmetric */&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;FALSE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="cm"&gt;/* No exceptions found: matrix is symmetric */&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;TRUE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This achieves the minimum number of iterations and element accesses by ignoring the diagonal, only
iterating through the upper triangle and reversing the indices to access the lower triangle.  The
only potential downside is that it's not as obvious what's going on, but &lt;em&gt;that's what comments are
for!&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The lesson is that you should always make sure you're using the correct method for the tool, and not
trying to hammer a screw in with a spanner.&lt;/p&gt;
</summary><category term="c"></category><category term="matlab"></category></entry><entry><title>Persistent Remote irssi Session</title><link href="http://alanbriolat.co.uk/persistent-remote-irssi-session.html" rel="alternate"></link><published>2009-03-28T00:00:00+00:00</published><updated>2009-03-28T00:00:00+00:00</updated><author><name>Alan Briolat</name></author><id>tag:alanbriolat.co.uk,2009-03-28:persistent-remote-irssi-session.html</id><summary type="html">&lt;p&gt;I've recently moved back to using irssi as my IRC client, because when combined with &lt;a class="reference external" href="http://www.gnu.org/software/screen/"&gt;GNU screen&lt;/a&gt;
it can be kept independent of a graphical session, or even better, of a particular client machine
(if you have a server somewhere).  Since I have a home fileserver at the moment, I want my IRC
client to always be running there.  However, my usual workflow to do this is to open a terminal, SSH
to the server, resume screen, move the window and resize it.  This is far from optimal for something
I usually want open...&lt;/p&gt;
&lt;p&gt;Instead, I pieced together a command that I can use as a panel shortcut to do it all for me:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;gnome-terminal --geometry 100x30-0-0 -x &lt;span class="se"&gt;\&lt;/span&gt;
        ssh &amp;lt;hostname&amp;gt; -t &lt;span class="s2"&gt;&amp;quot;screen -D -RR -S irssi irssi&amp;quot;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;dl class="docutils"&gt;
&lt;dt&gt;&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;gnome-terminal&lt;/span&gt; &lt;span class="pre"&gt;--geometry&lt;/span&gt; &lt;span class="pre"&gt;100x30-0-0&lt;/span&gt; &lt;span class="pre"&gt;-x&lt;/span&gt;&lt;/tt&gt;&lt;/dt&gt;
&lt;dd&gt;Open &amp;quot;gnome-terminal&amp;quot; at the bottom right of the screen with a size of 100 characters by 30.
Run the rest of the command inside the terminal.&lt;/dd&gt;
&lt;dt&gt;&lt;tt class="docutils literal"&gt;ssh &amp;lt;hostname&amp;gt; &lt;span class="pre"&gt;-t&lt;/span&gt;&lt;/tt&gt;&lt;/dt&gt;
&lt;dd&gt;Connect to &lt;tt class="docutils literal"&gt;&amp;lt;hostname&amp;gt;&lt;/tt&gt; and execute the supplied command in an interactive pseudo-TTY.&lt;/dd&gt;
&lt;dt&gt;&lt;tt class="docutils literal"&gt;screen &lt;span class="pre"&gt;-D&lt;/span&gt; &lt;span class="pre"&gt;-RR&lt;/span&gt; &lt;span class="pre"&gt;-S&lt;/span&gt; irssi irssi&lt;/tt&gt;&lt;/dt&gt;
&lt;dd&gt;Do whatever necessary to gain control of the &amp;quot;irssi&amp;quot; screen session if it exists, otherwise
create it and run irssi inside it.&lt;/dd&gt;
&lt;/dl&gt;
</summary><category term="screen"></category><category term="irssi"></category><category term="bash"></category></entry><entry><title>MPD + PulseAudio + Ubuntu Intrepid (8.10)</title><link href="http://alanbriolat.co.uk/mpd-pulseaudio-ubuntu-intrepid-8-10.html" rel="alternate"></link><published>2009-03-21T00:00:00+00:00</published><updated>2009-03-21T00:00:00+00:00</updated><author><name>Alan Briolat</name></author><id>tag:alanbriolat.co.uk,2009-03-21:mpd-pulseaudio-ubuntu-intrepid-8-10.html</id><summary type="html">&lt;div class="admonition admonition-update-2009-04-12"&gt;
&lt;p class="first admonition-title"&gt;Update (2009/04/12)&lt;/p&gt;
&lt;p class="last"&gt;It appears that as of Ubuntu Jaunty everything now obeys the system-wide setting properly, so
you only need to edit &lt;tt class="docutils literal"&gt;/etc/default/pulseaudio&lt;/tt&gt; and add the user to &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;pulse-access&lt;/span&gt;&lt;/tt&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;I'm a big fan of &lt;a class="reference external" href="http://www.musicpd.org/"&gt;MPD&lt;/a&gt;, and up until the last few months I used it almost exclusively.  It's
lightweight, it's good at what it does, and there are a lot of different frontends available.  One
of the things I like most is that it's not tied to a graphical session in any way---you don't need a
GUI open for it to be playing music.  Normal usage of MPD involves it being started and stopped as a
system service.&lt;/p&gt;
&lt;p&gt;Unfortunately, this doesn't play too nice with the concept of how &lt;a class="reference external" href="http://www.pulseaudio.org/"&gt;PulseAudio&lt;/a&gt; should be used.
PulseAudio is very user- and session-centric, and the recommended setup means than when nobody is
logged in, no sound is going to be playing.  While MPD is capable of &lt;a class="reference external" href="http://mpd.wikia.com/wiki/PulseAudio"&gt;playing to a PulseAudio
server&lt;/a&gt; just fine, having the sound server tied to the graphical session means it doesn't have a
sound device to attach to at boot, and the sound device suddenly disappears if the user logs off.&lt;/p&gt;
&lt;p&gt;Ubuntu has used PulseAudio for as many applications as possible by default since Hardy (8.04), and
while it can be removed, doing so can make life difficult.  This led me to pursue the option of a
system-wide instance which everything uses, and which is always running.  But no matter how hard I
tried, I got stuck with the same bug: starting GNOME would always result in a per-session instance
being spawned in addition to the system-wide one, the two would fight over the sound card, and I
would have to manually kill the new one every time I logged in.  Eventually I'd had enough of this
and started using something else.&lt;/p&gt;
&lt;p&gt;Today, I decided to take another stab at getting this set up properly and finding out where that
second PulseAudio instance was coming from.  Thanks to the help of a couple of people in
&lt;a class="reference external" href="irc://irc.freenode.net/#pulseaudio"&gt;#pulseaudio on FreeNode IRC&lt;/a&gt;, I was able to figure out how to do this, so here is the method I
used for the benefit of anybody else in the same position.&lt;/p&gt;
&lt;div class="section" id="stop-pulseaudio-spawning-per-session"&gt;
&lt;h2&gt;Stop PulseAudio spawning per-session&lt;/h2&gt;
&lt;p&gt;By default PulseAudio puts a script in &lt;tt class="docutils literal"&gt;/etc/X11/Xsession.d&lt;/tt&gt; which causes a &lt;tt class="docutils literal"&gt;pulseaudio&lt;/tt&gt;
instance to be spawned with every X session.  The first step is to move this script somewhere else
so it's never run:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
sudo mv /etc/X11/Xsession.d/70pulseaudio /root/
&lt;/pre&gt;
&lt;p&gt;The second cause of &lt;tt class="docutils literal"&gt;pulseaudio&lt;/tt&gt; being spawned is less obvious.  There is an &lt;a class="reference external" href="http://en.wikipedia.org/wiki/Enlightened_Sound_Daemon"&gt;Esound&lt;/a&gt; compatibility
layer for PulseAudio so that applications depending on it still work, transparently:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ ls -l /usr/bin/esd
lrwxrwxrwx 1 root root 9 2009-03-04 11:03 /usr/bin/esd -&amp;gt; esdcompat
&lt;/pre&gt;
&lt;p&gt;However, as of Ubuntu Intrepid (8.10) there is pretty much nothing which depends solely on Esound,
but it still gets spawned when GNOME starts.  This causes a PulseAudio session to be spawned for the
current user if one can't be found.  The simple but ugly fix is to move this link to somewhere
else:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
sudo mv /usr/bin/esd /usr/bin/esd.bak
&lt;/pre&gt;
&lt;/div&gt;
&lt;div class="section" id="set-up-a-system-wide-pulseaudio-instance"&gt;
&lt;h2&gt;Set up a system-wide PulseAudio instance&lt;/h2&gt;
&lt;p&gt;To get PulseAudio to actually start on boot, you need to set a variable to tell the init script you
want this to happen. Make sure you have the following line in &lt;tt class="docutils literal"&gt;/etc/default/pulseaudio&lt;/tt&gt;:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
PULSEAUDIO_SYSTEM_START=1
&lt;/pre&gt;
&lt;p&gt;Any users that will be using the system-wide PulseAudio instance need to be members of the correct
groups. This will most likely be your own user, plus whatever user MPD is running as (&lt;tt class="docutils literal"&gt;mpd&lt;/tt&gt; by
default). For each of these users, do:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
sudo usermod -aG pulse-access,pulse,pulse-rt &amp;lt;user&amp;gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;div class="section" id="getting-it-up-and-running"&gt;
&lt;h2&gt;Getting it up and running&lt;/h2&gt;
&lt;p&gt;First thing's first, you need to tell MPD to use PulseAudio. This can be achieved by adding the
following to &lt;tt class="docutils literal"&gt;/etc/mpd.conf&lt;/tt&gt;:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
audio_output {
    type    &amp;quot;pulse&amp;quot;
    name    &amp;quot;My MPD PulseAudio Output&amp;quot;
}
&lt;/pre&gt;
&lt;p&gt;If you're feeling lazy, the easiest thing to do right now would be reboot. Otherwise, you'll need to
kill all &lt;tt class="docutils literal"&gt;pulseaudio&lt;/tt&gt; instances, restart the system-wide instance, and restart MPD:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ sudo /etc/init.d/mpd stop
 * Stopping Music Player Daemon mpd                   [ OK ]
$ sudo killall -KILL pulseaudio
$ sudo /etc/init.d/pulseaudio restart
 * Stopping PulseAudio Daemon                         [ OK ]
 * Starting PulseAudio Daemon                         [ OK ]
$ sudo /etc/init.d/mpd start
 * Starting Music Player Daemon mpd                   [ OK ]
&lt;/pre&gt;
&lt;p&gt;Finally, log out and log back in again to allow your per-session &lt;tt class="docutils literal"&gt;pulseaudio&lt;/tt&gt; instance to die and
for your new group memberships to take effect.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="caveats"&gt;
&lt;h2&gt;Caveats&lt;/h2&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;You get &amp;quot;real-time&amp;quot; processing without any extra effort; by default the system-wide instance will
run with priority -11.&lt;/li&gt;
&lt;li&gt;Some apps are not PulseAudio-aware, but they can usually use an ALSA output; &lt;a class="reference external" href="http://www.pulseaudio.org/wiki/PerfectSetup#ALSAApplications"&gt;this guide&lt;/a&gt; shows
you how to redirect ALSA through PulseAudio if you have any problems with the default setup.&lt;/li&gt;
&lt;li&gt;Updates may undo the moving-a-file type of changes.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
</summary><category term="ubuntu"></category><category term="pulseaudio"></category><category term="mpd"></category></entry><entry><title>Universities push for higher fees</title><link href="http://alanbriolat.co.uk/universities-push-for-higher-fees.html" rel="alternate"></link><published>2009-03-17T00:00:00+00:00</published><updated>2009-03-17T00:00:00+00:00</updated><author><name>Alan Briolat</name></author><id>tag:alanbriolat.co.uk,2009-03-17:universities-push-for-higher-fees.html</id><summary type="html">&lt;p&gt;My comment on a recent BBC News article &lt;a class="reference external" href="http://news.bbc.co.uk/1/hi/education/7946912.stm"&gt;&amp;quot;Universities push for higher fees&amp;quot;&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I'm a university student from a low-income background, and having started my course just after
the last raise in fees took effect, I knew from the beginning that I'd be finishing with £32k of
debt (including maintenance loan).  While expensive, it's a risk I was willing to take, since
it's the best way to equip myself for the field I enjoy.  If this number were to be more in the
region of £85k, I think a lot of people would shy away from taking on such a staggering debt.&lt;/p&gt;
&lt;p&gt;The government needs to realise that if they allow such increases, and also increase student
loans to follow suit, then they will be footing the bill for allowing the fees to be raised (and
therefore passing it on to the taxpayers).  The vital safety net for most students is that
&lt;a class="reference external" href="http://www.hero.ac.uk/uk/studying/funding_your_study/sources_of_help/loans.cfm"&gt;student loans are written off 25 years after finishing/leaving the course&lt;/a&gt;, and since
the university already has the money, the gap has to be filled from somewhere.  This alone
explains the observations leading to &amp;quot;Two thirds believed that fees had not deterred
applications from students from poorer families&amp;quot;.  If the government wants to subsidise the
universities, then they should propose an increase in per-student subsidies as an alternative,
presenting the situation as it really is.&lt;/p&gt;
&lt;p&gt;Any attempt to raise or un-cap fees that isn't backed completely by student loans will be
disasterous.  This would change the university admissions process to be less &amp;quot;those who are most
able&amp;quot; and more &amp;quot;those who are most able to pay&amp;quot;.  For a government that campaigned on equal
availability of higher education, this would be a step backwards.  In a country with a shrinking
manufacturing base, intelligent well-educated individuals are a vital resource for staying
competitive in a global market.&lt;/p&gt;
&lt;p&gt;As it stands, I've not heard of universities being severely underfunded, and where they claim to
be it can usually be attributed to mismanagement of funds.  If they could survive when we were
paying £1150, why can't they survive when we're paying £3150?  It seems to me this may be a case
of &amp;quot;they did it once, maybe they'll do it again&amp;quot; on the part of universities, hopeful that the
government will grant them more revenue without having to show anything for it.&lt;/p&gt;
&lt;/blockquote&gt;
</summary></entry><entry><title>My painless Linux "upgrade" process</title><link href="http://alanbriolat.co.uk/my-painless-linux-upgrade-process.html" rel="alternate"></link><published>2009-01-07T00:00:00+00:00</published><updated>2009-01-07T00:00:00+00:00</updated><author><name>Alan Briolat</name></author><id>tag:alanbriolat.co.uk,2009-01-07:my-painless-linux-upgrade-process.html</id><summary type="html">&lt;p&gt;I like to keep up to date with the latest version of any Linux distro I use (naturally), but for
some reason I don't trust the upgrade process to work properly and/or not leave a load of cruft
behind.  I've actually attempted an upgrade once just to try and get over my upgrade fear, but
instead it went horribly wrong and convinced me to not try again for a long time.&lt;/p&gt;
&lt;p&gt;There is a simple way to make reinstallations painless enough that you don't need to offer yourself
up to the upgrade gods, and it takes only a small amount of forward planning.  &lt;strong&gt;Always always
always use a separate home partition!&lt;/strong&gt; Keeping your home partition separate allows you to go as far
as reformatting your main operating system partition without losing any of the data you really care
about.&lt;/p&gt;
&lt;p&gt;Here is my typical upgrade/reinstall process.  If you're planning on using this method, please read
the &lt;em&gt;whole thing&lt;/em&gt; before starting and make sure you understand what you're doing and why.  A lot of
this is done as root and mistakes can be painful.&lt;/p&gt;
&lt;div class="admonition note"&gt;
&lt;p class="first admonition-title"&gt;Note&lt;/p&gt;
&lt;p class="last"&gt;Just in case it's not obvious, my username is &lt;tt class="docutils literal"&gt;alan&lt;/tt&gt; - replace it with your own username!  If
you have multiple users, repeat operations on each user's home directory.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="prepare"&gt;
&lt;h2&gt;1 - Prepare&lt;/h2&gt;
&lt;p&gt;Your &lt;tt class="docutils literal"&gt;/home&lt;/tt&gt; partition isn't going to be reformatted if everything is done correctly, so if you
know what you're doing you shouldn't even need to do a full backup.  However, you've probably got
some other things on the root partition that have been changed that you want to keep, at least for
future reference.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;# Backup /etc&lt;/span&gt;
sudo tar czvpf /home/etc.tar.gz /etc
&lt;span class="c1"&gt;# Backup root&amp;#39;s home directory&lt;/span&gt;
sudo tar czvpf /home/root.tar.gz /root
&lt;span class="c1"&gt;# Backup anything else you might want to /home, for example MySQL databases&lt;/span&gt;
&lt;span class="c1"&gt;# (maybe backup /var the same way as above?)&lt;/span&gt;
&lt;span class="c1"&gt;# ...&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Next you need to make a note of which partition is which so you don't accidentally format the wrong
one.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$ df
/dev/sda5             &lt;span class="m"&gt;11718932&lt;/span&gt;   &lt;span class="m"&gt;2419420&lt;/span&gt;   &lt;span class="m"&gt;9299512&lt;/span&gt;  21% /
...
/dev/sda7             &lt;span class="m"&gt;44133352&lt;/span&gt;    &lt;span class="m"&gt;219500&lt;/span&gt;  &lt;span class="m"&gt;41671984&lt;/span&gt;   1% /home
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;So in this case, &lt;tt class="docutils literal"&gt;/dev/sda5&lt;/tt&gt; is what you'll be reformatting and installing your new operating
system on, and &lt;tt class="docutils literal"&gt;/dev/sda7&lt;/tt&gt; is the one you don't want to touch in any way whatsoever.&lt;/p&gt;
&lt;p&gt;Next you'll want to write the fstab line for your home partition somewhere so you can use it on your
new installation.  The following command will get that from &lt;tt class="docutils literal"&gt;/etc/fstab&lt;/tt&gt; for you:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ grep &amp;quot;/home&amp;quot; /etc/fstab
/dev/sda7      /home      ext3     defaults,relatime      0     2
&lt;/pre&gt;
&lt;p&gt;The final preparation step is to move your old home directory somewhere.  To do this you'll need to
be logged in directly as root.  If you're running an Ubuntu-based distribution and haven't set the
root password before, do so:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
sudo passwd
&lt;/pre&gt;
&lt;p&gt;Log out of your graphical session, switch to a virtual terminal (e.g. press &lt;em&gt;Ctrl-Alt-F2&lt;/em&gt;), and log
in as root.  Move your old home directory:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
mv /home/alan /home/alan-old
&lt;/pre&gt;
&lt;p&gt;Everything should be ready now - time to reboot into the installer of your distro of choice!&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="installation"&gt;
&lt;h2&gt;2 - Installation&lt;/h2&gt;
&lt;p&gt;Just install as usual, feel free to obliterate your old root partition but &lt;em&gt;make sure you don't
touch your home partition!&lt;/em&gt; Install as if your home directory will be on your root partition along
with everything else.  (It's possible to just use your old home partition at this point, but most
installers will format any partition you choose to use by default.  This way, there is no risk of
that happening.)  Reboot into your new fresh Linux installation.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="juggling"&gt;
&lt;h2&gt;3 - Juggling&lt;/h2&gt;
&lt;p&gt;Now all that's left to do is get your home directory onto your home partition, get your home
partition mounted and move all your files back to their rightful places.&lt;/p&gt;
&lt;p&gt;Yet again, this process will require you to log in directly as root to move the home directory
around, so set the root password as before if necessary for your distribution.&lt;/p&gt;
&lt;p&gt;Now log in as root on a virtual terminal (e.g. &lt;em&gt;Ctrl-Alt-F2&lt;/em&gt;) to mount your home partition
somewhere, copy your new home directory across, and unmount it again:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
mount /dev/sda7 /mnt
cp -a /home/alan /mnt/
umount /mnt
&lt;/pre&gt;
&lt;p&gt;Now we want to make sure the home partition get's mounted at &lt;tt class="docutils literal"&gt;/home&lt;/tt&gt; as it should.  Edit
&lt;tt class="docutils literal"&gt;/etc/fstab&lt;/tt&gt; with your editor of choice and add the fstab line from earlier.  To make sure
everything is correct, mount the home partition in a way that'll use fstab, and check that both the
old and new home directories are there:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ mount /home
$ ls /home/
alan   alan-old
&lt;/pre&gt;
&lt;p&gt;Just in case your user ID has changed, make sure your old home directory is owned by your new user:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
chown -R alan:alan /home/alan-old
&lt;/pre&gt;
&lt;p&gt;At this point, you should be finished with using the root account, and can log in as normal.  If you
want to lock the root account (in the way Ubuntu does by default), run:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
sudo usermod -L root
&lt;/pre&gt;
&lt;/div&gt;
&lt;div class="section" id="get-your-files"&gt;
&lt;h2&gt;4 - Get your files&lt;/h2&gt;
&lt;p&gt;Now you should be able to browse both your new and old home directories using your file manager of
choice.  Open one for each, show hidden files, and start dragging stuff around!&lt;/p&gt;
&lt;p&gt;This step might take some time, but has the added advantage that you get to learn where every
application stores its user files, and also gives you the opportunity to clear out some junk you
didn't need, clean up your directory structure, or whatever else.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="final-notes"&gt;
&lt;h2&gt;Final notes&lt;/h2&gt;
&lt;p&gt;This process is probably slower than an upgrade, especially considering the step of sorting your old
files into your new home directory.  However, it gives you very direct control over the process,
lets you start with a nice clean copy of your operating system, and if done correctly doesn't
require a full backup to be made.&lt;/p&gt;
&lt;p&gt;I much prefer this method to doing an upgrade because it leaves you free of the &amp;quot;old version cruft&amp;quot;
that accumulates when you upgrade---an operating system upgrade is a complex process and is never
going to handle every edge case.&lt;/p&gt;
&lt;p&gt;If you trust all of your applications to handle old configuration files etc. correctly and you want
to save some time, you can skip all of the steps relating to moving/copying of your user's home
directory, so that when you mount your home partition your old home directory is used.  If
reinstalling rather than upgrading, I tend to do this.&lt;/p&gt;
&lt;div class="admonition caution"&gt;
&lt;p class="first admonition-title"&gt;Caution!&lt;/p&gt;
&lt;p class="last"&gt;While I mention that this can be done without a backup, doing so is at your own risk.  Generally
speaking it is prudent to backup anything important to somewhere outside of your machine before
doing any operating system installation to protect against mistakes.  Otherwise, be extremely
careful!  I do things this way because my home directory is always too large to backup anywhere,
but I also run an automated nightly backup of the small, important stuff.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
</summary></entry><entry><title>C linked list macro</title><link href="http://alanbriolat.co.uk/c-linked-list-macro.html" rel="alternate"></link><published>2008-12-19T00:00:00+00:00</published><updated>2008-12-19T00:00:00+00:00</updated><author><name>Alan Briolat</name></author><id>tag:alanbriolat.co.uk,2008-12-19:c-linked-list-macro.html</id><summary type="html">&lt;p&gt;Here's a simple macro I came up with a few weeks ago for easily defining linked list types in C:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="cp"&gt;#define LINKED_LIST(type, name)     \&lt;/span&gt;
&lt;span class="cp"&gt;    struct name ## _ {              \&lt;/span&gt;
&lt;span class="cp"&gt;        struct name ## _ * next;    \&lt;/span&gt;
&lt;span class="cp"&gt;        type data;                  \&lt;/span&gt;
&lt;span class="cp"&gt;    };                              \&lt;/span&gt;
&lt;span class="cp"&gt;    typedef struct name ## _ name;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Usage is simple:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="n"&gt;LINKED_LIST&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;int_ll&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;gives the same type as:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;int_ll_&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;int_ll_&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="k"&gt;typedef&lt;/span&gt; &lt;span class="n"&gt;int_ll_&lt;/span&gt; &lt;span class="n"&gt;int_ll&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
</summary><category term="c"></category></entry><entry><title>Why I dislike PulseAudio (for now)</title><link href="http://alanbriolat.co.uk/why-i-dislike-pulseaudio-for-now.html" rel="alternate"></link><published>2008-12-17T00:00:00+00:00</published><updated>2008-12-17T00:00:00+00:00</updated><author><name>Alan Briolat</name></author><id>tag:alanbriolat.co.uk,2008-12-17:why-i-dislike-pulseaudio-for-now.html</id><summary type="html">&lt;p&gt;Before this sounds like a rant, I'd like to first say that I think &lt;a class="reference external" href="http://pulseaudio.org/"&gt;PulseAudio&lt;/a&gt; is a very nice
concept, from a technical perspective.  It's about time Linux got a manageable sound subsystem, and
some of the features---such as network streaming and synchronised playback---are quite impressive.&lt;/p&gt;
&lt;p&gt;However, one thing that really irks me is that, as deployed by &lt;a class="reference external" href="http://ubuntu.com/"&gt;major&lt;/a&gt; &lt;a class="reference external" href="http://fedoraproject.org/"&gt;distributions&lt;/a&gt;, it appears to
enforce the narrow-minded view that a desktop is used by only one person, and that sound is only
ever going to play when somebody is logged in to a graphical session.  Anybody who uses &lt;a class="reference external" href="http://mpd.wikia.com/wiki/"&gt;MPD&lt;/a&gt; has
probably experienced the pain caused by this already.  Unfortunately my experience so far with
Ubuntu Intrepid is that trying to change this results in even more pain.  Having set up a
system-wide instance I'm now in the position where the first time I attempt to play sound works
correctly, but any subsequent attempts fail until I kill a per-session PulseAudio instance that has
magically spawned (even though I've set it not to).  Once the per-session instance is dead, I have
no more problems and everything works perfectly until the next time I log in.&lt;/p&gt;
&lt;p&gt;I'm currently trialling Fedora 10 on my desktop, so I'll update this post if I have any more luck
there.  Feel free to correct me in the comments if I'm just being stupid or missing something!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; &lt;a class="reference external" href="http://alanbriolat.co.uk/mpd-pulseaudio-ubuntu-intrepid-8-10.html"&gt;I've since fixed this problem&lt;/a&gt;.&lt;/p&gt;
</summary><category term="linux"></category><category term="pulseaudio"></category></entry><entry><title>The curse of Firefox extensions</title><link href="http://alanbriolat.co.uk/the-curse-of-firefox-extensions.html" rel="alternate"></link><published>2008-02-24T00:00:00+00:00</published><updated>2008-02-24T00:00:00+00:00</updated><author><name>Alan Briolat</name></author><id>tag:alanbriolat.co.uk,2008-02-24:the-curse-of-firefox-extensions.html</id><summary type="html">&lt;p&gt;Today is my first day of Firefox usage after a three-week break - a break which taught me
something...&lt;/p&gt;
&lt;p&gt;First, a little background. I've been using Firefox since 0.9, and generally its always been the
best browser for me. However, recently I lost my taste for it due to the monumental lack of speed it
can display sometimes. I mean things like a half-second delay between hitting &lt;em&gt;Ctrl-T&lt;/em&gt; and being
able to type in the address bar of the new tab, really long page rendering times, etc. I know that
Firefox slowness is generally due to extensions, but I relied on most of my extensions. Here is a
list of the extensions I can remember having:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;AdBlock Plus&lt;/li&gt;
&lt;li&gt;AdBlock Filterset.G updater&lt;/li&gt;
&lt;li&gt;CustomiseGoogle&lt;/li&gt;
&lt;li&gt;Download statusbar&lt;/li&gt;
&lt;li&gt;Firebug&lt;/li&gt;
&lt;li&gt;Flashblock&lt;/li&gt;
&lt;li&gt;Foxmarks&lt;/li&gt;
&lt;li&gt;NoScript&lt;/li&gt;
&lt;li&gt;QuickRestart&lt;/li&gt;
&lt;li&gt;Stop Autoplay&lt;/li&gt;
&lt;li&gt;Stylish&lt;/li&gt;
&lt;li&gt;Tab Mix Plus&lt;/li&gt;
&lt;li&gt;Tiny Menu&lt;/li&gt;
&lt;li&gt;Web developer toolbar&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Then I remembered I had tried the &lt;a class="reference external" href="http://www.gnome.org/projects/epiphany/"&gt;Epiphany&lt;/a&gt; browser (for &lt;a class="reference external" href="http://www.gnome.org/"&gt;GNOME&lt;/a&gt;) at some point in the past, and that
it had been quite snappy. To put it simply, Epiphany is a browser that uses the Gecko rendering
engine, but doesn't include all the other stuff that slows down Firefox (which I can only assume to
be the Extension framework and XUL). The upside is that its blindingly fast. The downside is that
you no longer have all the amazing Firefox extensions you've become used to. One other advantage
over Firefox is that it already has working tag-based bookmarking (slated for Firefox 3.0).&lt;/p&gt;
&lt;p&gt;After forcing myself to cope without my extensions for a day, I started to really enjoy the speed
and lack of wait-induced stress - Epiphany stays out of my way and gets stuff done really fast. Once
I had the momentum, I just kept going. I discovered nice stuff like the fact typing in the address
bar also searches your bookmarks as well as your history (something also in Firefox 3.0). Epiphany's
UI is reasonably customisable, but not to the extent that Firefox's is.&lt;/p&gt;
&lt;p&gt;Eventually I had an epiphany (terrible pun, I know...) - I had just survived 3 weeks without the
huge number of extensions I came to think I &lt;em&gt;needed&lt;/em&gt; in Firefox. I now realised I could go back to
Firefox and use it more sensibly. I threw out my old Firefox profile and started again. I now have
only the following well-justified extensions:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Flashblock - on a laptop, unexpected Flash ads = bye-bye battery life&lt;/li&gt;
&lt;li&gt;Foxmarks - because I want my bookmarks on at least 3 different machines&lt;/li&gt;
&lt;li&gt;QuickRestart - no real effect on performance, and sometimes you want to restart Firefox quickly!&lt;/li&gt;
&lt;/ul&gt;
&lt;img alt="Condensed Firefox layout" src="http://alanbriolat.co.uk/static/images/ff-layout.png" style="width: 100%;" /&gt;
&lt;p&gt;I'm happier with this setup than I was with Epiphany, and it's a good trade-off between fancy
features and responsiveness. One thing I really like about Firefox is the ability to put anything
anywhere on the toolbars, and I use a fairly condensed layout, so I was also really happy to go back
to the layout I liked.&lt;/p&gt;
&lt;p&gt;In my opinion, the best thing to do when deciding if an extension is worth installing is ask
yourself the following questions:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Does it analyse and/or change what I am viewing?&lt;/li&gt;
&lt;li&gt;Does it make comparisons against a large whitelist/blacklist?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Extensions doing either of the above will almost certainly slow your browser down to some extent.
You will notice that the only content-sensitive extension I have is Flashblock, which is really
worth it on a laptop.&lt;/p&gt;
&lt;p&gt;Another option is to have multiple Firefox profiles, one of which is clean (like my current setup),
and the other having big slow extensions that you sometimes need, like Firebug. Using the &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;-P&lt;/span&gt;&lt;/tt&gt;
option to Firefox you can set up a launcher that starts your second profile instead of the default.&lt;/p&gt;
</summary><category term="firefox"></category></entry></feed>