It's amazing what you can buy on ebay.


I thought google were working on this, after someone did a search for African Slaves (low prices). MSN suffer as well.
Uploading images to this blog can be kinda fiddly. Say I have an image in the windows clipboard (e.g. a screen clip from OneNote and I want it on the blog, I have to fire up a graphics program, paste it in, save it to a file, fire up filezilla, upload it, delete the image file.
This little script does all this for me. It asks for a file name, writes the image in the clipboard to the file, uploads it and deletes the image. Job Done.
The uploading is done using pscp, a version of scp from the putty camp. It uses my putty private key so I don't have to give a password for access to the server (I didn't use the cygwin version of ssh as it didn't like having 'c:\' in file names). The script uses the Python Imaging Library to do the grabbing and wxPython to ask for the file name.
1 # 2 # Upload image in clipboard to server 3 # 4 import wx 5 import ImageGrab 6 import Image 7 import os 8 import tempfile 9 10 class MyApp(wx.App): 11 def OnInit(self): 12 oImage = ImageGrab.grabclipboard() 13 14 if not isinstance( oImage, Image.Image): 15 # 16 # In no way is wxPython an easy to use library. 17 # 18 dlg = wx.MessageDialog( None, 'No image in clipboard', 'Error', wx.OK) 19 dlg.ShowModal() 20 dlg.Destroy() 21 return True 22 23 dlg = wx.TextEntryDialog( None, 'Enter a file name', 'Upload Clipboard', '') 24 if dlg.ShowModal() != wx.ID_OK: 25 dlg.Destroy() 26 return True 27 28 strName = dlg.GetValue() 29 dlg.Destroy() 30 31 strTempFile = tempfile.mktemp( strName) 32 oImage.save( open( strTempFile, 'wb')) 33 34 strCmd = 'pscp -q -i "c:\my documents\puttykey.ppk" %s me@myserver.com:www/images/%s' % (strTempFile, strName) 35 36 os.system( strCmd) 37 38 os.unlink( strTempFile) 39 40 return True 41 42 app = MyApp(0) 43 app.MainLoop()
This is the result of alt-print screen and running this script:

The script itself inside VIM
ToDo:
Getting Python to talk with Windows XP:
import win32com.client o = win32com.client.Dispatch( 'SAPI.Spvoice') o.Speak( 'That was easy')
Talk from command line:
# # Speak # import win32com.client import sys win32com.client.Dispatch( 'SAPI.Spvoice').Speak( " ".join( sys.argv[1:]))
The pageranks of the various guises of this site have changed:
www.petersblog.org: was 4 now 0
petersblog.org: was 4 now 0
bisiand.me.uk: was 4 now 0
www.bisiand.me.uk: was 3 now 3
Bugger.
Maybe google consider the aliasing to be link farming or maybe life's a bitch.
I've been giving iPodder a try. It's an application for automatically downloading podcasts for later listening with iTunes: the podcasts appear in iTunes playlists.
I've been considering using my laptop for dowdloading podcasts instead of having a server running 24/7 and launching my downloading script once a day. The dell Inspiron 500m laptop can be turned on at certain times through it's Bios and after that it can sit in standby mode until the windows scheduler tells it to download podcasts. The laptop is effectively silent so it's not a pain like the server. I don't even know if it has a fan in it.
I gave iPodder a try as a more refined way of podcasting than the script. A potted review:

I'll probably stick with my script if I can get it to run on windows, which should not be a problem. During the 23 hours and 50 minutes of the day it is doing nothing it will consume negligible resources. Downsides are that I do have to edit the script to add new feeds and it won't integrate with iTunes.
In England at least a lemon is something that is something of a liability. It is also iPodder's icon.
Did 1170 strokes in 30 minutes yesterday, probably my best yet, 39 strokes/min for 30 minutes. I passed 2km in 24 minutes 20 seconds: I can remember when I was pleased to do 2km in 30 minutes.
2km on my Tunturi is just a number, the gold standard is a Concept 2.
I was reading the very comprehensive indoor rowing info on the concept 2 site and discovered something I have been wondering for a long time: in the 2km races, what difficulty setting is the machine set to? When I used to use a concept 2 at the gym I always had it on 10 which is the equivalent of rowing a lardy rowboat while 1 is a sleek scull. Well, the rules say that you can set the difficulty to whatever you like but you cannot change it.
I don't think I can do 2km in less than 6 minutes but maybe I could do better than the 7:38 I once did on level 10.
Filed under: rowing
Had to reboot Ubuntu server and it wouldn't reboot: grub gave errors about missing partitions. Argh. To make things worse, the CD Drive stopped working. Argh.
I managed to get it to boot using Puppy Linux on my USB key. I did the following:
mkdir /mnt/d mount /dev/hdb1 /mnt/d
)
chroot /mnt/d bash
System back up and running. I tried
sudo grub-install '(hd0)'
to try to get system booting again but didn't work so I have to keep booting from grub floppy. I'll come back to this sometime, I have work to do. I might go back to Lilo, grub is a bit too weird for my taste.
Google have released their new non-beta desktop search. Since they have given me pagerank 0, here's some spiteful Microsoft Desktop Search Evangelism:
=regedit

