RPM Packages for CentOS Linux

I have a bunch of RPM packages that I’ve made for CentOS over the last couple of years – nothing hugely earth-shattering, but just some stuff that I like to install by default whenever I have to build a new machine. I’ve created a yum repository on the same server that hosts this web site, so feel free to go ahead and make use of it!

To use this repository with (for example) the yum package manager, download and install linux2000-repo-1.0-1pke.noarch.rpm. This will also install the GPG public key that I use to sign my packages, allowing you to verify that downloaded RPMS have not been tampered with in transit to you.

If you would like to browse the contents of my repo to see what packages are contained therein, the URLs are:

Binary packages: http://packages.linux2000.com/l2k6server-x86_64/rpm

Source packages: http://packages.linux2000.com/l2k6server-x86_64/sources

Please note that my packages are intended to be used on a 64-bit install of CentOS v6.x. They *may* be compatible with a 64-bit install of RedHat Enterprise Linux v6.x, but I have not tested this. I have no plans to port these packages to other versions of CentOS or to other Linux distributions. Source RPMs are available for those who want to try.

These packages are offered as a public service in the hope that they will be considered useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Any use you may make of the contents of this repository is understood by you to be entirely at your own risk.

Feedback, comments or suggestions for improvements can be made to the e-mail address for me which is embedded in most of these packages.

Rusty Engineering Skills

I’ve been involved with IT since leaving college slightly over 30 years ago and for a couple of years before that, when I got swept up in the illegal CB radio craze in my mid to late teens, I used to supplement my pocket money as one of the local ‘rig doctors’, mostly replacing output stage transistors for people who did mad things like trying to use a metal coat hanger or their standard car radio aerial on 27MHZ. Perhaps if the muse takes me one day, I’ll write an article about the little cottage industry myself and one of my CB buddies (who was a BT RF engineer at the time) had going with rig repairs and home brewed accessories.

Computers have almost always (in my lifetime at least!) been so much easier to work on than transceivers, because the fix for most faults is a complete replacement of a self-contained component rather than a board-level repair. Ironically, though, the last 2 major faults that have befallen our main computer at home have required me to get my soldering iron out, which has had a certain nostalgia value about it, not to mention the fact that the second soldering iron episode highlighted just how out of practice I’ve got with the basic fault finding skills that I learned in my teens whilst repairing other peoples CB radios.

The first problem occured during what passed for the summer in 2012. The 22-inch LCD monitor which I’ve had for some time finally gave up the ghost, after a couple of weeks of needing to be switched off and back on again several times in succession in order to get a stable picture. I’d resigned myself to having to buy a replacement and was all set to take it to our local council waste site for proper disposal. Since I know very little about how TVs and computer screens actually work, I thought it might be educational to take it apart and see what was inside it. After removing 12 screws to take the back off and disconnecting the ribbon cable to the LCD panel, I was slightly disappointed to find just 2 fairly bland circuit boards. The smaller of the two had just 3 or 4 VLSI or very large scale integrated circuits on it and virtually no other components, so I assumed that it was the bit that did the job of decoding the digital video signal from the PC and putting it on the 1680×1050 screen. To my surprise, the larger board was quite clearly a switched mode power supply. To my further surprise, the fault was immediately obvious purely based on a visual inspection. There were 5 radial lead electrolytic capacitors at one end of the board, all of the mega-cheap chinese import variety. Each of these was bowed outwards quite significantly at the top, indicating that they had almost reached the point at which the magic smoke would leak out.

Swiftly bringing to bear my noble soldering iron of justice, I soon had the suspect components on the bench in front of me. They were all 100uF 16v, it was 4:20pm on a Sunday afternoon and my local branch of Maplin was still open for another 40 minutes. Ignoring the cries of “What do you mean you’re going to try to fix it?” from my wife, I jumped in the car and headed to the aforementioned purveyors of electrical and electronic components.

Some time later and the princely sum of £2.75 spent, I had a bag of 5 replacement capacitors, a hot soldering iron and a somewhat incredulous wife and mother-in-law, both with slightly worried looks on their faces. Not to be deterred, I spent the next few minutes carefully desoldering the pads where the original components had been mounted, soldering the new capacitors in place and trimming back the leads to make a neat job. I managed to put the monitor back together without having any parts left over and was feeling quite pleased with myself and my out-of-practice engineering skills, announcing that I was ready to test my repair and see if it had ‘done the trick’.

At this point, my wife suggested that if I was planning to put myself at risk of electrocution, it would be best to do so in the back garden rather than clutter up the house with my scorched and blackened corpse. Ever the obedient husband, I took the computer, keyboard and mouse outside along with an extension lead, the newly repaired monitor and a VGA cable. This was all deposited on the patio table and connected together as appropriate. Upon gingerly applying mains power, I was delighted to see the monitor come up as normal on the first go with an absolutely rock-steady picture. After leaving everything running for 15 minutes, the range safety officer (a.k.a my wife) declared herself satisfied that the fire/electrocution risk seemed to be minimal and I was finally allowed to bring the repaired device back into the family home.

