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

<channel>
	<title>The Troll-Range &#187; Internet</title>
	<atom:link href="http://blog.trollgod.org.uk/category/internet/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.trollgod.org.uk</link>
	<description>Ghworg&#039;s wibblings and geek projects.</description>
	<lastBuildDate>Mon, 26 Apr 2010 19:31:11 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
		<item>
		<title>OAuthcalypse</title>
		<link>http://blog.trollgod.org.uk/2010/04/oauthcalypse/</link>
		<comments>http://blog.trollgod.org.uk/2010/04/oauthcalypse/#comments</comments>
		<pubDate>Mon, 26 Apr 2010 19:31:11 +0000</pubDate>
		<dc:creator>Ghworg</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[Internet]]></category>
		<category><![CDATA[Javascript]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[oauth]]></category>
		<category><![CDATA[twitter]]></category>
		<category><![CDATA[webapp]]></category>

		<guid isPermaLink="false">http://blog.trollgod.org.uk/?p=396</guid>
		<description><![CDATA[<p>So, I have a twitter/status.net app that I use to consolidate all the micro-blogs I&#8217;m on and produce a single timeline in a sidebar of my news page. It was originally written as a python plugin for pyblosxom, which runs the rest of the site. It turns out that this causes huge delays in <span style="color:#777"> . . . &#8594; Read More: <a href="http://blog.trollgod.org.uk/2010/04/oauthcalypse/">OAuthcalypse</a></span>]]></description>
			<content:encoded><![CDATA[<p>So, I have a twitter/status.net <a href="http://blog.trollgod.org.uk/projects/twixm/">app</a> that I use to consolidate all the micro-blogs I&#8217;m on and produce a single timeline in a sidebar of my news page.  It was originally written as a python plugin for <a href="http://pyblosxom.bluesock.org/">pyblosxom</a>, which runs the rest of the site.  It turns out that this causes huge delays in producing the page though and I eventually rewrote it in javascript.</p>
<p>This is really nice because it all runs client-side and can take its sweet time to pull in the feeds without affecting the rendering of the bulk of the page.  It grabs the friend feeds so it needs to login to the various sites, and it uses http basic auth for this.  Nice and simple.</p>
<p>I&#8217;ve just learned of the coming <a href="http://countdowntooauth.com/">OAuthcalypse</a> though, where the basic auth method is going to be disabled, and this presents me with a quandary.  I need to update my app to use OAuth, there are three ways I could do this:</p>
<p><strong>1) Implement OAuth in javascript.</strong>  This is a really bad idea.  OAuth uses a secret key, and as javascript has to be sent to the browser in plain text it wouldn&#8217;t remain secret for long.</p>
<p><strong>2) Move the app back server side and implement OAuth in python.</strong>  Again this is a bad idea, I moved it client side for a <em>reason</em>, and putting it back server side would give me unacceptable performance.</p>
<p><strong>3) A hybrid approach where the OAuth is done server side, and the requests themselves remain javascript on the client.</strong>  Having had a brief look at how OAuth works I <em>think</em> this might be possible.  It will still slow things down, but it might be good enough.  It&#8217;s going to be a pain in the arse to implement though.</p>
<p>Well, at least I know what I&#8217;m doing with my Bank Holiday.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.trollgod.org.uk/2010/04/oauthcalypse/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Firefox 3.5 startup problem (solved)</title>
		<link>http://blog.trollgod.org.uk/2009/09/firefox-3-5-startup-problem-solved/</link>
		<comments>http://blog.trollgod.org.uk/2009/09/firefox-3-5-startup-problem-solved/#comments</comments>
		<pubDate>Mon, 28 Sep 2009 15:06:28 +0000</pubDate>
		<dc:creator>Ghworg</dc:creator>
				<category><![CDATA[Internet]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[debian]]></category>
		<category><![CDATA[firefox]]></category>
		<category><![CDATA[iceweasel]]></category>
		<category><![CDATA[web]]></category>

		<guid isPermaLink="false">http://blog.trollgod.org.uk/?p=358</guid>
		<description><![CDATA[<p>Firefox[1] 3.5 has been out for a while now, but I&#8217;ve only recently managed to switch due to the program not starting up unless I use a weird command line hack.</p> <p>By using the strace command I found it was hanging on a futex call, starting in safe-mode and even deleting .mozilla didn&#8217;t fix <span style="color:#777"> . . . &#8594; Read More: <a href="http://blog.trollgod.org.uk/2009/09/firefox-3-5-startup-problem-solved/">Firefox 3.5 startup problem (solved)</a></span>]]></description>
			<content:encoded><![CDATA[<p>Firefox<sup>[<a name="id394062" href="#ftn.id394062">1</a>]</sup> 3.5 has been out for a while now, but I&#8217;ve only recently managed to switch due to the program not starting up unless I use a weird command line hack.</p>
<p>By using the strace command I found it was hanging on a futex call, starting in safe-mode and even deleting .mozilla didn&#8217;t fix it.  I found a <a href="http://support.mozilla.com/tiki-view_forum_thread.php?comments_parentId=379151&#038;forumId=1">forum thread</a> on the mozilla forum that shows I&#8217;m not the only one to come across this.  There was a fix described in a post linked from there, but it only worked by editing the launch command, and I&#8217;m not prepared to dig through the OS and replace every instance of the launcher to make it work.</p>
<p>Yesterday though I found the real culprit, it was padsp!  A long time ago I had set Firefox to use padsp in order to get flash sound to work correctly with pulseaudio.  I had totally forgotten I had done this, because I had made the change in /etc not in my home folder.</p>
<p>So if you find Firefox 3.5 won&#8217;t start on linux even though 3.0 works fine then check if you have a FIREFOX_DSP (or ICEWEASEL_DSP if on Debian) set somewhere.  For me the fix was this:</p>
<p>In file /etc/iceweasel/iceweaselrc:</p>
<pre>
# which /dev/dsp wrapper to use
ICEWEASEL_DSP="padsp"
</pre>
<p>See the ICEWEASEL_DSP line, delete it or comment it out and Iceweasel starts working.  If you are using vanilla Firefox then obviously replace every instance of the word iceweasel with firefox to implement the fix on your system.</p>
<p>Hope this helps someone.  Oh and flash now works fine with pulseaudio without the padsp thing too.</p>
<div class="footnote">
<p>
<sup>[<a name="ftn.id394062" href="#id394062">1</a>]</sup> I&#8217;m actually using <a href="http://packages.debian.org/experimental/iceweasel">Iceweasel</a> but it is Firefox in all but name so I&#8217;ll call it that here</p>
</div>
]]></content:encoded>
			<wfw:commentRss>http://blog.trollgod.org.uk/2009/09/firefox-3-5-startup-problem-solved/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Poor mans offsite backup</title>
		<link>http://blog.trollgod.org.uk/2009/05/poor-mans-offsite-backup/</link>
		<comments>http://blog.trollgod.org.uk/2009/05/poor-mans-offsite-backup/#comments</comments>
		<pubDate>Sat, 02 May 2009 07:00:34 +0000</pubDate>
		<dc:creator>Ghworg</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[Internet]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[backup]]></category>
		<category><![CDATA[gmail]]></category>

		<guid isPermaLink="false">http://blog.trollgod.org.uk/?p=192</guid>
		<description><![CDATA[<p>Before I got some proper offsite backup space* I used to make tarballs of files and dump them in my gmail. Not the most elegant solution but it worked and is free (I know about gmailfs, but I could never get it to work reliably).</p> <p>This is the script I used to send the <span style="color:#777"> . . . &#8594; Read More: <a href="http://blog.trollgod.org.uk/2009/05/poor-mans-offsite-backup/">Poor mans offsite backup</a></span>]]></description>
			<content:encoded><![CDATA[<p>Before I got some proper offsite backup space* I used to make tarballs of files and dump them in my gmail.  Not the most elegant solution but it worked and is free (I know about gmailfs, but I could never get it to work reliably).</p>
<p>This is the script I used to send the files:</p>
<div class="dean_ch" style="white-space: nowrap;">
<span class="co1">#!/usr/bin/env python</span><br />
<span class="kw1">import</span> <span class="kw3">getpass</span><br />
<span class="kw1">import</span> <span class="kw3">optparse</span><br />
<span class="kw1">import</span> <span class="kw3">smtplib</span><br />
<span class="kw1">import</span> <span class="kw3">sys</span></p>
<p><span class="kw1">from</span> <span class="kw3">email</span> <span class="kw1">import</span> Encoders<br />
<span class="kw1">from</span> <span class="kw3">email</span>.<span class="me1">MIMEBase</span> <span class="kw1">import</span> MIMEBase<br />
<span class="kw1">from</span> <span class="kw3">email</span>.<span class="me1">MIMEMultipart</span> <span class="kw1">import</span> MIMEMultipart</p>
<p>
opts = <span class="kw3">optparse</span>.<span class="me1">OptionParser</span><span class="br0">&#40;</span><span class="br0">&#41;</span><br />
opts.<span class="me1">add_option</span><span class="br0">&#40;</span><span class="st0">&#8216;-u&#8217;</span>, <span class="st0">&#8216;&#8211;username&#8217;</span><span class="br0">&#41;</span><br />
opts.<span class="me1">add_option</span><span class="br0">&#40;</span><span class="st0">&#8216;-p&#8217;</span>, <span class="st0">&#8216;&#8211;password&#8217;</span><span class="br0">&#41;</span><br />
<span class="br0">&#40;</span>options, args<span class="br0">&#41;</span> = opts.<span class="me1">parse_args</span><span class="br0">&#40;</span><span class="br0">&#41;</span><br />
<span class="kw1">if</span> <span class="kw2">len</span><span class="br0">&#40;</span>args<span class="br0">&#41;</span> &lt; <span class="nu0">1</span>:<br />
&nbsp; &nbsp; <span class="kw1">print</span> <span class="st0">&quot;Usage: send_file_to_gmail.py [-u user] [-p pass] filename&quot;</span><br />
&nbsp; &nbsp; <span class="kw3">sys</span>.<span class="me1">exit</span><span class="br0">&#40;</span><span class="nu0">0</span><span class="br0">&#41;</span></p>
<p><span class="kw1">if</span> options.<span class="me1">username</span> == <span class="kw2">None</span>:<br />
&nbsp; &nbsp; options.<span class="me1">username</span> = <span class="kw2">raw_input</span><span class="br0">&#40;</span><span class="st0">&quot;Username: &quot;</span><span class="br0">&#41;</span><br />
<span class="kw1">if</span> options.<span class="me1">password</span> == <span class="kw2">None</span>:<br />
&nbsp; &nbsp; options.<span class="me1">password</span> = <span class="kw3">getpass</span>.<span class="kw3">getpass</span><span class="br0">&#40;</span><span class="br0">&#41;</span><br />
<span class="kw1">if</span> options.<span class="me1">username</span><span class="br0">&#91;</span><span class="kw2">len</span><span class="br0">&#40;</span>options.<span class="me1">username</span><span class="br0">&#41;</span><span class="nu0">-10</span>:<span class="br0">&#93;</span> != <span class="st0">&quot;@gmail.com&quot;</span>:<br />
&nbsp; &nbsp; options.<span class="me1">username</span> += <span class="st0">&quot;@gmail.com&quot;</span></p>
<p>
msg = MIMEMultipart<span class="br0">&#40;</span><span class="br0">&#41;</span><br />
msg<span class="br0">&#91;</span><span class="st0">&#8216;Subject&#8217;</span><span class="br0">&#93;</span> = <span class="st0">&quot;Backup of %s&quot;</span> % args<span class="br0">&#91;</span><span class="nu0">0</span><span class="br0">&#93;</span><br />
msg<span class="br0">&#91;</span><span class="st0">&#8216;From&#8217;</span><span class="br0">&#93;</span> = options.<span class="me1">username</span><br />
msg<span class="br0">&#91;</span><span class="st0">&#8216;To&#8217;</span><span class="br0">&#93;</span> = options.<span class="me1">username</span></p>
<p>msg.<span class="me1">preamble</span> = <span class="st0">&quot;Backup of %s&quot;</span> % args<span class="br0">&#91;</span><span class="nu0">0</span><span class="br0">&#93;</span><br />
msg.<span class="me1">epilogue</span> = <span class="st0">&quot; &quot;</span></p>
<p>fp = <span class="kw2">open</span><span class="br0">&#40;</span>args<span class="br0">&#91;</span><span class="nu0">0</span><span class="br0">&#93;</span>, <span class="st0">&quot;rb&quot;</span><span class="br0">&#41;</span><br />
atfile = MIMEBase<span class="br0">&#40;</span><span class="st0">&quot;application&quot;</span>, <span class="st0">&quot;octet-stream&quot;</span><span class="br0">&#41;</span><br />
atfile.<span class="me1">set_payload</span><span class="br0">&#40;</span>fp.<span class="me1">read</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><br />
fp.<span class="me1">close</span><span class="br0">&#40;</span><span class="br0">&#41;</span><br />
Encoders.<span class="me1">encode_base64</span><span class="br0">&#40;</span>atfile<span class="br0">&#41;</span><br />
atfile.<span class="me1">add_header</span><span class="br0">&#40;</span><span class="st0">&quot;Content-Disposition&quot;</span>, <span class="st0">&quot;attachment&quot;</span>, filename=args<span class="br0">&#91;</span><span class="nu0">0</span><span class="br0">&#93;</span><span class="br0">&#41;</span><br />
msg.<span class="me1">attach</span><span class="br0">&#40;</span>atfile<span class="br0">&#41;</span></p>
<p>s = <span class="kw3">smtplib</span>.<span class="me1">SMTP</span><span class="br0">&#40;</span><span class="br0">&#41;</span><br />
<span class="co1">#s.connect(&quot;localhost&quot;, &quot;8025&quot;)</span><br />
s.<span class="me1">connect</span><span class="br0">&#40;</span><span class="st0">&quot;smtp.gmail.com&quot;</span><span class="br0">&#41;</span><br />
s.<span class="me1">ehlo</span><span class="br0">&#40;</span><span class="br0">&#41;</span><br />
s.<span class="me1">starttls</span><span class="br0">&#40;</span><span class="br0">&#41;</span><br />
s.<span class="me1">ehlo</span><span class="br0">&#40;</span><span class="br0">&#41;</span><br />
s.<span class="me1">login</span><span class="br0">&#40;</span>options.<span class="me1">username</span>, options.<span class="me1">password</span><span class="br0">&#41;</span><br />
<span class="kw1">print</span> <span class="st0">&quot;Sending %s&quot;</span> % args<span class="br0">&#91;</span><span class="nu0">0</span><span class="br0">&#93;</span><br />
s.<span class="me1">sendmail</span><span class="br0">&#40;</span>options.<span class="me1">username</span>, options.<span class="me1">username</span>, msg.<span class="me1">as_string</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><br />
s.<span class="me1">close</span><span class="br0">&#40;</span><span class="br0">&#41;</span><br />
&nbsp;</div>
<p>The above code is made available under the <a href="http://www.opensource.org/licenses/mit-license.php">MIT</a> license.</p>
<p>* While I am writing this the Dreamhost backup space I use has been down for about two weeks (it came back briefly a couple of days ago but is back down again now).  I can&#8217;t complain too much as it is a free extra they throw in with the hosting package but I may have to restart my gmail sending if this keeps up.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.trollgod.org.uk/2009/05/poor-mans-offsite-backup/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Virgin Media are petty scumbags</title>
		<link>http://blog.trollgod.org.uk/2009/04/virgin-media-are-petty-scumbags/</link>
		<comments>http://blog.trollgod.org.uk/2009/04/virgin-media-are-petty-scumbags/#comments</comments>
		<pubDate>Wed, 29 Apr 2009 18:27:56 +0000</pubDate>
		<dc:creator>Ghworg</dc:creator>
				<category><![CDATA[Admin]]></category>
		<category><![CDATA[Hardware]]></category>
		<category><![CDATA[Internet]]></category>
		<category><![CDATA[bandwidth]]></category>
		<category><![CDATA[cablemodem]]></category>
		<category><![CDATA[munin]]></category>
		<category><![CDATA[snmp]]></category>

		<guid isPermaLink="false">http://blog.trollgod.org.uk/?p=150</guid>
		<description><![CDATA[<p>For a few days now I&#8217;ve been working (a few minutes at a time) on writing a post about how to monitor your bandwidth usage using munin by directly querying your cable-modem. Today however, when I checked my nice munin graph I found it had stopped working at about 8AM. Some further diagnostic procedures <span style="color:#777"> . . . &#8594; Read More: <a href="http://blog.trollgod.org.uk/2009/04/virgin-media-are-petty-scumbags/">Virgin Media are petty scumbags</a></span>]]></description>
			<content:encoded><![CDATA[<p>For a few days now I&#8217;ve been working (a few minutes at a time) on writing a post about how to monitor your bandwidth usage using <a href="http://munin.projects.linpro.no/">munin</a> by directly querying your cable-modem.  Today however, when I checked my nice munin graph I found it had stopped working at about 8AM.  Some further diagnostic procedures revealed that the cable modem was no longer responding to <a href="http://en.wikipedia.org/wiki/Simple_Network_Management_Protocol">SNMP</a> requests.</p>
<p>After a bit of googling I discovered the reason for this is that my ISP, Virgin Media, have deliberately disabled SNMP access.  Reports vary on the reasons for this, some claim &#8220;performance&#8221; others &#8220;security&#8221;, but both are utterly bogus reasons.  All this does is deny customers basic information about their connection like bandwidth usage, and I can only conclude that Virgin Media want to make it more difficult for people to dispute their figures.</p>
<p>This isn&#8217;t enough to make me ditch VM, but it has pissed me off, and the next time I move house VM are going to be waaay down the list of providers I&#8217;ll look at.</p>
<p>PS.  My router doesn&#8217;t support SNMP either so I can&#8217;t use that.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.trollgod.org.uk/2009/04/virgin-media-are-petty-scumbags/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Maintaining a WordPress install with git</title>
		<link>http://blog.trollgod.org.uk/2009/04/maintaining-a-wordpress-install-with-git/</link>
		<comments>http://blog.trollgod.org.uk/2009/04/maintaining-a-wordpress-install-with-git/#comments</comments>
		<pubDate>Thu, 23 Apr 2009 06:00:37 +0000</pubDate>
		<dc:creator>Ghworg</dc:creator>
				<category><![CDATA[Internet]]></category>
		<category><![CDATA[Wordpress]]></category>
		<category><![CDATA[git]]></category>
		<category><![CDATA[versioncontrol]]></category>

		<guid isPermaLink="false">http://blog.trollgod.org.uk/?p=200</guid>
		<description><![CDATA[<p>A while ago I started tracking WordPress updates using Subversion. Instead of downloading the official release from the WordPress website I checked out the code from the stable branch of their Subversion repo. This made upgrading as simple as running &#8220;svn up&#8221; and I didn&#8217;t lose any modifications I had made to the code.</p> <span style="color:#777"> . . . &#8594; Read More: <a href="http://blog.trollgod.org.uk/2009/04/maintaining-a-wordpress-install-with-git/">Maintaining a WordPress install with git</a></span>]]></description>
			<content:encoded><![CDATA[<p>A while ago I started tracking <a href="http://wordpress.org/">WordPress</a> updates using <a href="http://subversion.tigris.org/">Subversion</a>.  Instead of downloading the official release from the <a href="http://wordpress.org/download/">WordPress website</a> I checked out the code from the stable branch of their <a href="http://wordpress.org/download/svn/">Subversion repo</a>.  This made upgrading as simple as running &#8220;svn up&#8221; and I didn&#8217;t lose any modifications I had made to the code.</p>
<p>While this worked very well it does have one big drawback, it means I can&#8217;t put the themes and plugins I use into version control since they are inside the official svn checked out dirs.</p>
<p>Recently I&#8217;ve been switching to <a href="http://git.or.cz/index.html">git</a> and thought that switching the WordPress install to git would solve this problem.  My first attempt was using the git-svn tool to convert the upstream subversion repo to a local git one.  This would have enabled something very similar to what I was doing before with the &#8220;svn up&#8221; command, one git-svn command would have updated the code to the latest version.</p>
<p>The problem with that idea is that the WordPress repo contains over 10,000 revisions.  Duplicating that via git-svn would have taken days and all I really need is the current version.  I looked for a while to see if there was a way to limit the number of revisions copied but apparently there isn&#8217;t.</p>
<p>So, I fall back to searching the web and I came across <a href="http://ianloic.com/2008/09/06/tracking-wordpress-using-git/">Tracking WordPress using Git</a>, which is pretty close to what I wanted.  It is a little bit more work to do the updates that way but not that much.</p>
<p>What I need though is an internal dev version of the site on one branch, the live site on another and the upstream code on a third.  Then I need to push the live branch to my web host, and I also need to be able to pull any emergency fixes I make direct on the live site back into my local git repos.  Pushing changes with git is a little tricky since a push doesn&#8217;t update the checked out files, but I found a helpful blog entry <a href="http://joemaller.com/2008/11/25/a-web-focused-git-workflow/">A web focused git work-flow</a>, which gives me exactly what I want.</p>
<p>The one remaining problem I have is I don&#8217;t completely understand how git merges work.  The internal dev branch and the live branch have some differences I don&#8217;t want merged, paths etc.  Whenever I try to merge the branches though it invariably automatically changes one branch to exactly match the other and auto-commits.  I&#8217;m sure git can do this, merge some changes but not others without manual intervention each time but I haven&#8217;t worked out how yet.</p>
<p>Okay, after a bit more time working with this setup it seems the problem is bi-directional merges.  Merging from dev to live works great right up until the point I do a merge from live to dev, at which point git seems to forget that there is some stuff that I don&#8217;t want merged next time I go from dev to live.  Preventing the auto-commit makes this manageable though, to do this you (confusingly) need to specify &#8220;&#8211;no-commit &#8211;no-ff&#8221;.  You&#8217;d think the no-commit would be enough on its own but apparently not.</p>
<p>So in my local copy I have 3 branches:</p>
<ul>
<li>master, the extracted WordPress tarball</li>
<li>internal, my internal development/test site</li>
<li>external, copy of the live site</li>
</ul>
<p>I have the following settings set on my local git repo (private details redacted) to make pushing changes easier, I don&#8217;t have to remember any parameters for the git push command.</p>
<pre>
branch.internal.remote=origin
branch.internal.merge=refs/heads/internal
remote.external.url=ssh://$USER@$HOST/~/$GIT_PATH
remote.external.fetch=+refs/heads/*:refs/remotes/external/*
branch.external.merge=external
branch.external.remote=external
</pre>
<p>Then on my web host I have the bare git repo at $GIT_PATH that gets pushed to, and the actual live site.  Both of those only have the external branch.</p>
<p>To update the live site all I need to do is make the changes on my local copy of the external branch, then run &#8220;git push&#8221;.  This sends the changes up to the bare repo, which then automatically updates the live site.</p>
<p>Then when a new version WordPress gets released, what I will do is</p>
<ol>
<li>Switch to the master branch.</li>
<li>Delete everything except the git dir.</li>
<li>Unpack the new files to replace the deleted ones.</li>
<li>Commit those to git and it will work out what has changed for that release.</li>
<li>Change to the other branches in turn and git merge from the master branch.</li>
</ol>
<p>This should update me to the latest release without losing any of my local themes, plugins or mods.</p>
<p>I could go one step further and create &#8220;upstream&#8221; branches for each plugin I use in a similar manner to the main upstream WordPress branch.  That would allow me to mod the plugins, and still upgrade them easily.  I&#8217;m not going to do that though (yet) as I think it would be more trouble than it is worth.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.trollgod.org.uk/2009/04/maintaining-a-wordpress-install-with-git/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>How to Abuse the New DiggBar for Fun and Profit</title>
		<link>http://blog.trollgod.org.uk/2009/04/how-to-abuse-the-new-diggbar-for-fun-and-profit/</link>
		<comments>http://blog.trollgod.org.uk/2009/04/how-to-abuse-the-new-diggbar-for-fun-and-profit/#comments</comments>
		<pubDate>Fri, 10 Apr 2009 18:02:17 +0000</pubDate>
		<dc:creator>Ghworg</dc:creator>
				<category><![CDATA[Internet]]></category>
		<category><![CDATA[digg]]></category>
		<category><![CDATA[link]]></category>
		<category><![CDATA[web]]></category>

		<guid isPermaLink="false">http://blog.trollgod.org.uk/?p=261</guid>
		<description><![CDATA[<p>My cranky cynical old heart bursts with joy at the mere thought of Kevin Rose working the drive through window of McDonald’s asking people if they “want fries with that”. In fact I’m full prepared to strip down to a loincloth, dance and chant around a fire, and ritualistically sacrifice a live chicken if <span style="color:#777"> . . . &#8594; Read More: <a href="http://blog.trollgod.org.uk/2009/04/how-to-abuse-the-new-diggbar-for-fun-and-profit/">How to Abuse the New DiggBar for Fun and Profit</a></span>]]></description>
			<content:encoded><![CDATA[<p>My cranky cynical old heart bursts with joy at the mere thought of Kevin Rose working the drive through window of McDonald’s asking people if they “want fries with that”. In fact I’m full prepared to strip down to a loincloth, dance and chant around a fire, and ritualistically sacrifice a live chicken if I honestly felt it would help</p>
<p>via <a href="http://www.wolf-howl.com/socialmedia/abuse-diggbar-fun-profit/">How to Abuse the New DiggBar for Fun and Profit</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.trollgod.org.uk/2009/04/how-to-abuse-the-new-diggbar-for-fun-and-profit/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Twitter to XMPP (Jabber)</title>
		<link>http://blog.trollgod.org.uk/2009/03/twitter-to-xmpp-jabber/</link>
		<comments>http://blog.trollgod.org.uk/2009/03/twitter-to-xmpp-jabber/#comments</comments>
		<pubDate>Sat, 21 Mar 2009 21:23:50 +0000</pubDate>
		<dc:creator>Ghworg</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[Internet]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[project]]></category>
		<category><![CDATA[twitter]]></category>
		<category><![CDATA[xmpp]]></category>

		<guid isPermaLink="false">http://blog.trollgod.org.uk/?p=118</guid>
		<description><![CDATA[<p>The other day I noticed that irssi (the IRC client I use) had a XMPP plugin. It occurred to me that since I&#8217;m on IRC a lot it would be really cool to pull microblog feeds into irssi via this plugin.</p> <p>For identi.ca this was a doddle, since laconica supports XMPP natively. Twitter however <span style="color:#777"> . . . &#8594; Read More: <a href="http://blog.trollgod.org.uk/2009/03/twitter-to-xmpp-jabber/">Twitter to XMPP (Jabber)</a></span>]]></description>
			<content:encoded><![CDATA[<p>The other day I noticed that <a href="http://irssi.org/">irssi</a> (the <a href="http://en.wikipedia.org/wiki/Internet_Relay_Chat">IRC</a> client I use) had a <a href="http://cybione.org/~irssi-xmpp/">XMPP plugin</a>.  It occurred to me that since I&#8217;m on IRC a lot it would be really cool to pull microblog feeds into irssi via this plugin.</p>
<p>For <a href="http://identi.ca/ghworg">identi.ca</a> this was a doddle, since <a href="http://laconi.ca/">laconica</a> supports <a href="http://en.wikipedia.org/wiki/Extensible_Messaging_and_Presence_Protocol">XMPP</a> natively.  <a href="http://twitter.com/Ghworg">Twitter</a> however was a problem.  I believe twitter used to support XMPP but they pulled that feature for who knows what reason.</p>
<p>There are a couple of apps that will provided a twitter->XMPP gateway for you.  I looked at <a href="http://dustin.github.com/twitterspy/">twitterspy</a>, but it sounded like a pain to install.  So at first I tried <a href="https://www.tweet.im/">tweet.im</a>, which worked after a fashion.  It got the tweets into irssi, but it did it in some weird way so that irssi didn&#8217;t realise new messages had come in and hence it didn&#8217;t indicate there was activity when I was in a different irssi window.</p>
<p>At this point the little voice in my head that is the bane of my life started saying &#8220;You know, you could probably write your own gateway app.  How hard could it be?&#8221;.  Like a fool I listened to this voice, but for once it didn&#8217;t turn out disastrously.  A few hours later I had a functioning (one-way) twitter->XMPP app, written in python.</p>
<p>I&#8217;ve since learned that twitterspy has been rewritten in python and would have been a doddle to install.  Not only that but there is a public instance of it I could have used.  Still, I&#8217;m not immune to <a href="http://en.wikipedia.org/wiki/Not_Invented_Here">NIH</a> syndrome and having my own app to do it is nice.  If you want a twitter->XMPP gateway of your own though I suggest you try <a href="http://dustin.github.com/twitterspy/">twitterspy</a> first as it is much more capable (and mature) than my noddy little script.</p>
<p>But if you are interested, and because I like to boast about my tiny little achievements, here is twixm (I&#8217;ll give it its own page when I get round to it, but till then it is going to live in this blog post).</p>
<div class="dean_ch" style="white-space: nowrap;">
<p><span class="co1">#!/usr/bin/python -u</span><br />
<span class="co1">#</span><br />
<span class="co1"># This program is free software: you can redistribute it and/or modify</span><br />
<span class="co1"># it under the terms of the GNU General Public License as published by</span><br />
<span class="co1"># the Free Software Foundation, either version 2 of the License, or</span><br />
<span class="co1"># (at your option) any later version.</span><br />
<span class="co1">#</span><br />
<span class="co1"># This program is distributed in the hope that it will be useful,</span><br />
<span class="co1"># but WITHOUT ANY WARRANTY; without even the implied warranty of</span><br />
<span class="co1"># MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. &nbsp;See the</span><br />
<span class="co1"># GNU General Public License for more details.</span><br />
<span class="co1">#</span><br />
<span class="co1"># You should have received a copy of the GNU General Public License</span><br />
<span class="co1"># along with this program. &nbsp;If not, see &lt;http://www.gnu.org/licenses/&gt;.</span><br />
<span class="co1"># </span></p>
<p>__author__ = <span class="st0">&quot;Ghworg&quot;</span><br />
__version__ = <span class="st0">&quot;1.0&quot;</span><br />
__description__ = <span class="st0">&quot;Twitter to XMPP gateway&quot;</span></p>
<p>
<span class="kw1">import</span> <span class="kw3">logging</span>, <span class="kw3">os</span>, <span class="kw3">signal</span>, <span class="kw3">sys</span>, <span class="kw3">threading</span>, <span class="kw3">time</span>, <span class="kw3">urllib</span></p>
<p><span class="kw1">import</span> simplejson</p>
<p><span class="kw1">try</span>:<br />
&nbsp; &nbsp; <span class="kw1">from</span> iniparse.<span class="me1">compat</span> <span class="kw1">import</span> <span class="kw3">ConfigParser</span><br />
<span class="kw1">except</span> <span class="kw2">ImportError</span>:<br />
&nbsp; &nbsp; <span class="kw1">from</span> <span class="kw3">ConfigParser</span> <span class="kw1">import</span> <span class="kw3">ConfigParser</span></p>
<p><span class="kw1">from</span> pyxmpp.<span class="me1">jid</span> <span class="kw1">import</span> JID<br />
<span class="kw1">from</span> pyxmpp.<span class="me1">jabber</span>.<span class="me1">simple</span> <span class="kw1">import</span> send_message</p>
<p>
<span class="kw1">class</span> WebApiOpener<span class="br0">&#40;</span><span class="kw3">urllib</span>.<span class="me1">FancyURLopener</span><span class="br0">&#41;</span>:<br />
&nbsp; &nbsp; <span class="st0">&quot;&quot;</span><span class="st0">&quot;<br />
&nbsp; &nbsp; Provides a way for HTTP Basic authentication to take place without<br />
&nbsp; &nbsp; prompting the user for a username and password like FancyURLopener<br />
&nbsp; &nbsp; would.<br />
&nbsp; &nbsp; &quot;</span><span class="st0">&quot;&quot;</span><br />
&nbsp; &nbsp; <span class="kw1">def</span> <span class="kw4">__init__</span><span class="br0">&#40;</span><span class="kw2">self</span>, username, password<span class="br0">&#41;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">urllib</span>.<span class="me1">FancyURLopener</span>.<span class="kw4">__init__</span><span class="br0">&#40;</span><span class="kw2">self</span>,<span class="br0">&#123;</span><span class="br0">&#125;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">self</span>.<span class="me1">username</span> = username<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">self</span>.<span class="me1">password</span> = password<br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span class="kw1">def</span> prompt_user_passwd<span class="br0">&#40;</span><span class="kw2">self</span>, host, realm<span class="br0">&#41;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="st0">&quot;&quot;</span><span class="st0">&quot;Handle Basic Auth automatically.&quot;</span><span class="st0">&quot;&quot;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> <span class="br0">&#40;</span><span class="kw2">self</span>.<span class="me1">username</span>, <span class="kw2">self</span>.<span class="me1">password</span><span class="br0">&#41;</span></p>
<p>
<span class="kw1">class</span> CaseSensitiveConfigParser<span class="br0">&#40;</span><span class="kw3">ConfigParser</span><span class="br0">&#41;</span>:<br />
&nbsp; &nbsp; <span class="st0">&quot;&quot;</span><span class="st0">&quot;Case Sensitive version of ConfigParser&quot;</span><span class="st0">&quot;&quot;</span><br />
&nbsp; &nbsp; <span class="kw1">def</span> <span class="kw4">__init__</span><span class="br0">&#40;</span><span class="kw2">self</span><span class="br0">&#41;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">ConfigParser</span>.<span class="kw4">__init__</span><span class="br0">&#40;</span><span class="kw2">self</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; <span class="kw1">def</span> optionxform<span class="br0">&#40;</span><span class="kw2">self</span>, option<span class="br0">&#41;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="st0">&quot;&quot;</span><span class="st0">&quot;Make keys case-sensitive&quot;</span><span class="st0">&quot;&quot;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> <span class="kw2">str</span><span class="br0">&#40;</span>option<span class="br0">&#41;</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span class="kw1">def</span> getAndType<span class="br0">&#40;</span><span class="kw2">self</span>, section, option<span class="br0">&#41;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="st0">&quot;&quot;</span><span class="st0">&quot;Try to guess variable type and convert to type before returning&quot;</span><span class="st0">&quot;&quot;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; rawVal = <span class="kw2">self</span>.<span class="me1">get</span><span class="br0">&#40;</span>section, option<span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; isInt = <span class="kw2">True</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; isFloat = <span class="kw2">True</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">for</span> c <span class="kw1">in</span> rawVal:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="kw1">not</span> c.<span class="me1">isdigit</span><span class="br0">&#40;</span><span class="br0">&#41;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; isInt = <span class="kw2">False</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> c != <span class="st0">&#8216;.&#8217;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; isFloat = <span class="kw2">False</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> isInt:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> <span class="kw2">int</span><span class="br0">&#40;</span>rawVal<span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">elif</span> isFloat:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> <span class="kw2">float</span><span class="br0">&#40;</span>rawVal<span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">else</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> rawVal</p>
<p>
<span class="kw1">def</span> msgToXMPP<span class="br0">&#40;</span>msg<span class="br0">&#41;</span>:<br />
&nbsp; &nbsp; <span class="st0">&quot;&quot;</span><span class="st0">&quot;Send a message to Jabber (XMPP)&quot;</span><span class="st0">&quot;&quot;</span><br />
&nbsp; &nbsp; jid = JID<span class="br0">&#40;</span>config<span class="br0">&#91;</span><span class="st0">&#8216;jid&#8217;</span><span class="br0">&#93;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="kw1">if</span> <span class="kw1">not</span> jid.<span class="kw3">resource</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; jid = JID<span class="br0">&#40;</span>jid.<span class="me1">node</span>, jid.<span class="me1">domain</span>, <span class="st0">&#8216;send_message&#8217;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; recpt = JID<span class="br0">&#40;</span>config<span class="br0">&#91;</span><span class="st0">&#8216;jid&#8217;</span><span class="br0">&#93;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="kw3">logging</span>.<span class="me1">debug</span><span class="br0">&#40;</span><span class="st0">&#8216;Sending to XMPP &nbsp;%s&#8217;</span> % msg<span class="br0">&#41;</span><br />
&nbsp; &nbsp; send_message<span class="br0">&#40;</span>jid, config<span class="br0">&#91;</span><span class="st0">&#8216;XMPPpass&#8217;</span><span class="br0">&#93;</span>, recpt, msg<span class="br0">&#41;</span></p>
<p><span class="kw1">def</span> getTweets<span class="br0">&#40;</span><span class="kw3">site</span>, maxTweets=<span class="nu0">1</span><span class="br0">&#41;</span>:<br />
&nbsp; &nbsp; <span class="st0">&quot;&quot;</span><span class="st0">&quot;Read in a list of tweets made since the last check&quot;</span><span class="st0">&quot;&quot;</span><br />
&nbsp; &nbsp; <span class="kw1">if</span> <span class="kw3">site</span><span class="br0">&#91;</span><span class="nu0">0</span><span class="br0">&#93;</span> <span class="kw1">in</span> cache:<br />
&nbsp; &nbsp; &nbsp; &nbsp; url = <span class="st0">&#8216;%s?since_id=%d&#8217;</span> % <span class="br0">&#40;</span><span class="kw3">site</span><span class="br0">&#91;</span><span class="nu0">1</span><span class="br0">&#93;</span>, cache<span class="br0">&#91;</span><span class="kw3">site</span><span class="br0">&#91;</span><span class="nu0">0</span><span class="br0">&#93;</span><span class="br0">&#93;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="kw1">else</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; url = <span class="st0">&#8216;%s?count=%d&#8217;</span> % <span class="br0">&#40;</span><span class="kw3">site</span><span class="br0">&#91;</span><span class="nu0">1</span><span class="br0">&#93;</span>, maxTweets<span class="br0">&#41;</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; opener = WebApiOpener<span class="br0">&#40;</span><span class="kw3">site</span><span class="br0">&#91;</span><span class="nu0">2</span><span class="br0">&#93;</span>, <span class="kw3">site</span><span class="br0">&#91;</span><span class="nu0">3</span><span class="br0">&#93;</span><span class="br0">&#41;</span> &nbsp; &nbsp; &nbsp; &nbsp;<br />
&nbsp; &nbsp; <span class="kw1">try</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">logging</span>.<span class="me1">debug</span><span class="br0">&#40;</span><span class="st0">&#8216;Requesting %s&#8217;</span> % url<span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; webPage = opener.<span class="kw2">open</span><span class="br0">&#40;</span>url<span class="br0">&#41;</span> &nbsp; &nbsp; &nbsp; &nbsp;<br />
&nbsp; &nbsp; &nbsp; &nbsp; jsonData = simplejson.<span class="me1">load</span><span class="br0">&#40;</span>webPage<span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="st0">&#8216;error&#8217;</span> <span class="kw1">in</span> jsonData<span class="br0">&#41;</span> <span class="kw1">and</span> <span class="br0">&#40;</span>jsonData<span class="br0">&#91;</span><span class="st0">&#8216;error&#8217;</span><span class="br0">&#93;</span> != <span class="st0">&#8221;</span><span class="br0">&#41;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">logging</span>.<span class="me1">warning</span><span class="br0">&#40;</span><span class="st0">&#8216;Error from server %s: %s&#8217;</span> % <span class="br0">&#40;</span>url, jsonData<span class="br0">&#91;</span><span class="st0">&#8216;error&#8217;</span><span class="br0">&#93;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; jsonData = <span class="kw2">None</span><br />
&nbsp; &nbsp; <span class="kw1">except</span> <span class="kw2">IOError</span>, e:<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">logging</span>.<span class="me1">error</span><span class="br0">&#40;</span>e<span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">logging</span>.<span class="me1">error</span><span class="br0">&#40;</span><span class="st0">&#8216;URL = %s&#8217;</span> % src<span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="kw1">except</span> <span class="kw2">ValueError</span>, e:<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">logging</span>.<span class="me1">error</span><span class="br0">&#40;</span>e<span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">logging</span>.<span class="me1">error</span><span class="br0">&#40;</span><span class="st0">&#8216;URL = %s&#8217;</span> % src<span class="br0">&#41;</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; maxID = <span class="nu0">0</span><br />
&nbsp; &nbsp; <span class="kw1">for</span> tweet <span class="kw1">in</span> jsonData:<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> tweet<span class="br0">&#91;</span>u<span class="st0">&#8216;id&#8217;</span><span class="br0">&#93;</span> &gt; maxID:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; maxID = tweet<span class="br0">&#91;</span>u<span class="st0">&#8216;id&#8217;</span><span class="br0">&#93;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; msg = <span class="st0">&#8216;%s (%s): %s&#8217;</span> % <span class="br0">&#40;</span>tweet<span class="br0">&#91;</span>u<span class="st0">&#8216;user&#8217;</span><span class="br0">&#93;</span><span class="br0">&#91;</span>u<span class="st0">&#8216;screen_name&#8217;</span><span class="br0">&#93;</span>, <span class="kw3">site</span><span class="br0">&#91;</span><span class="nu0">0</span><span class="br0">&#93;</span>, tweet<span class="br0">&#91;</span>u<span class="st0">&#8216;text&#8217;</span><span class="br0">&#93;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">logging</span>.<span class="me1">debug</span><span class="br0">&#40;</span><span class="st0">&#8216;Read tweet &nbsp;%s&#8217;</span> % msg<span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; msgToXMPP<span class="br0">&#40;</span>msg<span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="kw1">return</span> maxID</p>
<p><span class="kw1">def</span> run<span class="br0">&#40;</span><span class="br0">&#41;</span>:<br />
&nbsp; &nbsp; <span class="st0">&quot;&quot;</span><span class="st0">&quot;Thread&quot;</span><span class="st0">&quot;&quot;</span><br />
&nbsp; &nbsp; <span class="kw1">while</span> <span class="kw2">True</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; startSignal.<span class="me1">wait</span><span class="br0">&#40;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> quitSignal.<span class="me1">isSet</span><span class="br0">&#40;</span><span class="br0">&#41;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; startSignal.<span class="me1">clear</span><span class="br0">&#40;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">for</span> <span class="kw3">site</span> <span class="kw1">in</span> config<span class="br0">&#91;</span><span class="st0">&#8216;site&#8217;</span><span class="br0">&#93;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; maxID = getTweets<span class="br0">&#40;</span><span class="kw3">site</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="kw3">site</span><span class="br0">&#91;</span><span class="nu0">0</span><span class="br0">&#93;</span> <span class="kw1">not</span> <span class="kw1">in</span> cache<span class="br0">&#41;</span> <span class="kw1">or</span> <span class="br0">&#40;</span>maxID &gt; cache<span class="br0">&#91;</span><span class="kw3">site</span><span class="br0">&#91;</span><span class="nu0">0</span><span class="br0">&#93;</span><span class="br0">&#93;</span><span class="br0">&#41;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; cache<span class="br0">&#91;</span><span class="kw3">site</span><span class="br0">&#91;</span><span class="nu0">0</span><span class="br0">&#93;</span><span class="br0">&#93;</span> = maxID</p>
<p><span class="kw1">def</span> readConfig<span class="br0">&#40;</span><span class="br0">&#41;</span>:<br />
&nbsp; &nbsp; <span class="st0">&quot;&quot;</span><span class="st0">&quot;Load config settings&quot;</span><span class="st0">&quot;&quot;</span><br />
&nbsp; &nbsp; config = <span class="br0">&#123;</span><span class="br0">&#125;</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; cfgfile = <span class="kw3">os</span>.<span class="me1">path</span>.<span class="me1">join</span><span class="br0">&#40;</span><span class="kw3">os</span>.<span class="me1">path</span>.<span class="me1">expanduser</span><span class="br0">&#40;</span><span class="st0">&#8216;~&#8217;</span><span class="br0">&#41;</span>, <span class="st0">&#8216;.twixmrc&#8217;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="kw3">parser</span> = CaseSensitiveConfigParser<span class="br0">&#40;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="kw3">parser</span>.<span class="me1">read</span><span class="br0">&#40;</span>cfgfile<span class="br0">&#41;</span><br />
&nbsp; &nbsp; settings = <span class="br0">&#123;</span><span class="br0">&#125;</span><br />
&nbsp; &nbsp; <span class="kw1">for</span> section <span class="kw1">in</span> <span class="kw3">parser</span>.<span class="me1">sections</span><span class="br0">&#40;</span><span class="br0">&#41;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="st0">&#8216;XMPP&#8217;</span> == section:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">for</span> optname <span class="kw1">in</span> <span class="kw3">parser</span>.<span class="me1">options</span><span class="br0">&#40;</span>section<span class="br0">&#41;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; config<span class="br0">&#91;</span>optname<span class="br0">&#93;</span> = <span class="kw3">parser</span>.<span class="me1">getAndType</span><span class="br0">&#40;</span>section, optname<span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">else</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; siteName = section<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; siteUrl = <span class="kw3">parser</span>.<span class="me1">getAndType</span><span class="br0">&#40;</span>section, <span class="st0">&#8216;URL&#8217;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; siteUser = <span class="kw3">parser</span>.<span class="me1">getAndType</span><span class="br0">&#40;</span>section, <span class="st0">&#8216;Username&#8217;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; sitePass = <span class="kw3">parser</span>.<span class="me1">getAndType</span><span class="br0">&#40;</span>section, <span class="st0">&#8216;Password&#8217;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">site</span> = <span class="br0">&#40;</span>siteName, siteUrl, siteUser, sitePass<span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="st0">&#8216;site&#8217;</span> <span class="kw1">not</span> <span class="kw1">in</span> config:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; config<span class="br0">&#91;</span><span class="st0">&#8216;site&#8217;</span><span class="br0">&#93;</span> = <span class="br0">&#91;</span><span class="br0">&#93;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; config<span class="br0">&#91;</span><span class="st0">&#8216;site&#8217;</span><span class="br0">&#93;</span>.<span class="me1">append</span><span class="br0">&#40;</span><span class="kw3">site</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; config<span class="br0">&#91;</span><span class="st0">&#8216;cycleTime&#8217;</span><span class="br0">&#93;</span> = <span class="nu0">60.0</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span class="co1"># !!! Check for missing config settings and bail out</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span class="kw3">logging</span>.<span class="me1">debug</span><span class="br0">&#40;</span><span class="st0">&#8216;XMPP ID = %s&#8217;</span> % config<span class="br0">&#91;</span><span class="st0">&#8216;jid&#8217;</span><span class="br0">&#93;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="kw3">logging</span>.<span class="me1">debug</span><span class="br0">&#40;</span><span class="st0">&#8216;XMPP Pass = %s&#8217;</span> % config<span class="br0">&#91;</span><span class="st0">&#8216;XMPPpass&#8217;</span><span class="br0">&#93;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="kw3">logging</span>.<span class="me1">debug</span><span class="br0">&#40;</span><span class="st0">&#8216;Cycle Time = %s&#8217;</span> % config<span class="br0">&#91;</span><span class="st0">&#8216;cycleTime&#8217;</span><span class="br0">&#93;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="kw1">for</span> <span class="kw3">site</span> <span class="kw1">in</span> config<span class="br0">&#91;</span><span class="st0">&#8216;site&#8217;</span><span class="br0">&#93;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">logging</span>.<span class="me1">debug</span><span class="br0">&#40;</span><span class="st0">&#8216;Site: %s&#8217;</span> % <span class="kw3">site</span><span class="br0">&#91;</span><span class="nu0">0</span><span class="br0">&#93;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">logging</span>.<span class="me1">debug</span><span class="br0">&#40;</span><span class="st0">&#8216;<span class="es0">\t</span>URL: %s&#8217;</span> % <span class="kw3">site</span><span class="br0">&#91;</span><span class="nu0">1</span><span class="br0">&#93;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">logging</span>.<span class="me1">debug</span><span class="br0">&#40;</span><span class="st0">&#8216;<span class="es0">\t</span>User: %s&#8217;</span> % <span class="kw3">site</span><span class="br0">&#91;</span><span class="nu0">2</span><span class="br0">&#93;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">logging</span>.<span class="me1">debug</span><span class="br0">&#40;</span><span class="st0">&#8216;<span class="es0">\t</span>Pass: %s&#8217;</span> % <span class="kw3">site</span><span class="br0">&#91;</span><span class="nu0">3</span><span class="br0">&#93;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span class="kw1">return</span> config<br />
&nbsp; &nbsp; &nbsp; &nbsp; </p>
<p><span class="kw1">def</span> setupLogging<span class="br0">&#40;</span><span class="br0">&#41;</span>:<br />
&nbsp; &nbsp; <span class="st0">&quot;&quot;</span><span class="st0">&quot;Setup python logging to stdout&quot;</span><span class="st0">&quot;&quot;</span><br />
&nbsp; &nbsp; log = <span class="kw3">logging</span>.<span class="me1">getLogger</span><span class="br0">&#40;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; logformat = <span class="st0">&#8216;%(asctime)s %(levelname)s %(message)s&#8217;</span><br />
&nbsp; &nbsp; dateformat = <span class="st0">&#8216;%Y-%m-%d %H:%M:%S&#8217;</span><br />
&nbsp; &nbsp; frmttr = <span class="kw3">logging</span>.<span class="me1">Formatter</span><span class="br0">&#40;</span>logformat, dateformat<span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="co1">#if options.logfile:</span><br />
&nbsp; &nbsp; <span class="co1"># &nbsp; &nbsp;fhdlr = logging.FileHandler(options.logfile)</span><br />
&nbsp; &nbsp; <span class="co1"># &nbsp; &nbsp;fhdlr.setFormatter(frmttr)</span><br />
&nbsp; &nbsp; <span class="co1"># &nbsp; &nbsp;log.addHandler(fhdlr)</span><br />
&nbsp; &nbsp; <span class="kw1">if</span> <span class="kw3">sys</span>.<span class="me1">stdin</span>.<span class="me1">isatty</span><span class="br0">&#40;</span><span class="br0">&#41;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; shdlr = <span class="kw3">logging</span>.<span class="me1">StreamHandler</span><span class="br0">&#40;</span><span class="kw3">sys</span>.<span class="me1">stdout</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; shdlr.<span class="me1">setFormatter</span><span class="br0">&#40;</span>frmttr<span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; log.<span class="me1">addHandler</span><span class="br0">&#40;</span>shdlr<span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="co1">#log.setLevel(logging.DEBUG)</span><br />
&nbsp; &nbsp; log.<span class="me1">setLevel</span><span class="br0">&#40;</span><span class="kw3">logging</span>.<span class="me1">INFO</span><span class="br0">&#41;</span></p>
<p><span class="kw1">def</span> handler<span class="br0">&#40;</span>signum, frame<span class="br0">&#41;</span>:<br />
&nbsp; &nbsp; <span class="st0">&quot;&quot;</span><span class="st0">&quot;Handle various termination signals gracefully&quot;</span><span class="st0">&quot;&quot;</span><br />
&nbsp; &nbsp; <span class="kw3">logging</span>.<span class="me1">warning</span><span class="br0">&#40;</span><span class="st0">&#8216;Signal handler called with signal %d&#8217;</span> % signum<span class="br0">&#41;</span><br />
&nbsp; &nbsp; quitSignal.<span class="kw2">set</span><span class="br0">&#40;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; startSignal.<span class="kw2">set</span><span class="br0">&#40;</span><span class="br0">&#41;</span></p>
<p>
<span class="co1">###############################################################################</span><br />
<span class="co1"># Main</span><br />
<span class="co1">###############################################################################</span></p>
<p><span class="co1"># Set the signal handlers</span><br />
<span class="kw3">signal</span>.<span class="kw3">signal</span><span class="br0">&#40;</span><span class="kw3">signal</span>.<span class="me1">SIGTERM</span>, handler<span class="br0">&#41;</span><br />
<span class="kw3">signal</span>.<span class="kw3">signal</span><span class="br0">&#40;</span><span class="kw3">signal</span>.<span class="me1">SIGQUIT</span>, handler<span class="br0">&#41;</span><br />
<span class="kw3">signal</span>.<span class="kw3">signal</span><span class="br0">&#40;</span><span class="kw3">signal</span>.<span class="me1">SIGINT</span>, handler<span class="br0">&#41;</span></p>
<p>setupLogging<span class="br0">&#40;</span><span class="br0">&#41;</span></p>
<p>config = readConfig<span class="br0">&#40;</span><span class="br0">&#41;</span><br />
cache = <span class="br0">&#123;</span><span class="br0">&#125;</span></p>
<p>
quitSignal = <span class="kw3">threading</span>.<span class="me1">Event</span><span class="br0">&#40;</span><span class="br0">&#41;</span><br />
startSignal = <span class="kw3">threading</span>.<span class="me1">Event</span><span class="br0">&#40;</span><span class="br0">&#41;</span></p>
<p>runThread = <span class="kw3">threading</span>.<span class="me1">Thread</span><span class="br0">&#40;</span>target=run<span class="br0">&#41;</span><br />
runThread.<span class="me1">start</span><span class="br0">&#40;</span><span class="br0">&#41;</span></p>
<p><span class="kw1">while</span> <span class="kw2">False</span> == quitSignal.<span class="me1">isSet</span><span class="br0">&#40;</span><span class="br0">&#41;</span>:<br />
&nbsp; &nbsp; startSignal.<span class="kw2">set</span><span class="br0">&#40;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; count = <span class="nu0">0.0</span><br />
&nbsp; &nbsp; <span class="kw1">while</span> count &lt; config<span class="br0">&#91;</span><span class="st0">&#8216;cycleTime&#8217;</span><span class="br0">&#93;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; quitSignal.<span class="me1">wait</span><span class="br0">&#40;</span><span class="nu0">0.5</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; count += <span class="nu0">0.5</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> quitSignal.<span class="me1">isSet</span><span class="br0">&#40;</span><span class="br0">&#41;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">break</span><br />
<span class="kw3">logging</span>.<span class="me1">info</span><span class="br0">&#40;</span><span class="st0">&#8216;Exiting&#8217;</span><span class="br0">&#41;</span></p>
<p>&nbsp;</p></div>
<p>Update 2009-11-25:  I have created a page for <a href="/projects/twixm/">twixm</a> now.  Go there for the latest code and info.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.trollgod.org.uk/2009/03/twitter-to-xmpp-jabber/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Multiconica update</title>
		<link>http://blog.trollgod.org.uk/2009/03/multiconica-update/</link>
		<comments>http://blog.trollgod.org.uk/2009/03/multiconica-update/#comments</comments>
		<pubDate>Sun, 01 Mar 2009 05:14:16 +0000</pubDate>
		<dc:creator>Ghworg</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[Internet]]></category>
		<category><![CDATA[Javascript]]></category>
		<category><![CDATA[laconica]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[projects]]></category>
		<category><![CDATA[twitter]]></category>

		<guid isPermaLink="false">http://blog.trollgod.org.uk/?p=96</guid>
		<description><![CDATA[<p>I&#8217;ve fixed a small bug in my twitter/laconica combining script. HTML tags in tweets were being interpreted by the browser because I wasn&#8217;t escaping the &#60; and &#62; characters. That should be fixed now.</p> <p>In addition I&#8217;ve decided to give the script a better name, from now on it will be Multiconica.</p> <p>Download <span style="color:#777"> . . . &#8594; Read More: <a href="http://blog.trollgod.org.uk/2009/03/multiconica-update/">Multiconica update</a></span>]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve fixed a small bug in my twitter/laconica combining script.  HTML tags in tweets were being interpreted by the browser because I wasn&#8217;t escaping the &lt; and &gt; characters.  That should be fixed now.</p>
<p>In addition I&#8217;ve decided to give the script a better name, from now on it will be Multiconica.</p>
<p><a href='http://blog.trollgod.org.uk/wp-content/uploads/2009/03/multiconica.js'>Download Multiconica</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.trollgod.org.uk/2009/03/multiconica-update/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Offsite backup Catch-22</title>
		<link>http://blog.trollgod.org.uk/2009/02/offsite-backup-catch-22/</link>
		<comments>http://blog.trollgod.org.uk/2009/02/offsite-backup-catch-22/#comments</comments>
		<pubDate>Thu, 26 Feb 2009 17:10:02 +0000</pubDate>
		<dc:creator>Ghworg</dc:creator>
				<category><![CDATA[Admin]]></category>
		<category><![CDATA[Internet]]></category>
		<category><![CDATA[backup]]></category>

		<guid isPermaLink="false">http://blog.trollgod.org.uk/?p=91</guid>
		<description><![CDATA[<p>Over the past couple of days I&#8217;ve been setting up a secure offsite backup for my home machines. Dreamhost started offering 50GB of space for backups for free to their customers, this is vastly superior to the &#8220;send an archive to gmail every now and then&#8221; method I was using before.</p> <p>I decided to <span style="color:#777"> . . . &#8594; Read More: <a href="http://blog.trollgod.org.uk/2009/02/offsite-backup-catch-22/">Offsite backup Catch-22</a></span>]]></description>
			<content:encoded><![CDATA[<p>Over the past couple of days I&#8217;ve been setting up a secure offsite backup for my home machines.  <a href="http://www.dreamhost.com/">Dreamhost</a> started offering 50GB of space for backups for free to their customers, this is vastly superior to the &#8220;send an archive to gmail every now and then&#8221; method I was using before.</p>
<p>I decided to use <a href="http://duplicity.nongnu.org/">duplicity</a> as it will use scp as the transfer (among manu others), encrypts all the data and automatically does incremental backups transferring only the changed files.  Newer versions even support gmail and amazon s3 as backends, which is really cool but not something I need.</p>
<p>I had one problem setting it up, which was the obscure and unhelpful error reporting.</p>
<pre>
Traceback (most recent call last):
  File "/usr/bin/duplicity", line 463, in <module>
    with_tempdir(main)
  File "/usr/bin/duplicity", line 458, in with_tempdir
    fn()
  File "/usr/bin/duplicity", line 451, in main
    incremental_backup(sig_chain)
  File "/usr/bin/duplicity", line 186, in incremental_backup
    bytes_written = write_multivol("inc", tarblock_iter, globals.backend)
  File "/usr/bin/duplicity", line 87, in write_multivol
    globals.gpg_profile,globals.volsize)
  File "/usr/lib/python2.5/site-packages/duplicity/gpg.py", line 217, in GPGWriteFile
    file.write(data)
  File "/usr/lib/python2.5/site-packages/duplicity/gpg.py", line 125, in write
    return self.gpg_input.write(buf)
IOError: [Errno 32] Broken pipe
close failed: [Errno 32] Broken pipe
</pre>
<p>That is not a useful error message (and I&#8217;ve programmed in python), the actual error turned out to be a typo in the GPG key id I had entered.  Once I&#8217;d worked that out everything went fine.</p>
<p>The real problem is the catch-22 between security and recoverability.  In order for the data to be secure it needs to be encrypted, for that you need either a key or a password (or both for an encrypted key).  Therefore in order to restore the data you need a copy of that key/password, but the situations in which you are going to be restoring from the offsite backup are ones in which <strong>all</strong> your data and local backups have gone poof.  In which case the key will have gone poof too.</p>
<p>Okay, if you used <strong>just</strong> a password and memorized it then you&#8217;d be fine.  But a password you can memorize is probably too weak to be secure, certainly for me it is with my terrible memory.</p>
<p>So, in order to make the data recoverable the key used for encryption needs to be backed up offsite too, but then your security goes out the window.  So the key itself needs to be encrypted before sending it offsite, and there we have the catch-22.</p>
<p>Data needs to be encrypted to be secure, but we need to save the key to make the data recoverable, which makes the data insecure.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.trollgod.org.uk/2009/02/offsite-backup-catch-22/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Twitter and Laconica combined</title>
		<link>http://blog.trollgod.org.uk/2009/02/twitter-and-laconica-combined/</link>
		<comments>http://blog.trollgod.org.uk/2009/02/twitter-and-laconica-combined/#comments</comments>
		<pubDate>Sat, 21 Feb 2009 20:34:41 +0000</pubDate>
		<dc:creator>Ghworg</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[Internet]]></category>
		<category><![CDATA[Javascript]]></category>
		<category><![CDATA[laconica]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[projects]]></category>
		<category><![CDATA[twitter]]></category>

		<guid isPermaLink="false">http://blog.trollgod.org.uk/?p=83</guid>
		<description><![CDATA[<p>I&#8217;ve written my first bit of javascript code. It&#8217;s designed to combine multiple twitter and laconica feeds into a single stream.</p> <p>It uses jquery, so you&#8217;ll need to include that as well as this code. Then add a div with an id of &#8220;microblog&#8221;, which will get filled up with the tweets. The tweets <span style="color:#777"> . . . &#8594; Read More: <a href="http://blog.trollgod.org.uk/2009/02/twitter-and-laconica-combined/">Twitter and Laconica combined</a></span>]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve written my first bit of javascript code.  It&#8217;s designed to combine multiple <a href="http://www.twitter.com/">twitter</a> and <a href="http://laconi.ca/">laconica</a> feeds into a single stream.</p>
<p>It uses <a href="http://jquery.com/">jquery</a>, so you&#8217;ll need to include that as well as this code.  Then add a div with an id of &#8220;microblog&#8221;, which will get filled up with the tweets.  The tweets are set to use the css class &#8220;tweet&#8221; so you can style them as you wish very easily.</p>
<p>It is currently set to read from <a href="http://www.twitter.com/">twitter</a> and <a href="http://identi.ca/">identica</a>, but any number of sites can be used.  Just replace the urls near the bottom of the file with the ones you want to use.</p>
<p>Please do note this is the first javascript I&#8217;ve written so it is very likely to have stupid errors and really bad style in it.  I welcome <strong>constructive</strong> criticism.</p>
<div class="dean_ch" style="white-space: nowrap;">
<span class="coMULTI">/*<br />
&nbsp;* twitter_identica &#8211; A program to combine twitter and laconica feeds<br />
&nbsp;* <br />
&nbsp;* @fileOverview A script to combine multiple twitter and laconica feeds.<br />
&nbsp;* @author Ghworg<br />
&nbsp;* @version 1.1<br />
&nbsp;* <br />
&nbsp;* Copyright (c) 2009 Ghworg<br />
&nbsp;* <br />
&nbsp;* This program is free software; you can redistribute it and/or modify it<br />
&nbsp;* under the terms of the GNU General Public License as published by the<br />
&nbsp;* Free Software Foundation; either version 2 of the License, or (at your<br />
&nbsp;* option) any later version.<br />
&nbsp;* <br />
&nbsp;* This program is distributed in the hope that it will be useful, but<br />
&nbsp;* WITHOUT ANY WARRANTY; without even the implied warranty of<br />
&nbsp;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General<br />
&nbsp;* Public License for more details.<br />
&nbsp;* <br />
&nbsp;* You should have received a copy of the GNU General Public License along<br />
&nbsp;* with this program; if not, write to the Free Software Foundation, Inc.,<br />
&nbsp;* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA<br />
&nbsp;* <br />
&nbsp;*/</span></p>
<p><span class="co1">/// @description Array to store the tweets in</span><br />
<span class="kw2">var</span> tweets = <span class="kw2">new</span> Array<span class="br0">&#40;</span><span class="br0">&#41;</span>;</p>
<p><span class="co1">/// @description Track which feed to pull from</span><br />
<span class="kw2">var</span> callCount = <span class="nu0">0</span>;</p>
<p><span class="coMULTI">/**<br />
&nbsp;* @description Convert a time string to the age of the tweet<br />
&nbsp;* @param time The time string<br />
&nbsp;* @returns The age<br />
&nbsp;*/</span><br />
<span class="kw2">function</span> dateToAge<span class="br0">&#40;</span>time<span class="br0">&#41;</span> &nbsp;<span class="br0">&#123;</span><br />
&nbsp; &nbsp;<span class="kw2">var</span> month = <span class="nu0">1000</span> * <span class="nu0">60</span> * <span class="nu0">60</span> * <span class="nu0">24</span> * <span class="nu0">30</span>;<br />
&nbsp; &nbsp;<span class="kw2">var</span> week = <span class="nu0">1000</span> * <span class="nu0">60</span> * <span class="nu0">60</span> * <span class="nu0">24</span> * <span class="nu0">7</span>;<br />
&nbsp; &nbsp;<span class="kw2">var</span> day = <span class="nu0">1000</span> * <span class="nu0">60</span> * <span class="nu0">60</span> * <span class="nu0">24</span>;<br />
&nbsp; &nbsp;<span class="kw2">var</span> hour = <span class="nu0">1000</span> * <span class="nu0">60</span> * <span class="nu0">60</span>;<br />
&nbsp; &nbsp;<span class="kw2">var</span> minute = <span class="nu0">1000</span> * <span class="nu0">60</span>;<br />
&nbsp; &nbsp;<span class="kw2">var</span> second = <span class="nu0">1000</span>;<br />
&nbsp; &nbsp;<br />
&nbsp; &nbsp;<span class="kw2">var</span> now = <span class="kw2">new</span> Date<span class="br0">&#40;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp;<span class="kw2">var</span> then = <span class="kw2">new</span> Date<span class="br0">&#40;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp;then.<span class="me1">setTime</span><span class="br0">&#40;</span>Date.<span class="me1">parse</span><span class="br0">&#40;</span>time<span class="br0">&#41;</span><span class="br0">&#41;</span>;</p>
<p>&nbsp; &nbsp;<span class="kw2">var</span> diff = now &#8211; then;<br />
&nbsp; &nbsp;<span class="kw2">var</span> text = <span class="st0">&#8221;</span>;<br />
&nbsp; &nbsp;<br />
&nbsp; &nbsp;<span class="kw1">if</span> <span class="br0">&#40;</span>diff &gt; month<span class="br0">&#41;</span> &nbsp;<span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; text = Math.<span class="me1">floor</span><span class="br0">&#40;</span>diff / month<span class="br0">&#41;</span> + <span class="st0">&#8216; months&#8217;</span>;<br />
&nbsp; &nbsp;<span class="br0">&#125;</span><br />
&nbsp; &nbsp;<span class="kw1">else</span> <span class="kw1">if</span> <span class="br0">&#40;</span>diff &gt; week<span class="br0">&#41;</span> &nbsp;<span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; text = Math.<span class="me1">floor</span><span class="br0">&#40;</span>diff / week<span class="br0">&#41;</span> + <span class="st0">&#8216; weeks&#8217;</span>;<br />
&nbsp; &nbsp;<span class="br0">&#125;</span><br />
&nbsp; &nbsp;<span class="kw1">else</span> <span class="kw1">if</span> <span class="br0">&#40;</span>diff &gt; day<span class="br0">&#41;</span> &nbsp;<span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; text = Math.<span class="me1">floor</span><span class="br0">&#40;</span>diff / day<span class="br0">&#41;</span> + <span class="st0">&#8216; days&#8217;</span>;<br />
&nbsp; &nbsp;<span class="br0">&#125;</span><br />
&nbsp; &nbsp;<span class="kw1">else</span> <span class="kw1">if</span> <span class="br0">&#40;</span>diff &gt; hour<span class="br0">&#41;</span> &nbsp;<span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; text = Math.<span class="me1">floor</span><span class="br0">&#40;</span>diff / hour<span class="br0">&#41;</span> + <span class="st0">&#8216; hours&#8217;</span>;<br />
&nbsp; &nbsp;<span class="br0">&#125;</span><br />
&nbsp; &nbsp;<span class="kw1">else</span> <span class="kw1">if</span> <span class="br0">&#40;</span>diff &gt; minute<span class="br0">&#41;</span> &nbsp;<span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; text = Math.<span class="me1">floor</span><span class="br0">&#40;</span>diff / minute<span class="br0">&#41;</span> + <span class="st0">&#8216; minutes&#8217;</span>;<br />
&nbsp; &nbsp;<span class="br0">&#125;</span><br />
&nbsp; &nbsp;<span class="kw1">else</span> &nbsp;<span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; text = Math.<span class="me1">floor</span><span class="br0">&#40;</span>diff / second<span class="br0">&#41;</span> + <span class="st0">&#8216; seconds&#8217;</span>;<br />
&nbsp; &nbsp;<span class="br0">&#125;</span><br />
&nbsp; &nbsp;text += <span class="st0">&#8216; ago&#8217;</span>;<br />
&nbsp; &nbsp;<br />
&nbsp; &nbsp;<span class="kw1">return</span> text;<br />
<span class="br0">&#125;</span></p>
<p>
<span class="coMULTI">/**<br />
&nbsp;* @description Make a JSON call<br />
&nbsp;* @param Url of handler to call<br />
&nbsp;* @param Event to call when complete<br />
&nbsp;* @param Event to call when an error is encountered<br />
&nbsp;*/</span><br />
<span class="kw2">function</span> reqJSON<span class="br0">&#40;</span>url, success, error<span class="br0">&#41;</span> <br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp;<span class="kw2">var</span> CallParams = <span class="br0">&#123;</span> <span class="br0">&#125;</span>;<br />
&nbsp; &nbsp;CallParams.<span class="me1">type</span> = <span class="st0">&quot;GET&quot;</span>;<br />
&nbsp; &nbsp;CallParams.<span class="me1">url</span> = url;<br />
&nbsp; &nbsp;<span class="co1">//CallParams.username = username;</span><br />
&nbsp; &nbsp;<span class="co1">//CallParams.password = password;</span><br />
&nbsp; &nbsp;CallParams.<span class="me1">processData</span> = <span class="kw2">true</span>;<br />
&nbsp; &nbsp;<span class="co1">//CallParams.cache = false;</span><br />
&nbsp; &nbsp;CallParams.<span class="me1">dataType</span> = <span class="st0">&quot;json&quot;</span>;<br />
&nbsp; &nbsp;CallParams.<span class="me1">success</span> = success;<br />
&nbsp; &nbsp;<span class="kw1">if</span> <span class="br0">&#40;</span>error<span class="br0">&#41;</span> &nbsp;<span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; CallParams.<span class="me1">error</span> = error;<br />
&nbsp; &nbsp;<span class="br0">&#125;</span><br />
&nbsp; &nbsp;$.<span class="me1">ajax</span><span class="br0">&#40;</span>CallParams<span class="br0">&#41;</span>;<br />
<span class="br0">&#125;</span></p>
<p>
<span class="coMULTI">/**<br />
&nbsp;* @description Compare two tweets based on their timestamps<br />
&nbsp;* @param a First tweet<br />
&nbsp;* @param b Second tweet<br />
&nbsp;* @returns -1 if a is newer than b else 1<br />
&nbsp;*/</span><br />
<span class="kw2">function</span> sortTweets<span class="br0">&#40;</span>a, b<span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp;<span class="kw2">var</span> timea = <span class="kw2">new</span> Date<span class="br0">&#40;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp;<span class="kw2">var</span> timeb = <span class="kw2">new</span> Date<span class="br0">&#40;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp;timea.<span class="me1">setTime</span><span class="br0">&#40;</span>Date.<span class="me1">parse</span><span class="br0">&#40;</span>a.<span class="me1">created_at</span><span class="br0">&#41;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp;timeb.<span class="me1">setTime</span><span class="br0">&#40;</span>Date.<span class="me1">parse</span><span class="br0">&#40;</span>b.<span class="me1">created_at</span><span class="br0">&#41;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp;<br />
&nbsp; &nbsp;<span class="kw1">if</span> <span class="br0">&#40;</span>timea &gt; timeb<span class="br0">&#41;</span> &nbsp;<span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; <span class="kw1">return</span> <span class="nu0">-1</span>;<br />
&nbsp; &nbsp;<span class="br0">&#125;</span><br />
&nbsp; &nbsp;<span class="kw1">else</span> &nbsp;<span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; <span class="kw1">return</span> <span class="nu0">1</span>;<br />
&nbsp; &nbsp;<span class="br0">&#125;</span><br />
<span class="br0">&#125;</span></p>
<p>
<span class="coMULTI">/**<br />
&nbsp;* @description Strip off the end of a URL to get the site address<br />
&nbsp;* @param fullurl The URL http://www.example.com/some/other/text<br />
&nbsp;* @returns http://www.example.com/<br />
&nbsp;*/</span><br />
<span class="kw2">function</span> getBaseUrl<span class="br0">&#40;</span>fullurl<span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp;<span class="kw2">var</span> stripped = <span class="st0">&#8221;</span>;<br />
&nbsp; &nbsp;<span class="kw1">if</span> <span class="br0">&#40;</span>fullurl.<span class="me1">substr</span><span class="br0">&#40;</span><span class="nu0">0</span>, <span class="nu0">8</span><span class="br0">&#41;</span> == <span class="st0">&#8216;https://&#8217;</span><span class="br0">&#41;</span> &nbsp;<span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; stripped = fullurl.<span class="me1">substring</span><span class="br0">&#40;</span><span class="nu0">8</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp;<span class="br0">&#125;</span><br />
&nbsp; &nbsp;<span class="kw1">else</span> &nbsp;<span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; stripped = fullurl.<span class="me1">substring</span><span class="br0">&#40;</span><span class="nu0">7</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp;<span class="br0">&#125;</span><br />
&nbsp; &nbsp;<span class="kw2">var</span> endIndex = stripped.<span class="me1">search</span><span class="br0">&#40;</span><span class="st0">&#8216;/&#8217;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp;stripped = stripped.<span class="me1">substr</span><span class="br0">&#40;</span><span class="nu0">0</span>, endIndex<span class="br0">&#41;</span>;<br />
&nbsp; &nbsp;<br />
&nbsp; &nbsp;<span class="kw1">return</span> stripped;<br />
<span class="br0">&#125;</span></p>
<p>
<span class="coMULTI">/**<br />
&nbsp;* @description Go through all the existing tweets and check if the new one <br />
&nbsp;* &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;is there already<br />
&nbsp;* @param oldTweets An array of all the existing tweets<br />
&nbsp;* @param newTweet The new tweet<br />
&nbsp;* @returns true or false<br />
&nbsp;*/</span><br />
<span class="kw2">function</span> checkForDups<span class="br0">&#40;</span>oldTweets, newTweet<span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp;<span class="kw2">var</span> dupe = <span class="kw2">false</span>;<br />
&nbsp; &nbsp;$.<span class="me1">each</span><span class="br0">&#40;</span>oldTweets, <span class="kw2">function</span><span class="br0">&#40;</span>i, tweet<span class="br0">&#41;</span> &nbsp;<span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span>tweet.<span class="me1">text</span> == newTweet.<span class="me1">text</span><span class="br0">&#41;</span> &nbsp;<span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;dupe = <span class="kw2">true</span>;<br />
&nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp;<span class="br0">&#125;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp;<span class="kw1">return</span> dupe;<br />
<span class="br0">&#125;</span><br />
&nbsp; &nbsp;</p>
<p><span class="coMULTI">/**<br />
&nbsp;* @description Search the text for links and make them clickable<br />
&nbsp;* @param startMarker Text to look for that indicates a link<br />
&nbsp;* @param text The original text<br />
&nbsp;* @param prefix Text to put in front of the URL<br />
&nbsp;* @returns Text with links<br />
&nbsp;*/</span><br />
<span class="kw2">function</span> addLink<span class="br0">&#40;</span>startMarker, text, prefix<span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp;<span class="kw2">var</span> endindex = <span class="nu0">0</span>;<br />
&nbsp; &nbsp;<span class="kw1">while</span> <span class="br0">&#40;</span>endindex &lt; text.<span class="me1">length</span><span class="br0">&#41;</span> &nbsp;<span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; startindex = text.<span class="me1">indexOf</span><span class="br0">&#40;</span>startMarker, endindex<span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span>startindex &gt;= <span class="nu0">0</span><span class="br0">&#41;</span> &nbsp;<span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;endindex = text.<span class="me1">indexOf</span><span class="br0">&#40;</span><span class="st0">&#8216; &#8216;</span>, startindex<span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="kw1">if</span> <span class="br0">&#40;</span>endindex &lt; <span class="nu0">0</span><span class="br0">&#41;</span> &nbsp;<span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; endindex = text.<span class="me1">length</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;before = text.<span class="me1">substring</span><span class="br0">&#40;</span><span class="nu0">0</span>, startindex<span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;url = text.<span class="me1">substring</span><span class="br0">&#40;</span>startindex, endindex<span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;after = text.<span class="me1">substring</span><span class="br0">&#40;</span>endindex<span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;href = url.<span class="me1">link</span><span class="br0">&#40;</span>prefix + url.<span class="me1">replace</span><span class="br0">&#40;</span><span class="st0">&#8216;@&#8217;</span>, <span class="st0">&#8221;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;text = before + href + after;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;endindex = before.<span class="me1">length</span> + href.<span class="me1">length</span><br />
&nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; <span class="kw1">else</span> &nbsp;<span class="br0">&#123;</span> &nbsp; &nbsp;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="kw1">break</span>;<br />
&nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp;<span class="br0">&#125;</span><br />
&nbsp; &nbsp;<span class="kw1">return</span> text;<br />
<span class="br0">&#125;</span></p>
<p>
<span class="coMULTI">/**<br />
&nbsp;* @description Convert http https and @ replies to links<br />
&nbsp;* @param text The original text<br />
&nbsp;* @param baseUrl Site the tweet came from (to use for @s)<br />
&nbsp;* @returns Text with links<br />
&nbsp;*/</span><br />
<span class="kw2">function</span> addLinks<span class="br0">&#40;</span>text, baseUrl<span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp;text = addLink<span class="br0">&#40;</span><span class="st0">&#8216;https://&#8217;</span>, text, <span class="st0">&#8221;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp;text = addLink<span class="br0">&#40;</span><span class="st0">&#8216;http://&#8217;</span>, text, <span class="st0">&#8221;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp;text = addLink<span class="br0">&#40;</span><span class="st0">&#8216;@&#8217;</span>, text, baseUrl<span class="br0">&#41;</span>;<br />
&nbsp; &nbsp;<span class="kw1">return</span> text<br />
<span class="br0">&#125;</span></p>
<p>
<span class="coMULTI">/**<br />
&nbsp;* @description JSON request succeeded, <br />
&nbsp;* &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;process the data and insert it into the web page<br />
&nbsp;* @param json The json data received<br />
&nbsp;* @param textStatus Result code<br />
&nbsp;*/</span><br />
<span class="kw2">function</span> readJson<span class="br0">&#40;</span>json, textStatus<span class="br0">&#41;</span> <br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp;<span class="co1">//Successful call</span><br />
&nbsp; &nbsp;<span class="co1">//Do stuff with the JSON</span><br />
&nbsp; &nbsp;<br />
&nbsp; &nbsp;<span class="kw2">var</span> requestUrl = <span class="kw1">this</span>.<span class="me1">url</span>;<br />
&nbsp; &nbsp;<span class="kw2">var</span> baseUrl = getBaseUrl<span class="br0">&#40;</span>requestUrl<span class="br0">&#41;</span>;<br />
&nbsp; &nbsp;<br />
&nbsp; &nbsp;<span class="co1">// Clear out any old tweets from the html</span><br />
&nbsp; &nbsp;$<span class="br0">&#40;</span><span class="st0">&quot;p.tweet&quot;</span><span class="br0">&#41;</span>.<span class="me1">remove</span><span class="br0">&#40;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp;<br />
&nbsp; &nbsp;<span class="co1">// Delete old tweets from this url from the list</span><br />
&nbsp; &nbsp;<span class="kw2">var</span> oldtweets = tweets;<br />
&nbsp; &nbsp;tweets = <span class="kw2">new</span> Array<span class="br0">&#40;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp;$.<span class="me1">each</span><span class="br0">&#40;</span>oldtweets, <span class="kw2">function</span><span class="br0">&#40;</span>i, <span class="kw1">item</span><span class="br0">&#41;</span> &nbsp;<span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="kw1">item</span>.<span class="me1">baseUrl</span> != baseUrl<span class="br0">&#41;</span> &nbsp;<span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;tweets<span class="br0">&#91;</span>tweets.<span class="me1">length</span><span class="br0">&#93;</span> = <span class="kw1">item</span>;<br />
&nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp;<span class="br0">&#125;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp;<br />
&nbsp; &nbsp;<span class="co1">// Add newly retrieved tweets to the list</span><br />
&nbsp; &nbsp;$.<span class="me1">each</span><span class="br0">&#40;</span>json, <span class="kw2">function</span><span class="br0">&#40;</span>i, <span class="kw1">item</span><span class="br0">&#41;</span> &nbsp;<span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; <span class="kw1">item</span>.<span class="me1">baseUrl</span> = baseUrl;<br />
&nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span>checkForDups<span class="br0">&#40;</span>tweets, <span class="kw1">item</span><span class="br0">&#41;</span> == <span class="kw2">false</span><span class="br0">&#41;</span> &nbsp;<span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;tweets<span class="br0">&#91;</span>tweets.<span class="me1">length</span><span class="br0">&#93;</span> = <span class="kw1">item</span>;<br />
&nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp;<span class="br0">&#125;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp;<br />
&nbsp; &nbsp;<span class="co1">// Sort the tweet list by age</span><br />
&nbsp; &nbsp;tweets.<span class="me1">sort</span><span class="br0">&#40;</span>sortTweets<span class="br0">&#41;</span>;<br />
&nbsp; &nbsp;<br />
&nbsp; &nbsp;<span class="co1">// Print the tweets to the html</span><br />
&nbsp; &nbsp;<span class="kw2">var</span> pretext = <span class="st0">&#8216;&lt;p class=&quot;tweet&quot;&gt;&#8217;</span>;<br />
&nbsp; &nbsp;<span class="kw2">var</span> postext = <span class="st0">&#8216;&lt;/p&gt;&#8217;</span>;<br />
&nbsp; &nbsp;$.<span class="me1">each</span><span class="br0">&#40;</span>tweets, <span class="kw2">function</span><span class="br0">&#40;</span>i, <span class="kw1">item</span><span class="br0">&#41;</span> &nbsp;<span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; <span class="co1">//pretext = &#8216;&lt;p class=&quot;tweet &#8216;;</span><br />
&nbsp; &nbsp; &nbsp; <span class="co1">//pretext = pretext + item.baseUrl.replace(&#8216;.&#8217;, &#8221;) + &#8216;&quot;&gt;&#8217;;</span><br />
&nbsp; &nbsp; &nbsp; <span class="kw2">var</span> ago = dateToAge<span class="br0">&#40;</span><span class="kw1">item</span>.<span class="me1">created_at</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; <span class="kw2">var</span> base = <span class="st0">&#8216;http://&#8217;</span> + <span class="kw1">item</span>.<span class="me1">baseUrl</span> + <span class="st0">&#8216;/&#8217;</span>;<br />
&nbsp; &nbsp; &nbsp; <span class="kw2">var</span> text = addLinks<span class="br0">&#40;</span><span class="kw1">item</span>.<span class="me1">text</span>, base<span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; <span class="kw2">var</span> userlink = <span class="kw1">item</span>.<span class="me1">user</span>.<span class="me1">screen_name</span>.<span class="me1">link</span><span class="br0">&#40;</span>base + <span class="kw1">item</span>.<span class="me1">user</span>.<span class="me1">screen_name</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; mb.<span class="me1">append</span><span class="br0">&#40;</span>pretext + ago + <span class="st0">&#8216;: &#8216;</span> + userlink + <span class="st0">&#8216;: &#8216;</span> + text + postext<span class="br0">&#41;</span>;<br />
&nbsp; &nbsp;<span class="br0">&#125;</span><span class="br0">&#41;</span>;<br />
<span class="br0">&#125;</span></p>
<p>
<span class="coMULTI">/**<br />
&nbsp;* @description Called if JSON request failed<br />
&nbsp;* @param XMLHttpRequest<br />
&nbsp;* @param textStatus<br />
&nbsp;* @param errorThrown<br />
&nbsp;*/</span><br />
<span class="kw2">function</span> failJson<span class="br0">&#40;</span>XMLHttpRequest, textStatus, errorThrown<span class="br0">&#41;</span> <br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp;<span class="co1">// typically only one of textStatus or errorThrown </span><br />
&nbsp; &nbsp;<span class="co1">// will have info</span><br />
&nbsp; &nbsp;<span class="co1">// </span><br />
&nbsp; &nbsp;mb.<span class="me1">append</span><span class="br0">&#40;</span><span class="st0">&quot;Error getting json data<br />
&quot;</span><span class="br0">&#41;</span>;<br />
<span class="br0">&#125;</span></p>
<p>
<span class="coMULTI">/**<br />
&nbsp;* @description Main function<br />
&nbsp;*/</span><br />
<span class="kw2">function</span> display<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp;mb = $<span class="br0">&#40;</span><span class="st0">&quot;#microblog&quot;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp;<span class="kw2">var</span> urls = <span class="br0">&#91;</span> <span class="st0">&quot;https://identi.ca/api/statuses/friends_timeline.json?callback=?&quot;</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st0">&quot;https://twitter.com/statuses/friends_timeline.json?callback=?&quot;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="br0">&#93;</span>;<br />
&nbsp; &nbsp;<br />
&nbsp; &nbsp;<span class="co1">//if ( 0 == $(&quot;p.tweet&quot;).length ) &nbsp;{</span><br />
&nbsp; &nbsp;<span class="co1">// &nbsp; $.each(urls, function(i, url) &nbsp;{</span><br />
&nbsp; &nbsp;<span class="co1">// &nbsp; &nbsp; &nbsp;reqJSON(url, readJson, failJson);</span><br />
&nbsp; &nbsp;<span class="co1">// &nbsp; });</span><br />
&nbsp; &nbsp;<span class="co1">//}</span><br />
&nbsp; &nbsp;<span class="co1">//else &nbsp;{</span><br />
&nbsp; &nbsp;<span class="kw1">if</span> <span class="br0">&#40;</span>callCount &lt; urls.<span class="me1">length</span><span class="br0">&#41;</span> &nbsp;<span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; reqJSON<span class="br0">&#40;</span>urls<span class="br0">&#91;</span>callCount<span class="br0">&#93;</span>, readJson, failJson<span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; callCount = callCount + <span class="nu0">1</span>;<br />
&nbsp; &nbsp;<span class="br0">&#125;</span><br />
&nbsp; &nbsp;<span class="kw1">else</span> &nbsp;<span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; callCount = <span class="nu0">0</span>;<br />
&nbsp; &nbsp;<span class="br0">&#125;</span><br />
&nbsp; &nbsp;<span class="co1">//}</span><br />
<span class="br0">&#125;</span></p>
<p>&nbsp;</p></div>
<p>Update (2009-02-22):  I forgot to mention, you need t call the display function to get it to actually do something.  It is currently set to read one feed every time display is called as it is designed to be called on a timer and I didn&#8217;t want two password requests to appear at once.  If you want to read all feeds simultaneously then uncomment the commented code in the display function.</p>
<p>Update (2009-02-28):  Fixed a small bug where html tags in tweets were interpreted, they are now escaped.  New version is available <a href='http://blog.trollgod.org.uk/wp-content/uploads/2009/02/twitter_identica.js'>twitter_identica</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.trollgod.org.uk/2009/02/twitter-and-laconica-combined/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>
