<?xml version='1.0' encoding='UTF-8'?>
<?xml-stylesheet href="https://lukeplant.me.uk/assets/xml/atom.xsl" type="text/xsl media="all"?>
<feed xml:lang="en" xmlns="http://www.w3.org/2005/Atom">
  <title>Luke Plant's home page (Posts about Linux)</title>
  <id>https://lukeplant.me.uk/blog/categories/linux.xml</id>
  <updated>2024-12-05T14:30:11Z</updated>
  <author>
    <name>Luke Plant</name>
  </author>
  <link rel="self" type="application/atom+xml" href="https://lukeplant.me.uk/blog/categories/linux.xml"/>
  <link rel="alternate" type="text/html" href="https://lukeplant.me.uk/blog/categories/linux/"/>
  <generator uri="https://getnikola.com/">Nikola</generator>
  <entry>
    <title>HP Pavilion 17-e153sa on Linux Mint</title>
    <id>https://lukeplant.me.uk/blog/posts/hp-pavilion-17-e153sa-on-linux-mint/</id>
    <updated>2014-08-04T10:54:30+01:00</updated>
    <published>2014-08-04T10:54:30+01:00</published>
    <author>
      <name>Luke Plant</name>
    </author>
    <link rel="alternate" type="text/html" href="https://lukeplant.me.uk/blog/posts/hp-pavilion-17-e153sa-on-linux-mint/"/>
    <summary type="html">&lt;p&gt;Compatibility report.&lt;/p&gt;</summary>
    <content type="html">&lt;p&gt;This page reports my success with installing and using Linux on an HP Pavilion