I really didn’t think I’d ever have cause to use my soldering iron to fix another computer problem. How wrong I was.

I decided at the end of February 2013 that it was about time to upgrade the home computer to Windows 7. Windows XP was fast approaching its ‘best before’ date and I’d always had a 32-bit version installed, despite having a computer that was 64-bit ready in almost all respects. After much wavering, I decided to take the plunge.

In preparation for the upgrade, I ordered an extra 8GB of memory, to bring the total installed up to 12GB. When this arrived, it also seemed that now was as good a time as any to strip the computer down and give it a good internal spring clean, removing all the dust, cleaning out fan filters, etc, etc.

So it was that I found myself once again out in the back garden, this time with the computer itself in bits around me. It took about 3 hours of careful disassembly, cleaning and dusting before I was happy with the result. During this process, I noticed that one of the front panel mounted USB connectors (that had been playing up for a while) had a loose connection to one of the pins on its associated header plug. Since I already had the machine in bits anyway, I stripped off the whole front panel switch and connector assembly and carefully teased the tiny little pin and attached wire back into place. I also took the opportunity to re-arrange some of the cable routing inside the case, both to make it look neater and to try and improve the airflow from the cooling fans.

I re-assembled everything, slotted in the extra 8G of memory and spent a moment admiring my shiny, new-looking computer before taking it back indoors. I wired everything back up, including mains power, speakers, USB printer, USB wireless adapter, monitor cable and USB wireless mouse/keyboard doo-hickey. Switching the mains back on, I saw the power LED light up on the front panel, the main chassis and CPU fans spun up for about a second and then everything went dead. No reassuring ‘beep’ to indicate that the power-on self-test or POST had completed successfully, nothing displayed on the freshly-repaired monitor, just complete silence and no sign of any activity at all. The machine hadn’t even had time to get to the point (usually after a couple of seconds) where it spins up the hard drive. The front panel power switch wasn’t causing aything to happen when I pressed it, but I found that if I pulled the kettle lead out of the power supply for 30 seconds then plugged it back in, I’d get the same thing as before, CPU and case fan spinning for about 1 second with the power LED lit, nothing else happening and a total shutdown almost straight away.

Okay, not to worry, I’ve had the whole thing in bits, I’ve obviously connected something back up wrong or left something not quite seated correctly. The first suspect was the newly-fitted memory modules. I discovered by trial and error that the machine would only do anything different if I removed all of its 4 memory modules. It still wouldn’t respond to the front panel power switch, but would at least get as far as the POST checks, at which point I’d get 2 short beeps in a row, which is the signal with this BIOS that it has failed to find any useable memory. I began to suspect at this point that all 4 memory modules had failed for some reason, which was disappointing since I didn’t have any spare DDR3 sticks in my spares box that I could test with.

Without boring you with all the details, I spent another hour trying to diagnose the problem without success. When I got the point where I’d disconnected and/or removed every component and external cable apart from the CPU and it still wouldn’t power up, I started to wonder if my spring clean had killed something vital on the motherboard with a dose of static electricity. Utterly despondent at this point, I put everything back together and had one more go at powering it up. Still no good. I sat and had a think about the problem over a cup of coffee, mentally reviewing what has to happen in order to get a modern PC to power up and load its operating system. It struck me that my last test had been to have the power LED header plug and the front panel switch header plug connected to the motherboard and nothing else and yet it would still only respond if I removed the kettle lead from the power supply for 30 seconds and plugged it back in. I was effectively simulating a power cut, in which case the machine was doing exactly what it was set to do in the BIOS, namely to stay powered off when the electrical supply was restored. The fact that pressing the front panel power button had had no effect in any of the tests I had devised had somehow slipped past me un-noticed.

I took the side panel off the computer once more, pulled out the power button header from the motherboard and shorted out the pins with a flat bladed screwdriver. Lo and behold, the computer powered on as normal, only complaining that it couldn’t find an operating system on the hard drive, which was because I’d completely wiped the drive in preparation for the upgrade to Windows 7. The fault appeared to be with either the actual power button itself or the wiring between the button on the front panel and the motherboard.

I quickly removed the whole front panel assembly again and inspected the ribbon cable connecting the small PCB holding the power and reset buttons to the motherboard. Instead of shiny blobs of solder where the 4-strand ribbon cable met the board, the solder on 3 of the 4 pads was dull and grey, classic signs of a ‘dry joint’. I’d obviously disturbed the cable durng the teardown and re-assembly process sufficiently for the poor quality soldering to make its effects known.

So the soldering iron came out again for the second time in 6 months. I removed all 4 ribbon cable strands and cleaned out the pads on the PCB. I trimmed the 4-way ribbon cable back by about 1.5cms and stripped 4 shiny new ends on each strand. After tinning the bare wires with the soldering iron, I re-attached the whole cable to the PCB, freshly soldered and secure. This time, the computer fired up on the first press of the power button and I was finally able to get Windows 7 installed and restore all the documents, pictures, videos and other data from a recent backup.

I’m hoping it will be a long time before I need to get that soldering iron out again, especially if it involves a broken computer or peripheral.

