Luke Plant's home page (Posts about KDE)https://lukeplant.me.uk/blog/categories/kde.xml2023-11-11T20:15:30ZLuke PlantNikolaKTimeTracker replacement - TimeCulthttps://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/2012-02-24T17:57:32Z2012-02-24T17:57:32ZLuke Plant<p>TimeCult works well, and I wrote a script for converting KTimeTracker files.</p><p>For a long time I haven't been able to find a decent replacement or alternative to KTimeTracker. But I've now succeeded: <a class="reference external" href="http://timecult.wordpress.com/">TimeCult</a>.</p>
<p>It is <a class="reference external" href="https://github.com/dyadix/TimeCult/issues/1">currently lacking an installer for Linux</a>, but it can be <a class="reference external" href="http://xmemory.tompium.com/2011/10/get-timecult-running-on-linux.html">made to work with Linux easily</a>.</p>
<p>I also found that it uses a very easy-to-deciper XML format, and, with the help of <a class="reference external" href="http://pypi.python.org/pypi/vobject">vobject</a>, the KTimeTracker ical files are only slightly harder to figure out, so I created a Python <a class="reference external" href="https://gist.github.com/1901236">script</a> that will do the conversion.</p>
<p>Use the script like this:</p>
<pre class="literal-block">./ics_to_timecult.py ~/.kde/share/apps/ktimetracker/ktimetracker.ics > out.tmt</pre>
<p>It's here for reference - dependencies are vobject and elementtree:</p>
<div class="code"><pre class="code python"><a id="rest_code_c1bb69f5878a42a8876517fab6802104-1" name="rest_code_c1bb69f5878a42a8876517fab6802104-1" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-1"></a><span class="ch">#!/usr/bin/env python</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-2" name="rest_code_c1bb69f5878a42a8876517fab6802104-2" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-2"></a><span class="c1"># Quick and dirty script to convert ktimetracker.ics files</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-3" name="rest_code_c1bb69f5878a42a8876517fab6802104-3" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-3"></a><span class="c1"># into TimeCult files.</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-4" name="rest_code_c1bb69f5878a42a8876517fab6802104-4" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-4"></a>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-5" name="rest_code_c1bb69f5878a42a8876517fab6802104-5" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-5"></a><span class="kn">import</span> <span class="nn">os.path</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-6" name="rest_code_c1bb69f5878a42a8876517fab6802104-6" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-6"></a><span class="kn">import</span> <span class="nn">sys</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-7" name="rest_code_c1bb69f5878a42a8876517fab6802104-7" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-7"></a><span class="kn">import</span> <span class="nn">time</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-8" name="rest_code_c1bb69f5878a42a8876517fab6802104-8" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-8"></a><span class="kn">import</span> <span class="nn">uuid</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-9" name="rest_code_c1bb69f5878a42a8876517fab6802104-9" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-9"></a>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-10" name="rest_code_c1bb69f5878a42a8876517fab6802104-10" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-10"></a><span class="kn">import</span> <span class="nn">elementtree.ElementTree</span> <span class="k">as</span> <span class="nn">ET</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-11" name="rest_code_c1bb69f5878a42a8876517fab6802104-11" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-11"></a><span class="kn">import</span> <span class="nn">vobject</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-12" name="rest_code_c1bb69f5878a42a8876517fab6802104-12" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-12"></a>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-13" name="rest_code_c1bb69f5878a42a8876517fab6802104-13" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-13"></a>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-14" name="rest_code_c1bb69f5878a42a8876517fab6802104-14" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-14"></a><span class="c1"># Structures to store the tree of data. Use native Python data types, and</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-15" name="rest_code_c1bb69f5878a42a8876517fab6802104-15" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-15"></a><span class="c1"># convert to what TimeCult expects when we 'render'</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-16" name="rest_code_c1bb69f5878a42a8876517fab6802104-16" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-16"></a>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-17" name="rest_code_c1bb69f5878a42a8876517fab6802104-17" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-17"></a><span class="k">class</span> <span class="nc">Struct</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-18" name="rest_code_c1bb69f5878a42a8876517fab6802104-18" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-18"></a> <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-19" name="rest_code_c1bb69f5878a42a8876517fab6802104-19" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-19"></a> <span class="bp">self</span><span class="o">.</span><span class="vm">__dict__</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">kwargs</span><span class="p">)</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-20" name="rest_code_c1bb69f5878a42a8876517fab6802104-20" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-20"></a>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-21" name="rest_code_c1bb69f5878a42a8876517fab6802104-21" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-21"></a>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-22" name="rest_code_c1bb69f5878a42a8876517fab6802104-22" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-22"></a><span class="k">class</span> <span class="nc">TimeCult</span><span class="p">(</span><span class="n">Struct</span><span class="p">):</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-23" name="rest_code_c1bb69f5878a42a8876517fab6802104-23" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-23"></a> <span class="c1"># <timecult></span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-24" name="rest_code_c1bb69f5878a42a8876517fab6802104-24" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-24"></a> <span class="c1"># Eventual attributes:</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-25" name="rest_code_c1bb69f5878a42a8876517fab6802104-25" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-25"></a> <span class="c1"># name</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-26" name="rest_code_c1bb69f5878a42a8876517fab6802104-26" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-26"></a> <span class="c1"># projectTree</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-27" name="rest_code_c1bb69f5878a42a8876517fab6802104-27" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-27"></a> <span class="c1"># timeLog</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-28" name="rest_code_c1bb69f5878a42a8876517fab6802104-28" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-28"></a>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-29" name="rest_code_c1bb69f5878a42a8876517fab6802104-29" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-29"></a> <span class="k">def</span> <span class="nf">toXML</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-30" name="rest_code_c1bb69f5878a42a8876517fab6802104-30" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-30"></a> <span class="n">root</span> <span class="o">=</span> <span class="n">ET</span><span class="o">.</span><span class="n">XML</span><span class="p">(</span><span class="s1">'<timecult appVersion="0.12" fileVersion="10" />'</span><span class="p">)</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-31" name="rest_code_c1bb69f5878a42a8876517fab6802104-31" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-31"></a> <span class="n">root</span><span class="o">.</span><span class="n">attrib</span><span class="p">[</span><span class="s1">'uuid'</span><span class="p">]</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="n">uuid</span><span class="o">.</span><span class="n">uuid1</span><span class="p">())</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-32" name="rest_code_c1bb69f5878a42a8876517fab6802104-32" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-32"></a> <span class="n">root</span><span class="o">.</span><span class="n">attrib</span><span class="p">[</span><span class="s1">'name'</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-33" name="rest_code_c1bb69f5878a42a8876517fab6802104-33" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-33"></a> <span class="n">pt</span> <span class="o">=</span> <span class="n">ET</span><span class="o">.</span><span class="n">Element</span><span class="p">(</span><span class="s1">'projectTree'</span><span class="p">)</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-34" name="rest_code_c1bb69f5878a42a8876517fab6802104-34" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-34"></a> <span class="k">for</span> <span class="n">n</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">projectTree</span><span class="p">:</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-35" name="rest_code_c1bb69f5878a42a8876517fab6802104-35" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-35"></a> <span class="n">pt</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">n</span><span class="o">.</span><span class="n">toXML</span><span class="p">())</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-36" name="rest_code_c1bb69f5878a42a8876517fab6802104-36" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-36"></a> <span class="n">root</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">pt</span><span class="p">)</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-37" name="rest_code_c1bb69f5878a42a8876517fab6802104-37" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-37"></a> <span class="n">tl</span> <span class="o">=</span> <span class="n">ET</span><span class="o">.</span><span class="n">Element</span><span class="p">(</span><span class="s1">'timeLog'</span><span class="p">)</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-38" name="rest_code_c1bb69f5878a42a8876517fab6802104-38" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-38"></a> <span class="k">for</span> <span class="n">tr</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">timeLog</span><span class="p">:</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-39" name="rest_code_c1bb69f5878a42a8876517fab6802104-39" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-39"></a> <span class="n">tl</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">tr</span><span class="o">.</span><span class="n">toXML</span><span class="p">())</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-40" name="rest_code_c1bb69f5878a42a8876517fab6802104-40" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-40"></a> <span class="n">root</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">tl</span><span class="p">)</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-41" name="rest_code_c1bb69f5878a42a8876517fab6802104-41" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-41"></a> <span class="k">return</span> <span class="n">root</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-42" name="rest_code_c1bb69f5878a42a8876517fab6802104-42" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-42"></a>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-43" name="rest_code_c1bb69f5878a42a8876517fab6802104-43" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-43"></a><span class="k">class</span> <span class="nc">Node</span><span class="p">(</span><span class="n">Struct</span><span class="p">):</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-44" name="rest_code_c1bb69f5878a42a8876517fab6802104-44" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-44"></a> <span class="c1"># <project> and <task></span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-45" name="rest_code_c1bb69f5878a42a8876517fab6802104-45" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-45"></a> <span class="c1"># Eventually will have these attributes:</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-46" name="rest_code_c1bb69f5878a42a8876517fab6802104-46" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-46"></a> <span class="c1"># vtodo</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-47" name="rest_code_c1bb69f5878a42a8876517fab6802104-47" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-47"></a> <span class="c1"># summary</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-48" name="rest_code_c1bb69f5878a42a8876517fab6802104-48" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-48"></a> <span class="c1"># uid</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-49" name="rest_code_c1bb69f5878a42a8876517fab6802104-49" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-49"></a> <span class="c1"># created</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-50" name="rest_code_c1bb69f5878a42a8876517fab6802104-50" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-50"></a> <span class="c1"># parent</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-51" name="rest_code_c1bb69f5878a42a8876517fab6802104-51" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-51"></a> <span class="c1"># children</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-52" name="rest_code_c1bb69f5878a42a8876517fab6802104-52" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-52"></a> <span class="c1"># type = "project|task"</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-53" name="rest_code_c1bb69f5878a42a8876517fab6802104-53" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-53"></a> <span class="c1"># finished</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-54" name="rest_code_c1bb69f5878a42a8876517fab6802104-54" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-54"></a> <span class="k">def</span> <span class="fm">__repr__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-55" name="rest_code_c1bb69f5878a42a8876517fab6802104-55" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-55"></a> <span class="k">return</span> <span class="s2">"<Node: uid=</span><span class="si">%s</span><span class="s2"> summary=</span><span class="si">%r</span><span class="s2">, parent=</span><span class="si">%r</span><span class="s2">>"</span> <span class="o">%</span> <span class="p">(</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-56" name="rest_code_c1bb69f5878a42a8876517fab6802104-56" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-56"></a> <span class="bp">self</span><span class="o">.</span><span class="n">uid</span><span class="p">,</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-57" name="rest_code_c1bb69f5878a42a8876517fab6802104-57" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-57"></a> <span class="bp">self</span><span class="o">.</span><span class="n">summary</span><span class="p">,</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-58" name="rest_code_c1bb69f5878a42a8876517fab6802104-58" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-58"></a> <span class="bp">self</span><span class="o">.</span><span class="n">parent</span><span class="o">.</span><span class="n">summary</span> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">parent</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span> <span class="k">else</span> <span class="kc">None</span><span class="p">)</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-59" name="rest_code_c1bb69f5878a42a8876517fab6802104-59" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-59"></a>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-60" name="rest_code_c1bb69f5878a42a8876517fab6802104-60" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-60"></a> <span class="k">def</span> <span class="nf">toXML</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-61" name="rest_code_c1bb69f5878a42a8876517fab6802104-61" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-61"></a> <span class="n">e</span> <span class="o">=</span> <span class="n">ET</span><span class="o">.</span><span class="n">Element</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">type</span><span class="p">)</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-62" name="rest_code_c1bb69f5878a42a8876517fab6802104-62" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-62"></a> <span class="n">e</span><span class="o">.</span><span class="n">attrib</span><span class="p">[</span><span class="s1">'id'</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">id</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-63" name="rest_code_c1bb69f5878a42a8876517fab6802104-63" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-63"></a> <span class="n">e</span><span class="o">.</span><span class="n">attrib</span><span class="p">[</span><span class="s1">'name'</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">summary</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-64" name="rest_code_c1bb69f5878a42a8876517fab6802104-64" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-64"></a> <span class="n">e</span><span class="o">.</span><span class="n">attrib</span><span class="p">[</span><span class="s1">'created'</span><span class="p">]</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="nb">int</span><span class="p">(</span><span class="n">time</span><span class="o">.</span><span class="n">mktime</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">created</span><span class="o">.</span><span class="n">timetuple</span><span class="p">())</span> <span class="o">*</span> <span class="mi">1000</span><span class="p">))</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-65" name="rest_code_c1bb69f5878a42a8876517fab6802104-65" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-65"></a> <span class="k">if</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">type</span> <span class="o">==</span> <span class="s2">"task"</span><span class="p">):</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-66" name="rest_code_c1bb69f5878a42a8876517fab6802104-66" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-66"></a> <span class="k">assert</span> <span class="nb">len</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">children</span><span class="p">)</span> <span class="o">==</span> <span class="mi">0</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-67" name="rest_code_c1bb69f5878a42a8876517fab6802104-67" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-67"></a> <span class="n">e</span><span class="o">.</span><span class="n">attrib</span><span class="p">[</span><span class="s1">'status'</span><span class="p">]</span> <span class="o">=</span> <span class="s1">'finished'</span> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">finished</span> <span class="k">else</span> <span class="s1">'inProgress'</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-68" name="rest_code_c1bb69f5878a42a8876517fab6802104-68" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-68"></a> <span class="k">else</span><span class="p">:</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-69" name="rest_code_c1bb69f5878a42a8876517fab6802104-69" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-69"></a> <span class="k">for</span> <span class="n">c</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">children</span><span class="p">:</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-70" name="rest_code_c1bb69f5878a42a8876517fab6802104-70" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-70"></a> <span class="n">e</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">c</span><span class="o">.</span><span class="n">toXML</span><span class="p">())</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-71" name="rest_code_c1bb69f5878a42a8876517fab6802104-71" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-71"></a> <span class="k">return</span> <span class="n">e</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-72" name="rest_code_c1bb69f5878a42a8876517fab6802104-72" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-72"></a>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-73" name="rest_code_c1bb69f5878a42a8876517fab6802104-73" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-73"></a><span class="k">class</span> <span class="nc">TimeRec</span><span class="p">(</span><span class="n">Struct</span><span class="p">):</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-74" name="rest_code_c1bb69f5878a42a8876517fab6802104-74" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-74"></a> <span class="c1"># <timerec></span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-75" name="rest_code_c1bb69f5878a42a8876517fab6802104-75" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-75"></a> <span class="c1"># Eventual attributes:</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-76" name="rest_code_c1bb69f5878a42a8876517fab6802104-76" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-76"></a> <span class="c1"># startTime # datetime</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-77" name="rest_code_c1bb69f5878a42a8876517fab6802104-77" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-77"></a> <span class="c1"># duration # seconds</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-78" name="rest_code_c1bb69f5878a42a8876517fab6802104-78" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-78"></a> <span class="c1"># task # Node</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-79" name="rest_code_c1bb69f5878a42a8876517fab6802104-79" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-79"></a> <span class="k">def</span> <span class="nf">toXML</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-80" name="rest_code_c1bb69f5878a42a8876517fab6802104-80" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-80"></a> <span class="n">e</span> <span class="o">=</span> <span class="n">ET</span><span class="o">.</span><span class="n">Element</span><span class="p">(</span><span class="s2">"timeRec"</span><span class="p">)</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-81" name="rest_code_c1bb69f5878a42a8876517fab6802104-81" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-81"></a> <span class="n">e</span><span class="o">.</span><span class="n">attrib</span><span class="p">[</span><span class="s1">'taskId'</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">taskId</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-82" name="rest_code_c1bb69f5878a42a8876517fab6802104-82" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-82"></a> <span class="n">e</span><span class="o">.</span><span class="n">attrib</span><span class="p">[</span><span class="s1">'startTime'</span><span class="p">]</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="nb">int</span><span class="p">(</span><span class="n">time</span><span class="o">.</span><span class="n">mktime</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">startTime</span><span class="o">.</span><span class="n">timetuple</span><span class="p">())</span> <span class="o">*</span> <span class="mi">1000</span><span class="p">))</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-83" name="rest_code_c1bb69f5878a42a8876517fab6802104-83" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-83"></a> <span class="n">e</span><span class="o">.</span><span class="n">attrib</span><span class="p">[</span><span class="s1">'duration'</span><span class="p">]</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="nb">int</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">duration</span> <span class="o">*</span> <span class="mi">1000</span><span class="p">))</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-84" name="rest_code_c1bb69f5878a42a8876517fab6802104-84" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-84"></a> <span class="n">e</span><span class="o">.</span><span class="n">attrib</span><span class="p">[</span><span class="s1">'notes'</span><span class="p">]</span> <span class="o">=</span> <span class="s2">""</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-85" name="rest_code_c1bb69f5878a42a8876517fab6802104-85" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-85"></a> <span class="k">return</span> <span class="n">e</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-86" name="rest_code_c1bb69f5878a42a8876517fab6802104-86" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-86"></a>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-87" name="rest_code_c1bb69f5878a42a8876517fab6802104-87" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-87"></a><span class="k">def</span> <span class="nf">convert</span><span class="p">(</span><span class="n">filename</span><span class="p">):</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-88" name="rest_code_c1bb69f5878a42a8876517fab6802104-88" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-88"></a> <span class="n">f</span> <span class="o">=</span> <span class="n">vobject</span><span class="o">.</span><span class="n">readOne</span><span class="p">(</span><span class="n">file</span><span class="p">(</span><span class="n">filename</span><span class="p">)</span><span class="o">.</span><span class="n">read</span><span class="p">())</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-89" name="rest_code_c1bb69f5878a42a8876517fab6802104-89" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-89"></a>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-90" name="rest_code_c1bb69f5878a42a8876517fab6802104-90" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-90"></a> <span class="c1"># First parse Todos</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-91" name="rest_code_c1bb69f5878a42a8876517fab6802104-91" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-91"></a> <span class="n">nodes</span> <span class="o">=</span> <span class="p">{}</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-92" name="rest_code_c1bb69f5878a42a8876517fab6802104-92" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-92"></a> <span class="k">for</span> <span class="n">vtodo</span> <span class="ow">in</span> <span class="n">f</span><span class="o">.</span><span class="n">vtodo_list</span><span class="p">:</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-93" name="rest_code_c1bb69f5878a42a8876517fab6802104-93" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-93"></a> <span class="n">n</span> <span class="o">=</span> <span class="n">Node</span><span class="p">(</span><span class="n">vtodo</span> <span class="o">=</span> <span class="n">vtodo</span><span class="p">,</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-94" name="rest_code_c1bb69f5878a42a8876517fab6802104-94" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-94"></a> <span class="n">uid</span><span class="o">=</span><span class="n">vtodo</span><span class="o">.</span><span class="n">uid</span><span class="o">.</span><span class="n">value</span><span class="p">,</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-95" name="rest_code_c1bb69f5878a42a8876517fab6802104-95" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-95"></a> <span class="n">summary</span><span class="o">=</span><span class="n">vtodo</span><span class="o">.</span><span class="n">summary</span><span class="o">.</span><span class="n">value</span><span class="p">,</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-96" name="rest_code_c1bb69f5878a42a8876517fab6802104-96" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-96"></a> <span class="n">created</span><span class="o">=</span><span class="n">vtodo</span><span class="o">.</span><span class="n">created</span><span class="o">.</span><span class="n">value</span><span class="p">,</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-97" name="rest_code_c1bb69f5878a42a8876517fab6802104-97" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-97"></a> <span class="n">finished</span><span class="o">=</span><span class="n">vtodo</span><span class="o">.</span><span class="n">contents</span><span class="p">[</span><span class="s1">'percent-complete'</span><span class="p">][</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">value</span> <span class="o">==</span> <span class="s2">"100"</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-98" name="rest_code_c1bb69f5878a42a8876517fab6802104-98" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-98"></a> <span class="p">)</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-99" name="rest_code_c1bb69f5878a42a8876517fab6802104-99" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-99"></a> <span class="n">nodes</span><span class="p">[</span><span class="n">n</span><span class="o">.</span><span class="n">uid</span><span class="p">]</span> <span class="o">=</span> <span class="n">n</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-100" name="rest_code_c1bb69f5878a42a8876517fab6802104-100" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-100"></a>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-101" name="rest_code_c1bb69f5878a42a8876517fab6802104-101" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-101"></a> <span class="n">children</span> <span class="o">=</span> <span class="p">{}</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-102" name="rest_code_c1bb69f5878a42a8876517fab6802104-102" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-102"></a> <span class="k">for</span> <span class="n">uid</span><span class="p">,</span> <span class="n">node</span> <span class="ow">in</span> <span class="n">nodes</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-103" name="rest_code_c1bb69f5878a42a8876517fab6802104-103" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-103"></a> <span class="n">vtodo</span> <span class="o">=</span> <span class="n">node</span><span class="o">.</span><span class="n">vtodo</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-104" name="rest_code_c1bb69f5878a42a8876517fab6802104-104" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-104"></a> <span class="k">try</span><span class="p">:</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-105" name="rest_code_c1bb69f5878a42a8876517fab6802104-105" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-105"></a> <span class="n">related_uid</span> <span class="o">=</span> <span class="n">vtodo</span><span class="o">.</span><span class="n">contents</span><span class="p">[</span><span class="s1">'related-to'</span><span class="p">][</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">value</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-106" name="rest_code_c1bb69f5878a42a8876517fab6802104-106" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-106"></a> <span class="n">node</span><span class="o">.</span><span class="n">parent</span> <span class="o">=</span> <span class="n">nodes</span><span class="p">[</span><span class="n">related_uid</span><span class="p">]</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-107" name="rest_code_c1bb69f5878a42a8876517fab6802104-107" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-107"></a> <span class="n">children</span><span class="o">.</span><span class="n">setdefault</span><span class="p">(</span><span class="n">related_uid</span><span class="p">,</span> <span class="p">[])</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">node</span><span class="p">)</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-108" name="rest_code_c1bb69f5878a42a8876517fab6802104-108" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-108"></a> <span class="k">except</span> <span class="ne">KeyError</span><span class="p">:</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-109" name="rest_code_c1bb69f5878a42a8876517fab6802104-109" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-109"></a> <span class="n">node</span><span class="o">.</span><span class="n">parent</span> <span class="o">=</span> <span class="kc">None</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-110" name="rest_code_c1bb69f5878a42a8876517fab6802104-110" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-110"></a>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-111" name="rest_code_c1bb69f5878a42a8876517fab6802104-111" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-111"></a> <span class="k">for</span> <span class="n">uid</span><span class="p">,</span> <span class="n">node</span> <span class="ow">in</span> <span class="n">nodes</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-112" name="rest_code_c1bb69f5878a42a8876517fab6802104-112" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-112"></a> <span class="n">node</span><span class="o">.</span><span class="n">children</span> <span class="o">=</span> <span class="n">children</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">uid</span><span class="p">,</span> <span class="p">[])</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-113" name="rest_code_c1bb69f5878a42a8876517fab6802104-113" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-113"></a> <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">node</span><span class="o">.</span><span class="n">children</span><span class="p">)</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-114" name="rest_code_c1bb69f5878a42a8876517fab6802104-114" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-114"></a> <span class="n">node</span><span class="o">.</span><span class="n">type</span> <span class="o">=</span> <span class="s2">"task"</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-115" name="rest_code_c1bb69f5878a42a8876517fab6802104-115" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-115"></a> <span class="k">else</span><span class="p">:</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-116" name="rest_code_c1bb69f5878a42a8876517fab6802104-116" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-116"></a> <span class="n">node</span><span class="o">.</span><span class="n">type</span> <span class="o">=</span> <span class="s2">"project"</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-117" name="rest_code_c1bb69f5878a42a8876517fab6802104-117" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-117"></a>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-118" name="rest_code_c1bb69f5878a42a8876517fab6802104-118" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-118"></a>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-119" name="rest_code_c1bb69f5878a42a8876517fab6802104-119" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-119"></a>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-120" name="rest_code_c1bb69f5878a42a8876517fab6802104-120" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-120"></a> <span class="n">autouid</span> <span class="o">=</span> <span class="mi">0</span> <span class="c1"># For newly created Tasks</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-121" name="rest_code_c1bb69f5878a42a8876517fab6802104-121" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-121"></a>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-122" name="rest_code_c1bb69f5878a42a8876517fab6802104-122" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-122"></a> <span class="c1"># Now find the time information in the ICS file</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-123" name="rest_code_c1bb69f5878a42a8876517fab6802104-123" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-123"></a> <span class="n">time_log</span> <span class="o">=</span> <span class="p">[]</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-124" name="rest_code_c1bb69f5878a42a8876517fab6802104-124" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-124"></a> <span class="k">for</span> <span class="n">vevent</span> <span class="ow">in</span> <span class="n">f</span><span class="o">.</span><span class="n">vevent_list</span><span class="p">:</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-125" name="rest_code_c1bb69f5878a42a8876517fab6802104-125" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-125"></a> <span class="n">related_uid</span> <span class="o">=</span> <span class="n">vevent</span><span class="o">.</span><span class="n">contents</span><span class="p">[</span><span class="s1">'related-to'</span><span class="p">][</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">value</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-126" name="rest_code_c1bb69f5878a42a8876517fab6802104-126" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-126"></a> <span class="n">task</span> <span class="o">=</span> <span class="n">nodes</span><span class="p">[</span><span class="n">related_uid</span><span class="p">]</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-127" name="rest_code_c1bb69f5878a42a8876517fab6802104-127" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-127"></a> <span class="k">if</span> <span class="n">task</span><span class="o">.</span><span class="n">type</span> <span class="o">==</span> <span class="s2">"project"</span><span class="p">:</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-128" name="rest_code_c1bb69f5878a42a8876517fab6802104-128" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-128"></a> <span class="c1"># TimeCult can only cope with time events being against 'leaf' nodes</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-129" name="rest_code_c1bb69f5878a42a8876517fab6802104-129" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-129"></a> <span class="c1"># in the tree. So we need to adjust and create an additional leaf</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-130" name="rest_code_c1bb69f5878a42a8876517fab6802104-130" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-130"></a> <span class="n">project</span> <span class="o">=</span> <span class="n">task</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-131" name="rest_code_c1bb69f5878a42a8876517fab6802104-131" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-131"></a> <span class="n">undefined_l</span> <span class="o">=</span> <span class="p">[</span><span class="n">t</span> <span class="k">for</span> <span class="n">t</span> <span class="ow">in</span> <span class="n">project</span><span class="o">.</span><span class="n">children</span> <span class="k">if</span> <span class="n">t</span><span class="o">.</span><span class="n">uid</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s1">'autouid'</span><span class="p">)]</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-132" name="rest_code_c1bb69f5878a42a8876517fab6802104-132" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-132"></a> <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">undefined_l</span><span class="p">)</span> <span class="o">></span> <span class="mi">0</span><span class="p">:</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-133" name="rest_code_c1bb69f5878a42a8876517fab6802104-133" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-133"></a> <span class="n">task</span> <span class="o">=</span> <span class="n">undefined_l</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-134" name="rest_code_c1bb69f5878a42a8876517fab6802104-134" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-134"></a> <span class="k">else</span><span class="p">:</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-135" name="rest_code_c1bb69f5878a42a8876517fab6802104-135" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-135"></a> <span class="n">task</span> <span class="o">=</span> <span class="n">Node</span><span class="p">(</span><span class="n">uid</span><span class="o">=</span><span class="s1">'autouid-</span><span class="si">%d</span><span class="s1">'</span> <span class="o">%</span> <span class="n">autouid</span><span class="p">,</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-136" name="rest_code_c1bb69f5878a42a8876517fab6802104-136" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-136"></a> <span class="n">summary</span><span class="o">=</span><span class="s1">'other'</span><span class="p">,</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-137" name="rest_code_c1bb69f5878a42a8876517fab6802104-137" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-137"></a> <span class="n">parent</span><span class="o">=</span><span class="n">project</span><span class="p">,</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-138" name="rest_code_c1bb69f5878a42a8876517fab6802104-138" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-138"></a> <span class="nb">type</span><span class="o">=</span><span class="s2">"task"</span><span class="p">,</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-139" name="rest_code_c1bb69f5878a42a8876517fab6802104-139" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-139"></a> <span class="n">created</span><span class="o">=</span><span class="n">project</span><span class="o">.</span><span class="n">created</span><span class="p">,</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-140" name="rest_code_c1bb69f5878a42a8876517fab6802104-140" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-140"></a> <span class="n">finished</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-141" name="rest_code_c1bb69f5878a42a8876517fab6802104-141" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-141"></a> <span class="n">children</span><span class="o">=</span><span class="p">[])</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-142" name="rest_code_c1bb69f5878a42a8876517fab6802104-142" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-142"></a> <span class="n">autouid</span> <span class="o">+=</span> <span class="mi">1</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-143" name="rest_code_c1bb69f5878a42a8876517fab6802104-143" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-143"></a> <span class="n">nodes</span><span class="p">[</span><span class="n">task</span><span class="o">.</span><span class="n">uid</span><span class="p">]</span> <span class="o">=</span> <span class="n">task</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-144" name="rest_code_c1bb69f5878a42a8876517fab6802104-144" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-144"></a> <span class="n">project</span><span class="o">.</span><span class="n">children</span><span class="o">.</span><span class="n">insert</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">task</span><span class="p">)</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-145" name="rest_code_c1bb69f5878a42a8876517fab6802104-145" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-145"></a>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-146" name="rest_code_c1bb69f5878a42a8876517fab6802104-146" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-146"></a> <span class="n">dtstart</span> <span class="o">=</span> <span class="n">vevent</span><span class="o">.</span><span class="n">dtstart</span><span class="o">.</span><span class="n">value</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-147" name="rest_code_c1bb69f5878a42a8876517fab6802104-147" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-147"></a> <span class="n">dtend</span> <span class="o">=</span> <span class="n">vevent</span><span class="o">.</span><span class="n">dtend</span><span class="o">.</span><span class="n">value</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-148" name="rest_code_c1bb69f5878a42a8876517fab6802104-148" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-148"></a> <span class="k">if</span> <span class="n">dtstart</span><span class="o">.</span><span class="n">tzinfo</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-149" name="rest_code_c1bb69f5878a42a8876517fab6802104-149" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-149"></a> <span class="n">dtstart</span> <span class="o">=</span> <span class="n">dtstart</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="n">tzinfo</span><span class="o">=</span><span class="n">dtend</span><span class="o">.</span><span class="n">tzinfo</span><span class="p">)</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-150" name="rest_code_c1bb69f5878a42a8876517fab6802104-150" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-150"></a> <span class="k">if</span> <span class="n">dtend</span><span class="o">.</span><span class="n">tzinfo</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-151" name="rest_code_c1bb69f5878a42a8876517fab6802104-151" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-151"></a> <span class="n">dtend</span> <span class="o">=</span> <span class="n">dtend</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="n">tzinfo</span><span class="o">=</span><span class="n">dtstart</span><span class="o">.</span><span class="n">tzinfo</span><span class="p">)</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-152" name="rest_code_c1bb69f5878a42a8876517fab6802104-152" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-152"></a> <span class="n">time_rec</span> <span class="o">=</span> <span class="n">TimeRec</span><span class="p">(</span><span class="n">startTime</span><span class="o">=</span><span class="n">dtstart</span><span class="p">,</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-153" name="rest_code_c1bb69f5878a42a8876517fab6802104-153" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-153"></a> <span class="n">duration</span><span class="o">=</span><span class="p">(</span><span class="n">dtend</span> <span class="o">-</span> <span class="n">dtstart</span><span class="p">)</span><span class="o">.</span><span class="n">total_seconds</span><span class="p">(),</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-154" name="rest_code_c1bb69f5878a42a8876517fab6802104-154" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-154"></a> <span class="n">task</span><span class="o">=</span><span class="n">task</span><span class="p">)</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-155" name="rest_code_c1bb69f5878a42a8876517fab6802104-155" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-155"></a> <span class="n">time_log</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">time_rec</span><span class="p">)</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-156" name="rest_code_c1bb69f5878a42a8876517fab6802104-156" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-156"></a>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-157" name="rest_code_c1bb69f5878a42a8876517fab6802104-157" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-157"></a> <span class="c1"># Now need to assign IDs</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-158" name="rest_code_c1bb69f5878a42a8876517fab6802104-158" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-158"></a> <span class="n">taskId</span> <span class="o">=</span> <span class="mi">0</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-159" name="rest_code_c1bb69f5878a42a8876517fab6802104-159" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-159"></a> <span class="k">for</span> <span class="n">u</span><span class="p">,</span> <span class="n">n</span> <span class="ow">in</span> <span class="n">nodes</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-160" name="rest_code_c1bb69f5878a42a8876517fab6802104-160" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-160"></a> <span class="n">taskId</span> <span class="o">+=</span> <span class="mi">1</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-161" name="rest_code_c1bb69f5878a42a8876517fab6802104-161" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-161"></a> <span class="n">n</span><span class="o">.</span><span class="n">id</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="n">taskId</span><span class="p">)</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-162" name="rest_code_c1bb69f5878a42a8876517fab6802104-162" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-162"></a>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-163" name="rest_code_c1bb69f5878a42a8876517fab6802104-163" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-163"></a> <span class="k">for</span> <span class="n">tr</span> <span class="ow">in</span> <span class="n">time_log</span><span class="p">:</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-164" name="rest_code_c1bb69f5878a42a8876517fab6802104-164" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-164"></a> <span class="n">tr</span><span class="o">.</span><span class="n">taskId</span> <span class="o">=</span> <span class="n">tr</span><span class="o">.</span><span class="n">task</span><span class="o">.</span><span class="n">id</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-165" name="rest_code_c1bb69f5878a42a8876517fab6802104-165" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-165"></a>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-166" name="rest_code_c1bb69f5878a42a8876517fab6802104-166" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-166"></a> <span class="k">return</span> <span class="n">TimeCult</span><span class="p">(</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-167" name="rest_code_c1bb69f5878a42a8876517fab6802104-167" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-167"></a> <span class="n">name</span><span class="o">=</span><span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">basename</span><span class="p">(</span><span class="n">filename</span><span class="p">),</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-168" name="rest_code_c1bb69f5878a42a8876517fab6802104-168" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-168"></a> <span class="n">projectTree</span><span class="o">=</span><span class="p">[</span><span class="n">n</span> <span class="k">for</span> <span class="n">u</span><span class="p">,</span> <span class="n">n</span> <span class="ow">in</span> <span class="n">nodes</span><span class="o">.</span><span class="n">items</span><span class="p">()</span> <span class="k">if</span> <span class="n">n</span><span class="o">.</span><span class="n">parent</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">],</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-169" name="rest_code_c1bb69f5878a42a8876517fab6802104-169" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-169"></a> <span class="n">timeLog</span><span class="o">=</span><span class="n">time_log</span><span class="p">)</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-170" name="rest_code_c1bb69f5878a42a8876517fab6802104-170" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-170"></a>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-171" name="rest_code_c1bb69f5878a42a8876517fab6802104-171" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-171"></a>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-172" name="rest_code_c1bb69f5878a42a8876517fab6802104-172" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-172"></a><span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s1">'__main__'</span><span class="p">:</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-173" name="rest_code_c1bb69f5878a42a8876517fab6802104-173" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-173"></a> <span class="n">filename</span> <span class="o">=</span> <span class="n">sys</span><span class="o">.</span><span class="n">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-174" name="rest_code_c1bb69f5878a42a8876517fab6802104-174" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-174"></a> <span class="n">timecult</span> <span class="o">=</span> <span class="n">convert</span><span class="p">(</span><span class="n">filename</span><span class="p">)</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-175" name="rest_code_c1bb69f5878a42a8876517fab6802104-175" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-175"></a> <span class="n">sys</span><span class="o">.</span><span class="n">stdout</span><span class="o">.</span><span class="n">write</span><span class="p">(</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-176" name="rest_code_c1bb69f5878a42a8876517fab6802104-176" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-176"></a> <span class="sd">"""<?xml version="1.0" encoding="UTF-8"?>"""</span> <span class="o">+</span>
<a id="rest_code_c1bb69f5878a42a8876517fab6802104-177" name="rest_code_c1bb69f5878a42a8876517fab6802104-177" href="https://lukeplant.me.uk/blog/posts/ktimetracker-replacement-timecult/#rest_code_c1bb69f5878a42a8876517fab6802104-177"></a> <span class="n">ET</span><span class="o">.</span><span class="n">tostring</span><span class="p">(</span><span class="n">timecult</span><span class="o">.</span><span class="n">toXML</span><span class="p">()))</span>
</pre></div>Leaving KDEhttps://lukeplant.me.uk/blog/posts/leaving-kde/2010-06-17T01:57:39+01:002010-06-17T01:57:39+01:00Luke Plant<p>After being a loyal fan of KDE for a long time, I've just left...</p><p>After being a loyal fan of KDE for a long time, I've just switched to GNOME.</p>
<p>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 <em>embarrassing</em> – 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).</p>
<p>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 <a class="reference external" href="https://lukeplant.me.uk/blog/posts/a-plea-to-kde-developers/">I feared</a> and is
‘losing’ some of my data.</p>
<p>I found that <a class="reference external" href="https://bugs.kde.org/show_bug.cgi?id=232773">some things added to the address book ‘never’
actually end up in the file they are supposed to be stored in</a>. 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.</p>
<p>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”.</p>
<p>Another bug is that <a class="reference external" href="https://bugs.kde.org/show_bug.cgi?id=232774">the Google contacts Akonadi plugin also loses data in a
serious way</a>, 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.</p>
<p>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 <strong>visible</strong> is a
major failing – the software layer it replaced was, after all, completely
invisible, just as it should have been.</p>
<p>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.</p>
<p>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.</p>
<p>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.</p>
<p>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 <em>much</em> faster than KDE.</p>
<p>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).</p>
<p>I certainly won't shed a tear over Nepomuk/Strigi. After <strong>weeks</strong> 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.</p>
<p>First experience with Ubuntu's GNOME has thrown up some problems. Here are some niggles I've been able to fix/solve:</p>
<ul class="simple">
<li><p>PulseAudio - this breaks lots of things, especially games, and provides no
added benefit. But <a class="reference external" href="http://art.ubuntuforums.org/showpost.php?p=9297829&postcount=146">it can be removed</a>.
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.</p></li>
<li><p>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</p></li>
<li><p>To turn off screen locking on resume - there is setting is in gconf,
search for 'lock'.</p></li>
</ul>
<p>And here are some that are still bothering me a bit:</p>
<ul class="simple">
<li><p>Reading new e-mails with keyboard only - it's a bit buggy/confusing with Evolution.</p></li>
<li><p>Some options are hidden away in gconf, so it's difficult to know if it is
possible to change things.</p></li>
<li><p>GNOME has less configurability in general, or harder to get to it,
especially for creating new keyboard shortcuts.</p></li>
<li><p>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.</p></li>
<li><p>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.</p></li>
</ul>
<p>But there are some niggles which are no longer there due to the switch from
KDE. Overall, things are similar at this level.</p>
<p>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.</p>Linux and calendars - bad combination...https://lukeplant.me.uk/blog/posts/linux-and-calendars-bad-combination/2010-03-23T13:22:49Z2010-03-23T13:22:49ZLuke Plant<p>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.</p><p>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?</p>
<ul class="simple">
<li><p>I already blogged the <a class="reference external" href="https://lukeplant.me.uk/blog/posts/blackberry-curve-kde-pim-sync-on-kubuntu-karmic-fail/">failure to sync directly</a>. Let's not go there.</p></li>
<li><p>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:</p>
<ul>
<li><p>I tried GCalDaemon, but found that it <a class="reference external" href="https://sourceforge.net/tracker/?func=detail&aid=2844153&group_id=184382&atid=909032">ignores/deletes all recurring events on your calendar</a>. Which is pretty evil.</p></li>
<li><p>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...</p>
<ul>
<li><p>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.</p></li>
</ul>
</li>
</ul>
</li>
<li><p>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.</p></li>
<li><p>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."</p></li>
</ul>
<p>Epic fail. Bad day.</p>
<hr class="docutils">
<p>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).</p>Blackberry Curve ↔ KDE-PIM sync on Kubuntu Karmic. FAILhttps://lukeplant.me.uk/blog/posts/blackberry-curve-kde-pim-sync-on-kubuntu-karmic-fail/2010-02-11T17:07:58Z2010-02-11T17:07:58ZLuke Plant<p>Complete fail for KDE-PIM/Linux/msynctool and Blackberry Curve.</p><p>For the sake of anyone else who might want to know about this in advance, I'll blog my failure.</p>
<p>I tried with Kubuntu Karmic, and the following steps:</p>
<ol class="arabic">
<li><p>Install the necessary packages:</p>
<div class="code"><pre class="code bash"><a id="rest_code_e2edbb83c83040f998255fd96bf5be90-1" name="rest_code_e2edbb83c83040f998255fd96bf5be90-1" href="https://lukeplant.me.uk/blog/posts/blackberry-curve-kde-pim-sync-on-kubuntu-karmic-fail/#rest_code_e2edbb83c83040f998255fd96bf5be90-1"></a>sudo aptitude install opensync-plugin-kdepim opensyncutils barrybackup-gui barry-util opensync-plugin-barry
</pre></div>
</li>
<li><p>Plug in the Blackberry, and choose "Mass storage" mode on the Blackberry.</p></li>
<li><p>Set up permissions to allow a non-root user to access the device. I added the file <code class="docutils literal"><span class="pre">/etc/udev/rules.d/040-devices.rules</span></code>, with the following contents:</p>
<pre class="literal-block">BUS=="usb", SYSFS{idVendor}=="0fca", SYSFS{idProduct}=="8004", GROUP="admin"</pre>
<p>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 <code class="docutils literal">lsusb</code>:</p>
<div class="code"><pre class="code bash"><a id="rest_code_6816d06adfd544419a8f23cc7ce3b9d7-1" name="rest_code_6816d06adfd544419a8f23cc7ce3b9d7-1" href="https://lukeplant.me.uk/blog/posts/blackberry-curve-kde-pim-sync-on-kubuntu-karmic-fail/#rest_code_6816d06adfd544419a8f23cc7ce3b9d7-1"></a>lsusb <span class="p">|</span> grep <span class="s2">"Research In Motion"</span>
</pre></div>
<p>Result:</p>
<div class="code"><pre class="code bash"><a id="rest_code_be9f5c04d9584ed6afcfde3ce93a7b63-1" name="rest_code_be9f5c04d9584ed6afcfde3ce93a7b63-1" href="https://lukeplant.me.uk/blog/posts/blackberry-curve-kde-pim-sync-on-kubuntu-karmic-fail/#rest_code_be9f5c04d9584ed6afcfde3ce93a7b63-1"></a>Bus <span class="m">002</span> Device <span class="m">008</span>: ID 0fca:8004 Research In Motion, Ltd.
</pre></div>
<p>You will need to unplug the Blackberry and plug back in after this step.</p>
</li>
<li><p>Check you can access the Blackberry.</p>
<div class="code"><pre class="code bash"><a id="rest_code_b2c05f8cd79f4ebe9bf859e775138e9e-1" name="rest_code_b2c05f8cd79f4ebe9bf859e775138e9e-1" href="https://lukeplant.me.uk/blog/posts/blackberry-curve-kde-pim-sync-on-kubuntu-karmic-fail/#rest_code_b2c05f8cd79f4ebe9bf859e775138e9e-1"></a>btool -t
</pre></div>
<p>This should list a series of databases on the Blackberry</p>
</li>
<li><p>Back up the current contents:</p>
<div class="code"><pre class="code bash"><a id="rest_code_7717e942704a494ea7e8a5d409856dc6-1" name="rest_code_7717e942704a494ea7e8a5d409856dc6-1" href="https://lukeplant.me.uk/blog/posts/blackberry-curve-kde-pim-sync-on-kubuntu-karmic-fail/#rest_code_7717e942704a494ea7e8a5d409856dc6-1"></a>barrybackup
</pre></div>
<p>Note the pin for later, and follow the prompts to backup the Blackberry data.</p>
</li>
<li><p>Back up your KDE-PIM data, in case of any corruption, duplicate elements etc. (It happened to me!).</p></li>
<li><p>Create a msynctool configuration for doing the synchronisation.</p>
<div class="code"><pre class="code bash"><a id="rest_code_50514db1193c4f328c8d5b281f9132e4-1" name="rest_code_50514db1193c4f328c8d5b281f9132e4-1" href="https://lukeplant.me.uk/blog/posts/blackberry-curve-kde-pim-sync-on-kubuntu-karmic-fail/#rest_code_50514db1193c4f328c8d5b281f9132e4-1"></a>msynctool --addgroup Blackberry
<a id="rest_code_50514db1193c4f328c8d5b281f9132e4-2" name="rest_code_50514db1193c4f328c8d5b281f9132e4-2" href="https://lukeplant.me.uk/blog/posts/blackberry-curve-kde-pim-sync-on-kubuntu-karmic-fail/#rest_code_50514db1193c4f328c8d5b281f9132e4-2"></a>msynctool --addmember Blackberry barry-sync
<a id="rest_code_50514db1193c4f328c8d5b281f9132e4-3" name="rest_code_50514db1193c4f328c8d5b281f9132e4-3" href="https://lukeplant.me.uk/blog/posts/blackberry-curve-kde-pim-sync-on-kubuntu-karmic-fail/#rest_code_50514db1193c4f328c8d5b281f9132e4-3"></a>msynctool --addmember Blackberry kdepim-sync
<a id="rest_code_50514db1193c4f328c8d5b281f9132e4-4" name="rest_code_50514db1193c4f328c8d5b281f9132e4-4" href="https://lukeplant.me.uk/blog/posts/blackberry-curve-kde-pim-sync-on-kubuntu-karmic-fail/#rest_code_50514db1193c4f328c8d5b281f9132e4-4"></a>msynctool --showgroup Blackberry
</pre></div>
<p>The final command should show the first member as missing configuration. Do the following</p>
<div class="code"><pre class="code bash"><a id="rest_code_fa291db68c384c828b279c0ea56cee6f-1" name="rest_code_fa291db68c384c828b279c0ea56cee6f-1" href="https://lukeplant.me.uk/blog/posts/blackberry-curve-kde-pim-sync-on-kubuntu-karmic-fail/#rest_code_fa291db68c384c828b279c0ea56cee6f-1"></a>msynctool --configure Blackberry <span class="m">1</span>
</pre></div>
<p>and insert your pin in the relevant place.</p>
</li>
<li><p>Moment of truth. Close KOrganizer and KMail, then:</p>
<div class="code"><pre class="code bash"><a id="rest_code_683cfe1714c7406b8408cf94d3f025b1-1" name="rest_code_683cfe1714c7406b8408cf94d3f025b1-1" href="https://lukeplant.me.uk/blog/posts/blackberry-curve-kde-pim-sync-on-kubuntu-karmic-fail/#rest_code_683cfe1714c7406b8408cf94d3f025b1-1"></a>msynctool --sync Blackberry
</pre></div>
</li>
</ol>
<p>I came across the following major bugs:</p>
<ul class="simple">
<li><p>Syncing never completes, and I have to press Ctrl-C to abort.</p></li>
<li><p>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.</p></li>
<li><p>Each time I attempt to sync, duplicate events and contacts build up on the Blackberry as well.</p></li>
<li><p>Using barrybackup to restore to a clean state with the backup made previously fails with lots of errors. By removing some items in <code class="docutils literal"><span class="pre">~/.barry/backup/<pin>/config</span></code>, 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 -> Menu -> 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.</p></li>
</ul>
<p>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.</p>
<p>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.</p>
<p>Sources:</p>
<ul class="simple">
<li><p><a class="reference external" href="http://forums.debian.net/viewtopic.php?t=20424">Contacts, sms messages and files from and to mobile phone</a></p></li>
<li><p><a class="reference external" href="http://www.linux.com/news/embedded-mobile/mids/8210-syncing-your-blackberry-on-linux">Syncing your BlackBerry on Linux</a></p></li>
</ul>A plea to KDE developershttps://lukeplant.me.uk/blog/posts/a-plea-to-kde-developers/2009-09-23T13:15:33+01:002009-09-23T13:15:33+01:00Luke Plant<p>In short: don't touch my data with alpha-quality software like Akonadi, and start working on things people actually want instead of grandiose schemes that have failed.</p><p>I recently upgraded to KDE 4.3.1 (from KDE 4.2.something). As seems to be par
for the course for the KDE 4 series, I then waded through nearly a dozen
bugs/crashes/regressions for the next day, filing bugs where I had the
energy. This has got pretty old, and fills me with no confidence about the
future of KDE – the stable desktop I'm hoping for still hasn't materialised.</p>
<p>But there is one thing about KDE 4 that <strong>terrifies</strong> me, and this post is an
attempt to get the KDE devs to change their approach before it's too late.</p>
<p>KDE 4.2 attempted to migrate some of my data to Akonadi, the new framework
for storing PIM data. There were a bunch of ways in which Akonadi did not
provide the features that previously existed (can't have multiple writable
calendars in KOrganizer, Kopete address book link didn't work...), so I had
to ditch it. Thankfully this was not hard (though the whole experience would
have been extremely confusing to Joe User).</p>
<p>I was prepared to give KDE 4.3 another shot on this front (after carefully
backing up my data). I cleared out any remnants of previous Akonadi data, and
the settings which told it not to do the migration.</p>
<p>The results were pretty disappointing:</p>
<ul>
<li><p>First, there was an initial setup process. This failed.
Unfortunately, the popup simply disappeared before I could note down the
error message. It was something to do with creating an agent. Did the
process crash, or was it supposed to just disappear like that?</p></li>
<li><p>Then, for individual applications, the migrations all partly failed.
Again, the popups telling me what was happening, including the error,
just disappeared after a short delay. The error was something about a
timeout when creating an instance of an agent. Did the process crash? Did
the agent instance get created eventually, so the process could continue
successfully? I've no idea. I can't even file an bug without the error
message.</p>
<p>Even while the popup remained, there was no indication of what I
should do about the error, if anything.</p>
<p>So I'm guessing all the migrations failed – my applications don't
seem to be migrated to using Akonadi at all.</p>
</li>
</ul>
<p>Why does this worry me so much? Well, I can cope with an unstable desktop.
It's a pain, it means I can't recommend KDE to anyone I know in it's current
state, but usually I can work around the pain points. Plasma restarts itself,
so although it is still pretty crashy (far more than the Windows shell, for
instance, has ever been in my experience), I don't have to worry about it too
much.</p>
<p>But Akonadi is a different matter. It is the proposed framework for handling
all PIM data – all my e-mails, calendars and address book. This data is
<strong>extremely</strong> important to me. Akonadi is clearly not up to the job of
handling it – if their migration tool can fail like this, and fail with
worrying errors about timeouts (which actually suggests the migration process
is <em>non-deterministic</em> – it's going to depend on how fast/busy your computer
is), it's clearly far from ready. It's not getting better, it's getting worse
— this time the migration failed completely, and I'm not even able to check
whether it's up to feature parity with non-Akonadi methods.</p>
<p>Even worse than this, is that either the KDE developers:</p>
<ul class="simple">
<li><p>think it's OK to start migrating to an alpha-quality framework for
handling user's data. To me, this is appalling. Desktop eye-candy in
exchange for a bit of instability is one thing, but my data is entirely
different.</p></li>
<li><p>or, they are unaware that Akonadi is not there yet. This is just as
worrying.</p></li>
</ul>
<p>Akonadi seems like an overly ambitious project. If you look at its <a class="reference external" href="http://pim.kde.org/akonadi/">home page</a>, the diagram includes the idea that other
desktop apps, outside of KDE, will use Akonadi as a backend for all their
data. To me, this seems extremely unlikely and is a tell-tail sign of
developers getting ideas that are just too big.</p>
<p>So, what do I propose?</p>
<p>Simply this: ditch Akonadi. Yes, I mean that. KDE 4 seems to lack a BDFL who
is willing to say "this is not working, time to pull the plug". Mark
Shuttleworth did that with a pet project of his when the developers got
<a class="reference external" href="http://www.markshuttleworth.com/archives/4">distracted with shiny geek toys</a>. Windows Vista ditched the
killer feature of Vista, their WinFS filesystem, because it just wasn't
ready. But it seems there is no-one in KDE who can make these kind of
decisions. The major obstacle is egos and pride – after all that work has
gone in for years, can we ditch a big feature like that? Yes, you can, and
you should, for the sake of your users and the future of KDE. Of course, you
can just move it to an experimental branch and come back to it for KDE 5/6/7,
but <strong>please</strong> do not turn it on until it's ready.</p>
<p>Akonadi is one instance of a bigger problem in KDE – grandiose ‘we'll fix
everything but it will take us five years’ schemes that are prioritised over
things users actually want, and could be implemented soon.</p>
<p>For example, I want desktop search and fast e-mail search. After all, this is
2009, right? Is it so much to ask for a decent way of searching all the files
on my computer, and fast full text search for my e-mails? If I used Mac or
Vista or Google docs & Gmail, I would have had this years ago. Instead of
that, KDE gives us: Nepomuk. The usefulness of Nepomuk completely escapes me.
Even though it includes Strigi indexing (which indexes all your files, though
it can be a big pain to get working), there is no decent interface for
searching those files. (No KRunner is not a decent interface). Currently,
turning Nepomuk off has exactly one consequence – it makes my computer much
more responsive and saves me 3 Gb of disk space. AFAICS, there are no
applications which make good use of Nepomuk. I think there is tagging in
Dolphin, but:</p>
<ul class="simple">
<li><p>There is no interface for searching tags! What kind of idiots do you
take us for? Going round tagging files in the hope that one day we'll be
able to make use of all that effort because someone actually implemented
a UI?</p></li>
<li><p>I don't want to manually tag files anyway, I want a decent desktop
search tool!</p></li>
</ul>
<p>Other applications that need tagging are better off implementing their own
solution, and then extracting a simple KTagging library which can be shared.</p>
<p>Nepomuk isn't as bad as Akonadi at the moment – it's useless, but I can turn
it off, and it doesn't threaten my data. But even then, all the effort that
is going into Nepomuk could be directed into manageable, achievable goals of
providing features that users will be able to make use of.</p>
<p>Please, KDE devs, stop the big grandiose schemes. Stop doing anything that
would threaten my data. I've been a loyal fan – pushed to the limits by the
KDE 4 series, I'll admit – but if you foist Akonadi on me in anything like
it's current state, I'm taking all my data and going. I don't yet know where
I'll go. I might go back to GNOME after a <em>long</em> time. It still sucks IMO,
and I'm not sure how I'm going find replacements for KMail (very nice despite
no fast full-text search), KOrganizer, Amarok, k3b etc. KDE currently has the
lion's share of the best Linux apps. But it doesn't really deserve them at
the moment, and it's going to lose all but its most stubborn and loyal users
at the current rate.</p>
<p>If you got this far, thanks for bothering to read this. I know the KDE
developers have got a lot of flack for KDE 4, and I have held back for a long
time, but some of the criticisms are deserved, and you do need to listen
occasionally...</p>Amarok 2 can corrupt MP3 fileshttps://lukeplant.me.uk/blog/posts/amarok-2-can-corrupt-mp3-files/2009-04-23T01:18:10+01:002009-04-23T01:18:10+01:00Luke Plant<p>Amarok 2 is not my favourite application at the moment...</p><p>I've found that Amarok 2 is really not ready to be used...</p>
<p>In terms of interface, it's not that bad, and I'm much happier than most
people with the changes from Amarok 1.4, and I've been giving it a fair try.</p>
<p>I was annoyed that it provides a UI for putting albums into 'Various
Artists', or removing then, but then forgets everything you've done next time
you open the program when it rescans the collection. But I could live with
that for the time being.</p>
<p>The fact that it clips the beginning off some tracks for some unknown reason
is also really annoying (it clips 1.2 seconds off the beginning of one of my
favourite tracks; Dragon Player, another KDE4 apps, also does it, but no
other media players do so).</p>
<p>But it has started doing things that mean I just don't trust it with my MP3s
any more:</p>
<p>Certain tracks start appearing with seemingly random album and artist names
in the playlist (picked from other tracks in my collect), though they have
the correct song title and play the correct song. If I right-click and select
'Edit track details', the same wrong details appear (so if I were to press
save, the wrong details would be saved back to the file). If, in the
collection pane, I go to the album the track ought to be in, it is missing. I
don't know how to find it again, except in the file browser. However, if I
look at the same file in any other player or ID3 tag editor, the correct info
appears. Somehow Amarok is not reading the info from the file itself, but
from some other source which is corrupt.</p>
<p>This means that editing any track details in Amarok is now dodgy, since if I
go to edit one detail, I can't be sure that other details will be supplied
correctly, and when I save I could save Amarok's corrupt data to the file.</p>
<p>Perhaps purging the collection completely might help, but I'm not sure how to
do it, and I don't really want to lose all the album covers etc.</p>
<p>I guess I should file a bug, but I've filed so many recently, and this is one
I don't know how to reproduce, and it's fairly pointless filing it – as a
developer myself, I know that, with the best will in the world, this kind of
bug will eventually just get WORKSFORME.</p>
<p>Before, I couldn't trust Amarok to actually play tracks correctly, and now
can't trust Amarok to show my collection so that I can find songs and albums,
and I certainly can't trust it to manage the MP3 files.</p>
<p>Fairly damning I'm afraid. I'm posting this as a warning to others, Amarok
could be corrupting the metadata in your MP3s...</p>
<p>Should I try upgrading to Amarok 2.1? Or do I just give up now and go back to
mocp?</p>Konsole/Yakuake and drag/drophttps://lukeplant.me.uk/blog/posts/konsole-yakuake-and-drag-drop/2008-05-10T01:50:14+01:002008-05-10T01:50:14+01:00Luke Plant<p>You can drag and drop files onto a Konsole (or Yakuake) terminal session, and it works...</p><p>You can drag and drop files onto a Konsole (or Yakuake) terminal session, and
it works – the file is copied to your current directory! That is pretty
cool. I just had the situation when I needed to copy a file from an email (in
KMail) into the current directory I was in, and I was very chuffed that the
drag and drop operation I instinctively went for worked just as planned. It
pops up a little menu so you can choose between 'Paste' (the filename) 'cp',
'cd', 'ln' and 'mv'.</p>Personal wiki and desktop integrationhttps://lukeplant.me.uk/blog/posts/personal-wiki-and-desktop-integration/2008-02-23T21:12:57Z2008-02-23T21:12:57ZLuke Plant<p>Some tools to help organise your computer and files.</p><p>Like many people, I find it easier to find stuff on the web than on my own
machine. This post is about some of my attempts to remedy that. You probably
need to be a developer or that way inclined to get the most out of some of
the solutions I've got here. Stuff to download is at the bottom.</p>
<section id="search-tool">
<h2>Search tool</h2>
<p>Obviously, first of all there is a need for a decent desktop search tool. On
Linux, your main options are:</p>
<ul class="simple">
<li><p><a class="reference external" href="http://desktop.google.com/linux/">Google desktop search</a></p>
<ul>
<li><p>Main problem: it stops it's initial index after 100,000
documents. I've got far more than that, and it means it never actually
reaches my mail. Typical crippleware. This is useless for me.</p></li>
</ul>
</li>
<li><p><a class="reference external" href="http://beagle-project.org/">Beagle</a></p>
<ul>
<li><p>Main problem: it will decide to thrash your disk and/or CPU and
crash. For me, runaway CPU usage and crashing made this completely
useless. It might be 99% of the way to being brilliant, but until these
things are sorted out, it is a 100% waste of time.</p></li>
</ul>
</li>
<li><p><a class="reference external" href="http://strigi.sourceforge.net/">Strigi</a></p>
<ul>
<li><p>Minor problem: the GUIs suck</p></li>
<li><p>Minor problem: it indexes too much, sometimes.</p></li>
<li><p>Main problem: after indexing about 300,000 documents, Strigi dies
on me and refuses to do anything useful at all. I don't know what causes
it to choke, but it, too, is 100% useless AFAIC. Maybe it's fixed now,
but I've got bored of filing bugs and compiling from source just to find
out it still doesn't work.</p></li>
</ul>
</li>
<li><p><a class="reference external" href="http://www.gnome.org/projects/tracker/">MetaTracker</a>, or Tracker
for short.</p>
<ul>
<li><p>It can't search zip files etc. like Strigi can, which is a shame.</p></li>
<li><p>It doesn't yet index my emails (KMail) – it only does evolution.</p></li>
<li><p>But I actually find this tool useful, . It doesn't thrash my
disk, it has a simple but effective GUI, as well as command line tools,
it integrates <em>reasonably</em> well into KDE, and it also has a nice tagging
facility.</p></li>
</ul>
</li>
</ul>
</section>
<section id="tagging-and-konqueror">
<h2>Tagging and Konqueror</h2>
<p>Adding tags to files needs to be easy to do if it's going to happen.
MetaTracker provides the <code class="docutils literal"><span class="pre">tracker-tag</span></code> program which works well, but it is
command line. So I've written a small GUI wrapper that integrates into
Konqueror via a service menu. If you tag more than one file at once (by
selecting a few files in Konqueror), it is in bulk tag mode, where it pops up
an input box and simple adds the space-separated tags you enter to all the
files.</p>
<p>In single file mode, it does something slightly different. It will first query
the file for any existing tags, adding them to the default text that is in the
input box, so that you can remove tags as well as add new ones. It will also add
a suggestion for an <code class="docutils literal">ID</code> tag – based on the filename, with punctuation
replaced by hyphens, and with <code class="docutils literal">ID-</code> prepended. The idea is that I edit this
and make it into something that will uniquely identify that file. For example, a
file <code class="docutils literal">bible reading schedule.pdf</code> ends up with the tag
<code class="docutils literal"><span class="pre">ID-bible-reading-schedule-pdf</span></code>, but <code class="docutils literal"><span class="pre">rest-quickref2.html</span></code> will expand to
<code class="docutils literal"><span class="pre">ID-restructured-text-quickref-html</span></code>, and in some cases I would have to
include something else that will distinguish it.</p>
<p>The nice thing about these tags is that MetaTracker will keep track of them
<strong>even if I move or rename the file</strong>. I'm not entirely sure how it does this (I
think it uses inotify). But it works, and that's all I care about for now.</p>
<section id="migrating">
<h3>Migrating</h3>
<p>It may be that strigi / Nepomuk will mature and become useful. When they do, I
can dump the tag database from MetaTracker pretty easily, and should be able to
import into strigi. Changing the tools/scripts I've developed to use a different
metadata database should be pretty simple.</p>
</section>
</section>
<section id="personal-wiki">
<h2>Personal wiki</h2>
<p>On top of this, there are other things that file systems are just not very
helpful for organising. Hierarchy works pretty well for about half my stuff
(development work in particular). But notes and things I like to jot down often
get lost on my disk – there are multiple places that some things belong, and
some belong nowhere at all.</p>
<p>I decided that a personal wiki would be the best way forward for this. However,
I then had to choose a wiki – thankfully the <a class="reference external" href="http://www.wikimatrix.org/">WikiMatrix</a> helps a lot. I had tried the <a class="reference external" href="http://www.instiki.org/show/HomePage">Instiki</a> wiki. But it turns out that Ruby on
Rails <em>does</em> suck as much as they say – the instiki process would sit there at
about 50Mb for a while, but then decide that it would <a class="reference external" href="http://rubyforge.org/tracker/index.php?func=detail&aid=18185&group_id=186&atid=783">use up all my memory</a>.
(Other people have noticed the same behaviour). So I wasted some time with that,
and I don't think I'll be trying Ruby on Rails soon if this is the kind of thing
I can expect.</p>
<p>But anyway, WikiMatrix helped me find the <a class="reference external" href="http://trac.edgewall.org/">Trac</a>
wiki. Though I've used Trac a lot before, I hadn't thought of this option, as it
is a wiki that is geared towards software projects, not general things. However,
I've discovered it is ideal for me:</p>
<ul class="simple">
<li><p>You can very easily turn off all the stuff you don't want, and then those
components just disappear from the interface, exactly like they should.</p></li>
<li><p>It has all the help you need built in.</p></li>
<li><p>Nice GUI for administering it – you need to use the command line UI for the
first few steps, and you need to use htdigest to set up a password file, which
some people might find tricky, but as a developer I'm right at home with that
kind of thing.</p></li>
<li><p>It is written in Python, and it seems to be very well written too.</p></li>
<li><p>It uses SQlite (can use other databases), so it easy to query from
outside if necessary.</p></li>
<li><p>It comes with a built in server – very little setup, easy to run as a normal
user.</p></li>
<li><p>It has a plugin architecture with <a class="reference external" href="http://trac.edgewall.org/wiki/PluginList">lots of good plugins</a>, and you can easily write your
own.</p></li>
</ul>
<p>This has allowed me to bring lots of bits and pieces into one place, and
organise them as loosely or tightly as I want. The <a class="reference external" href="http://trac-hacks.org/wiki/TagsPlugin">TagsPlugin</a> for Trac makes this particularly convenient. The
wiki is actually pretty nice for composing blog posts too – it can do all the
code highlighting I want, and I can just copy the output HTML into my blog when
it's ready.</p>
</section>
<section id="combining-wiki-and-desktop">
<h2>Combining wiki and desktop</h2>
<p>The final problem is integrating wiki and other files. Obviously, I have many
documents that are much better managed outside a wiki. It would be nice to be
able to refer to these easily. And by writing some Trac plugins, this is
actually pretty easy. I can now write things like this:</p>
<pre class="literal-block">file:ID-bible-reading-schedule-pdf</pre>
<p>in my wiki and it turns into a <code class="docutils literal"><span class="pre">file:///</span></code> link to the right document. In
Konqueror, this works really well – right-clicking on the link brings up the
same context menu that I would get in file browsing mode, so everything is
available to me right there from the wiki page. I can also do a search:</p>
<pre class="literal-block">[[MetaTrackerSearch(programming languages,web)]]</pre>
<p>This will returns links to all files containing the text "programming languages"
and "web", nicely formatted in a table. Or I can do a tag search like this:</p>
<pre class="literal-block">[[MetaTrackerTagSearch(sermon)]]</pre>
<p>to return all my sermons.</p>
</section>
<section id="further">
<h2>Further</h2>
<p>I've created a very simple Trac plugin for creating <a class="reference external" href="https://lukeplant.me.uk/kio-sword/">KioSword</a> links, which works nicely for embedding
links to Bible passages. I've got some ideas for further integrating different
parts of my desktop. One thing I'd like to do is produce a database of my
sermons and bible studies, the texts they are on, when and where I've preached
them etc. A private Django app using the Django admin would probably work
exceedingly well, and be very little work. A simple export routine could produce
a wiki page that could be 'included' into my wiki (using a Trac macro). It could
also export a read only ICal file which can be displayed in Kontact. So many
cool ideas, so little time...</p>
</section>
<section id="download-links">
<h2>Download links</h2>
<ul>
<li><p><a class="reference external" href="http://trac-hacks.org/wiki/MetaTrackerPluginMacro">MetaTrackerPluginMacro</a></p></li>
<li><p><a class="reference external" href="http://files.lukeplant.fastmail.fm/public/tracker_tag_file">tracker_tag_file</a></p>
<p>Install this by putting it in your path somewhere (e.g. ~/bin, if that is on
your PATH). It requires:</p>
<ul class="simple">
<li><p>kdialog (present on all KDE installations)</p></li>
<li><p>setClipboard – a little utility to set the clipboard with the
contents of the tags just added, for convenience only, see below.</p></li>
</ul>
</li>
<li><p><a class="reference external" href="http://files.lukeplant.fastmail.fm/public/setClipboard">setClipboard</a></p></li>
<li><p><a class="reference external" href="http://files.lukeplant.fastmail.fm/public/tagfile.desktop">tagfile.desktop</a></p>
<p>Install into <code class="docutils literal"><span class="pre">~/.kde/share/apps/konqueror/servicemenus/</span></code></p>
</li>
</ul>
</section>Gutsy woeshttps://lukeplant.me.uk/blog/posts/gutsy-woes/2007-10-15T13:59:32+01:002007-10-15T13:59:32+01:00Luke Plant<p>I upgraded to Gutsy RC last week, and I've really had nothing but trouble, and submitted lots of bugs...</p><p>I upgraded to Gutsy RC last week, and I've really had nothing but trouble,
and submitted lots of <a class="reference external" href="https://bugs.launchpad.net/~l-plant-98">bugs</a> (which
is what you are supposed to do with a release candidate, but with only a few
days left to go, I'm wondering how many of these are really gonna get fixed
in time). Some of these may be particularly related to Kubuntu/KDE, and some
might be due to not having a clean install, I don't know.</p>
<ul class="simple">
<li><p><a class="reference external" href="https://bugs.launchpad.net/ubuntu/+bug/152133">The upgrade tool failed</a> —
in fact I've never <em>ever</em> had a 'dist-upgrade' go smoothly, despite the
advertising. In my case after the tool failed, I had to manually do 'aptitude
dist-upgrade' <strong>3 times</strong> before everything was finally sorted out.
Dist-upgrading is simply not for novices. I guess the problem is that people
do it so infrequently, and test cases are so massively time consuming to set
up, that it is never properly tested in the real world.</p></li>
<li><p>The <a class="reference external" href="https://bugs.launchpad.net/ubuntu/+source/linux-restricted-modules-2.6.20/+bug/95956">Ubuntu-packaged nVidia drivers disappear every time I reboot</a>. It means I either have to use the open source
'nv' driver (and no accelerated graphics), or X fails to start and I have to
manually reinstall a package.</p></li>
<li><p>Even when I get the nVidia drivers it working, I still have <a class="reference external" href="https://bugs.launchpad.net/bugs/71913">X crashing on me
when using Compiz</a>. It only happens
when I'm doing lots of things at once – some changes in window activity at
the same time as doing something in the background that is disk and CPU
intensive (e.g. installing software). But this is still unacceptable for a
default option.</p></li>
<li><p>Compiz-fusion itself is quite nice (I've found a combination of plugins that
works very nicely, giving me a nicely animated 2x4 desktop, plus 'Expo' and
nice Alt-Tab mechanisms, with all my normal shortcuts for moving windows
around). However, KDE integration is pretty bad – whether I use the 'KDEWM'
environment setting to start Compiz, or put something in ~/.kde/Autostart, I
end up with lots of problems: <a class="reference external" href="https://bugs.launchpad.net/ubuntu/+source/compiz/+bug/145878">the KDE window decorator dies at startup</a>, and
<a class="reference external" href="https://bugs.launchpad.net/ubuntu/+source/compiz/+bug/129801">randomly dies at other times too</a>; some windows
that appear at startup, especially the prompt for the KDE Wallet, don't
actually ever appear; using KDEWM, the 'Alt-F1', 'Alt-F2' KDE shortcuts don't
work. The only safe method I've found is to do a manual 'compiz —replace'
after my session is completely restored.</p></li>
<li><p><a class="reference external" href="https://bugs.launchpad.net/ubuntu/+bug/152325">KControl and KInfoCenter were empty</a> – thankfully the fix
isn't too hard</p></li>
<li><p>My Input Actions (KHotkeys) were <a class="reference external" href="https://bugs.launchpad.net/ubuntu/+source/meta-kde/+bug/152190">wiped out</a>
(thankfully the relevant config file was not emptied, and eventually by
trial and error I found a workaround)</p></li>
<li><p><a class="reference external" href="https://sourceforge.net/tracker/index.php?func=detail&aid=1778330&group_id=954&atid=100954">BibleTime crashes when you change an option for module display</a>, which is a real killer for me. It also <a class="reference external" href="https://sourceforge.net/tracker/index.php?func=detail&aid=1778328&group_id=954&atid=100954">crashes/fails
when you try to add/change side-by-side Bible translations to a window</a>, which is equally painful.</p></li>
</ul>
<p>What's left of the advertised benefits of Kubuntu Gutsy? Well, there is
Dolphin – but I already had that before. There is 'Restricted Drivers
Manager' – great, except that it completely failed with the nVidia drivers
as described above. There is a newer version of strigi, but is no better than
it has been in the past – it is alpha quality software really (things like
the daemon refusing to stop etc, dying randomly, and the interface being
extremely basic compared to Beagle. Actually, it currently dies whenever I
tell it start indexing, so it is basically useless. And this problem reoccurs
after purging the indexes and starting again, after indexing about 300,000
documents).</p>
<p>Then there is GDebi, which is quite nice, but I'm not likely to use it often.
Amarok 1.4.7 is included in Gutsy but I was using that anyway from the
backports repository (using <a class="reference external" href="https://help.ubuntu.com/community/UbuntuBackports#head-0b2a1029f552e385c1af0dc485bf14bcc4ebd5bc">apt pinning to ensure I only got the packages I
deliberated upgraded</a>). There is also the enterprise
version of KDE PIM, which I imagine is quite good for some people, but the
only thing it brought me was a <a class="reference external" href="https://bugs.launchpad.net/ubuntu/+source/kdepim/+bug/152883">bug in which events are not updated in the
calendar</a>.
Finally, the OpenOffice suite has been updated to version 2.3, which may well
have some genuine improvements - I haven't used it enough to tell.</p>
<p>There was one really good thing – 'Suspend' actually works on this non-
laptop computer, for the first time. At least, it worked when using the
normal 'nv' video driver – it didn't with the nVidia driver. I'm not hopeful
that it will even if I get nVidia drivers properly sorted out. Which means
that I'll either be choosing between the ability to have 3D accelerated
graphics, and being able to suspend.</p>
<p>In conclusion – there is nothing so far in Kubuntu Gutsy that I would have
upgraded for. If the bugs above aren't fixed soon, then I would definitely be
far better off with Feisty, but I'm still hopeful that the guys at Ubuntu may
be able to get some of these sorted out.</p>
<p>UPDATE: Ubuntu 7.10 is upon us, and none of the above are addressed. I'm
wondering how difficult it is to downgrade...</p>
<p>UPDATE 2: Although nothing has really been addressed, I've discovered how to get
<a class="reference external" href="https://help.ubuntu.com/community/NvidiaLaptopBinaryDriverSuspend">'Hibernate' and 'Suspend' working with nVidia drivers</a>. Since I'm
no longer rebooting, aand not even having to log in again, this has alleviated
some of the problems.</p>
<p>UPDATE 3: Thanks to help on a bug report, I got my nVidia modules to stop
disappearing, result! Some genius also got BibleTime fixed up (had to compile
from source, but it was worth it). X crashing got worse – twice in 10 minutes
yesterday – so I've abandoned it again until the bug is fixed. But my system is
basically all working now, and both Hibernate and Suspend now work perfectly,
which is a real time/power saver, so I'm happy again :-)</p>Fixing Facebook in Konquerorhttps://lukeplant.me.uk/blog/posts/fixing-facebook-in-konqueror/2007-09-02T21:29:38+01:002007-09-02T21:29:38+01:00Luke Plant<p>Facebook is broken in Konqueror, but here is the work around...</p><p>I got fed up waiting for Facebook to fix their website that <a class="reference external" href="https://lukeplant.me.uk/blog/posts/facebook-broken-in-konqueror/">recently broke in
Konqueror</a>, so I did it myself. I
was correct in thinking that the problem was just this line of code:</p>
<div class="code"><pre class="code javascript"><a id="rest_code_65c07cf6804e4ab48393a28ca165fed3-1" name="rest_code_65c07cf6804e4ab48393a28ca165fed3-1" href="https://lukeplant.me.uk/blog/posts/fixing-facebook-in-konqueror/#rest_code_65c07cf6804e4ab48393a28ca165fed3-1"></a><span class="ow">delete</span><span class="w"> </span><span class="nb">Object</span><span class="p">.</span><span class="nx">prototype</span><span class="p">.</span><span class="nb">eval</span><span class="p">;</span><span class="w"></span>
</pre></div>
<p>...which seems to serve no purpose in other browsers, but deletes the global
'eval' function in Konqueror (as you would expect from the ECMA 262, Edition 3
specification). Konqueror doesn't have a GreaseMonkey equivalent (yet), so here
is a quick summary of how to do an equivalent hack.</p>
<ul>
<li><p>Install <a class="reference external" href="http://www.privoxy.org/">privoxy</a></p>
<div class="code"><pre class="code shell"><a id="rest_code_5a7c9e5558d54bd897241557ab7ee67d-1" name="rest_code_5a7c9e5558d54bd897241557ab7ee67d-1" href="https://lukeplant.me.uk/blog/posts/fixing-facebook-in-konqueror/#rest_code_5a7c9e5558d54bd897241557ab7ee67d-1"></a>wajig install privoxy
</pre></div>
<p>(assumes you are using Debian/Ubuntu and have <a class="reference external" href="http://www.togaware.com/linux/survivor/Wajig_Packages.html">wajig</a> installed).</p>
<p>NB: Privoxy does all kinds of other web filtering by default. If you
don't like that, as I don't, just truncate the original config 'action'
files:</p>
<div class="code"><pre class="code shell"><a id="rest_code_2d777761bb9f4754bf050e2d1318016c-1" name="rest_code_2d777761bb9f4754bf050e2d1318016c-1" href="https://lukeplant.me.uk/blog/posts/fixing-facebook-in-konqueror/#rest_code_2d777761bb9f4754bf050e2d1318016c-1"></a><span class="nb">cd</span> /etc/privoxy/
<a id="rest_code_2d777761bb9f4754bf050e2d1318016c-2" name="rest_code_2d777761bb9f4754bf050e2d1318016c-2" href="https://lukeplant.me.uk/blog/posts/fixing-facebook-in-konqueror/#rest_code_2d777761bb9f4754bf050e2d1318016c-2"></a>sudo rm *.action
<a id="rest_code_2d777761bb9f4754bf050e2d1318016c-3" name="rest_code_2d777761bb9f4754bf050e2d1318016c-3" href="https://lukeplant.me.uk/blog/posts/fixing-facebook-in-konqueror/#rest_code_2d777761bb9f4754bf050e2d1318016c-3"></a>sudo touch global.action default.action standard.action user.action
</pre></div>
</li>
<li><p>Configure Konqueror to use 127.0.0.1, port 8118 as the HTTP proxy
(use 'Manually specify the proxy settings' and press 'Setup').</p></li>
<li><p>Configure Privoxy to redirect one javascript file to a different
version that removes the offending line of code, by adding the following
lines to /etc/privoxy/user.action:</p>
<pre class="literal-block">{ +redirect{http://lukeplant.me.uk/privoxy/facebook/base.js} }
static.ak.facebook.com/js/base.js</pre>
<p>(of course, this will break as soon as Facebook update this file).</p>
</li>
<li><p>Check that privoxy and the redirect are working by going to:</p>
<p><a class="reference external" href="http://config.privoxy.org/show-url-info?url=http%3A%2F%2Fstatic.ak.facebook.com%2Fjs%2Fbase.js">http://config.privoxy.org/show-url-info?url=http%3A%2F%2Fstatic.ak.facebook.com%2Fjs%2Fbase.js</a></p>
<p>You are looking for a line that says:</p>
<p><strong>+redirect{http://lukeplant.me.uk/privoxy/facebook/base.js}</strong></p>
</li>
</ul>
<p>Assuming it all worked, you should now have a functional Facebook again! (I
do, anyway)</p>
<p>For performance, in Konqueror configuration you can add 'static.ak.facebook.com'
as the only domain to go through the proxy (you have to enable a check box and
add the domain to a list, it's fairly obvious in the GUI). You should do this
<em>after</em> you have checked it is all working, as otherwise even the
<strong>config.privoxy.org</strong> address that we used for checking won't be redirected to
the proxy, and will instead go to a page on the real internet telling you that
your privoxy setup isn't working.</p>