I decided to put a new backup strategy in place at work. I have my desktop PC running windows and an Ubuntu server. I wanted to back up my day-to-day work under windows to the server. I wanted incremental backup so I have the option to backtrack through file history if necessary.
rsync is a nice utility to copy an set of files from one pc to another and works under windows {via Cygwin) and Linux. It can copy over ssh and hence I can use my ssh keys to avoid having to log into the server or put my password in scripts. However it does not do incremental backups, it just duplicates.
rdiff-backup is a nice backup tool that can do cross-network incremental backups. It uses the rsync protocol so it is very efficient. It is also easy to use, no weird command line switches, just give it the name of the source and target directories. However, support for this on windows is not straightforward and it relies on using a cygwin version of python rather than the standard distribution.
So, a compromise solution, use both. I have set things up so that this is done every night when I go home:
cd c:\Projects rsync -avz --exclude-from="rsync.cnf" -e ssh ./ pcw@rd-pcw2:Projects/ > backup.log blat backup.log -to pcw@itl.co.uk
this copies files from my 'Projects' directory to the server. The "rsync.cnf" file is a set of things to exclude from the copy, e.g.:
# # Doxygen output files # - Doxygen/ # # Anything downloaded # - Download/ - lstfiles/ - ofiles/ - *.bak - *.Bak # # Anything generated by py2exe # - build/ - dist/ # # Anything in a folder called Old # - Old/ # # VC build directorys # Debug/ Release/ debug/ release/ # # Miscellaneous. # - *.obj - *.tmp - *.pyc - setup/*.exe - Output/setup.exe
After running this I use blat to email me what happened so I know it succeeded.
On the server I have crontab set up to run rdiff-backup every night after the files have been uploaded:
0 18 * * * rdiff-backup /home/pcw/Projects /home/pcw/Backup
This system gives me two full copies of my project files and incremental backups to boot.
Todo: rdiff-backup to a different disk, giving three copies.
A quick reminder on how to use Swig under Windows XP to generate Python modules with Visual Studio 6.
PYTHONINCLUDE = c:\python24\include PYTHONLIB = c:\Python24\Libs
Additional include directories = c:\python24\include Additional library path = c:\python24\libs
1 %module pyCan 2 %include exception.i 3 %{ 4 #include <windows.h> 5 #include <stdlib.h> 6 #include <stdio.h> 7 #include <string.h> 8 #include "pyCan.h" 9 %} 10 11 /* 12 * When a c++ exception occurs, this code will turn it into 13 * a python exception. Cool. 14 */ 15 %exception { 16 try { 17 $action 18 } catch( char *strError) { 19 PyErr_SetString(PyExc_RuntimeError, strError); 20 return NULL; 21 } 22 } 23 24 /* 25 * The function GetRxPacket returns a new object that python 26 * memory management must delete when required. 27 */ 28 %newobject GetRxPacket; 29 30 /* 31 * Class that will become a python class. The python class will have 32 * the same methods available. 33 */ 34 class pyCan { 35 public: 36 pyCan( void); 37 ~pyCan( void); 38 void Initialise( void); 39 void Poll( void); 40 pyCanPacket *GetRxPacket( void); 41 void TxPacket( int nID, PyObject *); 42 };
c:\python24\swig\swig -c++ -module pyCan -python c:\projects\694\src\pyCan\pyCan\pyCan.swig
Where
-c++ = generate c++
-module pyCan = output module is called 'pyCan
-python = generate python module
c:\projects\694\src\pyCan\pyCan\pyCan.swig = swig file name
_pyCan.dll
class pyCan {
public:
pyCan( void);
~pyCan( void);
void Initialise( void);
void Poll( void);
pyCanPacket *GetRxPacket( void);
void TxPacket( int nID, PyObject *);
};
In the above example I am passing a PyObject * to the function TxPacket. This is because I want to be able to pass python strings that may contain null characters and I want access to both the pointer to the data and the data length, which the raw PyObject gives me. If I only wanted a char * I would simply put that in the argument.
import pyCan o = pyCan.pyCan() o.Initialise() while 1: o.Poll() r = o.GetRxPacket() if r: print r
Swig is quite easy to get going. I think it has real power but there is a lot of documentation to go through to fully understand what it can do and the documentation and semantics are not all that clear. The PyObject trick above was a guess of mine that happened to work.