Too Many Computers

Between work and home, including real hardware and VM instances, I find myself hopping backwards and forwards between 5 or 6 different machines at any given time. I also happen to use the PuTTY SSH client quite a lot. I’ve got a bunch of PuTTY shortcuts configured across my little ‘herd’ of computers to give me quick access to the systems that I access most frequently.The problem is, the shortcuts aren’t exactly the same on all of my machines.

I use Windows-based computers with both 32 and 64 bit versions of the OS installed, which means that the PuTTY binary will be in a different location between, for example, a 32-bit Windows XP computer, a 32-bit Windows7 computer and a 64-bit Windows7 computer. This makes synchronisation of my folder of SSH shortcuts across all machines slightly problematical – if I change a shortcut on the 32-bit XP machine, I can’t just copy the changed .lnk file across to one of my 64-bit Windows7 boxes and expect it to work. With this in mind, I wrote a short Python script to deal with this for me. It will recursively scan a folder containing .lnk files and update each one so that it points off to the right place to launch a PuTTY session.

Note that this script depends upon you having Mark Hammonds ‘Python for Windows’ tool kit installed. If you haven’t got this, you can download it from SourceForge. For my script, either copy and paste the code below or scroll down for a direct download link.

This version (v 1.2) incorporates a bug fix which ensures that it only updates shortcuts which refer to ‘putty.exe’, otherwise it can end up overwriting your entire Start menu if you give it the right path.

#!/usr/bin/python
# Check and adjust PuTTY SSH shortcuts
# vim: ai et sw=4 ts=4
#
# Copyright (C)2012 Phil Edwards <phil 'at' linux2000.com>
#
# License: This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or (at your
# option) any later version. This program is distributed in the hope that it
# will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
# Public License for more details.
#
# CHANGELOG:
#
# Ver    Date       Who  Changes
# -----  ---------  ---  ---------------------------------------------------
# 1.0    21SEP2012  PKE  First version
# 1.1    06MAR2013  PKE  Enhanced command line option processing
# 1.2    16MAY2013  PKE  Bug fix - only update shortcuts that contain
#                        putty.exe in the target path

import os
import sys
import time
from optparse import OptionParser
import pythoncom
from win32com.shell import shell

class Win32Shortcut:
    def __init__(self, lnkname):
        self.shortcut = pythoncom.CoCreateInstance(
            shell.CLSID_ShellLink, None,
            pythoncom.CLSCTX_INPROC_SERVER, shell.IID_IShellLink)
        self.shortcut.QueryInterface(pythoncom.IID_IPersistFile).Load(lnkname)

    def __getattr__(self, name):
        return getattr(self.shortcut, name)

class RunTimeOptions:
    def __init__(self):
        self.__me__ = os.path.basename(sys.argv[0])
        self.__version__ = '1.2'
        self.__copyright__ = "Copyright (C)2013 Phil Edwards <phil 'at' linux2000.com> All Rights Reserved"
        self.__summary__ = 'Automatic PuTTY shortcut fixer'
       
        self.puttyPath = None
        self.found = 0
        self.updated = 0
        self.defaultPath = os.environ['appdata'] + "\Microsoft\Internet Explorer\Quick Launch"
       
        if os.path.exists("C:\Program Files (x86)\PuTTY\putty.exe"):
            self.puttyPath = 'C:\Program Files (x86)\PuTTY\putty.exe'

        if os.path.exists("C:\Program Files\PuTTY\putty.exe"):
            self.puttyPath = 'C:\Program Files\PuTTY\putty.exe'
   
        self.getCommandLineOptions()

        self.logMsg(txt = '%s v%s %s' % (self.__me__, self.__version__, self.__summary__))
        self.logMsg(txt = 'command line arguments: [%s]' % ' '.join(sys.argv[1:]))
        self.logMsg(txt = 'Executable found at [%s]' % self.puttyPath)

    def logMsg(self, **kwargs):
        txt = kwargs.get('txt', '')
        dateStamp = kwargs.get('dateStamp', True)
        msgLine = ''

        if txt != '':
            if dateStamp: msgLine += '[' + time.strftime("%Y%m%d-%H%M%S", time.localtime()) + '] '
            if not self.doUpdate: msgLine += 'NOUPDATE: '
            msgLine += txt
            print msgLine

    def debugMsg(self, **kwargs):
        txt = kwargs.get('txt', '')
        dateStamp = kwargs.get('dateStamp', True)
        pause = kwargs.get('pause', False)
        msgLine = ''

        if self.debugMode and txt != '':
            if dateStamp: msgLine += '[' + time.strftime("%Y%m%d-%H%M%S", time.localtime()) + '] '
            msgLine += 'DEBUG: ' + txt
            if pause:
                bull = raw_input(msgLine + ': Press any key to continue : ')
            else:
                print msgLine

    def getCommandLineOptions(self):
        vString = '%%prog (%s) v%s' % (self.__summary__, self.__version__)

        dString = 'Script to examine PuTTY SSH shortcuts found in the folder '
        dString += 'referenced by BASEPATH and update them so that '
        dString += 'they contain the correct path to the PuTTY executable'

        eString = ''
       
        uString = 'usage: %prog [options] BASEPATH'

        parser = OptionParser(version = vString, description = dString,
            epilog = eString, usage = uString)

        parser.add_option('-d', '--dry-run',
            action = 'store_false', dest = 'doupdate', default = True,
            help = 'process as normal, but do not update any files')

        parser.add_option('-x', '--debug',
            action = 'store_true', dest = 'debugmode', default = False,
            help = 'emit debug messages for troubleshooting')

        parser.add_option('-v', '--verbose',
            action = 'store_true', dest = 'verbose', default = False,
            help = 'be more verbose when processing')

        (options, args) = parser.parse_args()
       
        if len(args) == 0:
            self.basePath = self.defaultPath
        elif len(args) == 1:
            self.basePath = args[0]
        else:
            print 'ERROR: ambiguous command line parameters'
            sys.exit(0)

        if self.puttyPath is None:
            print 'ERROR: Unable to locate PuTTY executable'
            sys.exit(0)
           
        if not os.path.exists(self.basePath):
            print 'ERROR: base path does not exist'
            sys.exit(0)

        self.doUpdate = options.doupdate
        self.debugMode = options.debugmode
        self.verbose = options.verbose

        self.debugMsg(txt = 'options = %s' % options)
        self.debugMsg(txt = 'args = %s' % args)

