Peter's Blog

Redefining the Impossible

Posts made during March 2005


It's amazing what you can buy on ebay.

images/dogpoo.jpg
images/poo.jpg

I thought google were working on this, after someone did a search for African Slaves (low prices). MSN suffer as well.


Filed under: google

Add a comment

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:

images/grab.jpg

The script itself inside VIM

ToDo:

  • handle file names in clipboard
  • detect upload errors
  • allow resizing images

4 Comments

Getting Python to talk with Windows XP:

  • run C:\Python23\Lib\site-packages\win32com\client\makepy.py
  • choose 'Microsoft Speech Object Library (5.0)' from the list and OK
  • run this python
    import win32com.client
    
    o = win32com.client.Dispatch( 'SAPI.Spvoice')
    o.Speak( 'That was easy')
    
  • Combine this with remote sshd login and a loud av amp in church mode and scare the wife.

Talk from command line:

#
# Speak
#
import win32com.client
import sys

win32com.client.Dispatch( 'SAPI.Spvoice').Speak( " ".join( sys.argv[1:]))

Filed under: python windows

1 Comment

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.


Filed under: google pagerank

2 Comments

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:

  • it installs as a taskbar app
  • it's user interface is little more than a set of property pages
  • when it is idle, waiting to download podcasts once a day, it has about 20M of memory allocated to it. Ok, so most of this is probably swapped to disk all the time but even so, HOW MUCH?
images/ipoddermemory.jpg
  • as it is a taskbar app, someone has to be logged into windows to run it. It is not a service and the windows scheduler can log in automatically to launch a task.
  • it works but it is unremarkable.

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.


Filed under: dell inspiron ipodder windows

Add a comment

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

2 Comments

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:

  • boot puppy from floppy/usb key
  • open terminal
  • mount broken linux partition:
    mkdir /mnt/d
    mount /dev/hdb1 /mnt/d
    
  • chroot to broken linux so I get access to grub on it (no grub in puppy linux sad)
    chroot /mnt/d bash
    
  • Set up a grub floppy as described here as pc could not read the existing grub floppy (monday morning: Argh).
  • Boot into floppy and boot system from grub as also described there.

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.


Filed under: linux ubuntu

Add a comment

Google have released their new non-beta desktop search. Since they have given me pagerank 0, here's some spiteful Microsoft Desktop Search Evangelism:

  • New GDS has a plugin API. MDS already has installable filters for extra file types based on established technology: see here and here and especially here. Ok, IFilters are all based on deeply pretentious COM models so I wouldn't want to try writing them. Interesting to see that you can load filters through a win32 API called LoadIFilter. Wonder if this is of any use?
  • MDS can index PDF files by downloading Adobes own plugin.
  • MDS indexes my outlook messages, even though they are stored on an exchange server: can GDS do that?
  • MDS doesn't take copies of the documents it indexes so saves lots of disk space.
  • I do find MSN search useful, especially the taskbar thing. I like the way
    =regedit
    
    launches the registry editor without me having to open the 'run' box or a command prompt. Dunno if GDS can do this.
images/MDSTaskbar.jpg
  • I don't like the way GDS gives results in a web browser: it only gives you the option of opening files it finds: you cannot edit them, copy them or whatever. MDS results are presented in a file explorer, much more useful.

4 Comments

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.


8 Comments

A quick reminder on how to use Swig under Windows XP to generate Python modules with Visual Studio 6.

  • Download Windows version of Swig
  • Unzip it somewhere, I put it in c:/Python24/Swig
  • Create the following environment variables:
    PYTHONINCLUDE = c:\python24\include
    PYTHONLIB = c:\Python24\Libs
    
  • Create a project in Visual Studio for a plain empty win32 dll.
  • In all build settings, make sure the following settings are added:
    Additional include directories = c:\python24\include
    Additional library path = c:\python24\libs
    
  • Create swig definition file. Here is mine, it's for a CAN bus control module:
       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  };
    
  • Add the Swig file to the project, right click and select 'settings'. Set the custom build commands something like the following:
    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
    
  • The above will generate a c++ file called 'pyCan_wrap.cxx'. This should be put into the 'Outputs' box in the custom build step.
  • Run the build on the swig file to create the wrapper file pyCan_wrap.cxx and add that file to the project.
  • Set the link target to something like
    _pyCan.dll
    
    I.e. the name of the module with an underscore in front.
  • Create a 'real' c++ header and implementation for your classes. They can be totally straight c++, e.g.:
    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.
  • Build it
  • Swig will create a file called 'pyCan.py' which is the python wrapper module that loads the dll. It is the file that your python must import. You might want to add a post-build step to copy this somewhere more useful. You may also put the link target file in the same directory or you will get errors when you import the module.
  • Write some python:
    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.


Filed under: python swig windows

2 Comments