17 laptop, &lt;a class="reference external" href="https://ssl.www8.hp.com/ie/en/products/laptops/product-detail.html?oid=6723462#!tab=features"&gt;model e153sa&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;These results apply to Linux Mint Debian Edition (2014-03) and Linux
Mint 16. (These are similar to Debian and Ubuntu).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Overall status:&lt;/strong&gt; Almost everything works perfectly.&lt;/p&gt;
&lt;p&gt;Tests included:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;Screen, keyboard, touchpad, SD card reader, VGA output, HDMI output
(multi-monitor setup), CD/DVD reader/writer, 8Gb RAM, CPU (Linux reports and
uses 4 cores as expected for this i5 processor), wifi, webcam, built in
microphone, built in speakers, analog headphone/speaker out and microphone in,
USB inputs.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Notes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;To install Linux from CD/DVD, you have to press 'Esc' during bootup to go into
the BIOS settings. Change the boot order to boot from the install CD/DVD
before hard drive, and disable UEFI secure boot, then exit and reboot.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The laptop monitor seems to have some kind of default brightness that is
really, really low (almost black).&lt;/p&gt;
&lt;p&gt;Thankfully, you can adjust this using the keys on the keyboard. After you've
fixed it once after bootup, it can sometimes be triggered again e.g. when you
go into "System Settings" on Linux Mint - the laptop screen goes completely
black. This is a bit annoying, and can make you think it's not working at all,
but after setting the brightness once or twice I usually don't have a problem
again until I reboot, which is pretty rare.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The wifi/webcam/graphics all worked perfectly out of the box with no extra
drivers needed.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;WebGl in Firefox works great. I found it was disabled on Chrome by default,
but this can be easily fixed by enabling “Override software rendering list”
(opening a tab with the URL &lt;strong&gt;chrome://flags/#ignore-gpu-blacklist&lt;/strong&gt;) and then
it works fine.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Initially I found that SD cards were not recognised at all when inserted into
the slot. After some Googling, I found this can be solved by having an SD card
in the slot while the laptop boots, and whenever you resume from
suspend. Annoying, but not too serious if you have an old SD card that you
don't mind leaving in your laptop.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Very occasionally my external USB mouse stops working when I plug other
devices in to the nearby USB ports. Solved by unplugging and re-plugging the
USB mouse. I'm not sure if this is a hardware or Linux issue.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Multi-touch for touchpad works, at least to a basic level e.g. two finger
scrolling, using the Linux Mint control panel.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;I have not succeeded in getting HDMI audio output to work (using PulseAudio).
Update 2015-12-19 - with Linux Mint 17 this now works fine.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;</content>
    <category term="linux" label="Linux"/>
  </entry>
  <entry>
    <title>Import Chrome passwords into Firefox on Linux/Gnome</title>
    <id>https://lukeplant.me.uk/blog/posts/import-chrome-passwords-into-firefox-on-linux/gnome/</id>
    <updated>2014-03-07T09:32:32Z</updated>
    <published>2014-03-07T09:32:32Z</published>
    <author>
      <name>Luke Plant</name>
    </author>
    <link rel="alternate" type="text/html" href="https://lukeplant.me.uk/blog/posts/import-chrome-passwords-into-firefox-on-linux/gnome/"/>
    <summary type="html">&lt;p&gt;Python script to help Linux users transfer saved passwords from Chrome to Firefox.&lt;/p&gt;</summary>
    <content type="html">&lt;p&gt;If you are using Linux and the Gnome/Mate/Cinnamon desktop environments, Chrome
stores passwords in the Gnome password manager (also known as Seahorse).&lt;/p&gt;
&lt;p&gt;The following script will find these passwords, and export them to an XML
password file that can be imported by the &lt;a class="reference external" href="https://addons.mozilla.org/en-US/firefox/addon/password-exporter/"&gt;Firefox "Password Exporter" extension&lt;/a&gt;, so that,
between them, you can transfer saved passwords from Chrome to Firefox.&lt;/p&gt;
&lt;p&gt;Please see the top of the script for instructions, item 3. (The script also has
other modes, for pure export/import of Seahorse passwords). You'll need to know
how to install Python and related packages - this is not a point-and-click
solution, sorry!&lt;/p&gt;
&lt;p&gt;&lt;a class="reference external" href="https://github.com/spookylukey/gnome-keyring-import-export/blob/master/gnome_keyring_import_export.py"&gt;https://github.com/spookylukey/gnome-keyring-import-export/blob/master/gnome_keyring_import_export.py&lt;/a&gt;&lt;/p&gt;</content>
    <category term="linux" label="Linux"/>
  </entry>
  <entry>
    <title>Export and import for Gnome password manager (Seahorse)</title>
    <id>https://lukeplant.me.uk/blog/posts/export-and-import-for-gnome-password-manager-%28seahorse%29/</id>
    <updated>2014-03-07T09:17:44Z</updated>
    <published>2014-03-07T09:17:44Z</published>
    <author>
      <name>Luke Plant</name>
    </author>
    <link rel="alternate" type="text/html" href="https://lukeplant.me.uk/blog/posts/export-and-import-for-gnome-password-manager-%28seahorse%29/"/>
    <summary type="html">&lt;p&gt;A script to export/import passwords from the Gnome password manager&lt;/p&gt;</summary>
    <content type="html">&lt;p&gt;Without much ado, here is a Python script that will allow you to dump password
from the Gnome password manager (also known as Seahorse, and used in other
desktop environments such as Cinnamon) into a JSON file.&lt;/p&gt;
&lt;p&gt;This is useful for just viewing all your stored passwords (which are not always
visible in the password manager GUI), but it will also import them again, which
is especially useful when you want to pull in all your saved passwords from an
old machine.&lt;/p&gt;
&lt;p&gt;Please see the top of the script for instructions. You'll need to know how to
install Python and related packages - this is not a point-and-click solution, sorry!&lt;/p&gt;
&lt;p&gt;&lt;a class="reference external" href="https://github.com/spookylukey/gnome-keyring-import-export/blob/master/gnome_keyring_import_export.py"&gt;https://github.com/spookylukey/gnome-keyring-import-export/blob/master/gnome_keyring_import_export.py&lt;/a&gt;&lt;/p&gt;</content>
    <category term="linux" label="Linux"/>
  </entry>
  <entry>
    <title>Controlling Sozi remotely from an Android phone</title>
    <id>https://lukeplant.me.uk/blog/posts/controlling-sozi-remotely-from-an-android-phone/</id>
    <updated>2013-03-11T15:37:57Z</updated>
    <published>2013-03-11T15:37:57Z</published>
    <author>
      <name>Luke Plant</name>
    </author>
    <link rel="alternate" type="text/html" href="https://lukeplant.me.uk/blog/posts/controlling-sozi-remotely-from-an-android-phone/"/>
    <summary type="html">&lt;p&gt;Success story with Linux, Chrome, Android, Coversal and Python&lt;/p&gt;</summary>
    <content type="html">&lt;p&gt;I'm due to give a talk next Sunday evening, and I've created a presentation
using the very cool &lt;a class="reference external" href="http://sozi.baierouge.fr/wiki/en:welcome"&gt;Sozi&lt;/a&gt;. Sozi is
quite like &lt;a class="reference external" href="http://prezi.com/"&gt;Prezi&lt;/a&gt;, but open source and free, and its
output is a standard &lt;a class="reference external" href="http://en.wikipedia.org/wiki/Scalable_Vector_Graphics"&gt;SVG&lt;/a&gt; file (with a bit of
Javascript), so it can be displayed in several web browsers.&lt;/p&gt;
&lt;p&gt;(On the other hand, for many people Sozi is probably a lot harder to use for
simple presentations than Prezi, as it works as a plugin to &lt;a class="reference external" href="http://inkscape.org/"&gt;Inkscape&lt;/a&gt;, a general purpose drawing program, but, to me, it is
simply unacceptable to depend on the continued existence of a company, and a
subscription fee, to be able to continue to view/edit your presentations).&lt;/p&gt;
&lt;p&gt;One problem with not using ‘standard’ software like Powerpoint is that
proprietary tools like hand-held remote controls for Powerpoint won't work, or
won't work easily (and I don't want to find out that it won't work when I turn
up) [EDIT: it looks like Sozi &lt;a class="reference external" href="https://github.com/senshu/Sozi/issues/191"&gt;now has good compatibility with many wireless
presenter tools&lt;/a&gt;, but I don't have
one anyway]. But I've found a solution that works for me:&lt;/p&gt;
&lt;ol class="arabic"&gt;
&lt;li&gt;&lt;p&gt;On my Android phone, I installed &lt;a class="reference external" href="http://www.coversal.com/"&gt;Coversal&lt;/a&gt;,
which is an app designed for controlling media players, but allows custom
commands to be executed, so actually works fine for presentations.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Within Coversal, I installed the ‘SSH Custom’ plugin.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;On my Linux laptop, I installed openssh-server to allow the app to log in to
my machine. To avoid putting my laptop password on the phone, I created an
SSH keypair for this app, transferred to private key to the phone, and added
the public key to ~/.ssh/authorized_keys.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;I created a script on my laptop that can control Sozi running in Chrome:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code python"&gt;&lt;a id="rest_code_a84db36ddc7240e49591c7b3da3d504d-1" name="rest_code_a84db36ddc7240e49591c7b3da3d504d-1" href="https://lukeplant.me.uk/blog/posts/controlling-sozi-remotely-from-an-android-phone/#rest_code_a84db36ddc7240e49591c7b3da3d504d-1"&gt;&lt;/a&gt;&lt;span class="ch"&gt;#!/usr/bin/env python&lt;/span&gt;
&lt;a id="rest_code_a84db36ddc7240e49591c7b3da3d504d-2" name="rest_code_a84db36ddc7240e49591c7b3da3d504d-2" href="https://lukeplant.me.uk/blog/posts/controlling-sozi-remotely-from-an-android-phone/#rest_code_a84db36ddc7240e49591c7b3da3d504d-2"&gt;&lt;/a&gt;
&lt;a id="rest_code_a84db36ddc7240e49591c7b3da3d504d-3" name="rest_code_a84db36ddc7240e49591c7b3da3d504d-3" href="https://lukeplant.me.uk/blog/posts/controlling-sozi-remotely-from-an-android-phone/#rest_code_a84db36ddc7240e49591c7b3da3d504d-3"&gt;&lt;/a&gt;&lt;span class="c1"&gt;# controlsozi&lt;/span&gt;
&lt;a id="rest_code_a84db36ddc7240e49591c7b3da3d504d-4" name="rest_code_a84db36ddc7240e49591c7b3da3d504d-4" href="https://lukeplant.me.uk/blog/posts/controlling-sozi-remotely-from-an-android-phone/#rest_code_a84db36ddc7240e49591c7b3da3d504d-4"&gt;&lt;/a&gt;
&lt;a id="rest_code_a84db36ddc7240e49591c7b3da3d504d-5" name="rest_code_a84db36ddc7240e49591c7b3da3d504d-5" href="https://lukeplant.me.uk/blog/posts/controlling-sozi-remotely-from-an-android-phone/#rest_code_a84db36ddc7240e49591c7b3da3d504d-5"&gt;&lt;/a&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;os&lt;/span&gt;
&lt;a id="rest_code_a84db36ddc7240e49591c7b3da3d504d-6" name="rest_code_a84db36ddc7240e49591c7b3da3d504d-6" href="https://lukeplant.me.uk/blog/posts/controlling-sozi-remotely-from-an-android-phone/#rest_code_a84db36ddc7240e49591c7b3da3d504d-6"&gt;&lt;/a&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;subprocess&lt;/span&gt;
&lt;a id="rest_code_a84db36ddc7240e49591c7b3da3d504d-7" name="rest_code_a84db36ddc7240e49591c7b3da3d504d-7" href="https://lukeplant.me.uk/blog/posts/controlling-sozi-remotely-from-an-android-phone/#rest_code_a84db36ddc7240e49591c7b3da3d504d-7"&gt;&lt;/a&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;sys&lt;/span&gt;
&lt;a id="rest_code_a84db36ddc7240e49591c7b3da3d504d-8" name="rest_code_a84db36ddc7240e49591c7b3da3d504d-8" href="https://lukeplant.me.uk/blog/posts/controlling-sozi-remotely-from-an-android-phone/#rest_code_a84db36ddc7240e49591c7b3da3d504d-8"&gt;&lt;/a&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;logging&lt;/span&gt;
&lt;a id="rest_code_a84db36ddc7240e49591c7b3da3d504d-9" name="rest_code_a84db36ddc7240e49591c7b3da3d504d-9" href="https://lukeplant.me.uk/blog/posts/controlling-sozi-remotely-from-an-android-phone/#rest_code_a84db36ddc7240e49591c7b3da3d504d-9"&gt;&lt;/a&gt;
&lt;a id="rest_code_a84db36ddc7240e49591c7b3da3d504d-10" name="rest_code_a84db36ddc7240e49591c7b3da3d504d-10" href="https://lukeplant.me.uk/blog/posts/controlling-sozi-remotely-from-an-android-phone/#rest_code_a84db36ddc7240e49591c7b3da3d504d-10"&gt;&lt;/a&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;datetime&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;
&lt;a id="rest_code_a84db36ddc7240e49591c7b3da3d504d-11" name="rest_code_a84db36ddc7240e49591c7b3da3d504d-11" href="https://lukeplant.me.uk/blog/posts/controlling-sozi-remotely-from-an-android-phone/#rest_code_a84db36ddc7240e49591c7b3da3d504d-11"&gt;&lt;/a&gt;
&lt;a id="rest_code_a84db36ddc7240e49591c7b3da3d504d-12" name="rest_code_a84db36ddc7240e49591c7b3da3d504d-12" href="https://lukeplant.me.uk/blog/posts/controlling-sozi-remotely-from-an-android-phone/#rest_code_a84db36ddc7240e49591c7b3da3d504d-12"&gt;&lt;/a&gt;&lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;basicConfig&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DEBUG&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'/tmp/controlsozi.log'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;filemode&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"a"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_a84db36ddc7240e49591c7b3da3d504d-13" name="rest_code_a84db36ddc7240e49591c7b3da3d504d-13" href="https://lukeplant.me.uk/blog/posts/controlling-sozi-remotely-from-an-android-phone/#rest_code_a84db36ddc7240e49591c7b3da3d504d-13"&gt;&lt;/a&gt;
&lt;a id="rest_code_a84db36ddc7240e49591c7b3da3d504d-14" name="rest_code_a84db36ddc7240e49591c7b3da3d504d-14" href="https://lukeplant.me.uk/blog/posts/controlling-sozi-remotely-from-an-android-phone/#rest_code_a84db36ddc7240e49591c7b3da3d504d-14"&gt;&lt;/a&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_window&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;a id="rest_code_a84db36ddc7240e49591c7b3da3d504d-15" name="rest_code_a84db36ddc7240e49591c7b3da3d504d-15" href="https://lukeplant.me.uk/blog/posts/controlling-sozi-remotely-from-an-android-phone/#rest_code_a84db36ddc7240e49591c7b3da3d504d-15"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# Assumes that there is just a single Google Chrome window open, and this&lt;/span&gt;
&lt;a id="rest_code_a84db36ddc7240e49591c7b3da3d504d-16" name="rest_code_a84db36ddc7240e49591c7b3da3d504d-16" href="https://lukeplant.me.uk/blog/posts/controlling-sozi-remotely-from-an-android-phone/#rest_code_a84db36ddc7240e49591c7b3da3d504d-16"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# has the presentation in it.&lt;/span&gt;
&lt;a id="rest_code_a84db36ddc7240e49591c7b3da3d504d-17" name="rest_code_a84db36ddc7240e49591c7b3da3d504d-17" href="https://lukeplant.me.uk/blog/posts/controlling-sozi-remotely-from-an-android-phone/#rest_code_a84db36ddc7240e49591c7b3da3d504d-17"&gt;&lt;/a&gt;    &lt;span class="n"&gt;windows&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;subprocess&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;check_output&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"DISPLAY=:0 wmctrl -l -x | egrep 'google-chrome|gnome-www-browser'"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;shell&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_a84db36ddc7240e49591c7b3da3d504d-18" name="rest_code_a84db36ddc7240e49591c7b3da3d504d-18" href="https://lukeplant.me.uk/blog/posts/controlling-sozi-remotely-from-an-android-phone/#rest_code_a84db36ddc7240e49591c7b3da3d504d-18"&gt;&lt;/a&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;windows&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;()[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;a id="rest_code_a84db36ddc7240e49591c7b3da3d504d-19" name="rest_code_a84db36ddc7240e49591c7b3da3d504d-19" href="https://lukeplant.me.uk/blog/posts/controlling-sozi-remotely-from-an-android-phone/#rest_code_a84db36ddc7240e49591c7b3da3d504d-19"&gt;&lt;/a&gt;
&lt;a id="rest_code_a84db36ddc7240e49591c7b3da3d504d-20" name="rest_code_a84db36ddc7240e49591c7b3da3d504d-20" href="https://lukeplant.me.uk/blog/posts/controlling-sozi-remotely-from-an-android-phone/#rest_code_a84db36ddc7240e49591c7b3da3d504d-20"&gt;&lt;/a&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;send_text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a id="rest_code_a84db36ddc7240e49591c7b3da3d504d-21" name="rest_code_a84db36ddc7240e49591c7b3da3d504d-21" href="https://lukeplant.me.uk/blog/posts/controlling-sozi-remotely-from-an-android-phone/#rest_code_a84db36ddc7240e49591c7b3da3d504d-21"&gt;&lt;/a&gt;    &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;system&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"DISPLAY=:0 xvkbd -window &lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s2"&gt; -text '&lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s2"&gt;'"&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;get_window&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;a id="rest_code_a84db36ddc7240e49591c7b3da3d504d-22" name="rest_code_a84db36ddc7240e49591c7b3da3d504d-22" href="https://lukeplant.me.uk/blog/posts/controlling-sozi-remotely-from-an-android-phone/#rest_code_a84db36ddc7240e49591c7b3da3d504d-22"&gt;&lt;/a&gt;
&lt;a id="rest_code_a84db36ddc7240e49591c7b3da3d504d-23" name="rest_code_a84db36ddc7240e49591c7b3da3d504d-23" href="https://lukeplant.me.uk/blog/posts/controlling-sozi-remotely-from-an-android-phone/#rest_code_a84db36ddc7240e49591c7b3da3d504d-23"&gt;&lt;/a&gt;&lt;span class="n"&gt;ACTIONS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;a id="rest_code_a84db36ddc7240e49591c7b3da3d504d-24" name="rest_code_a84db36ddc7240e49591c7b3da3d504d-24" href="https://lukeplant.me.uk/blog/posts/controlling-sozi-remotely-from-an-android-phone/#rest_code_a84db36ddc7240e49591c7b3da3d504d-24"&gt;&lt;/a&gt;    &lt;span class="s1"&gt;'previous'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;      &lt;span class="s2"&gt;"\[Left]"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;a id="rest_code_a84db36ddc7240e49591c7b3da3d504d-25" name="rest_code_a84db36ddc7240e49591c7b3da3d504d-25" href="https://lukeplant.me.uk/blog/posts/controlling-sozi-remotely-from-an-android-phone/#rest_code_a84db36ddc7240e49591c7b3da3d504d-25"&gt;&lt;/a&gt;    &lt;span class="s1"&gt;'next'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;          &lt;span class="s2"&gt;"\[Right]"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;a id="rest_code_a84db36ddc7240e49591c7b3da3d504d-26" name="rest_code_a84db36ddc7240e49591c7b3da3d504d-26" href="https://lukeplant.me.uk/blog/posts/controlling-sozi-remotely-from-an-android-phone/#rest_code_a84db36ddc7240e49591c7b3da3d504d-26"&gt;&lt;/a&gt;    &lt;span class="s1"&gt;'fullscreen'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;    &lt;span class="s2"&gt;"\[F11]"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;a id="rest_code_a84db36ddc7240e49591c7b3da3d504d-27" name="rest_code_a84db36ddc7240e49591c7b3da3d504d-27" href="https://lukeplant.me.uk/blog/posts/controlling-sozi-remotely-from-an-android-phone/#rest_code_a84db36ddc7240e49591c7b3da3d504d-27"&gt;&lt;/a&gt;    &lt;span class="s1"&gt;'previous_fast'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"\[Up]"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;a id="rest_code_a84db36ddc7240e49591c7b3da3d504d-28" name="rest_code_a84db36ddc7240e49591c7b3da3d504d-28" href="https://lukeplant.me.uk/blog/posts/controlling-sozi-remotely-from-an-android-phone/#rest_code_a84db36ddc7240e49591c7b3da3d504d-28"&gt;&lt;/a&gt;    &lt;span class="s1"&gt;'next_fast'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;     &lt;span class="s2"&gt;"\[Down]"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;a id="rest_code_a84db36ddc7240e49591c7b3da3d504d-29" name="rest_code_a84db36ddc7240e49591c7b3da3d504d-29" href="https://lukeplant.me.uk/blog/posts/controlling-sozi-remotely-from-an-android-phone/#rest_code_a84db36ddc7240e49591c7b3da3d504d-29"&gt;&lt;/a&gt;    &lt;span class="s1"&gt;'start'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;         &lt;span class="s2"&gt;"\[Home]"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;a id="rest_code_a84db36ddc7240e49591c7b3da3d504d-30" name="rest_code_a84db36ddc7240e49591c7b3da3d504d-30" href="https://lukeplant.me.uk/blog/posts/controlling-sozi-remotely-from-an-android-phone/#rest_code_a84db36ddc7240e49591c7b3da3d504d-30"&gt;&lt;/a&gt;    &lt;span class="s1"&gt;'end'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;           &lt;span class="s2"&gt;"\[End]"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;a id="rest_code_a84db36ddc7240e49591c7b3da3d504d-31" name="rest_code_a84db36ddc7240e49591c7b3da3d504d-31" href="https://lukeplant.me.uk/blog/posts/controlling-sozi-remotely-from-an-android-phone/#rest_code_a84db36ddc7240e49591c7b3da3d504d-31"&gt;&lt;/a&gt;    &lt;span class="s1"&gt;'launch'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;        &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;a id="rest_code_a84db36ddc7240e49591c7b3da3d504d-32" name="rest_code_a84db36ddc7240e49591c7b3da3d504d-32" href="https://lukeplant.me.uk/blog/posts/controlling-sozi-remotely-from-an-android-phone/#rest_code_a84db36ddc7240e49591c7b3da3d504d-32"&gt;&lt;/a&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;a id="rest_code_a84db36ddc7240e49591c7b3da3d504d-33" name="rest_code_a84db36ddc7240e49591c7b3da3d504d-33" href="https://lukeplant.me.uk/blog/posts/controlling-sozi-remotely-from-an-android-phone/#rest_code_a84db36ddc7240e49591c7b3da3d504d-33"&gt;&lt;/a&gt;
&lt;a id="rest_code_a84db36ddc7240e49591c7b3da3d504d-34" name="rest_code_a84db36ddc7240e49591c7b3da3d504d-34" href="https://lukeplant.me.uk/blog/posts/controlling-sozi-remotely-from-an-android-phone/#rest_code_a84db36ddc7240e49591c7b3da3d504d-34"&gt;&lt;/a&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;log_uncaught_exceptions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;exc_info&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a id="rest_code_a84db36ddc7240e49591c7b3da3d504d-35" name="rest_code_a84db36ddc7240e49591c7b3da3d504d-35" href="https://lukeplant.me.uk/blog/posts/controlling-sozi-remotely-from-an-android-phone/#rest_code_a84db36ddc7240e49591c7b3da3d504d-35"&gt;&lt;/a&gt;    &lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;critical&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Unhandled exception:'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;exc_info&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;exc_info&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_a84db36ddc7240e49591c7b3da3d504d-36" name="rest_code_a84db36ddc7240e49591c7b3da3d504d-36" href="https://lukeplant.me.uk/blog/posts/controlling-sozi-remotely-from-an-android-phone/#rest_code_a84db36ddc7240e49591c7b3da3d504d-36"&gt;&lt;/a&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;excepthook&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;log_uncaught_exceptions&lt;/span&gt;
&lt;a id="rest_code_a84db36ddc7240e49591c7b3da3d504d-37" name="rest_code_a84db36ddc7240e49591c7b3da3d504d-37" href="https://lukeplant.me.uk/blog/posts/controlling-sozi-remotely-from-an-android-phone/#rest_code_a84db36ddc7240e49591c7b3da3d504d-37"&gt;&lt;/a&gt;
&lt;a id="rest_code_a84db36ddc7240e49591c7b3da3d504d-38" name="rest_code_a84db36ddc7240e49591c7b3da3d504d-38" href="https://lukeplant.me.uk/blog/posts/controlling-sozi-remotely-from-an-android-phone/#rest_code_a84db36ddc7240e49591c7b3da3d504d-38"&gt;&lt;/a&gt;
&lt;a id="rest_code_a84db36ddc7240e49591c7b3da3d504d-39" name="rest_code_a84db36ddc7240e49591c7b3da3d504d-39" href="https://lukeplant.me.uk/blog/posts/controlling-sozi-remotely-from-an-android-phone/#rest_code_a84db36ddc7240e49591c7b3da3d504d-39"&gt;&lt;/a&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="vm"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;'__main__'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a id="rest_code_a84db36ddc7240e49591c7b3da3d504d-40" name="rest_code_a84db36ddc7240e49591c7b3da3d504d-40" href="https://lukeplant.me.uk/blog/posts/controlling-sozi-remotely-from-an-android-phone/#rest_code_a84db36ddc7240e49591c7b3da3d504d-40"&gt;&lt;/a&gt;    &lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Starting..."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_a84db36ddc7240e49591c7b3da3d504d-41" name="rest_code_a84db36ddc7240e49591c7b3da3d504d-41" href="https://lukeplant.me.uk/blog/posts/controlling-sozi-remotely-from-an-android-phone/#rest_code_a84db36ddc7240e49591c7b3da3d504d-41"&gt;&lt;/a&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a id="rest_code_a84db36ddc7240e49591c7b3da3d504d-42" name="rest_code_a84db36ddc7240e49591c7b3da3d504d-42" href="https://lukeplant.me.uk/blog/posts/controlling-sozi-remotely-from-an-android-phone/#rest_code_a84db36ddc7240e49591c7b3da3d504d-42"&gt;&lt;/a&gt;        &lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="s2"&gt;"Usage: "&lt;/span&gt;
&lt;a id="rest_code_a84db36ddc7240e49591c7b3da3d504d-43" name="rest_code_a84db36ddc7240e49591c7b3da3d504d-43" href="https://lukeplant.me.uk/blog/posts/controlling-sozi-remotely-from-an-android-phone/#rest_code_a84db36ddc7240e49591c7b3da3d504d-43"&gt;&lt;/a&gt;        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;ACTIONS&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;a id="rest_code_a84db36ddc7240e49591c7b3da3d504d-44" name="rest_code_a84db36ddc7240e49591c7b3da3d504d-44" href="https://lukeplant.me.uk/blog/posts/controlling-sozi-remotely-from-an-android-phone/#rest_code_a84db36ddc7240e49591c7b3da3d504d-44"&gt;&lt;/a&gt;            &lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="s2"&gt;"  "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;
&lt;a id="rest_code_a84db36ddc7240e49591c7b3da3d504d-45" name="rest_code_a84db36ddc7240e49591c7b3da3d504d-45" href="https://lukeplant.me.uk/blog/posts/controlling-sozi-remotely-from-an-android-phone/#rest_code_a84db36ddc7240e49591c7b3da3d504d-45"&gt;&lt;/a&gt;    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a id="rest_code_a84db36ddc7240e49591c7b3da3d504d-46" name="rest_code_a84db36ddc7240e49591c7b3da3d504d-46" href="https://lukeplant.me.uk/blog/posts/controlling-sozi-remotely-from-an-android-phone/#rest_code_a84db36ddc7240e49591c7b3da3d504d-46"&gt;&lt;/a&gt;        &lt;span class="n"&gt;action&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;a id="rest_code_a84db36ddc7240e49591c7b3da3d504d-47" name="rest_code_a84db36ddc7240e49591c7b3da3d504d-47" href="https://lukeplant.me.uk/blog/posts/controlling-sozi-remotely-from-an-android-phone/#rest_code_a84db36ddc7240e49591c7b3da3d504d-47"&gt;&lt;/a&gt;        &lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Action = &lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_a84db36ddc7240e49591c7b3da3d504d-48" name="rest_code_a84db36ddc7240e49591c7b3da3d504d-48" href="https://lukeplant.me.uk/blog/posts/controlling-sozi-remotely-from-an-android-phone/#rest_code_a84db36ddc7240e49591c7b3da3d504d-48"&gt;&lt;/a&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;action&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"launch"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a id="rest_code_a84db36ddc7240e49591c7b3da3d504d-49" name="rest_code_a84db36ddc7240e49591c7b3da3d504d-49" href="https://lukeplant.me.uk/blog/posts/controlling-sozi-remotely-from-an-android-phone/#rest_code_a84db36ddc7240e49591c7b3da3d504d-49"&gt;&lt;/a&gt;            &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;system&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"DISPLAY=:0 nohup google-chrome '&lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s2"&gt;' &amp;amp;"&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;a id="rest_code_a84db36ddc7240e49591c7b3da3d504d-50" name="rest_code_a84db36ddc7240e49591c7b3da3d504d-50" href="https://lukeplant.me.uk/blog/posts/controlling-sozi-remotely-from-an-android-phone/#rest_code_a84db36ddc7240e49591c7b3da3d504d-50"&gt;&lt;/a&gt;        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a id="rest_code_a84db36ddc7240e49591c7b3da3d504d-51" name="rest_code_a84db36ddc7240e49591c7b3da3d504d-51" href="https://lukeplant.me.uk/blog/posts/controlling-sozi-remotely-from-an-android-phone/#rest_code_a84db36ddc7240e49591c7b3da3d504d-51"&gt;&lt;/a&gt;            &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ACTIONS&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;a id="rest_code_a84db36ddc7240e49591c7b3da3d504d-52" name="rest_code_a84db36ddc7240e49591c7b3da3d504d-52" href="https://lukeplant.me.uk/blog/posts/controlling-sozi-remotely-from-an-android-phone/#rest_code_a84db36ddc7240e49591c7b3da3d504d-52"&gt;&lt;/a&gt;            &lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Text = &lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_a84db36ddc7240e49591c7b3da3d504d-53" name="rest_code_a84db36ddc7240e49591c7b3da3d504d-53" href="https://lukeplant.me.uk/blog/posts/controlling-sozi-remotely-from-an-android-phone/#rest_code_a84db36ddc7240e49591c7b3da3d504d-53"&gt;&lt;/a&gt;            &lt;span class="n"&gt;send_text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_a84db36ddc7240e49591c7b3da3d504d-54" name="rest_code_a84db36ddc7240e49591c7b3da3d504d-54" href="https://lukeplant.me.uk/blog/posts/controlling-sozi-remotely-from-an-android-phone/#rest_code_a84db36ddc7240e49591c7b3da3d504d-54"&gt;&lt;/a&gt;
&lt;a id="rest_code_a84db36ddc7240e49591c7b3da3d504d-55" name="rest_code_a84db36ddc7240e49591c7b3da3d504d-55" href="https://lukeplant.me.uk/blog/posts/controlling-sozi-remotely-from-an-android-phone/#rest_code_a84db36ddc7240e49591c7b3da3d504d-55"&gt;&lt;/a&gt;    &lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Done"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This relies on command-line tools wmctrl and xvkbd. With only small
modifications it should work for Firefox too. It is not 100% reliable, as it
works by sending keypresses to windows, but it works fine for me.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;I set up a profile in Coversal to connect to my laptop and use this script.&lt;/p&gt;
&lt;p&gt;Coversal allows you to define the commands for certain actions – the list of
actions includes things like &lt;code class="docutils literal"&gt;up&lt;/code&gt;, &lt;code class="docutils literal"&gt;right&lt;/code&gt;, &lt;code class="docutils literal"&gt;next&lt;/code&gt; etc., but you can
add your own. You then assign actions to buttons, as desired.&lt;/p&gt;
&lt;p&gt;So I simply I had to set commands like "&lt;code class="docutils literal"&gt;/path/to/controlsozi next&lt;/code&gt;", and
then assign these actions to the buttons I wanted to use.&lt;/p&gt;
&lt;p&gt;By setting the &lt;code class="docutils literal"&gt;start_playback&lt;/code&gt; command to "&lt;code class="docutils literal"&gt;/path/to/controlsozi launch
'%s'&lt;/code&gt;", I could even use the file browser built in to Coversal to select the
presentation file to view, which is pretty neat.&lt;/p&gt;
&lt;p&gt;The one thing I was really missing was physical buttons – with a touch
screen, it's so easy to hit the wrong place, and I wanted something to rest
my finger or thumb on.&lt;/p&gt;
&lt;p&gt;I then realised that my phone does have a couple of physical buttons - the
volume control buttons on the side. By enabling the 'volume_up' and
'volume_down' buttons in Coversal and mapping them to the 'next' and
'previous' commands, the physical volume buttons get mapped to the same
actions, and they do the job just fine. I can use the rest of the controls on
the screen for the less common tasks.&lt;/p&gt;
&lt;img alt="Screen shot of Coversal" class="align-center" src="https://lukeplant.me.uk/blogmedia/2013-03-14-coversal.png"&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;For my phone to be able to connect to my laptop over SSH, there is one more
piece of configuration that must be done – the IP address of the laptop has to
be entered. If you have a local wifi, this is no problem – just connect the two
devices to the same wifi and they will be able to talk. My phone has a more
reliable option, though – it can itself operate as a wifi hotspot, creating a
wifi network that the laptop can connect to.&lt;/p&gt;
&lt;p&gt;Conclusions:&lt;/p&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;&lt;p&gt;Linux is awesome.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Smart phones are awesome.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Free Android apps are awesome (and I think it is the Linux culture which
encourages this).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Python is awesome.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Being a programmer and being able to plug all this stuff together is awesome.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;</content>
    <category term="linux" label="Linux"/>
    <category term="python" label="Python"/>
  </entry>
  <entry>
    <title>KTimeTracker replacement - TimeCult</title>
    <id>https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/</id>
    <updated>2012-02-24T17:57:32Z</updated>
    <published>2012-02-24T17:57:32Z</published>
    <author>
      <name>Luke Plant</name>
    </author>
    <link rel="alternate" type="text/html" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/"/>
    <summary type="html">&lt;p&gt;TimeCult works well, and I wrote a script for converting KTimeTracker files.&lt;/p&gt;</summary>
    <content type="html">&lt;p&gt;For a long time I haven't been able to find a decent replacement or alternative to KTimeTracker. But I've now succeeded: &lt;a class="reference external" href="http://timecult.wordpress.com/"&gt;TimeCult&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It is &lt;a class="reference external" href="https://github.com/dyadix/TimeCult/issues/1"&gt;currently lacking an installer for Linux&lt;/a&gt;, but it can be &lt;a class="reference external" href="http://xmemory.tompium.com/2011/10/get-timecult-running-on-linux.html"&gt;made to work with Linux easily&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I also found that it uses a very easy-to-deciper XML format, and, with the help of &lt;a class="reference external" href="http://pypi.python.org/pypi/vobject"&gt;vobject&lt;/a&gt;, the KTimeTracker ical files are only slightly harder to figure out, so I created a Python &lt;a class="reference external" href="https://gist.github.com/1901236"&gt;script&lt;/a&gt; that will do the conversion.&lt;/p&gt;