def processItem(my, path):
    my.found += 1
   
    s = Win32Shortcut(path)
    iconPath = s.GetIconLocation()[0]
    itemPath = s.GetPath(0)[0]
    my.debugMsg(txt = 'itemPath is %s' % itemPath, pause = True)

    if itemPath != my.puttyPath and 'putty.exe' in itemPath.lower():
        s.SetPath(my.puttyPath)
        pf = s.QueryInterface (pythoncom.IID_IPersistFile)
        if my.doUpdate: pf.Save(path, 0)
        my.updated += 1
        my.logMsg(txt = '%s updated' % path)
    else:
        if my.verbose:
            my.logMsg(txt = '%s OK' % path)

def processFolder(my, path):
    if not os.path.isdir(path): return
   
    if my.verbose:
        my.logMsg(txt = 'Processing folder [%s]' % path)
       
    flist = os.listdir(path)
    for item in flist:
        newPath = os.path.join(path, item)
        if os.path.isdir(newPath):
            processFolder(my, newPath)
        elif item.endswith('.lnk'):
            processItem(my, os.path.join(path, item))

def main():
    my = RunTimeOptions()

    my.logMsg(txt = 'Processing started')
    processFolder(my, my.basePath)
    my.logMsg(txt = '%s shortcuts found' % my.found)
    my.logMsg(txt = '%s shortcuts updated' % my.updated)
    my.logMsg(txt = 'Processing complete')

if __name__ == '__main__':
    main()
Download1185 downloads

Thank $DEITY For Disk Imaging Software

I often get called on to deal with family computer and/or data related mishaps. Disk imaging software has saved the day on several occasions recently.

The event that prompted this post actually happened a few weeks ago. Daughter #2 brought her 12 month old Acer laptop to me, complaining of random BSOD crashes. I took a quick look at it and noticed lots of suspicious symptoms straight away, for example the Windows security centre service was disabled and refused to restart, the AV system tray icon was not showing and the AV software itself wouldn’t start up. A boot into safe mode and a scan with Malware Bytes soon confirmed that the machine had been hosed by one of the many fake AntiVirus malware strains. The malware itself was able to be removed, but it had done extensive damage to the registry and the only option to ensure a full repair seemed to be a full re-install of Windows 7.

Just going off on an apparent tangent for a moment, manufacturers rarely provide physical media with a new computer. Instead, some kind of backup software is pre-installed which allows a set of physical media to be created by the end user. Whilst this seems like a good idea at first glance, my experience has been that it invariably fails utterly. The story almost always goes like this:

Amidst the excitement of getting a new laptop out of its box and having a shiny new toy to play with, the message that appears on screen requesting the creation of recovery media gets dismissed with a click on the ‘Not Now’ button.

The same prompt pops up again a bit later, by which time the owner is busy setting up their e-mail account, getting on to Facebook and posting ‘I haz new laptop’ status updates – the prompt once again gets dismissed.

Whilst this is going on, the operating system will have been silently downloading and installing updates in the background. Some of these will require a reboot, which irritates the owner because it interrupts the process of playing with the new toy.

At reboot time, the prompt for creation of recovery media appears again, only this time the owner notices that there is also a little tick box which says ‘Never remind me again’…

12 months down the line, the laptop has been used, abused and generally thrashed to within an inch of its life and suddenly starts playing up in some manner, or it gets hit with a virus. This is where I end up being asked to look at it. If it turns out that a new hard drive is required, or maybe (and more commonly, especially with a virus infestation) just a re-install of Windows to put everything back to a known clean state, the first thing I ask for is the recovery media. Inevitably the response to this is “The what?”. I patiently explain about recovery media and how they would have been prompted to create same when they first got the laptop. “Oh, yeah, I just ignored that. Was it important, then?” – at which point I’m in <herewegoagain> mode.

