<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Aptivate &#124; A Blog for ICT4D</title>
	<atom:link href="http://blog.aptivate.org/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.aptivate.org</link>
	<description>International I.T. Development</description>
	<lastBuildDate>Tue, 15 May 2012 10:56:37 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.6</generator>
		<item>
		<title>Improving Network Management for Universities and SMEs</title>
		<link>http://blog.aptivate.org/2012/05/14/improving-network-management-for-universities-and-smes/</link>
		<comments>http://blog.aptivate.org/2012/05/14/improving-network-management-for-universities-and-smes/#comments</comments>
		<pubDate>Mon, 14 May 2012 19:58:20 +0000</pubDate>
		<dc:creator>Chris Wilson</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://blog.aptivate.org/?p=1044</guid>
		<description><![CDATA[Improving Network Management for Universities and SMEs Chris Wilson Aptivate Ltd, UK My own opinions, not my employer&#8217;s A presentation at AfNOG 2012 Download here: Improving Network Management for Universities and SMEs]]></description>
			<content:encoded><![CDATA[<p><strong>Improving Network Management for Universities and SMEs</strong></p>
<p>Chris Wilson<br />
Aptivate Ltd, UK<br />
My own opinions, not my employer&#8217;s<br />
A presentation at AfNOG 2012</p>
<p>Download here:<br />
<a href="http://blog.aptivate.org/wp-content/uploads/2012/05/afnog-network-management-for-sme-presentation.pdf">Improving Network Management for Universities and SMEs</a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.aptivate.org/2012/05/14/improving-network-management-for-universities-and-smes/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>AfNOG 2012 Setup</title>
		<link>http://blog.aptivate.org/2012/05/05/afnog-2012-setup/</link>
		<comments>http://blog.aptivate.org/2012/05/05/afnog-2012-setup/#comments</comments>
		<pubDate>Sat, 05 May 2012 11:24:05 +0000</pubDate>
		<dc:creator>Chris Wilson</dc:creator>
				<category><![CDATA[AfNOG]]></category>
		<category><![CDATA[Africa]]></category>
		<category><![CDATA[Engineer's Log]]></category>
		<category><![CDATA[Infrastructure]]></category>
		<category><![CDATA[Internet]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Networking]]></category>
		<category><![CDATA[Open Source]]></category>
		<category><![CDATA[Software]]></category>
		<category><![CDATA[System Administration]]></category>
		<category><![CDATA[Training]]></category>

		<guid isPermaLink="false">http://blog.aptivate.org/?p=1019</guid>
		<description><![CDATA[I&#8217;m at the AfNOG Workshop 2012 in Serrekunda, Gambia as one of the instructors in the Scalable Services track (SS-E). A local TV company has reported about us on the local news, and you can watch the video. (Thanks to Nadejda Loumbeva for finding it on YouTube!) These are my notes from our setup for [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m at the <a href="http://www.ws.afnog.org/afnog2012/">AfNOG Workshop 2012</a> in Serrekunda, Gambia as one of the instructors in the <a href="http://www.ws.afnog.org/afnog2012/sse/">Scalable Services</a> track (SS-E).</p>
<p>A local TV company has reported about us on the local news, and you can <a href="http://www.youtube.com/watch?v=WtK6YotoGFM">watch the video</a>. (Thanks to <a href="http://loumbeva.wordpress.com/">Nadejda Loumbeva</a> for finding it on YouTube!)</p>
<p>These are my notes from our setup for 2012, building on the <a href="http://blog.aptivate.org/2011/05/28/afnog-2011-part-1/">virtualisation setup</a> from last year.</p>
<p>We are hosting on CentOS 6 this year. I had a lot of problems installing the VirtualBox RPM, with this error message:</p>
<pre>
error: unpacking of archive failed: cpio: read failed - No such file or directory
</pre>
<p>That almost had me abandon CentOS, but it turned out to be a corrupt download file.</p>
<p>CentOS 6 seems to install headless, which saves us memory, but makes the configuration of VirtualBox more challenging. Luckily we had most of the VBoxManage commands from last year.</p>
<h3>Remote headless installation</h3>
<p>VirtualBox for CentOS doesn&#8217;t appear to have VNC support at all. You need to install the extension pack, to enable RDP support, to get nice remote access to the machines to do the installation:</p>
<pre>
sudo VBoxManage extpack install Oracle_VM_VirtualBox_Extension_Pack-4.1.14-77440.vbox-extpack
</pre>
<p>Configure the Master virtual machine, ensuring that its first network interface is bridged to the host&#8217;s physical Ethernet interface and promiscuous mode is enabled:</p>
<pre>
VBoxManage modifyvm Master \
	--memory 256 \
	--nic1 bridged --bridgeadapter1 p4p1 \
	--nicpromisc1 allow-all --vram 4 \
	--pae off --audio none --usb on --uart1 0x3f8 4 \
	--uartmode1 server /home/inst/.VirtualBox/Master-console.pipe
</pre>
<p>To attach a 20GB virtual hard disk image to the Master virtual machine for installation:</p>
<pre>
VBoxManage createhd --filename VirtualBox\ VMs/Master/FreeBSD.vdi \
	--size 20480 --format VDI
VBoxManage storageattach Master --storagectl "IDE Controller" --port 0 \
	--device 0 --type hdd --medium VirtualBox\ VMs/Master/FreeBSD.vdi
</pre>
<p>To attach a FreeBSD ISO image to the Master virtual machine for installation:</p>
<pre>
VBoxManage storagectl Master --name "IDE Controller" --add ide
VBoxManage storageattach Master --type dvddrive --storagectl "IDE Controller" \
	--port 1 --device 0 --medium FreeBSD-8.3-RELEASE-i386-dvd1.iso
</pre>
<p>You can remove the virtual disk from the virtual CD-ROM drive like this:</p>
<pre>
VBoxManage storageattach Master --type dvddrive --storagectl "IDE Controller" \
	--port 1 --device 0 --medium emptydrive
</pre>
<p>This seems to trigger a <a href="http://forums.freebsd.org/showthread.php?t=24153">serious bug in FreeBSD</a> that makes the system unbootable. So instead, you can leave it connected but change the boot order so that the VM boots from disk instead of CD:</p>
<pre>
VBoxManage modifyvm Master --boot1 disk
</pre>
<p>To enable an RDP remote display on port 5900, for headless operation:</p>
<pre>
VBoxManage modifyvm Master --vrde=on --vrdeport=3380
</pre>
<p>To start the Master virtual machine:</p>
<pre>
VBoxManage startvm Master --type headless
</pre>
<p>If your virtual machine refuses to start, with an error like this:</p>
<pre>
[inst@host1 ~]$ VBoxManage startvm Master
Waiting for VM "Master" to power on...
VBoxManage: error: The virtual machine 'Master' has terminated unexpectedly during startup with exit code 0
VBoxManage: error: Details: code NS_ERROR_FAILURE (0x80004005), component Machine, interface IMachine, callee
</pre>
<p>It probably means that you&#8217;re running the command remotely without a GUI, and you forgot to add <code>--type headless</code>, so the graphical display can&#8217;t start. Thanks VirtualBox!</p>
<p>Install a caching nameserver such as BIND on the host, and when configuring the Master machine, set the DNS server to 10.0.3.2 to use the host&#8217;s DNS. This avoids problems using a DNS server on the network while all the clones are using the same IP address, resulting in long delays for SSH logins.</p>
<h3>Remote virtual serial console</h3>
<p>ConMan does indeed work for host to guest communication over the serial pipe, as an alternative to RDP. The following line enables the UNIX socket for the serial console, if you haven&#8217;t done this already (requires the virtual machine to be stopped):</p>
<pre>
VBoxManage modifyvm Master --uartmode1 server /home/inst/.VirtualBox/Master-console.pipe
</pre>
<p>The following line in <code>/etc/conman.conf</code> on the host enables the conman server:</p>
<pre>
console name="Master" dev="unix:/home/inst/.VirtualBox/Master-console.pipe"
</pre>
<p>To enable a serial terminal in a FreeBSD guest, add the following line to <code>/etc/ttys</code>:</p>
<pre>
ttyu0   "/usr/libexec/getty std.9600"   vt100   on secure
</pre>
<p>Then, after you start (or restart) <code>conmand</code>, you should be able to connect to the Master&#8217;s serial console like this:</p>
<pre>
conman Master
</pre>
<p>The escape sequence to terminate the conman session is &#038;. But this still isn&#8217;t a good way to mass-control multiple machines because <code>conman</code> doesn&#8217;t like commands being piped into it.</p>
<h3>Remote port-forwarded SSH management</h3>
<p>You can set up NAT port forwarding to a second virtual network interface in the guest, configured by DHCP, like this:</p>
<pre>
VBoxManage modifyvm Master --nic2 nat --natpf2 ssh,tcp,,4400,,22
</pre>
<p>This is really helpful when all your virtual machines start off with the same IP address. As long as you have SSH keys, you can iterate over all of them, using the host IP addresses, and update their network configurations to give them unique, preassigned IP addresses.</p>
<h3>FreeBSD proxy server configuration</h3>
<p>To save bandwidth and speed up package installation, I added the following to <code>/etc/profile</code>:</p>
<pre>
export FTP_PROXY=http://196.200.223.1:3128
export HTTP_PROXY=http://196.200.223.1:3128
export http_proxy=http://196.200.223.1:3128
</pre>
<h3>Bulk virtual machine management</h3>
<p>This is a shorter and more efficient script to create the guest virtual machines by snapshotting and cloning the master image, resulting in less disk usage (faster host and guest cloning) and more efficient disk cache usage (faster guest operation):</p>
<blockquote><p>
create-vms.sh</p>
<pre>
#!/bin/bash

set -e
set -x

master=Master
snapshot="Clone Source `date --rfc-3339=seconds`"
VBoxManage snapshot "$master" take "$snapshot" --pause

cd ~/"VirtualBox VMs"
for i in {1..7}; do
	# echo $i
	vmname=VM0$i
	if [ "$1" = "-f" ]; then
		VBoxManage unregistervm "$vmname" --delete || true
	fi
	VBoxManage clonevm "$master" --name "$vmname" --options link \
		--options keepdisknames --snapshot "$snapshot" --register
	VBoxManage modifyvm "$vmname" --memory 256 \
		--natpf2 "ssh-$vmname",tcp,,$[4400+$i],,22 \
		--uartmode1 server /home/inst/.VirtualBox/"$vmname"-console.pipe \
		--vrde=on --vrdeport=$[3380+$i]
done
</pre>
</blockquote>
<p>Note that you have to use a unique snapshot name for each new snapshot of the master image. VirtualBox doesn&#8217;t stop you from reusing an old name, but when you clone the master, you get a copy of the <strong>oldest</strong> snapshot with that name, not the latest one.</p>
<p>This script logs into each VM using the NAT port forwarding from the host, which works even when their IP address is not configured yet, sets their hostname and IP address and reboots them:</p>
<blockquote><p>
configure-vms.sh</p>
<pre>
#!/bin/bash

# set -e
set -x

guests_per_host=7

for host in 1; do
	hostname="196.200.219.$[200+$host]"
	for guest in `seq 1 $guests_per_host`; do
		nat_ssh_port=$[4400+$guest]
		guest_ip_suffix="$[($host-1)*$guests_per_host + $guest]"
		guest_ip="196.200.219.$guest_ip_suffix"
		guest_name="vm0$guest-host$host-ip$guest_ip_suffix.sse.ws.afnog.org"
		ssh root@$hostname -p $nat_ssh_port \
			-o "StrictHostKeyChecking no" &lt;&lt; EOF
set -x
sed 	-e 's/hostname=.*/hostname="$guest_name"/' \
	-e 's/ifconfig_em0=.*/ifconfig_em0="inet $guest_ip netmask 255.255.255.0"/' \
	-i '' /etc/rc.conf
reboot
EOF
	done
done
</pre>
</blockquote>
<h3>Starting virtual machines automatically</h3>
<p>We want all the virtual machines to start at boot time. My usual sudo trick doesn&#8217;t work in /etc/rc.local, but thanks to <a href="http://maymay.net/blog/2010/03/17/how-to-work-around-sorry-you-must-have-a-tty-to-run-sudo-without-sacrificing-security/">this blog post</a> I found a way:</p>
<blockquote><p>
/etc/rc.local</p>
<pre>
su --session-command "VBoxManage startvm VM01 --type headless" inst
su --session-command "VBoxManage startvm VM02 --type headless" inst
su --session-command "VBoxManage startvm VM03 --type headless" inst
su --session-command "VBoxManage startvm VM04 --type headless" inst
su --session-command "VBoxManage startvm VM05 --type headless" inst
su --session-command "VBoxManage startvm VM06 --type headless" inst
su --session-command "VBoxManage startvm VM07 --type headless" inst
</pre>
</blockquote>
<p>We also want the host to shut them down cleanly:</p>
<blockquote><p>
/etc/default/virtualbox-ose</p>
<pre>
SHUTDOWN_USERS=inst
SHUTDOWN=acpibutton
</pre>
</blockquote>
<h3>Assign unique MAC addresses</h3>
<p>After creating the remaining virtual machine hosts, by cloning the first one, and if you update and copy out the virtual machine disk images again, it&#8217;s important to randomise all the MAC addresses of all the hosts. If two virtual machines have the same MAC address, routers will have problems learning their addresses. You can do that in bulk with this command:</p>
<pre>
for i in `seq 201 208`; do
ssh -t inst@196.200.219.$i '
./manage-vms.sh controlvm acpipowerbutton
./manage-vms.sh modifyvm --macaddress1 auto
./manage-vms.sh startvm --type headless'
done
</pre>
<h3>Automatic Ubuntu desktop installation</h3>
<p>We received 12 desktops with Windows in various states of repair, and decided to reformat them all and install Ubuntu. Since there were several hardware variations, I did this using Debian/Ubuntu installation preseeding instead of system imaging.</p>
<p>Preseed options which need to be decided before networking is initialised cannot be stored in the <code>preseed</code> file, so they must be<br />
passed to the kernel on the command line:</p>
<ul>
<li>debian-installer/locale=en_US</li>
<li>netcfg/get_hostname=desktop.sse.ws.afnog.org</li>
<li>console-setup/ask_detect=false</li>
<li>console-setup/layoutcode=us</li>
</ul>
<p>This is the <code>pxelinux</code> configuration that we used:</p>
<blockquote><p>
/var/lib/tftpboot/pxelinux.cfg/default</p>
<pre>
label ubuntu
  menu label Install ^Ubuntu (10.04.4 alternate i386)
  kernel ubuntu-10.04.4-alternate-i386/linux
  append initrd=ubuntu-10.04.4-alternate-i386/initrd.gz url=http://196.200.219.200/tftp/ubuntu-10.04.4-alternate-i386/preseed.txt netcfg/get_hostname=desktop.sse.ws.afnog.org debian-installer/locale=en_US console-setup/ask_detect=false console-setup/layoutcode=us
  menu default
</pre>
</blockquote>
<p>Using preseeding, we were able to automate almost all of the installation process, providing a nearly unattended install. I wasn&#8217;t able to preseed the partition selection for some reason; the <a href="https://help.ubuntu.com/10.04/installation-guide/i386/preseed-contents.html#preseed-partman">instructions</a> did not appear to work.</p>
<p>This is the preseed configuration file we used:</p>
<blockquote><p>
preseed.txt</p>
<pre>
d-i netcfg/wireless_wep string
d-i mirror/country string enter information manually
d-i mirror/http/hostname string 196.200.219.200
d-i mirror/http/directory string /ubuntu-10.04.4-alternate-i386/ubuntu/
d-i mirror/http/proxy string http://196.200.219.200:3128/
d-i partman-auto/init_automatically_partition select Guided - use entire disk
d-i partman-auto/disk string /dev/discs/disc0/disc
d-i partman-auto/method string regular
d-i partman-auto/purge_lvm_from_device boolean true
d-i partman-lvm/confirm boolean true
d-i partman-auto/choose_recipe \
       select All files in one partition (recommended for new users)
d-i partman/confirm_write_new_label boolean true
d-i partman/choose_partition \
       select Finish partitioning and write changes to disk
d-i partman/confirm boolean true
d-i clock-setup/utc boolean true
d-i clock-setup/ntp boolean true
d-i time/zone string Africa/Banjul
d-i passwd/user-fullname string AfNOG User
d-i passwd/username string afnog
d-i passwd/user-password password afnog
d-i passwd/user-password-again password afnog
d-i user-setup/allow-password-weak boolean true
d-i user-setup/encrypt-home boolean false
d-i grub-installer/only_debian boolean true
d-i grub-installer/with_other_os boolean true
tasksel tasksel/first multiselect standard, ubuntu-desktop
popularity-contest popularity-contest/participate boolean true
d-i pkgsel/update-policy select unattended-upgrades
d-i finish-install/reboot_in_progress note
xserver-xorg xserver-xorg/autodetect_monitor boolean true
xserver-xorg xserver-xorg/config/monitor/lcd boolean true
</pre>
</blockquote>
<p>I ran into <a href="http://administratosphere.wordpress.com/2011/04/29/ubuntu-kickstart-installs-and-corrupt-packages-file/">this issue</a> while preseeding the Lucid desktop install: the installer reports an error and refuses to proceed:</p>
<blockquote><p>
http://server/ubuntu/lucid/dists/lucid/restricted/binary-i386/Packages was corrupt
</p></blockquote>
<p>The solution presented there basically worked. The steps I used were:</p>
<pre>
sudo cp -a ubuntu-10.04.4-alternate-i386/dists/lucid/restricted/binary-i386/ lucid-restricted-binary-i386.bugfix
cd lucid-restricted-binary-i386.bugfix/
sudo gunzip Packages.gz
cd ..
sudo mount --bind lucid-restricted-binary-i386.bugfix ubuntu-10.04.4-alternate-i386/dists/lucid/restricted/binary-i386/
</pre>
<p>If you use a Squid cache in front of your Ubuntu repository web server, for caching security updates, then it will cache the corrupted <code>Packages</code> file that you deleted in the above step, and the error will persist. I recommend you exclude the local web server from your Squid cache like this:</p>
<blockquote><p>
/etc/squid/squid.conf</p>
<pre>
acl localweb dstdomain 196.200.219.200
cache deny localweb
</pre>
</blockquote>
]]></content:encoded>
			<wfw:commentRss>http://blog.aptivate.org/2012/05/05/afnog-2012-setup/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>A tale of five bugs: Django Intranets on Windows</title>
		<link>http://blog.aptivate.org/2012/04/17/a-tale-of-fiv-bugs-django-intranets-on-windows/</link>
		<comments>http://blog.aptivate.org/2012/04/17/a-tale-of-fiv-bugs-django-intranets-on-windows/#comments</comments>
		<pubDate>Tue, 17 Apr 2012 18:30:17 +0000</pubDate>
		<dc:creator>Chris Wilson</dc:creator>
				<category><![CDATA[Django]]></category>
		<category><![CDATA[Engineer's Log]]></category>
		<category><![CDATA[Intranet]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Microsoft]]></category>
		<category><![CDATA[Open Source]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Software]]></category>
		<category><![CDATA[System Administration]]></category>

		<guid isPermaLink="false">http://blog.aptivate.org/?p=1010</guid>
		<description><![CDATA[I&#8217;m in Ethiopia working with the ATA to help install their Intranet. (Aside: Ethiopia has great, cheap food and beer, and fairly bad Internet.) Because they really want to run the server locally, and they only have Windows servers, we agreed to try to make it run on Windows. We haven&#8217;t done many deployments of [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m in Ethiopia working with the <a href="http://www.ata.gov.et/">ATA</a> to help install their Intranet. (Aside: Ethiopia has great, cheap food and beer, and fairly bad Internet.) Because they really want to run the server locally, and they only have Windows servers, we agreed to try to make it run on Windows.</p>
<p>We haven&#8217;t done many deployments of Django applications on Windows, and it always seems to be a challenge. Integration with Microsoft IIS seems to be a non-starter. Apache works, but getting the right combination of Python, MySQL, Apache and mod_wsgi installed is very challenging. I thought our worries were over when we discovered <a href="http://bitnami.org/stack/djangostack">BitNami djangoStack</a>, which installs a well-tested combination of all the above, and we successfully deployed a project on this stack.</p>
<p>So I didn&#8217;t worry much about how to get our <a href="https://github.com/aptivate/intranet">newest application</a> running on Windows. How wrong I was. This little jolly turned into a two-day exercise in frustration that pushed all my Python, C, Java, Windows and SQL skills to the limit.</p>
<dl>
<dt>Learning 1</dt>
<dd>Never assume that deployment on a new platform will be easy. Especially on Windows. Software deployment is hard.</dd>
</dl>
<p>I had some problems with our deployment script, which is supposed to make deployment easier by scripting the steps necessary to install and configure the applications&#8217; dependencies. This is very useful for allowing users without Django expertise to deploy applications, by reducing the number of steps required, but in many places they assume a Linux environment. I think I&#8217;ve fixed all of these now.</p>
<p>One of the tasks of this script is to create a <a href="http://pypi.python.org/pypi/virtualenv">virtualenv</a> which allows an application&#8217;s Python dependencies (Python extension libraries) to be installed in a subdirectory, where they can easily be removed and reinstalled. This even works for libraries that require compilation, <b>if you have a compiler installed</b>. All our Linux servers have <code>gcc</code> installed by default, so this hasn&#8217;t been a problem for us, except for the above-mentioned first Windows deployment. At that time, we discovered some binary packages that could be installed on the Windows host system, outside the virtualenv, to provide these features. But they didn&#8217;t include everything that our Intranet needs, so I had to add <a href="http://heanet.dl.sourceforge.net/project/pywin32/pywin32/README.txt">PyWin32</a> and <a href="http://effbot.org/downloads/#pil">PIL</a> to that list.</p>
<p>Then I discovered that our migrations wouldn&#8217;t run. There are several bugs with migrations on MySQL:</p>
<ul>
<li><a href="http://south.aeracode.org/ticket/471">Renaming a column which is a foreign key</a>: &#8220;MySQL doesn&#8217;t bother to re-point the foreign key constraints when you change a column name.&#8221;</li>
<li><a href="http://south.aeracode.org/ticket/523">Making a foreign key nullable after creation</a>: MySQL 5.5 broke backwards compatibility, the fix is in South 0.7.4.</li>
<li>You also can&#8217;t rename a column that has a UNIQUE key on it, and apparently can&#8217;t remove the UNIQUE key either, because South complains that it doesn&#8217;t exist.</li>
</ul>
<p>I ended up having to completely abandon the migrations in one of the apps that makes up the Intranet. Luckily nobody&#8217;s using it yet, so it won&#8217;t cause problems.</p>
<p>The second issue was with the <a href="http://blog.aptivate.org/2012/02/01/content-indexing-in-django-using-apache-tika/">Apache Tika integration</a>. I already spent several days working out how to integrate a JVM into the Python server process directly. I decided to abandon that approach for Windows, because I didn&#8217;t want to deal with the issues of compiling custom DLLs and embedding JVMs on a platform that I know less about, including potential threading conflicts between Apache, Python and Java in the same process.</p>
<p>Tika has a standalone server mode with a <a href="http://wiki.apache.org/tika/TikaJAXRS">web service API</a> which turned out to be fairly easy to call from Python:</p>
<pre>
    from httplib import HTTPConnection
    conn = HTTPConnection('localhost', 9998, True, 30)
    buffer = open(path) # wrong! see below
    conn.request('PUT', '/tika', buffer)
    response = conn.getresponse()
    if response.status != 200:
        raise Exception("Unknown response from TIKA server: %s: %s" %
            (response.status, response.reason))
    return response.read()
</pre>
<p>This server runs as a stand-alone application, and unlike Unix, Windows makes it fairly hard to set up such an application to be started at boot time, with no users logged in to the server. I had assumed that for a Java application, this was a solved problem, but I was wrong. As usual, Stack Overflow was very helpful, turning up a <a href="http://stackoverflow.com/questions/68113/how-to-create-a-windows-service-from-java-app">bunch of suggestions</a>, several of which I tried and failed to implement:</p>
<ul>
<li><a href="http://www.claytonstechnobabble.com/2011/08/run-any-application-as-windows-service.html">srvany.exe</a> abandons the child process, which means that you need to use Task Manager to kill it if you want to restart it. It remains an option, but not ideal.</li>
<li><a href="http://support.microsoft.com/kb/251192">sc.exe</a> is bundled with Windows XP, but also abandons the child process.</li>
<li><a href="http://wrapper.tanukisoftware.org/doc/english/introduction.html">Java Service Wrapper</a> is not free for 64-bit Windows, and I didn&#8217;t want to become dependent on a 32-bit JVM because that might not be possible in a future deployment, but it remains an option, if the 32-bit version runs on 64-bit Windows (not tested). Also, &#8220;the configuration file can get a little crazy&#8221;!</li>
<li><a href="http://yajsw.sourceforge.net/">YAJSW</a> aims to clone JSW without the license restriction, but I couldn&#8217;t understand how to use it from the documentation.</li>
<li><a href="http://commons.apache.org/daemon/index.html">Apache Commons Daemon</a> requires launching a separate process to tell the server process to shut down. Tomcat supports this with its control port listener, and so does plain Jetty, but Tika&#8217;s embedded Jetty doesn&#8217;t provide such a listener, and I didn&#8217;t fancy writing one.</li>
<li><a href="http://winrun4j.sourceforge.net/">WinRun4J</a> looked ideal, and ran the application absolutely fine on the command line.</li>
<li><a href="http://forge.objectweb.org/projects/javaservice/">JavaService</a>, apart from its obnoxious &#8220;free registration required&#8221; to download, was really difficult to work out how to use with the limited and broken documentation. When the command-line tool failed to accept any of the (documented) arguments I tried to pass to it, I gave up.</li>
<li>I didn&#8217;t like the idea of writing a service wrapper in Perl or .NET and adding another dependency.</li>
<li><a href="http://kenai.com/projects/winsw">WinSW</a> is written in .NET, I didn&#8217;t investigate further.</li>
<li><a href="http://www.firedaemon.com/">FireDaemon</a> would probably work, it&#8217;s not free.</li>
<li><a href="http://jslwin.sourceforge.net/">JSL</a> (Java Service Launcher) would probably work too. I couldn&#8217;t find the <a href="http://jslwin.sourceforge.net/howto.html">documentation</a> when I first looked at it.</li>
<li><a href="http://jsmooth.sourceforge.net/index.php">JSmooth</a> might also work, I missed it the first time.</li>
</ul>
<p>At this point I was left with only WinRun4J as an option. I discovered that you have to write a service class, using their JAR, to run your application as a service, so I wrote one. I had to bodge the classpath to compile it, since Tika uses Maven and WinRun4J <a href="http://sourceforge.net/tracker/index.php?func=detail&#038;aid=2984341&#038;group_id=195634&#038;atid=954232">isn&#8217;t available in Maven repositories</a>.</p>
<p>Then I wasted an hour with an <a href="http://sourceforge.net/projects/winrun4j/forums/forum/693148/topic/4804942">undocumented problem</a> when I added the <code>service.class</code> to my <code>winrun4j.ini</code> without removing the <code>main.class</code> entry, causing this misleading error message:</p>
<pre>
[err] Could not find service class
java.lang.NoClassDefFoundError: org.apache.tika.server.TikaServiceWinRun4J
</pre>
<p>After solving that one, I came to a problem that I couldn&#8217;t solve:</p>
<pre>
SEVERE: Can't start
java.lang.NullPointerException
        at com.sun.jersey.core.spi.scanning.PackageNamesScanner$ResourcesProvider$1.getResources(PackageNamesScanner.java:170)
        at com.sun.jersey.core.spi.scanning.PackageNamesScanner.scan(PackageNamesScanner.java:135)
        at com.sun.jersey.api.core.ScanningResourceConfig.<init>(ScanningResourceConfig.java:80)
        at com.sun.jersey.api.core.PackagesResourceConfig.</init><init>(PackagesResourceConfig.java:104)
        at com.sun.jersey.api.core.PackagesResourceConfig.</init><init>(PackagesResourceConfig.java:78)
        at TikaServiceWinRun4J.serviceMain(TikaServiceWinRun4J.java:83)
[info] Service method completed...
</init></pre>
<p>I spent much time wondering how to debug this, whether I could attach a debugger to a WinRun4J process while it was still starting up, etc. I gave up at that point and went home, still turning the problem over in my mind. Then it occured to me that the Tika web service is implemented using what appears to be a <a href="http://jersey.java.net/nonav/apidocs/1.1.1-ea/jersey/com/sun/jersey/spi/container/servlet/ServletContainer.html">standard Java servlet</a>, and if I could install that servlet into a servlet container like <a href="http://tomcat.apache.org/">Tomcat</a>, which has its own service integration with Windows, that would solve the startup problem. And it did, with the help of the <a href="http://maven.apache.org/maven-1.x/plugins/war/">Maven WAR plugin</a> which made it trivial. (At times like this I love Maven; at other times I hate its complexity.) I submitted a <a href="https://issues.apache.org/jira/browse/TIKA-894">patch</a> to the Tika developers in the hope that this will be adopted as a standard deployment method for Tika server.</p>
<p>Along the way, I discovered that the standalone Tika Server (command-line JAR) is <a href="https://issues.apache.org/jira/browse/TIKA-893">pretty badly broken</a>: it appears to work, but it can only extract content from Ogg Vorbis files and nothing else! I didn&#8217;t manage to fix this properly, but I did come up with a workaround, described in that ticket, which disables the Ogg Vorbis support and re-enables support for other formats that are more important to us, like Microsoft Word and Excel.</p>
<p>So finally, I was able to run the Django application under Apache on Windows, and log in and upload documents. But wait, what&#8217;s this? Error 500 from Tika? WHY?!</p>
<p>Tika wasn&#8217;t logging anything useful, so I had to fire up <a href="http://www.wireshark.org/">Wireshark</a> to inspect the conversation between the client (the Intranet application) and the server (Tika). And thanks to Microsoft&#8217;s infinite wisdom in removing the loopback interface when they ripped thir TCP/IP network code out of BSD, it&#8217;s <a href="http://stackoverflow.com/questions/46376/windows-packet-sniffer-that-can-capture-loopback-traffic">not possible to listen for loopback traffic on Windows</a>, so I had to point the Intranet on Windows at a Tika server on another machine to capture the traffic.</p>
<p>Then I discovered that <a href="http://docs.python.org/library/httplib.html">httplib</a> was telling the server that it was going to send 7168 bytes, but only sending 6. Tomcat waited 20 seconds for the rest, and then timed out the request, returning an Error 500 as I saw earlier, and helpfully not logging anything. So why was httplib not sending all the data? I stepped into it with a debugger and discovered a problem with one of the lines I wrote above:</p>
<pre>
    buffer = open(path)
</pre>
<p>On Unix this works fine, but on Windows it opens the file in ASCII mode by default, which stops at the first ^Z (hex 1A) character in the file. And guess what&#8217;s at byte 7 of every Excel XLS file?</p>
<p>And so onto the fifth bug. Although the intranet appeared to work fine, it would sometimes pop up a scary error message on the server:</p>
<pre>
Program: C:\PROGRA~1\BITNAM~1\apache2\bin\httpd.exe
R6034
An application has made an attempt to load the C runtime library incorrectly.
</pre>
<p>Past experience told me this was probably due to one of the Python extensions missing an embedded manifest, which would be required to tell Windows which version of the Microsoft C Runtime it&#8217;s supposed to use. However I had great difficulty tracking down the culprit. A bug in the <a href="http://groups.google.com/group/pyinstaller/browse_thread/thread/c4d7b57ef3a5bf8b">PIL installer</a> turned out to be a red herring, and while we&#8217;ve seen this problem in LXML in the past, it wasn&#8217;t there this time.</p>
<p>Eventually, after much soul-searching, I downloaded <a href="http://technet.microsoft.com/en-us/sysinternals/bb896645">Process Monitor</a> and configured it to monitor all file activity from <code>httpd.exe</code> processes. I found out that Apache was loading <code>msvcr90.dll</code> from <code>C:\Program Files\BitNami DjangoStack\Apache2\Bin</code>, which is a strange place to find it, because normally it would be installed in <code>C:\Windows\WinSxS</code>. I discovered manifest files in that directory that might confuse Windows into loading this copy instead. That can potentially end up with <a href="http://bugs.python.org/issue4120#msg74742">multiple copies of the DLL loaded</a>, which can result in random crashes, but in this case I think it was detected early.</p>
<p>Removing the <code>msvc*90.dll</code> and <code>Microsoft.VC90*.manifest</code> files from that directory didn&#8217;t solve the problem completely, because there was another copy of them in <code>C:\Program Files\BitNami DjangoStack\Python</code>. But with those second copies removed as well&#8230;</p>
<p><strong>The intranet now runs on Windows!</strong></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.aptivate.org/2012/04/17/a-tale-of-fiv-bugs-django-intranets-on-windows/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Sending email from Django</title>
		<link>http://blog.aptivate.org/2012/03/29/sending-email-from-django/</link>
		<comments>http://blog.aptivate.org/2012/03/29/sending-email-from-django/#comments</comments>
		<pubDate>Thu, 29 Mar 2012 13:51:36 +0000</pubDate>
		<dc:creator>Chris Wilson</dc:creator>
				<category><![CDATA[Code Kitchen]]></category>
		<category><![CDATA[Django]]></category>
		<category><![CDATA[Email]]></category>
		<category><![CDATA[Engineer's Log]]></category>
		<category><![CDATA[Intranet]]></category>
		<category><![CDATA[Open Source]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Software]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[agile]]></category>

		<guid isPermaLink="false">http://blog.aptivate.org/?p=1004</guid>
		<description><![CDATA[Yesterday I wanted to send email notifications for document changes in the Generic Intranet. I found that the built-in Django method requires you to hard-code the email body. It doesn&#8217;t support rendering email from templates, unlike Ruby on Rails, which is surprising and a shame. I spent some time coding template support for it, and [...]]]></description>
			<content:encoded><![CDATA[<p>Yesterday I wanted to send email notifications for document changes in the <a href="http://github.com/aptivate/intranet">Generic Intranet</a>. I found that the <a href="http://docs.djangoproject.com/en/dev/topics/email/">built-in Django method</a> requires you to hard-code the email body. It doesn&#8217;t support rendering email from templates, <a href="http://guides.rubyonrails.org/action_mailer_basics.html#mailer-views">unlike Ruby on Rails</a>, which is surprising and a shame.</p>
<p>I spent some time coding template support for it, and then when I tried to make it reusable, discovered that others had had the same idea.</p>
<dl>
<dt>Learning 1:</dt>
<dd>django is conservative. Lots of useful things never make it into the core. Search djangopackages.com for what you want before writing it. It has a LOT of packages.</dd>
<dt>Learning 2:</dt>
<dd>there&#8217;s an existing document management package called <a href="http://rosarior.github.com/mayan/index.html">Mayan EDMS</a>, that does most of what <a href="https://github.com/aptivate/intranet-documents">ours</a> does, which we could look at replacing or merging ours with.
</dd>
</dl>
<p>I found two email-sending packages that support templates:</p>
<ul>
<li><a href="https://github.com/artemrizhov/django-mail-templated">django-mail-templated</a> has an object-oriented interface but no tests;</li>
<li><a href="https://github.com/bradwhittington/django-templated-email">django-templated-email</a> has tests but no object-oriented interface.</li>
</ul>
<p>I decided to check out the object-oriented one, on a pretty much random basis, and add tests to it. You can find my fork of it <a href="https://github.com/aptivate/django-mail-templated">here</a>.</p>
<dl>
<dt>Learning 3:</dt>
<dd>If you want to send emails from a Django project, use <a href="https://github.com/aptivate/django-mail-templated">our email app</a>.</dd>
<dt>Learning 4:</dt>
<dd>if you want to send notifications in some kind of generic framework, not just email, have a look at the <a href="https://github.com/jtauber/django-notification/blob/master/docs/usage.txt">django-notification</a> app instead.</dd>
<dt>Learning 5 (meta-learning):</dt>
<dd>it&#8217;s useful to email round things that we discovered, like this one, as someone might have discovered this before and not told anyone, meaning that I had to spend time discovering it again; and also we can comment on each others&#8217; discoveries and add to them.</dd>
</dl>
]]></content:encoded>
			<wfw:commentRss>http://blog.aptivate.org/2012/03/29/sending-email-from-django/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Content indexing in Django using Apache Tika</title>
		<link>http://blog.aptivate.org/2012/02/01/content-indexing-in-django-using-apache-tika/</link>
		<comments>http://blog.aptivate.org/2012/02/01/content-indexing-in-django-using-apache-tika/#comments</comments>
		<pubDate>Wed, 01 Feb 2012 13:12:44 +0000</pubDate>
		<dc:creator>Chris Wilson</dc:creator>
				<category><![CDATA[Django]]></category>
		<category><![CDATA[Engineer's Log]]></category>
		<category><![CDATA[Infrastructure]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Microsoft]]></category>
		<category><![CDATA[Open Source]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Software]]></category>
		<category><![CDATA[System Administration]]></category>

		<guid isPermaLink="false">http://blog.aptivate.org/?p=992</guid>
		<description><![CDATA[For the Documents module of our new open-source Generic Intranet, we need to be able to extract the text content and metadata from various kinds of documents: PDF files Microsoft Office DOC, XLS and PPT files and the new XML equivalents, DOCX, XLSX and PPTX. I found various tools online to help extract this text, [...]]]></description>
			<content:encoded><![CDATA[<p>For the Documents module of our new open-source <a href="https://github.com/aptivate/intranet">Generic Intranet</a>, we need to be able to extract the text content and metadata from various kinds of documents:</p>
<ul>
<li>PDF files</li>
<li>Microsoft Office DOC, XLS and PPT files</li>
<li>and the new XML equivalents, DOCX, XLSX and PPTX.</li>
</ul>
<p>I found various tools online to help extract this text, largely thanks to Stack Overflow <a href="http://superuser.com/questions/165978/command-line-tool-in-linux-to-extract-text-from-word-excel-powerpoint-or-co">here</a> and <a href="http://stackoverflow.com/questions/888784/extract-text-from-a-powerpoint-ppt-or-pptx-file">here</a>. This ended up with a hodgepodge of tools:</p>
<ul>
<li><a href="http://www.unixuser.org/~euske/python/pdfminer/">PDF Miner</a> for PDF files</li>
<li><a href="http://github.com/mikemaccana/python-docx/tarball/master">python-docx</a> for DOCX files</li>
<li><a href="http://silvercoders.com/en/products/doctotext/">DocToText</a> for PPTX, XLSX and PPT files</li>
<li><a href="http://www.winfield.demon.nl/">antiword</a> for DOC files</li>
</ul>
<p>There were a number of problems with this hodgepodge:</p>
<ul>
<li>I was <strong>unable to find</strong> any Python or command-line solution for <strong>old Excel (XLS) files</strong><strong>;</strong></li>
<li>These solutions did not extract metadata, only document text;</li>
<li>The choice of which tool to use depends on the MIME type returned by the <a href="http://www.darwinsys.com/file/">file(1)</a> command, which varies depending on the OS (Debian/Ubuntu or CentOS) and which version of the library is installed</li>
</ul>
<p><a href="http://stackoverflow.com/questions/2239459/python-based-document-metadata-parser">Another Stack Overflow post</a> recommended Apache Tika for metadata extraction. It appears to support all the document formats that we need, and to have auto-detection of the document format, which solves all the MIME type problems as well. However, it introduces a new problem: it&#8217;s written in Java, which is hard to access from Python.</p>
<p>Luckily I found some <a href="http://redmine.djity.net/projects/pythontika/wiki">instructions</a> for building a Python wrapper around Tika, using some tools that I&#8217;d never heard of, and this seemed like a good approach. Unfortunately the installation process is very non-standard, which would not fit in with our fabric-based automated deployment process, and would make it harder for users to install the Intranet themselves.</p>
<p>The instructions are somewhat outdated at the time of writing, as they refer to Tika version 0.7, while 1.0 has been released. I was unable to register for an account to update that page, so I wrote to the author with the details that I discovered, and will also document here that the following command works for me:</p>
<pre>python ../jcc/jcc/__main__.py \
        --include /usr/share/java/org.eclipse.osgi.jar \
        --jar tika-parsers-1.0.jar \
        --jar tika-core-1.0.jar \
        java.io.File java.io.FileInputStream \
        java.io.StringBufferInputStream \
        --package org.xml.sax \
        --include tika-app-1.0.jar \
        --python tika --version 1.0 --reserved asm</pre>
<p>I was able to go further than this, and package Tika in a way that makes it easy to install with Pip, and thus integrate with our deployment process.</p>
<p>The wrapper is written using JCC, which works by generating and compiling C++ code that links to the Java classes, and then a Python wrapper around that C++. This means that it needs to be recompiled for each platform, so I couldn&#8217;t just distribute a binary blob with the Intranet (I had the same problem with DocToText above).</p>
<p>The version of setuptools on our servers doesn&#8217;t support JCC&#8217;s <a href="http://lucene.apache.org/pylucene/jcc/documentation/install.html#shared">shared library mode</a>. JCC dies with an error if it&#8217;s not explicitly disabled or the patch applies. I couldn&#8217;t do either of these as part of our standard deployment process. So I <a href="https://github.com/aptivate/jcc">patched JCC</a> to disabled shared mode, since we don&#8217;t need it anyway. I also added some patches to allow various <code>setup.py</code> commands used by <code>pip</code> to be forwarded through JCC to the <code>setup</code> function call.</p>
<p>This seems to be enough to allow you to install JCC like this:</p>
<pre>pip install git+git://github.com/aptivate/jcc.git</pre>
<p>I also wrote a setup.py file that handles pip&#8217;s command line invokations and passes the necessary options to JCC, and JCC&#8217;s invocation of the setup function. This seems to be enough to install the package using pip:</p>
<pre>pip install git+git://github.com/aptivate/python-tika.git</pre>
<p>and you can use the last parameter as a package specification in pip_packages.txt, or whatever you pass to pip -r.</p>
<p>You can find the pip-installable Tika package, complete with <a href="http://repo1.maven.org/maven2/org/apache/tika/">Tika 1.0 JAR files</a>, in our <a href="https://github.com/aptivate/python-tika">python-tika</a> repository on Github. This will save you the work of downloading and compiling Tika and all of its dependencies. I have started a <a href="http://mail-archives.apache.org/mod_mbox/lucene-pylucene-dev/201202.mbox/%3Calpine.DEB.2.02.1202011310060.5732%40lap-x201%3E">discussion</a> with the JCC developers about merging these changes into the upstream project.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.aptivate.org/2012/02/01/content-indexing-in-django-using-apache-tika/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Rough Guide to rural data collection with ODK</title>
		<link>http://blog.aptivate.org/2011/12/05/rough-guide-to-rural-data-collection-with-odk/</link>
		<comments>http://blog.aptivate.org/2011/12/05/rough-guide-to-rural-data-collection-with-odk/#comments</comments>
		<pubDate>Mon, 05 Dec 2011 17:58:43 +0000</pubDate>
		<dc:creator>Chris Wilson</dc:creator>
				<category><![CDATA[Appropriate Technology]]></category>
		<category><![CDATA[Database]]></category>
		<category><![CDATA[Engineer's Log]]></category>
		<category><![CDATA[Internet]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[Mobiles]]></category>
		<category><![CDATA[Open Source]]></category>
		<category><![CDATA[data collection]]></category>

		<guid isPermaLink="false">http://blog.aptivate.org/?p=986</guid>
		<description><![CDATA[This post has three purposes, which I think overlap sufficiently to combine them: A User Guide for the system that we developed for UNICEF, IDS and RuralNet Zambia A Developers&#8217; Guide for anyone wishing to build something similar Notes on lessons learned that may assist future implementers Project goals Automate the data entry part of [...]]]></description>
			<content:encoded><![CDATA[<p>This post has three purposes, which I think overlap sufficiently to combine them:</p>
<ul>
<li>A User Guide for the system that we developed for UNICEF, IDS and RuralNet Zambia</li>
<li>A Developers&#8217; Guide for anyone wishing to build something similar</li>
<li>Notes on lessons learned that may assist future implementers</li>
</ul>
<h3>Project goals</h3>
<p>Automate the data entry part of a long paper-based survey, by replacing the paper forms with electronic devices.</p>
<h3>Hardware and application selection</h3>
<p>The survey has several long and complex questions, and long sets of multiple-choice answers. The data collection needs to be done in dusty rural Zambia, and the devices might need to be used for a full day without power. Collected data should be sent wirelessly to a secure data repository at some time after collection.</p>
<p>Text entry is required for many fields. That means either a real keyboard with keys, or a sufficiently large touch screen to type comfortably on. Use of the device camera, and presentation of reports and graphs on the same device, might be required in future.</p>
<p>Two possible hardware platforms were identified:</p>
<ul>
<li>Tablet laptops with touch screens</li>
<li>Tablet mobile devices (iPad or Android tablet)</li>
</ul>
<p>We selected the latter for this project due to lower cost, lighter weight, better usability and longer battery life.</p>
<p>The available software options that we identified were:</p>
<ul>
<li>EpiSurveyor (Java J2ME, partly closed source, we have used before and fixed bugs)</li>
<li>OpenXdata (Java J2ME, open source, developed and supported by an Aptivate alumnus among others)</li>
<li>Open Data Kit (ODK) (Android, open source, active community)</li>
<li>Bespoke online/offline survey in HTML5</li>
</ul>
<p>Of these, we eliminated EpiSurveyor and OpenXdata due to lack of compatibility with the hardware platform(s) we had chosen.</p>
<p>We chose ODK over a bespoke system due to limited time available for development, and ability to easily take photos and record GPS coordinates using the device&#8217;s hardware.</p>
<p>Of the available Android tablet devices, we chose the Samsung Galaxy Tab for the pilot project, due to its high quality construction. For future projects we would probably use a lower cost device; see the lessons learned for details.</p>
<h3>Form creation</h3>
<p>Since the survey is quite long (about 230 questions) we wanted an easy way to enter the questions. The ODK application requires the form to be in XForms format. We identified the following tools for creating XForms:</p>
<ul>
<li><a href="http://opendatakit.org/use/build">ODK Build</a></li>
<li><a href="http://code.google.com/p/purcforms/">PurcForms</a></li>
<li><a href="https://sites.google.com/site/kobodesk/kobo-form-builder">Kobo Form Builder</a></li>
<li><a href="http://opendatakit.org/use/xls2xform">XLS2XForm</a> (actually the <a href="https://github.com/jbeorse/pyxform">pyxform</a> fork)</li>
</ul>
<p>We decided to use XLS2XForm, which enabled us to enter the large number of questions easily in Excel. The others all have graphical builders, which have advantages and disadvantages for less technical users:</p>
<ul>
<li>More visually appealing</li>
<li>All available options presented visually (types of controls, groups, etc.)</li>
<li>Less likely to make a mistake and produce an invalid form</li>
<li>Cumbersome user interface slows down data entry</li>
</ul>
<p>Unfortunately, none of these designers were able to import an existing form in XForms format, which means that the modifiable &#8220;source code&#8221; of the form must be maintained in a &#8220;proprietary&#8221; format in each case, and it&#8217;s difficult to switch between tools.</p>
<p>You can download the conversion tools, and the Excel spreadsheet with the completed questionnaire as we delivered it to RuralNet, <a href="https://github.com/aptivate/idspartimob">here</a>. RuralNet staff, please use the latest version of the spreadsheet that you can find locally. To use the tools, you will need to download and install <a href="http://www.python.org/getit/">Python 2.7</a> and <a href="http://www.oracle.com/technetwork/java/javase/downloads/jre-7u1-download-513652.html">Java</a> (JRE). Then download the tools <a title="ZIP download" href="https://github.com/aptivate/idspartimob/zipball/master">as a ZIP file</a> and extract it somewhere. I recommend that you keep the master copy of the spreadsheet in <a href="https://www.dropbox.com/home">Dropbox</a> to ensure that it&#8217;s backed up, and it&#8217;s always clear what the latest version is.</p>
<p>For help in building surveys using XLS2XForm, please see the <a href="http://opendatakit.org/help/form-design/xls2xform/">documentation</a>. In addition to the question types listed there, we have used the following shortcuts, which also work in this customised version of XLS2XForm:</p>
<ul>
<li><code>text</code> is short for <code>add text prompt</code> (a text field, such as a person&#8217;s name)</li>
<li><code>note</code> is short for <code>add note prompt</code> (a read-only field, providing additional information for the user)</li>
<li><code>time</code> is a time field without a date (for example, survey start and end times)</li>
</ul>
<p>To compile the spreadsheet into an XForms form, run the <code>build_and_validate.py</code> script by double-clicking on it. If it works, it will show the message &#8220;Success!&#8221;, otherwise it will show an error message, usually caused by a mistake in the Excel spreadsheet. If it works, it will create (replace) the file called <code>zambia-ranq-round3.xml</code> in the same directory. If your spreadsheet has a different name, you can create a shortcut to call <code>build_and_validate_custom.py</code> with the name of the spreadsheet on the command line.</p>
<h3>Software components</h3>
<p><a href="http://opendatakit.org/use/aggregate/">ODK Aggregate</a> is the software that powers the Internet server. It is a repository for blank forms (designs) and completed forms (data). Our server is located at <a href="http://partimob.appspot.com/">http://partimob.appspot.com/</a>. This server is currently paid for by us, and will need to transfer to RuralNet at some point.</p>
<p><a href="http://opendatakit.org/use/collect/">ODK Collect</a> is the application runs on the device, and users interact with it to complete the survey. It&#8217;s essentially a user interface for XForms. It can download blank forms (designs) from an ODK Aggregate server, and upload completed forms (data) to the Aggregate server as well.</p>
<p><a href="http://code.google.com/p/opendatakit/wiki/ODKBriefcase">ODK Briefcase</a> is the software that downloads completed forms (data) from the Aggregate server and convert them into CSV (spreadsheet) format, which can be loaded into</p>
<h3>Customised ODK Collect</h3>
<p>We are using a custom version of ODK Collect. You can download the source code for it <a href="http://code.google.com/r/chris-collect/">here</a>, or the compiled application <a href="https://github.com/aptivate/idspartimob/blob/master/ODK-Collect-trunk-111119-custom.apk">here</a>. You can also find it in the ZIP file download. If you prefer, you can use the <a href="http://opendatakit.org/use/collect/">latest official version of ODK Collect</a>. The two are compatible, but our version adds the following useful features:</p>
<ul>
<li>Use supplied login and password by default to save a round trip and a prompt.</li>
<li>Add keyboard navigation, useful for form filling on android-x86 because the mouse interface is pretty clunky.</li>
<li>Restore ability to modify completed and submitted forms on the device, which was removed from the official version in 1.1.7.</li>
<li>Improved error messages and progress indication during form uploads.</li>
<li>Allow setting the instance name on the first page of the survey.</li>
<li>Allow saving incomplete surveys on required questions (in case a survey is interrupted; almost all of our questions are required).</li>
</ul>
<p>There are several ways to install ODK Collect on a device:</p>
<ul>
<li>Download it from the Android Market (official version only, not our customised version)</li>
<li>Copy the APK file onto a microSD card, insert the card into the device, and use the <em>My Files</em> application find and open it from the SD card.</li>
<li>Attach the USB cable from the device to a computer, enable mass storage mode on the device, and on the computer, drag and drop the APK file onto the device&#8217;s internal memory, then use the <em>My Files</em> application to find and open it.</li>
<li>Attach the USB cable from the device to a computer, and use <a href="http://developer.android.com/guide/developing/tools/adb.html">ADB</a>&#8216;s <code>install</code> command to install the APK file.</li>
</ul>
<p>It&#8217;s useful to put the application onto the device&#8217;s desktop. To do that, open the Applications list, find ODK Collect, and press and hold it with your finger for a few seconds. The background will change to the desktop; release your finger to drop the application there.</p>
<p>It&#8217;s also useful to remove all the other junk from the desktop. For each icon and widget on the desktop, press and hold it with your finger for a few seconds, until the trashcan icon appears, then drag your finger to the trashcan and release it there.</p>
<h3><span>Form management on the device</span></h3>
<p><span style="font-weight: normal;">There are several ways to put blank forms (designs) onto the tablets:</span></p>
<ul>
<li>Download them from the ODK Aggregate server using ODK Collect.</li>
<li>Copy them onto a microSD card, insert the card into the device, and use the <em>My Files</em> application to copy them from the SD card to the /sdcard/odk/forms directory.</li>
<li>Attach the USB cable from the device to a computer, enable mass storage mode on the device, and on the computer, drag and drop the form into the /sdcard/odk/forms directory.</li>
<li>Attach the USB cable from the device to a computer, and use <a href="http://developer.android.com/guide/developing/tools/adb.html">ADB</a> or <a href="http://developer.android.com/guide/developing/debugging/ddms.html">DDMS</a> to push the file onto the device, into the /sdcard/odk/forms directory.</li>
</ul>
<p>Of these methods, ADB or DDMS is recommended for rapid development, and using the Aggregate server is recommended for production use, since the form must be installed on the Aggregate server for it to be able to accept submissions.</p>
<p>Similarly there are several ways to copy completed forms (data) off the device:</p>
<ul>
<li>Upload them to the ODK Aggregate server using ODK Collect.</li>
<li>Use the <em>My Files</em> application to copy them from /sdcard/odk/instances to a microSD card, then remove the card and connect it to the computer, and drop the files into the ODK Briefcase data directory.</li>
<li>Attach the USB cable from the device to a computer, enable mass storage mode on the device, and on the computer, drag and drop the files from the /sdcard/odk/instances directory to the ODK Briefcase data directory.</li>
<li>Attach the USB cable from the device to a computer, and use <a href="http://developer.android.com/guide/developing/tools/adb.html">ADB</a> or <a href="http://developer.android.com/guide/developing/debugging/ddms.html">DDMS</a> to pull the file from the device&#8217;s /sdcard/odk/instances directory to the ODK Briefcase data directory.</li>
</ul>
<p>Of these methods, using ODK Aggregate is recommended for development and production use.</p>
<p>Since the Aggregate server is on the Internet, this method requires that the device have Internet access. So it either needs a valid SIM card installed with credit and a data bundle, or a WiFi network connected. We had many problems with using SIM cards for data, so WiFi is preferred if possible.</p>
<p>The directories mentioned above will not exist until ODK Collect is installed on the device and run for the first time. Forms downloaded from the Aggregate server will also be placed in the /sdcard/odk/forms directory. Forms completed on the device will be placed in the /sdcard/odk/instances directory.</p>
<h3>Configuring ODK Collect</h3>
<p>Collect needs to know the details of the ODK Aggregate server to log into it, download blank forms and upload completed forms.</p>
<p>Open the ODK Collect application, press the Settings button and click on <em>Change Settings</em>. Click on <em>URL</em> and enter <em>https://partimob.appspot.com</em>. Similarly, complete the Username and Password using the details that you&#8217;ve been given by the Aggregate server operator, or the account that you&#8217;ve created on the Aggregate server. This account should only have <em>Data Collector</em> permissions, no more. Press the Back key to get back to the main menu of ODK Collect.</p>
<h3>Downloading forms using ODK Collect</h3>
<p>Open ODK Collect on the device, and click on the <em>Get Blank Form</em> button. Collect will try to log into the Aggregate server using the details that you&#8217;ve provided, and get a list of forms on the server that have the <em>Downloadable</em> box ticked. This is on by default for newly uploaded forms.</p>
<p>Tick the box next to all the forms that you want to download, and click on the <em>Get Selected</em> button.</p>
<h3>Filling forms on the device</h3>
<p>Open ODK Collect on the device, and click on the <em>Fill Blank Form</em> button. All the forms in the device&#8217;s <em>/sdcard/odk/forms</em> directory should be listed. Choose the form that you want to complete.</p>
<p>You will see an introductory screen showing how to move between questions by swiping your finger across the screen, from right to left or left to right. This screen has a text box at the bottom, which you can use to name the form that you&#8217;re completing. Naming forms is useful if your data collection is interrupted and you need to resume it later. It&#8217;s much easier to identify the form using its name, rather than opening it and flicking through to find some identifying information. You might name the form based on the household code that you&#8217;re surveying.</p>
<p>Depending on your answers to some questions, others may be hidden, or their text might change.</p>
<p>At the end of the form there is another chance to <em>Name this form</em>, and a tickbox to <em>Mark form as finalized</em>. Before you can upload the form to the Aggregate server, this box must be ticked, and you must press the <em>Save Form and Exit</em> button. Otherwise Collect will consider that the form is incomplete.</p>
<h3>Sending completed forms to Aggregate</h3>
<p>Open ODK Collect on the device, and click on the <em>Send Finalized Form</em> button on the main menu. Tick the box next to all the forms that you want to upload to Aggregate, and click on <em>Send Selected</em>. After the upload is complete, you should see the <em>Upload Results</em> message. Every form should have &#8220;Success&#8221; next to it, otherwise it was not sent successfully.</p>
<h3>Downloading forms using Briefcase</h3>
<p>We are using a customised version of ODK Briefcase with the following changes:</p>
<ul>
<li>Fix the export of repeated groups, which before only worked for the first row (<a href="http://code.google.com/p/opendatakit/issues/detail?id=461">issue 461</a>).</li>
<li>Shorten exported column names, to allow the CSV file to be imported into Access.</li>
<li>Allow the server name, username and password to be provided on the command line (or via a shortcut).</li>
</ul>
<p>You can find the source code <a href="http://code.google.com/r/chris-briefcase/source/checkout">here</a> and the pre-compiled version <a href="https://github.com/aptivate/idspartimob/blob/master/briefcase-1.0-jar-with-dependencies.jar?raw=true">here</a>, as an executable JAR file. You can also find it in the ZIP file download. If you make changes to the source and want to build the executable JAR again, install Maven and use the <code>mvn package</code> command.</p>
<p>To download the completed forms, open Briefcase by double-clicking on the <code>briefcase-1.0-jar-with-dependencies.jar</code> file. On the Transfer tab, click on the Connect button. For the URL, enter <code>https://partimob.appspot.com</code>, and for the user name and password, give the details of an ODK Aggregate account with <em>Data Viewer</em> permissions.</p>
<p>Then you should see a list of forms appear under the heading <em>Forms to Transfer</em>. Tick the box next to the one that your users have been completing, and then click on the Transfer button. If you do this after all the completed forms (data) have been submitted to the ODK Aggregate server, you will not need to do it again for that form template (design).</p>
<p>Now switch to the <em>Transform</em> tab and see if the form appears in the <em>Form</em> list. If it doesn&#8217;t, then exit and restart the Briefcase application (<a href="http://code.google.com/p/opendatakit/issues/detail?id=464">issue 464</a>).</p>
<p>For <em>Output Type</em>, choose <em>.csv and media files</em>. For <em>Output Directory</em>, choose the directory where you&#8217;d like to save the CSV files. Note that any previous files exported to that directory from the same form will be overwritten without warning, even if they have been modified (cleaned). Click on the <em>Output</em> button to write the CSV files.</p>
<h3><strong>Cleaning data in Excel</strong></h3>
<p>You can find the Excel spreadsheet that we use for data storage and cleaning here. Note that Excel is a long way from the best way to store and manipulate data like this. Microsoft Access would be far more appropriate. Yet again I wish there was a sufficiently powerful open source alternative desktop application to Access, allowing ordinary people (not developers) to develop and maintain their databases themselves.</p>
<p>Because the spreadsheet contains cleaned data, which is &#8220;better&#8221; than the raw data which is included in the CSV export, we don&#8217;t want to overwrite existing rows. For the main section of the questionnaire (the so-called Single Responses) you can include only the new data like this:</p>
<ul>
<li>Open the main spreadsheet and switch to the <em>Single Responses</em> tab</li>
<li>Highlight all rows from 3 down to the bottom, and <em>Sort</em> them by the <em>SubmissionDate</em> column.</li>
<li>Note the last submission date on this spreadsheet.</li>
<li>Open the newly exported CSV file for the single responses (something like <em>RANQ-2011-Round-4-v5.csv</em>).</li>
<li>Sort this file by the <em>SubmissionDate</em> column as well.</li>
<li>Highlight and copy all the rows whose submission date is later (more recent) than the last one in the main spreadsheet.</li>
<li>Paste them at the bottom of the Single Responses tab of the main spreadsheet, below the other data.</li>
</ul>
<p>For the other tables, this process needs to be done completely manually at present.</p>
<p>You can then check and clean the data by viewing and modifying it in Excel. Note that each sheet has one or two columns at the end, which are filled by formulae that look up values from the Single Responses sheet, such as the <em>Household Code</em>.</p>
<h3>Using the Android x86 Emulator</h3>
<p>To be written.</p>
<h3>Lessons learned</h3>
<h4>Project Goals</h4>
<p>The actual aim of the project was never clear, because all the stakeholders wanted different things. But if it was to help our partners work more efficiently, then we could have attacked other parts of the process that would have yielded bigger improvements more quickly, such as helping with the output processing (data analysis and report writing) rather than data collection. If the project had incorporated a systems analyst early on, we would have identified and addressed these needs better.</p>
<p>Nobody wanted to be the product owner, to take responsibility for setting priorities for the project. We normally refuse to do this ourselves, because we see our role as assisting someone else to achieve their goals, and that person will need to maintain ownership of the project after our work is done. But in this case we had no choice but to become the product owners, because we couldn&#8217;t function without one.</p>
<h4>Development Process</h4>
<p>We found that workflow elicitation was useful for generating user stories in the agile sense, but we did not have a clear map of the workflow during the development process.</p>
<p>During development we collectively discounted the need for data cleaning, because we thought incorrectly that all the errors were introduced during transcription. Data cleaning might be less necessary if we had collected more data, since the errors would tend to average out, but it was still essential, and not planned for, and there was no workflow to make it happen, so we had to hack something together in the field.</p>
<p>The agile process meant that some of the tasks that we had identified were deprioritised, and never completed due to lack of time. This was supposed to be agreed by all the stakeholders, but some were unfortunately not involved. Some project members expected us to have automated these tasks, and were surprised and angry that this had not been done. We had not automated the production of graphs from the data, and we had to hack this together in the field in a hurry. Some project members had unfulfilled expectations about how the data would be presented for review and cleaning.</p>
<p>We also had some disagreements about the definition of &#8220;automated&#8221;. Some of the project team thought it meant that they would press buttons on their tablets and graphs would magically, instantly appear on the Internet. We did not have time to develop this level of automation, and the need for data cleaning made it logically impossible. We were able to produce graphs directly and instantly during data cleaning in Excel. </p>
<h4>Procurement</h4>
<p>We had difficulty actually purchasing equipment in country. Samsung Zambia could not accept credit card payments over the phone. In the end, we had to bring large amounts of cash into Zambia and change it locally. This resulted in late and risky procurement of the equipment.</p>
<p>We received disappointing service from the retailer of the tablets, including repeated failure to deliver the tablets to their shop for purchase despite prior agreements and assurances, and supplying us with devices in unsealed boxes. We suspect that some of the tablets had been used as demonstration models in shops, or returned by other customers. </p>
<p>The supplier&#8217;s warranty was only one week, after which we would have to return the tablets to Samsung in China.</p>
<p>In future we would:</p>
<ul>
<li>Ensure equipment is new (in sealed boxes)</li>
<li>Have a trusted in-country agent pick up and test the equipment &#8212; this agent must take responsibility for functioning goods</li>
<li>Ensure that equipment is in warranty, and if it fails tests it must be returned</li>
</ul>
<p>We expected that Samsung would supply high quality, reliable tablets at a high price. We were disappointed with their reliability and performance. We could have spent much less money on the tablets for a similar level of performance, and had more spares.</p>
<h4>Hardware</h4>
<p>We had only a limited number of hardware devices, and our user experience developer did not even have access to an Android phone or an emulator. </p>
<p>Two tablets had hardware problems: short battery life and failure to connect to the mobile network. These were discovered in the field, too late to return the devices to the supplier for replacement.</p>
<p>We had reports from enumerators that the touch screen became less sensitive as the battery drained. </p>
<p>Most tablets failed to submit data over the wireless network at all. We had many problems with data communications in Mufulira, which we expected, but we thought we would at least be able to submit small amounts of data wirelessly, and this turned out not to work.</p>
<h4>Survey Instrument</h4>
<p>The survey instrument itself was unclear, complex, and not designed for electronic use. The wording of the questions was unclear and we had many arguments over it. Some questions would have benefited from having a calculator embedded, to help with subtraction and conversion of units, such as calculating change in land area owned by a household.</p>
<p>We had many problems with the form logic, in particular skipping questions depending on the answers to previous questions. This was very difficult to get right, and took us a long time, especially when using XLS2XForm to input the survey. It would have been easier if we could have visualised the flows through the form. We suspect that we did not have time to provide enough training that the local staff would be comfortable maintaining the survey in the XLS2XForm spreadsheet by themselves.</p>
<h4>ODK Software</h4>
<p>We had problems with ODK Collect crashing many times while enumerators were entering data. This always resulted in loss of the completed survey, unlike paper forms. We debugged and patched several bugs in Collect in the field. This required us to have an Android and ODK development environment already set up, because there was no way to download that software in Mufulira. At least we were able to fix the bugs, as this was open source software; some other products would have left us powerless.</p>
<p>Enumerators reported that Collect would sometimes register a different response than intended. Perhaps touching the screen in the wrong place, between questions, or an unclear/lazy touch, might activate the wrong answer. I noticed several times that Collect did not register an answer at all, and I found myself repeatedly jabbing at the screen in frustration. I put this down to hardware problems with the tablets.</p>
<p>For some questions, a grid with three columns (Question, Yes and No checkboxes) would have been a faster way to enter data than repeatedly touching an answer and then dragging left to flip pages. This was not a component that we had available to us in Collect.</p>
<h4>Data Analysis</h4>
<p>We had intended to load the survey output into Microsoft Access for data processing and storage for future use. However we were not able to make the data load into Access successfully. ODK Briefcase outputs CSV files with field names (column headings) too long for Access to import. Importing 20 separate CSV files into Access was very painful. I strongly recommend building much better integration between ODK and Access in future. We have an open question as to whether Access is the best data storage and management solution, but it would fit the needs and fit within the comfort zone of the project members who would be carrying this process forward in future.</p>
<p>We identified the need to check that we could import multiple spreadsheets into SPSS during the development phase, but we ran out of time and did not actually complete this task. When we got around to processing the data, we discovered that it was not possible, which seriously disrupted our assumptions and plans for the data analysis.</p>
<p>In addition, our backup plan to process the data and produce graphs using Google Fusion Tables, also failed because Aggregate was unable to export the data successfully to Fusion Tables, and editing (cleaning) the data online turned out to be too difficult (complex, inconvenient and awkward).</p>
<h4>Positive Outcomes</h4>
<p>All the enumerators reported they would prefer to use tablets than paper forms in future.</p>
<p>We also realised that interviewing people can create social change by encouraging them to think in new directions, and question previous assumptions about how things worked. Being listened to is also empowering.</p>
<p>One of our enumerators took photos of the people he interviewed, using the tablet camera, without even being asked! Well done that man. I think the photos were one of the most valuable outputs from the project, more than the data collected. Politicians, all of us can relate to photos, they tell a much more powerful and personal story than numbers.</p>
<p>I would really like to see technology used to empower local people to reach out to their politicians and hold them to account.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.aptivate.org/2011/12/05/rough-guide-to-rural-data-collection-with-odk/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Embedding jinja2 templates in Django templates</title>
		<link>http://blog.aptivate.org/2011/11/15/embedding-jinja2-templates-in-django-templates/</link>
		<comments>http://blog.aptivate.org/2011/11/15/embedding-jinja2-templates-in-django-templates/#comments</comments>
		<pubDate>Tue, 15 Nov 2011 10:57:38 +0000</pubDate>
		<dc:creator>Martin Burchell</dc:creator>
				<category><![CDATA[Django]]></category>

		<guid isPermaLink="false">http://blog.aptivate.org/?p=910</guid>
		<description><![CDATA[We recently integrated the Askbot forum into the Django-based websites we developed for the RIMI4AC Project. Askbot uses the Jinja2 templating language but this was incompatible with the standard Django templates we had used up to this point. Here&#8217;s how we solved the problem. When we were asked to recommend a forum to be integrated [...]]]></description>
			<content:encoded><![CDATA[<p>
We recently integrated the <a href="http://askbot.org">Askbot</a> forum into the <a href="https://www.djangoproject.com/">Django</a>-based websites we developed for the <a href="http://www.rimi4ac.net/en/">RIMI4AC Project</a>. Askbot uses the <a href="http://jinja.pocoo.org/docs/">Jinja2</a> templating language but this was incompatible with the standard Django templates we had used up to this point. Here&#8217;s how we solved the problem.
</p>
<p>
When we were asked to recommend a forum to be integrated into the suite of websites we were developing for the RIMI4AC Project, Askbot was the clear favourite, due to its large feature set, ease of customisation, active development team and wide user base. The only drawback was that the templating engine used by Askbot was Jinja2, which would make it difficult for Askbot to be embedded into the websites. Up until then these websites had been developed using standard Django templates.
</p>
<p>
We came up with the following options to solve this problem:
</p>
<h2>Create an Askbot skin using Jinja2, which would mimic our existing templates</h2>
<p>
This would be easy to implement but would incur high maintenance costs, as any changes to the standard Django templates would need to be made also to the Jinja2 templates. This could possibly be scripted to make this easier.
</p>
<h2>Embed Askbot in an iframe</h2>
<p>
Again this would be simple to implement but iframes introduce a number of problems themselves with navigation and rendering.
</p>
<h2>Rewrite Askbot to use Django templates</h2>
<p>
This would be a lot of work and as we would effectively be forking Askbot we would incur the costs of maintaining our own version.
</p>
<h2>Rewrite the rest of our websites to use Jinja2 templates</h2>
<p>
This would be quite a bit of work and any new components we wanted to integrate into our websites would also need to use Jinja2.
</p>
<h2>Choose a different forum that used Django templates</h2>
<p>
We really didn&#8217;t want to do this as we had had good reasons for choosing Askbot.
</p>
<h2>Some way of rendering Django templates from within Jinja2</h2>
<p>
Although Jinja2 supports extensions and we could possibly have written one to render Django templates, this seemed to be the opposite of what we wanted &#8211; to embed Askbot as a component of our website and not the other way around.
</p>
<h2>Some way of rendering Jinja2 templates from within Django templates</h2>
<p>
This looked like the most promising solution. Fortunately the Askbot developers were good enough to name their views, which meant that we could provide our own urls.py with views of the same name and then any reverse() lookups within Askbot would just work. Any view that rendered into a Jinja2 template by calling the function render_into_skin() would be replaced with this wrapper function:
</p>
<pre>
def render_jinja2_into_django_template(request, jinja2_view, *args, **kwargs):
    response = jinja2_view(request, *args, **kwargs)

    return render_to_response("forum_container.html",
        {'forum_content':response.content},
        context_instance=RequestContext(request))
</pre>
<p>
The wrapper function would call the original Jinja2 view function and we could pull the raw content out of the returned response object. This would go into the forum_content variable that would be passed to our own Django template and simply written out from within there.
</p>
<p>
Because we wanted Askbot to appear as a component within a page rather than its own standalone application, we would also need to remove the headers and footers from the Askbot Jinja2 templates. Askbot&#8217;s skin customisation made this straightforward. The Django container template would need to include any stylesheets or scripts that we had removed from the headers.
</p>
<p>
With some fixes to the CSS we had successfully embedded Askbot in our website. There would be some maintenance costs in that any future changes to the Askbot views would need to be reflected in our own Askbot views, but this would be far preferable to having to maintain our own set of templates.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.aptivate.org/2011/11/15/embedding-jinja2-templates-in-django-templates/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>How can a $35 tablet computer change the world?</title>
		<link>http://blog.aptivate.org/2011/10/21/how-can-a-35-tablet-computer-change-the-world/</link>
		<comments>http://blog.aptivate.org/2011/10/21/how-can-a-35-tablet-computer-change-the-world/#comments</comments>
		<pubDate>Fri, 21 Oct 2011 22:38:51 +0000</pubDate>
		<dc:creator>Chris Wilson</dc:creator>
				<category><![CDATA[Africa]]></category>
		<category><![CDATA[Appropriate Technology]]></category>
		<category><![CDATA[Education]]></category>
		<category><![CDATA[India]]></category>
		<category><![CDATA[Internet]]></category>
		<category><![CDATA[Mobiles]]></category>
		<category><![CDATA[Networking]]></category>
		<category><![CDATA[Teaching]]></category>
		<category><![CDATA[Web]]></category>

		<guid isPermaLink="false">http://blog.aptivate.org/?p=966</guid>
		<description><![CDATA[Osama Manzar poses some very interesting questions about India&#8217;s new $35 tablet computer &#8220;for the poor&#8221;. However he doesn&#8217;t attempt to answer these questions, leaving the reader in no doubt that he thinks the answer is No! in all cases. I must admit to being skeptical about any such innovation, and I&#8217;ve been listening to [...]]]></description>
			<content:encoded><![CDATA[<p>Osama Manzar poses some <a href="http://www.livemint.com/Articles/2011/10/17000845/Aakash-may-not-help-bridge-the.html">very interesting questions</a> about India&#8217;s new $35 tablet computer &#8220;for the poor&#8221;. However he doesn&#8217;t attempt to answer these questions, leaving the reader in no doubt that he thinks the answer is <strong>No!</strong> in all cases.</p>
<p>I must admit to being skeptical about any such innovation, and I&#8217;ve been listening to <a href="http://tech.groups.yahoo.com/group/bytesforall_readers/message/14910">both</a> <a href="http://tech.groups.yahoo.com/group/bytesforall_readers/message/14921">sides</a> of the <a href="http://tech.groups.yahoo.com/group/bytesforall_readers/message/14929">debate</a> on the <a href="http://tech.groups.yahoo.com/group/bytesforall_readers/">BytesForAll</a> mailing list. Despite my skepticism, Osama&#8217;s questions have some answers, and I&#8217;d like to present them for comment.</p>
<blockquote>
<ul>
<li>India has one of the lowest ratio of teachers—just 456 teachers per million people.</li>
<li>Seventy-two percent of our primary schools have only three teachers or less.</li>
<li>25% of teachers were absent from school, and only about half were teaching, during unannounced visits to a nationally representative sample of government primary schools.</li>
</ul>
<p>How is the $35 tablet going to solve any of these problems?
</p></blockquote>
<p>Of course technology on its own is not going to solve these problems. It is just a valuable weapon in the armoury of those who would launch an all-out war on poverty (and other abstract nouns).</p>
<p>Kentaro Toyama, an ex-Microsoft guru turned ICT4D researcher, <a href="https://plus.google.com/113254845719530983612/posts/gtju48L8bYq">says</a> that &#8220;technology is [just] an amplifier of human intent and capacity.&#8221; And when faced with a task that&#8217;s possible but simply too large, an amplifier is exactly what we need. It doesn&#8217;t need to be high tech. Tanzania did just fine with radio, one of the oldest, simplest and most inclusive ICTs:</p>
<blockquote><p>
About ten years after independence, Tanzania decided to move towards universal primary education, almost doubling the number of children in school. The government estimated that it needed an extra 40,000 teachers. As the existing training colleges were producing only 5,000 new teachers a year, it was decided to recruit secondary school leavers and train them on an apprenticeship model, partly on the job and partly through distance education. Over a period of three years, they were posted in schools where they had a reduced teaching load. They then followed correspondence courses backed by radio programmes; they were supervised and tested on their classroom practices, and passed their examinations. Two evaluations found that they ended up reasonably competent in the classroom (Chale, 1993; quoted by Perranton, 2000; retrieved from <a href="http://archive.unu.edu/africa/files/UNU_RevitalizingHigherEducation.pdf">UNU</a>)
</p></blockquote>
<p>If India were to launch a massive teacher education programme, they would find it cheaper to implement that programme using technology. For example, they might distribute radios, TVs, portable audio players or even (heaven forbid!) computers to trainee teachers. It might take longer for those teachers to reach high standards, and more might drop out, without the personal connection and feedback of face-to-face training. Even so, one could train more teachers for more time and achieve a similar number of fully trained teachers at a lower cost.</p>
<blockquote><p>
In the business sector, more than 70% micro, small and medium enterprises (MSMEs) are not connected to information society to leverage opportunities of business and efficiency. How will the $35 tablet help in the financial inclusion of MSMEs, which are largely situated in small towns and remote areas?
</p></blockquote>
<p>It&#8217;s unfortunate that the tablet doesn&#8217;t include a long-range wireless network (such as GPRS), which must surely cover most of India as it does Africa. Even without an Internet connection, it can still provide useful services such as record keeping, business accounting and stock tracking to small enterprises. The tablet is based on Android, but the marketplace has been disabled, and this is a serious limitation. I think it&#8217;s likely to be overcome soon. When that happens, India&#8217;s many skilled software developers will be free to create localised applications for a potentially huge local market.</p>
<blockquote><p>Most of India’s 3.3 million non-governmental organisations (NGOs) are also located in remote areas—70% of them lack any sort of information and communication technology (ICT) infrastructure or connectivity, and have no websites.</p>
<p>How can the $35 tablet help these NGOs’ global outreach efforts or aid the millions of people working with them in rural areas?</p></blockquote>
<p>You probably know the answer to this question as well as I do: <em>The same way as computer and phones can, only more so.</em> Helping people to communicate and to do their work is exactly what ICTs do. All of them. With the possible exception of Angry Birds. A computer can help us to make leaflets, track visits to patients and beneficiaries, diagnose illnesses, improve farming techniques, or learn about anything we wish to know in the whole world of knowledge. </p>
<blockquote><p>Can it bring transparency in governance at this level?</p></blockquote>
<p>Good question. Not by itself, sure. Transparency comes from open data. The people might get together to publish what the government would rather hide, or pressure the government to release the data, but a $35 tablet won&#8217;t help them much.</p>
<p>When they do release that data, however, the usual problem is how to make use of it. Government data tends to be massive and unwieldy, and answering difficult questions takes much time and significant skill even with the best of data. I think that free, open, widecast media provide the biggest opportunity to make real use of transparency, and our use of the Internet as an enabler of democracy is the best example of that.  Potentially, a simple but powerful Internet device could help bring people together to investigate and answer those difficult questions. But by the sound of it, this tablet is not quite there yet. Hopefully it will be soon.</p>
<blockquote><p>
Since a large population of our country communicate verbally, and cannot read and write with ease, their preferred medium of content consumption and content production is audio-visual&#8230; But to make use of good multimedia content, you need powerful machines, not cheap and underperforming ones.
</p></blockquote>
<p>I disagree with that. I grew up with &#8220;multimedia content&#8221; on BBC Micros: simple games, moving blocks around a screen, simple word processors and spreadsheets and databases and graphics. A picture is worth a thousand words, and a simple, clear diagram can be worth far more than a complex, confusing one. Advanced graphics are no substitute for a visual designer&#8217;s ingenuity and skill. Wikipedia is &#8220;multimedia content&#8221; that is perfectly suited to a $35 tablet.</p>
<blockquote><p>
If the $35 tablet can do anything good to education in India, the only way is by handing them to each and every teacher and school management staff to monitor the workings and functioning of the school and its teachers&#8230;
</p></blockquote>
<p>Monitoring is an interesting application, and a double-edged sword. <a href="http://www.ids.ac.uk/go/idsperson/professor-robert-chambers">Robert Chambers</a>, the inventor of <a href="http://en.wikipedia.org/wiki/Participatory_rural_appraisal">participatory rural appraisal</a>, told us a story at the recent <a href="http://ict4d-finale.eventbrite.com/">ICT4D Finale</a> event in Cambridge of a hospital in India where the nurses were given mobile phones &#8220;to collect data at the source.&#8221; But the director of the hospital used it to monitor what they were doing, effectively spying on them. The nurses went on strike and eventually the director was fired. I think that for monitoring to have a positive benefit, it must be done with consent and a shared vision to use the data to improve performance, not to criticise and control.</p>
<blockquote><p>rather than assuming that each student will buy Aakash and India will become digitally literate overnight.</p></blockquote>
<p>I have to agree with that sentiment, although I&#8217;m not sure who raised it. Kapil Sibal, who takes the credit for inventing the $35 tablet, merely <a href="http://www.telegraphindia.com/1111016/jsp/7days/story_14628545.jsp">said</a>:</p>
<blockquote><p>This low cost device is part of our national mission on education through information and communication technology (NME-ICT) which will connect over 1,000 institutions across the country, enabling tonnes of web-based course content for free.</p></blockquote>
<p>Now that doesn&#8217;t sound so far-fetched, does it?</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.aptivate.org/2011/10/21/how-can-a-35-tablet-computer-change-the-world/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Jazz Talking: The Agile &amp; Participation Event</title>
		<link>http://blog.aptivate.org/2011/09/28/jazz-talking-the-agile-participation-event/</link>
		<comments>http://blog.aptivate.org/2011/09/28/jazz-talking-the-agile-participation-event/#comments</comments>
		<pubDate>Wed, 28 Sep 2011 22:50:40 +0000</pubDate>
		<dc:creator>alan</dc:creator>
				<category><![CDATA[agile]]></category>
		<category><![CDATA[participation]]></category>
		<category><![CDATA[Alistair Cockburn]]></category>
		<category><![CDATA[Jazz talk]]></category>
		<category><![CDATA[Robert Chambers]]></category>

		<guid isPermaLink="false">http://blog.aptivate.org/?p=952</guid>
		<description><![CDATA[A format for a multi-disciplinary conversation - two experts, on a sofa, in front of an audience. ]]></description>
			<content:encoded><![CDATA[<p><a rel="attachment wp-att-955" href="http://blog.aptivate.org/2011/09/28/jazz-talking-the-agile-participation-event/robert_and_alistair_360x216/"><img class="alignnone size-full wp-image-955" title="Robert and Alistair" src="http://blog.aptivate.org/wp-content/uploads/2011/09/robert_and_alistair_360x216.jpg" alt="Robert and Alistair" width="360" height="216" /></a></p>
<p>For a while I&#8217;ve felt that the Agile methodologies from the software development world share a similar outlook to the Participatory methodologies from the international development world.</p>
<p>So we came up with an idea for an event. Wouldn&#8217;t it be great to get an expert from each discipline and have them talk to each other, in front of an audience?</p>
<p>Last night, thanks to support from the <a href="http://www.humanitariancentre.org/">Humanitarian Centre</a>, and our two esteemed guests, our idea became <a href="http://ict4d-finale.eventbrite.com/">reality</a>.</p>
<p>Alistair Cockburn, Agile guru, sat on a sofa next to Robert Chambers, expert on Participatory approaches, in front of an audience.</p>
<p>I thought it was fantastic and we&#8217;ve had a lot of positive feedback about the event. It was so good, I found myself afterwards wondering if this is in general a good format for an event.</p>
<p>So I wanted to write a post about the form of the event, rather than the content.</p>
<p>After the event I was chatting with Alistair and he&#8217;d already been thinking along similar lines. We called it a <strong>&#8220;Jazz Talk&#8221;</strong>. We were drawing an analogy with two jazz musicians improvising.</p>
<h2>Jazz Talks</h2>
<p>Here&#8217;s the format -</p>
<p><strong>1)</strong> Get <strong>two affable speakers</strong> from different disciplines<br />
<strong>2)</strong> Sit them on a <strong>sofa</strong> in front of an audience<br />
<strong>3)</strong> Let them talk about the relationship between their disciplines<br />
<strong>4)</strong> Periodically interrupt them with <strong>&#8220;Kibitzers&#8221;</strong></p>
<h2>Kibitzer</h2>
<p>A &#8220;kibitzer&#8221; is a person who comments on the conversation.</p>
<p>&#8220;Kibitzer&#8221; was a term Alistair came up with. I had to look it up, literally it means an observer of a card game who gives (unwanted) commentary.</p>
<p>There&#8217;s two types of Kibitzer. A &#8220;content kibitzer&#8221; gives comment on the content of the conversation. In the event last night I played the role of one of the kibitzers and asked the question <em>&#8220;How do we get funders to engage with agile / participatory proposals?&#8221;</em>.  All of our kibitzers last night were content kibitzers.</p>
<p>Talking to Alistair afterwards, he was keen to push the idea of a &#8220;form kibitzer&#8221;. This is someone who gives a commentary on the form of the conversation, not the subject matter. For instance, <em>&#8220;I liked how speaker-A extended speaker-B&#8217;s questions to the audience&#8221;</em>, or <em>&#8220;Can we hear more from speaker-A?&#8221;</em>. I think form kibitzing is less natural but likely to be shorter. It also potentially plays a facilitatory role in guiding the conversation and could help address issues like one speaker dominating the conversation.</p>
<p>Perhaps a mix of both types could work. Each commentary would start with a short form kibitz followed by a content kibitz.</p>
<h2>Timing</h2>
<p>Here&#8217;s a suggested recipe:</p>
<ul>
<li>a <strong>90 minute conversation</strong></li>
<li><strong>kibitzing</strong> every <strong>15 minutes</strong> (eg 5 interruptions)</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://blog.aptivate.org/2011/09/28/jazz-talking-the-agile-participation-event/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Computers in Schools: Sound solutions</title>
		<link>http://blog.aptivate.org/2011/09/05/computers-in-schools-sound-solutions/</link>
		<comments>http://blog.aptivate.org/2011/09/05/computers-in-schools-sound-solutions/#comments</comments>
		<pubDate>Mon, 05 Sep 2011 11:55:50 +0000</pubDate>
		<dc:creator>Chris Wilson</dc:creator>
				<category><![CDATA[Africa]]></category>
		<category><![CDATA[Appropriate Technology]]></category>
		<category><![CDATA[Hardware]]></category>
		<category><![CDATA[Teaching]]></category>

		<guid isPermaLink="false">http://blog.aptivate.org/?p=928</guid>
		<description><![CDATA[Activities with sound are ideal for kids. Preferably lots of sound. Especially when it comes to teaching language, reading and writing. When you have a classroom full of children with computers, each working at their own pace on speech or language tasks, they need private sound rather than the built-in speakers of their laptops. Otherwise [...]]]></description>
			<content:encoded><![CDATA[<p>Activities with sound are ideal for kids. Preferably lots of sound. Especially when it comes to teaching language, reading and writing.</p>
<p>When you have a classroom full of children with computers, each working at their own pace on speech or language tasks, they need private sound rather than the built-in speakers of their laptops. Otherwise the cacophony would make learning much harder for all of them.</p>
<p>Headphones (or headsets) are the normal solution for language labs in UK schools. But they&#8217;re not great for use with primary school kids in a dirty, dusty environment. They&#8217;re extremely fragile, hard to clean, uncomfortable to wear for long periods, and can spread ear infections.</p>
<p>A bluetooth headset would work, and would be nice in theory, but much more expensive, and would need charging often.</p>
<p>The most obvious solution seems to be something that looks like a mobile phone, but attaches to a computer with a cable. They&#8217;re very hard to find. It seems that everyone wants tiny, delicate, wireless or in-ear headsets. So manufacturers don&#8217;t bother making the kind of big, clunky, bulletproof handsets I&#8217;m thinking of.</p>
<p>First, after long and fruitless searching, I discovered that what I&#8217;m looking for is actually called a handset (because you hold it in your hands) and not a headset (that fits over your head).</p>
<p>And then I found them:</p>
<p><a href="http://www.maplin.co.uk/voip-usb-handset-46145"><img style="border: 1px solid black;" title="Maplin USB Handset" src="http://images.maplin.co.uk/300/a87cu.jpg" alt="USB Handset" width="250" height="250" /></a> <a href="http://www.eastel33.com/Trimline-Phone-E-720-12.html"><img style="border: 1px solid black;" alt="USB Handset" src="http://www.eastel33.com/upload/photo/d81439a2f6c9d713f61dccec076fe3f5.jpg" title="Eastel Trimline Phone E-720" class="alignnone" width="250" height="250" /></a> <a href="http://www.gd-wholesale.com/wholesale-dir/a66c/e3227f/usb-phone-s-1.html"><img style="border: 1px solid black;" alt="Nokia-like USB Handset" src="http://www.gd-wholesale.com/userimg/66/3227i1/usb-phone-180.jpg" title="GD Wholesale UGW-141906" class="alignnone" width="250" height="250" /></a> <a href="http://www.amazon.co.uk/gp/product/B000XRMB0W/ref=cm_cr_rev_prod_img"><img style="border: 1px solid black;" class="alignnone" title="USB handset (discontinued)" src="http://ecx.images-amazon.com/images/I/21A8-ymqT-L._SL500_AA300_.jpg" alt="Slim grey USB handset" width="250" height="250" /></a></p>
<p>Unfortunately the cheapest I&#8217;ve found so far is £10 ($14) through Maplin, which is about ten times the cost of the cheap, fragile headsets we&#8217;d like to replace.</p>
<p>If you know of any others, or a cheaper bulk supplier than Maplin (such as their supplier in China) please let us know!</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.aptivate.org/2011/09/05/computers-in-schools-sound-solutions/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