&lt;p&gt;Use the script like this:&lt;/p&gt;
&lt;pre class="literal-block"&gt;./ics_to_timecult.py ~/.kde/share/apps/ktimetracker/ktimetracker.ics &amp;gt; out.tmt&lt;/pre&gt;
&lt;p&gt;It's here for reference - dependencies are vobject and elementtree:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code python"&gt;&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-1" name="rest_code_a0450a4012644093b79d6d15f29b9edd-1" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-1"&gt;&lt;/a&gt;&lt;span class="ch"&gt;#!/usr/bin/env python&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-2" name="rest_code_a0450a4012644093b79d6d15f29b9edd-2" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-2"&gt;&lt;/a&gt;&lt;span class="c1"&gt;# Quick and dirty script to convert ktimetracker.ics files&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-3" name="rest_code_a0450a4012644093b79d6d15f29b9edd-3" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-3"&gt;&lt;/a&gt;&lt;span class="c1"&gt;# into TimeCult files.&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-4" name="rest_code_a0450a4012644093b79d6d15f29b9edd-4" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-4"&gt;&lt;/a&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-5" name="rest_code_a0450a4012644093b79d6d15f29b9edd-5" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-5"&gt;&lt;/a&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;os.path&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-6" name="rest_code_a0450a4012644093b79d6d15f29b9edd-6" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-6"&gt;&lt;/a&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;sys&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-7" name="rest_code_a0450a4012644093b79d6d15f29b9edd-7" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-7"&gt;&lt;/a&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;time&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-8" name="rest_code_a0450a4012644093b79d6d15f29b9edd-8" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-8"&gt;&lt;/a&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;uuid&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-9" name="rest_code_a0450a4012644093b79d6d15f29b9edd-9" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-9"&gt;&lt;/a&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-10" name="rest_code_a0450a4012644093b79d6d15f29b9edd-10" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-10"&gt;&lt;/a&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;elementtree.ElementTree&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nn"&gt;ET&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-11" name="rest_code_a0450a4012644093b79d6d15f29b9edd-11" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-11"&gt;&lt;/a&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;vobject&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-12" name="rest_code_a0450a4012644093b79d6d15f29b9edd-12" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-12"&gt;&lt;/a&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-13" name="rest_code_a0450a4012644093b79d6d15f29b9edd-13" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-13"&gt;&lt;/a&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-14" name="rest_code_a0450a4012644093b79d6d15f29b9edd-14" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-14"&gt;&lt;/a&gt;&lt;span class="c1"&gt;# Structures to store the tree of data. Use native Python data types, and&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-15" name="rest_code_a0450a4012644093b79d6d15f29b9edd-15" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-15"&gt;&lt;/a&gt;&lt;span class="c1"&gt;# convert to what TimeCult expects when we 'render'&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-16" name="rest_code_a0450a4012644093b79d6d15f29b9edd-16" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-16"&gt;&lt;/a&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-17" name="rest_code_a0450a4012644093b79d6d15f29b9edd-17" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-17"&gt;&lt;/a&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Struct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;object&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-18" name="rest_code_a0450a4012644093b79d6d15f29b9edd-18" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-18"&gt;&lt;/a&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="fm"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-19" name="rest_code_a0450a4012644093b79d6d15f29b9edd-19" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-19"&gt;&lt;/a&gt;        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="vm"&gt;__dict__&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-20" name="rest_code_a0450a4012644093b79d6d15f29b9edd-20" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-20"&gt;&lt;/a&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-21" name="rest_code_a0450a4012644093b79d6d15f29b9edd-21" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-21"&gt;&lt;/a&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-22" name="rest_code_a0450a4012644093b79d6d15f29b9edd-22" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-22"&gt;&lt;/a&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TimeCult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Struct&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-23" name="rest_code_a0450a4012644093b79d6d15f29b9edd-23" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-23"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# &amp;lt;timecult&amp;gt;&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-24" name="rest_code_a0450a4012644093b79d6d15f29b9edd-24" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-24"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# Eventual attributes:&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-25" name="rest_code_a0450a4012644093b79d6d15f29b9edd-25" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-25"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;#  name&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-26" name="rest_code_a0450a4012644093b79d6d15f29b9edd-26" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-26"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;#  projectTree&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-27" name="rest_code_a0450a4012644093b79d6d15f29b9edd-27" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-27"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;#  timeLog&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-28" name="rest_code_a0450a4012644093b79d6d15f29b9edd-28" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-28"&gt;&lt;/a&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-29" name="rest_code_a0450a4012644093b79d6d15f29b9edd-29" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-29"&gt;&lt;/a&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;toXML&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-30" name="rest_code_a0450a4012644093b79d6d15f29b9edd-30" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-30"&gt;&lt;/a&gt;        &lt;span class="n"&gt;root&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ET&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;XML&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'&amp;lt;timecult appVersion="0.12" fileVersion="10" /&amp;gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-31" name="rest_code_a0450a4012644093b79d6d15f29b9edd-31" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-31"&gt;&lt;/a&gt;        &lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;attrib&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'uuid'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;uuid&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;uuid1&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-32" name="rest_code_a0450a4012644093b79d6d15f29b9edd-32" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-32"&gt;&lt;/a&gt;        &lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;attrib&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'name'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-33" name="rest_code_a0450a4012644093b79d6d15f29b9edd-33" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-33"&gt;&lt;/a&gt;        &lt;span class="n"&gt;pt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ET&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Element&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'projectTree'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-34" name="rest_code_a0450a4012644093b79d6d15f29b9edd-34" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-34"&gt;&lt;/a&gt;        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;projectTree&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-35" name="rest_code_a0450a4012644093b79d6d15f29b9edd-35" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-35"&gt;&lt;/a&gt;            &lt;span class="n"&gt;pt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;toXML&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-36" name="rest_code_a0450a4012644093b79d6d15f29b9edd-36" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-36"&gt;&lt;/a&gt;        &lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-37" name="rest_code_a0450a4012644093b79d6d15f29b9edd-37" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-37"&gt;&lt;/a&gt;        &lt;span class="n"&gt;tl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ET&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Element&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'timeLog'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-38" name="rest_code_a0450a4012644093b79d6d15f29b9edd-38" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-38"&gt;&lt;/a&gt;        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;tr&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;timeLog&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-39" name="rest_code_a0450a4012644093b79d6d15f29b9edd-39" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-39"&gt;&lt;/a&gt;            &lt;span class="n"&gt;tl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;toXML&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-40" name="rest_code_a0450a4012644093b79d6d15f29b9edd-40" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-40"&gt;&lt;/a&gt;        &lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tl&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-41" name="rest_code_a0450a4012644093b79d6d15f29b9edd-41" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-41"&gt;&lt;/a&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;root&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-42" name="rest_code_a0450a4012644093b79d6d15f29b9edd-42" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-42"&gt;&lt;/a&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-43" name="rest_code_a0450a4012644093b79d6d15f29b9edd-43" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-43"&gt;&lt;/a&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Node&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Struct&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-44" name="rest_code_a0450a4012644093b79d6d15f29b9edd-44" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-44"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# &amp;lt;project&amp;gt; and &amp;lt;task&amp;gt;&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-45" name="rest_code_a0450a4012644093b79d6d15f29b9edd-45" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-45"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# Eventually will have these attributes:&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-46" name="rest_code_a0450a4012644093b79d6d15f29b9edd-46" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-46"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;#  vtodo&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-47" name="rest_code_a0450a4012644093b79d6d15f29b9edd-47" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-47"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;#  summary&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-48" name="rest_code_a0450a4012644093b79d6d15f29b9edd-48" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-48"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;#  uid&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-49" name="rest_code_a0450a4012644093b79d6d15f29b9edd-49" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-49"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;#  created&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-50" name="rest_code_a0450a4012644093b79d6d15f29b9edd-50" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-50"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;#  parent&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-51" name="rest_code_a0450a4012644093b79d6d15f29b9edd-51" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-51"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;#  children&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-52" name="rest_code_a0450a4012644093b79d6d15f29b9edd-52" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-52"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;#  type = "project|task"&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-53" name="rest_code_a0450a4012644093b79d6d15f29b9edd-53" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-53"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;#  finished&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-54" name="rest_code_a0450a4012644093b79d6d15f29b9edd-54" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-54"&gt;&lt;/a&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="fm"&gt;__repr__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-55" name="rest_code_a0450a4012644093b79d6d15f29b9edd-55" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-55"&gt;&lt;/a&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;"&amp;lt;Node: uid=&lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s2"&gt; summary=&lt;/span&gt;&lt;span class="si"&gt;%r&lt;/span&gt;&lt;span class="s2"&gt;, parent=&lt;/span&gt;&lt;span class="si"&gt;%r&lt;/span&gt;&lt;span class="s2"&gt;&amp;gt;"&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-56" name="rest_code_a0450a4012644093b79d6d15f29b9edd-56" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-56"&gt;&lt;/a&gt;            &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;uid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-57" name="rest_code_a0450a4012644093b79d6d15f29b9edd-57" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-57"&gt;&lt;/a&gt;            &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;summary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-58" name="rest_code_a0450a4012644093b79d6d15f29b9edd-58" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-58"&gt;&lt;/a&gt;            &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;summary&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parent&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-59" name="rest_code_a0450a4012644093b79d6d15f29b9edd-59" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-59"&gt;&lt;/a&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-60" name="rest_code_a0450a4012644093b79d6d15f29b9edd-60" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-60"&gt;&lt;/a&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;toXML&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-61" name="rest_code_a0450a4012644093b79d6d15f29b9edd-61" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-61"&gt;&lt;/a&gt;        &lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ET&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Element&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-62" name="rest_code_a0450a4012644093b79d6d15f29b9edd-62" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-62"&gt;&lt;/a&gt;        &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;attrib&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'id'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-63" name="rest_code_a0450a4012644093b79d6d15f29b9edd-63" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-63"&gt;&lt;/a&gt;        &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;attrib&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'name'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;summary&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-64" name="rest_code_a0450a4012644093b79d6d15f29b9edd-64" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-64"&gt;&lt;/a&gt;        &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;attrib&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'created'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mktime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;created&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;timetuple&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-65" name="rest_code_a0450a4012644093b79d6d15f29b9edd-65" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-65"&gt;&lt;/a&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"task"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-66" name="rest_code_a0450a4012644093b79d6d15f29b9edd-66" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-66"&gt;&lt;/a&gt;            &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;children&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-67" name="rest_code_a0450a4012644093b79d6d15f29b9edd-67" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-67"&gt;&lt;/a&gt;            &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;attrib&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'status'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'finished'&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;finished&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="s1"&gt;'inProgress'&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-68" name="rest_code_a0450a4012644093b79d6d15f29b9edd-68" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-68"&gt;&lt;/a&gt;        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-69" name="rest_code_a0450a4012644093b79d6d15f29b9edd-69" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-69"&gt;&lt;/a&gt;            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;children&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-70" name="rest_code_a0450a4012644093b79d6d15f29b9edd-70" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-70"&gt;&lt;/a&gt;                &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;toXML&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-71" name="rest_code_a0450a4012644093b79d6d15f29b9edd-71" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-71"&gt;&lt;/a&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-72" name="rest_code_a0450a4012644093b79d6d15f29b9edd-72" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-72"&gt;&lt;/a&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-73" name="rest_code_a0450a4012644093b79d6d15f29b9edd-73" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-73"&gt;&lt;/a&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TimeRec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Struct&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-74" name="rest_code_a0450a4012644093b79d6d15f29b9edd-74" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-74"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# &amp;lt;timerec&amp;gt;&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-75" name="rest_code_a0450a4012644093b79d6d15f29b9edd-75" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-75"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# Eventual attributes:&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-76" name="rest_code_a0450a4012644093b79d6d15f29b9edd-76" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-76"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;#  startTime  # datetime&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-77" name="rest_code_a0450a4012644093b79d6d15f29b9edd-77" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-77"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;#  duration   # seconds&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-78" name="rest_code_a0450a4012644093b79d6d15f29b9edd-78" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-78"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;#  task       # Node&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-79" name="rest_code_a0450a4012644093b79d6d15f29b9edd-79" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-79"&gt;&lt;/a&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;toXML&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-80" name="rest_code_a0450a4012644093b79d6d15f29b9edd-80" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-80"&gt;&lt;/a&gt;        &lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ET&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Element&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"timeRec"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-81" name="rest_code_a0450a4012644093b79d6d15f29b9edd-81" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-81"&gt;&lt;/a&gt;        &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;attrib&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'taskId'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;taskId&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-82" name="rest_code_a0450a4012644093b79d6d15f29b9edd-82" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-82"&gt;&lt;/a&gt;        &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;attrib&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'startTime'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mktime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;startTime&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;timetuple&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-83" name="rest_code_a0450a4012644093b79d6d15f29b9edd-83" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-83"&gt;&lt;/a&gt;        &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;attrib&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'duration'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;duration&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-84" name="rest_code_a0450a4012644093b79d6d15f29b9edd-84" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-84"&gt;&lt;/a&gt;        &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;attrib&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'notes'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-85" name="rest_code_a0450a4012644093b79d6d15f29b9edd-85" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-85"&gt;&lt;/a&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-86" name="rest_code_a0450a4012644093b79d6d15f29b9edd-86" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-86"&gt;&lt;/a&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-87" name="rest_code_a0450a4012644093b79d6d15f29b9edd-87" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-87"&gt;&lt;/a&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;convert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-88" name="rest_code_a0450a4012644093b79d6d15f29b9edd-88" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-88"&gt;&lt;/a&gt;    &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;vobject&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;readOne&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-89" name="rest_code_a0450a4012644093b79d6d15f29b9edd-89" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-89"&gt;&lt;/a&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-90" name="rest_code_a0450a4012644093b79d6d15f29b9edd-90" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-90"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# First parse Todos&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-91" name="rest_code_a0450a4012644093b79d6d15f29b9edd-91" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-91"&gt;&lt;/a&gt;    &lt;span class="n"&gt;nodes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-92" name="rest_code_a0450a4012644093b79d6d15f29b9edd-92" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-92"&gt;&lt;/a&gt;    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;vtodo&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;vtodo_list&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-93" name="rest_code_a0450a4012644093b79d6d15f29b9edd-93" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-93"&gt;&lt;/a&gt;        &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Node&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vtodo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;vtodo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-94" name="rest_code_a0450a4012644093b79d6d15f29b9edd-94" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-94"&gt;&lt;/a&gt;                 &lt;span class="n"&gt;uid&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;vtodo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;uid&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-95" name="rest_code_a0450a4012644093b79d6d15f29b9edd-95" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-95"&gt;&lt;/a&gt;                 &lt;span class="n"&gt;summary&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;vtodo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;summary&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-96" name="rest_code_a0450a4012644093b79d6d15f29b9edd-96" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-96"&gt;&lt;/a&gt;                 &lt;span class="n"&gt;created&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;vtodo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;created&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-97" name="rest_code_a0450a4012644093b79d6d15f29b9edd-97" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-97"&gt;&lt;/a&gt;                 &lt;span class="n"&gt;finished&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;vtodo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;contents&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'percent-complete'&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"100"&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-98" name="rest_code_a0450a4012644093b79d6d15f29b9edd-98" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-98"&gt;&lt;/a&gt;                 &lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-99" name="rest_code_a0450a4012644093b79d6d15f29b9edd-99" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-99"&gt;&lt;/a&gt;        &lt;span class="n"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;uid&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-100" name="rest_code_a0450a4012644093b79d6d15f29b9edd-100" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-100"&gt;&lt;/a&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-101" name="rest_code_a0450a4012644093b79d6d15f29b9edd-101" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-101"&gt;&lt;/a&gt;    &lt;span class="n"&gt;children&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-102" name="rest_code_a0450a4012644093b79d6d15f29b9edd-102" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-102"&gt;&lt;/a&gt;    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;uid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;nodes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-103" name="rest_code_a0450a4012644093b79d6d15f29b9edd-103" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-103"&gt;&lt;/a&gt;        &lt;span class="n"&gt;vtodo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;vtodo&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-104" name="rest_code_a0450a4012644093b79d6d15f29b9edd-104" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-104"&gt;&lt;/a&gt;        &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-105" name="rest_code_a0450a4012644093b79d6d15f29b9edd-105" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-105"&gt;&lt;/a&gt;            &lt;span class="n"&gt;related_uid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;vtodo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;contents&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'related-to'&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-106" name="rest_code_a0450a4012644093b79d6d15f29b9edd-106" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-106"&gt;&lt;/a&gt;            &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;related_uid&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-107" name="rest_code_a0450a4012644093b79d6d15f29b9edd-107" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-107"&gt;&lt;/a&gt;            &lt;span class="n"&gt;children&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setdefault&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;related_uid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[])&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-108" name="rest_code_a0450a4012644093b79d6d15f29b9edd-108" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-108"&gt;&lt;/a&gt;        &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="ne"&gt;KeyError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-109" name="rest_code_a0450a4012644093b79d6d15f29b9edd-109" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-109"&gt;&lt;/a&gt;            &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-110" name="rest_code_a0450a4012644093b79d6d15f29b9edd-110" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-110"&gt;&lt;/a&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-111" name="rest_code_a0450a4012644093b79d6d15f29b9edd-111" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-111"&gt;&lt;/a&gt;    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;uid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;nodes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-112" name="rest_code_a0450a4012644093b79d6d15f29b9edd-112" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-112"&gt;&lt;/a&gt;        &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;children&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;children&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;uid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[])&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-113" name="rest_code_a0450a4012644093b79d6d15f29b9edd-113" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-113"&gt;&lt;/a&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;children&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-114" name="rest_code_a0450a4012644093b79d6d15f29b9edd-114" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-114"&gt;&lt;/a&gt;            &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"task"&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-115" name="rest_code_a0450a4012644093b79d6d15f29b9edd-115" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-115"&gt;&lt;/a&gt;        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-116" name="rest_code_a0450a4012644093b79d6d15f29b9edd-116" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-116"&gt;&lt;/a&gt;            &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"project"&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-117" name="rest_code_a0450a4012644093b79d6d15f29b9edd-117" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-117"&gt;&lt;/a&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-118" name="rest_code_a0450a4012644093b79d6d15f29b9edd-118" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-118"&gt;&lt;/a&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-119" name="rest_code_a0450a4012644093b79d6d15f29b9edd-119" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-119"&gt;&lt;/a&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-120" name="rest_code_a0450a4012644093b79d6d15f29b9edd-120" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-120"&gt;&lt;/a&gt;    &lt;span class="n"&gt;autouid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="c1"&gt;# For newly created Tasks&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-121" name="rest_code_a0450a4012644093b79d6d15f29b9edd-121" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-121"&gt;&lt;/a&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-122" name="rest_code_a0450a4012644093b79d6d15f29b9edd-122" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-122"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# Now find the time information in the ICS file&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-123" name="rest_code_a0450a4012644093b79d6d15f29b9edd-123" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-123"&gt;&lt;/a&gt;    &lt;span class="n"&gt;time_log&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-124" name="rest_code_a0450a4012644093b79d6d15f29b9edd-124" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-124"&gt;&lt;/a&gt;    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;vevent&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;vevent_list&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-125" name="rest_code_a0450a4012644093b79d6d15f29b9edd-125" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-125"&gt;&lt;/a&gt;        &lt;span class="n"&gt;related_uid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;vevent&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;contents&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'related-to'&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-126" name="rest_code_a0450a4012644093b79d6d15f29b9edd-126" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-126"&gt;&lt;/a&gt;        &lt;span class="n"&gt;task&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;related_uid&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-127" name="rest_code_a0450a4012644093b79d6d15f29b9edd-127" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-127"&gt;&lt;/a&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"project"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-128" name="rest_code_a0450a4012644093b79d6d15f29b9edd-128" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-128"&gt;&lt;/a&gt;            &lt;span class="c1"&gt;# TimeCult can only cope with time events being against 'leaf' nodes&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-129" name="rest_code_a0450a4012644093b79d6d15f29b9edd-129" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-129"&gt;&lt;/a&gt;            &lt;span class="c1"&gt;# in the tree. So we need to adjust and create an additional leaf&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-130" name="rest_code_a0450a4012644093b79d6d15f29b9edd-130" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-130"&gt;&lt;/a&gt;            &lt;span class="n"&gt;project&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;task&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-131" name="rest_code_a0450a4012644093b79d6d15f29b9edd-131" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-131"&gt;&lt;/a&gt;            &lt;span class="n"&gt;undefined_l&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;project&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;children&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;uid&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;startswith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'autouid'&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-132" name="rest_code_a0450a4012644093b79d6d15f29b9edd-132" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-132"&gt;&lt;/a&gt;            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;undefined_l&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-133" name="rest_code_a0450a4012644093b79d6d15f29b9edd-133" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-133"&gt;&lt;/a&gt;                &lt;span class="n"&gt;task&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;undefined_l&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-134" name="rest_code_a0450a4012644093b79d6d15f29b9edd-134" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-134"&gt;&lt;/a&gt;            &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-135" name="rest_code_a0450a4012644093b79d6d15f29b9edd-135" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-135"&gt;&lt;/a&gt;                &lt;span class="n"&gt;task&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Node&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;uid&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'autouid-&lt;/span&gt;&lt;span class="si"&gt;%d&lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;autouid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-136" name="rest_code_a0450a4012644093b79d6d15f29b9edd-136" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-136"&gt;&lt;/a&gt;                            &lt;span class="n"&gt;summary&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'other'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-137" name="rest_code_a0450a4012644093b79d6d15f29b9edd-137" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-137"&gt;&lt;/a&gt;                            &lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;project&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-138" name="rest_code_a0450a4012644093b79d6d15f29b9edd-138" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-138"&gt;&lt;/a&gt;                            &lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"task"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-139" name="rest_code_a0450a4012644093b79d6d15f29b9edd-139" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-139"&gt;&lt;/a&gt;                            &lt;span class="n"&gt;created&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;project&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;created&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-140" name="rest_code_a0450a4012644093b79d6d15f29b9edd-140" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-140"&gt;&lt;/a&gt;                            &lt;span class="n"&gt;finished&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-141" name="rest_code_a0450a4012644093b79d6d15f29b9edd-141" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-141"&gt;&lt;/a&gt;                            &lt;span class="n"&gt;children&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[])&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-142" name="rest_code_a0450a4012644093b79d6d15f29b9edd-142" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-142"&gt;&lt;/a&gt;                &lt;span class="n"&gt;autouid&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-143" name="rest_code_a0450a4012644093b79d6d15f29b9edd-143" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-143"&gt;&lt;/a&gt;                &lt;span class="n"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;uid&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;task&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-144" name="rest_code_a0450a4012644093b79d6d15f29b9edd-144" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-144"&gt;&lt;/a&gt;                &lt;span class="n"&gt;project&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;children&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-145" name="rest_code_a0450a4012644093b79d6d15f29b9edd-145" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-145"&gt;&lt;/a&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-146" name="rest_code_a0450a4012644093b79d6d15f29b9edd-146" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-146"&gt;&lt;/a&gt;        &lt;span class="n"&gt;dtstart&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;vevent&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dtstart&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-147" name="rest_code_a0450a4012644093b79d6d15f29b9edd-147" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-147"&gt;&lt;/a&gt;        &lt;span class="n"&gt;dtend&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;vevent&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dtend&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-148" name="rest_code_a0450a4012644093b79d6d15f29b9edd-148" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-148"&gt;&lt;/a&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;dtstart&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tzinfo&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-149" name="rest_code_a0450a4012644093b79d6d15f29b9edd-149" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-149"&gt;&lt;/a&gt;            &lt;span class="n"&gt;dtstart&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dtstart&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tzinfo&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;dtend&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tzinfo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-150" name="rest_code_a0450a4012644093b79d6d15f29b9edd-150" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-150"&gt;&lt;/a&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;dtend&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tzinfo&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-151" name="rest_code_a0450a4012644093b79d6d15f29b9edd-151" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-151"&gt;&lt;/a&gt;            &lt;span class="n"&gt;dtend&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dtend&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tzinfo&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;dtstart&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tzinfo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-152" name="rest_code_a0450a4012644093b79d6d15f29b9edd-152" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-152"&gt;&lt;/a&gt;        &lt;span class="n"&gt;time_rec&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;TimeRec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;startTime&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;dtstart&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-153" name="rest_code_a0450a4012644093b79d6d15f29b9edd-153" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-153"&gt;&lt;/a&gt;                           &lt;span class="n"&gt;duration&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dtend&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;dtstart&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;total_seconds&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-154" name="rest_code_a0450a4012644093b79d6d15f29b9edd-154" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-154"&gt;&lt;/a&gt;                           &lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-155" name="rest_code_a0450a4012644093b79d6d15f29b9edd-155" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-155"&gt;&lt;/a&gt;        &lt;span class="n"&gt;time_log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;time_rec&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-156" name="rest_code_a0450a4012644093b79d6d15f29b9edd-156" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-156"&gt;&lt;/a&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-157" name="rest_code_a0450a4012644093b79d6d15f29b9edd-157" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-157"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# Now need to assign IDs&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-158" name="rest_code_a0450a4012644093b79d6d15f29b9edd-158" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-158"&gt;&lt;/a&gt;    &lt;span class="n"&gt;taskId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-159" name="rest_code_a0450a4012644093b79d6d15f29b9edd-159" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-159"&gt;&lt;/a&gt;    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;nodes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-160" name="rest_code_a0450a4012644093b79d6d15f29b9edd-160" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-160"&gt;&lt;/a&gt;        &lt;span class="n"&gt;taskId&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-161" name="rest_code_a0450a4012644093b79d6d15f29b9edd-161" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-161"&gt;&lt;/a&gt;        &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;taskId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-162" name="rest_code_a0450a4012644093b79d6d15f29b9edd-162" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-162"&gt;&lt;/a&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-163" name="rest_code_a0450a4012644093b79d6d15f29b9edd-163" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-163"&gt;&lt;/a&gt;    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;tr&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;time_log&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-164" name="rest_code_a0450a4012644093b79d6d15f29b9edd-164" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-164"&gt;&lt;/a&gt;        &lt;span class="n"&gt;tr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;taskId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-165" name="rest_code_a0450a4012644093b79d6d15f29b9edd-165" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-165"&gt;&lt;/a&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-166" name="rest_code_a0450a4012644093b79d6d15f29b9edd-166" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-166"&gt;&lt;/a&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;TimeCult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-167" name="rest_code_a0450a4012644093b79d6d15f29b9edd-167" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-167"&gt;&lt;/a&gt;        &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;basename&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-168" name="rest_code_a0450a4012644093b79d6d15f29b9edd-168" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-168"&gt;&lt;/a&gt;        &lt;span class="n"&gt;projectTree&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;nodes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parent&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-169" name="rest_code_a0450a4012644093b79d6d15f29b9edd-169" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-169"&gt;&lt;/a&gt;        &lt;span class="n"&gt;timeLog&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;time_log&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-170" name="rest_code_a0450a4012644093b79d6d15f29b9edd-170" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-170"&gt;&lt;/a&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-171" name="rest_code_a0450a4012644093b79d6d15f29b9edd-171" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-171"&gt;&lt;/a&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-172" name="rest_code_a0450a4012644093b79d6d15f29b9edd-172" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-172"&gt;&lt;/a&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="vm"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;'__main__'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-173" name="rest_code_a0450a4012644093b79d6d15f29b9edd-173" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-173"&gt;&lt;/a&gt;    &lt;span class="n"&gt;filename&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-174" name="rest_code_a0450a4012644093b79d6d15f29b9edd-174" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-174"&gt;&lt;/a&gt;    &lt;span class="n"&gt;timecult&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;convert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-175" name="rest_code_a0450a4012644093b79d6d15f29b9edd-175" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-175"&gt;&lt;/a&gt;    &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stdout&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-176" name="rest_code_a0450a4012644093b79d6d15f29b9edd-176" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-176"&gt;&lt;/a&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="sd"&gt;"""&amp;lt;?xml version="1.0" encoding="UTF-8"?&amp;gt;"""&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
&lt;a id="rest_code_a0450a4012644093b79d6d15f29b9edd-177" name="rest_code_a0450a4012644093b79d6d15f29b9edd-177" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_a0450a4012644093b79d6d15f29b9edd-177"&gt;&lt;/a&gt;        &lt;span class="n"&gt;ET&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tostring&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;timecult&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;toXML&lt;/span&gt;&lt;span class="p"&gt;()))&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;</content>
    <category term="kde" label="KDE"/>
    <category term="linux" label="Linux"/>
    <category term="python" label="Python"/>
  </entry>
  <entry>
    <title>My Bash prompt</title>
    <id>https://lukeplant.me.uk/blog/posts/my-bash-prompt/</id>
    <updated>2011-02-28T23:32:42Z</updated>
    <published>2011-02-28T23:32:42Z</published>
    <author>
      <name>Luke Plant</name>
    </author>
    <link rel="alternate" type="text/html" href="https://lukeplant.me.uk/blog/posts/my-bash-prompt/"/>
    <summary type="html">&lt;p&gt;My bash prompt, including git/hg branch name.&lt;/p&gt;</summary>
    <content type="html">&lt;p&gt;I like my &lt;a class="reference external" href="http://tldp.org/HOWTO/Bash-Prompt-HOWTO/"&gt;bash prompt&lt;/a&gt;:&lt;/p&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;&lt;p&gt;to include the current &lt;a class="reference external" href="http://mercurial.selenic.com/"&gt;Mercurial&lt;/a&gt;/&lt;a class="reference external" href="http://git-scm.com/"&gt;Git&lt;/a&gt; branch if applicable – otherwise I would quickly get in big trouble with committing things to the wrong branch in &lt;a class="reference external" href="https://lukeplant.me.uk/blog/posts/my-bash-prompt/www.djangoproject.com"&gt;Django&lt;/a&gt; etc.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;to show the &lt;strong&gt;full&lt;/strong&gt; current working directory - for similar reasons to above, as I often end up lost in a maze of twisty little directories, all alike.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;to be always instantaneous (tricky, when 'hg branch' can take up to a second on a bad day due to startup time)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;to work well with virtualenv (which adds the environment name to the beginning of the prompt)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;to show the time (so that if I have a long running job that I didn't realise was going to be long running, all the info is there to find out how long it took).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;to do all the above without confusing me!&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;All of these together mean I need two lines, but this has advantages - it means the commands I type always start at the same column. I achieve (1) by a bash function that looks for .hg or .git recursively, and looks for '.hg/branch' where applicable. I achieve (6) by using some colours distinguish the different bits.&lt;/p&gt;
&lt;p&gt;The end product looks like this - first without a virtualenv, then with:&lt;/p&gt;
&lt;img alt="Image of command line prompt" class="align-center" src="https://lukeplant.me.uk/blogmedia/custom_bash_prompt.png"&gt;
&lt;p&gt;The code looks like this (in ~/.bashrc)&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code bash"&gt;&lt;a id="rest_code_c8f4f833e1824dc48d47d30e115b75e1-1" name="rest_code_c8f4f833e1824dc48d47d30e115b75e1-1" href="https://lukeplant.me.uk/blog/posts/my-bash-prompt/#rest_code_c8f4f833e1824dc48d47d30e115b75e1-1"&gt;&lt;/a&gt;&lt;span class="c1"&gt;# Prints " $branchname" if in a hg or git repo, otherwise nothing.&lt;/span&gt;
&lt;a id="rest_code_c8f4f833e1824dc48d47d30e115b75e1-2" name="rest_code_c8f4f833e1824dc48d47d30e115b75e1-2" href="https://lukeplant.me.uk/blog/posts/my-bash-prompt/#rest_code_c8f4f833e1824dc48d47d30e115b75e1-2"&gt;&lt;/a&gt;print_branch_name&lt;span class="o"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;
&lt;a id="rest_code_c8f4f833e1824dc48d47d30e115b75e1-3" name="rest_code_c8f4f833e1824dc48d47d30e115b75e1-3" href="https://lukeplant.me.uk/blog/posts/my-bash-prompt/#rest_code_c8f4f833e1824dc48d47d30e115b75e1-3"&gt;&lt;/a&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-z&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;a id="rest_code_c8f4f833e1824dc48d47d30e115b75e1-4" name="rest_code_c8f4f833e1824dc48d47d30e115b75e1-4" href="https://lukeplant.me.uk/blog/posts/my-bash-prompt/#rest_code_c8f4f833e1824dc48d47d30e115b75e1-4"&gt;&lt;/a&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;then&lt;/span&gt;
&lt;a id="rest_code_c8f4f833e1824dc48d47d30e115b75e1-5" name="rest_code_c8f4f833e1824dc48d47d30e115b75e1-5" href="https://lukeplant.me.uk/blog/posts/my-bash-prompt/#rest_code_c8f4f833e1824dc48d47d30e115b75e1-5"&gt;&lt;/a&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nv"&gt;curdir&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="nb"&gt;pwd&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;
&lt;a id="rest_code_c8f4f833e1824dc48d47d30e115b75e1-6" name="rest_code_c8f4f833e1824dc48d47d30e115b75e1-6" href="https://lukeplant.me.uk/blog/posts/my-bash-prompt/#rest_code_c8f4f833e1824dc48d47d30e115b75e1-6"&gt;&lt;/a&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;
&lt;a id="rest_code_c8f4f833e1824dc48d47d30e115b75e1-7" name="rest_code_c8f4f833e1824dc48d47d30e115b75e1-7" href="https://lukeplant.me.uk/blog/posts/my-bash-prompt/#rest_code_c8f4f833e1824dc48d47d30e115b75e1-7"&gt;&lt;/a&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nv"&gt;curdir&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;
&lt;a id="rest_code_c8f4f833e1824dc48d47d30e115b75e1-8" name="rest_code_c8f4f833e1824dc48d47d30e115b75e1-8" href="https://lukeplant.me.uk/blog/posts/my-bash-prompt/#rest_code_c8f4f833e1824dc48d47d30e115b75e1-8"&gt;&lt;/a&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;a id="rest_code_c8f4f833e1824dc48d47d30e115b75e1-9" name="rest_code_c8f4f833e1824dc48d47d30e115b75e1-9" href="https://lukeplant.me.uk/blog/posts/my-bash-prompt/#rest_code_c8f4f833e1824dc48d47d30e115b75e1-9"&gt;&lt;/a&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-d&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$curdir&lt;/span&gt;&lt;span class="s2"&gt;/.hg"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;a id="rest_code_c8f4f833e1824dc48d47d30e115b75e1-10" name="rest_code_c8f4f833e1824dc48d47d30e115b75e1-10" href="https://lukeplant.me.uk/blog/posts/my-bash-prompt/#rest_code_c8f4f833e1824dc48d47d30e115b75e1-10"&gt;&lt;/a&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;then&lt;/span&gt;
&lt;a id="rest_code_c8f4f833e1824dc48d47d30e115b75e1-11" name="rest_code_c8f4f833e1824dc48d47d30e115b75e1-11" href="https://lukeplant.me.uk/blog/posts/my-bash-prompt/#rest_code_c8f4f833e1824dc48d47d30e115b75e1-11"&gt;&lt;/a&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-n&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;" "&lt;/span&gt;
&lt;a id="rest_code_c8f4f833e1824dc48d47d30e115b75e1-12" name="rest_code_c8f4f833e1824dc48d47d30e115b75e1-12" href="https://lukeplant.me.uk/blog/posts/my-bash-prompt/#rest_code_c8f4f833e1824dc48d47d30e115b75e1-12"&gt;&lt;/a&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-f&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$curdir&lt;/span&gt;&lt;span class="s2"&gt;/.hg/branch"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;a id="rest_code_c8f4f833e1824dc48d47d30e115b75e1-13" name="rest_code_c8f4f833e1824dc48d47d30e115b75e1-13" href="https://lukeplant.me.uk/blog/posts/my-bash-prompt/#rest_code_c8f4f833e1824dc48d47d30e115b75e1-13"&gt;&lt;/a&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;then&lt;/span&gt;
&lt;a id="rest_code_c8f4f833e1824dc48d47d30e115b75e1-14" name="rest_code_c8f4f833e1824dc48d47d30e115b75e1-14" href="https://lukeplant.me.uk/blog/posts/my-bash-prompt/#rest_code_c8f4f833e1824dc48d47d30e115b75e1-14"&gt;&lt;/a&gt;&lt;span class="w"&gt;            &lt;/span&gt;cat&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$curdir&lt;/span&gt;&lt;span class="s2"&gt;/.hg/branch"&lt;/span&gt;
&lt;a id="rest_code_c8f4f833e1824dc48d47d30e115b75e1-15" name="rest_code_c8f4f833e1824dc48d47d30e115b75e1-15" href="https://lukeplant.me.uk/blog/posts/my-bash-prompt/#rest_code_c8f4f833e1824dc48d47d30e115b75e1-15"&gt;&lt;/a&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;
&lt;a id="rest_code_c8f4f833e1824dc48d47d30e115b75e1-16" name="rest_code_c8f4f833e1824dc48d47d30e115b75e1-16" href="https://lukeplant.me.uk/blog/posts/my-bash-prompt/#rest_code_c8f4f833e1824dc48d47d30e115b75e1-16"&gt;&lt;/a&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"default"&lt;/span&gt;
&lt;a id="rest_code_c8f4f833e1824dc48d47d30e115b75e1-17" name="rest_code_c8f4f833e1824dc48d47d30e115b75e1-17" href="https://lukeplant.me.uk/blog/posts/my-bash-prompt/#rest_code_c8f4f833e1824dc48d47d30e115b75e1-17"&gt;&lt;/a&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;a id="rest_code_c8f4f833e1824dc48d47d30e115b75e1-18" name="rest_code_c8f4f833e1824dc48d47d30e115b75e1-18" href="https://lukeplant.me.uk/blog/posts/my-bash-prompt/#rest_code_c8f4f833e1824dc48d47d30e115b75e1-18"&gt;&lt;/a&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
&lt;a id="rest_code_c8f4f833e1824dc48d47d30e115b75e1-19" name="rest_code_c8f4f833e1824dc48d47d30e115b75e1-19" href="https://lukeplant.me.uk/blog/posts/my-bash-prompt/#rest_code_c8f4f833e1824dc48d47d30e115b75e1-19"&gt;&lt;/a&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;elif&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-d&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$curdir&lt;/span&gt;&lt;span class="s2"&gt;/.git"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;a id="rest_code_c8f4f833e1824dc48d47d30e115b75e1-20" name="rest_code_c8f4f833e1824dc48d47d30e115b75e1-20" href="https://lukeplant.me.uk/blog/posts/my-bash-prompt/#rest_code_c8f4f833e1824dc48d47d30e115b75e1-20"&gt;&lt;/a&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;then&lt;/span&gt;
&lt;a id="rest_code_c8f4f833e1824dc48d47d30e115b75e1-21" name="rest_code_c8f4f833e1824dc48d47d30e115b75e1-21" href="https://lukeplant.me.uk/blog/posts/my-bash-prompt/#rest_code_c8f4f833e1824dc48d47d30e115b75e1-21"&gt;&lt;/a&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-n&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;" "&lt;/span&gt;
&lt;a id="rest_code_c8f4f833e1824dc48d47d30e115b75e1-22" name="rest_code_c8f4f833e1824dc48d47d30e115b75e1-22" href="https://lukeplant.me.uk/blog/posts/my-bash-prompt/#rest_code_c8f4f833e1824dc48d47d30e115b75e1-22"&gt;&lt;/a&gt;&lt;span class="w"&gt;        &lt;/span&gt;git&lt;span class="w"&gt; &lt;/span&gt;branch&lt;span class="w"&gt; &lt;/span&gt;--no-color&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;/dev/null&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;sed&lt;span class="w"&gt; &lt;/span&gt;-e&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'/^[^*]/d'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-e&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'s/* \(.*\)/\1/'&lt;/span&gt;
&lt;a id="rest_code_c8f4f833e1824dc48d47d30e115b75e1-23" name="rest_code_c8f4f833e1824dc48d47d30e115b75e1-23" href="https://lukeplant.me.uk/blog/posts/my-bash-prompt/#rest_code_c8f4f833e1824dc48d47d30e115b75e1-23"&gt;&lt;/a&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;a id="rest_code_c8f4f833e1824dc48d47d30e115b75e1-24" name="rest_code_c8f4f833e1824dc48d47d30e115b75e1-24" href="https://lukeplant.me.uk/blog/posts/my-bash-prompt/#rest_code_c8f4f833e1824dc48d47d30e115b75e1-24"&gt;&lt;/a&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;# Recurse upwards&lt;/span&gt;
&lt;a id="rest_code_c8f4f833e1824dc48d47d30e115b75e1-25" name="rest_code_c8f4f833e1824dc48d47d30e115b75e1-25" href="https://lukeplant.me.uk/blog/posts/my-bash-prompt/#rest_code_c8f4f833e1824dc48d47d30e115b75e1-25"&gt;&lt;/a&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$curdir&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'/'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;a id="rest_code_c8f4f833e1824dc48d47d30e115b75e1-26" name="rest_code_c8f4f833e1824dc48d47d30e115b75e1-26" href="https://lukeplant.me.uk/blog/posts/my-bash-prompt/#rest_code_c8f4f833e1824dc48d47d30e115b75e1-26"&gt;&lt;/a&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;then&lt;/span&gt;
&lt;a id="rest_code_c8f4f833e1824dc48d47d30e115b75e1-27" name="rest_code_c8f4f833e1824dc48d47d30e115b75e1-27" href="https://lukeplant.me.uk/blog/posts/my-bash-prompt/#rest_code_c8f4f833e1824dc48d47d30e115b75e1-27"&gt;&lt;/a&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;
&lt;a id="rest_code_c8f4f833e1824dc48d47d30e115b75e1-28" name="rest_code_c8f4f833e1824dc48d47d30e115b75e1-28" href="https://lukeplant.me.uk/blog/posts/my-bash-prompt/#rest_code_c8f4f833e1824dc48d47d30e115b75e1-28"&gt;&lt;/a&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;
&lt;a id="rest_code_c8f4f833e1824dc48d47d30e115b75e1-29" name="rest_code_c8f4f833e1824dc48d47d30e115b75e1-29" href="https://lukeplant.me.uk/blog/posts/my-bash-prompt/#rest_code_c8f4f833e1824dc48d47d30e115b75e1-29"&gt;&lt;/a&gt;&lt;span class="w"&gt;        &lt;/span&gt;print_branch_name&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;dirname&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$curdir&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;
&lt;a id="rest_code_c8f4f833e1824dc48d47d30e115b75e1-30" name="rest_code_c8f4f833e1824dc48d47d30e115b75e1-30" href="https://lukeplant.me.uk/blog/posts/my-bash-prompt/#rest_code_c8f4f833e1824dc48d47d30e115b75e1-30"&gt;&lt;/a&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;a id="rest_code_c8f4f833e1824dc48d47d30e115b75e1-31" name="rest_code_c8f4f833e1824dc48d47d30e115b75e1-31" href="https://lukeplant.me.uk/blog/posts/my-bash-prompt/#rest_code_c8f4f833e1824dc48d47d30e115b75e1-31"&gt;&lt;/a&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;a id="rest_code_c8f4f833e1824dc48d47d30e115b75e1-32" name="rest_code_c8f4f833e1824dc48d47d30e115b75e1-32" href="https://lukeplant.me.uk/blog/posts/my-bash-prompt/#rest_code_c8f4f833e1824dc48d47d30e115b75e1-32"&gt;&lt;/a&gt;
&lt;a id="rest_code_c8f4f833e1824dc48d47d30e115b75e1-33" name="rest_code_c8f4f833e1824dc48d47d30e115b75e1-33" href="https://lukeplant.me.uk/blog/posts/my-bash-prompt/#rest_code_c8f4f833e1824dc48d47d30e115b75e1-33"&gt;&lt;/a&gt;&lt;span class="nv"&gt;e&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="se"&gt;\\\0&lt;/span&gt;&lt;span class="m"&gt;33&lt;/span&gt;
&lt;a id="rest_code_c8f4f833e1824dc48d47d30e115b75e1-34" name="rest_code_c8f4f833e1824dc48d47d30e115b75e1-34" href="https://lukeplant.me.uk/blog/posts/my-bash-prompt/#rest_code_c8f4f833e1824dc48d47d30e115b75e1-34"&gt;&lt;/a&gt;&lt;span class="nb"&gt;export&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;PS1&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"\[&lt;/span&gt;&lt;span class="nv"&gt;$e&lt;/span&gt;&lt;span class="s2"&gt;[1;36m\][\u@\h \t]\[&lt;/span&gt;&lt;span class="nv"&gt;$e&lt;/span&gt;&lt;span class="s2"&gt;[1;33m\]\$(print_branch_name) \[&lt;/span&gt;&lt;span class="nv"&gt;$e&lt;/span&gt;&lt;span class="s2"&gt;[0m\]\w\n\[&lt;/span&gt;&lt;span class="nv"&gt;$e&lt;/span&gt;&lt;span class="s2"&gt;[1;37m\]——&amp;gt; \[&lt;/span&gt;&lt;span class="nv"&gt;$e&lt;/span&gt;&lt;span class="s2"&gt;[0m\]"&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;</content>
    <category term="linux" label="Linux"/>
    <category term="software-development" label="Software development"/>
  </entry>
  <entry>
    <title>player_do – control multiple media players from a single (command line) interface</title>
    <id>https://lukeplant.me.uk/blog/posts/player-do-control-multiple-media-players-from-a-single-command-line-interface/</id>
    <updated>2010-07-15T16:23:05+01:00</updated>
    <published>2010-07-15T16:23:05+01:00</published>
    <author>
      <name>Luke Plant</name>
    </author>
    <link rel="alternate" type="text/html" href="https://lukeplant.me.uk/blog/posts/player-do-control-multiple-media-players-from-a-single-command-line-interface/"/>
    <summary type="html">&lt;p&gt;I tend to use several music/media players, such as shell-fm, moc and Clementine. In order to be able to use the media buttons on my keyboard for pausing/skipping, I wrote this Python script to automatically route the commands to the right one.&lt;/p&gt;</summary>
    <content type="html">&lt;p&gt;I tend to use several music/media players, such as &lt;a class="reference external" href="http://nex.scrapping.cc/shell-fm/"&gt;shell-fm&lt;/a&gt;, &lt;a class="reference external" href="http://moc.daper.net/"&gt;moc&lt;/a&gt; and &lt;a class="reference external" href="http://code.google.com/p/clementine-player/"&gt;Clementine&lt;/a&gt;.  And I often try out new ones.  In order to be able to use the media buttons on my keyboard for pausing/skipping, I wrote this &lt;a class="reference external" href="http://pypi.python.org/pypi/playerdo"&gt;player_do Python script&lt;/a&gt; to automatically route the commands to the right one.&lt;/p&gt;
&lt;p&gt;Quick start:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code class="docutils literal"&gt;sudo easy_install playerdo&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Or, if you prefer this way like me, and have &lt;code class="docutils literal"&gt;&lt;span class="pre"&gt;$HOME/.local/bin&lt;/span&gt;&lt;/code&gt; on your &lt;code class="docutils literal"&gt;$PATH&lt;/code&gt;:&lt;/p&gt;
&lt;p&gt;&lt;code class="docutils literal"&gt;easy_install &lt;span class="pre"&gt;--prefix=$HOME/.local&lt;/span&gt; playerdo&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code class="docutils literal"&gt;player_do help&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Then use your window manager/desktop to setup keyboard shortcuts to &lt;code class="docutils literal"&gt;player_do playpause&lt;/code&gt;, &lt;code class="docutils literal"&gt;player_do next&lt;/code&gt; etc.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a class="reference external" href="http://incise.org/mpris-remote.html"&gt;mpris-remote&lt;/a&gt; does a similar job, but only for &lt;a class="reference external" href="http://en.wikipedia.org/wiki/Media_Player_Remote_Interfacing_Specification"&gt;MPRIS players&lt;/a&gt;, and I needed others.  My script also has an MPRIS backend, so it will support XMMS2, Amarok, Clementine, Exaile, Dragon Player and various others out of the box.  It also has support for shell-fm, moc, and rhythmbox.&lt;/p&gt;
&lt;p&gt;If you have more than one running at a time, it tries to be intelligent about which one to talk to, although of course it is not always possible to read your mind correctly!&lt;/p&gt;
&lt;p&gt;For other players that don't support MPRIS it should be quite easy to add a backend – please fork the &lt;a class="reference external" href="https://github.com/spookylukey/playerdo"&gt;GitHub repository&lt;/a&gt;, have a look at the existing backends and send me your patches!&lt;/p&gt;</content>
    <category term="linux" label="Linux"/>
    <category term="music" label="Music"/>
    <category term="python" label="Python"/>
  </entry>
  <entry>
    <title>Leaving KDE</title>
    <id>https://lukeplant.me.uk/blog/posts/leaving-kde/</id>
    <updated>2010-06-17T01:57:39+01:00</updated>
    <published>2010-06-17T01:57:39+01:00</published>
    <author>
      <name>Luke Plant</name>
    </author>
    <link rel="alternate" type="text/html" href="https://lukeplant.me.uk/blog/posts/leaving-kde/"/>
    <summary type="html">&lt;p&gt;After being a loyal fan of KDE for a long time, I've just left...&lt;/p&gt;</summary>
    <content type="html">&lt;p&gt;After being a loyal fan of KDE for a long time, I've just switched to GNOME.&lt;/p&gt;
&lt;p&gt;I'm afraid to say that since the KDE 4 series, I've been unable to recommend
KDE to anyone.  With KDE 4.0 to 4.3, that was due to general crashiness,
brokenness and bugs that are at the level of &lt;em&gt;embarrassing&lt;/em&gt; – when a bug is
obvious enough and significant enough that a new user would be shocked to find it and I would have a hard time explaining how I could use software that is clearly inferior to whatever they were using before (usually Windows).&lt;/p&gt;
&lt;p&gt;With KDE 4.4, most desktop instability has been ironed out, but it has been
replaced by problems that mean I can no longer stomach or risk staying with
KDE for myself, let alone recommend it to anyone else.  The final straw was
that the framework for storing PIM data (Akondai) is turning out no better
than &lt;a class="reference external" href="https://lukeplant.me.uk/blog/posts/a-plea-to-kde-developers/"&gt;I feared&lt;/a&gt; and is
‘losing’ some of my data.&lt;/p&gt;
&lt;p&gt;I found that &lt;a class="reference external" href="https://bugs.kde.org/show_bug.cgi?id=232773"&gt;some things added to the address book ‘never’
actually end up in the file they are supposed to be stored in&lt;/a&gt;.  I've added an e-mail
address for a contact, and it appears to have added fine in KAddressBook.
The data persists even across reboots etc., so it isn't ‘lost’ in one sense.
Usually, the data appears in my std.vcf after a few seconds.  In this case,
however, four days later it still hasn't appeared in std.vcf.  That counts
as close enough to ‘never’ in my book, so it is fair to say it is ‘lost’.
This has happened intermittently since KDE 4.4.1.&lt;/p&gt;
&lt;p&gt;One additional result of this is that KMail never sees that address – at the
moment it seems that it looks only in std.vcf, not Akonadi (and this is
probably the only reason I found the bug in the first place).  That's a
pain, but the more serious problem is that my data is just not where it is
supposed to be.  If I need to backup and restore, I imagine it would be
possible for that to succeed, if the Akonadi data was backed-up and restored
along with the underlying data.  But if you get that bit wrong, I can only
imagine a world of pain and subtle data corruption.  It is completely
unacceptable that my data is being stored in “my data files + completely
opaque Akonadi database” rather than just “my data files”.&lt;/p&gt;
&lt;p&gt;Another bug is that &lt;a class="reference external" href="https://bugs.kde.org/show_bug.cgi?id=232774"&gt;the Google contacts Akonadi plugin also loses data in a
serious way&lt;/a&gt;, making it far
worse than useless.  The nature of this bug makes me think that either there
is a significant bug in the Akonadi framework, or that the framework API
made it is easy to get this wrong – both of which are worrying.&lt;/p&gt;
&lt;p&gt;These bugs are on top my general concerns with the framework – it has always
been painful to work with, and the fact that it is even &lt;strong&gt;visible&lt;/strong&gt; is a
major failing – the software layer it replaced was, after all, completely
invisible, just as it should have been.&lt;/p&gt;
&lt;p&gt;From what I can tell, migration of KMail to Akonadi is going ahead at full
pace and will be mandatory soon.  My contact data is modest (500 Kb), so I
have been able to cope with moving it around and fixing some problems,
including some data loss and mistakes caused, I think, by the above bugs,
since backups are quick.  But my e-mail data is 2.5 Gb, and detecting
problems or errors is going to be massively harder.  I'm not willing to risk
my e-mail data with Akonadi, so I need a new e-mail client.&lt;/p&gt;
&lt;p&gt;It turns out that Evolution works for me.  It stores data in mbox files,
which isn't my preferred (1 file per e-mail, like maildir or MH, is nicer
for various purposes), but it is a standard format, and since my backup tool
is 'diff' based it will still cope efficiently with it.  It even integrates
with Google contacts out of the box, and the calendar app integrates with
Google calendar, while allowing me to work offline.  This is what Akonadi is
supposed to offer one day, and I wish them the best of luck with that.  But
for now I'm going to stick with a system that prioritises the safety of my
data, and that I know works.  Evolution has a few significant niggles, but I
think I can live with them.&lt;/p&gt;
&lt;p&gt;That leaves me with the choice of desktop.  Using programs from one desktop
suite generally is faster and easier and looks nicer.  I had already dropped
Konqueror for Chrome (Konqueror has fallen far too far behind these days),
and GNOME equivalents to most KDE apps work well enough – like
Empathy/Pidgin.  That tips the balance over to GNOME – and I can still use
apps like k3b for specialist work when I need them.&lt;/p&gt;
&lt;p&gt;Most of my reasons for leaving GNOME in the first place (about 7 years ago I
think) have been resolved.  GNOME apps like Nautilus and Evolution are no
longer as excuciatingly slow and bloated as they used to be (and I don't
think it is just that my computer got faster), and actually feel quite
snappy most of the time.  In some cases they definitely outperform the
equivalent KDE default app (e.g. Eye of GNOME is very fast and works very
nicely, doing 90% of what I used Gwenview for before, but much faster).
Generally GNOME is much snappier as a desktop – it takes only about 5
seconds to start after I've logged in, which is &lt;em&gt;much&lt;/em&gt; faster than KDE.&lt;/p&gt;
&lt;p&gt;So I'm using Ubuntu's GNOME desktop, and I no longer have plasma and all the
plasmoids.  To be honest, I don't think I'm missing them.  I have all the
panel applets I need, and they are well designed and work properly.
Proliferation of plasmoids is like the proliferation of apps on Apple app
store – most of them are not worth having, and having to search through to
find the ones that are is an anti-feature (not to mention that the new
horizontal applet picker in KDE 4.4, which replaced the vertical one in KDE
4.3, is just awful – I don't understand how such a major regression happened).&lt;/p&gt;
&lt;p&gt;I certainly won't shed a tear over Nepomuk/Strigi.  After &lt;strong&gt;weeks&lt;/strong&gt; of it constant disk activity as they attempted to index my files, they never seemed to do anything useful. They have been replaced by Tracker, which works very well, and very quickly, and without being a huge resource hog. It does not update immediately when I add new files, but it is fast enough to know that when I really want to find something in a real situation, it is likely to be in the index already.  And it isn't the massive resource hog that Nepomuk was.&lt;/p&gt;
&lt;p&gt;First experience with Ubuntu's GNOME has thrown up some problems.  Here are some niggles I've been able to fix/solve:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;PulseAudio - this breaks lots of things, especially games, and provides no
added benefit.  But &lt;a class="reference external" href="http://art.ubuntuforums.org/showpost.php?p=9297829&amp;amp;postcount=146"&gt;it can be removed&lt;/a&gt;.
Perhaps the Ubuntu guys will remove it in future, or make it easier to
remove.  Lots of people and programs seem to have problems with it, it's
very difficult to see what value it is adding for most people.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;To turn off desktop effects quickly (for better performance games)
- either: install fusion-icon (use "fusion-icon -n" as the command)
- or, to do it automatically for fullscreen games, set this option to true: /apps/compiz/general/screen0/options/unredirect_fullscreen_windows&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;To turn off screen locking on resume - there is setting is in gconf,
search for 'lock'.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And here are some that are still bothering me a bit:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;Reading new e-mails with keyboard only - it's a bit buggy/confusing with Evolution.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Some options are hidden away in gconf, so it's difficult to know if it is
possible to change things.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;GNOME has less configurability in general, or harder to get to it,
especially for creating new keyboard shortcuts.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Compiz doesn't always seem to obey or understand all metacity options
(e.g.  shortcut for fullscreen-ing windows), so it sometimes confusing
working out what is going on.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The GNOME file dialog boxes have improved a little bit since I was last using GNOME, but haven't begun to close the gap on KDE's far superior ones.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;But there are some niggles which are no longer there due to the switch from
KDE.  Overall, things are similar at this level.&lt;/p&gt;
&lt;p&gt;To conclude, I think the KDE developers were far too ambitious with the KDE 4 series.  The cost has been that the only supported versions of KDE are ones that you cannot recommend to anyone, and that is a critical mistake in a competitive environment.  Meanwhile, GNOME has massively improved in speed and has incrementally added features that people actually need, instead of creating large frameworks that may or may not be robust and useful one day.&lt;/p&gt;</content>
    <category term="kde" label="KDE"/>
    <category term="linux" label="Linux"/>
    <category term="rants" label="Rants"/>
  </entry>
  <entry>
    <title>Linux and calendars - bad combination...</title>
    <id>https://lukeplant.me.uk/blog/posts/linux-and-calendars-bad-combination/</id>
    <updated>2010-03-23T13:22:49Z</updated>
    <published>2010-03-23T13:22:49Z</published>
    <author>
      <name>Luke Plant</name>
    </author>
    <link rel="alternate" type="text/html" href="https://lukeplant.me.uk/blog/posts/linux-and-calendars-bad-combination/"/>
    <summary type="html">&lt;p&gt;There doesn't appear to be any way for a Linux user to get a local calendar app to inter-operate with Google or other devices.&lt;/p&gt;</summary>
    <content type="html">&lt;p&gt;So, I'd like to be able to access my sync the calendar on my computer with other devices, like my BlackBerry Curve.  This is 2010 right?&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;I already blogged the &lt;a class="reference external" href="https://lukeplant.me.uk/blog/posts/blackberry-curve-kde-pim-sync-on-kubuntu-karmic-fail/"&gt;failure to sync directly&lt;/a&gt;. Let's not go there.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;How about just syncing KOrganizer with Google, and syncing the BlackBerry with Google?  I already have some calendars on Google, and that works fine.  But now for my main calender:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;I tried GCalDaemon, but found that it &lt;a class="reference external" href="https://sourceforge.net/tracker/?func=detail&amp;amp;aid=2844153&amp;amp;group_id=184382&amp;amp;atid=909032"&gt;ignores/deletes all recurring events on your calendar&lt;/a&gt;.  Which is pretty evil.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;There is Akonadi... Given how hopelessly buggy Akonadi is for syncing contacts to Google (like, if Google has more than one e-mail for a contact, none of them are transferred, and worse), I'm not very hopeful about this (and I'm using most recent KDE 4.4.1).  But I'll try anyway...&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The whole experience is fraught with bugs and confusion.  You click 'Add' and things aren't added, you click 'Remove' and they don't disappear, or only after some indefinite period of time (I've waited 30 seconds, is it just broken or should I carry on waiting?).  You close the Akonadi configuration and open it again, or restart the server, and items have appeared, and other things that you didn't ask for.  A lot seems to go on asynchronously, which might be a good idea, but you get the impression you are attempting to communicate with a forgetful, deaf, sleepy, indecisive, incompetent idiot.  I have eventually managed to add a Google calendar resource, but it says "Failed getting last updated event", and nothing appears on my calendar.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;OK, let's try Evolution calendar.  At first it didn't work, then it seemed to work a bit better, but trying to modify events returns "Unknown error", and now it refuses to show the calendar at all.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;OK, let's just try using Google calendar, importing all my existing calendar data, ditching any hope of using a local calendar app.  But Google doesn't like my calendar file - "Failed to import events: Processing error during upload."&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Epic fail.  Bad day.&lt;/p&gt;