So, broken laptop, users data may or may not be intact, OS is definitely screwed, no data backup available. What to do? The last 3 times I’ve been in this situation, I’ve used a product called Macrium Reflect to get what I could off the broken machine prior to repair/rebuild. Together with an adapter cable to allow PATA/SATA drives to be hooked up to a USB port, recovering the data becomes a fairly straightforward, if sometimes time-consuming, exercise:

  • Extract the hard drive from the broken machine, connect it to my computer and image it using Macrium Reflect
  • Put the drive back in its host machine, launch the manufacturers factory recovery process and put the machine back to its default ‘out of the box’ state
  • Remove the vendors assorted items of bloatware, re-install any required applications software and allow Windows to apply all outstanding updates
  • Extract the hard drive from the now working machine, connect it to my computer and restore the users data (documents, pictures, videos, etc) from the disk image taken earlier
  • Put the drive back into the host machine

With the machine now in a known good state, including all user data, it is possible at this point to create a second disk image using Macrium. This can be kept on offline storage (for example, an external hard drive) until such time as the machine breaks again or gets hit with another virus. Next time round, the recovery process is much simpler, needing only a restore of the second disk image to get everything back to normal in a single operation. Even better, Macrium can be installed on the machine you just repaired and configured to take a regular backup. Provided you’re careful with storage requirements, the end user is then keeping a copy of their own data in readiness for the next disaster that strikes them.

Macrium is free for personal use and registration for the full version is US $45 for a single machine licence, rising to US $90 for a ‘household’ licence which covers up to 4 machines. The licenced version adds incremental backup features, encryption of backed up data and integration with the Windows boot menu to allow easy recovery. I’ll make the usual disclaimer that I have no connection with Paramount Software other than as an very satisfied user of their products.

 

 

Got My Slice!

My Raspberry pi finally arrived today. Haven’t decided what to do with it yet, haven’t even opened the box, in fact!

image

Oh, forgot – this article is also the first one I’ve posted from the WordPress app on my Galaxy S3, so double whammy!

Python Command Line Script Template

Despite having used Python as my scripting language of choice for several years, I still find myself stumbling across the odd ‘hidden gem’ when searching through the ‘global module index’, which is part of the documentation that comes with the language.

A fine example of this cropped up recently when I was writing some command line utilities to help with a particular project. I like to make these things as user-friendly as possible, mainly so that if someone else has to use them, they can do so without me having to write reams of documentation explaining how each one works. I also have an intense dislike for the process of re-inventing wheels, it therefore made sense to come up with some boilerplate code that I could use for each script which covered just the basics of getting command line options, providing a help feature and allowing for debug messages to be added for diagnostic purposes when testing the code.

Python comes with several modules which deal with command line option processing, each of which has its own strengths and weaknesses. The code template shown here uses the optparse module, which is able to provide all of the features that I wanted to have in my scripts, without making me re-code everything by hand for each one. I wanted each script to:

  • Provide online help for available command line options, using the accepted convention of running the script with a ‘-h’ or ‘–help’ argument.
  • Support a ‘-v’ or ‘–verbose’ argument so that there is the option to provide more detailed output when the script is run.
  • Support the use of a ‘–dry-run’ option so that a script can show what it would do, but not actually make any changes to input data or files
  • Have predefined functions for displaying status and/or debug messages

The resulting code template runs to a rather svelte 120 lines. Of these, 19 lines are comments and 24 are blank lines inserted for readability. The code below also has some extra examples of how you might, for example, specify an input file to be processed, or restrict processing to the first few lines of input data only.

You can either copy and paste the code below, or scroll down for a download link:

#!/usr/bin/python
# Skeleton script with command line parsing
# vim: ai et sw=4 ts=4
#
# Copyright (C)2012 Phil Edwards <phil 'at' linux2000.com>
#
# License: This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or (at your
# option) any later version. This program is distributed in the hope that it
# will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
# Public License for more details.
#
# CHANGELOG:
#
# Ver    Date       Who  Changes
# -----  ---------  ---  ---------------------------------------------------
# 1.0    21SEP2012  PKE  First version

import os
import sys
import time
from optparse import OptionParser

