<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-8109854847430899154</id><updated>2011-12-04T16:14:31.543Z</updated><category term='dell mini mythtv 3mmpro110'/><category term='open source software'/><category term='postgres'/><category term='pylint'/><category term='rsync'/><category term='ebay'/><category term='apt-get'/><category term='spammer'/><category term='random linux thought for the day'/><category term='QSessionManager'/><category term='pyside'/><category term='VPS hosting'/><category term='opensource'/><category term='sound'/><category term='python'/><category term='python classes'/><category term='video'/><category term='alsa'/><category term='compiz'/><category term='pyqt4'/><category term='alan'/><category term='backup'/><category term='apache2 config'/><category term='linux'/><category term='pyqt pyqt4'/><category term='intel ich8'/><category term='packages'/><category term='doppleganger'/><category term='radio'/><category term='cgi-bin'/><category term='PyQt'/><category term='dell-mini ubuntu'/><category term='GPL law freedom'/><category term='openmolar'/><category term='tllts'/><category term='cube'/><category term='MySQL Python'/><category term='ubuntu 9.10'/><category term='launchpad code hosting bzr hg'/><category term='hotmail microsoft'/><category term='intrepid'/><category term='python pyqt apache2'/><category term='iwconfig'/><category term='python pyqt4'/><category term='ubuntu linux intrepid hardy apache2'/><category term='big buck bunny'/><category term='wireless'/><category term='Peter64'/><category term='pyqt translation openmolar'/><category term='ubuntu'/><category term='gmail'/><category term='karmic'/><category term='aeroplane'/><category term='html markup'/><category term='screencast'/><title type='text'>rowinggolfer</title><subtitle type='html'>Random musings on GNU+Linux.
open source software, and Python.