&lt;hr class="docutils"&gt;
&lt;p&gt;Update: in the last case, I discovered after some investigation that Google doesn't like the 'VTIMEZONE' sections in my calendar file.  Removing them allows the import to succeed (although it still produces an error message, and I'm guessing it might have lost some time information on summer events though, not sure).&lt;/p&gt;</content>
    <category term="kde" label="KDE"/>
    <category term="linux" label="Linux"/>
    <category term="rants" label="Rants"/>
  </entry>
  <entry>
    <title>Blackberry Curve ↔ KDE-PIM sync on Kubuntu Karmic. FAIL</title>
    <id>https://lukeplant.me.uk/blog/posts/blackberry-curve-kde-pim-sync-on-kubuntu-karmic-fail/</id>
    <updated>2010-02-11T17:07:58Z</updated>
    <published>2010-02-11T17:07:58Z</published>
    <author>
      <name>Luke Plant</name>
    </author>
    <link rel="alternate" type="text/html" href="https://lukeplant.me.uk/blog/posts/blackberry-curve-kde-pim-sync-on-kubuntu-karmic-fail/"/>
    <summary type="html">&lt;p&gt;Complete fail for KDE-PIM/Linux/msynctool and Blackberry Curve.&lt;/p&gt;</summary>
    <content type="html">&lt;p&gt;For the sake of anyone else who might want to know about this in advance, I'll blog my failure.&lt;/p&gt;