class RunTimeOptions:
    def __init__(self):
        self.__me__ = os.path.basename(sys.argv[0])
        self.__version__ = '1.0'
        self.__copyright__ = "Copyright (C)2012 Phil Edwards <phil 'at' linux2000.com> All Rights Reserved"
        self.__summary__ = 'Awesome Python script written by Phil'
        self.getCommandLineOptions()
        self.validateOptions()

        self.logMsg(txt = '%s v%s %s' % (self.__me__, self.__version__, self.__summary__))
        self.logMsg(txt = 'command line arguments: [%s]' % ' '.join(sys.argv[1:]))

    def logMsg(self, **kwargs):
        txt = kwargs.get('txt', '')
        dateStamp = kwargs.get('dateStamp', True)
        msgLine = ''

        if txt != '':
            if dateStamp: msgLine += '[' + time.strftime("%Y%m%d-%H%M%S", time.localtime()) + '] '
            if not self.doUpdate: msgLine += 'NOUPDATE: '
            msgLine += txt
            print msgLine

    def debugMsg(self, **kwargs):
        txt = kwargs.get('txt', '')
        dateStamp = kwargs.get('dateStamp', True)
        pause = kwargs.get('pause', False)
        msgLine = ''

        if self.debugMode and txt != '':
            if dateStamp: msgLine += '[' + time.strftime("%Y%m%d-%H%M%S", time.localtime()) + '] '
            msgLine += 'DEBUG: ' + txt
            if pause:
                bull = raw_input(msgLine + ': Press any key to continue : ')
            else:
                print msgLine

    def getCommandLineOptions(self):
        vString = '%%prog (%s) v%s' % (self.__summary__, self.__version__)

        dString = 'A super awesome Python script. Phil wrote it, so it must be good! '
        dString += 'It does all sorts of really cool stuff, and even has some flashing '
        dString += 'lights to keep you amused.'

        eString = 'OK, maybe I lied about the flashing lights, but the rest '
        eString += 'of it is really good'

        parser = OptionParser(version = vString, description = dString, epilog = eString)

        parser.add_option('-d', '--dry-run',
            action = 'store_false', dest = 'doupdate', default = True,
            help = 'process as normal, but do not update any files')

        parser.add_option('-x', '--debug',
            action = 'store_true', dest = 'debugmode', default = False,
            help = 'emit debug messages for troubleshooting')

        parser.add_option('-i', '--input', dest = 'inputfile',
            #action = 'append', # lets you have more than one file if required
            help = 'read input data from FILE, which must exist', metavar = 'FILE')

        parser.add_option('-l', '--limit', dest = 'limit', type='int',
            help = 'limit processing to the first NUM items found', metavar = 'NUM')

        parser.add_option('-v', '--verbose',
            action = 'store_true', dest = 'verbose', default = False,
            help = 'be more verbose when processing')

        (options, args) = parser.parse_args()

        self.doUpdate = options.doupdate
        self.debugMode = options.debugmode
        self.verbose = options.verbose
        self.inputfile = options.inputfile

        self.debugMsg(txt = 'options = %s' % options)
        self.debugMsg(txt = 'args = %s' % args)

    def validateOptions(self):
        if self.inputfile is not None and not os.path.exists(self.inputfile):
            self.logMsg(txt = 'ERROR: file %s does not exist' % self.inputfile, dateStamp = False)
            sys.exit(0)

def main():
    my = RunTimeOptions()

    my.logMsg(txt = 'Processing started')
    my.debugMsg(txt = 'This is a debug message with no datestamp', dateStamp=False)
    my.debugMsg(txt = 'This debug message has a datestamp')
    my.debugMsg(txt = 'Debug message with datestamp and a pause', pause=True)
    my.debugMsg(txt = 'Debug message without datestamp, with a pause', dateStamp=False, pause=True)

    my.logMsg(txt = 'Processing complete')

if __name__ == '__main__':
    main()
Download a copy1201 downloads

The site finally gets an update…

The original linux2000 site layout was designed in 2002 and was starting to look extremely dated and generally just very web-1.0. Added to that, it wasn’t as easy to make updates as I would have liked. The new site is on a dedicated server and is based around some reasonably up to date blogging software, so look out (hopefully) for slightly more regular updates in the future.

Not all of the content from the old site has been transferred yet, but being the king of procrastination that I am, I’ve spent weeks agonising over colour schemes, menu layouts, etc, etc, so I came to the conclusion that if I didn’t just do the DNS change to make the new site live, it would ever happen. So enjoy – I’ll get the rest of the junk uploaded as and when I can!

Logbook Summary

I’d had a yearning to fly since the age of 13, when I was a cadet in the ATC. I started studying for a group D licence, i.e. microlights, in 1991 and had clocked up less than 4 hours when I suddenly found myself out of a job for around 9 months. In the years that followed, I found another job, moved to the south coast of England, changed jobs again, met the girl who would later become my wife, got a mortgage, had 2 children, etc, etc, etc. Before I knew what was going on, more than 10 years had passed and I had almost forgotten all about flying, until my 40th birthday arrived…

This is how my flying experience stands at present. The full JAA-PPL is just too expensive for me to contemplate at this point, so it”s back to microlighting for me! The minimum requirement for a NPPL with microlight rating is 25 hours and very few people manage it in the minimum time. I”ll just keep telling myself that…

 

  • Last Lesson: 26 June 2011
  • Total Time: 11h 10m
  • Next Lesson: n/a

Aerobatics!

What an amazing way to spend 30 minutes on a sunny Sunday.

I was given a voucher at christmas time by SWMBO for a short flight in a Stampe SV4 at Shoreham. An irritating combination of bookings cancelled due bad wx, work commitments and the aircraft being away for an extended period for maintenance meant that I didn’t get to use my voucher until today.

All I can say is that it was well worth waiting for!