The main purpose of this blog is to archive (for myself) what I am learning about these wonderful technologies/communities</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://rowinggolfer.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://rowinggolfer.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default?start-index=101&amp;max-results=100'/><author><name>Neil</name><uri>http://www.blogger.com/profile/06112117080373993301</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/-GEhvN_g7Kk4/TfnhG7DCMiI/AAAAAAAAAHo/HmAn1zC-xXM/s220/geek.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>102</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-8109854847430899154.post-2709257120172404909</id><published>2011-10-22T20:28:00.001+01:00</published><updated>2011-10-22T20:29:15.321+01:00</updated><title type='text'>My own debian repository</title><content type='html'>I've created my own debian repository.&lt;br /&gt;I'll put only auteur and openmolar related packages into this, and currently I just have the latest stable in there.&lt;br /&gt;&lt;br /&gt;I'm using repropro to add packages and handle signing, and think it is wonderful in it's simplicity.&lt;br /&gt;&lt;br /&gt;to add this to a debian based distro do the following.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;~$ sudo su&lt;br /&gt;~# echo "deb http://openmolar.com/repos/apt/debian squeeze main" &gt;&gt; /etc/apt/sources.list&lt;br /&gt;~# wget -O - http://www.openmolar.com/rowinggolfer.gpg.key| apt-key add -&lt;br /&gt;~# apt-get update&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8109854847430899154-2709257120172404909?l=rowinggolfer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rowinggolfer.blogspot.com/feeds/2709257120172404909/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8109854847430899154&amp;postID=2709257120172404909' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/2709257120172404909'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/2709257120172404909'/><link rel='alternate' type='text/html' href='http://rowinggolfer.blogspot.com/2011/10/my-own-debian-repository.html' title='My own debian repository'/><author><name>Neil</name><uri>http://www.blogger.com/profile/06112117080373993301</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/-GEhvN_g7Kk4/TfnhG7DCMiI/AAAAAAAAAHo/HmAn1zC-xXM/s220/geek.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8109854847430899154.post-219808256204314861</id><published>2011-10-06T12:17:00.000+01:00</published><updated>2011-10-06T12:17:27.025+01:00</updated><title type='text'>Ecryptfs and Dropbox - a match made in heaven for secure backup</title><content type='html'>Dropbox is a wonderful service, but there's the problem that they (Dropbox) have a copy of your data, so it is smart to encrypt anything sensitive you store there.&lt;br /&gt;&lt;br /&gt;The problem is, of course, that this adds complexity, and get's in the way of one's workflow.&lt;br /&gt;&lt;br /&gt;However, I realised yesterday that there's an easy way to do this.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;~$ ecryptfs-setup-private&lt;br /&gt;~$ ln -s ~/.Private ~/Dropbox/Private&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;b&gt;Note the "." in the first path&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Now anything you put into ~/Private will be automatically synced up to Dropbox. Very, very convenient way of doing this IMHO.&lt;br /&gt;&lt;br /&gt;These instructions are very, very simplified, and the ecryptfs setup can be done in many other ways than using the setup-private script. Using a common encryption passphrase across your boxes, or not encrypting filenames, or using public/private key for the ecrtyptfs mount all should be investigated.&lt;br /&gt;&lt;br /&gt;But the main point here is the symlink idea to the hidden encrypted folder. I don't recall hearing anyone suggest this before.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8109854847430899154-219808256204314861?l=rowinggolfer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rowinggolfer.blogspot.com/feeds/219808256204314861/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8109854847430899154&amp;postID=219808256204314861' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/219808256204314861'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/219808256204314861'/><link rel='alternate' type='text/html' href='http://rowinggolfer.blogspot.com/2011/10/ecryptfs-and-dropbox-match-made-in.html' title='Ecryptfs and Dropbox - a match made in heaven for secure backup'/><author><name>Neil</name><uri>http://www.blogger.com/profile/06112117080373993301</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/-GEhvN_g7Kk4/TfnhG7DCMiI/AAAAAAAAAHo/HmAn1zC-xXM/s220/geek.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8109854847430899154.post-826975519851216003</id><published>2011-08-23T10:37:00.001+01:00</published><updated>2011-08-23T11:49:48.753+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python pyqt apache2'/><title type='text'>toggling /etc/hosts file via a simple gui</title><content type='html'>Like many folks who play at web development, I have local running instances of all my websites to enable offline development and/or testing.&lt;br /&gt;&lt;br /&gt;To switch between the two, I have a launcher to a little gui I've written.&lt;br /&gt;&lt;br /&gt;&lt;table cellpadding="0" cellspacing="0" class="tr-caption-container" &gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-CDBKhLYQS20/TlNwp5mjHAI/AAAAAAAAAJk/IgMBR60vYso/s1600/Screenshot-toggle+-etc-hosts+file.png" imageanchor="1" style="clear: right; margin-bottom: 1em; margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/-CDBKhLYQS20/TlNwp5mjHAI/AAAAAAAAAJk/IgMBR60vYso/s1600/Screenshot-toggle+-etc-hosts+file.png" /&gt;&lt;/a&gt;&lt;/td&gt; &lt;td class="tr-caption" style="text-align: center;"&gt;The Interface&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-3pepbVzBFYA/TlNwpnnQkRI/AAAAAAAAAJg/p_y1hNcrc-w/s1600/Screenshot-confirm.png" imageanchor="1" style="clear: right; margin-bottom: 1em; margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="89" src="http://2.bp.blogspot.com/-3pepbVzBFYA/TlNwpnnQkRI/AAAAAAAAAJg/p_y1hNcrc-w/s320/Screenshot-confirm.png" width="320" /&gt;&lt;/a&gt;&lt;/td&gt; &lt;td class="tr-caption" style="text-align: center;"&gt;The Dialog raised on request.&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;works great.&lt;br /&gt;&lt;br /&gt;the code is below.&lt;br /&gt;&lt;br /&gt;Incidentally, as /etc/hosts required root permissions, I call the write using gksu. KDE users would need to change this. &lt;br /&gt;&lt;br /&gt;Here's the full code.&lt;br /&gt;&lt;pre&gt;#! /usr/bin/env python&lt;br /&gt;&lt;br /&gt;'''&lt;br /&gt;This script modifies the /etc/hosts file so that I utilise this machines&lt;br /&gt;web server rather than doing a dns lookup and going to the online &lt;br /&gt;sites.&lt;br /&gt;It's for testing purposes. &lt;br /&gt;&lt;br /&gt;my /etc/hosts file has this text present.&lt;br /&gt;&lt;br /&gt;127.0.0.1   localhost &lt;br /&gt;127.0.0.1   rowinggolfer.org &lt;br /&gt;127.0.0.1   openmolar.com &lt;br /&gt;127.0.0.1   academydental.com &lt;br /&gt;127.0.1.1    slim-maroon&lt;br /&gt;&lt;br /&gt;and when I want to use the "cloud" servers, the sites listed in variable SITES&lt;br /&gt;are commented out.&lt;br /&gt;&lt;br /&gt;'''&lt;br /&gt;&lt;br /&gt;from PyQt4 import QtGui, QtCore&lt;br /&gt;import re, subprocess, sys, tempfile&lt;br /&gt;&lt;br /&gt;SITES = ["rowinggolfer.org", "academydental.com", "openmolar.com",]&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;class Dialog(QtGui.QDialog):&lt;br /&gt;    def __init__(self, parent=None):&lt;br /&gt;        QtGui.QDialog.__init__(self, parent)&lt;br /&gt;    &lt;br /&gt;        self.setWindowTitle("toggle /etc/hosts file")&lt;br /&gt;        &lt;br /&gt;        self.local_rb = QtGui.QRadioButton("Using localhost")&lt;br /&gt;        self.global_rb = QtGui.QRadioButton("Using remote host(s)")&lt;br /&gt;        &lt;br /&gt;        layout = QtGui.QVBoxLayout(self)&lt;br /&gt;        layout.addWidget(self.local_rb)&lt;br /&gt;        layout.addWidget(self.global_rb)&lt;br /&gt;        &lt;br /&gt;        self.global_rb.setChecked(True)&lt;br /&gt;        self.local_rb.setChecked(self.check_state)&lt;br /&gt;        &lt;br /&gt;        self.local_rb.toggled.connect(self.apply_changes)&lt;br /&gt;    &lt;br /&gt;    def sizeHint(self):&lt;br /&gt;        return QtCore.QSize(200,50)&lt;br /&gt;    &lt;br /&gt;    @property&lt;br /&gt;    def check_state(self):&lt;br /&gt;        '''&lt;br /&gt;        checks /etc/hosts to see if it is set to use the local instance of &lt;br /&gt;        apache2 for the SITES&lt;br /&gt;        '''&lt;br /&gt;        local = False&lt;br /&gt;        &lt;br /&gt;        f = open("/etc/hosts", "r")&lt;br /&gt;        for line in f:&lt;br /&gt;            for site in SITES:&lt;br /&gt;                if re.match("127\.0\.0\.1[ \t]*%s"% site, line):&lt;br /&gt;                    local = True&lt;br /&gt;        &lt;br /&gt;        return local&lt;br /&gt;        &lt;br /&gt;    def apply_changes(self, use_local):&lt;br /&gt;        host = "localhost" if use_local else "remote host(s)"&lt;br /&gt;        &lt;br /&gt;        message = '''modify &amp;lt;em&amp;gt;/etc/hosts&amp;lt;/em&amp;gt; so that &lt;br /&gt;            &amp;lt;b&amp;gt;%s&amp;lt;/b&amp;gt; is used for the following sites?&amp;lt;ul&amp;gt;{sites}&amp;lt;/ul&amp;gt;'''% host&lt;br /&gt;        &lt;br /&gt;        sites = ""&lt;br /&gt;        for site in SITES:&lt;br /&gt;            sites += "&amp;lt;li&amp;gt;%s&amp;lt;/li&amp;gt;"% site&lt;br /&gt;            &lt;br /&gt;        message = message.replace("{sites}", sites)&lt;br /&gt;        &lt;br /&gt;        result = QtGui.QMessageBox.question(self, "confirm", message,&lt;br /&gt;        QtGui.QMessageBox.Ok|QtGui.QMessageBox.Cancel,&lt;br /&gt;        QtGui.QMessageBox.Ok) == QtGui.QMessageBox.Ok&lt;br /&gt;        &lt;br /&gt;        if result:&lt;br /&gt;            self.write_file(use_local)&lt;br /&gt;        &lt;br /&gt;        &lt;br /&gt;        success = use_local == self.check_state&lt;br /&gt;        &lt;br /&gt;        if success:&lt;br /&gt;            QtGui.QMessageBox.inforamtion(self, "success", &lt;br /&gt;                "changes applied sucessfully")&lt;br /&gt;        &lt;br /&gt;        self.local_rb.toggled.disconnect(self.apply_changes)&lt;br /&gt;        self.local_rb.setChecked(self.check_state)&lt;br /&gt;        self.local_rb.toggled.connect(self.apply_changes)&lt;br /&gt;        &lt;br /&gt;        &lt;br /&gt;        &lt;br /&gt;    def write_file(self, local):&lt;br /&gt;    &lt;br /&gt;        def repl(arg):&lt;br /&gt;            if local:&lt;br /&gt;                return re.sub("\n#*", "\n", arg.group())&lt;br /&gt;            else:&lt;br /&gt;                return arg.group().replace("\n", "\n#")&lt;br /&gt;    &lt;br /&gt;        f = open("/etc/hosts", "r")&lt;br /&gt;        data = f.read()&lt;br /&gt;        f.close()&lt;br /&gt;        if not local:&lt;br /&gt;            for site in SITES:&lt;br /&gt;                data = re.sub(  "(\n127\.0\.0\.1[ \t]*%s)"% site, &lt;br /&gt;                                repl, data)&lt;br /&gt;        else:&lt;br /&gt;            for site in SITES:&lt;br /&gt;                data = re.sub(  "\n#*127\.0\.0\.1[ \t]*(%s)"% site, &lt;br /&gt;                                repl, data)&lt;br /&gt;    &lt;br /&gt;        t = tempfile.NamedTemporaryFile("w", delete=False)&lt;br /&gt;        t.write(data)&lt;br /&gt;        t.close()&lt;br /&gt;        &lt;br /&gt;        p = subprocess.Popen(["gksu", "mv", t.name, "/etc/hosts"]) &lt;br /&gt;        assert p.wait()==0&lt;br /&gt;        &lt;br /&gt;        &lt;br /&gt;if __name__ == "__main__":&lt;br /&gt;    app = QtGui.QApplication([])&lt;br /&gt;    dl = Dialog()&lt;br /&gt;    dl.exec_()&lt;br /&gt;    &lt;br /&gt;    &lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8109854847430899154-826975519851216003?l=rowinggolfer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rowinggolfer.blogspot.com/feeds/826975519851216003/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8109854847430899154&amp;postID=826975519851216003' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/826975519851216003'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/826975519851216003'/><link rel='alternate' type='text/html' href='http://rowinggolfer.blogspot.com/2011/08/toggling-etchosts-file-via-simple-gui.html' title='toggling /etc/hosts file via a simple gui'/><author><name>Neil</name><uri>http://www.blogger.com/profile/06112117080373993301</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/-GEhvN_g7Kk4/TfnhG7DCMiI/AAAAAAAAAHo/HmAn1zC-xXM/s220/geek.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/-CDBKhLYQS20/TlNwp5mjHAI/AAAAAAAAAJk/IgMBR60vYso/s72-c/Screenshot-toggle+-etc-hosts+file.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8109854847430899154.post-454383221408415166</id><published>2011-08-22T11:38:00.000+01:00</published><updated>2011-08-22T11:45:33.034+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='VPS hosting'/><title type='text'>A VPS from Bitfolk</title><content type='html'>I've had a VPS from amazon up and running for a few months, but I simply couldn't get my head around their billing tariffs. I am sure they are great and really flexible, but they weren't working out as a good deal for me.&lt;br /&gt;(on average I was paying $75 a month). On top of that, on Friday, I was having trouble logging in (probably my own fault).&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;So I finally got around to switching provider.&lt;br /&gt;and as&amp;nbsp;&lt;a href="http://bitfolk.com/"&gt;http://bitfolk.com/&lt;/a&gt; are well known to the UK floss community as a sponsor of &lt;a href="http://oggcamp.org/"&gt;http://oggcamp.org/&lt;/a&gt; , and patronised by the internet's very own "Alan (popey) Pope".&lt;br /&gt;&lt;br /&gt;Bitfolk have been an absolute joy to deal with, I had my server up and running within a couple of hours of my enquiry.&lt;br /&gt;&lt;br /&gt;I have now moved both &lt;a href="http://www.openmolar.com/"&gt;www.openmolar.com&lt;/a&gt; and &lt;a href="http://www.rowinggolfer.org/"&gt;www.rowinggolfer.org&lt;/a&gt; onto that server and they seem fast and stable.&lt;br /&gt;&amp;nbsp;How much for this incredible service? Under 20% of the cost of the amazon box (which is now cancelled), and easy to understand.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Thanks Bitfolk, and a 5 star rating from yours truly.&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8109854847430899154-454383221408415166?l=rowinggolfer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rowinggolfer.blogspot.com/feeds/454383221408415166/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8109854847430899154&amp;postID=454383221408415166' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/454383221408415166'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/454383221408415166'/><link rel='alternate' type='text/html' href='http://rowinggolfer.blogspot.com/2011/08/vps-from-bitfolk.html' title='A VPS from Bitfolk'/><author><name>Neil</name><uri>http://www.blogger.com/profile/06112117080373993301</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/-GEhvN_g7Kk4/TfnhG7DCMiI/AAAAAAAAAHo/HmAn1zC-xXM/s220/geek.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8109854847430899154.post-3785478580175310270</id><published>2011-08-16T23:47:00.000+01:00</published><updated>2011-08-16T23:47:39.253+01:00</updated><title type='text'>Screencasting on linux</title><content type='html'>There are lots of good screen capturing options for linux.&lt;br /&gt;&lt;br /&gt;On #oggcastplanet on irc.freenode.net,&amp;nbsp; K4k asked about streaming the output, with a webcam shot of the speaker somewhere on the screen.&lt;br /&gt;&lt;br /&gt;here's one way to do that.&lt;br /&gt;&lt;br /&gt;1st, start the webcam in a non-intrusive frame. mplayer fits the bill here.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;~$ mplayer -cache 128 -tv driver=v4l2:width=320:height=240 -vo xv tv:// &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;when that window appears, resize it, place it where you find least intrusive, and set it to remain "on top".&lt;br /&gt;&lt;br /&gt;in another terminal, do this&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;~$ ffmpeg -f oss -i /dev/dsp -f x11grab -s xga -r 15 -i :0.0 out.mp4&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;then record your screencast.&lt;br /&gt;&lt;br /&gt;hit q in the second terminal when you are finished.&lt;br /&gt;&lt;br /&gt;If this works.. replace out.mp4 with whatever format or stream you wish to create.&lt;br /&gt;&lt;br /&gt;Below is the video I created with this method (on ubuntu 10.04). &lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;object width="320" height="266" class="BLOG_video_class" id="BLOG_video-185035f8461b0ac6" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0"&gt;&lt;param name="movie" value="http://www.youtube.com/get_player"&gt;&lt;param name="bgcolor" value="#FFFFFF"&gt;&lt;param name="allowfullscreen" value="true"&gt;&lt;param name="flashvars" value="flvurl=http://v14.nonxt1.googlevideo.com/videoplayback?id%3D185035f8461b0ac6%26itag%3D5%26app%3Dblogger%26ip%3D0.0.0.0%26ipbits%3D0%26expire%3D1330189460%26sparams%3Did,itag,ip,ipbits,expire%26signature%3D3D67485DBE811FA169D13C3891FC8C2F63935D2C.5A362BCE9B3F5B3ACE9083695B770AF043D6123F%26key%3Dck1&amp;amp;iurl=http://video.google.com/ThumbnailServer2?app%3Dblogger%26contentid%3D185035f8461b0ac6%26offsetms%3D5000%26itag%3Dw160%26sigh%3DJ0QIjf05_QE0ohxe9lNG8zg3DOg&amp;amp;autoplay=0&amp;amp;ps=blogger"&gt;&lt;embed src="http://www.youtube.com/get_player" type="application/x-shockwave-flash"width="320" height="266" bgcolor="#FFFFFF"flashvars="flvurl=http://v14.nonxt1.googlevideo.com/videoplayback?id%3D185035f8461b0ac6%26itag%3D5%26app%3Dblogger%26ip%3D0.0.0.0%26ipbits%3D0%26expire%3D1330189460%26sparams%3Did,itag,ip,ipbits,expire%26signature%3D3D67485DBE811FA169D13C3891FC8C2F63935D2C.5A362BCE9B3F5B3ACE9083695B770AF043D6123F%26key%3Dck1&amp;iurl=http://video.google.com/ThumbnailServer2?app%3Dblogger%26contentid%3D185035f8461b0ac6%26offsetms%3D5000%26itag%3Dw160%26sigh%3DJ0QIjf05_QE0ohxe9lNG8zg3DOg&amp;autoplay=0&amp;ps=blogger"allowFullScreen="true" /&gt;&lt;/object&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8109854847430899154-3785478580175310270?l=rowinggolfer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rowinggolfer.blogspot.com/feeds/3785478580175310270/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8109854847430899154&amp;postID=3785478580175310270' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/3785478580175310270'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/3785478580175310270'/><link rel='alternate' type='text/html' href='http://rowinggolfer.blogspot.com/2011/08/screencasting-on-linux.html' title='Screencasting on linux'/><author><name>Neil</name><uri>http://www.blogger.com/profile/06112117080373993301</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/-GEhvN_g7Kk4/TfnhG7DCMiI/AAAAAAAAAHo/HmAn1zC-xXM/s220/geek.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8109854847430899154.post-5909623208884720988</id><published>2011-08-11T21:44:00.000+01:00</published><updated>2011-08-11T21:44:17.554+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='open source software'/><title type='text'>Customised Business Software or Software Customised Businesses?</title><content type='html'>So I am reading Bookeeping for Dummies at the moment (because double-entry booking is a complete mystery to me).&lt;br /&gt;&lt;br /&gt;This paragraph caught my eye, when the author discusses software.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://books.google.com/books?id=-alwHRRIV6oC&amp;amp;printsec=frontcover&amp;amp;img=1&amp;amp;zoom=1&amp;amp;l=90" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="90" src="http://books.google.com/books?id=-alwHRRIV6oC&amp;amp;printsec=frontcover&amp;amp;img=1&amp;amp;zoom=1&amp;amp;l=90" width="70" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;i&gt;Chapter 6&lt;/i&gt;&lt;br /&gt;&lt;i&gt;Surveying Computer Options.&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;&lt;i&gt;&lt;br /&gt;&lt;/i&gt;&lt;br /&gt;&lt;i&gt;...... we must mention the fact that in a significant number of business situations no accounting software package does exactly what you did before in the same way. Every accounting package is a compromise because it offers the features that someone else decided are important for the majority of businesses. The decision you may have to make is whether to &lt;b&gt;modify your business processes&lt;/b&gt; to fall into line with the new accounting software &lt;b&gt;or have some bespoke modification&lt;/b&gt; to the accounting package you decide to buy. The simplest and cheapest solution is to fall into line with your chosen accounting software.&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Get the gist?&lt;br /&gt;The choice is.. change how you do things, or make the software do what you need it to, and the author suggests the former.&lt;br /&gt;&lt;br /&gt;I believe it is a shame that ANYONE holds this view. Would we buy shoes that don't fit our feet? Why then do we have to use software that doesn't fit our needs?&lt;br /&gt;&lt;br /&gt;Get an open source solution that is the closest fit, then get it modified.&lt;br /&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8109854847430899154-5909623208884720988?l=rowinggolfer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rowinggolfer.blogspot.com/feeds/5909623208884720988/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8109854847430899154&amp;postID=5909623208884720988' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/5909623208884720988'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/5909623208884720988'/><link rel='alternate' type='text/html' href='http://rowinggolfer.blogspot.com/2011/08/customised-business-software-or.html' title='Customised Business Software or Software Customised Businesses?'/><author><name>Neil</name><uri>http://www.blogger.com/profile/06112117080373993301</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/-GEhvN_g7Kk4/TfnhG7DCMiI/AAAAAAAAAHo/HmAn1zC-xXM/s220/geek.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8109854847430899154.post-3411923357519335066</id><published>2011-06-15T11:01:00.000+01:00</published><updated>2011-06-15T11:01:23.802+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='launchpad code hosting bzr hg'/><title type='text'>Screw you launchpad</title><content type='html'>I've moved my code hosting to http://code.google.com/p/openmolar/, switching from bzr to hg.&lt;br /&gt;&lt;br /&gt;Why?&lt;br /&gt;https://bugs.launchpad.net/launchpad/+bug/220082&lt;br /&gt;&lt;br /&gt;I'm absolutely bloody furious.&lt;br /&gt;&lt;br /&gt;However, I feel this move was absolutely necessary. &lt;br /&gt;Launchpad is falling behind other code hosting sites from a &lt;i&gt;my perspective as a coder&lt;/i&gt;. Only time will tell if I am right.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;p.s. as a dentist.. should i really be using hg?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8109854847430899154-3411923357519335066?l=rowinggolfer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rowinggolfer.blogspot.com/feeds/3411923357519335066/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8109854847430899154&amp;postID=3411923357519335066' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/3411923357519335066'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/3411923357519335066'/><link rel='alternate' type='text/html' href='http://rowinggolfer.blogspot.com/2011/06/screw-you-launchpad.html' title='Screw you launchpad'/><author><name>Neil</name><uri>http://www.blogger.com/profile/06112117080373993301</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/-GEhvN_g7Kk4/TfnhG7DCMiI/AAAAAAAAAHo/HmAn1zC-xXM/s220/geek.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8109854847430899154.post-5418827623036701023</id><published>2011-06-13T23:20:00.000+01:00</published><updated>2011-06-13T23:20:54.590+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='pyqt pyqt4'/><title type='text'>PyQt QSysTrayIcon Example</title><content type='html'>&lt;a href="http://1.bp.blogspot.com/-MJ7nHJIoDFE/TfaMY9i2VfI/AAAAAAAAAHg/Cz9SzJ2l-fE/s1600/systray.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"&gt;&lt;img border="0" height="200" src="http://1.bp.blogspot.com/-MJ7nHJIoDFE/TfaMY9i2VfI/AAAAAAAAAHg/Cz9SzJ2l-fE/s200/systray.png" width="150" /&gt;&lt;/a&gt;Following A question in #pyqt on irc.freenode.net, I had a play with QSysTrayIcon.&lt;br /&gt;&lt;br /&gt;"Hugo__" wanted a tray icon in Gnome which showed a different menu for left and right clicking.&lt;br /&gt;&lt;br /&gt;Here's one way to achieve such with PyQt4.&lt;br /&gt;&lt;br /&gt;Note - I use QtGui.QIcon.fromTheme here.. and do NOT supply a fallback icon.&lt;br /&gt;Hence, the icons will only show on freedesktop standards compliant environments (gnome, KDE etc..)&lt;br /&gt;&lt;br /&gt;see &lt;a href="http://standards.freedesktop.org/icon-naming-spec/icon-naming-spec-latest.html"&gt;&lt;br /&gt;http://standards.freedesktop.org/icon-naming-spec/icon-naming-spec-latest.html&lt;/a&gt; for details.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br clear="all" /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;#! /usr/bin/env python&lt;br /&gt;from PyQt4 import QtGui, QtCore&lt;br /&gt;&lt;br /&gt;class RightClickMenu(QtGui.QMenu):&lt;br /&gt;    def __init__(self, parent=None):&lt;br /&gt;        QtGui.QMenu.__init__(self, "Edit", parent)&lt;br /&gt;&lt;br /&gt;        icon = QtGui.QIcon.fromTheme("edit-cut")&lt;br /&gt;        self.addAction(QtGui.QAction(icon, "&amp;amp;Cut", self))&lt;br /&gt;&lt;br /&gt;        icon = QtGui.QIcon.fromTheme("edit-copy")&lt;br /&gt;        self.addAction(QtGui.QAction(icon, "Copy (&amp;amp;X)", self))&lt;br /&gt;&lt;br /&gt;        icon = QtGui.QIcon.fromTheme("edit-paste")&lt;br /&gt;        self.addAction(QtGui.QAction(icon, "&amp;amp;Paste", self))&lt;br /&gt;    &lt;br /&gt;class LeftClickMenu(QtGui.QMenu):&lt;br /&gt;    def __init__(self, parent=None):&lt;br /&gt;        QtGui.QMenu.__init__(self, "File", parent)&lt;br /&gt;&lt;br /&gt;        icon = QtGui.QIcon.fromTheme("document-new")&lt;br /&gt;        self.addAction(QtGui.QAction(icon, "&amp;amp;New", self))&lt;br /&gt;&lt;br /&gt;        icon = QtGui.QIcon.fromTheme("document-open")&lt;br /&gt;        self.addAction(QtGui.QAction(icon, "&amp;amp;Open", self))&lt;br /&gt;&lt;br /&gt;        icon = QtGui.QIcon.fromTheme("document-save")&lt;br /&gt;        self.addAction(QtGui.QAction(icon, "&amp;amp;Save", self))&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;class SystemTrayIcon(QtGui.QSystemTrayIcon):&lt;br /&gt;    def __init__(self, parent=None):&lt;br /&gt;        QtGui.QSystemTrayIcon.__init__(self, parent)&lt;br /&gt;        self.setIcon(QtGui.QIcon.fromTheme("document-save"))&lt;br /&gt;&lt;br /&gt;        self.right_menu = RightClickMenu()&lt;br /&gt;        self.setContextMenu(self.right_menu)&lt;br /&gt;&lt;br /&gt;        self.left_menu = LeftClickMenu()&lt;br /&gt;    &lt;br /&gt;        self.activated.connect(self.click_trap)&lt;br /&gt;&lt;br /&gt;    def click_trap(self, value):&lt;br /&gt;        if value == self.Trigger: #left click!&lt;br /&gt;            self.left_menu.exec_(QtGui.QCursor.pos())&lt;br /&gt;&lt;br /&gt;    def welcome(self):&lt;br /&gt;        self.showMessage("Hello", "I should be aware of both buttons")&lt;br /&gt;        &lt;br /&gt;    def show(self):&lt;br /&gt;        QtGui.QSystemTrayIcon.show(self)&lt;br /&gt;        QtCore.QTimer.singleShot(100, self.welcome)&lt;br /&gt;&lt;br /&gt;if __name__ == "__main__":&lt;br /&gt;    app = QtGui.QApplication([])&lt;br /&gt;&lt;br /&gt;    tray = SystemTrayIcon()&lt;br /&gt;    tray.show()&lt;br /&gt;    &lt;br /&gt;    #set the exec loop going&lt;br /&gt;    app.exec_()&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8109854847430899154-5418827623036701023?l=rowinggolfer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rowinggolfer.blogspot.com/feeds/5418827623036701023/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8109854847430899154&amp;postID=5418827623036701023' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/5418827623036701023'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/5418827623036701023'/><link rel='alternate' type='text/html' href='http://rowinggolfer.blogspot.com/2011/06/pyqt-qsystrayicon-example.html' title='PyQt QSysTrayIcon Example'/><author><name>Neil</name><uri>http://www.blogger.com/profile/06112117080373993301</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/-GEhvN_g7Kk4/TfnhG7DCMiI/AAAAAAAAAHo/HmAn1zC-xXM/s220/geek.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-MJ7nHJIoDFE/TfaMY9i2VfI/AAAAAAAAAHg/Cz9SzJ2l-fE/s72-c/systray.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8109854847430899154.post-8846184505611798444</id><published>2011-06-13T11:36:00.000+01:00</published><updated>2011-06-13T11:36:12.835+01:00</updated><title type='text'>Making PyQt experimentation easier</title><content type='html'>Over the past few months, I've encountered the same issue. namely, I want to do *SOMETHING* with the openmolar project be it:&lt;br /&gt;&lt;ol&gt;&lt;li&gt; document with sphinx&lt;/li&gt;&lt;li&gt;write unittests (I know... I should have written them 1st..)&lt;/li&gt;&lt;li&gt;make a deb or rpm&lt;/li&gt;&lt;li&gt;make a windows executable&lt;/li&gt;&lt;li&gt;convert to python 3 with 2to3 etc..&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;&lt;a href="http://2.bp.blogspot.com/-Dt8OEkHlwDk/TfXl3ian98I/AAAAAAAAAHU/IT1o9zZcTq4/s1600/example_pyqt_app.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"&gt;&lt;img border="0" height="219" src="http://2.bp.blogspot.com/-Dt8OEkHlwDk/TfXl3ian98I/AAAAAAAAAHU/IT1o9zZcTq4/s320/example_pyqt_app.png" width="320" /&gt;&lt;/a&gt;Rather than risk breaking my main codebase however, I believe it always helps to attempt this stuff with a smaller application first I think. So I've written one. It is trivial enough to keep the codebase simple, but complex enough to be realistic.&lt;br /&gt;&lt;br /&gt;It raises dialogs, stores data, etc. &lt;br /&gt;&lt;br /&gt;I've tried to follow a lot of my coding style choices (which you may hate), but on checking the modules with pylint, most get a 10/10, only decreasing when PyQt4 own naming conventions dictate.&lt;br /&gt;&lt;br /&gt;anyways, to cut to the chase.. the code is here is anyone wants a play. This is in the public domain, so do with it as you wish.&lt;br /&gt;download it from my dropbox account &lt;a href="http://dl.dropbox.com/u/1989100/example_pyqt_app.tar.bz2"&gt;http://dl.dropbox.com/u/1989100/example_pyqt_app.tar.bz2&lt;/a&gt; &lt;br /&gt;&lt;br /&gt;My current focus is writing unittests (something I am ashamed to admit I have never done before), and it is proving VERY interesting.&lt;br /&gt;&lt;br /&gt;for example. dialogs are interesting, in that the exec_ function needs to be called to ensure correct code coverage. Calling that during a test run causes a pause in the procedings.. not good.&lt;br /&gt;&lt;br /&gt;So what is the best way to call accept() or reject() on such a dialog?&lt;br /&gt;I am experimenting with installEventFilter into QApplication itself, and accepting the dialog when the focus event is encountered seems to be working really well.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8109854847430899154-8846184505611798444?l=rowinggolfer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rowinggolfer.blogspot.com/feeds/8846184505611798444/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8109854847430899154&amp;postID=8846184505611798444' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/8846184505611798444'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/8846184505611798444'/><link rel='alternate' type='text/html' href='http://rowinggolfer.blogspot.com/2011/06/making-pyqt-experimentation-easier.html' title='Making PyQt experimentation easier'/><author><name>Neil</name><uri>http://www.blogger.com/profile/06112117080373993301</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/-GEhvN_g7Kk4/TfnhG7DCMiI/AAAAAAAAAHo/HmAn1zC-xXM/s220/geek.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/-Dt8OEkHlwDk/TfXl3ian98I/AAAAAAAAAHU/IT1o9zZcTq4/s72-c/example_pyqt_app.png' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8109854847430899154.post-4889148873579100008</id><published>2011-06-07T13:21:00.000+01:00</published><updated>2011-06-07T13:21:35.625+01:00</updated><title type='text'>Python Class - Am I a subclass?</title><content type='html'>&lt;pre style="white-space: pre-wrap; word-wrap: break-word;"&gt;Problem...&lt;/pre&gt;&lt;pre style="white-space: pre-wrap; word-wrap: break-word;"&gt;in #python on freenode, a question was asked about identifying a subclass during the __init__ method.&lt;/pre&gt;&lt;pre style="white-space: pre-wrap; word-wrap: break-word;"&gt;I came up with this example. &lt;/pre&gt;&lt;pre style="white-space: pre-wrap; word-wrap: break-word;"&gt;&lt;/pre&gt;&lt;pre style="white-space: pre-wrap; word-wrap: break-word;"&gt;&lt;pre&gt;&lt;/pre&gt;&lt;pre style="white-space: pre-wrap; word-wrap: break-word;"&gt;class Example(object):&lt;br /&gt;    def __init__(self):&lt;br /&gt;        if self.__class__ != Example.mro()[0]:&lt;br /&gt;            print "I am an instance of a subclass of Example"&lt;br /&gt;        else:&lt;br /&gt;            print "I am an instance of Example"&lt;br /&gt;&lt;br /&gt;class ExampleDeritive(Example):&lt;br /&gt;    ''' the most basic of subclasses! '''&lt;br /&gt;    pass&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; Example()&lt;br /&gt;I am an instance of Example&lt;br /&gt;&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; ExampleDeritive()&lt;br /&gt;I am an instance of a subclass of Example&lt;/pre&gt;&lt;pre style="white-space: pre-wrap; word-wrap: break-word;"&gt;&lt;/pre&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8109854847430899154-4889148873579100008?l=rowinggolfer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rowinggolfer.blogspot.com/feeds/4889148873579100008/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8109854847430899154&amp;postID=4889148873579100008' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/4889148873579100008'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/4889148873579100008'/><link rel='alternate' type='text/html' href='http://rowinggolfer.blogspot.com/2011/06/python-class-am-i-subclass.html' title='Python Class - Am I a subclass?'/><author><name>Neil</name><uri>http://www.blogger.com/profile/06112117080373993301</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/-GEhvN_g7Kk4/TfnhG7DCMiI/AAAAAAAAAHo/HmAn1zC-xXM/s220/geek.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8109854847430899154.post-713953771628140978</id><published>2011-05-23T14:33:00.000+01:00</published><updated>2011-05-23T14:36:42.081+01:00</updated><title type='text'>ubuntu-dental doppleganger</title><content type='html'>my dental life and open source advocacy seldom collide.&lt;br /&gt;&lt;br /&gt;however, I'm struck by the likeness between these two women, who are leaders in each field.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="https://www.blackhillsclinic.com/assets/images/Marilou-Ciantar.jpg" imageanchor="1" style="clear: left; display: inline !important; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="200" src="https://www.blackhillsclinic.com/assets/images/Marilou-Ciantar.jpg" width="129" /&gt;&lt;/a&gt;&lt;/div&gt;This is Marilou-Ciantar, arguably Scotland's most&amp;nbsp;eminent&amp;nbsp;periodontal specialist.&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://www.linuxuser.co.uk/wp-content/uploads/2010/07/Jane-Silber-Large_web.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="200" src="http://www.linuxuser.co.uk/wp-content/uploads/2010/07/Jane-Silber-Large_web.jpg" width="132" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;and this is Jane Silber, CEO of canonical (the company behind ubuntu)&lt;br /&gt;&lt;br /&gt;uncanny in my opinion.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8109854847430899154-713953771628140978?l=rowinggolfer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rowinggolfer.blogspot.com/feeds/713953771628140978/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8109854847430899154&amp;postID=713953771628140978' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/713953771628140978'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/713953771628140978'/><link rel='alternate' type='text/html' href='http://rowinggolfer.blogspot.com/2011/05/ubuntu-dental-doppleganger.html' title='ubuntu-dental doppleganger'/><author><name>Neil</name><uri>http://www.blogger.com/profile/06112117080373993301</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/-GEhvN_g7Kk4/TfnhG7DCMiI/AAAAAAAAAHo/HmAn1zC-xXM/s220/geek.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8109854847430899154.post-7355660361205994344</id><published>2011-04-08T19:01:00.000+01:00</published><updated>2011-04-08T19:41:51.760+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python pyqt4'/><title type='text'>Hiding the MenuBar in a PyQt application.</title><content type='html'>I've long been a fan of the firefox plugin "tiny menu" where screen real estate is preserved by compressing the application's menubar down into a single menu button.&lt;br /&gt;&lt;br /&gt;Here's one way to achieve the same effect in pyqt4.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://4.bp.blogspot.com/-z-5RNLhgTb4/TZ9LBjXbULI/AAAAAAAAAG8/B62Crwu7_BQ/s1600/tiny_menu1.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"&gt;&lt;img border="0" src="http://4.bp.blogspot.com/-z-5RNLhgTb4/TZ9LBjXbULI/AAAAAAAAAG8/B62Crwu7_BQ/s1600/tiny_menu1.png" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://3.bp.blogspot.com/-OOXZG1FkJlg/TZ9LBpluWlI/AAAAAAAAAHE/VLtvAGx1wdg/s1600/tiny_menu2.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/-OOXZG1FkJlg/TZ9LBpluWlI/AAAAAAAAAHE/VLtvAGx1wdg/s1600/tiny_menu2.png" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;span style="font-size: xx-small;"&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span style="font-size: xx-small;"&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span style="font-size: xx-small;"&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span style="font-size: xx-small;"&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span style="font-size: xx-small;"&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span style="font-size: xx-small;"&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span style="font-size: xx-small;"&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span style="font-size: xx-small;"&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span style="font-size: xx-small;"&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span style="font-size: xx-small;"&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span style="font-size: xx-small;"&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span style="font-size: xx-small;"&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span style="font-size: xx-small;"&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span style="font-size: xx-small;"&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span style="font-size: xx-small;"&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span style="font-size: xx-small;"&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span style="font-size: xx-small;"&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span style="font-size: xx-small;"&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span style="font-size: xx-small;"&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span style="font-size: xx-small;"&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span style="font-size: xx-small;"&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span style="font-size: xx-small;"&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span style="font-size: xx-small;"&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span style="font-size: xx-small;"&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;#! /usr/bin/env python&lt;br /&gt;# -*- coding: utf-8 -*-&lt;br /&gt;'''&lt;br /&gt;A simple application with a shrinkable menu bar.&lt;br /&gt;(similar functionality to firefox4)&lt;br /&gt;&lt;br /&gt;At any point either the tiny menu or menubar should be visible.&lt;br /&gt;Therefore if the toolbar is hidden, the menu will re-appear.&lt;br /&gt;&lt;br /&gt;to experience this... either &lt;br /&gt;&lt;br /&gt;    click View&amp;gt;Tiny Menu or hit F11&lt;br /&gt;'''&lt;br /&gt;&lt;br /&gt;from PyQt4 import QtGui, QtCore&lt;br /&gt;&lt;br /&gt;class DockableMenuBar(QtGui.QMenuBar):&lt;br /&gt;    def __init__(self, parent=None):&lt;br /&gt;        QtGui.QMenuBar.__init__(self, parent)&lt;br /&gt;        &lt;br /&gt;        self.toggleViewAction = QtGui.QAction(_("Tiny &amp;amp;Menu"), parent)&lt;br /&gt;        self.toggleViewAction.setShortcut('f11')&lt;br /&gt;        self.toggleViewAction.setCheckable(True)&lt;br /&gt;        self.toggleViewAction.triggered.connect(self.toggle_visability)&lt;br /&gt;        &lt;br /&gt;        self.menu_view = QtGui.QMenu(_("&amp;amp;View"), self)&lt;br /&gt;        self.menu_view.addAction(self.toggleViewAction)&lt;br /&gt;        self.addMenu(self.menu_view)&lt;br /&gt;        &lt;br /&gt;        self._menu_button = None&lt;br /&gt;        &lt;br /&gt;    @property&lt;br /&gt;    def menu_button(self):&lt;br /&gt;        self._menu_button = QtGui.QToolButton()&lt;br /&gt;        self._menu_button.setPopupMode(QtGui.QToolButton.InstantPopup)&lt;br /&gt;        self._menu_button.setText(_("Menu"))&lt;br /&gt;        self._menu_button.setMenu(self.mini_menu)        &lt;br /&gt;        self._menu_button.setToolButtonStyle(&lt;br /&gt;            QtCore.Qt.ToolButtonFollowStyle)&lt;br /&gt;        return self._menu_button&lt;br /&gt;&lt;br /&gt;    @property&lt;br /&gt;    def mini_menu(self):&lt;br /&gt;        self._mini_menu = QtGui.QMenu()&lt;br /&gt;        for action in self.actions():&lt;br /&gt;            self._mini_menu.addAction(action)&lt;br /&gt;        return self._mini_menu&lt;br /&gt;        &lt;br /&gt;    def addViewOption(self, action):&lt;br /&gt;        '''&lt;br /&gt;        add an action to the 'view' category of the toolbar&lt;br /&gt;        ''' &lt;br /&gt;        self.menu_view.addAction(action)&lt;br /&gt;        &lt;br /&gt;    def addMenu(self, *args):&lt;br /&gt;        try:&lt;br /&gt;            return self.insertMenu(self.actions()[0], *args)&lt;br /&gt;        except IndexError:&lt;br /&gt;            return QtGui.QMenuBar.addMenu(self, *args)&lt;br /&gt;            &lt;br /&gt;    def addAction(self, *args):&lt;br /&gt;        try:&lt;br /&gt;            return self.insertAction(self.actions()[0], *args)&lt;br /&gt;        except IndexError:&lt;br /&gt;            return QtGui.QMenuBar.addAction(self, *args)        &lt;br /&gt;&lt;br /&gt;    def toggle_visability(self, set_visible):&lt;br /&gt;        self.setVisible(not set_visible)&lt;br /&gt;        if set_visible:&lt;br /&gt;            self.emit(QtCore.SIGNAL("mini menu required"), self.menu_button)&lt;br /&gt;        else:&lt;br /&gt;            self.emit(QtCore.SIGNAL("hide mini menu"))&lt;br /&gt;            &lt;br /&gt;    def setNotVisible(self, menu_bar_visible):&lt;br /&gt;        '''&lt;br /&gt;        make sure that we don't end up with neither menu visible!&lt;br /&gt;        ''' &lt;br /&gt;        if not menu_bar_visible:&lt;br /&gt;            self.setVisible(True)&lt;br /&gt;        &lt;br /&gt;class DockAwareToolBar(QtGui.QToolBar):&lt;br /&gt;    def __init__(self, parent=None):&lt;br /&gt;        QtGui.QToolBar.__init__(self, parent)&lt;br /&gt;        self.setToolButtonStyle(QtCore.Qt.ToolButtonTextBesideIcon)&lt;br /&gt;        self.setObjectName("DockAwareToolbar") #for QSettings&lt;br /&gt;        &lt;br /&gt;        # this should happen by default IMO.&lt;br /&gt;        self.toggleViewAction().setText(_("&amp;amp;ToolBar"))&lt;br /&gt;&lt;br /&gt;    def add_mini_menu(self, menu_button):&lt;br /&gt;        self._menu_button = menu_button&lt;br /&gt;        if self.actions():&lt;br /&gt;            self.insertWidget(self.actions()[0], menu_button)&lt;br /&gt;        else:&lt;br /&gt;            self.addWidget(menu_button)&lt;br /&gt;        self.show()&lt;br /&gt;    &lt;br /&gt;    def clear_mini_menu(self):&lt;br /&gt;        self._menu_button.hide()&lt;br /&gt;        self._menu_button.setParent(None)&lt;br /&gt;        self._menu_button.deleteLater()&lt;br /&gt;        self._menu_button = None&lt;br /&gt;              &lt;br /&gt;class TestMainWindow(QtGui.QMainWindow):&lt;br /&gt;    def __init__(self, parent=None):&lt;br /&gt;        QtGui.QMainWindow.__init__(self, parent)&lt;br /&gt;        &lt;br /&gt;        ## initiate instances of our classes&lt;br /&gt;        &lt;br /&gt;        self.toolbar = DockAwareToolBar()        &lt;br /&gt;        menu_bar = DockableMenuBar(self)&lt;br /&gt;        &lt;br /&gt;        ## the menu bar needs this action adding&lt;br /&gt;        menu_bar.addViewOption(self.toolbar.toggleViewAction())&lt;br /&gt;        &lt;br /&gt;        ## add them to the app&lt;br /&gt;        self.addToolBar(QtCore.Qt.TopToolBarArea, self.toolbar)&lt;br /&gt;        self.setMenuBar(menu_bar)&lt;br /&gt;        &lt;br /&gt;        ## make them aware of one another&lt;br /&gt;        self.connect(self.menuBar(), QtCore.SIGNAL("mini menu required"),&lt;br /&gt;            self.toolbar.add_mini_menu)&lt;br /&gt;        self.connect(self.menuBar(), QtCore.SIGNAL("hide mini menu"),&lt;br /&gt;            self.toolbar.clear_mini_menu)&lt;br /&gt;        self.toolbar.toggleViewAction().triggered.connect(&lt;br /&gt;            self.menuBar().setNotVisible)&lt;br /&gt;        &lt;br /&gt;        ## some arbitrary stuff to make the app more realistic&lt;br /&gt;        file_action = QtGui.QAction("&amp;amp;File", self)&lt;br /&gt;        self.menuBar().addAction(file_action)&lt;br /&gt;        &lt;br /&gt;        line_edit = QtGui.QLineEdit("http://google.com")&lt;br /&gt;        self.toolbar.addWidget(line_edit)&lt;br /&gt;        &lt;br /&gt;        go_but = QtGui.QPushButton("Go!")&lt;br /&gt;        go_but.setFixedWidth(60)&lt;br /&gt;        self.toolbar.addWidget(go_but)&lt;br /&gt;        &lt;br /&gt;        te = QtGui.QTextEdit()&lt;br /&gt;        self.setCentralWidget(te)&lt;br /&gt;        te.setText(__doc__)&lt;br /&gt;        &lt;br /&gt;&lt;br /&gt;if __name__ == "__main__":&lt;br /&gt;    import gettext&lt;br /&gt;    gettext.install("")&lt;br /&gt;    &lt;br /&gt;    app = QtGui.QApplication([])&lt;br /&gt;    mw = TestMainWindow()&lt;br /&gt;    mw.show()&lt;br /&gt;    app.exec_()&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8109854847430899154-7355660361205994344?l=rowinggolfer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rowinggolfer.blogspot.com/feeds/7355660361205994344/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8109854847430899154&amp;postID=7355660361205994344' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/7355660361205994344'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/7355660361205994344'/><link rel='alternate' type='text/html' href='http://rowinggolfer.blogspot.com/2011/04/hiding-menubar-in-pyqt-application.html' title='Hiding the MenuBar in a PyQt application.'/><author><name>Neil</name><uri>http://www.blogger.com/profile/06112117080373993301</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/-GEhvN_g7Kk4/TfnhG7DCMiI/AAAAAAAAAHo/HmAn1zC-xXM/s220/geek.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/-z-5RNLhgTb4/TZ9LBjXbULI/AAAAAAAAAG8/B62Crwu7_BQ/s72-c/tiny_menu1.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8109854847430899154.post-8320179969704192119</id><published>2011-04-07T17:23:00.000+01:00</published><updated>2011-04-07T17:23:31.546+01:00</updated><title type='text'>Python Class Attributes. A Quiz!</title><content type='html'>So take a look at this code.&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;#! /usr/bin/env python&lt;br /&gt;'''&lt;br /&gt;A simple class demonstrating attributes&lt;br /&gt;'''&lt;br /&gt;ID_COUNTER = 0&lt;br /&gt;&lt;br /&gt;class Person(object):&lt;br /&gt;    genus = "homo sapien"&lt;br /&gt;&lt;br /&gt;    def __init__(self, name, sex="M"):&lt;br /&gt;        global ID_COUNTER&lt;br /&gt;    &lt;br /&gt;        assert sex in ("M", "F"), 'INVALID SEX "%s" must be "M" or "F"'% sex&lt;br /&gt;        ID_COUNTER += 1&lt;br /&gt;        self.id = ID_COUNTER&lt;br /&gt;        self.name = name&lt;br /&gt;        self._sex = sex&lt;br /&gt;        self._profession = None&lt;br /&gt;&lt;br /&gt;    @property&lt;br /&gt;    def sex(self):&lt;br /&gt;        return "Male" if self._sex=="M" else "Female"&lt;br /&gt;&lt;br /&gt;    @property&lt;br /&gt;    def profession(self):&lt;br /&gt;        if self._profession is None:&lt;br /&gt;           return "unknown"&lt;br /&gt;        return self._profession&lt;br /&gt;&lt;br /&gt;    def set_profession(self, profession):&lt;br /&gt;        self._profession = profession&lt;br /&gt;&lt;br /&gt;    def __repr__(self):&lt;br /&gt;        return "Person %03d:\n\t%s\n\tGenus\t(%s)\n\t%s\n\t%s"% (&lt;br /&gt;            self.id,&lt;br /&gt;            self.name,&lt;br /&gt;            self.genus,&lt;br /&gt;            self.sex,&lt;br /&gt;            self.profession)&lt;br /&gt;&lt;br /&gt;if __name__ == "__main__":&lt;br /&gt;    person1 = Person("Neil")&lt;br /&gt;    person1.set_profession("dentist")&lt;br /&gt;&lt;br /&gt;    person2 = Person("Joan", "F")&lt;br /&gt;    person2.genus = "Neanderthal"&lt;br /&gt;&lt;br /&gt;    person3 = Person("Timrit", "M")&lt;br /&gt;    person3.set_profession("refrigeration")&lt;br /&gt;    &lt;br /&gt;    for object_ in (Person.genus, person1, person2, person3):&lt;br /&gt;        print object_&lt;br /&gt;        print&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;which gives the following output&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;homo sapien&lt;br /&gt;&lt;br /&gt;Person 001:&lt;br /&gt; Neil&lt;br /&gt; Genus (homo sapien)&lt;br /&gt; Male&lt;br /&gt; dentist&lt;br /&gt;&lt;br /&gt;Person 002:&lt;br /&gt; Joan&lt;br /&gt; Genus (Neanderthal)&lt;br /&gt; Female&lt;br /&gt; unknown&lt;br /&gt;&lt;br /&gt;Person 003:&lt;br /&gt; Timrit&lt;br /&gt; Genus (homo sapien)&lt;br /&gt; Male&lt;br /&gt; refrigeration&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;And here are your questions.&lt;br /&gt;1. Why is the Global statement used on line 11?&lt;br /&gt;2. is there a better way of implementing a unique serial ID for these objects?&lt;br /&gt;3. What would happen if I tried to create an instance with the following call?&lt;br /&gt;&lt;pre style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;person4 = Person("ArtV61", "unknown")&lt;/pre&gt;4. is genus a "class attribute" or an "instance attribute"? &lt;br /&gt;5. what is the difference between a "class attribute" or an "instance attribute"?&lt;br /&gt;6. is Person an old or new style class?&lt;br /&gt;7. what would need to change in this code to make it run under python3?&lt;br /&gt;8. what is the __repr__ function for, and what would be the output if it were deleted?&lt;br /&gt;9. what namespace is the __name__ variable found in?&lt;br /&gt;10. why is the trailing underscore used for object_ on the penultimate line of code?&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Answers, as always to linc AT thelinuxlink.net, quoting "QUIZ" in the subject field.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8109854847430899154-8320179969704192119?l=rowinggolfer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rowinggolfer.blogspot.com/feeds/8320179969704192119/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8109854847430899154&amp;postID=8320179969704192119' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/8320179969704192119'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/8320179969704192119'/><link rel='alternate' type='text/html' href='http://rowinggolfer.blogspot.com/2011/04/python-class-attributes-quiz.html' title='Python Class Attributes. A Quiz!'/><author><name>Neil</name><uri>http://www.blogger.com/profile/06112117080373993301</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/-GEhvN_g7Kk4/TfnhG7DCMiI/AAAAAAAAAHo/HmAn1zC-xXM/s220/geek.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8109854847430899154.post-3863421655521290711</id><published>2011-01-15T23:36:00.000Z</published><updated>2011-01-15T23:36:43.462Z</updated><title type='text'>using pyqt4 to validate XML Schemas</title><content type='html'>Follow up to the problem solved in the last posting.&lt;br /&gt;lxml worked great, but I don't want to burden folks with yet another 3rd party module.&lt;br /&gt;&lt;br /&gt;so I once again looked to pyqt4 for help....&lt;br /&gt;and.. &lt;br /&gt;&lt;br /&gt;&lt;pre&gt;from PyQt4.QtXmlPatterns import QXmlSchemaValidator, QXmlSchema&lt;br /&gt;&lt;br /&gt;#open up the xsd file - and load it into QXMLSchema&lt;br /&gt;f=open("foo.xsd", "r")&lt;br /&gt;xsd = f.read()&lt;br /&gt;f.close()&lt;br /&gt;&lt;br /&gt;schema = QXmlSchema()&lt;br /&gt;schema.load(xsd)&lt;br /&gt;&lt;br /&gt;#now the xml itself.&lt;br /&gt;f = open("foo.xml", "r")&lt;br /&gt;xml = f.read()&lt;br /&gt;f.close()&lt;br /&gt;&lt;br /&gt;validator = QXmlSchemaValidator(schema)&lt;br /&gt;print (validator.validate(xml))&lt;br /&gt;&lt;br /&gt;#Returns True :)&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8109854847430899154-3863421655521290711?l=rowinggolfer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rowinggolfer.blogspot.com/feeds/3863421655521290711/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8109854847430899154&amp;postID=3863421655521290711' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/3863421655521290711'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/3863421655521290711'/><link rel='alternate' type='text/html' href='http://rowinggolfer.blogspot.com/2011/01/using-pyqt4-to-validate-xml-schemas.html' title='using pyqt4 to validate XML Schemas'/><author><name>Neil</name><uri>http://www.blogger.com/profile/06112117080373993301</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/-GEhvN_g7Kk4/TfnhG7DCMiI/AAAAAAAAAHo/HmAn1zC-xXM/s220/geek.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8109854847430899154.post-270150756226150616</id><published>2011-01-15T23:14:00.000Z</published><updated>2011-01-15T23:14:31.681Z</updated><title type='text'>validating xml with python</title><content type='html'>&lt;h4&gt;THE XML&lt;/h4&gt;I wanted to validate the XML sheets produced by auteur&lt;br /&gt;example XML produced by auteur.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&amp;lt;?xml version="1.0" encoding="UTF-8"?&amp;gt;&lt;br /&gt;    &lt;br /&gt;&amp;lt;auteur&amp;gt;&lt;br /&gt;  &amp;lt;source&amp;gt;&lt;br /&gt;    &amp;lt;location&amp;gt;/home/neil/Videos/2010_04_canada/M2U00547.MPG&amp;lt;/location&amp;gt;&lt;br /&gt;      &amp;lt;timestamp pos="11" /&amp;gt;&lt;br /&gt;      &amp;lt;clip end="7.5" id="0001" start="1.5" /&amp;gt;&lt;br /&gt;      &amp;lt;clip end="13.6" id="0002" start="7.5" /&amp;gt;&lt;br /&gt;      &amp;lt;clip end="1.5" id="0003" start="0.0" /&amp;gt;&lt;br /&gt;  &amp;lt;/source&amp;gt;&lt;br /&gt;  &lt;br /&gt;  &amp;lt;source&amp;gt;&lt;br /&gt;    &amp;lt;location&amp;gt;/home/neil/Videos/2010_04_canada/M2U00549.MPG&amp;lt;/location&amp;gt;&lt;br /&gt;    &amp;lt;timestamp pos="2.678" /&amp;gt;&lt;br /&gt;  &amp;lt;/source&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;/auteur&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;h4&gt;The Schema&lt;/h4&gt;and here's the schema I wrote to check the validity of that data.&lt;br /&gt;(saved as foo.xsd)&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&amp;lt;?xml version="1.0"?&amp;gt;&lt;br /&gt;&amp;lt;xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;xs:annotation&amp;gt;&lt;br /&gt;    &amp;lt;xs:documentation&amp;gt;&lt;br /&gt;       The rules in this schema will be used to validate &lt;br /&gt;       the content of an auteur project file.&lt;br /&gt;    &amp;lt;/xs:documentation&amp;gt;&lt;br /&gt;    &amp;lt;xs:appinfo source="http://www.auteur-project.org" &amp;gt; &amp;lt;/xs:appinfo&amp;gt;&lt;br /&gt;&amp;lt;/xs:annotation&amp;gt;&lt;br /&gt;&amp;lt;!--RULES START HERE --&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;!-- ROOT NODE --&amp;gt;&lt;br /&gt;&amp;lt;xs:element name="auteur" &amp;gt;&lt;br /&gt;&amp;lt;xs:complexType&amp;gt;&lt;br /&gt;&amp;lt;xs:sequence&amp;gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;  &amp;lt;!-- SOURCES --&amp;gt;&lt;br /&gt;  &amp;lt;xs:element name="source" minOccurs="0" maxOccurs="unbounded"&amp;gt;&lt;br /&gt;  &lt;br /&gt;    &amp;lt;xs:complexType&amp;gt;&lt;br /&gt;    &amp;lt;xs:sequence&amp;gt;&lt;br /&gt;        &amp;lt;!-- only 1 location allowed per source --&amp;gt;&lt;br /&gt;        &amp;lt;xs:element name = "location"  type="xs:string" minOccurs="1" maxOccurs="1"/&amp;gt;&lt;br /&gt;        &lt;br /&gt;        &amp;lt;!-- TIMESTAMPS --&amp;gt;&lt;br /&gt;        &amp;lt;xs:element name = "timestamp" minOccurs="0" maxOccurs="unbounded" &amp;gt;&lt;br /&gt;          &amp;lt;xs:complexType&amp;gt;&lt;br /&gt;          &amp;lt;xs:attribute name="pos" type="xs:decimal" use="required" /&amp;gt;&lt;br /&gt;          &amp;lt;/xs:complexType&amp;gt;&lt;br /&gt;        &amp;lt;/xs:element&amp;gt;&lt;br /&gt;          &lt;br /&gt;        &amp;lt;!-- CLIPS --&amp;gt;&lt;br /&gt;        &amp;lt;xs:element name="clip" minOccurs="0" maxOccurs="unbounded" &amp;gt;&lt;br /&gt;            &amp;lt;xs:complexType&amp;gt;&lt;br /&gt;            &amp;lt;xs:attribute name = "id" type="xs:string"  use="required" /&amp;gt;&lt;br /&gt;            &amp;lt;xs:attribute name = "start" type="xs:decimal" /&amp;gt;&lt;br /&gt;            &amp;lt;xs:attribute name = "end" type="xs:decimal" /&amp;gt;&lt;br /&gt;            &amp;lt;/xs:complexType&amp;gt;&lt;br /&gt;        &amp;lt;/xs:element&amp;gt;&lt;br /&gt;        &lt;br /&gt;    &lt;br /&gt;    &amp;lt;/xs:sequence&amp;gt;&lt;br /&gt;    &amp;lt;/xs:complexType&amp;gt;  &lt;br /&gt;    &lt;br /&gt;  &amp;lt;/xs:element&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;/xs:sequence&amp;gt;&lt;br /&gt;&amp;lt;/xs:complexType&amp;gt;&lt;br /&gt;&amp;lt;/xs:element&amp;gt;&lt;br /&gt;&amp;lt;/xs:schema&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;h4&gt;THE PYTHON to put it all together&lt;/h4&gt;a short python script to check foo.xml's validity with foo.xsd&lt;br /&gt;&lt;br /&gt;(note lxml is NOT in python standard lib - a real pity!)&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;#! /usr/bin/env python&lt;br /&gt;from lxml import etree&lt;br /&gt;&lt;br /&gt;try:&lt;br /&gt;    doc = etree.parse("foo.xml")    &lt;br /&gt;    xsd = etree.parse("foo.xsd")&lt;br /&gt;&lt;br /&gt;    xmlschema = etree.XMLSchema(xsd)&lt;br /&gt;    xmlschema.assertValid(doc)&lt;br /&gt;    &lt;br /&gt;    print ("document validates!")&lt;br /&gt;&lt;br /&gt;except etree.XMLSyntaxError as e:&lt;br /&gt;    print ("PARSING ERROR", e)&lt;br /&gt;    &lt;br /&gt;except AssertionError as e:&lt;br /&gt;    print ("INVALID DOCUMENT", e)&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8109854847430899154-270150756226150616?l=rowinggolfer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rowinggolfer.blogspot.com/feeds/270150756226150616/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8109854847430899154&amp;postID=270150756226150616' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/270150756226150616'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/270150756226150616'/><link rel='alternate' type='text/html' href='http://rowinggolfer.blogspot.com/2011/01/validating-xml-with-python.html' title='validating xml with python'/><author><name>Neil</name><uri>http://www.blogger.com/profile/06112117080373993301</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/-GEhvN_g7Kk4/TfnhG7DCMiI/AAAAAAAAAHo/HmAn1zC-xXM/s220/geek.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8109854847430899154.post-8773393041851308554</id><published>2010-12-15T09:54:00.000Z</published><updated>2010-12-15T09:54:35.845Z</updated><title type='text'>QtCore.QDate gotcha for python dictionaries</title><content type='html'>I came across an odd little issue this morning while creating a data model for a diary I am writing.&lt;br /&gt;&lt;br /&gt;In the model, Data is stored in a dictionary, with dates as keys.&lt;br /&gt;For a variety of reasons, my first choice was to use a QDate for the keys, however this produced odd results.&lt;br /&gt;The following example code should demonstrate.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&gt;&gt;&gt; from PyQt4.QtCore import QDate&lt;br /&gt;&gt;&gt;&gt; mydict = {}&lt;br /&gt;&gt;&gt;&gt; for year in range(2009,2013):&lt;br /&gt;...     dt = QDate(year,1,1)&lt;br /&gt;...     while dt.year() == year:&lt;br /&gt;...         mydict[d] = "boo"&lt;br /&gt;...         dt = dt.addDays(1)&lt;br /&gt;&gt;&gt;&gt;&lt;br /&gt;&gt;&gt;&gt; mydict.keys()[:3]&lt;br /&gt;3: [PyQt4.QtCore.QDate(2011, 8, 21),&lt;br /&gt; PyQt4.QtCore.QDate(2009, 12, 17),&lt;br /&gt; PyQt4.QtCore.QDate(2009, 7, 15)]&lt;br /&gt;&gt;&gt;&gt;&lt;br /&gt;&gt;&gt;&gt; mydict[QDate(2011,8,21)]&lt;br /&gt;KeyError: PyQt4.QtCore.QDate(2011, 8, 21)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;so what is going on? The dictionary DOES have a key of QDate(2011,8,21)... but is unable to find it.&lt;br /&gt;&lt;br /&gt;In debugging, I was reminded that python dictionaries hash the key values and it turns out that there is a known bug in QDate.__hash__&lt;br /&gt;&lt;pre&gt;&gt;&gt;&gt; d1 = QDate(2009,12,9)&lt;br /&gt;&gt;&gt;&gt; d1.__hash__()&lt;br /&gt;4: 48759696&lt;br /&gt;&gt;&gt;&gt;&lt;br /&gt;&gt;&gt;&gt; d2 = QDate(2009,12,9)&lt;br /&gt;&gt;&gt;&gt; d2.__hash__()&lt;br /&gt;5: 45344152&lt;br /&gt;&gt;&gt;&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;this has been fixed in the very latest versions of PyQt4 I believe (including the python3 version)&lt;br /&gt;In the meantime, I am simply adding a step of conversion to python date types for the keys.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&gt;&gt;&gt; d1.toPyDate().__hash__()&lt;br /&gt;6: 5917697570912074722&lt;br /&gt;&gt;&gt;&gt; d2.toPyDate().__hash__()&lt;br /&gt;7: 5917697570912074722&lt;br /&gt;&gt;&gt;&gt; &lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8109854847430899154-8773393041851308554?l=rowinggolfer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rowinggolfer.blogspot.com/feeds/8773393041851308554/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8109854847430899154&amp;postID=8773393041851308554' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/8773393041851308554'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/8773393041851308554'/><link rel='alternate' type='text/html' href='http://rowinggolfer.blogspot.com/2010/12/qtcoreqdate-gotcha-for-python.html' title='QtCore.QDate gotcha for python dictionaries'/><author><name>Neil</name><uri>http://www.blogger.com/profile/06112117080373993301</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/-GEhvN_g7Kk4/TfnhG7DCMiI/AAAAAAAAAHo/HmAn1zC-xXM/s220/geek.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8109854847430899154.post-3827017553857125246</id><published>2010-11-18T18:01:00.000Z</published><updated>2010-11-18T18:12:42.834Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='postgres'/><title type='text'>a neat(?) postgresql solution using row_number() and  self joining</title><content type='html'>For the scheduling aspect of openmolar, a common task is to find where "freeslots" occur. In the original openmolar, I performed this logic using python code. For openmolar2 the database itself will perform this search.&lt;br /&gt;Here's how. &lt;br /&gt;&lt;br /&gt;let's make a trivial diary table&lt;br /&gt;&lt;pre&gt;create table diary (&lt;br /&gt; ix serial primary key, &lt;br /&gt; startTime time, &lt;br /&gt; endTime time, &lt;br /&gt; activity varchar(80));&lt;br /&gt;&lt;/pre&gt;leading to this table of data.&lt;br /&gt;select * from diary;&lt;br /&gt;&lt;table width="100%", border="1"&gt;&lt;tr&gt;&lt;td&gt;&lt;b&gt;ix&lt;/b&gt;&lt;/td&gt;&lt;td&gt;&lt;b&gt;starttime&lt;/b&gt;&lt;/td&gt;&lt;td&gt;&lt;b&gt;endtime&lt;/b&gt;&lt;/td&gt;&lt;td&gt;&lt;b&gt;activity&lt;/b&gt;&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;09:00:00&lt;/td&gt;&lt;td&gt;09:30:00&lt;/td&gt;&lt;td&gt;breakfast&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;09:30:00&lt;/td&gt;&lt;td&gt;10:00:00&lt;/td&gt;&lt;td&gt;jogging&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;3&lt;/td&gt;&lt;td&gt;13:00:00&lt;/td&gt;&lt;td&gt;14:00:00&lt;/td&gt;&lt;td&gt;lunch&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;4&lt;/td&gt;&lt;td&gt;10:00:00&lt;/td&gt;&lt;td&gt;11:30:00&lt;/td&gt;&lt;td&gt;meeting with joe&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;5&lt;/td&gt;&lt;td&gt;14:00:00&lt;/td&gt;&lt;td&gt;18:00:00&lt;/td&gt;&lt;td&gt;golfing at Royal Dornoch&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;br /&gt;so the problem is this... how can I query that table to discover my free time on that day?&lt;br /&gt;(there is 90 minutes before lunch)&lt;br /&gt;NOTE - the activities are NOT in order!&lt;br /&gt;&lt;br /&gt;the answer (and I found this in the excellent "sql cookbook") involves getting a view of that table in the correct order, and then performing a join on adjacent rows.&lt;br /&gt;&lt;br /&gt;so first, get the ordered view.&lt;br /&gt;=&gt; select * from diary order by starttime;&lt;br /&gt;&lt;table border = "1"&gt;&lt;tr&gt;&lt;td&gt; ix &lt;/td&gt;&lt;td&gt; starttime &lt;/td&gt;&lt;td&gt; endtime  &lt;/td&gt;&lt;td&gt;         activity&lt;/td&gt;&lt;tr&gt;&lt;tr&gt;&lt;td&gt;  1 &lt;/td&gt;&lt;td&gt; 09:00:00  &lt;/td&gt;&lt;td&gt; 09:30:00 &lt;/td&gt;&lt;td&gt; breakfast&lt;/td&gt;&lt;tr&gt;&lt;tr&gt;&lt;td&gt;  2 &lt;/td&gt;&lt;td&gt; 09:30:00  &lt;/td&gt;&lt;td&gt; 10:00:00 &lt;/td&gt;&lt;td&gt; jogging&lt;/td&gt;&lt;tr&gt;&lt;tr&gt;&lt;td&gt;  4 &lt;/td&gt;&lt;td&gt; 13:00:00  &lt;/td&gt;&lt;td&gt; 14:00:00 &lt;/td&gt;&lt;td&gt; lunch&lt;/td&gt;&lt;tr&gt;&lt;tr&gt;&lt;td&gt;  3 &lt;/td&gt;&lt;td&gt; 10:00:00  &lt;/td&gt;&lt;td&gt; 11:30:00 &lt;/td&gt;&lt;td&gt; meeting with joe&lt;/td&gt;&lt;tr&gt;&lt;tr&gt;&lt;td&gt;  5 &lt;/td&gt;&lt;td&gt; 14:00:00  &lt;/td&gt;&lt;td&gt; 18:00:00 &lt;/td&gt;&lt;td&gt; golfing at Royal Dornoch&lt;/td&gt;&lt;tr&gt; &lt;/table&gt;&lt;br /&gt;&lt;br /&gt;But this doesn't help... because there is no way to definatively refer to the "next" activity, to do this we need to replace ix with a generated rownumber. We will use the row_number() window function of postgres 8.4. &lt;br /&gt;&lt;br /&gt;=&gt; select * from (select row_number() over (order by starttime) as rownumber, &lt;br /&gt;starttime, endtime, activity from diary) as ordered_diary;&lt;br /&gt;&lt;br /&gt;&lt;table border = "1"&gt;&lt;tr&gt;&lt;td&gt;rownumber &lt;/td&gt;&lt;td&gt; starttime &lt;/td&gt;&lt;td&gt; endtime  &lt;/td&gt;&lt;td&gt;         activity&lt;/td&gt;&lt;tr&gt;&lt;tr&gt;&lt;td&gt;        1 &lt;/td&gt;&lt;td&gt; 09:00:00  &lt;/td&gt;&lt;td&gt; 09:30:00 &lt;/td&gt;&lt;td&gt; breakfast&lt;/td&gt;&lt;tr&gt;&lt;tr&gt;&lt;td&gt;        2 &lt;/td&gt;&lt;td&gt; 09:30:00  &lt;/td&gt;&lt;td&gt; 10:00:00 &lt;/td&gt;&lt;td&gt; jogging&lt;/td&gt;&lt;tr&gt;&lt;tr&gt;&lt;td&gt;        3 &lt;/td&gt;&lt;td&gt; 10:00:00  &lt;/td&gt;&lt;td&gt; 11:30:00 &lt;/td&gt;&lt;td&gt; meeting with joe&lt;/td&gt;&lt;tr&gt;&lt;tr&gt;&lt;td&gt;        4 &lt;/td&gt;&lt;td&gt; 13:00:00  &lt;/td&gt;&lt;td&gt; 14:00:00 &lt;/td&gt;&lt;td&gt; lunch&lt;/td&gt;&lt;tr&gt;&lt;tr&gt;&lt;td&gt;        5 &lt;/td&gt;&lt;td&gt; 14:00:00  &lt;/td&gt;&lt;td&gt; 18:00:00 &lt;/td&gt;&lt;td&gt; golfing at Royal Dornoch&lt;/td&gt;&lt;tr&gt; &lt;/table&gt;&lt;br /&gt;no we can self join that result set on itself.. &lt;br /&gt;(adding columns from the next row to the current row)&lt;br /&gt;&lt;br /&gt;=&gt; select * from&lt;br /&gt;(select row_number() over (order by starttime) as row_number, * from diary) as diary1,  &lt;br /&gt;(select row_number() over (order by starttime) as row_number, * from diary) as diary2 &lt;br /&gt;where diary2.row_number = diary1.row_number+1&lt;br /&gt;&lt;br /&gt;&lt;table border = "1"&gt;&lt;tr&gt;&lt;td&gt;row_number &lt;/td&gt;&lt;td&gt; ix &lt;/td&gt;&lt;td&gt; starttime &lt;/td&gt;&lt;td&gt; endtime  &lt;/td&gt;&lt;td&gt;     activity     &lt;/td&gt;&lt;td&gt; row_number &lt;/td&gt;&lt;td&gt; ix &lt;/td&gt;&lt;td&gt; starttime &lt;/td&gt;&lt;td&gt; endtime  &lt;/td&gt;&lt;td&gt;         activity&lt;/td&gt;&lt;tr&gt;&lt;tr&gt;&lt;td&gt;         1 &lt;/td&gt;&lt;td&gt;  1 &lt;/td&gt;&lt;td&gt; 09:00:00  &lt;/td&gt;&lt;td&gt; 09:30:00 &lt;/td&gt;&lt;td&gt; breakfast        &lt;/td&gt;&lt;td&gt;          2 &lt;/td&gt;&lt;td&gt;  2 &lt;/td&gt;&lt;td&gt; 09:30:00  &lt;/td&gt;&lt;td&gt; 10:00:00 &lt;/td&gt;&lt;td&gt; jogging&lt;/td&gt;&lt;tr&gt;&lt;tr&gt;&lt;td&gt;         2 &lt;/td&gt;&lt;td&gt;  2 &lt;/td&gt;&lt;td&gt; 09:30:00  &lt;/td&gt;&lt;td&gt; 10:00:00 &lt;/td&gt;&lt;td&gt; jogging          &lt;/td&gt;&lt;td&gt;          3 &lt;/td&gt;&lt;td&gt;  4 &lt;/td&gt;&lt;td&gt; 10:00:00  &lt;/td&gt;&lt;td&gt; 11:30:00 &lt;/td&gt;&lt;td&gt; meeting with joe&lt;/td&gt;&lt;tr&gt;&lt;tr&gt;&lt;td&gt;         3 &lt;/td&gt;&lt;td&gt;  4 &lt;/td&gt;&lt;td&gt; 10:00:00  &lt;/td&gt;&lt;td&gt; 11:30:00 &lt;/td&gt;&lt;td&gt; meeting with joe &lt;/td&gt;&lt;td&gt;          4 &lt;/td&gt;&lt;td&gt;  3 &lt;/td&gt;&lt;td&gt; 13:00:00  &lt;/td&gt;&lt;td&gt; 14:00:00 &lt;/td&gt;&lt;td&gt; lunch&lt;/td&gt;&lt;tr&gt;&lt;tr&gt;&lt;td&gt;         4 &lt;/td&gt;&lt;td&gt;  3 &lt;/td&gt;&lt;td&gt; 13:00:00  &lt;/td&gt;&lt;td&gt; 14:00:00 &lt;/td&gt;&lt;td&gt; lunch            &lt;/td&gt;&lt;td&gt;          5 &lt;/td&gt;&lt;td&gt;  5 &lt;/td&gt;&lt;td&gt; 14:00:00  &lt;/td&gt;&lt;td&gt; 18:00:00 &lt;/td&gt;&lt;td&gt; golfing at Royal Dornoch&lt;/td&gt;&lt;tr&gt; &lt;/table&gt;&lt;br /&gt;&lt;br /&gt;or more succinctly...&lt;br /&gt;=&gt; select diary1.activity as first_activity, diary1.endtime as finishes, &lt;br /&gt;diary2.activity as next_activity, diary2.starttime as starts from&lt;br /&gt;(select row_number() over (order by starttime) as row_number, * from diary) as diary1,  &lt;br /&gt;(select row_number() over (order by starttime) as row_number, * from diary) as diary2 &lt;br /&gt;where diary2.row_number = diary1.row_number+1&lt;br /&gt;&lt;br /&gt;&lt;table border = "1"&gt;&lt;tr&gt;&lt;td&gt; first_activity  &lt;/td&gt;&lt;td&gt; finishes &lt;/td&gt;&lt;td&gt;      next_activity       &lt;/td&gt;&lt;td&gt;  starts  &lt;/td&gt;&lt;tr&gt;&lt;tr&gt;&lt;td&gt;breakfast        &lt;/td&gt;&lt;td&gt; 09:30:00 &lt;/td&gt;&lt;td&gt; jogging                  &lt;/td&gt;&lt;td&gt; 09:30:00&lt;/td&gt;&lt;tr&gt;&lt;tr&gt;&lt;td&gt;jogging          &lt;/td&gt;&lt;td&gt; 10:00:00 &lt;/td&gt;&lt;td&gt; meeting with joe         &lt;/td&gt;&lt;td&gt; 10:00:00&lt;/td&gt;&lt;tr&gt;&lt;tr&gt;&lt;td&gt;meeting with joe &lt;/td&gt;&lt;td&gt; 11:30:00 &lt;/td&gt;&lt;td&gt; lunch                    &lt;/td&gt;&lt;td&gt; 13:00:00&lt;/td&gt;&lt;tr&gt;&lt;tr&gt;&lt;td&gt;lunch            &lt;/td&gt;&lt;td&gt; 14:00:00 &lt;/td&gt;&lt;td&gt; golfing at Royal Dornoch &lt;/td&gt;&lt;td&gt; 14:00:00&lt;/td&gt;&lt;tr&gt; &lt;/table&gt;&lt;br /&gt;so we simply now have to add a check to see if those times differ&lt;br /&gt;&lt;br /&gt;so here's the final query!&lt;br /&gt;&lt;br /&gt;=&gt; select diary1.endtime as freetime_start, diary2.starttime as freetime_end from&lt;br /&gt;(select row_number() over (order by starttime) as row_number, endtime from diary) as diary1,  &lt;br /&gt;(select row_number() over (order by starttime) as row_number, starttime from diary) as diary2 &lt;br /&gt;where diary2.row_number = diary1.row_number+1 &lt;br /&gt;and diary1.endtime &lt; diary2.starttime&lt;table border = "1"&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;freetime_start &lt;/td&gt;&lt;td&gt; freetime_end &lt;/td&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;11:30:00       &lt;/td&gt;&lt;td&gt; 13:00:00&lt;/td&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;/table&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8109854847430899154-3827017553857125246?l=rowinggolfer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rowinggolfer.blogspot.com/feeds/3827017553857125246/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8109854847430899154&amp;postID=3827017553857125246' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/3827017553857125246'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/3827017553857125246'/><link rel='alternate' type='text/html' href='http://rowinggolfer.blogspot.com/2010/11/neat-postgresql-solution-using.html' title='a neat(?) postgresql solution using row_number() and  self joining'/><author><name>Neil</name><uri>http://www.blogger.com/profile/06112117080373993301</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/-GEhvN_g7Kk4/TfnhG7DCMiI/AAAAAAAAAHo/HmAn1zC-xXM/s220/geek.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8109854847430899154.post-9089975068664482936</id><published>2010-11-12T22:14:00.000Z</published><updated>2010-11-12T22:14:55.841Z</updated><title type='text'>Firesheep in Action</title><content type='html'>further to &lt;a href="http://rowinggolfer.blogspot.com/2010/11/firesheep.html"&gt;Yesterday's post on installing firesheep on 64-bit ubuntu&lt;/a&gt; .... I had a play with the firesheep plugin.&lt;br /&gt;&lt;br /&gt;I disabled (temporarily) WPA on my home network, and started monitoring. I was able to hijack both my facebook and twitter sessions.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_wAfH8S6uz00/TN275m2T4qI/AAAAAAAAAGw/kihn0F3bSWw/s1600/firesheep_in_action.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="262" src="http://3.bp.blogspot.com/_wAfH8S6uz00/TN275m2T4qI/AAAAAAAAAGw/kihn0F3bSWw/s320/firesheep_in_action.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8109854847430899154-9089975068664482936?l=rowinggolfer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rowinggolfer.blogspot.com/feeds/9089975068664482936/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8109854847430899154&amp;postID=9089975068664482936' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/9089975068664482936'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/9089975068664482936'/><link rel='alternate' type='text/html' href='http://rowinggolfer.blogspot.com/2010/11/firesheep-in-action.html' title='Firesheep in Action'/><author><name>Neil</name><uri>http://www.blogger.com/profile/06112117080373993301</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/-GEhvN_g7Kk4/TfnhG7DCMiI/AAAAAAAAAHo/HmAn1zC-xXM/s220/geek.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_wAfH8S6uz00/TN275m2T4qI/AAAAAAAAAGw/kihn0F3bSWw/s72-c/firesheep_in_action.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8109854847430899154.post-5872033642872322868</id><published>2010-11-11T15:06:00.000Z</published><updated>2010-11-12T22:17:20.012Z</updated><title type='text'>Firesheep.</title><content type='html'>&lt;a href="https://github.com/codebutler/firesheep"&gt;Firesheep&lt;/a&gt; is a plugin for &lt;a href="http://www.blogger.com/www.mozilla.com/firefox/"&gt;Firefox&lt;/a&gt; that is creating a lot of noise in the IT security community. It allows you to hijack sessions of other users on open wifi. &lt;br /&gt;&lt;br /&gt;There is a windows/mac version of this plugin, but that is no use to me (and I will point out my intentions are NOT malicious, but to demonstrate to friends/colleagues the dangers of the interwebs).&lt;br /&gt;&lt;br /&gt;thanks to &lt;a href="https://github.com/codebutler/firesheep/issues#issue/70"&gt;information on this page&lt;/a&gt; I got it working on my 64-bit ubuntu 10.04(lucid) laptop.&lt;br /&gt;&lt;br /&gt;here's what I did to get it working.&lt;br /&gt;regards&lt;br /&gt;&lt;br /&gt;Neil.&lt;br /&gt;&lt;br /&gt;to install firesheep on lucid&lt;br /&gt;&lt;br /&gt;1. get dependencies (your mileage may vary)&lt;br /&gt;&lt;br /&gt;&lt;div style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;sudo apt-get install libhal-dev libtool autoconf xulrunner-dev libboost-dev libpcap-dev iw git&lt;/div&gt;&lt;br /&gt;2. get the latest firesheep code from github&lt;br /&gt;&lt;br /&gt;&lt;div style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;git clone git://github.com/mickflemm/firesheep.git&lt;/div&gt;&lt;br /&gt;3. compile the firesheep.xpi "plugin"&lt;br /&gt;&lt;br /&gt;&lt;div style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;cd firesheep&lt;/div&gt;&lt;div style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;./autogen.sh&lt;/div&gt;&lt;div style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;git submodule update --init&lt;/div&gt;&lt;div style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;make&lt;/div&gt;&lt;br /&gt;4. set up a monitor interface&lt;br /&gt;&lt;div style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;sudo iw wlan0 interface add mon0 type monitor&lt;/div&gt;&lt;div style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;sudo ifconfig mon0 up&lt;/div&gt;&lt;br /&gt;5. Install the plugin into firefox.&lt;br /&gt;Open Firefox, and from the menu choose "File", then open ~/firesheep/build/firesheep.xpi&lt;br /&gt;&lt;br /&gt;restart firefox when asked&lt;br /&gt;&lt;br /&gt;6. firesheep needs correct permissions to access your wifi card.&lt;br /&gt;&lt;br /&gt;&lt;div style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;cd ~/.mozilla/firefox/7oyiuecg.default/extension/firesheep@codebutler.com/platform/Linux_x86_64-gcc3/&lt;/div&gt;&lt;div style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;sudo ./firesheep-backend --fix-permissions&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;note- there WILL be subtle differences in this directory&lt;br /&gt;&lt;br /&gt;7. Ready to go!&lt;br /&gt;&lt;br /&gt;open firefox and click on &lt;br /&gt;add-ons-&amp;gt;firesheep-&amp;gt;preferences-&amp;gt;interface&lt;br /&gt;then choose mon0 from the drop down list. (see screenshot below)&lt;br /&gt;&lt;br /&gt;8. Enable the Firesheep Sidebar.&lt;br /&gt;&lt;br /&gt;view-&amp;gt;SideBar-&amp;gt;firesheep;&lt;br /&gt;(or ctrl-shift-s)&lt;br /&gt;&lt;br /&gt;DONE!&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/_wAfH8S6uz00/TNwGewti7LI/AAAAAAAAAGs/XDl7BH6IkAc/s1600/firesheep.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="248" src="http://2.bp.blogspot.com/_wAfH8S6uz00/TNwGewti7LI/AAAAAAAAAGs/XDl7BH6IkAc/s320/firesheep.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8109854847430899154-5872033642872322868?l=rowinggolfer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rowinggolfer.blogspot.com/feeds/5872033642872322868/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8109854847430899154&amp;postID=5872033642872322868' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/5872033642872322868'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/5872033642872322868'/><link rel='alternate' type='text/html' href='http://rowinggolfer.blogspot.com/2010/11/firesheep.html' title='Firesheep.'/><author><name>Neil</name><uri>http://www.blogger.com/profile/06112117080373993301</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/-GEhvN_g7Kk4/TfnhG7DCMiI/AAAAAAAAAHo/HmAn1zC-xXM/s220/geek.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_wAfH8S6uz00/TNwGewti7LI/AAAAAAAAAGs/XDl7BH6IkAc/s72-c/firesheep.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8109854847430899154.post-4174775050909083802</id><published>2010-09-28T22:22:00.000+01:00</published><updated>2010-09-28T22:24:36.360+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python classes'/><title type='text'>Object Orientation Example</title><content type='html'>I knocked this example up today for a friend on IRC. Thought I would post it here.&lt;br /&gt;&lt;pre&gt;#! /usr/bin/env python&lt;br /&gt;################################################################################&lt;br /&gt;##  Python Object Orientated example by rowinggolfer                          ##&lt;br /&gt;##  the same object... but extra functionality added in layers                ##&lt;br /&gt;##                                                                            ##&lt;br /&gt;##  A noteable "Gotcha" for newbs is the __init__ function.                   ##&lt;br /&gt;##  the base class in this example sets some important attributes in this     ##&lt;br /&gt;##  function. Therefore classes which inherit from it, but be careful if      ##&lt;br /&gt;##  re-implementing this function                                             ##&lt;br /&gt;##  NOTE - the teenager class does NOT overwrite this function... hence when  ##&lt;br /&gt;##  a teenager is initiated, python looks up the class hierarchy and executes ##&lt;br /&gt;##  the first __init__ method it finds.. in this case the Toddler's __init__  ##&lt;br /&gt;##                                                                            ##&lt;br /&gt;##                                                                            ##&lt;br /&gt;##  Run this script, and study the output.                                    ##&lt;br /&gt;##                                                                            ##&lt;br /&gt;##  Pay special attention to the attribute "description, and see how it is    ##&lt;br /&gt;##  altered mid method in the teenage years.                                  ##&lt;br /&gt;##                                                                            ##&lt;br /&gt;################################################################################&lt;br /&gt;&lt;br /&gt;from datetime import date&lt;br /&gt;from base64 import b64decode&lt;br /&gt;&lt;br /&gt;class TimritBaby(object):&lt;br /&gt;    '''&lt;br /&gt;    a baby has a date of birth, a name, and limited functionality&lt;br /&gt;    '''&lt;br /&gt;    def __init__(self, date_of_birth):&lt;br /&gt;        print "TimritBaby initiated"&lt;br /&gt;        self.name = 'Scott Murtz'&lt;br /&gt;        self.dob = date_of_birth&lt;br /&gt;        self.description = "(a baby)"&lt;br /&gt;&lt;br /&gt;    def poop(self):&lt;br /&gt;        print "    %s %s can Poop!"% (self.name, self.description)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;class TimritToddler(TimritBaby):&lt;br /&gt;    '''&lt;br /&gt;    a toddler has a new method&lt;br /&gt;    '''&lt;br /&gt;    def __init__(self, dob):&lt;br /&gt;        # call the init method of the base class..&lt;br /&gt;        # otherwise the name attribute won't work!!&lt;br /&gt;        print "\nTimritToddler initiated"&lt;br /&gt;        TimritBaby.__init__(self, dob)&lt;br /&gt;        self.description = "(a toddler)"&lt;br /&gt;    &lt;br /&gt;    def walk(self):&lt;br /&gt;        print "    %s %s can Walk!"% (self.name, self.description)&lt;br /&gt;&lt;br /&gt;class TimritTeenager(TimritToddler):&lt;br /&gt;    '''&lt;br /&gt;    a teenager with a secret habit&lt;br /&gt;    '''&lt;br /&gt;    def private_time(self):&lt;br /&gt;        self.description = "(now a teeneager)"&lt;br /&gt;        message = b64decode('aXMgbWFzdHVyYmF0aW5nIGFnYWlu')&lt;br /&gt;        print "    %s %s %s"% (self.name, self.description, message)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;if __name__ == "__main__":&lt;br /&gt;    baby = TimritBaby(date(1968,1,1))&lt;br /&gt;    baby.poop()&lt;br /&gt;    try:&lt;br /&gt;        baby.walk()&lt;br /&gt;    except AttributeError as e:&lt;br /&gt;        print "ERROR - WHOOPS!", e&lt;br /&gt;    &lt;br /&gt;    teenager = TimritTeenager(date(1968,1,1))&lt;br /&gt;    teenager.poop()&lt;br /&gt;    teenager.walk()&lt;br /&gt;    teenager.private_time()&lt;br /&gt;    teenager.walk()&lt;br /&gt; &lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8109854847430899154-4174775050909083802?l=rowinggolfer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rowinggolfer.blogspot.com/feeds/4174775050909083802/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8109854847430899154&amp;postID=4174775050909083802' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/4174775050909083802'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/4174775050909083802'/><link rel='alternate' type='text/html' href='http://rowinggolfer.blogspot.com/2010/09/object-orientation-example.html' title='Object Orientation Example'/><author><name>Neil</name><uri>http://www.blogger.com/profile/06112117080373993301</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/-GEhvN_g7Kk4/TfnhG7DCMiI/AAAAAAAAAHo/HmAn1zC-xXM/s220/geek.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8109854847430899154.post-2778380189118966629</id><published>2010-09-12T20:36:00.000+01:00</published><updated>2010-09-12T20:37:27.436+01:00</updated><title type='text'>fuzzymatching in postgres on ubuntu</title><content type='html'>I had a battle getting the soundex function installed into my database on postgres.&lt;br /&gt;but here's how I succeeded.&lt;br /&gt;&lt;br /&gt;One - Install the postgres-contrib package&lt;br /&gt;&lt;pre&gt;sudo apt-get install  postgresql-contrib&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Two - change user to postgres (a database superuser created on install of postgresql&lt;br /&gt;&lt;pre&gt;neil@slim-maroon:~$ sudo su - postgres&lt;br /&gt;postgres@slim-maroon:~$ &lt;/pre&gt;&lt;br /&gt;Three - pipe the supplied script into the database (my database is called "openmolar_demo")&lt;br /&gt;&lt;pre&gt;postgres@slim-maroon:~$ psql -d openmolar_demo -f /usr/share/postgresql/8.4/contrib/fuzzystrmatch.sql&lt;br /&gt;SET&lt;br /&gt;CREATE FUNCTION&lt;br /&gt;CREATE FUNCTION&lt;br /&gt;CREATE FUNCTION&lt;br /&gt;CREATE FUNCTION&lt;br /&gt;CREATE FUNCTION&lt;br /&gt;CREATE FUNCTION&lt;br /&gt;CREATE FUNCTION&lt;br /&gt;CREATE FUNCTION&lt;br /&gt;postgres@slim-maroon:~$&lt;/pre&gt;&lt;br /&gt;Four - test it!&lt;br /&gt;&lt;pre&gt;openmolar_demo=&gt; SELECT soundex('Neil');&lt;br /&gt; soundex &lt;br /&gt;---------&lt;br /&gt; N400&lt;br /&gt;(1 row)&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8109854847430899154-2778380189118966629?l=rowinggolfer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rowinggolfer.blogspot.com/feeds/2778380189118966629/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8109854847430899154&amp;postID=2778380189118966629' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/2778380189118966629'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/2778380189118966629'/><link rel='alternate' type='text/html' href='http://rowinggolfer.blogspot.com/2010/09/fuzzymatching-in-postgres-on-ubuntu.html' title='fuzzymatching in postgres on ubuntu'/><author><name>Neil</name><uri>http://www.blogger.com/profile/06112117080373993301</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/-GEhvN_g7Kk4/TfnhG7DCMiI/AAAAAAAAAHo/HmAn1zC-xXM/s220/geek.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8109854847430899154.post-7386292827301035132</id><published>2010-09-07T14:28:00.000+01:00</published><updated>2010-09-07T14:32:24.213+01:00</updated><title type='text'>Postgres for openmolar2</title><content type='html'>&lt;a href="http://3.bp.blogspot.com/_wAfH8S6uz00/TIY-M8xHYDI/AAAAAAAAAGk/Pn2TI-z3NUg/s1600/postgresql.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="155" src="http://3.bp.blogspot.com/_wAfH8S6uz00/TIY-M8xHYDI/AAAAAAAAAGk/Pn2TI-z3NUg/s200/postgresql.png" width="200" /&gt;&lt;/a&gt;I've been playing with postgres all morning, and&amp;nbsp;have decided that the next version of openmolar will use it in preference to MySQL.&lt;br /&gt;&lt;div&gt;&lt;br /&gt;Main Reasons.&lt;br /&gt;&lt;ol&gt;&lt;ol&gt;&lt;li style="text-align: left;"&gt;it's a clean break with the past&lt;/li&gt;&lt;li style="text-align: left;"&gt;GNUmed use postgres&lt;/li&gt;&lt;li style="text-align: left;"&gt;active development&lt;/li&gt;&lt;li style="text-align: left;"&gt;standards compliance&lt;/li&gt;&lt;li style="text-align: left;"&gt;not owned by oracle&lt;/li&gt;&lt;/ol&gt;&lt;/ol&gt;A huge thankyou to all postgres devs for a wonderful open-source back-end.&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8109854847430899154-7386292827301035132?l=rowinggolfer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rowinggolfer.blogspot.com/feeds/7386292827301035132/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8109854847430899154&amp;postID=7386292827301035132' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/7386292827301035132'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/7386292827301035132'/><link rel='alternate' type='text/html' href='http://rowinggolfer.blogspot.com/2010/09/postgres-for-openmolar2.html' title='Postgres for openmolar2'/><author><name>Neil</name><uri>http://www.blogger.com/profile/06112117080373993301</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/-GEhvN_g7Kk4/TfnhG7DCMiI/AAAAAAAAAHo/HmAn1zC-xXM/s220/geek.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_wAfH8S6uz00/TIY-M8xHYDI/AAAAAAAAAGk/Pn2TI-z3NUg/s72-c/postgresql.png' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8109854847430899154.post-5353801391264722585</id><published>2010-09-02T13:21:00.000+01:00</published><updated>2010-09-02T13:43:37.547+01:00</updated><title type='text'>Pynotify style notifications</title><content type='html'>The notifcation system for openmolar2 is nearly complete.&lt;br /&gt;&lt;br /&gt;Why not use pynotify? Cross-platform is a goal here.&lt;br /&gt;&lt;br /&gt;&lt;video controls="controls" preload="metadata" src="http://tinyvid.tv/file/1x6otttme5xfu.ogg"&gt;&lt;/video&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8109854847430899154-5353801391264722585?l=rowinggolfer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rowinggolfer.blogspot.com/feeds/5353801391264722585/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8109854847430899154&amp;postID=5353801391264722585' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/5353801391264722585'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/5353801391264722585'/><link rel='alternate' type='text/html' href='http://rowinggolfer.blogspot.com/2010/09/pynotify-style-notifications.html' title='Pynotify style notifications'/><author><name>Neil</name><uri>http://www.blogger.com/profile/06112117080373993301</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/-GEhvN_g7Kk4/TfnhG7DCMiI/AAAAAAAAAHo/HmAn1zC-xXM/s220/geek.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8109854847430899154.post-4394123201674928930</id><published>2010-08-04T18:24:00.000+01:00</published><updated>2010-08-04T18:24:53.036+01:00</updated><title type='text'>tllts co-incidence makes me feel awful.</title><content type='html'>so today, I am playing golf and listening to last week's &lt;a href="http://tllts.org/"&gt;tllts&lt;/a&gt;.&lt;br /&gt;for the 1st time in my life, I get half way through the show (well, maybe 30 minutes in)... and i think "not enjoying this!" and delete it!&lt;br /&gt;&lt;br /&gt;imagine what a douche i feel then, when I get home.... to find an air mail package containing a tllts T-shirt and hackey sack.&lt;br /&gt;&lt;br /&gt;it's as if the cock just crowed 3 times, and i realise my denial.&lt;br /&gt;&lt;br /&gt;Allan, Pat, Linc and Dann, please forgive me, it won't happen again.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8109854847430899154-4394123201674928930?l=rowinggolfer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rowinggolfer.blogspot.com/feeds/4394123201674928930/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8109854847430899154&amp;postID=4394123201674928930' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/4394123201674928930'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/4394123201674928930'/><link rel='alternate' type='text/html' href='http://rowinggolfer.blogspot.com/2010/08/tllts-co-incidence-makes-me-feel-awful.html' title='tllts co-incidence makes me feel awful.'/><author><name>Neil</name><uri>http://www.blogger.com/profile/06112117080373993301</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/-GEhvN_g7Kk4/TfnhG7DCMiI/AAAAAAAAAHo/HmAn1zC-xXM/s220/geek.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8109854847430899154.post-5579688908548814021</id><published>2010-08-04T09:13:00.000+01:00</published><updated>2010-08-04T09:13:23.377+01:00</updated><title type='text'>openmolar2</title><content type='html'>last night I began work on a new version of openmolar.&lt;br /&gt;&lt;br /&gt;this one will not be done in a hurry (ie. in 4 months because of a proprietary license termination), nor will I be bound to a schema which I dare not change. I have come a long way on my programming journey, and feel ready to take the plunge into what I hope will be the most customisable, pluggable, and downright froody piece of dental management software known to mankind.&lt;br /&gt;&lt;br /&gt;openmolar up to this point, is software for my practice alone.&lt;br /&gt;openmolar2 will be of use to other practices (I hope).&lt;br /&gt;&lt;br /&gt;more later.&lt;br /&gt;&lt;br /&gt;Neil.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8109854847430899154-5579688908548814021?l=rowinggolfer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rowinggolfer.blogspot.com/feeds/5579688908548814021/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8109854847430899154&amp;postID=5579688908548814021' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/5579688908548814021'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/5579688908548814021'/><link rel='alternate' type='text/html' href='http://rowinggolfer.blogspot.com/2010/08/openmolar2.html' title='openmolar2'/><author><name>Neil</name><uri>http://www.blogger.com/profile/06112117080373993301</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/-GEhvN_g7Kk4/TfnhG7DCMiI/AAAAAAAAAHo/HmAn1zC-xXM/s220/geek.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8109854847430899154.post-7287828053237163753</id><published>2010-08-03T12:57:00.000+01:00</published><updated>2010-08-03T13:18:12.034+01:00</updated><title type='text'>QTextEdit with autocompletion using pyqt</title><content type='html'>Problem - I wanted a text-edit which would help enter long words.&lt;br /&gt;&lt;br /&gt;Solution - I have converted the &lt;a href="http://doc.trolltech.com/4.3/tools-customcompleter.html"&gt;C++ example code&lt;/a&gt; into python, and post it here to for all to see.&lt;br /&gt;&lt;br /&gt;NB - The code assumes your dictionary is located at /usr/share/dict/words.&lt;br /&gt;&lt;div align="center"&gt;&lt;video width = "416" height="214" src='http://tinyvid.tv/file/29nnd9e2zjymw.ogg' preload='metadata' controls='controls'&gt;&lt;/video&gt;&lt;br /&gt;&lt;/div&gt;&lt;pre&gt;from PyQt4 import QtGui, QtCore&lt;br /&gt;&lt;br /&gt;STARTTEXT = ('This TextEdit provides autocompletions for words that have ' +&lt;br /&gt;'more than 3 characters.\nYou can trigger autocompletion using %s\n\n'''% (&lt;br /&gt;QtGui.QKeySequence("Ctrl+E").toString(QtGui.QKeySequence.NativeText)))&lt;br /&gt;&lt;br /&gt;class DictionaryCompleter(QtGui.QCompleter):&lt;br /&gt;    def __init__(self, parent=None):&lt;br /&gt;        words = []&lt;br /&gt;        try:&lt;br /&gt;            f = open("/usr/share/dict/words","r")&lt;br /&gt;            for word in f:&lt;br /&gt;                words.append(word.strip())&lt;br /&gt;            f.close()&lt;br /&gt;        except IOError:&lt;br /&gt;            print "dictionary not in anticipated location"&lt;br /&gt;        QtGui.QCompleter.__init__(self, words, parent)&lt;br /&gt;&lt;br /&gt;class CompletionTextEdit(QtGui.QTextEdit):&lt;br /&gt;    def __init__(self, parent=None):&lt;br /&gt;        super(CompletionTextEdit, self).__init__(parent)&lt;br /&gt;        self.setMinimumWidth(400)&lt;br /&gt;        self.setPlainText(STARTTEXT)&lt;br /&gt;        self.completer = None&lt;br /&gt;        self.moveCursor(QtGui.QTextCursor.End)&lt;br /&gt;&lt;br /&gt;    def setCompleter(self, completer):&lt;br /&gt;        if self.completer:&lt;br /&gt;            self.disconnect(self.completer, 0, self, 0)&lt;br /&gt;        if not completer:&lt;br /&gt;            return&lt;br /&gt;&lt;br /&gt;        completer.setWidget(self)&lt;br /&gt;        completer.setCompletionMode(QtGui.QCompleter.PopupCompletion)&lt;br /&gt;        completer.setCaseSensitivity(QtCore.Qt.CaseInsensitive)&lt;br /&gt;        self.completer = completer&lt;br /&gt;        self.connect(self.completer,&lt;br /&gt;            QtCore.SIGNAL("activated(const QString&amp;amp;)"), self.insertCompletion)&lt;br /&gt;&lt;br /&gt;    def insertCompletion(self, completion):&lt;br /&gt;        tc = self.textCursor()&lt;br /&gt;        extra = (completion.length() -&lt;br /&gt;            self.completer.completionPrefix().length())&lt;br /&gt;        tc.movePosition(QtGui.QTextCursor.Left)&lt;br /&gt;        tc.movePosition(QtGui.QTextCursor.EndOfWord)&lt;br /&gt;        tc.insertText(completion.right(extra))&lt;br /&gt;        self.setTextCursor(tc)&lt;br /&gt;&lt;br /&gt;    def textUnderCursor(self):&lt;br /&gt;        tc = self.textCursor()&lt;br /&gt;        tc.select(QtGui.QTextCursor.WordUnderCursor)&lt;br /&gt;        return tc.selectedText()&lt;br /&gt;&lt;br /&gt;    def focusInEvent(self, event):&lt;br /&gt;        if self.completer:&lt;br /&gt;            self.completer.setWidget(self);&lt;br /&gt;        QtGui.QTextEdit.focusInEvent(self, event)&lt;br /&gt;&lt;br /&gt;    def keyPressEvent(self, event):&lt;br /&gt;        if self.completer and self.completer.popup().isVisible():&lt;br /&gt;            if event.key() in (&lt;br /&gt;            QtCore.Qt.Key_Enter,&lt;br /&gt;            QtCore.Qt.Key_Return,&lt;br /&gt;            QtCore.Qt.Key_Escape,&lt;br /&gt;            QtCore.Qt.Key_Tab,&lt;br /&gt;            QtCore.Qt.Key_Backtab):&lt;br /&gt;                event.ignore()&lt;br /&gt;                return&lt;br /&gt;&lt;br /&gt;        ## has ctrl-E been pressed??&lt;br /&gt;        isShortcut = (event.modifiers() == QtCore.Qt.ControlModifier and&lt;br /&gt;                      event.key() == QtCore.Qt.Key_E)&lt;br /&gt;        if (not self.completer or not isShortcut):&lt;br /&gt;            QtGui.QTextEdit.keyPressEvent(self, event)&lt;br /&gt;&lt;br /&gt;        ## ctrl or shift key on it's own??&lt;br /&gt;        ctrlOrShift = event.modifiers() in (QtCore.Qt.ControlModifier ,&lt;br /&gt;                QtCore.Qt.ShiftModifier)&lt;br /&gt;        if ctrlOrShift and event.text().isEmpty():&lt;br /&gt;            # ctrl or shift key on it's own&lt;br /&gt;            return&lt;br /&gt;&lt;br /&gt;        eow = QtCore.QString("~!@#$%^&amp;amp;*()_+{}|:\"&amp;lt;&amp;gt;?,./;'[]\\-=") #end of word&lt;br /&gt;&lt;br /&gt;        hasModifier = ((event.modifiers() != QtCore.Qt.NoModifier) and&lt;br /&gt;                        not ctrlOrShift)&lt;br /&gt;&lt;br /&gt;        completionPrefix = self.textUnderCursor()&lt;br /&gt;&lt;br /&gt;        if (not isShortcut and (hasModifier or event.text().isEmpty() or&lt;br /&gt;        completionPrefix.length() &amp;lt; 3 or&lt;br /&gt;        eow.contains(event.text().right(1)))):&lt;br /&gt;            self.completer.popup().hide()&lt;br /&gt;            return&lt;br /&gt;&lt;br /&gt;        if (completionPrefix != self.completer.completionPrefix()):&lt;br /&gt;            self.completer.setCompletionPrefix(completionPrefix)&lt;br /&gt;            popup = self.completer.popup()&lt;br /&gt;            popup.setCurrentIndex(&lt;br /&gt;                self.completer.completionModel().index(0,0))&lt;br /&gt;&lt;br /&gt;        cr = self.cursorRect()&lt;br /&gt;        cr.setWidth(self.completer.popup().sizeHintForColumn(0)&lt;br /&gt;            + self.completer.popup().verticalScrollBar().sizeHint().width())&lt;br /&gt;        self.completer.complete(cr) ## popup it up!&lt;br /&gt;&lt;br /&gt;if __name__ == "__main__":&lt;br /&gt;&lt;br /&gt;    app = QtGui.QApplication([])&lt;br /&gt;    completer = DictionaryCompleter()&lt;br /&gt;    te = CompletionTextEdit()&lt;br /&gt;    te.setCompleter(completer)&lt;br /&gt;    te.show()&lt;br /&gt;    app.exec_()&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8109854847430899154-7287828053237163753?l=rowinggolfer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rowinggolfer.blogspot.com/feeds/7287828053237163753/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8109854847430899154&amp;postID=7287828053237163753' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/7287828053237163753'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/7287828053237163753'/><link rel='alternate' type='text/html' href='http://rowinggolfer.blogspot.com/2010/08/qtextedit-with-autocompletion-using.html' title='QTextEdit with autocompletion using pyqt'/><author><name>Neil</name><uri>http://www.blogger.com/profile/06112117080373993301</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/-GEhvN_g7Kk4/TfnhG7DCMiI/AAAAAAAAAHo/HmAn1zC-xXM/s220/geek.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8109854847430899154.post-1054521915153590734</id><published>2010-06-30T01:27:00.000+01:00</published><updated>2010-06-30T01:39:50.464+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='QSessionManager'/><category scheme='http://www.blogger.com/atom/ns#' term='PyQt'/><title type='text'>Session Managers and PyQt Applications</title><content type='html'>X11 window managers commonly have an option to "remember" applications which are running when a session ends.&lt;br /&gt;&lt;br /&gt;Here's the gnome-checkbox (System -&gt; Preferences -&gt; Startup Applications)&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_wAfH8S6uz00/TCqM_8OINiI/AAAAAAAAAGM/Vj8mCdiFMCA/s1600/gnome_memory.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://4.bp.blogspot.com/_wAfH8S6uz00/TCqM_8OINiI/AAAAAAAAAGM/Vj8mCdiFMCA/s320/gnome_memory.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;but for this to work, the applications themselves need to comply. Qt does this with the QSessionManager class.&lt;br /&gt;&lt;br /&gt;The class is not used directly, but is passed as an argument into functions of qApp, namely the saveState and commitData functions.&lt;br /&gt;qApp therefore needs to be subclassed, and these two functions overwritten.&lt;br /&gt;&lt;br /&gt;here's a working example. Note the simplicity of the functions!&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;#! /usr/bin/env python&lt;br /&gt;&lt;br /&gt;from PyQt4 import QtGui, QtCore&lt;br /&gt;import sys&lt;br /&gt;&lt;br /&gt;class RestorableApplication(QtGui.QApplication):&lt;br /&gt;    def __init__(self):&lt;br /&gt;        super(RestorableApplication, self).__init__(sys.argv)&lt;br /&gt;&lt;br /&gt;    def commitData(self, session):&lt;br /&gt;        '''re-implement this method, called on quit'''&lt;br /&gt;        pass&lt;br /&gt;&lt;br /&gt;    def saveState(self, session):&lt;br /&gt;        '''re-implement this method, called on run'''&lt;br /&gt;        pass&lt;br /&gt;&lt;br /&gt;app = RestorableApplication()&lt;br /&gt;&lt;br /&gt;mw = QtGui.QMainWindow()&lt;br /&gt;mw.setMinimumSize(300,300)&lt;br /&gt;mw.setWindowTitle("I live on after a logout!")&lt;br /&gt;&lt;br /&gt;label = QtGui.QLabel(&lt;br /&gt;'''Leave me running and log off&lt;br /&gt;I will survive! (on X11 systems)&lt;br /&gt;Window size and position will be restored&lt;br /&gt;... cool eh?''', mw)&lt;br /&gt;&lt;br /&gt;label.setAlignment(QtCore.Qt.AlignCenter)&lt;br /&gt;&lt;br /&gt;mw.setCentralWidget(label)&lt;br /&gt;mw.show()&lt;br /&gt;&lt;br /&gt;app.exec_()&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8109854847430899154-1054521915153590734?l=rowinggolfer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rowinggolfer.blogspot.com/feeds/1054521915153590734/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8109854847430899154&amp;postID=1054521915153590734' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/1054521915153590734'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/1054521915153590734'/><link rel='alternate' type='text/html' href='http://rowinggolfer.blogspot.com/2010/06/session-managers-and-pyqt-applications.html' title='Session Managers and PyQt Applications'/><author><name>Neil</name><uri>http://www.blogger.com/profile/06112117080373993301</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/-GEhvN_g7Kk4/TfnhG7DCMiI/AAAAAAAAAHo/HmAn1zC-xXM/s220/geek.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_wAfH8S6uz00/TCqM_8OINiI/AAAAAAAAAGM/Vj8mCdiFMCA/s72-c/gnome_memory.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8109854847430899154.post-6891022567903275968</id><published>2010-06-22T12:58:00.000+01:00</published><updated>2010-06-22T13:13:42.009+01:00</updated><title type='text'>qt-o-fax</title><content type='html'>Making the pluggable pyqt app has been more fun than I thought, and I believe the application may actually turn out to be half decent contacts manager.&lt;br /&gt;&lt;br /&gt;it accepts plugins now (a zipped folder, with a config file within) and I am still finialising the plugin API, but I am certain I am on the right lines. The "zipimport" module did all that I hoped for and more.&lt;br /&gt;&lt;br /&gt;It's running great on linux and windows. Plugins can simply be dropped into the applications plugins folder which reside here.&lt;pre&gt;linux = ~/.qt-o-fax/plugins&lt;br /&gt;windows = C:\Documents and Settings\USER\.qt-o-fax\&lt;br /&gt;&lt;/pre&gt;Config file is simple format, heavily influenced by the gedit method of plugin config&lt;br /&gt;&lt;pre&gt;[qt-o-fax Plugin]&lt;br /&gt;# module is where the entry point of the plugin is&lt;br /&gt;# it should contain a class Plugin, with a method run()&lt;br /&gt;# for this example, it is main.py&lt;br /&gt;# THIS IS THE ONLY FIELD WHICH IS ABSOLUTELY REQUIRED&lt;br /&gt;Module=main&lt;br /&gt;&lt;br /&gt;restartneeded=False&lt;br /&gt;&lt;br /&gt;Name=Hello World&lt;br /&gt;Name[fr]=bonjour toulemande&lt;br /&gt;Description=The simplest possible plugin&lt;br /&gt;Description[fr]=Un plugin moins sofisticate&lt;br /&gt;&lt;br /&gt;Version=0.1&lt;br /&gt;Authors=Neil Wallace &lt;rowinggolfer@googlemail.com&gt;&lt;br /&gt;Copyright=Copyright © 2010 Neil Wallace&lt;br /&gt;Licence=LGPLv3&lt;br /&gt;Website=https://launchpad.net/qt-o-fax/&lt;br /&gt;&lt;br /&gt;LongDescription=&lt;h4&gt;Hello World Plugin&lt;/h4&gt;This plugin simply displays a hello world message when activated.&lt;br /&gt;It connects to no signals, nor alters the database.&lt;/pre&gt;&lt;br /&gt;So what plugins could be created?? I think the sky is the limit. Add custom fields to the database, send SMS messages, create word processor documents with addresses embedded, christmas card lists.... contact sharing..&lt;br /&gt;&lt;br /&gt;I've stuck it up on launchpad &lt;a href="https://launchpad.net/qt-o-fax"&gt;https://launchpad.net/qt-o-fax&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Screenshots&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_wAfH8S6uz00/TCCj-da9oxI/AAAAAAAAAFc/AtZF3Aaa1Fc/s1600/Screenshot-Qt-O-Fax.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/_wAfH8S6uz00/TCCj-da9oxI/AAAAAAAAAFc/AtZF3Aaa1Fc/s320/Screenshot-Qt-O-Fax.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;a href="http://1.bp.blogspot.com/_wAfH8S6uz00/TCCkNhkM1kI/AAAAAAAAAF0/k0d3j3sQiB8/s1600/Screenshot-Qt-O-Fax-1.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="320" src="http://1.bp.blogspot.com/_wAfH8S6uz00/TCCkNhkM1kI/AAAAAAAAAF0/k0d3j3sQiB8/s320/Screenshot-Qt-O-Fax-1.png" width="320" /&gt;&lt;/a&gt;&lt;a href="http://2.bp.blogspot.com/_wAfH8S6uz00/TCCkFARXojI/AAAAAAAAAFk/q4QfmL2BdQQ/s1600/Screenshot-About+Hello+World.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="115" src="http://2.bp.blogspot.com/_wAfH8S6uz00/TCCkFARXojI/AAAAAAAAAFk/q4QfmL2BdQQ/s200/Screenshot-About+Hello+World.png" width="200" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/_wAfH8S6uz00/TCCl3vlluVI/AAAAAAAAAGE/R36_-ermikc/s1600/windows-qt-o-fax.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/_wAfH8S6uz00/TCCl3vlluVI/AAAAAAAAAGE/R36_-ermikc/s320/windows-qt-o-fax.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8109854847430899154-6891022567903275968?l=rowinggolfer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rowinggolfer.blogspot.com/feeds/6891022567903275968/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8109854847430899154&amp;postID=6891022567903275968' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/6891022567903275968'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/6891022567903275968'/><link rel='alternate' type='text/html' href='http://rowinggolfer.blogspot.com/2010/06/qt-o-fax.html' title='qt-o-fax'/><author><name>Neil</name><uri>http://www.blogger.com/profile/06112117080373993301</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/-GEhvN_g7Kk4/TfnhG7DCMiI/AAAAAAAAAHo/HmAn1zC-xXM/s220/geek.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_wAfH8S6uz00/TCCj-da9oxI/AAAAAAAAAFc/AtZF3Aaa1Fc/s72-c/Screenshot-Qt-O-Fax.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8109854847430899154.post-135390526764913923</id><published>2010-06-16T08:56:00.000+01:00</published><updated>2010-06-16T09:49:11.230+01:00</updated><title type='text'>Making a pyqt4 application which accepts "plugins".</title><content type='html'>So I decided that openmolar needed to be broken up into bits. I did this last week, Client, Server and language packs are now seperate packages, meaning that I can update one part of it independently of the other bits. All well and good.&lt;br /&gt;&lt;br /&gt;However, I REALLY want&amp;nbsp;"plugins" (similar to firefox functionality) to provide some of the functionality that folks are going to want (partly because it will make it possible for them to code such things themselves)&lt;br /&gt;&lt;br /&gt;So, as ever, 1st stage is to make a trivial app, and see if I can get some form of plugin system going. &lt;br /&gt;&lt;br /&gt;Here's a video of that application (In making it, I learned a lot about QToolbar class... something I haven't used much before).&lt;br /&gt;&lt;a href="http://tinyvid.tv/show/2q6yruijgemsd"&gt;http://tinyvid.tv/show/2q6yruijgemsd&lt;/a&gt;&lt;br /&gt;(if you have an HTML5 compatible browser, that should appear by magic below.. simply hit play)&lt;br /&gt;&lt;br /&gt;If you want to see the code for this little application, I stuck it on launchpad - get it this way.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;~$ bzr branch lp:~rowinggolfer/+junk/pluggable-pyqt-app&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;the vid was taken with the files at revision 1.&lt;br /&gt;&lt;br /&gt;Now for the difficult bit.. designing and loading the plugins.&lt;br /&gt;&lt;br /&gt;My idea is that plugins should be zipped folders. Signed by the author ideally, and containing a config file which describes it, gives version numbers, and installation instructions which the parent app can use.&lt;br /&gt;&lt;br /&gt;Python can import modules from zipped folders easily thanks to the &lt;a href="http://docs.python.org/library/zipimport.html"&gt;zipimport&lt;/a&gt; module.&lt;br /&gt;&lt;br /&gt;I think I am on the right lines for this... I'll let you know (via this blog) how I get on&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;video controls="controls" preload="metadata" src="http://tinyvid.tv/file/2q6yruijgemsd.ogg" width="800"&gt;&lt;/video&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8109854847430899154-135390526764913923?l=rowinggolfer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rowinggolfer.blogspot.com/feeds/135390526764913923/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8109854847430899154&amp;postID=135390526764913923' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/135390526764913923'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/135390526764913923'/><link rel='alternate' type='text/html' href='http://rowinggolfer.blogspot.com/2010/06/making-pyqt4-application-which-accepts.html' title='Making a pyqt4 application which accepts &quot;plugins&quot;.'/><author><name>Neil</name><uri>http://www.blogger.com/profile/06112117080373993301</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/-GEhvN_g7Kk4/TfnhG7DCMiI/AAAAAAAAAHo/HmAn1zC-xXM/s220/geek.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8109854847430899154.post-6144026810628313717</id><published>2010-05-07T11:54:00.000+01:00</published><updated>2010-05-07T12:47:03.376+01:00</updated><title type='text'>cloud required??</title><content type='html'>I have 2 issues to solve today.&lt;br /&gt;1. backup of x-ray images (currently that is approx 3GB of data per year)&lt;br /&gt;2. being able to share these images with colleagues when appropriate&lt;br /&gt;now... forgive me if I am wrong.. but is the solution not "dropbox" or similar??&lt;br /&gt;&lt;br /&gt;big opportunity for a lucrative market.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;follow-up---&lt;br /&gt;&lt;a href="http://www.ironmountain.co.uk/solutions/industry/healthcare/imaging.asp"&gt;http://www.ironmountain.co.uk/solutions/industry/healthcare/imaging.asp&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8109854847430899154-6144026810628313717?l=rowinggolfer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rowinggolfer.blogspot.com/feeds/6144026810628313717/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8109854847430899154&amp;postID=6144026810628313717' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/6144026810628313717'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/6144026810628313717'/><link rel='alternate' type='text/html' href='http://rowinggolfer.blogspot.com/2010/05/cloud-required.html' title='cloud required??'/><author><name>Neil</name><uri>http://www.blogger.com/profile/06112117080373993301</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/-GEhvN_g7Kk4/TfnhG7DCMiI/AAAAAAAAAHo/HmAn1zC-xXM/s220/geek.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8109854847430899154.post-4943840640136837688</id><published>2010-05-05T10:57:00.000+01:00</published><updated>2010-05-05T10:57:51.354+01:00</updated><title type='text'>QTreeView and QAbractItemModel example</title><content type='html'>This little example sets up a pythonic model, attaches a treeview to it, and allows user interaction in 2 ways.&lt;br /&gt;&lt;br /&gt;1. clicking on the treeview&lt;br /&gt;2. making selections using buttons.&lt;br /&gt;&lt;br /&gt;Why is this important? Well, "models" are not aware of what is selected by the various views attached to them. With multiple views of the same data (or related data) it is up to the coder to keep this reference. the button click stuff is used in this example to explore such a scenario.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_wAfH8S6uz00/S-FAyjbX4HI/AAAAAAAAAFU/pyv5La2HBVQ/s1600/person_selector.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/_wAfH8S6uz00/S-FAyjbX4HI/AAAAAAAAAFU/pyv5La2HBVQ/s320/person_selector.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;pre&gt;from PyQt4 import QtGui, QtCore&lt;br /&gt;&lt;br /&gt;HORIZONTAL_HEADERS = ("Surname", "Given Name")&lt;br /&gt;    &lt;br /&gt;class person_class(object):&lt;br /&gt;    '''&lt;br /&gt;    a trivial custom data object&lt;br /&gt;    '''&lt;br /&gt;    def __init__(self, sname, fname, isMale):&lt;br /&gt;        self.sname = sname&lt;br /&gt;        self.fname = fname&lt;br /&gt;        self.isMale = isMale&lt;br /&gt;&lt;br /&gt;    def __repr__(self):&lt;br /&gt;        return "PERSON - %s %s"% (self.fname, self.sname)&lt;br /&gt;    &lt;br /&gt;class TreeItem(object):&lt;br /&gt;    '''&lt;br /&gt;    a python object used to return row/column data, and keep note of&lt;br /&gt;    it's parents and/or children&lt;br /&gt;    '''&lt;br /&gt;    def __init__(self, person, header, parentItem):&lt;br /&gt;        self.person = person&lt;br /&gt;        self.parentItem = parentItem&lt;br /&gt;        self.header = header&lt;br /&gt;        self.childItems = []&lt;br /&gt;&lt;br /&gt;    def appendChild(self, item):&lt;br /&gt;        self.childItems.append(item)&lt;br /&gt;&lt;br /&gt;    def child(self, row):&lt;br /&gt;        return self.childItems[row]&lt;br /&gt;&lt;br /&gt;    def childCount(self):&lt;br /&gt;        return len(self.childItems)&lt;br /&gt;&lt;br /&gt;    def columnCount(self):&lt;br /&gt;        return 2&lt;br /&gt;    &lt;br /&gt;    def data(self, column):&lt;br /&gt;        if self.person == None:&lt;br /&gt;            if column == 0:&lt;br /&gt;                return QtCore.QVariant(self.header)&lt;br /&gt;            if column == 1:&lt;br /&gt;                return QtCore.QVariant("")                &lt;br /&gt;        else:&lt;br /&gt;            if column == 0:&lt;br /&gt;                return QtCore.QVariant(self.person.sname)&lt;br /&gt;            if column == 1:&lt;br /&gt;                return QtCore.QVariant(self.person.fname)&lt;br /&gt;        return QtCore.QVariant()&lt;br /&gt;&lt;br /&gt;    def parent(self):&lt;br /&gt;        return self.parentItem&lt;br /&gt;    &lt;br /&gt;    def row(self):&lt;br /&gt;        if self.parentItem:&lt;br /&gt;            return self.parentItem.childItems.index(self)&lt;br /&gt;        return 0&lt;br /&gt;&lt;br /&gt;class treeModel(QtCore.QAbstractItemModel):&lt;br /&gt;    '''&lt;br /&gt;    a model to display a few names, ordered by sex&lt;br /&gt;    '''&lt;br /&gt;    def __init__(self, parent=None):&lt;br /&gt;        super(treeModel, self).__init__(parent)&lt;br /&gt;        self.people = []&lt;br /&gt;        for fname, sname, isMale in (("John","Brown", 1), &lt;br /&gt;        ("Fred", "Bloggs", 1), ("Sue", "Smith", 0)):&lt;br /&gt;            person = person_class(sname, fname, isMale)&lt;br /&gt;            self.people.append(person)&lt;br /&gt;            &lt;br /&gt;        self.rootItem = TreeItem(None, "ALL", None)&lt;br /&gt;        self.parents = {0 : self.rootItem}&lt;br /&gt;        self.setupModelData()&lt;br /&gt;&lt;br /&gt;    def columnCount(self, parent=None):&lt;br /&gt;        if parent and parent.isValid():&lt;br /&gt;            return parent.internalPointer().columnCount()&lt;br /&gt;        else:&lt;br /&gt;            return len(HORIZONTAL_HEADERS)&lt;br /&gt;&lt;br /&gt;    def data(self, index, role):&lt;br /&gt;        if not index.isValid():&lt;br /&gt;            return QtCore.QVariant()&lt;br /&gt;&lt;br /&gt;        item = index.internalPointer()&lt;br /&gt;        if role == QtCore.Qt.DisplayRole:&lt;br /&gt;            return item.data(index.column())&lt;br /&gt;        if role == QtCore.Qt.UserRole:&lt;br /&gt;            if item:&lt;br /&gt;                return item.person&lt;br /&gt;&lt;br /&gt;        return QtCore.QVariant()&lt;br /&gt;&lt;br /&gt;    def headerData(self, column, orientation, role):&lt;br /&gt;        if (orientation == QtCore.Qt.Horizontal and&lt;br /&gt;        role == QtCore.Qt.DisplayRole):&lt;br /&gt;            try:&lt;br /&gt;                return QtCore.QVariant(HORIZONTAL_HEADERS[column])&lt;br /&gt;            except IndexError:&lt;br /&gt;                pass&lt;br /&gt;&lt;br /&gt;        return QtCore.QVariant()&lt;br /&gt;&lt;br /&gt;    def index(self, row, column, parent):&lt;br /&gt;        if not self.hasIndex(row, column, parent):&lt;br /&gt;            return QtCore.QModelIndex()&lt;br /&gt;&lt;br /&gt;        if not parent.isValid():&lt;br /&gt;            parentItem = self.rootItem&lt;br /&gt;        else:&lt;br /&gt;            parentItem = parent.internalPointer()&lt;br /&gt;&lt;br /&gt;        childItem = parentItem.child(row)&lt;br /&gt;        if childItem:&lt;br /&gt;            return self.createIndex(row, column, childItem)&lt;br /&gt;        else:&lt;br /&gt;            return QtCore.QModelIndex()&lt;br /&gt;&lt;br /&gt;    def parent(self, index):&lt;br /&gt;        if not index.isValid():&lt;br /&gt;            return QtCore.QModelIndex()&lt;br /&gt;&lt;br /&gt;        childItem = index.internalPointer()&lt;br /&gt;        if not childItem:&lt;br /&gt;            return QtCore.QModelIndex()&lt;br /&gt;        &lt;br /&gt;        parentItem = childItem.parent()&lt;br /&gt;&lt;br /&gt;        if parentItem == self.rootItem:&lt;br /&gt;            return QtCore.QModelIndex()&lt;br /&gt;&lt;br /&gt;        return self.createIndex(parentItem.row(), 0, parentItem)&lt;br /&gt;&lt;br /&gt;    def rowCount(self, parent=QtCore.QModelIndex()):&lt;br /&gt;        if parent.column() &gt; 0:&lt;br /&gt;            return 0&lt;br /&gt;        if not parent.isValid():&lt;br /&gt;            p_Item = self.rootItem&lt;br /&gt;        else:&lt;br /&gt;            p_Item = parent.internalPointer()&lt;br /&gt;        return p_Item.childCount()&lt;br /&gt;    &lt;br /&gt;    def setupModelData(self):&lt;br /&gt;        for person in self.people:&lt;br /&gt;            if person.isMale:&lt;br /&gt;                sex = "MALES"&lt;br /&gt;            else:&lt;br /&gt;                sex = "FEMALES"&lt;br /&gt;            &lt;br /&gt;            if not self.parents.has_key(sex):                &lt;br /&gt;                newparent = TreeItem(None, sex, self.rootItem)&lt;br /&gt;                self.rootItem.appendChild(newparent)&lt;br /&gt;&lt;br /&gt;                self.parents[sex] = newparent&lt;br /&gt;&lt;br /&gt;            parentItem = self.parents[sex]&lt;br /&gt;            newItem = TreeItem(person, "", parentItem)&lt;br /&gt;            parentItem.appendChild(newItem)&lt;br /&gt;        &lt;br /&gt;    def searchModel(self, person):&lt;br /&gt;        '''&lt;br /&gt;        get the modelIndex for a given appointment&lt;br /&gt;        '''&lt;br /&gt;        def searchNode(node):&lt;br /&gt;            '''&lt;br /&gt;            a function called recursively, looking at all nodes beneath node&lt;br /&gt;            '''&lt;br /&gt;            for child in node.childItems:&lt;br /&gt;                if person == child.person:&lt;br /&gt;                    index = self.createIndex(child.row(), 0, child)&lt;br /&gt;                    return index&lt;br /&gt;                    &lt;br /&gt;                if child.childCount() &gt; 0:&lt;br /&gt;                    result = searchNode(child)&lt;br /&gt;                    if result:&lt;br /&gt;                        return result&lt;br /&gt;        &lt;br /&gt;        retarg = searchNode(self.parents[0])&lt;br /&gt;        print retarg&lt;br /&gt;        return retarg&lt;br /&gt;            &lt;br /&gt;    def find_GivenName(self, fname):&lt;br /&gt;        app = None&lt;br /&gt;        for person in self.people:&lt;br /&gt;            if person.fname == fname:&lt;br /&gt;                app = person&lt;br /&gt;                break&lt;br /&gt;        if app != None:&lt;br /&gt;            index = self.searchModel(app)&lt;br /&gt;            return (True, index)            &lt;br /&gt;        return (False, None)&lt;br /&gt;&lt;br /&gt;if __name__ == "__main__":    &lt;br /&gt;&lt;br /&gt;    def row_clicked(index):&lt;br /&gt;        '''&lt;br /&gt;        when a row is clicked... show the name&lt;br /&gt;        '''&lt;br /&gt;        print tv.model().data(index, QtCore.Qt.UserRole)&lt;br /&gt;        &lt;br /&gt;    def but_clicked():&lt;br /&gt;        '''&lt;br /&gt;        when a name button is clicked, I iterate over the model, &lt;br /&gt;        find the person with this name, and set the treeviews current item&lt;br /&gt;        '''&lt;br /&gt;        name = dialog.sender().text()&lt;br /&gt;        print "BUTTON CLICKED:", name&lt;br /&gt;        result, index = model.find_GivenName(name)&lt;br /&gt;        if result:&lt;br /&gt;            if index:&lt;br /&gt;                tv.setCurrentIndex(index)&lt;br /&gt;                return&lt;br /&gt;        tv.clearSelection()&lt;br /&gt;        &lt;br /&gt;    app = QtGui.QApplication([])&lt;br /&gt;    &lt;br /&gt;    model = treeModel()&lt;br /&gt;    dialog = QtGui.QDialog()&lt;br /&gt;&lt;br /&gt;    dialog.setMinimumSize(300,150)&lt;br /&gt;    layout = QtGui.QVBoxLayout(dialog)&lt;br /&gt;&lt;br /&gt;    tv = QtGui.QTreeView(dialog)&lt;br /&gt;    tv.setModel(model)&lt;br /&gt;    tv.setAlternatingRowColors(True)&lt;br /&gt;    layout.addWidget(tv)&lt;br /&gt;    &lt;br /&gt;    label = QtGui.QLabel("Search for the following person")&lt;br /&gt;    layout.addWidget(label)&lt;br /&gt;    &lt;br /&gt;    buts = []&lt;br /&gt;    frame = QtGui.QFrame(dialog)&lt;br /&gt;    layout2 = QtGui.QHBoxLayout(frame)&lt;br /&gt;    &lt;br /&gt;    for person in model.people:&lt;br /&gt;        but = QtGui.QPushButton(person.fname, frame)&lt;br /&gt;        buts.append(but)&lt;br /&gt;        layout2.addWidget(but)&lt;br /&gt;        QtCore.QObject.connect(but, QtCore.SIGNAL("clicked()"), but_clicked)&lt;br /&gt;        &lt;br /&gt;    layout.addWidget(frame)&lt;br /&gt;&lt;br /&gt;    but = QtGui.QPushButton("Clear Selection")&lt;br /&gt;    layout.addWidget(but)&lt;br /&gt;    QtCore.QObject.connect(but, QtCore.SIGNAL("clicked()"), tv.clearSelection)&lt;br /&gt;&lt;br /&gt;    QtCore.QObject.connect(tv, QtCore.SIGNAL("clicked (QModelIndex)"),&lt;br /&gt;        row_clicked)&lt;br /&gt;&lt;br /&gt;    dialog.exec_()&lt;br /&gt;&lt;br /&gt;    app.closeAllWindows()&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8109854847430899154-4943840640136837688?l=rowinggolfer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rowinggolfer.blogspot.com/feeds/4943840640136837688/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8109854847430899154&amp;postID=4943840640136837688' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/4943840640136837688'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/4943840640136837688'/><link rel='alternate' type='text/html' href='http://rowinggolfer.blogspot.com/2010/05/qtreeview-and-qabractitemmodel-example.html' title='QTreeView and QAbractItemModel example'/><author><name>Neil</name><uri>http://www.blogger.com/profile/06112117080373993301</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/-GEhvN_g7Kk4/TfnhG7DCMiI/AAAAAAAAAHo/HmAn1zC-xXM/s220/geek.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_wAfH8S6uz00/S-FAyjbX4HI/AAAAAAAAAFU/pyv5La2HBVQ/s72-c/person_selector.png' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8109854847430899154.post-4363303063858952243</id><published>2010-04-17T10:44:00.000+01:00</published><updated>2010-04-17T10:44:41.298+01:00</updated><title type='text'>openmolar - preparing for roll out</title><content type='html'>i am thinking of breaking openmolar into bits&lt;br /&gt;&lt;br /&gt;ie. separate packages namely openmolar-server, openmolar-client and openmolar-help multiple reasons for this.&lt;br /&gt;A slimmer version of the existing package will become the client, and this will be the cross platform bit (ie. I will make a windows executable)&lt;br /&gt;&lt;br /&gt;openmolar-server will be the package which sets up and configures the mysql server and allows for practice customisation. This will only run on unix-like OSs.&lt;br /&gt;&lt;br /&gt;openmolar-help will simply put a set of html docs and videos into a pre-destined location.&lt;br /&gt;&lt;br /&gt;&amp;nbsp;if anyone has any thoughts, please let me know.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8109854847430899154-4363303063858952243?l=rowinggolfer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rowinggolfer.blogspot.com/feeds/4363303063858952243/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8109854847430899154&amp;postID=4363303063858952243' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/4363303063858952243'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/4363303063858952243'/><link rel='alternate' type='text/html' href='http://rowinggolfer.blogspot.com/2010/04/openmolar-preparing-for-roll-out.html' title='openmolar - preparing for roll out'/><author><name>Neil</name><uri>http://www.blogger.com/profile/06112117080373993301</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/-GEhvN_g7Kk4/TfnhG7DCMiI/AAAAAAAAAHo/HmAn1zC-xXM/s220/geek.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8109854847430899154.post-3778314695844554810</id><published>2010-04-12T18:09:00.000+01:00</published><updated>2011-06-15T17:10:21.354+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='pyqt4'/><title type='text'>PyQt4 model/view drag &amp; drop example</title><content type='html'>In PyQt4, drag and drop with QListWidget works really, really well. &lt;br /&gt;&lt;br /&gt;However, for real life application, I believe it's best to leave the convenience widgets (like QListWidget) behind, and head for the model/view pyqt4 classes. This gives a lot more flexibility than the "one-size fits all" model which comes with QListwidget et al.&lt;br /&gt;&lt;br /&gt;This enables easy referencing of the true python objects that underlie the model, using Qt.UserRole to refer to the object, and pickle (or cPickle) to convert to a bytestream which the drag/drop can handle. &lt;br /&gt;&lt;br /&gt;here is a little example using a few tricks to get drag and drop of native python objects in PyQt4.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/_wAfH8S6uz00/S8NTy1qRLfI/AAAAAAAAAFM/BW71QK_gUZs/s1600/Screenshot-Drag+Drop+Test.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="208" src="http://2.bp.blogspot.com/_wAfH8S6uz00/S8NTy1qRLfI/AAAAAAAAAFM/BW71QK_gUZs/s400/Screenshot-Drag+Drop+Test.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;import datetime&lt;br /&gt;import cPickle&lt;br /&gt;import pickle&lt;br /&gt;import sys&lt;br /&gt;&lt;br /&gt;from PyQt4 import QtGui, QtCore&lt;br /&gt;&lt;br /&gt;class person(object):&lt;br /&gt;    '''&lt;br /&gt;    a custom data structure, for example purposes&lt;br /&gt;    '''&lt;br /&gt;    def __init__(self, name, dob, house_no):&lt;br /&gt;        self.name = name&lt;br /&gt;        self.dob = dob&lt;br /&gt;        self.addr = "%d Rue de la Soleil"% house_no&lt;br /&gt;    def __repr__(self):&lt;br /&gt;        return "%s\n%s\n%s"% (self.name, self.dob, self.addr)&lt;br /&gt;&lt;br /&gt;class simple_model(QtCore.QAbstractListModel):&lt;br /&gt;    def __init__(self, parent=None):&lt;br /&gt;        super(simple_model, self).__init__(parent)&lt;br /&gt;        self.list = []&lt;br /&gt;        for name, dob, house_no in (&lt;br /&gt;        ("Neil", datetime.date(1969,12,9), 23),&lt;br /&gt;        ("John", datetime.date(1952,5,3), 2543),&lt;br /&gt;        ("Ilona", datetime.date(1975,4,6), 1)):&lt;br /&gt;            self.list.append(person(name, dob, house_no))&lt;br /&gt;        self.setSupportedDragActions(QtCore.Qt.MoveAction)&lt;br /&gt;&lt;br /&gt;    def rowCount(self, parent=QtCore.QModelIndex()):&lt;br /&gt;        return len(self.list)&lt;br /&gt;&lt;br /&gt;    def data(self, index, role):&lt;br /&gt;        if role == QtCore.Qt.DisplayRole: #show just the name&lt;br /&gt;            person = self.list[index.row()]&lt;br /&gt;            return QtCore.QVariant(person.name)&lt;br /&gt;        elif role == QtCore.Qt.UserRole:  #return the whole python object&lt;br /&gt;            person = self.list[index.row()]&lt;br /&gt;            return person&lt;br /&gt;        return QtCore.QVariant()&lt;br /&gt;&lt;br /&gt;    def removeRow(self, position):&lt;br /&gt;        self.list = self.list[:position] + self.list[position+1:]&lt;br /&gt;        self.reset()&lt;br /&gt;&lt;br /&gt;class dropZone(QtGui.QLabel):&lt;br /&gt;    def __init__(self, parent=None):&lt;br /&gt;        super(dropZone, self).__init__(parent)&lt;br /&gt;        self.setMinimumSize(200,200)&lt;br /&gt;        self.set_bg()&lt;br /&gt;        self.setText("Drop Here")&lt;br /&gt;        self.setAlignment(QtCore.Qt.AlignCenter)&lt;br /&gt;        self.setAcceptDrops(True)&lt;br /&gt;&lt;br /&gt;    def dragEnterEvent(self, event):&lt;br /&gt;        if event.mimeData().hasFormat("application/x-person"):&lt;br /&gt;            self.set_bg(True)&lt;br /&gt;            event.accept()&lt;br /&gt;        else:&lt;br /&gt;            event.ignore()&lt;br /&gt;&lt;br /&gt;    def dragMoveEvent(self, event):&lt;br /&gt;        if event.mimeData().hasFormat("application/x-person"):&lt;br /&gt;            event.setDropAction(QtCore.Qt.MoveAction)&lt;br /&gt;            event.accept()&lt;br /&gt;        else:&lt;br /&gt;            event.ignore()&lt;br /&gt;&lt;br /&gt;    def dragLeaveEvent(self, event):&lt;br /&gt;        self.set_bg()&lt;br /&gt;&lt;br /&gt;    def dropEvent(self, event):&lt;br /&gt;        data = event.mimeData()&lt;br /&gt;        bstream = data.retrieveData("application/x-person",&lt;br /&gt;            QtCore.QVariant.ByteArray)&lt;br /&gt;        selected = pickle.loads(bstream.toByteArray())&lt;br /&gt;        self.setText(str(selected))&lt;br /&gt;        self.set_bg()&lt;br /&gt;        event.accept()&lt;br /&gt;&lt;br /&gt;    def set_bg(self, active=False):&lt;br /&gt;        if active:&lt;br /&gt;            val = "background:yellow;"&lt;br /&gt;        else:&lt;br /&gt;            val = "background:green;"&lt;br /&gt;        self.setStyleSheet(val)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;class draggableList(QtGui.QListView):&lt;br /&gt;    '''&lt;br /&gt;    a listView whose items can be moved&lt;br /&gt;    '''&lt;br /&gt;    def ___init__(self, parent=None):&lt;br /&gt;        super(draggableList, self).__init__(parent)&lt;br /&gt;        self.setDragEnabled(True)&lt;br /&gt;&lt;br /&gt;    def dragEnterEvent(self, event):&lt;br /&gt;        if event.mimeData().hasFormat("application/x-person"):&lt;br /&gt;            event.setDropAction(QtCore.Qt.QMoveAction)&lt;br /&gt;            event.accept()&lt;br /&gt;        else:&lt;br /&gt;            event.ignore()&lt;br /&gt;&lt;br /&gt;    def startDrag(self, event):&lt;br /&gt;        index = self.indexAt(event.pos())&lt;br /&gt;        if not index.isValid():&lt;br /&gt;            return&lt;br /&gt;&lt;br /&gt;        ## selected is the relevant person object&lt;br /&gt;        selected = self.model().data(index,QtCore.Qt.UserRole)&lt;br /&gt;&lt;br /&gt;        ## convert to  a bytestream&lt;br /&gt;        bstream = cPickle.dumps(selected)&lt;br /&gt;        mimeData = QtCore.QMimeData()&lt;br /&gt;        mimeData.setData("application/x-person", bstream)&lt;br /&gt;&lt;br /&gt;        drag = QtGui.QDrag(self)&lt;br /&gt;        drag.setMimeData(mimeData)&lt;br /&gt;&lt;br /&gt;        # example 1 - the object itself&lt;br /&gt;&lt;br /&gt;        pixmap = QtGui.QPixmap()&lt;br /&gt;        pixmap = pixmap.grabWidget(self, self.rectForIndex(index))&lt;br /&gt;&lt;br /&gt;        # example 2 -  a plain pixmap&lt;br /&gt;        #pixmap = QtGui.QPixmap(100, self.height()/2)&lt;br /&gt;        #pixmap.fill(QtGui.QColor("orange"))&lt;br /&gt;        drag.setPixmap(pixmap)&lt;br /&gt;&lt;br /&gt;        drag.setHotSpot(QtCore.QPoint(pixmap.width()/2, pixmap.height()/2))&lt;br /&gt;        drag.setPixmap(pixmap)&lt;br /&gt;        result = drag.start(QtCore.Qt.MoveAction)&lt;br /&gt;        if result: # == QtCore.Qt.MoveAction:&lt;br /&gt;            self.model().removeRow(index.row())&lt;br /&gt;&lt;br /&gt;    def mouseMoveEvent(self, event):&lt;br /&gt;        self.startDrag(event)&lt;br /&gt;&lt;br /&gt;class testDialog(QtGui.QDialog):&lt;br /&gt;    def __init__(self, parent=None):&lt;br /&gt;        super(testDialog, self).__init__(parent)&lt;br /&gt;        self.setWindowTitle("Drag Drop Test")&lt;br /&gt;        layout = QtGui.QGridLayout(self)&lt;br /&gt;&lt;br /&gt;        label = QtGui.QLabel("Drag Name From This List")&lt;br /&gt;&lt;br /&gt;        self.model = simple_model()&lt;br /&gt;        self.listView = draggableList()&lt;br /&gt;        self.listView.setModel(self.model)&lt;br /&gt;        self.dz = dropZone()&lt;br /&gt;&lt;br /&gt;        layout.addWidget(label,0,0)&lt;br /&gt;        layout.addWidget(self.listView,1,0)&lt;br /&gt;        layout.addWidget(self.dz,0,1,2,2)&lt;br /&gt;&lt;br /&gt;if __name__ == "__main__":&lt;br /&gt;    '''&lt;br /&gt;    the try catch here is to ensure that the app exits cleanly no matter what&lt;br /&gt;    makes life better for SPE&lt;br /&gt;    '''&lt;br /&gt;    try:&lt;br /&gt;        app = QtGui.QApplication([])&lt;br /&gt;        dl = testDialog()&lt;br /&gt;        dl.exec_()&lt;br /&gt;    except Exception, e:  #could use as e for python 2.6...&lt;br /&gt;        print e&lt;br /&gt;    sys.exit(app.closeAllWindows())&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8109854847430899154-3778314695844554810?l=rowinggolfer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rowinggolfer.blogspot.com/feeds/3778314695844554810/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8109854847430899154&amp;postID=3778314695844554810' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/3778314695844554810'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/3778314695844554810'/><link rel='alternate' type='text/html' href='http://rowinggolfer.blogspot.com/2010/04/pyqt4-modelview-drag-drop-example.html' title='PyQt4 model/view drag &amp; drop example'/><author><name>Neil</name><uri>http://www.blogger.com/profile/06112117080373993301</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/-GEhvN_g7Kk4/TfnhG7DCMiI/AAAAAAAAAHo/HmAn1zC-xXM/s220/geek.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_wAfH8S6uz00/S8NTy1qRLfI/AAAAAAAAAFM/BW71QK_gUZs/s72-c/Screenshot-Drag+Drop+Test.png' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8109854847430899154.post-2587939224156808014</id><published>2010-03-25T01:05:00.000Z</published><updated>2010-03-25T01:05:56.070Z</updated><title type='text'>putting video onto lg ks360 mobile phone</title><content type='html'>Tonight the problem I had to solve was putting video onto my daughter's mobile phone,&amp;nbsp;which is an inexpensive lg ks360.&lt;br /&gt;First I grabbed the latest, uncrippled ffmpeg, following this howto&amp;nbsp;&lt;a href="http://ubuntuforums.org/showthread.php?t=786095"&gt;http://ubuntuforums.org/showthread.php?t=786095&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;now after some experimenting I settled on the following params to convert to a format the phone supported.&lt;br /&gt;&lt;pre&gt;ffmpeg -i input_file -acodec libfaac -ar 22000 -ab 32k -ac 2 -vtag mp4v -r 15 -s 320x240 output_file.mp4&lt;br /&gt;&lt;/pre&gt;then I drop the output_file.mp4 onto the phone's miniSD card, in the folder "Videos", and I'm done.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8109854847430899154-2587939224156808014?l=rowinggolfer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rowinggolfer.blogspot.com/feeds/2587939224156808014/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8109854847430899154&amp;postID=2587939224156808014' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/2587939224156808014'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/2587939224156808014'/><link rel='alternate' type='text/html' href='http://rowinggolfer.blogspot.com/2010/03/putting-video-onto-lg-ks360-mobile.html' title='putting video onto lg ks360 mobile phone'/><author><name>Neil</name><uri>http://www.blogger.com/profile/06112117080373993301</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/-GEhvN_g7Kk4/TfnhG7DCMiI/AAAAAAAAAHo/HmAn1zC-xXM/s220/geek.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8109854847430899154.post-4095203218702165300</id><published>2010-03-01T09:52:00.000Z</published><updated>2010-03-01T09:52:07.795Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>The DreamPie Python Shell</title><content type='html'>Just trying out the &lt;a href="http://dreampie.sourceforge.net/"&gt;DreamPie Python Shell&lt;/a&gt;.&lt;br /&gt;Lovin' it so far, this solves a lot of problems I have with other interative shells.&lt;br /&gt;I grabbed it from &lt;a href="https://launchpad.net/~dreampie-devel/+archive/ppa"&gt;The dreampie PPA&lt;/a&gt;&lt;br /&gt;Highly recommended.&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/_wAfH8S6uz00/S4uOLS4r3XI/AAAAAAAAAFE/hkkkAl0UHNM/s1600-h/Screenshot-DreamPie.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/_wAfH8S6uz00/S4uOLS4r3XI/AAAAAAAAAFE/hkkkAl0UHNM/s320/Screenshot-DreamPie.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8109854847430899154-4095203218702165300?l=rowinggolfer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rowinggolfer.blogspot.com/feeds/4095203218702165300/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8109854847430899154&amp;postID=4095203218702165300' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/4095203218702165300'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/4095203218702165300'/><link rel='alternate' type='text/html' href='http://rowinggolfer.blogspot.com/2010/03/dreampie-python-shell.html' title='The DreamPie Python Shell'/><author><name>Neil</name><uri>http://www.blogger.com/profile/06112117080373993301</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/-GEhvN_g7Kk4/TfnhG7DCMiI/AAAAAAAAAHo/HmAn1zC-xXM/s220/geek.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_wAfH8S6uz00/S4uOLS4r3XI/AAAAAAAAAFE/hkkkAl0UHNM/s72-c/Screenshot-DreamPie.png' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8109854847430899154.post-5075394667940834938</id><published>2010-02-25T14:08:00.000Z</published><updated>2010-02-25T14:10:42.706Z</updated><title type='text'>Graphical database application with 67 lines of python</title><content type='html'>&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_wAfH8S6uz00/S4aEYCaEc4I/AAAAAAAAAE8/8n1D4IVpytk/s1600-h/sqlite_table.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/_wAfH8S6uz00/S4aEYCaEc4I/AAAAAAAAAE8/8n1D4IVpytk/s320/sqlite_table.png" /&gt;&lt;/a&gt;&lt;/div&gt;Following some discussion in the #pyqt chatroom on freenode.net, I decided to play with the QtSql module of pyqt.&lt;br /&gt;&lt;br /&gt;Here's the results, the table allows direct editing of the db.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;note - you may need to install some dependencies&lt;br /&gt;sudo apt-get install python-qt4&amp;nbsp;python-qt4-sql&amp;nbsp;libqt4-sql-sqlite&lt;br /&gt;&lt;pre&gt;#! /usr/bin/env python&lt;br /&gt;'''&lt;br /&gt;###########################################################&lt;br /&gt;##   A Demo Application showing the use of sqlite3     ##&lt;br /&gt;##   and the QSqlTableModel    Class                    ##&lt;br /&gt;##   written by rowinggolfer 24th Feb 2010              ##&lt;br /&gt;##   version 0.1 and NOT YET WORKING!!                  ##&lt;br /&gt;##   this work is in the public domain,                 ##&lt;br /&gt;##   do with it as you please                           ##&lt;br /&gt;###########################################################&lt;br /&gt;'''&lt;br /&gt;import os, sys&lt;br /&gt;from PyQt4 import QtCore, QtGui, QtSql&lt;br /&gt;&lt;br /&gt;def makeDB():&lt;br /&gt;    import sqlite3&lt;br /&gt;    db = sqlite3.connect("test.db")&lt;br /&gt;    db.execute("create table if not exists table1 (value text, data text)")&lt;br /&gt;    &lt;br /&gt;    query = "insert into table1 (value, data) values (?, ?)"&lt;br /&gt;    &lt;br /&gt;    valueSet = (("day","today"),("time","noon"),("food","cheese"))&lt;br /&gt;    for values in valueSet:&lt;br /&gt;        db.execute(query, values)&lt;br /&gt;    db.commit()&lt;br /&gt;&lt;br /&gt;class TestApp(QtGui.QDialog):&lt;br /&gt;    def __init__(self, model, parent = None):&lt;br /&gt;        super(TestApp, self).__init__(parent)&lt;br /&gt;        self.model = model&lt;br /&gt;        &lt;br /&gt;        table = QtGui.QTableView()&lt;br /&gt;        table.setModel(self.model)&lt;br /&gt;&lt;br /&gt;        button = QtGui.QPushButton("Add a row")&lt;br /&gt;        layout = QtGui.QVBoxLayout(self)&lt;br /&gt;        layout.addWidget(table)&lt;br /&gt;        layout.addWidget(button)&lt;br /&gt;&lt;br /&gt;        self.connect(button, QtCore.SIGNAL("clicked()"), self.addRow)&lt;br /&gt;&lt;br /&gt;    def addRow(self):&lt;br /&gt;        self.model.insertRows(self.model.rowCount(), 1)&lt;br /&gt;&lt;br /&gt;class myModel(QtSql.QSqlTableModel):&lt;br /&gt;    def __init__(self, parent = None):&lt;br /&gt;        super(myModel, self).__init__(parent)&lt;br /&gt;        self.setEditStrategy(QtSql.QSqlTableModel.OnFieldChange)&lt;br /&gt;&lt;br /&gt;        self.setTable("table1")&lt;br /&gt;        self.select()&lt;br /&gt;        &lt;br /&gt;if __name__ == "__main__":&lt;br /&gt;    if not os.path.exists("test.db"):&lt;br /&gt;        makeDB()&lt;br /&gt;    &lt;br /&gt;    myDb = QtSql.QSqlDatabase.addDatabase("QSQLITE")&lt;br /&gt;    myDb.setDatabaseName("test.db")&lt;br /&gt;    if not myDb.open():&lt;br /&gt;        print "Unable to create connection!"&lt;br /&gt;        print "have you installed the sqlite driver?"&lt;br /&gt;        print "sudo apt-get install libqt4-sql-sqlite"&lt;br /&gt;        sys.exit(1)&lt;br /&gt;    model = myModel()&lt;br /&gt;    &lt;br /&gt;    app = QtGui.QApplication(sys.argv)&lt;br /&gt;    dl = TestApp(model)&lt;br /&gt;    dl.exec_()&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8109854847430899154-5075394667940834938?l=rowinggolfer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rowinggolfer.blogspot.com/feeds/5075394667940834938/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8109854847430899154&amp;postID=5075394667940834938' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/5075394667940834938'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/5075394667940834938'/><link rel='alternate' type='text/html' href='http://rowinggolfer.blogspot.com/2010/02/graphical-database-application-with-67.html' title='Graphical database application with 67 lines of python'/><author><name>Neil</name><uri>http://www.blogger.com/profile/06112117080373993301</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/-GEhvN_g7Kk4/TfnhG7DCMiI/AAAAAAAAAHo/HmAn1zC-xXM/s220/geek.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_wAfH8S6uz00/S4aEYCaEc4I/AAAAAAAAAE8/8n1D4IVpytk/s72-c/sqlite_table.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8109854847430899154.post-9169736812460414124</id><published>2010-02-24T09:04:00.000Z</published><updated>2010-02-24T10:16:12.872Z</updated><title type='text'>Ubuntu Update manager - feature request</title><content type='html'>Ubuntu handles updates really well, no question. The user is prompted to update, but without annoying pop ups that disrupt a workflow (cf M$ windows reboot in 5 minutes - ARGHH!)&lt;br /&gt;However, there's one thing I would like to see altered.&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/_wAfH8S6uz00/S4TqlAI3ouI/AAAAAAAAAE0/CTfRB75Bm1k/s1600-h/updateManager.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/_wAfH8S6uz00/S4TqlAI3ouI/AAAAAAAAAE0/CTfRB75Bm1k/s320/updateManager.png" /&gt;&lt;/a&gt;&lt;/div&gt;Once one has clicked "install", the top level dialog box prevents access to all the wonderful information about the updates being installed. Granted, one should check before accepting these.. but....&lt;br /&gt;I would prefer if I could still read details about what is being installed... as it happens.&lt;br /&gt;&lt;br /&gt;As a hobby coder, I realise this is extra work, but if the scrollArea and Description widgets were still acessible.. I would be delighted.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;update - I've filed a bug&lt;br /&gt;https://bugs.launchpad.net/update-manager/+bug/526937&lt;br /&gt;&lt;br /&gt;watch this space&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8109854847430899154-9169736812460414124?l=rowinggolfer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rowinggolfer.blogspot.com/feeds/9169736812460414124/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8109854847430899154&amp;postID=9169736812460414124' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/9169736812460414124'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/9169736812460414124'/><link rel='alternate' type='text/html' href='http://rowinggolfer.blogspot.com/2010/02/ubuntu-update-manager-feature-request.html' title='Ubuntu Update manager - feature request'/><author><name>Neil</name><uri>http://www.blogger.com/profile/06112117080373993301</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/-GEhvN_g7Kk4/TfnhG7DCMiI/AAAAAAAAAHo/HmAn1zC-xXM/s220/geek.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_wAfH8S6uz00/S4TqlAI3ouI/AAAAAAAAAE0/CTfRB75Bm1k/s72-c/updateManager.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8109854847430899154.post-2993637359792173175</id><published>2010-02-10T03:41:00.000Z</published><updated>2010-02-10T03:52:02.744Z</updated><title type='text'>pitivi</title><content type='html'>There's been a lot of buzz about pitivi perhaps being in ubuntu lucid by default.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;So I thought I would try the latest version.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I was surprised to learn that there isn't a ppa version available, so I set one up, and made a deb from the latest git version of pitivi. It works very well indeed, and is very intuitive.&lt;br /&gt;&lt;br /&gt;My ppa for pitivi "unstable" is &lt;a href="https://launchpad.net/%7Erowinggolfer/+archive/pitivi-unstable"&gt;here&lt;/a&gt;, and can be added using the new add-apt-repository command, which saves a lot of key hassle.&lt;br /&gt;&lt;br /&gt;&lt;i&gt;sudo add-apt-repository ppa:rowinggolfer/pitivi-unstable&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;add the g-streamer ppa while you are at it (pitivi uses gstreamer for the heavy lifting)&lt;br /&gt;&lt;i&gt;sudo add-apt-repository ppa:gstreamer-developers/ppa&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Here's my  &lt;a href="http://www.archive.org/details/AWeeJumpEnLesTroisVallees"&gt;first attempt&lt;/a&gt; with the new pitivi.. a title page tacked onto the front of a wee video.&lt;br /&gt;&lt;br /&gt;How did I make the title page? Gimp. But that's another issue altogether....&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8109854847430899154-2993637359792173175?l=rowinggolfer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rowinggolfer.blogspot.com/feeds/2993637359792173175/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8109854847430899154&amp;postID=2993637359792173175' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/2993637359792173175'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/2993637359792173175'/><link rel='alternate' type='text/html' href='http://rowinggolfer.blogspot.com/2010/02/pitivi.html' title='pitivi'/><author><name>Neil</name><uri>http://www.blogger.com/profile/06112117080373993301</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/-GEhvN_g7Kk4/TfnhG7DCMiI/AAAAAAAAAHo/HmAn1zC-xXM/s220/geek.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8109854847430899154.post-7492101011130007097</id><published>2009-12-09T12:01:00.000Z</published><updated>2009-12-09T12:01:44.681Z</updated><title type='text'>SCALE 2010</title><content type='html'>I have just submitted a talk for the beginner track at next years Southern California Linux Expo.&lt;br /&gt;&lt;br /&gt;I have no idea whether it will be accepted. However, here's the submission.&lt;br /&gt;&lt;br /&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Title&lt;/td&gt;         &lt;td&gt;Get Developing - it's easy.&lt;/td&gt;     &lt;/tr&gt;&lt;tr&gt;         &lt;td&gt;Categories&lt;/td&gt;         &lt;td&gt;General&lt;/td&gt;     &lt;/tr&gt;&lt;tr&gt;         &lt;td&gt;Audiences&lt;/td&gt;         &lt;td&gt;Beginner, Intermediate&lt;/td&gt;     &lt;/tr&gt;&lt;tr&gt;         &lt;td&gt;Description&lt;/td&gt;         &lt;td&gt;We all know that Linux has some wonderful tools for developing applications. I learnt these tools to become the sole IT support for my business ( a sucessful dental office). I'll tell you what I did, and hopefully inspire you to do the same.&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;b&gt;Short submission.&lt;/b&gt;&lt;br /&gt;I started writing an application called "openMolar" in November of 2008. openMolar is an application used in my dental practice.&lt;br /&gt;&lt;br /&gt;To do this I had to learn Python, Qt4, the bazaar version control system, mysql, GNU gettext, and debian packaging.&lt;br /&gt;I also learnt to use the Launchpad facilities for code hosting, bug tracking, translation and a PPA repository for ubuntu .&lt;br /&gt;&lt;br /&gt;In this talk, I hope to give you a basic synopsis of why I chose these particular tools (because, let's face it, there are some fine alternatives to each). &lt;br /&gt;I do not claim to be anything other than an enthusiastic hobbyist in any of these areas, but I have successfully used them to get my application to a stage which is working well in a demanding real-life situation.&lt;br /&gt;&lt;br /&gt;So if you are not developing applications yet, or are doing so using different tools, please come along and hear what I hope is an interesting story of "an application from scratch".&lt;br /&gt;&lt;br /&gt;p.s. if you are not writing code yet... I will endeavour to change this. If I (a middle-aged dentist) can write working code.. anyone can.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Long Submission.&lt;/b&gt;&lt;br /&gt;I want to discuss the following items during the talk.&lt;br /&gt;&lt;br /&gt;1. Having A problem to solve - a demonstration of my application in use.&lt;br /&gt;2. Choosing a license.&lt;br /&gt;3. Why Python?&lt;br /&gt;4. Why PyQt?&lt;br /&gt;5. Collaborating with others, using launchpad for code hosting and bug tracking.&lt;br /&gt;6. Packaging the app so that you get feedback. Debian packaging and the use of a PPA.&lt;br /&gt;7. Translating into other languages - the GNU gettext tools. Porquoi?&lt;br /&gt;8. the future for the application - can we make money from this?&lt;br /&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;Message to Reviewers.&lt;/b&gt;&lt;br /&gt;No presentation to upload at present, but I do have a video online at &lt;br /&gt;http://tinyvid.tv/show/1174zh4v3sldz&lt;br /&gt;&lt;br /&gt;project website is https://launchpad.net/openmolar&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8109854847430899154-7492101011130007097?l=rowinggolfer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rowinggolfer.blogspot.com/feeds/7492101011130007097/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8109854847430899154&amp;postID=7492101011130007097' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/7492101011130007097'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/7492101011130007097'/><link rel='alternate' type='text/html' href='http://rowinggolfer.blogspot.com/2009/12/scale-2010.html' title='SCALE 2010'/><author><name>Neil</name><uri>http://www.blogger.com/profile/06112117080373993301</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/-GEhvN_g7Kk4/TfnhG7DCMiI/AAAAAAAAAHo/HmAn1zC-xXM/s220/geek.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8109854847430899154.post-2814462137070345569</id><published>2009-11-19T21:40:00.000Z</published><updated>2009-11-20T01:21:24.815Z</updated><title type='text'>regex saves the pyqt day</title><content type='html'>I'm developing openmolar on Ubuntu Karmic, and that creates some backwards compatibility issues for hardy, intrepid and jaunty with code generated by pyuic4.&lt;br /&gt;&lt;br /&gt;so I have to make some substitutions, and that's where regex comes in.&lt;br /&gt;the python regex module is "re", and I am using a few of it's features here. Anyways, I'll let the code speak for itself.&lt;br /&gt;&lt;br /&gt;the problem is to turn generated code like this (on pyqt 4.6 where native python integers are acceptable) &lt;br /&gt;&lt;pre style="background-color: #cccccc;"&gt;spinBox.setProperty("value", 8)&lt;br /&gt;progressBar.setProperty("value", 10)&lt;br /&gt;randomWidget.setProperty("value", 260)&lt;br /&gt;&lt;/pre&gt;into this....&lt;br /&gt;&lt;pre style="background-color: #cccccc;"&gt;spinBox.setProperty("value", QtCore.QVariant(8))&lt;br /&gt;progressBar.setProperty("value", QtCore.QVariant(10))&lt;br /&gt;randomWidget.setProperty("value", QtCore.QVariant(260)&lt;/pre&gt;Here's one way to do it...&lt;br /&gt;&lt;pre style="background-color: #cccccc;"&gt;import re&lt;br /&gt;&lt;br /&gt;matches = re.finditer('setProperty\("value", (\d+)\)', data)&lt;br /&gt;for m in matches:&lt;br /&gt;    data = data.replace(m.group(), "QtCore.QVariant(%s)"% m.groups()[0])&lt;/pre&gt;&lt;br /&gt;my script for compiling any qt-designer generated ui files into python code can be found &lt;a href="http://bazaar.launchpad.net/%7Erowinggolfer/openmolar/trunk/annotate/head%3A/src/openmolar/qt-designer/om_pyuic4.py"&gt; here &lt;/a&gt; the above code is in lines 38 - 48.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8109854847430899154-2814462137070345569?l=rowinggolfer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rowinggolfer.blogspot.com/feeds/2814462137070345569/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8109854847430899154&amp;postID=2814462137070345569' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/2814462137070345569'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/2814462137070345569'/><link rel='alternate' type='text/html' href='http://rowinggolfer.blogspot.com/2009/11/regex-saves-pyqt-day.html' title='regex saves the pyqt day'/><author><name>Neil</name><uri>http://www.blogger.com/profile/06112117080373993301</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/-GEhvN_g7Kk4/TfnhG7DCMiI/AAAAAAAAAHo/HmAn1zC-xXM/s220/geek.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8109854847430899154.post-7231088158251192976</id><published>2009-11-01T10:34:00.001Z</published><updated>2009-11-01T10:43:37.563Z</updated><title type='text'>Using an mdiArea in PyQt</title><content type='html'>&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_wAfH8S6uz00/Su1lxMRkQ0I/AAAAAAAAAEo/z4BHXamSWM8/s1600-h/Screenshot.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://4.bp.blogspot.com/_wAfH8S6uz00/Su1lxMRkQ0I/AAAAAAAAAEo/z4BHXamSWM8/s320/Screenshot.png" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;I am adding a notifications area to openmolar, and experimenting with an mdiArea for this.&lt;br /&gt;I couldn't find a nice python (PyQt) example on the web, so offer this for google's sake.&lt;br /&gt;&lt;div style="clear: both;"&gt;&lt;pre&gt;import sys&lt;br /&gt;from PyQt4 import QtCore, QtGui&lt;br /&gt;&lt;br /&gt;app = QtGui.QApplication(sys.argv)&lt;br /&gt;&lt;br /&gt;mdiArea = QtGui.QMdiArea()&lt;br /&gt;mdiArea.show()&lt;br /&gt;&lt;br /&gt;labels = []&lt;br /&gt;&lt;br /&gt;for i in range(5):&lt;br /&gt;    labels.append(QtGui.QLabel())&lt;br /&gt;    labels[i].setText("hello world")&lt;br /&gt;    mdiArea.addSubWindow(labels[i])&lt;br /&gt;    labels[i].show()&lt;br /&gt;    &lt;br /&gt;mdiArea.cascadeSubWindows()&lt;br /&gt;&lt;br /&gt;sys.exit(app.exec_())&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8109854847430899154-7231088158251192976?l=rowinggolfer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rowinggolfer.blogspot.com/feeds/7231088158251192976/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8109854847430899154&amp;postID=7231088158251192976' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/7231088158251192976'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/7231088158251192976'/><link rel='alternate' type='text/html' href='http://rowinggolfer.blogspot.com/2009/11/using-mdiarea-in-pyqt.html' title='Using an mdiArea in PyQt'/><author><name>Neil</name><uri>http://www.blogger.com/profile/06112117080373993301</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/-GEhvN_g7Kk4/TfnhG7DCMiI/AAAAAAAAAHo/HmAn1zC-xXM/s220/geek.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_wAfH8S6uz00/Su1lxMRkQ0I/AAAAAAAAAEo/z4BHXamSWM8/s72-c/Screenshot.png' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8109854847430899154.post-5608412201333192117</id><published>2009-10-05T12:38:00.000+01:00</published><updated>2009-10-05T12:38:57.357+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='pyqt translation openmolar'/><title type='text'>Internationalising Openmolar</title><content type='html'>&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_wAfH8S6uz00/SsnJZEwM6wI/AAAAAAAAAEY/H-F1BqbjNto/s1600-h/translate1.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"&gt;&lt;img border="0" src="http://4.bp.blogspot.com/_wAfH8S6uz00/SsnJZEwM6wI/AAAAAAAAAEY/H-F1BqbjNto/s320/translate1.png" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;I was approached by 2 fine gents who offered to translate OpenMolar.&lt;br /&gt;&lt;br /&gt;Firstly Ariel Cornejo offered a Spanish translation, closely followed by Philippe Le Toquin who offered a French Version. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Anyways, the experience has been 100% positive. Lots of fun, and valuable learning again. The Gnu Gettext stuff, and the Launchpad translation facilities are very well thought out. Ditto Python's own implementation of such tools.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/_wAfH8S6uz00/SsnYJR-9xPI/AAAAAAAAAEg/MFC3da3sHso/s1600-h/translate2.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/_wAfH8S6uz00/SsnYJR-9xPI/AAAAAAAAAEg/MFC3da3sHso/s320/translate2.png" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;The screenshots to the right show the application&lt;br /&gt;switching into French Mode.&lt;br /&gt;&lt;br /&gt;Tres bon, n' est ce pas??&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I'll do a technical write up on what I learned in doing this over on the &lt;a href="http://openmolar.wikidot.com/"&gt;openmolar wiki&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8109854847430899154-5608412201333192117?l=rowinggolfer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rowinggolfer.blogspot.com/feeds/5608412201333192117/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8109854847430899154&amp;postID=5608412201333192117' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/5608412201333192117'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/5608412201333192117'/><link rel='alternate' type='text/html' href='http://rowinggolfer.blogspot.com/2009/10/internationalising-openmolar.html' title='Internationalising Openmolar'/><author><name>Neil</name><uri>http://www.blogger.com/profile/06112117080373993301</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/-GEhvN_g7Kk4/TfnhG7DCMiI/AAAAAAAAAHo/HmAn1zC-xXM/s220/geek.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_wAfH8S6uz00/SsnJZEwM6wI/AAAAAAAAAEY/H-F1BqbjNto/s72-c/translate1.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8109854847430899154.post-8330165867485500701</id><published>2009-09-20T09:56:00.000+01:00</published><updated>2009-09-20T09:58:05.812+01:00</updated><title type='text'>OpenMolar on the Ubuntu-uk podcast</title><content type='html'>This week I was interviewed by the ubuntu loco team for the ubuntu-uk podcast.&lt;br /&gt;I was totally overwhelmed (as I always am when in the company of REAL nerds/geeks), but they were kind to me, and their editing skills have produced some audio of which I am proud to be a part of.&lt;br /&gt;&lt;br /&gt;The ubuntu-uk podcast is a professional and highly regarded podcast within the linux community and beyond. What an honour! I have already had lots of interesting feedback.&lt;br /&gt;&lt;br /&gt;If you haven't heard the podcast, choose on of these formats.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://podcast.ubuntu-uk.org/download/uupc_s02e13_high.ogg"&gt;HQ ogg&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://podcast.ubuntu-uk.org/download/uupc_s02e13_low.ogg"&gt;LQ ogg&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://podcast.ubuntu-uk.org/download/uupc_s02e13_high.mp3"&gt;HQ mp3&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://podcast.ubuntu-uk.org/download/uupc_s02e13_low.mp3"&gt;LQ mp3&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Many thanks to Alan, Daviey, Ciemon, Daviey, Tony and Laura.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8109854847430899154-8330165867485500701?l=rowinggolfer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rowinggolfer.blogspot.com/feeds/8330165867485500701/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8109854847430899154&amp;postID=8330165867485500701' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/8330165867485500701'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/8330165867485500701'/><link rel='alternate' type='text/html' href='http://rowinggolfer.blogspot.com/2009/09/openmolar-on-ubuntu-uk-podcast.html' title='OpenMolar on the Ubuntu-uk podcast'/><author><name>Neil</name><uri>http://www.blogger.com/profile/06112117080373993301</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/-GEhvN_g7Kk4/TfnhG7DCMiI/AAAAAAAAAHo/HmAn1zC-xXM/s220/geek.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8109854847430899154.post-7702237071740830466</id><published>2009-09-03T00:58:00.000+01:00</published><updated>2009-09-03T11:38:13.018+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='openmolar'/><category scheme='http://www.blogger.com/atom/ns#' term='screencast'/><title type='text'>OpenMolar - screencast</title><content type='html'>ok.. I finally got around to doing this. A 15 minute intro to openmolar.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://tinyvid.tv/show/1174zh4v3sldz"&gt;http://tinyvid.tv/show/1174zh4v3sldz&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;as an aside... A note about tinyvid.tv.&lt;br /&gt;&lt;br /&gt;I didn't use youtube because they have a 10 minute restriction on length. &lt;br /&gt;Trawling the web, I came across tinyvid via floss manuals... there is some seriously good community content on there (Stallman vids etc..)... and all the content is ogg.&lt;br /&gt;&lt;br /&gt;Putting content onto Tinyvid is a wonderful experience, from start to finish.&lt;br /&gt;It accepted my launchpad page as openID. Uploaded the video without fuss, and even transcodes non-ogg content into ogg "in the cloud".&lt;br /&gt;&lt;br /&gt;I hope they are around for a long time to come. I tried to leave a donation, but couldn't see how to do that.&lt;br /&gt;&lt;br /&gt;Hope you enjoy the video. Comments, as always, very welcome.&lt;br /&gt;&lt;br /&gt;(screencast done on dell-mini9 using gtk-recordmydesktop and logitech USB headset)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8109854847430899154-7702237071740830466?l=rowinggolfer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rowinggolfer.blogspot.com/feeds/7702237071740830466/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8109854847430899154&amp;postID=7702237071740830466' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/7702237071740830466'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/7702237071740830466'/><link rel='alternate' type='text/html' href='http://rowinggolfer.blogspot.com/2009/09/openmolar-screencast.html' title='OpenMolar - screencast'/><author><name>Neil</name><uri>http://www.blogger.com/profile/06112117080373993301</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/-GEhvN_g7Kk4/TfnhG7DCMiI/AAAAAAAAAHo/HmAn1zC-xXM/s220/geek.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8109854847430899154.post-3054504299654219794</id><published>2009-08-30T03:02:00.000+01:00</published><updated>2009-08-30T03:48:44.878+01:00</updated><title type='text'>Ubuntu mysql and ssl</title><content type='html'>4 flippin' hours I have been tearing my hair out trying to force an ssl connection with mysql.&lt;br /&gt;I generated keys, wrote the code, but it didn't work.&lt;br /&gt;&lt;br /&gt;finally got it going though.&lt;br /&gt;this &lt;a href="http://www.waterlovinghead.com/MysqlSSL"&gt;HOW TO&lt;/a&gt; is the bomb.&lt;br /&gt;&lt;br /&gt;for ubuntu swap all references to /var/db/mysql to /etc/mysql&lt;br /&gt;&lt;br /&gt;so now you can all sniff my packets, see if I care.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8109854847430899154-3054504299654219794?l=rowinggolfer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rowinggolfer.blogspot.com/feeds/3054504299654219794/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8109854847430899154&amp;postID=3054504299654219794' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/3054504299654219794'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/3054504299654219794'/><link rel='alternate' type='text/html' href='http://rowinggolfer.blogspot.com/2009/08/ubuntu-mysql-and-ssl.html' title='Ubuntu mysql and ssl'/><author><name>Neil</name><uri>http://www.blogger.com/profile/06112117080373993301</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/-GEhvN_g7Kk4/TfnhG7DCMiI/AAAAAAAAAHo/HmAn1zC-xXM/s220/geek.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8109854847430899154.post-3367631669373332623</id><published>2009-08-27T15:31:00.000+01:00</published><updated>2009-08-28T15:56:53.033+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='ubuntu'/><title type='text'>pyAppTemplate</title><content type='html'>So I've started an application to help make and deploy python apps on Ubuntu.&lt;br /&gt;&lt;br /&gt;Here's a screencast showing it in use (version 0.2)&lt;br /&gt;&lt;a href="http://www.youtube.com/watch?v=jklX-IlXL9Y"&gt;http://www.youtube.com/watch?v=jklX-IlXL9Y&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;project is at https://launchpad.net/pyapptemplate&lt;br /&gt;&lt;br /&gt;I would love feedback as to whether this application is of interest to anyone.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8109854847430899154-3367631669373332623?l=rowinggolfer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rowinggolfer.blogspot.com/feeds/3367631669373332623/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8109854847430899154&amp;postID=3367631669373332623' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/3367631669373332623'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/3367631669373332623'/><link rel='alternate' type='text/html' href='http://rowinggolfer.blogspot.com/2009/08/pyapptemplate_27.html' title='pyAppTemplate'/><author><name>Neil</name><uri>http://www.blogger.com/profile/06112117080373993301</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/-GEhvN_g7Kk4/TfnhG7DCMiI/AAAAAAAAAHo/HmAn1zC-xXM/s220/geek.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8109854847430899154.post-1390448951390749534</id><published>2009-08-25T15:56:00.000+01:00</published><updated>2009-08-25T16:35:04.139+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='ubuntu'/><title type='text'>pyAppTemplate</title><content type='html'>to get a break from programming openMolar... but to help cement what I had learned about ubuntu packaging, I started another project pyAppTemplate.&lt;br /&gt;&lt;br /&gt;The goal of pyAppTemplate is to create a "debianisable" source tree from the get go of a project and... it works! The debs put the app onto the python path, and an executable in /usr/bin an icon into /usr/share/icons/hicolor/scalable and create a menu item.&lt;br /&gt;&lt;br /&gt;pyAppTemplate is currently a command-line only app, (I had my first play with the getopt module to parse the command line args passed), but I intend to create a qt, gtk, wx and tkinter frontend for it... just for fun! &lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_wAfH8S6uz00/SpP9WX9i1VI/AAAAAAAAAEQ/HJS-yKid16Q/s1600-h/pyapps.png"&gt;&lt;img style="float:right; margin:0 0 10px 10px;cursor:pointer; cursor:hand;width: 337px; height: 347px;" src="http://1.bp.blogspot.com/_wAfH8S6uz00/SpP9WX9i1VI/AAAAAAAAAEQ/HJS-yKid16Q/s400/pyapps.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5373917341214233938" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;I quickly made 2 virgin packages... and deployed them locally.&lt;br /&gt;&lt;br /&gt;pyAppTemplate is, of course, gplv3 code, and available at &lt;a href="https://launchpad.net/pyAppTemplate"&gt;https://launchpad.net/pyAppTemplate&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;I'll put a deb into &lt;a href="https://launchpad.net/~rowinggolfer/+archive/ppa"&gt;My PPA&lt;/a&gt; soon, and create a demo of the tool in use.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8109854847430899154-1390448951390749534?l=rowinggolfer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rowinggolfer.blogspot.com/feeds/1390448951390749534/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8109854847430899154&amp;postID=1390448951390749534' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/1390448951390749534'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/1390448951390749534'/><link rel='alternate' type='text/html' href='http://rowinggolfer.blogspot.com/2009/08/pyapptemplate.html' title='pyAppTemplate'/><author><name>Neil</name><uri>http://www.blogger.com/profile/06112117080373993301</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/-GEhvN_g7Kk4/TfnhG7DCMiI/AAAAAAAAAHo/HmAn1zC-xXM/s220/geek.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_wAfH8S6uz00/SpP9WX9i1VI/AAAAAAAAAEQ/HJS-yKid16Q/s72-c/pyapps.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8109854847430899154.post-3405446505416783193</id><published>2009-08-24T10:01:00.000+01:00</published><updated>2009-08-24T10:05:01.344+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='pyside'/><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='pyqt4'/><title type='text'>Silly python lyrics....</title><content type='html'>To the lyrics of "Always on your side" by Sheryl Crow.&lt;br /&gt;&lt;i&gt;&lt;br /&gt;My pyqt apps are all boxed up and neatly put away&lt;br /&gt;The qt kit with python they did bind&lt;br /&gt;But we were always waiting for the license to be changed&lt;br /&gt;From the LGPL, it found a place to hide&lt;br /&gt;Which is a shame but now we have PySide.&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;why is my head full of such garbage?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8109854847430899154-3405446505416783193?l=rowinggolfer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rowinggolfer.blogspot.com/feeds/3405446505416783193/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8109854847430899154&amp;postID=3405446505416783193' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/3405446505416783193'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/3405446505416783193'/><link rel='alternate' type='text/html' href='http://rowinggolfer.blogspot.com/2009/08/silly-python-lyrics.html' title='Silly python lyrics....'/><author><name>Neil</name><uri>http://www.blogger.com/profile/06112117080373993301</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/-GEhvN_g7Kk4/TfnhG7DCMiI/AAAAAAAAAHo/HmAn1zC-xXM/s220/geek.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8109854847430899154.post-2528493830074684512</id><published>2009-08-23T22:52:00.000+01:00</published><updated>2009-08-25T09:06:41.526+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='backup'/><category scheme='http://www.blogger.com/atom/ns#' term='rsync'/><title type='text'>.bashrc for pythonistas</title><content type='html'>It's a great trick for creating a clean copy of a directory of python stuff,  but I got sick of typing&lt;br /&gt; &lt;br /&gt;~$ rsync -av --exclude="*~" --exclude="*.pyc" ~/tests/ ~/tested/&lt;br /&gt;&lt;br /&gt;so I decided to add an alias to ~/.bashrc&lt;br /&gt;&lt;br /&gt;alias rsync='rsync --exclude="*~" --exclude="*.pyc"'&lt;br /&gt;&lt;br /&gt;works fine.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8109854847430899154-2528493830074684512?l=rowinggolfer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rowinggolfer.blogspot.com/feeds/2528493830074684512/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8109854847430899154&amp;postID=2528493830074684512' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/2528493830074684512'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/2528493830074684512'/><link rel='alternate' type='text/html' href='http://rowinggolfer.blogspot.com/2009/08/bashrc-for-pythonistas.html' title='.bashrc for pythonistas'/><author><name>Neil</name><uri>http://www.blogger.com/profile/06112117080373993301</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/-GEhvN_g7Kk4/TfnhG7DCMiI/AAAAAAAAAHo/HmAn1zC-xXM/s220/geek.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8109854847430899154.post-8159415426916642151</id><published>2009-08-22T12:36:00.000+01:00</published><updated>2009-08-22T12:57:15.252+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='karmic'/><category scheme='http://www.blogger.com/atom/ns#' term='ubuntu'/><title type='text'>Ubuntu Karmic alpha4 - 1st impressions</title><content type='html'>2 months before the release of Ubuntu 9.10 "Karmic Koala" (due 29th October), I am trying out the alpha 64-bit live CD on my advent 9112 laptop.&lt;br /&gt;&lt;br /&gt;I have to tell you I am MIGHTILY impressed.&lt;br /&gt;&lt;br /&gt;First linux distro that has recognised my rf (wireless) switch.&lt;br /&gt;And palimpsest gave me a warning about my failing hard drive. &lt;br /&gt;Time to run captain spinrite methinks. &lt;br /&gt;&lt;br /&gt;My keyboard was incorrectly recognised as us... but that gave me my first look at the keyboard settings app. A thing of beauty. Dunno if that's new to karmic?&lt;br /&gt;Anyways I would stake my mortgage on the keyboard layout being correct if I choose to install this to disk......&lt;br /&gt;&lt;br /&gt;.... and do you know what? I am going to, because this just feels RIGHT.&lt;br /&gt;&lt;br /&gt;congrats and thanks to everyone involved!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8109854847430899154-8159415426916642151?l=rowinggolfer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rowinggolfer.blogspot.com/feeds/8159415426916642151/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8109854847430899154&amp;postID=8159415426916642151' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/8159415426916642151'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/8159415426916642151'/><link rel='alternate' type='text/html' href='http://rowinggolfer.blogspot.com/2009/08/ubuntu-karmic-alpha4-1st-impressions.html' title='Ubuntu Karmic alpha4 - 1st impressions'/><author><name>Neil</name><uri>http://www.blogger.com/profile/06112117080373993301</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/-GEhvN_g7Kk4/TfnhG7DCMiI/AAAAAAAAAHo/HmAn1zC-xXM/s220/geek.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8109854847430899154.post-1691984562339998739</id><published>2009-08-14T00:14:00.000+01:00</published><updated>2009-08-14T00:23:24.073+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='pylint'/><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>Pylint Recursively</title><content type='html'>Not sure why I am blogging this, but I've been having a bit of fun with pylint, which checks python code for "bad smells" (ie. code which doesn't match the PEP standards).&lt;br /&gt;Pylint also finds unused imports, variables etc...&lt;br /&gt;&lt;br /&gt;I have written a little script to get only errors and scores out of pylint.&lt;br /&gt;It works recursively looking for *.py scripts within a directory passed to it on the command line, or (if that is missing) within the current working directory.&lt;br /&gt;&lt;br /&gt;Posted here in case it is of any use to anyone.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;#! /usr/bin/env python&lt;br /&gt;'''&lt;br /&gt;this module runs pylint on all python scripts found in a directory tree&lt;br /&gt;'''&lt;br /&gt;&lt;br /&gt;import os&lt;br /&gt;import re&lt;br /&gt;import sys&lt;br /&gt;&lt;br /&gt;total = 0.0&lt;br /&gt;count = 0&lt;br /&gt;&lt;br /&gt;def check(module):&lt;br /&gt;    '''&lt;br /&gt;    apply pylint to the file specified if it is a *.py file&lt;br /&gt;    '''&lt;br /&gt;    global total, count&lt;br /&gt;&lt;br /&gt;    if module[-3:] == ".py":&lt;br /&gt;&lt;br /&gt;        print "CHECKING ", module&lt;br /&gt;        pout = os.popen('pylint %s'% module, 'r')&lt;br /&gt;        for line in pout:&lt;br /&gt;            if  re.match("E....:.", line):&lt;br /&gt;                print line&lt;br /&gt;            if "Your code has been rated at" in line:&lt;br /&gt;                print line&lt;br /&gt;                score = re.findall("\d.\d\d", line)[0]&lt;br /&gt;                total += float(score)&lt;br /&gt;                count += 1&lt;br /&gt;    &lt;br /&gt;if __name__ == "__main__":&lt;br /&gt;    try:&lt;br /&gt;        print sys.argv   &lt;br /&gt;        BASE_DIRECTORY = sys.argv[1]&lt;br /&gt;    except IndexError:&lt;br /&gt;        print "no directory specified, defaulting to current working directory"&lt;br /&gt;        BASE_DIRECTORY = os.getcwd()&lt;br /&gt;&lt;br /&gt;    print "looking for *.py scripts in subdirectories of ", BASE_DIRECTORY &lt;br /&gt;    for root, dirs, files in os.walk(BASE_DIRECTORY):&lt;br /&gt;        for name in files:&lt;br /&gt;            filepath = os.path.join(root, name)&lt;br /&gt;            check(filepath)&lt;br /&gt;            &lt;br /&gt;    print "==" * 50&lt;br /&gt;    print "%d modules found"% count&lt;br /&gt;    print "AVERAGE SCORE = %.02f"% (total / count)&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8109854847430899154-1691984562339998739?l=rowinggolfer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rowinggolfer.blogspot.com/feeds/1691984562339998739/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8109854847430899154&amp;postID=1691984562339998739' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/1691984562339998739'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/1691984562339998739'/><link rel='alternate' type='text/html' href='http://rowinggolfer.blogspot.com/2009/08/pylint-recursively.html' title='Pylint Recursively'/><author><name>Neil</name><uri>http://www.blogger.com/profile/06112117080373993301</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/-GEhvN_g7Kk4/TfnhG7DCMiI/AAAAAAAAAHo/HmAn1zC-xXM/s220/geek.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8109854847430899154.post-4792676567825901824</id><published>2009-08-13T08:49:00.000+01:00</published><updated>2009-08-13T08:58:28.321+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='gmail'/><title type='text'>gmail-notifier</title><content type='html'>I went trawling through synaptic to find a little app to notify me when a new piece of email arrived in my googlemail account, and found "gmail-notifier". I installed it, and decided that this was perfect for me.&lt;br /&gt;&lt;br /&gt;however....&lt;br /&gt;&lt;br /&gt;the project looks stale (last commit in 2007) and the project's &lt;a href="http://sourceforge.net/mailarchive/forum.php?forum_name=gmail-notify-devel"&gt;mailing list &lt;/a&gt; is full of spam.&lt;br /&gt;&lt;br /&gt;the app has IMHO two major shortcomings...&lt;br /&gt;&lt;ul&gt;&lt;li&gt;password is stored in plain text in a config file&lt;/li&gt;&lt;br /&gt;&lt;li&gt;I suspect the password is sent in the clear&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;I may be wrong about point number 2, I was going to ask via the mailing list, but I very much doubt anyone reads it unless they want a bigger willy or cheap pharmaceuticals.&lt;br /&gt;&lt;br /&gt;So it looks like I will have to use the FF plug in like everybody else :(&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8109854847430899154-4792676567825901824?l=rowinggolfer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rowinggolfer.blogspot.com/feeds/4792676567825901824/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8109854847430899154&amp;postID=4792676567825901824' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/4792676567825901824'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/4792676567825901824'/><link rel='alternate' type='text/html' href='http://rowinggolfer.blogspot.com/2009/08/gmail-notifier.html' title='gmail-notifier'/><author><name>Neil</name><uri>http://www.blogger.com/profile/06112117080373993301</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/-GEhvN_g7Kk4/TfnhG7DCMiI/AAAAAAAAAHo/HmAn1zC-xXM/s220/geek.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8109854847430899154.post-7576523927012377791</id><published>2009-07-23T23:54:00.000+01:00</published><updated>2009-07-23T23:55:47.781+01:00</updated><title type='text'>Sansa Clip Firmware upgrade</title><content type='html'>Just sucessfully updated the firmware on my sansa clip player following&lt;br /&gt;&lt;a href="http://forums.sandisk.com/sansa/board/message?board.id=clip&amp;thread.id=15109"&gt;This thread&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Did not need to resort to the windows method :)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8109854847430899154-7576523927012377791?l=rowinggolfer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rowinggolfer.blogspot.com/feeds/7576523927012377791/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8109854847430899154&amp;postID=7576523927012377791' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/7576523927012377791'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/7576523927012377791'/><link rel='alternate' type='text/html' href='http://rowinggolfer.blogspot.com/2009/07/sansa-clip-firmware-upgrade.html' title='Sansa Clip Firmware upgrade'/><author><name>Neil</name><uri>http://www.blogger.com/profile/06112117080373993301</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/-GEhvN_g7Kk4/TfnhG7DCMiI/AAAAAAAAAHo/HmAn1zC-xXM/s220/geek.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8109854847430899154.post-9094312552089302097</id><published>2009-07-16T11:31:00.000+01:00</published><updated>2009-07-16T11:33:47.074+01:00</updated><title type='text'>Programming resource</title><content type='html'>Highly recommended reading, on object orientation and software design in general.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://homepage.mac.com/s_lott/books/oodesign.html"&gt;http://homepage.mac.com/s_lott/books/oodesign.html&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8109854847430899154-9094312552089302097?l=rowinggolfer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rowinggolfer.blogspot.com/feeds/9094312552089302097/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8109854847430899154&amp;postID=9094312552089302097' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/9094312552089302097'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/9094312552089302097'/><link rel='alternate' type='text/html' href='http://rowinggolfer.blogspot.com/2009/07/programming-resource.html' title='Programming resource'/><author><name>Neil</name><uri>http://www.blogger.com/profile/06112117080373993301</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/-GEhvN_g7Kk4/TfnhG7DCMiI/AAAAAAAAAHo/HmAn1zC-xXM/s220/geek.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8109854847430899154.post-1784096798610514704</id><published>2009-07-11T09:34:00.000+01:00</published><updated>2009-07-11T09:58:47.678+01:00</updated><title type='text'>bash-history  - a tip and some thoughts.</title><content type='html'>A great tip on the &lt;a href="http://podcast.ubuntu-uk.org/"&gt;Ubuntu-uk podcast&lt;/a&gt; this week for keeping your .bash_history file a little leaner (AND MORE SECURE!).&lt;br /&gt;&lt;br /&gt;what's the difference between these two lines?&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;~mysqldump -u user -ppassword mydatabase &gt; backup.sql&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;~ mysqldump -u user -ppassword mydatabase &gt; backup.sql&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;well both do the same thing (backup a mysql database to a flat file).&lt;br /&gt;However, the first variant would go into your .bash_history, whereas the second one wouldn't thanks to the space at the line start.&lt;br /&gt;&lt;br /&gt;why does this matter?&lt;br /&gt;1. you probably don't want to put plain text passwords into the shell history. It may be convenient, but this file is one of the first places anyone malicious (or simply mischievous) would look to harvest such things if they got physical or virtual access to your machine.&lt;br /&gt;&lt;br /&gt;2. perhaps, like me, your .bash_history get's full of stuff like &lt;br /&gt;&lt;br /&gt;cd ~&lt;br /&gt;ls&lt;br /&gt;cp -av /home/neil/bashpodder/2009-06-25/ .&lt;br /&gt;mount /dev/sdb /media/player&lt;br /&gt;sudo mount /dev/sdb /media/player&lt;br /&gt;sudo -s&lt;br /&gt;ssh -p 3298 -N -L 2948:192.168.88.2:3306 dentists@mywork.com&lt;br /&gt;sudo umount /media/player&lt;br /&gt;python&lt;br /&gt;echo "http://feeds.conversationsnetwork.org/channel/itc" &gt;&gt; bashpodder/bp.conf&lt;br /&gt;cd ~/windows_openmolar/openmolar/ &amp;&amp; bzr pull&lt;br /&gt;&lt;br /&gt;now of those commands, only one or two benefit from being available via arrow navigation. in future, I will be considering putting a space before the majority of my command line playing.&lt;br /&gt;&lt;br /&gt;but d'you know what? I think I need to look into the behaviour of bash_history some more. Ideally I would like it to have everything &lt;span style="font-weight:bold;"&gt;from that terminal session&lt;/span&gt; directly available, spaces or no...(in case of typos, which I'll admit happen occasionally) but archive only those without. &lt;br /&gt;&lt;br /&gt;I'll bet there's something in the man page... must check sometime.&lt;br /&gt;Neil.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8109854847430899154-1784096798610514704?l=rowinggolfer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rowinggolfer.blogspot.com/feeds/1784096798610514704/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8109854847430899154&amp;postID=1784096798610514704' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/1784096798610514704'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/1784096798610514704'/><link rel='alternate' type='text/html' href='http://rowinggolfer.blogspot.com/2009/07/bash-history-tip-and-some-thoughts.html' title='bash-history  - a tip and some thoughts.'/><author><name>Neil</name><uri>http://www.blogger.com/profile/06112117080373993301</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/-GEhvN_g7Kk4/TfnhG7DCMiI/AAAAAAAAAHo/HmAn1zC-xXM/s220/geek.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8109854847430899154.post-5646425593925564075</id><published>2009-07-02T15:18:00.000+01:00</published><updated>2009-07-02T16:20:24.242+01:00</updated><title type='text'>tunneling mysql over ssh</title><content type='html'>Here's my setup for remote access to my mysql server at work.&lt;br /&gt;&lt;br /&gt;My work has a dynamically assigned ip from the local provider. I use the free service from dyndns.com to make that ip available. So let's say the hostname I chose from dyndns was mywork.dyn-alias.com.&lt;br /&gt;I could ping that address using&lt;br /&gt;&lt;br /&gt;~ping mywork.dyn-alias.com&lt;br /&gt;&lt;br /&gt;I set up a machine at work (machine A) to listen for ssh connections on port 34567&lt;br /&gt;so I can connect to that machine using.&lt;br /&gt;&lt;br /&gt;~ssh -p 34567 mywork.dyn-alias.com&lt;br /&gt;&lt;br /&gt;oh hang on.. my home user "neil" is not allowed, silly me, so let's say I have a known user called "dentist"&lt;br /&gt;&lt;br /&gt;~ssh -p 34567 dentist@mywork.dyn-alias.com&lt;br /&gt;&lt;br /&gt;that works!&lt;br /&gt;&lt;br /&gt;Now A separate mysql server (machine B) resides on that network. It's LAN IP is 192.168.0.2. &lt;br /&gt;This machine does not allow any other type of connection. What if I want to lever that database remotely? The easiest way is to ssh into machine A (as above) and use the mysql-client command line tool on that machine to connect to machine B.&lt;br /&gt;&lt;br /&gt;that command is&lt;br /&gt;~mysql -h 192.168.0.2 -u databaseUser -p&lt;br /&gt;&lt;br /&gt;which will prompt for a password. or&lt;br /&gt;~mysql -h 192.168.0.2 -u databaseUser -pPASSWORD mydatabase&lt;br /&gt;&lt;br /&gt;which will pass the password "PASSWORD" automatically, and start using database "mydatabase" automatically.&lt;br /&gt;&lt;br /&gt;but what if I want to use an application - like openmolar - to connect to that database.&lt;br /&gt;&lt;br /&gt;the answer here is to forward the mysql port from machine B through machine A, so that it appears as a service running on my local machine.&lt;br /&gt;here's how..... &lt;br /&gt;&lt;br /&gt;~ssh -p 34567 -N -L 45678:192.168.0.2:3306 dentist@mywork.dyn-alias.com&lt;br /&gt;&lt;br /&gt;which means...&lt;br /&gt;-p 34567 use "port" 34567  (isn't port a silly term... surely this should be "channel")&lt;br /&gt;-N from the ssh manual - "Do not execute a remote command" I don't fully understand this, but do know the connection is refused if I ommit this.&lt;br /&gt;&lt;br /&gt;-L 45678:192.168.0.2:3306 let's break this down. -L is the command to "bind an address"&lt;br /&gt;&lt;br /&gt;45678 is a random port on mylocal machine.&lt;br /&gt;&lt;br /&gt;192.168.0.2:3306 is the address of the mysql service on machine B. machine A has permission to connect to this.  Also note - 3306 is mysql's standard port.&lt;br /&gt;&lt;br /&gt;with that command running, I can now point the app to 127.0.0.1:45678 and I'm golden.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8109854847430899154-5646425593925564075?l=rowinggolfer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rowinggolfer.blogspot.com/feeds/5646425593925564075/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8109854847430899154&amp;postID=5646425593925564075' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/5646425593925564075'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/5646425593925564075'/><link rel='alternate' type='text/html' href='http://rowinggolfer.blogspot.com/2009/07/tunneling-mysql-over-ssh.html' title='tunneling mysql over ssh'/><author><name>Neil</name><uri>http://www.blogger.com/profile/06112117080373993301</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/-GEhvN_g7Kk4/TfnhG7DCMiI/AAAAAAAAAHo/HmAn1zC-xXM/s220/geek.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8109854847430899154.post-7037684705346699633</id><published>2009-06-20T14:55:00.000+01:00</published><updated>2009-06-20T14:58:42.277+01:00</updated><title type='text'>dell mini bios upgrade</title><content type='html'>I've just upgraded the bios on my dell mini-9.&lt;br /&gt;&lt;br /&gt;Followed this howto.&lt;br /&gt;http://ubuntuforums.org/showpost.php?p=7336044&amp;postcount=64&lt;br /&gt;&lt;br /&gt;the new bios makes Fn+Z and Fn+X as function keys, and apprarently improves battery life.&lt;br /&gt;&lt;br /&gt;more importantly... fancy graphics on boot :)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8109854847430899154-7037684705346699633?l=rowinggolfer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rowinggolfer.blogspot.com/feeds/7037684705346699633/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8109854847430899154&amp;postID=7037684705346699633' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/7037684705346699633'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/7037684705346699633'/><link rel='alternate' type='text/html' href='http://rowinggolfer.blogspot.com/2009/06/dell-mini-bios-upgrade.html' title='dell mini bios upgrade'/><author><name>Neil</name><uri>http://www.blogger.com/profile/06112117080373993301</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/-GEhvN_g7Kk4/TfnhG7DCMiI/AAAAAAAAAHo/HmAn1zC-xXM/s220/geek.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8109854847430899154.post-8100327883547147739</id><published>2009-06-12T12:13:00.000+01:00</published><updated>2009-06-12T12:14:41.204+01:00</updated><title type='text'>Floss Manuals</title><content type='html'>Fascinating podcasts have emerged from the libre planet event.&lt;br /&gt;&lt;br /&gt;Many mention the work done (in sprints thereat) to improve the floss manuals.&lt;br /&gt;&lt;br /&gt;Here they are. Highly recommended.&lt;br /&gt;http://en.flossmanuals.net/&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8109854847430899154-8100327883547147739?l=rowinggolfer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rowinggolfer.blogspot.com/feeds/8100327883547147739/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8109854847430899154&amp;postID=8100327883547147739' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/8100327883547147739'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/8100327883547147739'/><link rel='alternate' type='text/html' href='http://rowinggolfer.blogspot.com/2009/06/floss-manuals.html' title='Floss Manuals'/><author><name>Neil</name><uri>http://www.blogger.com/profile/06112117080373993301</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/-GEhvN_g7Kk4/TfnhG7DCMiI/AAAAAAAAAHo/HmAn1zC-xXM/s220/geek.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8109854847430899154.post-5990320883066420701</id><published>2009-05-11T10:58:00.000+01:00</published><updated>2009-05-11T11:06:19.453+01:00</updated><title type='text'>3 tips for new pythonistas</title><content type='html'>1. learn regex.&lt;br /&gt;2. learn regex&lt;br /&gt;3. learn regex.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8109854847430899154-5990320883066420701?l=rowinggolfer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rowinggolfer.blogspot.com/feeds/5990320883066420701/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8109854847430899154&amp;postID=5990320883066420701' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/5990320883066420701'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/5990320883066420701'/><link rel='alternate' type='text/html' href='http://rowinggolfer.blogspot.com/2009/05/3-tips-for-new-pythonistas.html' title='3 tips for new pythonistas'/><author><name>Neil</name><uri>http://www.blogger.com/profile/06112117080373993301</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/-GEhvN_g7Kk4/TfnhG7DCMiI/AAAAAAAAAHo/HmAn1zC-xXM/s220/geek.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8109854847430899154.post-989334844469500965</id><published>2009-05-09T22:29:00.000+01:00</published><updated>2009-05-09T22:39:12.332+01:00</updated><title type='text'>Promote linux campaign</title><content type='html'>If I were involved in the marketing of Ubuntu... here is the advertising campaign I would run.&lt;br /&gt;&lt;br /&gt;Setting - a school IT classroom&lt;br /&gt;Music - Pink Floyd. "we don't need no education"&lt;br /&gt;Theme - zombie kids being taught to use a popular word-processing application by (no names).&lt;br /&gt;&lt;br /&gt;cool kid in the back of the classroom has a different desktop... what is it?&lt;br /&gt;he's spinning the cube switching between all the killer apps. he winks to camera.&lt;br /&gt;&lt;br /&gt;fade out...&lt;br /&gt;&lt;br /&gt;ubuntu logo...&lt;br /&gt;&lt;br /&gt;"because kids don't need no thought control"&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8109854847430899154-989334844469500965?l=rowinggolfer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rowinggolfer.blogspot.com/feeds/989334844469500965/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8109854847430899154&amp;postID=989334844469500965' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/989334844469500965'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/989334844469500965'/><link rel='alternate' type='text/html' href='http://rowinggolfer.blogspot.com/2009/05/promote-linux-campaign.html' title='Promote linux campaign'/><author><name>Neil</name><uri>http://www.blogger.com/profile/06112117080373993301</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/-GEhvN_g7Kk4/TfnhG7DCMiI/AAAAAAAAAHo/HmAn1zC-xXM/s220/geek.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8109854847430899154.post-4424809464356631833</id><published>2009-04-30T23:59:00.000+01:00</published><updated>2009-05-01T00:43:46.197+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='openmolar'/><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><category scheme='http://www.blogger.com/atom/ns#' term='opensource'/><title type='text'>openmolar update and a plea for sanity</title><content type='html'>2 weeks ago I switched off our commercially provided uber expensive crapware for the last time, and moved 100% to using my own solution "openMolar".&lt;br /&gt;&lt;br /&gt;openMolar is a multi-client/single server application. Presently I have 2 linux clients, 3 windows clients running my software and a linux mysql server.&lt;br /&gt;(I also have the full front-end and backend application running on my dell-mini9, but that's another story...)&lt;br /&gt;&lt;br /&gt;The development of this application has been quite a trip, but proves that even someone with my limited coding skills can knock up a professional quality app using only open source tools.&lt;br /&gt;&lt;br /&gt;And the bandwagon keeps on rolling. &lt;br /&gt;Bryan Harris from the US and Mehmet nur Olcay from Turkey have joined in on the launchpad site, and are working on packaging the app for ubuntu and (more interestingly) Pardus linux. I look forward to making the code accessible for language translation purposes.&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_wAfH8S6uz00/Sfoxx-RnreI/AAAAAAAAAEI/UfdBcfOSvXM/s1600-h/newlogo.png"&gt;&lt;img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer; width: 200px; height: 127px;" src="http://3.bp.blogspot.com/_wAfH8S6uz00/Sfoxx-RnreI/AAAAAAAAAEI/UfdBcfOSvXM/s320/newlogo.png" alt="" id="BLOGGER_PHOTO_ID_5330627843546656226" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Richard Querin has again exceeded all expectations by providing an alternative logo focusing on the freedom aspect of the software. I intend to get some embroidered t-shirts for the practice staff to wear when we attend the British Dental Association Conference in 4 weeks time.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;But before folks get too carried away, a reminder. This bandwagon needs the brakes applying somewhat.&lt;br /&gt;&lt;br /&gt;My focus has always been (and will for the medium term at least) to have this software working in the practice.&lt;br /&gt;The interest that is being shown from the dental profession and open source movement alike is quite humbling but a little frightening. It goes to show that there is demand for open source solutions, however, please &lt;b&gt;let nobody be under the impression that this product is finished&lt;/b&gt;. &lt;br /&gt;I am wary that if others take my code and push it out at this stage it could get it a reputation from which it will never recover. I am also fully aware that there are many companies who would love to see this project fail. I beg the open source community not to play a part in making this happen. &lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.academydental.com/openmolar"&gt;Here is a page of screenshots and explanations&lt;/a&gt; for those who would like to know more.&lt;br /&gt;&lt;br /&gt;The project can be found on launchpad.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8109854847430899154-4424809464356631833?l=rowinggolfer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rowinggolfer.blogspot.com/feeds/4424809464356631833/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8109854847430899154&amp;postID=4424809464356631833' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/4424809464356631833'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/4424809464356631833'/><link rel='alternate' type='text/html' href='http://rowinggolfer.blogspot.com/2009/04/openmolar-update-and-plea-for-sanity.html' title='openmolar update and a plea for sanity'/><author><name>Neil</name><uri>http://www.blogger.com/profile/06112117080373993301</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/-GEhvN_g7Kk4/TfnhG7DCMiI/AAAAAAAAAHo/HmAn1zC-xXM/s220/geek.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_wAfH8S6uz00/Sfoxx-RnreI/AAAAAAAAAEI/UfdBcfOSvXM/s72-c/newlogo.png' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8109854847430899154.post-2654615318575670065</id><published>2009-04-16T11:29:00.000+01:00</published><updated>2009-04-16T19:50:39.589+01:00</updated><title type='text'>logos, launchpad and bizarre experiences</title><content type='html'>Three things.&lt;br /&gt;&lt;ol&gt;&lt;li&gt;I am overjoyed with &lt;a href="http://rfquerin.org/"&gt;Richard Querin's&lt;/a&gt; first draft of a logo for openMolar.&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_wAfH8S6uz00/SecKtzVhUHI/AAAAAAAAAEA/TEtIy_5yQwo/s1600-h/logo1.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 90px;" src="http://2.bp.blogspot.com/_wAfH8S6uz00/SecKtzVhUHI/AAAAAAAAAEA/TEtIy_5yQwo/s320/logo1.png" alt="" id="BLOGGER_PHOTO_ID_5325236866379763826" border="0" /&gt;&lt;/a&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;My code is up on launchpad.net at &lt;a href="http://launchpad.net/openmolar"&gt;http://launchpad.net/openmolar&lt;/a&gt;.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;The python versioning control system Bzr is working well. I hope. thanks to "thumper" in #launchpad on freenode for his guidance. I have made 3 pushes already. Awesome.&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8109854847430899154-2654615318575670065?l=rowinggolfer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rowinggolfer.blogspot.com/feeds/2654615318575670065/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8109854847430899154&amp;postID=2654615318575670065' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/2654615318575670065'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/2654615318575670065'/><link rel='alternate' type='text/html' href='http://rowinggolfer.blogspot.com/2009/04/logos-launchpad-and-bizarre-experiences.html' title='logos, launchpad and bizarre experiences'/><author><name>Neil</name><uri>http://www.blogger.com/profile/06112117080373993301</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/-GEhvN_g7Kk4/TfnhG7DCMiI/AAAAAAAAAHo/HmAn1zC-xXM/s220/geek.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_wAfH8S6uz00/SecKtzVhUHI/AAAAAAAAAEA/TEtIy_5yQwo/s72-c/logo1.png' height='72' width='72'/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8109854847430899154.post-1365966237033611639</id><published>2009-04-08T10:18:00.000+01:00</published><updated>2009-04-08T10:29:51.029+01:00</updated><title type='text'>openmolar - new tarball</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_wAfH8S6uz00/Sdxuda85qUI/AAAAAAAAAD4/F-UhZZhsOXk/s1600-h/perioWidget.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 59px;" src="http://1.bp.blogspot.com/_wAfH8S6uz00/Sdxuda85qUI/AAAAAAAAAD4/F-UhZZhsOXk/s320/perioWidget.png" alt="" id="BLOGGER_PHOTO_ID_5322250311375104322" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;another test tarball for interested folks to install and try.&lt;br /&gt;&lt;br /&gt;Still immature software, but a fair few new features.&lt;br /&gt;&lt;br /&gt;Many thanks to all who sucessfully installed the 1st version despite a few errors in my README file!&lt;br /&gt;Hopefully those bugs are now ironed out.&lt;br /&gt;&lt;br /&gt;please note, you will need to refresh to the new database if you installed 0.0.3 version.&lt;br /&gt;&lt;br /&gt;BTW - hopefully I will get the hang of bzr / launchpad for future releases... meantime, the tarball can be found &lt;a href="http://www.invernessrowingclub.co.uk/misc/openmolar/"&gt; HERE &lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8109854847430899154-1365966237033611639?l=rowinggolfer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rowinggolfer.blogspot.com/feeds/1365966237033611639/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8109854847430899154&amp;postID=1365966237033611639' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/1365966237033611639'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/1365966237033611639'/><link rel='alternate' type='text/html' href='http://rowinggolfer.blogspot.com/2009/04/openmolar-new-tarball.html' title='openmolar - new tarball'/><author><name>Neil</name><uri>http://www.blogger.com/profile/06112117080373993301</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/-GEhvN_g7Kk4/TfnhG7DCMiI/AAAAAAAAAHo/HmAn1zC-xXM/s220/geek.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_wAfH8S6uz00/Sdxuda85qUI/AAAAAAAAAD4/F-UhZZhsOXk/s72-c/perioWidget.png' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8109854847430899154.post-1289267328622478577</id><published>2009-03-22T07:01:00.000Z</published><updated>2009-03-22T07:20:11.689Z</updated><title type='text'>two wee python lifesavers</title><content type='html'>filed under the "notes to self" category... if I forget these tips I'll googling for them... so let's put them on my random blog for now.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;This should be enabled by default in the standard python shell. &lt;a href="http://blog.venthur.de/2008/07/06/tab-completion-in-pythons-interactive-mode/"&gt;http://blog.venthur.de/2008/07/06/tab-completion-in-pythons-interactive-mode/&lt;/a&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;'enscript' is a must have for printing code...  and from the man page, is this suggestion from the developer himself - flags for printing code: gaudy  header,  two  columns, landscape, code highlighting, 2-up printing.&lt;pre&gt;~$enscript -G2rE -U2 main.py&lt;/pre&gt;&lt;br /&gt;if you have a long script, check it out... it's beautiful.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8109854847430899154-1289267328622478577?l=rowinggolfer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rowinggolfer.blogspot.com/feeds/1289267328622478577/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8109854847430899154&amp;postID=1289267328622478577' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/1289267328622478577'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/1289267328622478577'/><link rel='alternate' type='text/html' href='http://rowinggolfer.blogspot.com/2009/03/two-wee-python-lifesavers.html' title='two wee python lifesavers'/><author><name>Neil</name><uri>http://www.blogger.com/profile/06112117080373993301</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/-GEhvN_g7Kk4/TfnhG7DCMiI/AAAAAAAAAHo/HmAn1zC-xXM/s220/geek.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8109854847430899154.post-9154558500939879311</id><published>2009-03-19T12:33:00.000Z</published><updated>2009-03-19T12:43:15.793Z</updated><title type='text'>openMolar - it's not a comic book reader.</title><content type='html'>I was a guest on the linux link tech show last night, I was my usual incoherent babbling self, but I had a great time.&lt;br /&gt;&lt;br /&gt;If anyone is interested in seeing just how badly I write code, please download,play with, and scrutinise the openMolar software.&lt;br /&gt;&lt;br /&gt;tarball (inlcuding an example database for March and April 2009) and a checksum for the paranoid can be found at&lt;br /&gt;&lt;a href="http://www.invernessrowingclub.co.uk/misc/openmolar"&gt;www.invernessrowingclub.co.uk/misc/openmolar&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_wAfH8S6uz00/ScI9AeNBcEI/AAAAAAAAADw/T9M9Z0TL3_8/s1600-h/pt_sum.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 189px;" src="http://3.bp.blogspot.com/_wAfH8S6uz00/ScI9AeNBcEI/AAAAAAAAADw/T9M9Z0TL3_8/s320/pt_sum.png" alt="" id="BLOGGER_PHOTO_ID_5314877588567584834" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_wAfH8S6uz00/ScI8x0BglwI/AAAAAAAAADo/4a-_e-DHwiU/s1600-h/aptBook.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 189px;" src="http://4.bp.blogspot.com/_wAfH8S6uz00/ScI8x0BglwI/AAAAAAAAADo/4a-_e-DHwiU/s320/aptBook.png" alt="" id="BLOGGER_PHOTO_ID_5314877336726836994" border="0" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8109854847430899154-9154558500939879311?l=rowinggolfer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rowinggolfer.blogspot.com/feeds/9154558500939879311/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8109854847430899154&amp;postID=9154558500939879311' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/9154558500939879311'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/9154558500939879311'/><link rel='alternate' type='text/html' href='http://rowinggolfer.blogspot.com/2009/03/openmolar-its-not-comic-book-reader.html' title='openMolar - it&apos;s not a comic book reader.'/><author><name>Neil</name><uri>http://www.blogger.com/profile/06112117080373993301</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/-GEhvN_g7Kk4/TfnhG7DCMiI/AAAAAAAAAHo/HmAn1zC-xXM/s220/geek.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_wAfH8S6uz00/ScI9AeNBcEI/AAAAAAAAADw/T9M9Z0TL3_8/s72-c/pt_sum.png' height='72' width='72'/><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8109854847430899154.post-399734848072912569</id><published>2009-02-17T11:48:00.000Z</published><updated>2009-02-17T12:08:32.979Z</updated><title type='text'>Review - sansa clip ogg/mp3 player</title><content type='html'>With Linux cranks and the bad apples podcasts going to ogg only, I decided to invest in a new player.&lt;br /&gt;&lt;br /&gt;The sansa clip seemed to fit the bill perfectly, for the following reasons.&lt;br /&gt;&lt;ul&gt;&lt;li&gt; mounts as a drive, easy drag and drop of files&lt;/li&gt;&lt;br /&gt;&lt;li&gt;plays ogg&lt;/li&gt;&lt;br /&gt;&lt;li&gt;built in fm radio&lt;/li&gt;&lt;br /&gt;&lt;li&gt;small&lt;/li&gt;&lt;br /&gt;&lt;li&gt;cheap&lt;/li&gt;&lt;br /&gt;&lt;li&gt;sexy&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_wAfH8S6uz00/SZqlvR0etuI/AAAAAAAAADg/MKvsGEb6DgA/s1600-h/SansaClipTilt.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 318px;" src="http://4.bp.blogspot.com/_wAfH8S6uz00/SZqlvR0etuI/AAAAAAAAADg/MKvsGEb6DgA/s320/SansaClipTilt.jpg" alt="" id="BLOGGER_PHOTO_ID_5303733742838134498" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;but it turns out that this is the best damn player I've ever owned... and here's why.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;It can delete tracks. Very useful. I need to do this, otherwise I forget what I've listened to.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;it can play tracks at an increased speed&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;That last feature sounds like a gimmick (or a discourtesy to the podcaster) however, I am enjoying it.&lt;br /&gt;This morning, for example - it compressed lottalinuxlinks 106 down to MY commuting time, not Daves. Lynn didn't sound so sexy.. but kajarii did ;)&lt;br /&gt;&lt;br /&gt;Battery Life could maybe be better... I have been spoilt by Sony players, having said that, battery life is perhaps the only thing to recommend Sony players.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8109854847430899154-399734848072912569?l=rowinggolfer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rowinggolfer.blogspot.com/feeds/399734848072912569/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8109854847430899154&amp;postID=399734848072912569' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/399734848072912569'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/399734848072912569'/><link rel='alternate' type='text/html' href='http://rowinggolfer.blogspot.com/2009/02/review-sansa-clip-oggmp3-player.html' title='Review - sansa clip ogg/mp3 player'/><author><name>Neil</name><uri>http://www.blogger.com/profile/06112117080373993301</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/-GEhvN_g7Kk4/TfnhG7DCMiI/AAAAAAAAAHo/HmAn1zC-xXM/s220/geek.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_wAfH8S6uz00/SZqlvR0etuI/AAAAAAAAADg/MKvsGEb6DgA/s72-c/SansaClipTilt.jpg' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8109854847430899154.post-2034729924474802980</id><published>2009-02-16T14:03:00.000Z</published><updated>2009-02-16T14:05:01.305Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='dell-mini ubuntu'/><title type='text'>dell mini ram trouble</title><content type='html'>Odd problem with my dell mini on Saturday. I needed to get a few packages up to ubuntu intrepid versions, and found that wasn't a trivial affair given the "lpia" archictecture that the pre-installed 'dellbuntu' insists upon.&lt;br /&gt;&lt;br /&gt;I was installing dependencies, but they were still appearing to be missing. Very odd, so I decide to install the vanilla 32 bit Ubuntu8.10.&lt;br /&gt;&lt;br /&gt;I partition the drive (ext2 with no swap) and stick in an 8.10 usb startup disk. Start the install and BOOM!! major problems at 27%. I get warnings that "source and destination files don't match".... "you probably have a dirty CD, or a damaged hard-drive".&lt;br /&gt;&lt;br /&gt;Bummer - it has to be the hard-drive right? We all know these solid state drives are friable?&lt;br /&gt;&lt;br /&gt;A quick google suggests several folks have had trouble with the dell mini drives, so I was 100% certain that was the problem.&lt;br /&gt;Anyway... long story short, it turns out it wasn't that at all.&lt;br /&gt;&lt;br /&gt;My RAM was hosed. memtest86 on the startup disk (which I tried on a whim whilst googling for SSD device checking software) found 40,000 errors at a very specific range of addresses.&lt;br /&gt;&lt;br /&gt;So I popped in a different ram block, and voila! All is well. Ubuntu 8.10 was running flawlessly 20 minutes later.&lt;br /&gt;&lt;br /&gt;On the off chance any ubuntu devs reading this.. it might be worth adding a line to the error dialog stating that the memory could be an issue as well as the more likely CD or hardrive cause.&lt;br /&gt;&lt;br /&gt;Even more importantly, THANKYOU for having that memtest86 on the install media by default.. you saved me from ringing dell support (a fate worse than death methinks?)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8109854847430899154-2034729924474802980?l=rowinggolfer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rowinggolfer.blogspot.com/feeds/2034729924474802980/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8109854847430899154&amp;postID=2034729924474802980' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/2034729924474802980'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/2034729924474802980'/><link rel='alternate' type='text/html' href='http://rowinggolfer.blogspot.com/2009/02/dell-mini-ram-trouble.html' title='dell mini ram trouble'/><author><name>Neil</name><uri>http://www.blogger.com/profile/06112117080373993301</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/-GEhvN_g7Kk4/TfnhG7DCMiI/AAAAAAAAAHo/HmAn1zC-xXM/s220/geek.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8109854847430899154.post-3021149430850231239</id><published>2009-02-04T13:28:00.000Z</published><updated>2009-02-04T15:51:50.769Z</updated><title type='text'>Using binary data in python</title><content type='html'>For those who don't know, I am writing a python gui-frontend to an existing mysql database.&lt;br /&gt;&lt;br /&gt;The original program that wrote out the data was written by an old-school C guy. Some of the data has been put into the tables in a "blob" format.  Example&lt;br /&gt;&lt;pre&gt;mysql&gt; describe esttable;&lt;br /&gt;+----------+-------------+------+-----+---------+-------+&lt;br /&gt;| Field    | Type        | Null | Key | Default | Extra |&lt;br /&gt;+----------+-------------+------+-----+---------+-------+&lt;br /&gt;| serialno | int(11)     | NO   | PRI | 0       |       | &lt;br /&gt;| data     | blob        | YES  |     | NULL    |       | &lt;br /&gt;+----------+-------------+------+-----+---------+-------+&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;so when I read this table with the MySQLdb module (a third party module for python) I get a string like this.&lt;br /&gt;&lt;pre&gt;import MySQLdb&lt;br /&gt;db=MySQLdb.connect(host="localhost",user="myUser",passwd="myPassword",db="myDatabase")&lt;br /&gt;Cursor=db.cursor()&lt;br /&gt;Cursor.execute('select data from esttable where serialno=31599')&lt;br /&gt;Cursor.fetchall()&lt;br /&gt;(('\x01\x00o\x00\n\x0f\x00\x00\x04\x00\xc9\x00\x00\x00\x00\x00\x01\x00&lt;br /&gt;\xe9\x03"\x0b\x00\x00\x02\x00\x87\x05@\x1f\x00\x00',),)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;You will note that this is packed with characters which need to be handled with care (understatement!)&lt;br /&gt;&lt;br /&gt;So how to make sense of it?&lt;br /&gt;One way is to use python's build in &lt;a href="http://docs.python.org/library/struct.html"&gt;Struct module&lt;/a&gt;, which allows conversion between python and C types of variable.&lt;br /&gt;&lt;br /&gt;after a bit of decoding.... I noticed the above is in chunks of 8 bytes, with /x00 at every 2,6,7 position. I also realise (by experiment) that the data contains 2 distinct unsigned doubles so the following code works for me.&lt;br /&gt;&lt;pre&gt;import struct&lt;br /&gt;def blobToList(blob):&lt;br /&gt;   pythonlist=[]&lt;br /&gt;   i=0&lt;br /&gt;   for i in range(0,len(blob),8):&lt;br /&gt;       number=struct.unpack_from('b',blob,i)[0]&lt;br /&gt;       item=struct.unpack_from('H',blob,i+2)[0]&lt;br /&gt;       cost=struct.unpack_from('H',blob,i+4)[0]&lt;br /&gt;       pythonlist.append("%s %s $%d.%02d"%(number,item,cost/100,cost%100)) &lt;br /&gt;   return pythonlist&lt;br /&gt;if __name__=="__main__":&lt;br /&gt;    testdata ='\x01\x00o\x00\n\x0f\x00\x00\x04\x00\xc9\x00\x00\x00\x00\x00'&lt;br /&gt;    testdata+='\x01\x00\xe9\x03"\x0b\x00\x00\x02\x00\x87\x05@\x1f\x00\x00'&lt;br /&gt;    print blobToList(testdata)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;which gives me the following output&lt;br /&gt;&lt;pre&gt;['1 111 $38.50', '4 201 $0.00', '1 1001 $28.50', '2 1415 $80.00']&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;and that makes more sense to me (just).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8109854847430899154-3021149430850231239?l=rowinggolfer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rowinggolfer.blogspot.com/feeds/3021149430850231239/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8109854847430899154&amp;postID=3021149430850231239' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/3021149430850231239'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/3021149430850231239'/><link rel='alternate' type='text/html' href='http://rowinggolfer.blogspot.com/2009/02/using-binary-data-in-python.html' title='Using binary data in python'/><author><name>Neil</name><uri>http://www.blogger.com/profile/06112117080373993301</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/-GEhvN_g7Kk4/TfnhG7DCMiI/AAAAAAAAAHo/HmAn1zC-xXM/s220/geek.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8109854847430899154.post-8238266114331308458</id><published>2009-01-16T20:45:00.000Z</published><updated>2009-01-16T20:52:53.145Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='random linux thought for the day'/><title type='text'>Wikipedia for young minds</title><content type='html'>Another random idea inspired by real life.&lt;br /&gt;&lt;br /&gt;Assuming there isn't (see picture)... wouldn't it be nice if there was a version of wikipedia aimed at kids under 12.&lt;br /&gt;Same as wikipedia (and linking to it), but less verbose, simplified language, and guaranteed free of adult material?&lt;br /&gt;&lt;br /&gt;Heck that would be a great resource for junior schools, teachers and parents alike.&lt;br /&gt;&lt;br /&gt;Possible Names - "WikiJunior", "Junior Wikipedia", "PaedoPedia" (ok... one of the 1st 2)&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_wAfH8S6uz00/SXDzQp_JyaI/AAAAAAAAADQ/RRp2xuV5470/s1600-h/wiki_junior.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 108px;" src="http://2.bp.blogspot.com/_wAfH8S6uz00/SXDzQp_JyaI/AAAAAAAAADQ/RRp2xuV5470/s400/wiki_junior.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5291997029634525602" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8109854847430899154-8238266114331308458?l=rowinggolfer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rowinggolfer.blogspot.com/feeds/8238266114331308458/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8109854847430899154&amp;postID=8238266114331308458' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/8238266114331308458'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/8238266114331308458'/><link rel='alternate' type='text/html' href='http://rowinggolfer.blogspot.com/2009/01/wikipedia-for-young-minds.html' title='Wikipedia for young minds'/><author><name>Neil</name><uri>http://www.blogger.com/profile/06112117080373993301</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/-GEhvN_g7Kk4/TfnhG7DCMiI/AAAAAAAAAHo/HmAn1zC-xXM/s220/geek.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_wAfH8S6uz00/SXDzQp_JyaI/AAAAAAAAADQ/RRp2xuV5470/s72-c/wiki_junior.png' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8109854847430899154.post-2732682810040169881</id><published>2009-01-12T13:07:00.000Z</published><updated>2009-01-12T13:29:24.051Z</updated><title type='text'>Dell Mini-9 update DISASTER!</title><content type='html'>This post is about the dell-mini-9.&lt;br /&gt;A netbook with pre-installed ubuntu 8.04. These machines use a separate repo for updates, (suffix http://dell-mini.archive.canonical,com) so would you expect the following to happen?&lt;br /&gt;&lt;br /&gt;After weeks with no new packages for the standard dell-mini ubuntu repos, last night saw me pulling down 170MB.&lt;br /&gt;(note - this is a vanilla ubuntu 8.04 dell-mini, first used in 'dec 08)&lt;br /&gt;however, these upgrades have left me with several annoying issues.&lt;br /&gt;&lt;br /&gt;1. an x-server update bust my uk keyboard layout. &lt;b&gt;#~{}]["£&lt;/b&gt; all moved around&lt;br /&gt;&lt;br /&gt;2. New Firefox and/or WebFav packages wiped all my browser history/usernames/passwords AND removed all my add-ons. Furthermore I got an annoying "Yahoo" home page, default search and a task bar (the bloody screen is small enough, thanks)&lt;br /&gt;&lt;b&gt;Read again - I lost my homepage, all addons, history and bookmarks&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;3. the upgrading of &lt;i&gt;lsb-base (3.2-4ubuntu1) to 3.2-4ubuntu1netbook1&lt;/i&gt; meant that the &lt;b&gt;mysql-server-5.0 wouldn't start&lt;/b&gt;, as I got an error about an unbound variable. Mysql is mission critical on this machine.&lt;br /&gt;&lt;br /&gt;Anyway, I have smart friends on irc (thanks jlindsay and Peter64) and I am now fixed up again.&lt;br /&gt;However, these machines are aimed at a broad spectrum of users who would be more inconvenienced than I.&lt;br /&gt;&lt;br /&gt;For the sake of the ubuntu and gnu/linux community... please hold these upgrades back for further testing before unleashing them on new linux users.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8109854847430899154-2732682810040169881?l=rowinggolfer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rowinggolfer.blogspot.com/feeds/2732682810040169881/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8109854847430899154&amp;postID=2732682810040169881' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/2732682810040169881'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/2732682810040169881'/><link rel='alternate' type='text/html' href='http://rowinggolfer.blogspot.com/2009/01/dell-mini-9-update-disaster.html' title='Dell Mini-9 update DISASTER!'/><author><name>Neil</name><uri>http://www.blogger.com/profile/06112117080373993301</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/-GEhvN_g7Kk4/TfnhG7DCMiI/AAAAAAAAAHo/HmAn1zC-xXM/s220/geek.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8109854847430899154.post-6322625899595050494</id><published>2009-01-11T22:51:00.000Z</published><updated>2009-01-11T23:03:41.758Z</updated><title type='text'>Richard Querin - I love you!</title><content type='html'>Thanks to the linuxplanet.org aggregation, I have become a huge fan of Richard Querin's Work.&lt;br /&gt;I am particulary grateful for his post about an easy way to &lt;a href="http://blog.rfquerin.org/2008/12/11/so-you-want-your-own-stinkin-font/"&gt;CREATE YOUR OWN FONT&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Anyway, my 10 year old daughter followed this advice, and I noticed today that she has not only made such a font, but has tweaked it with fontforge (an apt-get away for us debian derivatives) and is now using it as her default application/Desktop/Window-Title and Document Font.&lt;br /&gt;&lt;br /&gt;linux truly is flippin' awesome.&lt;br /&gt;&lt;br /&gt;here is her desktop... (click image for a larger view)&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_wAfH8S6uz00/SWp58Xd355I/AAAAAAAAACU/G6nEifA7WNQ/s1600-h/myDaughtersScreenshot.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="http://1.bp.blogspot.com/_wAfH8S6uz00/SWp58Xd355I/AAAAAAAAACU/G6nEifA7WNQ/s400/myDaughtersScreenshot.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5290174790298494866" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8109854847430899154-6322625899595050494?l=rowinggolfer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rowinggolfer.blogspot.com/feeds/6322625899595050494/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8109854847430899154&amp;postID=6322625899595050494' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/6322625899595050494'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/6322625899595050494'/><link rel='alternate' type='text/html' href='http://rowinggolfer.blogspot.com/2009/01/richard-querin-i-love-you.html' title='Richard Querin - I love you!'/><author><name>Neil</name><uri>http://www.blogger.com/profile/06112117080373993301</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/-GEhvN_g7Kk4/TfnhG7DCMiI/AAAAAAAAAHo/HmAn1zC-xXM/s220/geek.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_wAfH8S6uz00/SWp58Xd355I/AAAAAAAAACU/G6nEifA7WNQ/s72-c/myDaughtersScreenshot.png' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8109854847430899154.post-4268135649668346931</id><published>2009-01-08T22:59:00.000Z</published><updated>2009-01-12T13:42:01.865Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='python pyqt4'/><title type='text'>Implementing a Custom Widget using pyqt4.</title><content type='html'>Pat from the linux link tech show (and others) have told me to stop whinging, and solve my own IT worries. I won't go over these again here, but scroll down for the full story.&lt;br /&gt;So I dusted down all the programming manuals on the shelf and got to it, and I have to say, so far so good, I have spend many happy hours coding, and am REALLY enjoying the experience.&lt;br /&gt;&lt;br /&gt;The tools - python and the qt4 toolkit, mysql, mysqldb, qt-designer and SPE (a wonderful python IDE)&lt;br /&gt;&lt;br /&gt;Tomorrow, I have a meeting with a colleague, and I need to show him where I'm at. Thought I'd share here also. Here's a screenshot.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_wAfH8S6uz00/SWaIjg7M-bI/AAAAAAAAACM/S8JmLSNyUCY/s1600-h/Screenshot.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 198px;" src="http://3.bp.blogspot.com/_wAfH8S6uz00/SWaIjg7M-bI/AAAAAAAAACM/S8JmLSNyUCY/s320/Screenshot.png" alt="" id="BLOGGER_PHOTO_ID_5289064956108274098" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;A thing of beauty IMHO!&lt;br /&gt;&lt;br /&gt;Anyway, I was delighted how easy PyQt4 makes it to embed a custom widget. My little dental chart slotted into the tabPageWidget above is such a thing. The code is below for all to laugh at.&lt;br /&gt;Note - if you have python and pyqt4 installed, this script will run as a top-level window, something ALL qt widgets are capable of doing. Very cool.&lt;br /&gt;&lt;br /&gt;The chartWidget inherits from the QWidgetClass, but overwrites several methods, including the all-important paint method. So today I learned how to draw rectangles, rounded rectangles, lines and points again. QCanvas is like a big etch-a-sketch for nerds. Much Fun. &lt;br /&gt;&lt;br /&gt;&lt;b&gt;NOTE&lt;/b&gt; - this code borrows heavily from the "counters.py" example in chapter 11 of the pyqt4 book by Mark Summerfield.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;#!/usr/bin/env python&lt;br /&gt;from __future__ import division&lt;br /&gt;from PyQt4 import QtGui,QtCore&lt;br /&gt;&lt;br /&gt;class chartWidget(QtGui.QWidget):&lt;br /&gt;    '''a custom widget to show a standard UK dental chart - allows for user navigation with mouse and/or keyboard'''&lt;br /&gt;    def __init__(self, parent=None):&lt;br /&gt;        super(chartWidget,self).__init__(parent)&lt;br /&gt;        self.setSizePolicy(QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding,QtGui.QSizePolicy.Expanding))&lt;br /&gt;        self.grid = [[18,17,16,15,14,13,12,11,21,22,23,24,25,26,27,28],[48,47,46,45,44,43,42,41,31,32,33,34,35,36,37,38]]&lt;br /&gt;        self.selected = [0, 0]&lt;br /&gt;        self.setMinimumSize(self.minimumSizeHint())&lt;br /&gt;    def sizeHint(self):&lt;br /&gt;        return QtCore.QSize(600, 150)&lt;br /&gt;    def minimumSizeHint(self):&lt;br /&gt;        return QtCore.QSize(240, 80)&lt;br /&gt;    def mousePressEvent(self, event):&lt;br /&gt;        xOffset = self.width() / 16&lt;br /&gt;        yOffset = self.height() / 2&lt;br /&gt;        x= event.x()//xOffset&lt;br /&gt;        if event.y() &lt; yOffset:&lt;br /&gt;            y = 0&lt;br /&gt;        else:&lt;br /&gt;            y = 1&lt;br /&gt;        self.selected = [x, y]&lt;br /&gt;        self.update()&lt;br /&gt;&lt;br /&gt;    def keyPressEvent(self, event):&lt;br /&gt;        if event.key() == QtCore.Qt.Key_Left:&lt;br /&gt;            self.selected[0] = 15 if self.selected[0] == 0 else self.selected[0] - 1&lt;br /&gt;        elif event.key() == QtCore.Qt.Key_Right:&lt;br /&gt;            self.selected[0] = 0 if self.selected[0] == 15 else self.selected[0] + 1&lt;br /&gt;        elif event.key() == QtCore.Qt.Key_Up:&lt;br /&gt;            self.selected[1] = 1 if self.selected[1] == 0 else self.selected[1] - 1&lt;br /&gt;        elif event.key() == QtCore.Qt.Key_Down:&lt;br /&gt;            self.selected[1] = 0 if self.selected[1] == 1 else self.selected[1] + 1&lt;br /&gt;        self.update()&lt;br /&gt;        &lt;br /&gt;    def paintEvent(self,event=None):&lt;br /&gt;        painter = QtGui.QPainter(self)&lt;br /&gt;        painter.setRenderHint(QtGui.QPainter.Antialiasing, True)&lt;br /&gt;        midline=self.width()/100&lt;br /&gt;        midlineV=self.height()/20&lt;br /&gt;        xOffset = (self.width() - midline) / 16  #cell width&lt;br /&gt;        yOffset = (self.height() - midlineV) / 2 #cell height&lt;br /&gt;        painter.setPen(QtCore.Qt.red)&lt;br /&gt;        painter.drawLine(0,self.height()/2,self.width(),self.height()/2)&lt;br /&gt;        painter.drawLine(self.width()/2,0,self.width()/2,self.height())&lt;br /&gt;        &lt;br /&gt;        for x in range(16):&lt;br /&gt;            if x&gt;7: &lt;br /&gt;                midx=midline&lt;br /&gt;            else:&lt;br /&gt;                midx=0&lt;br /&gt;            for y in range(2):&lt;br /&gt;                cell = self.grid[y][x]&lt;br /&gt;                rect = QtCore.QRectF(x * xOffset + midx, y * yOffset+y*midlineV,xOffset, yOffset).adjusted(0.5, 0.5, -0.5, -0.5)&lt;br /&gt;                backTooth=False&lt;br /&gt;                color = QtGui.QColor("#ddddff")&lt;br /&gt;                if str(cell)[1] in ("8","7","6","5","4"): #molars&lt;br /&gt;                        backTooth=True&lt;br /&gt;                painter.setPen(QtGui.QColor("black"))&lt;br /&gt;                painter.setBrush(color)&lt;br /&gt;                if backTooth:&lt;br /&gt;                    outerRect=rect.adjusted(0,2,0,-2)&lt;br /&gt;                    irw=outerRect.width()/4 #inner rectangle width&lt;br /&gt;                    irh=outerRect.height()/4 #inner rectangle height&lt;br /&gt;                    innerRect=rect.adjusted(irw,irh,-irw,-irh)&lt;br /&gt;                    painter.drawRect(outerRect)&lt;br /&gt;                    painter.drawRect(innerRect)&lt;br /&gt;                    painter.drawLine(outerRect.topLeft(),innerRect.topLeft())&lt;br /&gt;                    painter.drawLine(outerRect.topRight(),innerRect.topRight())&lt;br /&gt;                    painter.drawLine(outerRect.bottomLeft(),innerRect.bottomLeft())&lt;br /&gt;                    painter.drawLine(outerRect.bottomRight(),innerRect.bottomRight())&lt;br /&gt;                else:&lt;br /&gt;                    outerRect=rect.adjusted(0,2,0,-2)&lt;br /&gt;                    rw=outerRect.width()/3&lt;br /&gt;                    rh=outerRect.height()/2.1&lt;br /&gt;                    innerRect=rect.adjusted(rw,rh,-rw,-rh)&lt;br /&gt;                    painter.drawRect(outerRect)&lt;br /&gt;                    painter.drawRect(innerRect)&lt;br /&gt;                    painter.drawLine(outerRect.topLeft(),innerRect.topLeft())&lt;br /&gt;                    painter.drawLine(outerRect.topRight(),innerRect.topRight())&lt;br /&gt;                    painter.drawLine(outerRect.bottomLeft(),innerRect.bottomLeft())&lt;br /&gt;                    painter.drawLine(outerRect.bottomRight(),innerRect.bottomRight())&lt;br /&gt;                &lt;br /&gt;                #draw a rectangle around the selected tooth, but don't overwrite the centre&lt;br /&gt;                if [x, y] == self.selected:&lt;br /&gt;                    painter.setPen(QtGui.QPen(QtCore.Qt.blue, 3))&lt;br /&gt;                    painter.setBrush(QtCore.Qt.transparent)&lt;br /&gt;                    painter.drawRect(rect.adjusted(1,1,-1,-1))&lt;br /&gt;            &lt;br /&gt;if __name__ == "__main__":&lt;br /&gt;    import sys&lt;br /&gt;    app = QtGui.QApplication(sys.argv)&lt;br /&gt;    form = chartWidget()&lt;br /&gt;    form.show()&lt;br /&gt;    sys.exit(app.exec_())&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8109854847430899154-4268135649668346931?l=rowinggolfer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rowinggolfer.blogspot.com/feeds/4268135649668346931/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8109854847430899154&amp;postID=4268135649668346931' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/4268135649668346931'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/4268135649668346931'/><link rel='alternate' type='text/html' href='http://rowinggolfer.blogspot.com/2009/01/implimenting-custom-widget-using-pyqt4.html' title='Implementing a Custom Widget using pyqt4.'/><author><name>Neil</name><uri>http://www.blogger.com/profile/06112117080373993301</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/-GEhvN_g7Kk4/TfnhG7DCMiI/AAAAAAAAAHo/HmAn1zC-xXM/s220/geek.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_wAfH8S6uz00/SWaIjg7M-bI/AAAAAAAAACM/S8JmLSNyUCY/s72-c/Screenshot.png' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8109854847430899154.post-6793981683198308891</id><published>2008-12-09T22:35:00.000Z</published><updated>2008-12-09T22:39:19.179Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='dell mini mythtv 3mmpro110'/><title type='text'>pocket projector / mythtv / dell mini combo</title><content type='html'>blimey - home cinema in a bag.&lt;br /&gt;the projector is a 3m MPro 110, and is about the size of a pack of cigarettes.&lt;br /&gt;watchable as 50inch screen&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_wAfH8S6uz00/ST7yucM1KWI/AAAAAAAAAB8/m7tqt-olrXA/s1600-h/3m_myth.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 150px; height: 200px;" src="http://3.bp.blogspot.com/_wAfH8S6uz00/ST7yucM1KWI/AAAAAAAAAB8/m7tqt-olrXA/s200/3m_myth.jpg" alt="" id="BLOGGER_PHOTO_ID_5277922692982712674" border="0" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8109854847430899154-6793981683198308891?l=rowinggolfer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rowinggolfer.blogspot.com/feeds/6793981683198308891/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8109854847430899154&amp;postID=6793981683198308891' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/6793981683198308891'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/6793981683198308891'/><link rel='alternate' type='text/html' href='http://rowinggolfer.blogspot.com/2008/12/pocket-projector-mythtv-dell-mini-combo.html' title='pocket projector / mythtv / dell mini combo'/><author><name>Neil</name><uri>http://www.blogger.com/profile/06112117080373993301</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/-GEhvN_g7Kk4/TfnhG7DCMiI/AAAAAAAAAHo/HmAn1zC-xXM/s220/geek.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_wAfH8S6uz00/ST7yucM1KWI/AAAAAAAAAB8/m7tqt-olrXA/s72-c/3m_myth.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8109854847430899154.post-3776675482659746522</id><published>2008-12-09T20:51:00.000Z</published><updated>2008-12-09T20:54:40.900Z</updated><title type='text'>Rowinggolfer - the true linux outlaw</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_wAfH8S6uz00/ST7axx2LZuI/AAAAAAAAAB0/pHuf5_fEzPI/s1600-h/Screenshot.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: left; cursor: pointer; width: 200px; height: 106px;" src="http://3.bp.blogspot.com/_wAfH8S6uz00/ST7axx2LZuI/AAAAAAAAAB0/pHuf5_fEzPI/s200/Screenshot.png" alt="" id="BLOGGER_PHOTO_ID_5277896362053822178" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Fab and Dan... move over.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8109854847430899154-3776675482659746522?l=rowinggolfer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rowinggolfer.blogspot.com/feeds/3776675482659746522/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8109854847430899154&amp;postID=3776675482659746522' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/3776675482659746522'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/3776675482659746522'/><link rel='alternate' type='text/html' href='http://rowinggolfer.blogspot.com/2008/12/rowinggolfer-true-linux-outlaw.html' title='Rowinggolfer - the true linux outlaw'/><author><name>Neil</name><uri>http://www.blogger.com/profile/06112117080373993301</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/-GEhvN_g7Kk4/TfnhG7DCMiI/AAAAAAAAAHo/HmAn1zC-xXM/s220/geek.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_wAfH8S6uz00/ST7axx2LZuI/AAAAAAAAAB0/pHuf5_fEzPI/s72-c/Screenshot.png' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8109854847430899154.post-2330888124050234026</id><published>2008-12-08T21:11:00.001Z</published><updated>2008-12-08T22:17:16.014Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>Packages and the PythonPath.</title><content type='html'>Here's another "blog to self" to archive stuff that I keep forgetting.&lt;br /&gt;&lt;br /&gt;The pythonpath variable is a system variable which tells the python interpreter where to look for python modules when an import statement is called. The current shell's pythonpath is a list and can be found by&lt;br /&gt;&lt;span style="font-style:italic;"&gt;&gt;&gt;&gt;import sys&lt;br /&gt;&gt;&gt;&gt;sys.path&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;on my system this returns&lt;br /&gt;&lt;span style="font-style:bold;"&gt;[' ','/home/neil/pycode', '/usr/lib/python2.5', '/usr/lib/python2.5/plat-linux2', etc....&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;the first item on this list is ' ', which means that the current shell's directory is checked, and '/usr/lib/python2.5' is no surprise. Also on the path (not shown for brevity) are some 3rd party python modules I've installed such as wxpython, PIL, PyQt4 etc....&lt;br /&gt;&lt;br /&gt;but hang on... what is that '/home/neil/pycode'?&lt;br /&gt;&lt;br /&gt;That is there (and unlike other methods survives a reboot) thanks to this line in my .profile file&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;export PYTHONPATH=/home/neil/pycode&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;pycode is a directory where I put my own python modules.&lt;br /&gt;Any modules in this directory can be imported by others.&lt;br /&gt;However, I need to be careful of contaminating the python namespace.&lt;br /&gt;Example - If I save a module I've named "sys.py" in there this will be found BEFORE the sys module native to python (because the pythonpath is checked in order)&lt;br /&gt;&lt;br /&gt;so.. here's one way around that problem, and A neat way of organising your modules to boot.&lt;br /&gt;Python "Packages".&lt;br /&gt;Packages are just folders which contain other modules AND a file named __init__.py (this file can be and usually is empty)&lt;br /&gt;&lt;br /&gt;Example I have a package called "norman" which is simply a folder of modules (/home/neil/pycode/norman) and thanks to the __init__.py trick, I can do import statements like...&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;&gt;&gt;&gt;from norman import mymodule&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;if I am still stupid enough to want to write a module called sys.py, and put it in the norman folder... it won't get imported by&lt;br /&gt;&lt;span style="font-style:italic;"&gt;&gt;&gt;&gt;import sys&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;but would by&lt;br /&gt;&lt;span style="font-style:italic;"&gt;&gt;&gt;&gt;from norman import sys&lt;/span&gt;&lt;br /&gt;or&lt;br /&gt;&lt;span style="font-style:italic;"&gt;&gt;&gt;&gt;from norman import *&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;but we don't do that, do we??&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8109854847430899154-2330888124050234026?l=rowinggolfer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rowinggolfer.blogspot.com/feeds/2330888124050234026/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8109854847430899154&amp;postID=2330888124050234026' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/2330888124050234026'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/2330888124050234026'/><link rel='alternate' type='text/html' href='http://rowinggolfer.blogspot.com/2008/12/packages-and-pythonpath.html' title='Packages and the PythonPath.'/><author><name>Neil</name><uri>http://www.blogger.com/profile/06112117080373993301</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/-GEhvN_g7Kk4/TfnhG7DCMiI/AAAAAAAAAHo/HmAn1zC-xXM/s220/geek.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8109854847430899154.post-8485899141674379798</id><published>2008-12-04T00:04:00.000Z</published><updated>2008-12-04T00:14:21.693Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='ebay'/><title type='text'>Ebay is CRAP!</title><content type='html'>It's been a while for me, but I ventured onto ebay today to search for a 2nd hand n800 or n810.&lt;br /&gt;&lt;br /&gt;I used to love ebay, but I don't think I'll be heading back. &lt;br /&gt;Nothing but "buy it now" offers for peripherals, or doubtful looking re-sellers.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8109854847430899154-8485899141674379798?l=rowinggolfer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rowinggolfer.blogspot.com/feeds/8485899141674379798/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8109854847430899154&amp;postID=8485899141674379798' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/8485899141674379798'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/8485899141674379798'/><link rel='alternate' type='text/html' href='http://rowinggolfer.blogspot.com/2008/12/ebay-is-crap.html' title='Ebay is CRAP!'/><author><name>Neil</name><uri>http://www.blogger.com/profile/06112117080373993301</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/-GEhvN_g7Kk4/TfnhG7DCMiI/AAAAAAAAAHo/HmAn1zC-xXM/s220/geek.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8109854847430899154.post-7223173934966241075</id><published>2008-11-30T15:42:00.000Z</published><updated>2008-11-30T15:50:23.191Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='ubuntu 9.10'/><title type='text'>Prior Art</title><content type='html'>One thing the 'blogosphere' provides is a place for ideas to be voiced early.&lt;br /&gt;&lt;br /&gt;In doing so, presumably this establishes 'prior art' when the idea is widely adopted.&lt;br /&gt;&lt;br /&gt;In the spirit of this... I make the following prediction.&lt;br /&gt;&lt;span class="entry-content"&gt;Ubuntu 9.10 will be "Killer Kangaroo", "Kinky Koala", "Kissable Kitten" or "Kinetic Kestrel" (or some combination thereof).&lt;br /&gt;&lt;br /&gt;Personally I like Kinetic Kestrel the best - "I'm running Kenetic" has a certain ring to it.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8109854847430899154-7223173934966241075?l=rowinggolfer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rowinggolfer.blogspot.com/feeds/7223173934966241075/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8109854847430899154&amp;postID=7223173934966241075' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/7223173934966241075'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/7223173934966241075'/><link rel='alternate' type='text/html' href='http://rowinggolfer.blogspot.com/2008/11/prior-art.html' title='Prior Art'/><author><name>Neil</name><uri>http://www.blogger.com/profile/06112117080373993301</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/-GEhvN_g7Kk4/TfnhG7DCMiI/AAAAAAAAAHo/HmAn1zC-xXM/s220/geek.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8109854847430899154.post-1897398043757152683</id><published>2008-11-28T21:31:00.000Z</published><updated>2008-11-28T21:39:05.069Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='GPL law freedom'/><title type='text'>Bring on the IT lawyers</title><content type='html'>I have just written to &lt;a href="http://www.moorcrofts.com"&gt;www.moorcrofts.com&lt;/a&gt; a law firm specialising in IT.&lt;br /&gt;&lt;br /&gt;Hello,&lt;br /&gt;&lt;br /&gt;My name is &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_0"&gt;xxxx&lt;/span&gt; &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_1"&gt;xxxxx&lt;/span&gt;, and I am a dentist. My practice is in &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_2"&gt;xxxxxxxx&lt;/span&gt;, www.xxxxxxxx.com.&lt;br /&gt;I am also a hobby programmer and &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_3"&gt;linux&lt;/span&gt; advocate.&lt;br /&gt;&lt;br /&gt;I write to you because I am in a hole with my dental software provider. After 12 years with them, we have just taken  delivery of a £13,000+ 'upgrade'.&lt;br /&gt;It is a disaster.&lt;br /&gt;&lt;br /&gt;At this early stage, I have written to the business owner expressing my concerns, and asking to meet with him. They are based in &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_4"&gt;xxxx&lt;/span&gt;-&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_5"&gt;xxxxx&lt;/span&gt;.&lt;br /&gt;I suspect that I will be breaking &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_6"&gt;allegiance&lt;/span&gt; with this company in the short to medium term, and would value the advice of a lawyer who is familiar with software licensing. Your firm was mentioned to me by a fellow member of the open rights group.&lt;br /&gt;&lt;br /&gt;My ideal outcome would be to get this company to agree to a license which opens up the software to me so that I can help them improve the software, and in doing so, secure my data.&lt;br /&gt;I can understand why they will probably be wary of such a license. However, I would be willing to consider clauses which commit me to continue with them for a period of say 5 years (and continue paying maintenance/support fees for that time - some £2500 per &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_7"&gt;annum&lt;/span&gt;)&lt;br /&gt;&lt;br /&gt;Obviously, what I would get from this is future freedom, and a system which is not a 'brick' as is currently the case.&lt;br /&gt;&lt;br /&gt;If you feel you can help PLEASE contact me.&lt;br /&gt;&lt;br /&gt;Kind regards&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8109854847430899154-1897398043757152683?l=rowinggolfer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rowinggolfer.blogspot.com/feeds/1897398043757152683/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8109854847430899154&amp;postID=1897398043757152683' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/1897398043757152683'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/1897398043757152683'/><link rel='alternate' type='text/html' href='http://rowinggolfer.blogspot.com/2008/11/bring-on-it-lawyers.html' title='Bring on the IT lawyers'/><author><name>Neil</name><uri>http://www.blogger.com/profile/06112117080373993301</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/-GEhvN_g7Kk4/TfnhG7DCMiI/AAAAAAAAAHo/HmAn1zC-xXM/s220/geek.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8109854847430899154.post-4500170584202899962</id><published>2008-11-28T16:20:00.000Z</published><updated>2008-11-28T16:29:38.424Z</updated><title type='text'>Database Security.</title><content type='html'>My database provider has asked me to send them a backup drive by post.&lt;br /&gt;&lt;br /&gt;I'm not going to comply. I've sighted &lt;a href="http://www.openrightsgroup.org/newsblog/2008/11/catalogue-of-nhs-data-losses/"&gt; this &lt;/a&gt; as my reason.&lt;br /&gt;&lt;br /&gt;I accept that they need to check the integrity of the data. However, I feel that a request such as this should be in writing so as to create a paper chain showing that a disk in the post was&lt;br /&gt;&lt;ol&gt;&lt;li&gt;absolutely necessary given the risk to my business of the possible bad publicity if it goes astray&lt;/li&gt;&lt;li&gt;done with adequate encryption&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;These issues are on-going.&lt;br /&gt;I need to find myself a good IT aware lawyer, as soon as possible, to help me get these guys on the right track.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8109854847430899154-4500170584202899962?l=rowinggolfer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rowinggolfer.blogspot.com/feeds/4500170584202899962/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8109854847430899154&amp;postID=4500170584202899962' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/4500170584202899962'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/4500170584202899962'/><link rel='alternate' type='text/html' href='http://rowinggolfer.blogspot.com/2008/11/database-security.html' title='Database Security.'/><author><name>Neil</name><uri>http://www.blogger.com/profile/06112117080373993301</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/-GEhvN_g7Kk4/TfnhG7DCMiI/AAAAAAAAAHo/HmAn1zC-xXM/s220/geek.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8109854847430899154.post-6879202452135337127</id><published>2008-11-27T11:09:00.000Z</published><updated>2008-11-27T11:24:20.250Z</updated><title type='text'>Asking the right question about software licensing.</title><content type='html'>I have mentioned here before how dissatisfied I am with the software I use the most at work.&lt;br /&gt;I guess lots of people can understand that feeling.&lt;br /&gt;&lt;br /&gt;We are having to change the way we work to fit around this software. That is NOT acceptable to me.&lt;br /&gt;Again.. I hear that a lot, nothing unusual there.&lt;br /&gt;&lt;br /&gt;However, my situation is perhaps unusual in that I personally made the decision to purchase this software and paid for it myself. (We are talking several thousand pounds).&lt;br /&gt;&lt;br /&gt;Also unusual, is that it would be trivial for me to improve the software myself if I had the source code. In fact, I have already written several plug-ins to give me the functionality I desperately need to keep my business running smoothly (functionality destroyed by the recent 'upgrade'). In doing so, I may already have broken my side of the 'license' (not that I've seen one.)&lt;br /&gt;&lt;br /&gt;This software is central to my livelyhood.My 'support' contract is due for renewal on 22nd March 2009. I need to clarify my position before then.&lt;br /&gt;&lt;br /&gt;Ideally, I want to continue with this software, albeit heavily modified. My staff are trained to use it, and I have 12 years of invaluable data which no other software could lever correctly.&lt;br /&gt;&lt;br /&gt;I am writing to the company expressing my dissatisfaction, but after listening to the freedom law centre podcast this morning... I think I need to accept that what I need to do is re-write my contract with this company. I need them to agree to an open-source license of some description.&lt;br /&gt;&lt;br /&gt;I would love to hear from anyone who has been in a similar situation. &lt;br /&gt;&lt;br /&gt;Sorry for the verbosity of this posting... my thoughts are unclear due to 2 weeks with disturbed sleep. This issue is one I need to get 'closure' on.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8109854847430899154-6879202452135337127?l=rowinggolfer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rowinggolfer.blogspot.com/feeds/6879202452135337127/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8109854847430899154&amp;postID=6879202452135337127' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/6879202452135337127'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/6879202452135337127'/><link rel='alternate' type='text/html' href='http://rowinggolfer.blogspot.com/2008/11/asking-right-question-about-software.html' title='Asking the right question about software licensing.'/><author><name>Neil</name><uri>http://www.blogger.com/profile/06112117080373993301</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/-GEhvN_g7Kk4/TfnhG7DCMiI/AAAAAAAAAHo/HmAn1zC-xXM/s220/geek.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8109854847430899154.post-3939148557205098873</id><published>2008-11-24T20:11:00.000Z</published><updated>2008-11-24T21:06:04.187Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='Peter64'/><title type='text'>Far away friends.</title><content type='html'>I'll never need to ask Peter64 what time it is with him again.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_wAfH8S6uz00/SSsXIit2LJI/AAAAAAAAABs/UZSiY6hBNjA/s1600-h/Screenshot.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 175px; height: 320px;" src="http://2.bp.blogspot.com/_wAfH8S6uz00/SSsXIit2LJI/AAAAAAAAABs/UZSiY6hBNjA/s320/Screenshot.png" alt="" id="BLOGGER_PHOTO_ID_5272333224292789394" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Now - how to get 'Peter64 timezone' to the repositories?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8109854847430899154-3939148557205098873?l=rowinggolfer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rowinggolfer.blogspot.com/feeds/3939148557205098873/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8109854847430899154&amp;postID=3939148557205098873' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/3939148557205098873'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/3939148557205098873'/><link rel='alternate' type='text/html' href='http://rowinggolfer.blogspot.com/2008/11/far-away-friends.html' title='Far away friends.'/><author><name>Neil</name><uri>http://www.blogger.com/profile/06112117080373993301</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/-GEhvN_g7Kk4/TfnhG7DCMiI/AAAAAAAAAHo/HmAn1zC-xXM/s220/geek.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_wAfH8S6uz00/SSsXIit2LJI/AAAAAAAAABs/UZSiY6hBNjA/s72-c/Screenshot.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8109854847430899154.post-6413363659510914646</id><published>2008-11-22T07:57:00.000Z</published><updated>2008-11-22T08:03:48.731Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>the ipython shell</title><content type='html'>I thought ipython == iron python.&lt;br /&gt;&lt;br /&gt;what a pillock I am.&lt;br /&gt;ipython is going to change my life.&lt;br /&gt;&lt;br /&gt;thanks to the guys on irc.freenode.net #lottalinuxlinks for pointing out my stupidity, and for not laughing too much.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8109854847430899154-6413363659510914646?l=rowinggolfer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rowinggolfer.blogspot.com/feeds/6413363659510914646/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8109854847430899154&amp;postID=6413363659510914646' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/6413363659510914646'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/6413363659510914646'/><link rel='alternate' type='text/html' href='http://rowinggolfer.blogspot.com/2008/11/ipython-shell.html' title='the ipython shell'/><author><name>Neil</name><uri>http://www.blogger.com/profile/06112117080373993301</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/-GEhvN_g7Kk4/TfnhG7DCMiI/AAAAAAAAAHo/HmAn1zC-xXM/s220/geek.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8109854847430899154.post-4805060277995561757</id><published>2008-11-18T23:38:00.000Z</published><updated>2008-11-22T07:57:15.082Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='MySQL Python'/><title type='text'>MySQL - exploring a database with python and MySQLdb</title><content type='html'>Here's a script  wrote to explore a MySQL database, and report information on all the tables therein.&lt;br /&gt;note - you need python (surely everyone has the python?)&lt;br /&gt;and MySQLdb - which on ubuntu is simply ~apt-get install python-mysqldb&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;#! /usr/bin/env python&lt;br /&gt;import MySQLdb&lt;br /&gt;#change the following line as neccesary,&lt;br /&gt;db = MySQLdb.connect(host="localhost",user="YOUR_USER",&lt;br /&gt;                   passwd="YOUR_PASSWORD",db="YOUR_DATABASE")&lt;br /&gt;cursor = db.cursor()&lt;br /&gt;cursor.execute("SHOW TABLES")&lt;br /&gt;result=cursor.fetchall()&lt;br /&gt;for record in result:&lt;br /&gt;    print "TABLE '%s'"%record[0]&lt;br /&gt;    cursor.execute("DESCRIBE %s"%record[0])&lt;br /&gt;    descriptions = cursor.fetchall()&lt;br /&gt;    for description in descriptions:&lt;br /&gt;        for field in description:&lt;br /&gt;            print field,"\t",&lt;br /&gt;        print&lt;br /&gt;    print "_"*50&lt;br /&gt;cursor.close()&lt;br /&gt;db.close()&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8109854847430899154-4805060277995561757?l=rowinggolfer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rowinggolfer.blogspot.com/feeds/4805060277995561757/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8109854847430899154&amp;postID=4805060277995561757' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/4805060277995561757'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/4805060277995561757'/><link rel='alternate' type='text/html' href='http://rowinggolfer.blogspot.com/2008/11/mysql-exploring-database-with-python.html' title='MySQL - exploring a database with python and MySQLdb'/><author><name>Neil</name><uri>http://www.blogger.com/profile/06112117080373993301</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/-GEhvN_g7Kk4/TfnhG7DCMiI/AAAAAAAAAHo/HmAn1zC-xXM/s220/geek.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8109854847430899154.post-7680642607849725261</id><published>2008-11-14T13:57:00.000Z</published><updated>2008-11-14T14:26:19.053Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='hotmail microsoft'/><title type='text'>Goodbye Hotmail</title><content type='html'>I got myself a hotmail account on the 18th September 2001. &lt;br /&gt;&lt;br /&gt;Yesterday I deleted it for 2 reasons.&lt;br /&gt;&lt;br /&gt;Firstly, I haven't used it to send mail for over 2 years, because M$ append ad links, and they look like I am recommended said links.&lt;br /&gt;&lt;br /&gt;Secondly, the thunderbird plugins which enable webmail/hotmail have (for me) become erratic of late. &lt;br /&gt;&lt;br /&gt;So.. good riddance hotmail.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8109854847430899154-7680642607849725261?l=rowinggolfer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rowinggolfer.blogspot.com/feeds/7680642607849725261/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8109854847430899154&amp;postID=7680642607849725261' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/7680642607849725261'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/7680642607849725261'/><link rel='alternate' type='text/html' href='http://rowinggolfer.blogspot.com/2008/11/goodbye-hotmail.html' title='Goodbye Hotmail'/><author><name>Neil</name><uri>http://www.blogger.com/profile/06112117080373993301</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/-GEhvN_g7Kk4/TfnhG7DCMiI/AAAAAAAAAHo/HmAn1zC-xXM/s220/geek.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8109854847430899154.post-2615648520725114906</id><published>2008-11-14T00:22:00.000Z</published><updated>2008-11-14T00:34:29.355Z</updated><title type='text'>Virtual Jam Sessions.</title><content type='html'>I had an idea earlier... and put it to some musicians out in IRC land.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;rowinggolfer&lt;/b&gt;.. imagine a world where musicians can simply join into an online jam session.&lt;br /&gt;various categories of music.&lt;br /&gt;&lt;b&gt;kajarii&lt;/b&gt; rowinggolfer:  that'd actually be pretty cool.&lt;br /&gt;&lt;b&gt;rowinggolfer&lt;/b&gt; You are the man to set up this audio server. 'JamServer' ?&lt;br /&gt;&lt;b&gt;rowinggolfer&lt;/b&gt; Kajarii: I had the idea earlier when listening to guitarman4's music&lt;br /&gt;&lt;b&gt;kajarii&lt;/b&gt; Nice.&lt;br /&gt;&lt;b&gt;rowinggolfer&lt;/b&gt; I believe there is a business here, so I am thinking some more over this idea.&lt;br /&gt;&lt;b&gt;guitarman4&lt;/b&gt; rowinggolfer - there is a tool that allows for collaboration... open source, they beggin for someone to port linux, so far only mac and linux clients &lt;a href="http://www.koblo.com/"&gt; http://www.koblo.com &lt;/a&gt;&lt;br /&gt;* rowinggolfer checks out koblo.com&lt;br /&gt;&lt;b&gt;rowinggolfer&lt;/b&gt; guitarman4: I am thinking... irc type jam server... anyone can start a jam... and the initiator retains "op status", so that if a clueless player joins in... he/she can boot 'em off. then maybe some paid services? where you buy a room, but can charge people to listen?&lt;br /&gt;something like that... dunno&lt;br /&gt;&lt;b&gt;kajarii&lt;/b&gt;&gt; yeah, that's a better idea Especially since irc is low bandwidth so you have more room for music.&lt;br /&gt;&lt;b&gt;rowinggolfer&lt;/b&gt; It would be cool to lay down a beat then wait for folks to join in.&lt;br /&gt;&lt;b&gt;kajarii&lt;/b&gt; How you'd do that in real time with low latency would be an odd thing though.&lt;br /&gt;even sip is very latent.&lt;br /&gt;&lt;b&gt;rowinggolfer&lt;/b&gt; Kajarii: good point. UDP?&lt;br /&gt;&lt;b&gt;kajarii&lt;/b&gt; yeah, SIP uses UDP.&lt;br /&gt;&lt;b&gt;rowinggolfer&lt;/b&gt; lots of dropped packets... but real time.&lt;br /&gt;&lt;b&gt;guitarman4&lt;/b&gt; interstin...&lt;br /&gt;&lt;b&gt;kajarii&lt;/b&gt; I wonder if we ran a pulseaudio server on the irc machine which could then do the mixing and send it out to the other machines.&lt;br /&gt;&lt;b&gt;guitarman4&lt;/b&gt; ooooooo.&lt;br /&gt;&lt;b&gt;rowinggolfer&lt;/b&gt; Kajarii: I knew you were the man to speak to.&lt;br /&gt;&lt;b&gt;guitarman4&lt;/b&gt; i like that.  u know its worth trying out - worst case scenario is it doesnt fly.. wouldnt we need some way of syncing stuff...&lt;br /&gt;i wonder if midi makes more sense.&lt;br /&gt;&lt;b&gt;kajarii&lt;/b&gt; yeah, but pulseaudio should take care of that. or jack.&lt;br /&gt;&lt;b&gt;guitarman4&lt;/b&gt; really? k&lt;br /&gt;&lt;b&gt;kajarii&lt;/b&gt; jack is designed for low latency pro audio work.&lt;br /&gt;&lt;b&gt;guitarman4&lt;/b&gt; yeah.  so how would we connect to the jack server remotely&lt;br /&gt;&lt;b&gt;kajarii&lt;/b&gt; I wonder if we had everybody run a jack instance on their machine then hook them all together somehow. I'm not sure.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8109854847430899154-2615648520725114906?l=rowinggolfer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rowinggolfer.blogspot.com/feeds/2615648520725114906/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8109854847430899154&amp;postID=2615648520725114906' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/2615648520725114906'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/2615648520725114906'/><link rel='alternate' type='text/html' href='http://rowinggolfer.blogspot.com/2008/11/virtual-jam-sessions.html' title='Virtual Jam Sessions.'/><author><name>Neil</name><uri>http://www.blogger.com/profile/06112117080373993301</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/-GEhvN_g7Kk4/TfnhG7DCMiI/AAAAAAAAAHo/HmAn1zC-xXM/s220/geek.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8109854847430899154.post-2323916663395083782</id><published>2008-11-07T13:56:00.000Z</published><updated>2008-11-12T12:09:40.473Z</updated><title type='text'>Digital Dental Records</title><content type='html'>Last week I was a free software/open standards advocate.&lt;br /&gt;Today, due to my work IT upgrade this week I am a free software/open standards fanatic.&lt;br /&gt;&lt;br /&gt;I am a dentist BTW, and we have upgraded our old clinical database to a new version.&lt;br /&gt;&lt;br /&gt;This upgrade is to another proprietary, closed source "solution". &lt;br /&gt;That's bad for me and fellow dental practice owners who want high quality, bug free, modifiable, secure software.&lt;br /&gt;&lt;br /&gt;However, I realised something that affects a much wider audience... patients.&lt;br /&gt;&lt;br /&gt;Dental Records.&lt;br /&gt;We need a minimum standard for a digital dental record that any dental practice in the UK with a clinical database must be able to export to ooxml for dental records if you like.&lt;br /&gt;Note - this is not for my benefit, but for my patients past, current and future they have a right to their data... and it must be in an import/exportable form IMHO.&lt;br /&gt;&lt;br /&gt;moving to another practice/country?&lt;br /&gt;want to build a case against me for poor treatment?&lt;br /&gt;want to find out which anaesthetic you had a bad reaction to in 1998?&lt;br /&gt;Need to see your x-ray or intra-oral image data?&lt;br /&gt;&lt;br /&gt;no problem. (or at least.. it shouldn't be.. under present legislation you may get a crappy print out if you're lucky)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8109854847430899154-2323916663395083782?l=rowinggolfer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rowinggolfer.blogspot.com/feeds/2323916663395083782/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8109854847430899154&amp;postID=2323916663395083782' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/2323916663395083782'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/2323916663395083782'/><link rel='alternate' type='text/html' href='http://rowinggolfer.blogspot.com/2008/11/last-week-i-was-free-softwareopen.html' title='Digital Dental Records'/><author><name>Neil</name><uri>http://www.blogger.com/profile/06112117080373993301</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/-GEhvN_g7Kk4/TfnhG7DCMiI/AAAAAAAAAHo/HmAn1zC-xXM/s220/geek.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8109854847430899154.post-4357608339496720406</id><published>2008-11-04T11:59:00.000Z</published><updated>2008-11-04T13:28:22.873Z</updated><title type='text'>Intrepid - cruft remover</title><content type='html'>&lt;a style="" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_wAfH8S6uz00/SRA6Snd6jAI/AAAAAAAAABc/YpPmghKM9Bg/s1600-h/Screenshot.png"&gt;&lt;img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer; width: 261px; height: 320px;" src="http://3.bp.blogspot.com/_wAfH8S6uz00/SRA6Snd6jAI/AAAAAAAAABc/YpPmghKM9Bg/s320/Screenshot.png" alt="" id="BLOGGER_PHOTO_ID_5264772055902620674" border="0" /&gt;&lt;/a&gt;UPDATE - THIS PACKAGE HAS BEEN REMOVED FROM INTREPID&lt;br /&gt;IT WAS IN THE BETA VERSION ONLY.&lt;br /&gt;&lt;br /&gt;I found the "cruft remover app" today which is new to Ubuntu with the intrepid release.&lt;br /&gt;&lt;br /&gt;A neat app if used properly, but will need to gather more information about the packages on a system and the frequency of use etc.. to give the user more info before prompting for removal of a package.&lt;br /&gt;&lt;br /&gt;I think the default for most check boxes until that point is reached should be False.&lt;br /&gt;&lt;br /&gt;anyway.. &lt;a href="http://www.thecrumb.com/2008/10/31/beware-ubuntu-810-cruft-remover/"&gt;this blog &lt;/a&gt; sums up the app much better than I could&lt;br /&gt;&lt;br /&gt;By the way "cruft"? I bet that wasn't the original name of this app.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8109854847430899154-4357608339496720406?l=rowinggolfer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rowinggolfer.blogspot.com/feeds/4357608339496720406/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8109854847430899154&amp;postID=4357608339496720406' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/4357608339496720406'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/4357608339496720406'/><link rel='alternate' type='text/html' href='http://rowinggolfer.blogspot.com/2008/11/intrepid-cruft-remover.html' title='Intrepid - cruft remover'/><author><name>Neil</name><uri>http://www.blogger.com/profile/06112117080373993301</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/-GEhvN_g7Kk4/TfnhG7DCMiI/AAAAAAAAAHo/HmAn1zC-xXM/s220/geek.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_wAfH8S6uz00/SRA6Snd6jAI/AAAAAAAAABc/YpPmghKM9Bg/s72-c/Screenshot.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8109854847430899154.post-7870663564857071726</id><published>2008-10-31T09:59:00.000Z</published><updated>2008-10-31T10:12:41.878Z</updated><title type='text'>RIP Feisty - welcome to the world Intrepid</title><content type='html'>ok - here's a point for debate.&lt;br /&gt; End-of-life for feisty = 19th October.&lt;br /&gt; Intrepid Launch = 30th October&lt;br /&gt; one option offered to feisty users on &lt;a href="http://ubuntuforums.org/showthread.php?p=5962335"&gt;http://ubuntuforums.org/showthread.php?p=5962335&lt;/a&gt; is to update to intrepid&lt;br /&gt;I think, therefore, that either &lt;ul&gt;&lt;br /&gt;&lt;li&gt;feisty end-of-life was premature.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;the advice isn't ideal.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;pedantic? maybe.&lt;br /&gt;&lt;br /&gt;I'm sure the ubuntu fanboys will say so.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8109854847430899154-7870663564857071726?l=rowinggolfer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rowinggolfer.blogspot.com/feeds/7870663564857071726/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8109854847430899154&amp;postID=7870663564857071726' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/7870663564857071726'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/7870663564857071726'/><link rel='alternate' type='text/html' href='http://rowinggolfer.blogspot.com/2008/10/rip-feisty-welcome-to-world-intrepid.html' title='RIP Feisty - welcome to the world Intrepid'/><author><name>Neil</name><uri>http://www.blogger.com/profile/06112117080373993301</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/-GEhvN_g7Kk4/TfnhG7DCMiI/AAAAAAAAAHo/HmAn1zC-xXM/s220/geek.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8109854847430899154.post-3248894488030287203</id><published>2008-10-30T11:17:00.000Z</published><updated>2008-10-30T11:25:46.990Z</updated><title type='text'>Pitivi 0.11.2.1</title><content type='html'>George Farris has created a .deb package for the new pitivi release. Pitivi is a very easy to use video editor based on GStreamer.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.cowlug.org/downloads/pitivi_0.11.2.1-0ubuntu1_all.deb"&gt;http://www.cowlug.org/downloads/pitivi_0.11.2.1-0ubuntu1_all.deb&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;it installed (with a sensible warning about over-riding the package in the official repos) flawlessly with gdebi.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8109854847430899154-3248894488030287203?l=rowinggolfer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rowinggolfer.blogspot.com/feeds/3248894488030287203/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8109854847430899154&amp;postID=3248894488030287203' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/3248894488030287203'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/3248894488030287203'/><link rel='alternate' type='text/html' href='http://rowinggolfer.blogspot.com/2008/10/pitivi-01121.html' title='Pitivi 0.11.2.1'/><author><name>Neil</name><uri>http://www.blogger.com/profile/06112117080373993301</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/-GEhvN_g7Kk4/TfnhG7DCMiI/AAAAAAAAAHo/HmAn1zC-xXM/s220/geek.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8109854847430899154.post-445610024649712858</id><published>2008-10-28T16:37:00.000Z</published><updated>2008-10-28T18:23:01.405Z</updated><title type='text'>Scott Sigler - podcast novelist</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.scottsigler.com/images/slices/cover-animation.gif"&gt;&lt;img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer; width: 180px; height: 250px;" src="http://www.scottsigler.com/images/slices/cover-animation.gif" alt="" border="0" /&gt;&lt;/a&gt;This guy deserves recognition as an internet pioneer.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;I WANT YOU TO BUY HIS NEW BOOK&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Why?&lt;br /&gt;&lt;br /&gt;Scott Sigler was one of the first (if not THE first) unpublished authors to distribute his work in audio form for "free" on the internet, under a creative commons type license.&lt;br /&gt;&lt;br /&gt;I have listened to several of his books... namely "Eathcore", "Ancestor" and "Infected".&lt;br /&gt;&lt;br /&gt;I would recommend them to anyone who isn't offended by language and violence. You can get them from his site &lt;a href="http://www.scottsigler.com"&gt;www.scottsigler.com&lt;/a&gt; or &lt;a href="http://www.podiobooks.com"&gt;www.podiobooks.com&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;"Infected" has been published as a paper novel, and can be purchased from amazon or high street stores... it is currently being considered for a film.&lt;br /&gt;&lt;br /&gt;So buy infected if you wish, buy PLEASE pre-order the sequel "Contagious" which is to be released on the 30th December 2008.&lt;br /&gt;&lt;br /&gt;How cool would it be for a podcast novelist to be the number one bestseller on the hardback fiction list?&lt;br /&gt;&lt;br /&gt;In my opinion, very cool indeed. This is how art should be marketed in the internet age. Give your stuff away in one form, accept donations if it is any good, and charge for it in other formats. Much better than allowing editors to dictate what we get to consume.&lt;br /&gt;&lt;br /&gt;If you agree, please buy the book.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8109854847430899154-445610024649712858?l=rowinggolfer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rowinggolfer.blogspot.com/feeds/445610024649712858/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8109854847430899154&amp;postID=445610024649712858' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/445610024649712858'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/445610024649712858'/><link rel='alternate' type='text/html' href='http://rowinggolfer.blogspot.com/2008/10/scott-sigler-podcast-novelist.html' title='Scott Sigler - podcast novelist'/><author><name>Neil</name><uri>http://www.blogger.com/profile/06112117080373993301</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/-GEhvN_g7Kk4/TfnhG7DCMiI/AAAAAAAAAHo/HmAn1zC-xXM/s220/geek.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8109854847430899154.post-2539474043360076339</id><published>2008-10-23T02:18:00.000+01:00</published><updated>2008-10-23T02:24:38.834+01:00</updated><title type='text'>Holiday Highlight.</title><content type='html'>My wife has fallen for another man.&lt;br /&gt;&lt;br /&gt;It's been a while since she looked at me like this!&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_wAfH8S6uz00/SP_RUXgOopI/AAAAAAAAABU/fo7IzqziXvs/s1600-h/M101408_00_8115a.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 214px;" src="http://1.bp.blogspot.com/_wAfH8S6uz00/SP_RUXgOopI/AAAAAAAAABU/fo7IzqziXvs/s320/M101408_00_8115a.jpg" alt="" id="BLOGGER_PHOTO_ID_5260153037628809874" border="0" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8109854847430899154-2539474043360076339?l=rowinggolfer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rowinggolfer.blogspot.com/feeds/2539474043360076339/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8109854847430899154&amp;postID=2539474043360076339' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/2539474043360076339'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/2539474043360076339'/><link rel='alternate' type='text/html' href='http://rowinggolfer.blogspot.com/2008/10/holiday-highlight.html' title='Holiday Highlight.'/><author><name>Neil</name><uri>http://www.blogger.com/profile/06112117080373993301</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/-GEhvN_g7Kk4/TfnhG7DCMiI/AAAAAAAAAHo/HmAn1zC-xXM/s220/geek.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_wAfH8S6uz00/SP_RUXgOopI/AAAAAAAAABU/fo7IzqziXvs/s72-c/M101408_00_8115a.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8109854847430899154.post-7498172487516960969</id><published>2008-10-10T21:08:00.000+01:00</published><updated>2008-10-10T21:13:04.202+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='iwconfig'/><category scheme='http://www.blogger.com/atom/ns#' term='aeroplane'/><category scheme='http://www.blogger.com/atom/ns#' term='radio'/><category scheme='http://www.blogger.com/atom/ns#' term='wireless'/><category scheme='http://www.blogger.com/atom/ns#' term='ubuntu'/><title type='text'>Radio free Ubuntu Laptop.</title><content type='html'>Travelling transatlantic tomorrow (yippee!!), and one issue I needed to address is how to turn off my wireless card for the flight (to save battery life and/or stop the plane crashing.. you decide which;)&lt;br /&gt;&lt;br /&gt;Here's how it's done -&lt;br /&gt;Turn the thing off -&lt;br /&gt;~$ sudo iwconfig wlan0 txpower off&lt;br /&gt;&lt;br /&gt;And back on again-&lt;br /&gt;~$ sudo iwconfig wlan0 txpower on&lt;br /&gt;&lt;br /&gt;simple!&lt;br /&gt;&lt;br /&gt;BTW - bluetooth services are disabled on this laptop... I have no need for it.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8109854847430899154-7498172487516960969?l=rowinggolfer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rowinggolfer.blogspot.com/feeds/7498172487516960969/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8109854847430899154&amp;postID=7498172487516960969' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/7498172487516960969'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/7498172487516960969'/><link rel='alternate' type='text/html' href='http://rowinggolfer.blogspot.com/2008/10/radio-free-ubuntu-laptop.html' title='Radio free Ubuntu Laptop.'/><author><name>Neil</name><uri>http://www.blogger.com/profile/06112117080373993301</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/-GEhvN_g7Kk4/TfnhG7DCMiI/AAAAAAAAAHo/HmAn1zC-xXM/s220/geek.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8109854847430899154.post-4441093341167716729</id><published>2008-10-08T22:37:00.000+01:00</published><updated>2008-10-08T22:55:39.376+01:00</updated><title type='text'>Capitalism and what it can learn from Open Source</title><content type='html'>What a mess the world economy is in.&lt;br /&gt;&lt;br /&gt;Banks are falling left, right and centre, and governments (i.e. tax payers) around the world are propping them up.&lt;br /&gt;Part of the problem is the way that there is no working regulation of banks.&lt;br /&gt;&lt;br /&gt;No-one has been keeping an eye on what they are up to... and how could they?&lt;br /&gt;As I see it, banks do not exchange their trading information with governments, regulators, competitors, shareholders, or customers.&lt;br /&gt;&lt;br /&gt;They are totally "closed-source". This has got to change.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Freedom of information legislation needs to be extended to these institutions, I can see no other way.&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8109854847430899154-4441093341167716729?l=rowinggolfer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rowinggolfer.blogspot.com/feeds/4441093341167716729/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8109854847430899154&amp;postID=4441093341167716729' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/4441093341167716729'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/4441093341167716729'/><link rel='alternate' type='text/html' href='http://rowinggolfer.blogspot.com/2008/10/capitalism-and-what-it-can-learn-from.html' title='Capitalism and what it can learn from Open Source'/><author><name>Neil</name><uri>http://www.blogger.com/profile/06112117080373993301</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/-GEhvN_g7Kk4/TfnhG7DCMiI/AAAAAAAAAHo/HmAn1zC-xXM/s220/geek.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8109854847430899154.post-7704009604653088157</id><published>2008-10-07T16:02:00.000+01:00</published><updated>2008-10-07T17:15:58.382+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sound'/><category scheme='http://www.blogger.com/atom/ns#' term='intel ich8'/><category scheme='http://www.blogger.com/atom/ns#' term='alsa'/><category scheme='http://www.blogger.com/atom/ns#' term='ubuntu'/><title type='text'>Advent 9112 headphones</title><content type='html'>&lt;a style="" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_wAfH8S6uz00/SOuK9ykqUbI/AAAAAAAAABI/paODso8DTio/s1600-h/headphones.jpg"&gt;&lt;img style="margin: 0pt 0pt 10px 10px; float: left; cursor: pointer;" src="http://3.bp.blogspot.com/_wAfH8S6uz00/SOuK9ykqUbI/AAAAAAAAABI/paODso8DTio/s320/headphones.jpg" alt="" id="BLOGGER_PHOTO_ID_5254446184410010034" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;My laptop is an &lt;a href="http://reviews.cnet.co.uk/laptops/0,39030092,49295980,00.htm"&gt;Advent 9112&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;With Ubuntu, the soundcard (Audio device: Intel Corporation 82801H (ICH8 Family) HD Audio Controller (rev 03) - has issues.&lt;br /&gt;&lt;br /&gt;In particular, pluging in the headphones doesn't mute the main speakers.&lt;br /&gt;&lt;br /&gt;The solution add  the following lines at the bottom of  /etc/modprobe.d/alsa-base&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(102, 102, 102);"&gt;#I have modified this file on TODAY's Date to get headphones working&lt;/span&gt; &lt;span style="color: rgb(102, 102, 102);"&gt;options snd-hda-intel model=mitac&lt;/span&gt;&lt;br /&gt;then restart alsa.&lt;br /&gt;&lt;span style="color: rgb(255, 102, 0);"&gt;sudo /etc/init.d/alsa restart&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8109854847430899154-7704009604653088157?l=rowinggolfer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rowinggolfer.blogspot.com/feeds/7704009604653088157/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8109854847430899154&amp;postID=7704009604653088157' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/7704009604653088157'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/7704009604653088157'/><link rel='alternate' type='text/html' href='http://rowinggolfer.blogspot.com/2008/10/advent-9112-headphones.html' title='Advent 9112 headphones'/><author><name>Neil</name><uri>http://www.blogger.com/profile/06112117080373993301</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/-GEhvN_g7Kk4/TfnhG7DCMiI/AAAAAAAAAHo/HmAn1zC-xXM/s220/geek.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_wAfH8S6uz00/SOuK9ykqUbI/AAAAAAAAABI/paODso8DTio/s72-c/headphones.jpg' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8109854847430899154.post-4183796133913706802</id><published>2008-10-07T13:01:00.000+01:00</published><updated>2008-10-07T13:20:20.617+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='spammer'/><category scheme='http://www.blogger.com/atom/ns#' term='html markup'/><title type='text'>Me a spammer??</title><content type='html'>&lt;a style="" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_wAfH8S6uz00/SOtT2LIKk7I/AAAAAAAAABA/yAHO4bi11Kc/s1600-h/spam.jpg"&gt;&lt;img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer;" src="http://4.bp.blogspot.com/_wAfH8S6uz00/SOtT2LIKk7I/AAAAAAAAABA/yAHO4bi11Kc/s320/spam.jpg" alt="" id="BLOGGER_PHOTO_ID_5254385580422894514" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Oh dear.&lt;br /&gt;&lt;br /&gt;This morning I got an email from blogger.com telling me that my blog has been flagged by their automated spam filter, and therefore my blog has been blocked because of a "violation of their terms of use".&lt;br /&gt;&lt;br /&gt;My blog is in quarantine and in 20 days this blog may be destroyed!!&lt;br /&gt;&lt;br /&gt;anyway, I think the issue may be that I put my httpd.conf file text in the last posting, and this contains some html markup. So I have changed all the  &amp;gt; symbols to &amp;amp;gt; and the &amp;lt; symbols to &amp;lt;&lt;br /&gt;&lt;br /&gt;(yes it did take an age to type the above sentence, and I have had to go through captcha hell to post this!)&lt;br /&gt;&lt;br /&gt;blogger.com please don't kill my blog!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8109854847430899154-4183796133913706802?l=rowinggolfer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rowinggolfer.blogspot.com/feeds/4183796133913706802/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8109854847430899154&amp;postID=4183796133913706802' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/4183796133913706802'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/4183796133913706802'/><link rel='alternate' type='text/html' href='http://rowinggolfer.blogspot.com/2008/10/me-spammer.html' title='Me a spammer??'/><author><name>Neil</name><uri>http://www.blogger.com/profile/06112117080373993301</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/-GEhvN_g7Kk4/TfnhG7DCMiI/AAAAAAAAAHo/HmAn1zC-xXM/s220/geek.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_wAfH8S6uz00/SOtT2LIKk7I/AAAAAAAAABA/yAHO4bi11Kc/s72-c/spam.jpg' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8109854847430899154.post-7783494873551969714</id><published>2008-10-06T15:35:00.000+01:00</published><updated>2008-10-07T13:01:15.239+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='cgi-bin'/><category scheme='http://www.blogger.com/atom/ns#' term='apache2 config'/><title type='text'>httpd.conf improvement</title><content type='html'>I noticed today that apache2 on my laptop was executing files in&lt;br /&gt;~/website/cgi-bin&lt;br /&gt;but not in&lt;br /&gt;~/website/cgi-bin/*/&lt;br /&gt;&lt;br /&gt;anyway, turns out I had configured it incorrectly :(&lt;br /&gt;originally I had added my local cgi-bin as a directory (useful for a directory of scripts in an odd place)&lt;br /&gt;My old httpd.conf file&lt;br /&gt;&lt;div style="text-align: left;"&gt;&lt;span style="color: rgb(204, 0, 0);"&gt;&amp;lt;VirtualHost *&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(204, 0, 0);"&gt;    ServerName testhost&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(204, 0, 0);"&gt;    DocumentRoot /home/neil/ircwebsite&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(204, 0, 0);"&gt;&amp;lt;/Virtualhost&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(204, 0, 0);"&gt;&amp;lt;Directory /home/neil/ircwebsite/cgi-bin&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(204, 0, 0);"&gt;Options ExecCGI&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(204, 0, 0);"&gt;SetHandler cgi-script&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(204, 0, 0);"&gt;&amp;lt;/Directory&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;span style="color: rgb(153, 153, 153);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: rgb(153, 153, 153);"&gt; &lt;virtualhost&gt;&lt;/virtualhost&gt;&lt;/span&gt;but a ScriptAlias is shorter and works for cgi-bin AND all child folders therein&lt;br /&gt;&lt;span style="color: rgb(153, 153, 153);"&gt;&lt;span style="color: rgb(153, 0, 0);"&gt;&amp;lt;VirtualHost *&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(153, 0, 0);"&gt;     ServerName testhost&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(153, 0, 0);"&gt;     DocumentRoot /home/neil/ircwebsite&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(153, 0, 0);"&gt;&amp;lt;/Virtualhost&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(153, 0, 0);"&gt;ScriptAlias          /cgi-bin/        /home/neil/ircwebsite/cgi-bin/&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8109854847430899154-7783494873551969714?l=rowinggolfer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rowinggolfer.blogspot.com/feeds/7783494873551969714/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8109854847430899154&amp;postID=7783494873551969714' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/7783494873551969714'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/7783494873551969714'/><link rel='alternate' type='text/html' href='http://rowinggolfer.blogspot.com/2008/10/httpdconf-improvement.html' title='httpd.conf improvement'/><author><name>Neil</name><uri>http://www.blogger.com/profile/06112117080373993301</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/-GEhvN_g7Kk4/TfnhG7DCMiI/AAAAAAAAAHo/HmAn1zC-xXM/s220/geek.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8109854847430899154.post-8647527866210719745</id><published>2008-10-04T21:18:00.000+01:00</published><updated>2008-10-04T22:19:57.560+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='video'/><category scheme='http://www.blogger.com/atom/ns#' term='compiz'/><category scheme='http://www.blogger.com/atom/ns#' term='cube'/><category scheme='http://www.blogger.com/atom/ns#' term='intrepid'/><category scheme='http://www.blogger.com/atom/ns#' term='ubuntu'/><title type='text'>Intrepid's improved handling of video</title><content type='html'>As I posted yesterday, I have moved over to intrepid.&lt;br /&gt;I have noticed a few major improvements over hardy (for me, on my hardware), but a MAJOR improvement is the way that video is handled in windows that are being moved. It just works. Perfectly.&lt;br /&gt;&lt;br /&gt;Here's an example - I have totem playing the big buck bunny, and mplayer showing a home movie of the family in Italy. Rotate the cube... and it's no problem!&lt;br /&gt;&lt;br /&gt;Flipping cool.&lt;br /&gt;( BTW - I did a sanity check and confirm this isn't/wasn't the behaviour on the same machine in Hardy.)&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_wAfH8S6uz00/SOfP-1ZBr-I/AAAAAAAAAAU/2pAvP3fGTI0/s1600-h/Cube.jpg"&gt;&lt;img style="cursor: pointer;" src="http://2.bp.blogspot.com/_wAfH8S6uz00/SOfP-1ZBr-I/AAAAAAAAAAU/2pAvP3fGTI0/s320/Cube.jpg" alt="video on intrepid" id="BLOGGER_PHOTO_ID_5253396168741859298" border="0" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8109854847430899154-8647527866210719745?l=rowinggolfer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rowinggolfer.blogspot.com/feeds/8647527866210719745/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8109854847430899154&amp;postID=8647527866210719745' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/8647527866210719745'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/8647527866210719745'/><link rel='alternate' type='text/html' href='http://rowinggolfer.blogspot.com/2008/10/intrepids-improved-handling-of-video.html' title='Intrepid&apos;s improved handling of video'/><author><name>Neil</name><uri>http://www.blogger.com/profile/06112117080373993301</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/-GEhvN_g7Kk4/TfnhG7DCMiI/AAAAAAAAAHo/HmAn1zC-xXM/s220/geek.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_wAfH8S6uz00/SOfP-1ZBr-I/AAAAAAAAAAU/2pAvP3fGTI0/s72-c/Cube.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8109854847430899154.post-1687817521444190987</id><published>2008-10-04T13:35:00.000+01:00</published><updated>2008-10-04T13:49:18.032+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='random linux thought for the day'/><title type='text'>The Gnome devs bible part 1.</title><content type='html'>The sermon on the mount.&lt;br /&gt;&lt;br /&gt;"Blessed are the cheese-makers.&lt;br /&gt;for they shall enable the webcams"&lt;br /&gt;&lt;br /&gt;not to be taken literally, of course&lt;br /&gt;it refers to all V4linux apps.&lt;br /&gt;&lt;br /&gt;(with apologies to Jesus AND monty python)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8109854847430899154-1687817521444190987?l=rowinggolfer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rowinggolfer.blogspot.com/feeds/1687817521444190987/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8109854847430899154&amp;postID=1687817521444190987' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/1687817521444190987'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/1687817521444190987'/><link rel='alternate' type='text/html' href='http://rowinggolfer.blogspot.com/2008/10/gnome-devs-bible-part-1.html' title='The Gnome devs bible part 1.'/><author><name>Neil</name><uri>http://www.blogger.com/profile/06112117080373993301</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/-GEhvN_g7Kk4/TfnhG7DCMiI/AAAAAAAAAHo/HmAn1zC-xXM/s220/geek.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8109854847430899154.post-4540966297630372144</id><published>2008-10-04T08:14:00.001+01:00</published><updated>2008-10-04T22:20:50.584+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='big buck bunny'/><category scheme='http://www.blogger.com/atom/ns#' term='tllts'/><category scheme='http://www.blogger.com/atom/ns#' term='doppleganger'/><category scheme='http://www.blogger.com/atom/ns#' term='alan'/><title type='text'>Big Buck Bunny</title><content type='html'>&lt;a style="" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_wAfH8S6uz00/SOcZFNG_fuI/AAAAAAAAAAM/el1bAo5vUdQ/s1600-h/doppleganger.jpg"&gt;&lt;img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer;" src="http://1.bp.blogspot.com/_wAfH8S6uz00/SOcZFNG_fuI/AAAAAAAAAAM/el1bAo5vUdQ/s320/doppleganger.jpg" alt="alan looks like big buck bunny" id="BLOGGER_PHOTO_ID_5253195067560001250" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;I listen to a great podcast called &lt;a href="http://tllts.org/"&gt;"the linux link tech show"&lt;/a&gt; which is mainly about flatulence and mythtv.&lt;br /&gt;&lt;br /&gt;One of the less verbose hosts of the show has a striking resemblence to the bunny in the open source movie &lt;a href="http://www.bigbuckbunny.org/"&gt;Big Buck Bunny&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;I mention this because I want to upload my first picture to this already infamous blog of mine, so here, with a quick flick of the gimp is the proof.....&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8109854847430899154-4540966297630372144?l=rowinggolfer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rowinggolfer.blogspot.com/feeds/4540966297630372144/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8109854847430899154&amp;postID=4540966297630372144' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/4540966297630372144'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/4540966297630372144'/><link rel='alternate' type='text/html' href='http://rowinggolfer.blogspot.com/2008/10/big-buck-bunny.html' title='Big Buck Bunny'/><author><name>Neil</name><uri>http://www.blogger.com/profile/06112117080373993301</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/-GEhvN_g7Kk4/TfnhG7DCMiI/AAAAAAAAAHo/HmAn1zC-xXM/s220/geek.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_wAfH8S6uz00/SOcZFNG_fuI/AAAAAAAAAAM/el1bAo5vUdQ/s72-c/doppleganger.jpg' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8109854847430899154.post-7098285353793710270</id><published>2008-10-04T00:14:00.000+01:00</published><updated>2008-10-04T08:25:17.153+01:00</updated><title type='text'>rough hack to fix that sudo path issue</title><content type='html'>remembered how I got the script  "~/bin/bright" to be on sudo's path.&lt;br /&gt;&lt;br /&gt;# ln -s ~/bin/bright /usr/bin/bright&lt;br /&gt;&lt;br /&gt;a bit of a cheat, but it works dandy.&lt;br /&gt;BTW - here is that script.&lt;br /&gt;&lt;br /&gt;#! /bin/bash&lt;br /&gt;echo 100 &gt; /proc/acpi/video/GFX0/DD02/brightness&lt;br /&gt;&lt;br /&gt;why do I need it? because my brightness buttons don't work unless I disable ACPI :(&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8109854847430899154-7098285353793710270?l=rowinggolfer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rowinggolfer.blogspot.com/feeds/7098285353793710270/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8109854847430899154&amp;postID=7098285353793710270' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/7098285353793710270'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8109854847430899154/posts/default/7098285353793710270'/><link rel='alternate' type='text/html' href='http://rowinggolfer.blogspot.com/2008/10/remembered-how-i-got-script-binbright.html' title='rough hack to fix that sudo path issue'/><author><name>Neil</name><uri>http://www.blogger.com/profile/06112117080373993301</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/-GEhvN_g7Kk4/TfnhG7DCMiI/AAAAAAAAAHo/HmAn1zC-xXM/s220/geek.jpg'/></author><thr:total>0</thr:total></entry></feed>