&lt;p&gt;I tried with Kubuntu Karmic, and the following steps:&lt;/p&gt;
&lt;ol class="arabic"&gt;
&lt;li&gt;&lt;p&gt;Install the necessary packages:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code bash"&gt;&lt;a id="rest_code_ae2768d6573f4cf5b2dbe6ce2f8132e6-1" name="rest_code_ae2768d6573f4cf5b2dbe6ce2f8132e6-1" href="https://lukeplant.me.uk/blog/posts/blackberry-curve-kde-pim-sync-on-kubuntu-karmic-fail/#rest_code_ae2768d6573f4cf5b2dbe6ce2f8132e6-1"&gt;&lt;/a&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;aptitude&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;opensync-plugin-kdepim&lt;span class="w"&gt; &lt;/span&gt;opensyncutils&lt;span class="w"&gt; &lt;/span&gt;barrybackup-gui&lt;span class="w"&gt; &lt;/span&gt;barry-util&lt;span class="w"&gt; &lt;/span&gt;opensync-plugin-barry
&lt;/pre&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Plug in the Blackberry, and choose "Mass storage" mode on the Blackberry.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Set up permissions to allow a non-root user to access the device.  I added the file &lt;code class="docutils literal"&gt;&lt;span class="pre"&gt;/etc/udev/rules.d/040-devices.rules&lt;/span&gt;&lt;/code&gt;, with the following contents:&lt;/p&gt;
&lt;pre class="literal-block"&gt;BUS=="usb", SYSFS{idVendor}=="0fca", SYSFS{idProduct}=="8004", GROUP="admin"&lt;/pre&gt;
&lt;p&gt;The above line gives permissions to all users of group 'admin', which includes my normal user.  The numbers "0fca" and "8004" are device numbers obtainable from &lt;code class="docutils literal"&gt;lsusb&lt;/code&gt;:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code bash"&gt;&lt;a id="rest_code_f67083c6749d43b3ac2bc823fae626e3-1" name="rest_code_f67083c6749d43b3ac2bc823fae626e3-1" href="https://lukeplant.me.uk/blog/posts/blackberry-curve-kde-pim-sync-on-kubuntu-karmic-fail/#rest_code_f67083c6749d43b3ac2bc823fae626e3-1"&gt;&lt;/a&gt;lsusb&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;grep&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Research In Motion"&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Result:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code bash"&gt;&lt;a id="rest_code_004312a73e51419baef69f0f3b661d51-1" name="rest_code_004312a73e51419baef69f0f3b661d51-1" href="https://lukeplant.me.uk/blog/posts/blackberry-curve-kde-pim-sync-on-kubuntu-karmic-fail/#rest_code_004312a73e51419baef69f0f3b661d51-1"&gt;&lt;/a&gt;Bus&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;002&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Device&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;008&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;ID&lt;span class="w"&gt; &lt;/span&gt;0fca:8004&lt;span class="w"&gt; &lt;/span&gt;Research&lt;span class="w"&gt; &lt;/span&gt;In&lt;span class="w"&gt; &lt;/span&gt;Motion,&lt;span class="w"&gt; &lt;/span&gt;Ltd.
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;You will need to unplug the Blackberry and plug back in after this step.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Check you can access the Blackberry.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code bash"&gt;&lt;a id="rest_code_74c5000904f3469ab7245bb256611081-1" name="rest_code_74c5000904f3469ab7245bb256611081-1" href="https://lukeplant.me.uk/blog/posts/blackberry-curve-kde-pim-sync-on-kubuntu-karmic-fail/#rest_code_74c5000904f3469ab7245bb256611081-1"&gt;&lt;/a&gt;btool&lt;span class="w"&gt; &lt;/span&gt;-t
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This should list a series of databases on the Blackberry&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Back up the current contents:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code bash"&gt;&lt;a id="rest_code_1cbd32a3cbf640b5b9738790804ff4f6-1" name="rest_code_1cbd32a3cbf640b5b9738790804ff4f6-1" href="https://lukeplant.me.uk/blog/posts/blackberry-curve-kde-pim-sync-on-kubuntu-karmic-fail/#rest_code_1cbd32a3cbf640b5b9738790804ff4f6-1"&gt;&lt;/a&gt;barrybackup
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Note the pin for later, and follow the prompts to backup the Blackberry data.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Back up your KDE-PIM data, in case of any corruption, duplicate elements etc. (It happened to me!).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create a msynctool configuration for doing the synchronisation.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code bash"&gt;&lt;a id="rest_code_990c598162bb4575b85fb72458cd0915-1" name="rest_code_990c598162bb4575b85fb72458cd0915-1" href="https://lukeplant.me.uk/blog/posts/blackberry-curve-kde-pim-sync-on-kubuntu-karmic-fail/#rest_code_990c598162bb4575b85fb72458cd0915-1"&gt;&lt;/a&gt;msynctool&lt;span class="w"&gt; &lt;/span&gt;--addgroup&lt;span class="w"&gt; &lt;/span&gt;Blackberry
&lt;a id="rest_code_990c598162bb4575b85fb72458cd0915-2" name="rest_code_990c598162bb4575b85fb72458cd0915-2" href="https://lukeplant.me.uk/blog/posts/blackberry-curve-kde-pim-sync-on-kubuntu-karmic-fail/#rest_code_990c598162bb4575b85fb72458cd0915-2"&gt;&lt;/a&gt;msynctool&lt;span class="w"&gt; &lt;/span&gt;--addmember&lt;span class="w"&gt; &lt;/span&gt;Blackberry&lt;span class="w"&gt; &lt;/span&gt;barry-sync
&lt;a id="rest_code_990c598162bb4575b85fb72458cd0915-3" name="rest_code_990c598162bb4575b85fb72458cd0915-3" href="https://lukeplant.me.uk/blog/posts/blackberry-curve-kde-pim-sync-on-kubuntu-karmic-fail/#rest_code_990c598162bb4575b85fb72458cd0915-3"&gt;&lt;/a&gt;msynctool&lt;span class="w"&gt; &lt;/span&gt;--addmember&lt;span class="w"&gt; &lt;/span&gt;Blackberry&lt;span class="w"&gt; &lt;/span&gt;kdepim-sync
&lt;a id="rest_code_990c598162bb4575b85fb72458cd0915-4" name="rest_code_990c598162bb4575b85fb72458cd0915-4" href="https://lukeplant.me.uk/blog/posts/blackberry-curve-kde-pim-sync-on-kubuntu-karmic-fail/#rest_code_990c598162bb4575b85fb72458cd0915-4"&gt;&lt;/a&gt;msynctool&lt;span class="w"&gt; &lt;/span&gt;--showgroup&lt;span class="w"&gt; &lt;/span&gt;Blackberry
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The final command should show the first member as missing configuration. Do the following&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code bash"&gt;&lt;a id="rest_code_c2b503d18be6484983df4ef8d49d3cc6-1" name="rest_code_c2b503d18be6484983df4ef8d49d3cc6-1" href="https://lukeplant.me.uk/blog/posts/blackberry-curve-kde-pim-sync-on-kubuntu-karmic-fail/#rest_code_c2b503d18be6484983df4ef8d49d3cc6-1"&gt;&lt;/a&gt;msynctool&lt;span class="w"&gt; &lt;/span&gt;--configure&lt;span class="w"&gt; &lt;/span&gt;Blackberry&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;and insert your pin in the relevant place.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Moment of truth.  Close KOrganizer and KMail, then:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code bash"&gt;&lt;a id="rest_code_ab30f6b0ac424b4e81acd7244d054abf-1" name="rest_code_ab30f6b0ac424b4e81acd7244d054abf-1" href="https://lukeplant.me.uk/blog/posts/blackberry-curve-kde-pim-sync-on-kubuntu-karmic-fail/#rest_code_ab30f6b0ac424b4e81acd7244d054abf-1"&gt;&lt;/a&gt;msynctool&lt;span class="w"&gt; &lt;/span&gt;--sync&lt;span class="w"&gt; &lt;/span&gt;Blackberry
&lt;/pre&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I came across the following major bugs:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;Syncing never completes, and I have to press Ctrl-C to abort.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;When I try to sync a second/third time, I end up with lots of duplicates on my computer, caused by items from the Blackberry being copied back.  I'm not sure if they are to do with the unclean abort, or the following symptoms:
* 'All day events'.  A duplicate appears with the start time set to '0:00'
* Daylight savings problems - for summer events, a duplicate appears 1 hour different from the original
* Items from my Google calendar (which is a read only calendar) got copied back to my main calendar.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Each time I attempt to sync, duplicate events and contacts build up on the Blackberry as well.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Using barrybackup to restore to a clean state with the backup made previously fails with lots of errors.  By removing some items in &lt;code class="docutils literal"&gt;&lt;span class="pre"&gt;~/.barry/backup/&amp;lt;pin&amp;gt;/config&lt;/span&gt;&lt;/code&gt;, I've got it to apparently succeed, but the contacts and calendar on the Blackberry are not cleared out, which is the point of the exercise.
* There is a way to clear calendar/contacts on the Blackberry.  Go to Calendar -&amp;gt; Menu -&amp;gt; Options.  Type RSET.  The calendar will be cleared (though it says nothing).  Repeat for contacts.  This time you will get a prompt about clearing.  Clearing out the msynctool database is also a good idea to keep further attempts  clean and fast.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In the end, a one-time, one-way sync is all that I have been able to achieve.  That is quite disappointing, since none of the web pages I found before deciding on a Blackberry mentioned any problems like these.&lt;/p&gt;
&lt;p&gt;I tried upgrading all the barry packages from 0.14 to 0.16, but got lots more errors - when trying to send data to the Blackberry I just got "Timeout in usb_bulk_read" blah blah and do data was actually sent.&lt;/p&gt;
&lt;p&gt;Sources:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;&lt;a class="reference external" href="http://forums.debian.net/viewtopic.php?t=20424"&gt;Contacts, sms messages and files from and to mobile phone&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a class="reference external" href="http://www.linux.com/news/embedded-mobile/mids/8210-syncing-your-blackberry-on-linux"&gt;Syncing your BlackBerry on Linux&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;</content>
    <category term="kde" label="KDE"/>
    <category term="linux" label="Linux"/>
  </entry>
</feed>