After strapping in and watching while the prop was hand swung, I had my first go at taxying a tail dragger. It seemed to take an age to get any response when pushing the pedals, but when it finally did start to turn, it turned like a dodgem car. Is this common to all tail wheel aeroplanes, or more likley to be just my lack of experience?

We took off and pottered along the coast, heading for Brighton Marina. I took the opportunity to get the feel of the controls, starting with some gentle turns. As I began to feel a bit more confident, the bank angles started to increase until the instructor was happy for me to be twirling us round each wingtip at 60 degrees or more of bank. Great fun and probably not something I’d be allowed to do in the C42 that I’m more used to.

The first aerobatic maneouver was a loop. Using Brighton pier to orient ourselves, the instructor pushed the nose down and let the airspeed build up to 110 knots, then smoothly pulled back. The sensation as we went over the top and I looked up at the sea was incredible! A reasonably tight turn out to sea, climbing back up to about 1800 feet and we pointed back at the pier to have another go. This time I was asked to follow through on the controls to get the feel of the stick forces involved. Paying slightly more attention this time, I noticed the wind singing in the wires next to me as the airspeed bled off at the top and found myself looking straight down at a matchbox sized model of a yacht as we pulled through and back up to level flight. For the 3rd loop, I got to work the stick and throttle myself with the instructor following me and correcting for any mistakes – I’m sure there were several!

We continued along the coast and did the usual ‘ooh, I can see my house from here’ bit. Turning slightly inland, a roll was the next order of the day. Apparently the Stampe has a tendency for the engine to cut on a roll if you’re too ham fisted with it. 99 times out of 100, it starts up again without any problems just by the propellor rotating in the airflow, but the instructor wanted us over the dry bit rather than the wet bit, just in case…

The roll wasn’t quite how I’d imagined it to be. Dive slightly, pull up and stick over to the left and roughly half way forward until we came back round to level again. I’m sure there was something going on with the rudder pedals, too, but it all seemed to happen so quickly I wasn’t sure. We did another 2 of those as well just for good measure, but I didn’t make a particularly good job of following the control inputs.

I was surprised to find that despite this being my first time doing aerobatics, I wasn’t feeling even a tiny bit queasy. Having too much fun I guess!

Regrettably, that was almost the end of the half hour. I was told ‘your aircraft’ and the instructor asked me to fly us along the ridge of the downs back towards Shoreham for a right base join into the circuit for runway 13. As we approached the circuit I handed the controls back and just enjoyed the view as we settled gently onto the grass, then taxy’d back to our little parking spot near the pumps and the fire station.

It was perfect weather today for an introduction to the slighly more hooliganistic corners of the flight envelope. The grin still hasn’t quite worn off, nearly 5 hours later. A big thumbs up for Ian and the rest of the guys/girls at PerryAir and, of course, to my wife for having the idea in the first place!

Now, who wants to demonstrate a stall turn or 3 for me…? 😀

Getting My Mojo Back

After the debacle that was my last lesson, I was keen to get back in the air to try and redeem myself a little. Once again, however, a combination of work and domestic commitments, bad weather and straight forward lack of cash meant that another 8 weeks went by with no aviation being committed. I tried to pass the time constructively, spending my lunch breaks with my head in my books, staring intently at cloud formations and plotting pretend cross countries on my quarter mil chart.

The weather on Thursday and Friday looked decidedly un-cooperative. It started to look a little more hopeful on Friday night, with a long cold front passing from west to east over the south of the country, promising better weather behind it. The forecast winds were still at around 25 knots gusting to 30, so I had to wait until the morning to see what transpired.

I got up at 8:15 on Saturday morning to find a bright day, slightly damp on the ground where there had been rain just after sunrise and a light breeze from just south of west. As the sun climbed higher up in the sky, heating the ground and stirring the air up, the wind picked up a little. I called Keith at just after 9:30. He lives about 10 miles to the north of me and after comparing what we could each see in terms of weather, the verdict was that we wouldn’t be able to get over to Headcorn for circuits but a local training flight might be do-able.

I arrived at Deanland just as Keith did. We opened up the portakabin, put the kettle on and walked out to the middle of the runway to see what was happening. The instability in the air was obvious from looking at some of the cumulus clouds to the north and east of us. You could actually see the tops billowing upwards in the heat from the ground. To the north of the field there was a rainbow arching over the Downs, and the rain falling in the distance was clear to see. We decided to get the aeroplane out of the hangar and get it pre-flighted, then see what the weather was doing. As we were doing this, and as if to confirm the rain that we’d seen earlier, Keiths wife rang to let him know that the heavens had opened and it was pouring down over his house. By the time we’d done that, things had calmed down slightly, although there was now a fairly stiff breeze whipping almost straight down runway 24. To add to the indecision, the windsocks at either end of the runway were pointing in different directions, which I’m told isn’t at all unusual at Deanland.

We made coffee and went over the briefing for a navex to Headcorn, even though it was highly unlikely that we’d be able to make it over there. As we talked, the airfield itself gradually came to life around us, with people arriving and poking their heads round the portakabin door to say hello, grumble about the weather and offer their opinions on what was likely to happen over the next couple of hours. That took up the best part of 45 minutes, by which time the cloud tops had stabilised and the wind had dropped slightly and wasn’t so gusty. Keith pushed his chair back from the desk and said, “Come on then, lets do some flying while we can!”.

Keith pumped a jerry can full of fuel into the C42 and we climbed in. As per usual, it started on the first press of the button and I taxied to the end of the runway and turned into the wind for the run-up checks. I had to be reasonably brisk about getting us lined up and off the ground, as there was someone in the circuit on mid-downwind, so I didn’t want to either have to wait for him or force him to go around by not being quick enough.

The climb out was a little bumpy but not too bad, with the air smoothing out considerably as soon as we got above 1,000 feet. When we briefed the actual lesson we were going to fly, Keith had stressed that he wanted to see me taking more care over attitude and airspeed and at the same time not let my look out suffer as a result. I levelled us off at about 1,800 feet and let the aircraft find its own way through the patches of sink and lift while I concentrated on keeping the nose in the right place and the wings level. I was pleased to find that despite not having flown for 8 weeks, I was nicely relaxed on the controls and able to keep us on heading and track without having to think too hard about what I was doing before I needed to do it. It’s difficult to describe exactly what I mean, but the whole act of flying today just seemed to ‘flow’ more smoothly. The gliding site to the north of the field was active, so we headed off towards the coast for some of what I believe is termed ‘general handling’, i.e. chucking the aeroplane about just for the fun of it! Keith then had me climb up to about 3,200 feet chasing holes in the clouds. By this time we were just out over the sea, so we turned into a gentle descending spiral to the left down to 1,700 feet, heading off to Pevensey marshes to see if I could remember how to carry out a forced landing. Again, I found that it all came fairly easily, there was the usual concentration on keeping the aiming point in sight, adjusting the turn to keep the constant aspect, and I found that as soon as I was thinking, “Bit low, roll out a bit”, or “Wind is pushing me away from the field, turn in a bit more”, Keith would say the same thing half a second later. It seems like I’m actually starting to learn how to fly!

As we climbed back up, I pointed out to Keith that I’d passed a flying milestone about 5 minutes previously. The total number of hours in my log book is now into double figures at last! It’s taken 19 years from the very first entry to the one that I put in today. I wonder how long it will take before I get into triple figures?

We did some steep turns (which I must admit I always enjoy!) and slow flight next, pulling the power right back to get us down to 60 knots with the first stage of flaps then keep hauling the stick back until we got down to 50 knots, then holding it there, paddling on the rudder pedals to keep us in a straight line. Keith asked me to get the aircraft into a descent at 60 knots, aiming for a point on the horizon, so I pushed the power back up, pulled the nose up a touch and did another little dance on the pedals as we went down at 500 feet per minute. As we levelled out at just under 1,000 feet, we noticed a fairly expensive looking helicopter on a curving path in towards us from the west, descending as he went. He made a pass over a large-ish field at about 500 fet below us and turned back onto a downwind heading just as he passed almost to the limit of where I could see him out of the right hand window. Keith asked me to turn to the left to get us pointing in roughly the right direction for Deanland. To my great surprise, I decided I didn’t want to do that. I said, “Actually if you don’t mind, I’m going to make a right turn instead. If I go left, I’ll be turning my back on that helicopter and I won’t be able to see what he’s up to”. With that, and without waiting for Keith to say anything, I rolled us about 20 degrees to the right, at which point I could see the helicopter again, this time he had descended more and was lining up for an into wind landing in some farmers field at the back of a house that I hadn’t seen earlier. Satisfied that he wasn’t in a position where I had to worry about him any more, I turned back to the left and we headed off to Arlington reservoir to join the circuit downwind. I think that that may possibly count as my first totally independent command decision in an aeroplane.

Back in the circuit, we started getting bounced about a bit on the late downwind leg, with the chop getting worse on the base leg. Reducing speed to 60 knots again, I turned onto final and immediately had to get on the rudder pedals to keep the gusting cross wind from pushing me towards the adjacent field. I’m still having trouble judging height on the approach, so Keith had to prompt me a couple of times to increase power to allow for the gusting wind and the turbulence. As we descended to just a couple of hundred feet off the ground, we hit a patch of sink over the edge of the trees, causing the aeroplane to suddenly drop about 20 feet all at once, prompting a “Whoah” from me and a “Bleedin hell!” from Keith. The landing was seriously hard work on both stick and rudder, I was fighting with the crosswind all the way down to about 10 feet off he ground, where it all smoothed out again. We settled onto the grass, but the C42 clearly wasnt quite ready to stop flying yet, as it did a very gentle bounce and climbed a couple of feet back up into the air. I held the stick whre it was and let it settle again, this time we stayed on the ground and rolled out in perfect time to pull off to the left at the very end of the runway and taxi down to the hangar. We shut down and went back to the portakabin for a well earned (in my opinion anyway!) coffee together with a short debrief. I couldn’t help feeling pleased with myself when Keith said I’d been flying brilliantly.

So, I’ve still not got to Headcorn for circuit practice, but today was a great lesson, very enjoyable and just what I needed to boost my confidence again.