« December 2005 | Main | February 2006 »
January 31, 2006
Loosing breath with Gerald
John walked in to the training course this morning and he was very much out of breath. "Usually it takes me 25 minutes to walk to work" he said "but this morning I walked down with Gerald - my goodness he walks quickly - I was here in 10".
I offered a few words of sympathy and quietly wondered at Gerald - couldn't he see that his fast pace wasn't appropriate for John?
Jack came in and was chatting with John. "Oh yeah - no-one can keep up with Gerald" and there was some joke or other about his nickname - "six legs Gerald".
It twigged a bit later (and with some further clues). Gerald does have six legs - two are his own and four belong to his guide dog and, no, he couldn't see that he was walking too fast for John.
Posted by gje at 06:56 PM
More about Graham Ellis of Well House ConsultantsRemember to process blank lines
I've got a Perl program that processes a data file 200 lines long.
15 of the lines are comments that start with a # (I test for those using ($line =~ /^#/), and 181 of the lines contain real data - in other words they start with a character that's not a # - my regular expression match reads ($line =~ /^[^#]/).
Whole file processed? No! There are 200 lines in the file but I've only processed 196. Although you'll think inventively that a line starts with either a hash or a character that's not a hash, there's a third case - a line that doesn't start with any character at all, i.e. a blank line. That's where my extra four lines have gone.
Rather than using two if statements to process all the lines, and match up the conditions, I should have used if and else. That way I can have my program securely find the "others" rather than having to work out potentially buggy code to do so.
Being Perl (where there's half a dozen ways to do anything), there are other good solutions such as writing the same condition twice but using the !~ operator in place of =~ to get the inverse set, or using an unless statement, or doing the test just once and saving the result as a boolean - $iscomment = ($line !~ /^\s*[^#]/);.
Posted by gje at 06:58 AM
January 30, 2006
DWIM and AWWO
"Do what I mean". One of the new buzzwords for Perl 6.
I first heard the new term "DWIM" mentioned some three or four years ago and it's a noble target. And I thought of it again last night as I was looking through hotel reviews and considering how we'll react to customer comments - indeed how we can ensure that people are happy from the start rather that having to fight any fires.
Instead of DWIM - do what I mean
how about AWWO - advertise what we offer.
"The information pack said the bar would be open but it wasn't".
"The accommodation was in a separate block, not in the main building - I don't recall this being pointed out anywhere."
""The photo is deceptive as it looks like a country farm house ..."
AWWO - Advertise what we offer! I hope we get nothing like this with Well House Manor. Of course, we wouldn't as there won't be a bar, there won't be a separate accommodation block and it couldn't even be fiddled to make it look like a farmhouse but I'm sure you get my drift
On Friday, I was making a late hotel booking for this week - I'm away in Staffordshire - and I phone up a hotel and enquired for a double to be let as a single. "We've only got a single, I'm afraid". I asked a couple more questions and established that it's a small single too - not really room to work as I need to in the evening, and sitting in the bar with my laptop isn't my style, so I politely said I would look elsewhere. A sale lost to the Peak Weavers? Yes - in the short term. But in the longer term I'll remember them and try them next time I'm in the area and someone might even follow the link in this article ...
Posted by gje at 12:47 AM
January 29, 2006
Saving a MySQL query results to your local disc for Excel
Do you want to run a database query on a remote server and save the results into a text file on your LOCAL disc - i.e. the disc of the computer at which you're seated and not the disc of the server that's in a remote location?
It's not as easy as you think it should be. Because of the security risks involved, you cannot save to LOCAL OUTFILE from a SELECT in MySQL, even though you can read from LOCAL INFILE in a LOAD. Reading in known data is OK, but saving what could be malicious or confidential information away from the server is quite a different kettle of fish.
Solution?
One possibility is to wrap your query in a web page, and allow your browser's facilities to store the result set locally. In other words, to put up a form and have the user enter his query in that. When submitted, the user's browser deals with the security issues of saving the data locally using the security preferences already set up by the user for his browser..
I've written a sample script to demonstrate the saving of a query result to a local .csv file. You could change the comma to a tab separator for your own use and that way you'll get a page that save a databases to your local system suitable for import to spreadsheets such as Excel.
Run the script here
View the source here
Other common questions on MySQL answered here
UPDATE - Summer '07. See also additional comments about the header() function and changes needed to the original script for new PHP versions!. Thank you.
Posted by gje at 06:12 AM
January 28, 2006
What to do with milk
We follow an old British tradition - we have milk delivered in bottles every morning, and our Milkman's here before the sun rises. I think he was away last week and a standin was doing his rounds - the milk was left on the front step rather than in the rack by the side door, and on several mornings it was still there when our first visitors of the day rolled up.
Who were our visitors?
On one day, bankers. On another day, civil servants. On a third, our own team.
What did they do when they saw the milk still on the step?
On one day, carried it in for us. On another day, pointed it out to us. And on the third it was left - I don't know if that group even noticed.
But can you guess which group took which action?
Added ... 2nd Feb. Want to know the answer? See forum discussion on the topic.
Posted by gje at 09:49 AM
January 27, 2006
Short Linux and Perl courses for small groups
Around a half of my training time is spend presenting public courses - the other half goes on private courses to groups ranging in size from a handful of trainees up to (in exceptional cases) 15 or 16.
Every customer has a slightly different requirement ... so wants a slightly different agenda. Our module-based training notes allow us to add and subtract elements to tailor private courses to provide what's needed by the client, without stretching the length and covering other interesting but irrelevant topics. I'm writing about this now because I've just put together two private course programmes and felt they're worth sharing as an example of what we can do.
The Perl Bootcamp is a fast start Perl course, covering the basics of the language for newcomers to Perl who are, however, experienced programmers. Lasting for three days rather than the five days of courses like Perl Programming, it's presented for a single target application to a group who know each other well before the course even starts. We know that the course will run on after 5 p.m. each day, and we know that this customer will truly provide delegates who are all very much at a similar level, and this gives us great confidence that the intensive approach will work well for them.
Our Linux Admin Bootcamp covers some of the basics of Linux systems admin again as a very fast course for a small group of trainees who are already very familiar with Linux as users. We know there will be no need to slow down to remind people of vi, or how to rename or delete files ...
Posted by gje at 01:20 AM
Useful links: Linux training, Perl training
January 26, 2006
Woman screaming at me
An irate woman stood in front of me. "I want you to stop keeping my Darren behind and let him leave at the time that everyone else can go" she demanded.
School scene? No - this was at work, and Sharon had marched in, past the bemused receptionist and up to my desk, and Darren was her husband and not her son. The incident happened some 20 years ago, but it's still fresh in my mind.
I love having enthusiastic people working alongside me - it makes for a fabulous team, for a job well done, for a customer base that's happy and growing and it makes the job fun for all. And a motivated team member will look not only at their own role, but beyond it. They'll make those useful suggestions that make the whole machine more efficient, they'll notice those odd little extras that need doing, and quietly do them, and they'll be "worth their weight in gold". Ok - let me rephrase that - they'll be an asset that's worth paying very much over the odds for their participation.
I think that everyone has it in them to be an enthusiast - it just takes a while to find the right position sometimes, and sometimes there are going to be conflicts between different facets of someone's life. It's a question of finding a round peg for a round hole, and a square peg for a square hole. There's times that holes can be eased to suit a peg, and times that pegs can be shaved to fit (but, hey, I'm not in the peg-shaving business). And alas there are times that you find you've got a peg and you're left looking all over the board and having trouble finding a suitable hole.
Why was Sharon yelling at me? Was I punishing Darren like some naughty kid? No - he was a bit of an enthusiast - he designed us some amazing video mixing board was back in the '80s when such technology was in its infancy. And he loved to stop around after the end of his formal day and learn a little more of software which was new and intriguing to him; with his own office key he was stopping around, it turned out, long after the rest of us had headed for home.
There was a new, yelling baby at their little home. He could have headed off to the pub at 5, but that's not the sort of peg he was ... his learning more about his software was his hobby. Now that's the sort of team member who with just a little bit of guidance was a real asset to the team.
Sharon - thank you for shouting at me. You opened my eyes.
Posted by gje at 08:06 AM
Learning to program in Perl or PHP
* Course - Perl for Beginners.
* Tutor lead lessons - Learning to Program in PHP.
* Classes in MySQL from the ground up.
Our IT industry can be so inward-looking at times! Many training courses are really conversion courses where a programmer skilled in language P learns language Q. Such courses are certainly a product for which there's a market need, but there's also the need for a different product - "Learning to ..." courses.
I was on a cruise to Alaska with Larry Wall (the guy who wrote Perl) together with a bunch of around 100 other enthusiastic practitioners, and someone asked Larry if he would recommend Perl as a first language. "Sure, why not" was his reply. Mind you, taking a survey of the group, most of them had started with something else. So ...
There's a lot of very bright people out there who are "computer=savyy" or "net-aware" but have never programmed or designed a database in their lives. Quite simply, they've had too much else to do from blowing glass to offering legal advice, to reporting for the local paper. But something brings them to PHP or to MySQL. The need for a specialist statistical analysis of some data perhaps, or a requirement to make information interactively available through a web site. And it's very hard to find an absolute beginner's course for such people.
Personally, I love running some of our more fundamental courses. To see the real and very effective results - and pleasure too - that people get from what is rarely rocket science. A joy, and a customer's requirement well met. I appreciate that many tutors feel that the more fundamental stuff is beneath them, or assume that their class knows these things; that's fair enough on a course that's labelled "intermediate" or "advanced".
If you're learning Perl, or PHP or MySQL or Tcl from scratch, we can help you with a training course - (matrix). If you're learning Python or Ruby from scratch, we can probably help too; please email me and let me know a little bit about what you're looking for.
Posted by gje at 06:48 AM
Useful links: Perl training, PHP training
January 25, 2006
Why run two different web servers
You wouldn't choose to use a Ford Ka as your car for that holiday of a lifetime travelling across Europe, neither would you choose a Jaguar as your idea car for the school run. Yet both of them are perfectly good models of car. Indeed as a family, you might have one of each.
Apache httpd and Apache Tomcat and both web servers. You can have either of them listen on port 80 for requests in http and answer those requests. But just as the luxury Ford - the Jaguar - was great for that holiday and the budget Ford - the Ka - was great for the school trips, so each has its own use and place.
Apache httpd - the original Apache Web Server is sometimes just called "Apache" still. It's great for serving out static content - HTML pages that don't change, Images, style sheet, and also shorter scripts and quieter site activities with the scripts often written in Perl or PHP. Apache httpd is pretty common - I think I've seen comment that it's the server that fronts as many as 70% of all registered domains worldwide.
Apache Tomcat is a different beast. Rather than serving each page "ad hoc" as it's called up, it runs web applications in containers and it keeps them running, handling requests from multiple users, with the application staying in the computer memory. In contrast to httpd, Tomcat is great for the big sites - on line banking and passport applications, shopping sites for huge supermarkets, end the like.
Just as a family might have a Ka and a Jag, so a web site might be run with both httpd and Tomcat. In fact, it would be much more common that having two cars as both servers are open source and only cost you memory and resources. It's usual for httpd to be the user-facing server since so many requests made are for odd images, help information, style sheets and the like. Then httpd calls on to Tomcat in the case of meatier requests. Properly configured, the user doesn't even need to know that the web server he's contacted has passed his request on and is just acting as a relay station.
Links:
Course - Deploying Apache httpd and Tomcat
Connection Apache httpd to Tomcat - 7 ways to do it
Posted by gje at 03:26 PM
January 24, 2006
Eating for the single business traveller
Hello from Southend, where I'm giving a private course on Apache httpd and Tomcat. Last night, a cold January evening left me preferring to stick around my hotel and the attached restaurant / pub rather than traipse down to a blustery Seafront, and that gave me an opportunity to catch up on some sleep after an obnoxiously early morning too.
When I walk into a restaurant as a lone traveller, I always take something of a deep breath. These places are designed for groups - eating out is a social event and us business visitors are somewhat forced into sole dining in a place we don't know anyone else from Adam. I recall a brave alternative which I hope to emulate one day, where all lone diners are seated together. For a specialist business accommodation / conference centre it can work well, though I'm not so sure that it would at a more general place such as the Strawberry Field where I am now.
But they DO have some things right at the Strawberry Field. Cards on the table that you can turn over to say "this table is occupied" when you go up to the bar, for example. Doesn't that sound such a little thing. Well - it IS a little thing to provide but it sure makes a big difference at times. It's very awkward for all concerned when a singleton leaves a table (for loo, to order, etc) during a meal and another person or group comes along, doesn't see perhaps a book left at a place, or a coat on a chair, and gets seated. Been there ... on both sides!
Service - I've a suggestion that singles meals should be prioritised - served quicker. The best part of half an hour waiting for food is fine if you're chatting with the partner, or having a business meeting or discussing how "The Blues" did at the weekend. Alone, waiting, time can drag. I've no proof, but there's a chain I sometimes used that I use that I swear DO take that extra care, and tell their wait staff to stop for enough time to say a couple of words too. And it makes all the difference.
Alternatives ... a quick cheap and cheerful trip to MacDonalds, KFC, Burger King or the like (yes, I frequently use them when away) or getting a takeway and taking it back into my room. Great solution this last one if I've work to do or had a long day, but I always feel slightly guilty when I carry my bag of loot back past reception.
Now if the hotel clearly welcomed people bringing their own food in (and remember they don't have room service) - perhaps by providing a plate, or knife and fork - wouldn't that be great. For sure, a few less grumpy old men in the restaurant next door (they didn't have the staff to cope anyway!), but a number of happier visitors who could become firm regulars if they're staying - in the example in question - here in Eastern Essex.
Posted by gje at 07:14 AM
January 23, 2006
PHP - dividing a string up into pieces
"There's a function to do that ..." is the oft-used answer to many questions asked of PHP, but naturally that's followed by a plea of "what's it called". If you're looking to divide a string into a series or pieces, choose from these.
explode Returns an array, elements divided at a particular separator
strtok Returns the next element (token) each time it's called.
substr Returns a part of the incoming string based on position and length
split Returns an a array of elements divided at a case sensitive POSIX regular expression
spliti Returns an a array of elements divided at a case insensitive POSIX regular expression
preg_split Returns an array of elements divided at a Perl style regular expression
fgetcsv Reads a line from file and return it as an array. Input format is comma (or tab) separated variables, where delimiters can be included within quoted strings without causing an extra element to be generated.
unpack Unpacks the data from a binary string into an associative array
You can also use ereg, eregi and preg_match to match a string and return an array of interesting bits ... you could consider that to be yet another way to divide a string into pieces.
Posted by gje at 02:20 AM
Useful link: PHP training
January 22, 2006
Giving an excuse for Christmas
From a message dated 20th January: "being just after Xmas they are swamped".
Hmm ... a very late use of that excuse, and an indication that the supplier in question gets lots of returns, and doesn't actually gear up for business peaks which they can and should predict.
Watch our for "the Christmas excuse" at this time of year! I can recall several occasions in the past chasing up grossly overdue payments during January and being offered Christmas as the reason they were late ... even in some cases where payment should have been sent well before the holiday.
I recall asking one accounts clerk if they hadn't realised that Christmas was coming up and it had caught them by surprise. She had no answer, and I'm not pleased with myself for such a catty remark to some poor office junior. But, gee, there's such a huge amount of effort that goes into making excuses when SORTING OUT THE ISSUE would take less effort.
Posted by gje at 02:16 PM
Giving the researcher power over database analysis
Sometimes, you'll be able to define the queries you'll be doing on a database to a number of specific types, but in other applications you'll be able to narrowly define how you do your joins, but you'll have a wide variety of extraction requirements. This sort of requirement is typical of medical researchers, who have a database of information that they've gathered over the years and they want to look at the results in all sorts of different ways in order to find patterns and trends in the data. From such patterns and trends will come the clues from which an understanding develops, and from which in turn, and in time, a cure can be found.
So how do you ensure that the strange and adhoc queries that you wish to run maintain the integrity of the background data? One very good way is by fronting your MySQL database with a PHP script which forces you to do the correct joins between the tables to ensure the data integrity, but gives you full flexibility in the columns you select and in your where clauses.
On the course concluded last Friday, I wrote a demonstration PHP page to show this type of application, and as it's of general interest I've put all the source code and help files up on this site. I've also installed a full working copy on our server if you wish to try it out. You're very welcome to log in as demo with a password of xxx111.
This is a VERY flexible application. I could just change a few configuration lines and it would switch from estate agents and houses for sale to some totally different set.
If you want to learn how to write an application like this yourself, or how to tailor and look after mine, have a look at our PHP courses and MySQL courses. If you're already into PHP and MySQL, our Opentalk Forum provides a venue where you can ask any remaining questions you have and discuss the best techniques.
Posted by gje at 01:13 AM
January 21, 2006
Well House Manor
The background - we've been running open source training courses in Melksham for more than 5 years, and we foresee ourselves doing so into the future. We love the town, we have a good customer base, and the work is great fun as well as being work.
Being in a niche market, our delegates travel far and wide to our courses (that would be the case wherever we were based) and around 80% of them stay at local hotels and B&Bs. But alas - from a flood of good places in 2000 we've moved to something of a famine. We're also finding that, more and more, our delegates need office facilities where they're staying, wish to pay by credit card, and have a few other requirements.
In a few months' time, we'll be offering public and private training courses here in Melksham at our current training centre that includes accommodation and breakfast, which will be provided just up the road from us at Well House Manor - currently "The Old Manor" B&B where many of our delegates already choose to stay. We'll own Well House Manor ourselves, and oversee its operation.
Key features will include:
* All rooms en suite, with double or twin beds (but let as business singles).
* All rooms fitted with flat screen TV, work desk, plenty of power points.
* All rooms will be smoke free.
* Uncapped wireless and wired internet access facilities.
* Business facilities include copier / scanner / black and write printer
* Payment included in your course cost or payable by credit card.
* Continental breakfast provided from 7 a.m.
* No evening meal service, but you are welcome to bring food in from one of the many local takeaways if you wish.
* Well House Manor will be exclusively reserved for delegates during busy courses.
* Car parking on site for all guests (although we know a lot of you come by train or share with colleagues).
Around and about:
* Well House Manor is set in a large garden around which delegates are welcome to walk.
* Bus routes X72 (hourly to Devizes and Bath) and 237 stop right outside.
* Well House Manor is just 2 doors from the local Spar shop and garage, open from 6 a.m. to 10 p.m.
* You're 5 minutes walk from the town centre.
* You're 10 minutes walk from our training centre; it's your choice whether you walk or drive - you're welcome to leave your car at either location.
Further afield:
* There's plenty of lovely countryside around and the Kennet and Avon Canal passes close by
* We're 4 miles from the National Trust village of Lacock, 6 miles from Corsham
* 6 miles from Devizes and 12 miles from Bath, both reachable by bus from outside the front door, or by car.
* The Marlborough Downs and Salisbury Plain are just a few miles away.
* Avebury stone circle and the Westbury White Horse are less than 30 minutes drive.
* Stonehenge, Longleat, Marlborough and Salisbury are all within an hour by car.
Getting to us:
* Melksham station is currently served by 10 trains a day. Fastest journey from London is 90 minutes.
* We're 100 miles West of London, just 20 minutes off the M4 Chippenham exit.
* Melksham is on National Cycle Route 4, and we have secure storage for cycles.
Once we're up and running smoothly with our own delegates, Well House Manor will welcome weekend visitors to Melksham who are looking for a quiet base from which to explore Wiltshire and the surrounding counties. We're also planning to accept bookings from business visitors to other Melksham businesses who require such facilities as the business centre access we'll be providing. We'll not be looking for walkup trade, and our facilities won't be appropriate for budget bookings. We'll routinely let any room for single or double occupancy, but we won't have family rooms nor any facilities to accommodate families - that's just not our market and there are other places that can help you - we don't regard ourselves as competition to any other providers as we're offering a specialist and different product.
You may like to look further:
The embryonic Well House Manor web site
Updating index of related resources
Project pages on our main site
Register for updates (mailing list)
Other accommodation in Melksham
The contact number for Well House Manor will be 01225 709638 - that will reach our booking and administration desk. The number is already in service and manned from early in the morning to late at night. Faxes via our main fax number - 01225 707126. At this stage we can't be sure of opening dates and indeed it's possible that the whole project falls through if we don't get appropriate permissions, but I'm sufficiently confident that any issues that arise will be quickly resolved to be talking about it in detail.
Posted by gje at 06:15 AM
January 20, 2006
Features and Benefits
Many years ago, I was sent on a sales training course. Truth be told, I didn't want to go but I had a wise boss and I decided to make the most of it. And it turned out to be something that I look back to with some pleasure as it did so much for me. In other words, it was a huge benefit. It provided me with things I needed, with solutions to things I needed solved.
You'll notice I'm not telling you about features of the course such as where it was, what the hours were, or where we ate lunch. I'm not even going through chapter and verse headings of the subject matter. I'm telling you about the benefits for me.
Today is the final day of a PHP course. I'm starting the day by converting features that we've been talking about earlier on into a real live application that's closely akin to what the trainees will be using PHP and MySQL to do - a huge benefit to them to go away with a template for their application and the thing that they'll remember the course fondly for in the future.
Posted by gje at 06:36 AM
January 19, 2006
Instructions for bright people
"Graham, I doubt that the guy will understand that." writes another contributor on a forum where I post, following up on my instructions to change a password and login name embedded within a sample script.
On one hand it's easy - all too easy - to overcomplicate instructions and to go into too much detail. But on the other hand there are many geeks out there who feel that others who don't know a topic as well as they do are somehow lacking in an ability to follow anything but the simplest of instructions.
I find that a huge majority of people that I train, and a majority of those I answer on forums and by email, are bright - very bright. They've got the ability to do a lot more than my geek friend who followed up gives them credit for, and they can (and do) ask supplimentary questions if they need to. To refuse to answer a question, which was being advocated on this thread, is to deny the questioner any chance of learning and taking his requirement forward, and it's also to deny anyone else who's interested that opportunity too.
Posted by gje at 09:32 AM
January 18, 2006
NB ''Aspiration''
I was walking around the back streets of Melksham with morning and I passed a house with a steel narrow boat on the drive; covered in tarpaulins and with some green algae / moss growing on what had been, I'm sure, pristine black paint work at one time. Grass was growing up through the flagstones around the boat, and an old car and motor bike were lying around too.
A twinge of sadness; I shared a narrow boat - Blyth Spirit - with the family for 20 years. We bought her when son Chris was a toddler, and sold her after he got married. Chris and Kimberly (born after we bought 'the boat') could crew and drive her as if she was a part of them. Many, many good times on board - and some interesting and eventful days that we look back at and smile at through the rosy tinted spectacles of time. I can remember waking in the middle of the night to a drunken group of 20 using the boat as a table for their beer bottles (and just me and Kimberly, then around 11, on board). And waiting for Lisa at Hatton station with Chris, friend Hugh and other sufficiently bored to be spitting on the platform and trying to make patterns in their spit. Rosy spectacles.
A year or so back, we sold Blyth Spirit. Increasingly busy times, and a boat that needed a little more TLC as she got older, meant that we used her less than was practical and kept me awake at night worrying about when I was next going to get to the boat yard to keep her running. Increasing bureaucracy - the equivalent of a boat MOT scheme that changes and set tighter and retrospective standards as time went on, Chris married and away, Kimberly off too. Time to move on.
So - a twinge of sadness when I saw someone's aspirations lying on their drive this morning, but a confirmation that we had done the right thing to acknowledge the need for change. Doesn't mean that we're getting old and slowing down - oh no, we're on to appropriate new and exciting projects - in fact the Well House Manor project is an exciting new future - not just an aspiration as it will be so much more. If you follow the link in the sentence above as I write this article , you'll find it's just a place holder. Come back to the archive in a week or two, and you'll read much more.
Posted by gje at 10:42 AM
January 17, 2006
Combining similar rows from a MySQL database select
If you're selecting data from a MySQL database and you want to report back the total or average for a column, you can use a function such as avg or sum on the column. If you want to choose only certain records to include in your sum or average, add a WHERE clause and if you want to produce a separate sum or average for each unique value in another column, use a GROUP BY clause.
Basic data:
mysql> select agid, asking from sales where agid > 9; +------+--------+ | agid | asking | +------+--------+ | 10 | 225000 | | 10 | 195000 | | 10 | 237500 | | 11 | 465000 | | 11 | 275000 | +------+--------+
Summing all the asking prices:
mysql> select sum(asking) from sales where agid > 9; +-------------+ | sum(asking) | +-------------+ | 1397500 | +-------------+
Summing the asking prices agid by agid:
mysql> select agid, sum(asking) from sales where agid > 9 group by agid; +------+-------------+ | agid | sum(asking) | +------+-------------+ | 10 | 657500 | | 11 | 740000 | +------+-------------+
See [url=http://www.wellho.net/mouth/515_MySQL-an-FAQ.html]our MySQL FAQ[/url] for other hints on MySQL SELECT commands.
Posted by gje at 03:43 AM
January 16, 2006
May all your screw-ups be big ones
Isn't the ability to communicate with lots of people all at once great? No longer the need to envelope 50 letters and put them in the post - just a quick mailing list program. But that does mean that as well as getting through very quickly, you can really make a mess of things very quickly too.
At 9 o'clock, I received an email telling me that a "Speed Networking Dinner" this Wednesday is cancelled due to a lack of bookings. And that was followed at half past 9 by another email making no reference to the first one, and telling me that it's my last opportunity to book for the event.
Somewhere, someone's sitting in an office with a flood (or perhaps it's a trickle and that's the problem) of emails, all of which now need individual attention, filling them in on what's happening. And it leaves all the other hundreds of members of the group who have received the emails wondering at the organisation's organisation.
Posted by gje at 10:01 AM
January 15, 2006
Using PHP to output images, XML, Style sheets, etc
PHP is usually used to generate a stream of HTML to be sent to the browser, but if you use the header function within your page you can use it to send any other type you wish. For example, if I include
header("Content-type: image/jpeg");
then I can script the production of images. Easy? Yes, but two words or caution:
a) The header call must be included within your script before it generates a single byte of output. Rephrasing that, the < character of the initial <?php must be on the very first line and in the very first column of your script, and not a single byte may be output until you've made the header call.
b) If you select a format such as jpeg to send out, it's your responsibility to ensure that it's a valid jpeg image stream. More often than not, you'll do this with the Gd library, but if you're using PHP simply to upload images and manage their storage, that's not necessary. We have an example script to upload, store and retrieve images in a database in our solution centre.
Posted by gje at 12:44 PM
Useful link: PHP training
January 14, 2006
Open Source training from Well House Consultants
Just occasionally, it's work going back to basic - who we are and what we do. Lisa wrote a great introduction this morning when filling in a form. With her permission, I'm sharing it with you:
"Well House Consultants has been training OpenSource computer programming for the past 10 years. All material is written and presented by Well House Consultants staff.
Subjects include: Perl, PHP, MySQL, Python, Tcl, Linux, C/C++, Ruby, Apache httpd and Tomcat. New topics are always under consideration.
Public courses are limited to 7 delegates. Private courses (for up to 15) can be held at your offices, or own dedicated centre in Wiltshire.
Manuals are comprised of regularly revised, individual modules to ensure that the training provided accurately covers just the subjects that are relevant to your needs. We are happy to develop additional modules that pertain to your specific use."
Excellent work, Lisa. We discussed whether price should be mentioned in such a short introduction, and decided against. Although we're 20 to 30 % lower that other companies who train, we're very open about our prices on the web site and people will very quickly find that out. Having a product that meets a customer requirement is discussed first, and only then is price looked at.
Lisa was also wondering whether to add that the courses are all taught by someone who's actually met / learned with the originators and luminaries of the languages we teach. Close call that one - it does make a huge difference, but I'm not sure that it's something to put in just an attention grabbing few paragraphs.
If you've come across this page while doing a web search, you'll find links to the subjects we teach, our diary, and far more details all on our home page.
Posted by gje at 01:12 PM
January 13, 2006
Merging pictures using PHP and GD

I wanted, regrettably, to fade (tear) one picture into another - a train at Melksham into a picture of a disused railway trackbed. We have one of those nearby at Seend, where the Trowbridge - Devizes - Reading - London train service used to run. Here's another 2 options I looked at:

and

The GD library in PHP provides a number of useful graphics and manipulation commands - can you believe that the images above are generated by programs that are 17 lines / 400 bytes long! See fade source code and tear source code and xtipple xource code
Posted by gje at 03:27 AM
Useful link: PHP training
January 12, 2006
Smoke and mirrors
I spoke with FD and GD and DP and they all told me that I had an excellent and logical case, and I should ask R in the appropriate government department. I asked RJ and his colleague DH. RJ is rude and didn't reply (he never does according to DP), but DH did answer me and tell me that it was a commercial decision for company FGW to make. I've written to several people at company FGW. AB wrote back to say she hoped they could provide me with what I was looking for, and GB wrote back to tell me that although it didn't look great, they hadn't yet made a final decision. Then this morning I heard back from AF, who's the managing director of FGW to tell me that they're not allowed to decide because of government rules; she suggests I write to the department where DH and RJ work.
Meanwhile, DT who's the boss as the government department concerned side steps questions put to him by the presenter of Radio 4's "You and yours" program, preferring to talk about different things to what he was being asked about .... and ZB of FGW tells me that although they're having a meeting for interested parties, too many people want to attend so I can't and I should talk to GD who they have invited. ZB rubs salt in the wound by confirming that they will be discussing the commercial decision that I'm on about, and that I've had over 120 people sign up to.
Time ticks on, not one person in the loop has said "I am a decision maker" ... it's just bounced around in a circle. You know - I can respect someone who makes a decision that goes against me if I know the situation has been fairly looked at. But I find it hard to respect someone (or sometwo or somethree or somefour) who try to hide things with a magician's smoke and mirrors trick. Oh - you may be able to identify some of the names involved here. From their viewpoint, the great thing about smoke and mirrors is that I can't clearly tell which of them is the decision maker but won't admit to it.
Posted by gje at 07:12 PM
January 11, 2006
Python's Generator functions
When you write a program, you should split your code down into a series of named blocks, each of which performs a single logical action. Blocks will be called up in different ways in different languages - and they'll be know as functions, subs, methods, procs (and perhaps other names too), but the principle is very much the same in each case.
Named blocks are usually performed one after another as a sequence of statements from within another block.
In this example, the pow2 function is performed completely before the for loop is run - the returned list being used as input to feed the variable called vv:
def pow2(upto):
powers = []
startat = 1
startpower = 1
while startpower <= upto:
powers.append(startat)
startat *= 2
startpower += 1
return powers
for vv in pow2(10):
print vv
It works, and works well. But the list called "powers" is constructed completely and stored in memory while the for loop is run. That's not a problem in this case with a list of ten values, but it could be a problem if the list was to contain a billion values. Writing things in this style is rather like building up a whole supply of water in a reservoir, then letting it back out as it's required. If the reservoir isn't big enough, you'll get serious flooding and damage to nearby properties.
Python provides an alternative in Generator Functions. A generator function is one that does NOT run to completion when it's first called - instead, it only runs until it has a value available to return, at which point it yields that value back and suspends operation until called again to resume. Here's the program I provided above, modified to use a generator.
def pow2(upto):
startat = 1
startpower = 1
while startpower <= upto:
yield startat
startat *= 2
startpower += 1
for vv in pow2(10):
print vv
Operation is exactly the same as the example above ... but there is NOT an intermediate list produced - i.e. no reservoir, and no risk of flooding or damage if the reservoir spills. A better model in this case is to think of a water pipe with a tap (faucet) on the end, which can be turned on and off at will as the next element - drop of water - is required.
Generators provide a very neat way of providing data as required on applications that potentially use huge intermediate lists. If you've every wondered what the difference is between range and xrange, or between readlines and xreadlines, it's that the "x" version uses a generator internally. I recall being given a customer problem handling a huge (10 Gb) file, and fixing his problem straight away just by adding an "x" in front of "readlines". That is the power of a generator.
Further example
Further articles on Python functions
Posted by gje at 03:06 AM
Useful link: Python training
January 10, 2006
The fencepost problem
If you erect a fence of 10 panels, you'll need 11 fenceposts to hold it up. And if you write a program that joins together 10 elements on a line, you'll only need 9 separators between them - this is known as the "fencepost problem".
If you write a simple program loop to output each element from a list followed by a separator, you'll end with a spurious separator on the end of the line. Here's what I mean (in Python).
posts = ["apple","banana","cherry"] panel = "and" for place in posts: print place,panel, printwhich gives the result
apple and banana and cherry and
It would be possible - but long winded - to print out the connecting panel only for the second and subsequent posts:
posts = ["apple","banana","cherry"]
panel = "and"
i = 0
for place in posts:
if i: print panel,
i += 1
print place,
but surely there's a better way?? Yes - there is.
In Python, the join method lets me connect a list of strings using another string as the glue between them. My example becomes:
posts = ["kiwi","orange","pineapple"]
panel = " with "
salad = panel.join(posts)
print salad
which gives the result
kiwi with orange with pineapple
Link - full source code
In Perl, the join function performs the same task:
@salad = ("Cherry","Damson",Fig");
print (join(" and ",@salad));
With PHP, the function you'll use is implode:
$salad = array("tangerine","pear","grape");
$fsal = implode(" and ",$salad);
Posted by gje at 03:03 AM
January 09, 2006
''I don't know'' is sometimes a good answer
There's just a few occasions when I'm training that I'm asked a question I don't know the answer to. It's not very common, since I actually write the courses / material and I know most of the things that people are likely to ask. And I've learnt that on those few occasions, being honest and saying I don't know is far and away the best answer to give.
But ... I tend not to leave it at that. Questions are asked for a genuine reason and my answer should be expanded. If I don't know, how can I do that? Firstly, we have a library of over 600 books on technical topics where I can look the answer up, or direct my trainee to do so. Then with my computer science background and extensive commercial experience there's a good chance that I can deduce the answer or formulate a test to work it out. And of course there's the web - anything from the excellent manual sites of open source products such as mysql and PHP through various FAQs such as the ones on Python and Perl to forums such as our own Opentalk and Webforumz. And if that still doesn't turn up the answer, a few Google searches are more than likely to lead to an answer, or at the very least to someone else asking the same question.
Taking an educated guess - provided that it's stated as such - is often an option for questions which are asked more out of interest than necessity, but I'll rarely make a wild guess. "Don't know" is much more honest and works far better in the longer term.
I've been talking over recent months about our "Well House Manor" project and getting very excited about the prospect. The route we chose wasn't an easy one - it required a planning application that we were assured would be welcome / trivial, moving part of our business into an area where we were assured we would be very welcome, and taking over a rental cottage which we were assured was good and let easily. With a project such as this, we expect ups and downs, but we're finding that just too many of the assurances are just optimistic guesswork (at best) and that budgets are likely to rise, time taken (thus cash flow projections) aren't so good, and the chances of planning applications going through remain good, but are nothing like certainties as there are major concerns from other parties.
So you'll see me very quiet on this project for the next couple of weeks. Lisa and I would rather walk away at this stage, in spite of a huge time investment and some major spending of surveys, architects and solicitors too. A pity really, but we feel comfortable that this is a wise pause / decision. Ironically, a couple of "Don't know" answers would have flagged issues earlier; at best, that would have resulted in us investigating and still going ahead - "forewarned is forearmed", and at worst it would have saved us money and saved the vendor living in hope for several months.
Posted by gje at 03:07 AM
January 08, 2006
Converting between acres and hectares
I wanted to do a few conversions between hectares and acres and - guess what - I didn't know the conversion values off the top of my head. Then I may have a few other area conversion to do too, and I could do with some more PHP examples. Guess what ... a program ... and one worth sharing too
If you want to convert square cms to square ins, acres to hectares, or square miles to square kms, please use my converter!. Please feel free to copy the code too and change it to different type of units if you like; a credit / link back to my site would be appreciated.
If you're into PHP, there are some great examples of explode and implode, or the uses of associative arrays, of here documents, and of the (rather odd) list function. If you're not into PHP, simply enjoy converting your land sizes!
P.S - did I ever tell you about our currency converter with rates that are always up to date? Unlike units of area which never change, in the case of monetary exchange rates we have to take a daily feed from the European Central Bank to ensure we're reflecting current rates.
Posted by gje at 03:03 AM
January 07, 2006
A new sign
At long last - we have two new signs at Melksham station to replace the old and faded one that was there before.
Before:

After:

It is slightly ironic that the new sign is branded "Wessex Trains" ... which is the name of the company that's running the service for the next 12 weeks. Then the service is taken over by the First group. It almost looks spiteful to brand the station with the old name at this time!
Posted by gje at 08:05 PM
January 06, 2006
Colour doesn't have to mean colourful
In my early days of putting together websites, I used to confuse "colour" and "colourful". It's a common trait of the programmer who's required to do a little graphics art as well to use string, vibrant colours and pictures ... but there are actually times where subtle colouring is much more effective.
Here are three pictures taken in the last couple of days. Yes, they ARE colour pictures rather than monochrome ones, but the colour is all the more effective from being subdued.

Near the top of a ski run, South Lake Tahoe

The Pacific Ocean at Pacifica, near San Francisco

Sunset over the levees, south of Sacremento, California
Posted by gje at 04:01 PM
January 05, 2006
Hotel novelties
We're studying good and bad hotel practises to that we know what's on offer ... you may have read a little about the Well House Manor project already on "The Horse's Mouth", and although it will be neither a hotel nor a B&B we can learn plenty from establishments of both types - especially those that are trying innovative ideas.
There's a vending machine here in the lobby that's the vending machine to out-trump all vending machines - it has a big screen that you can go through menus, takes credit cards, and offers products from a packet of crisps and drinks through to toiletries to bluetooth (wireless) headsets and even iPods. I did notice a lack of condoms ... I guess because all the products are on show in a public area and they would raise too many questions in the minds of the inquisitive young.
I'm posting from the hotel room. Just open the laptop, and it's on broadband that's included in the room price which I have to say I feel is good value - about 65 quid for the double. There's also a wired network point on the desk which we could have used an an alternative.
The bed is adjustable for firmness / softness - and adjustable separately for both sides. Not a big fuss to me (as I can sleep anywhere) but I know that Lisa appreciates it ... and I suspect that many others do too.
Have you ever showered standing in the bath and found that the shower curtain sticks to you? The shower curtain here is on an arced rail so that the ends naturally drop into the bath, but the centre of the curtain is held well out to give the showering person as much additional room as possible. And the toilet's set at an odd angle ... I haven't worked out a "why" for that one yet.
Isn't it interesting how .... as you start to get involved in a new venture ... you start seeing things with different eyes!
Posted by gje at 03:07 PM
January 04, 2006
What backup is adequate?
I've been ski-ing for the last 5 days. Or rather - trying too. On one day, the slopes were completely closed and on the other days there has only been limited opening - of the 30 lifts perhaps 10 have
been running on average, and this is peak season. Yesterday, we went to the Gondola Station here in South Lake Tahoe to find that the Gondola wasn't running ... and we queued for well over an hour for a bus to take us about a mile and a half to the next lift. Got onto "the mountain" at about midday.
Finished ski-ing when the lifts closed at 4 p.m., queued for the bus again and got back to the Gondola station for about 5:30. Rather took the shine off the day.
I know that bad weather happens. But the folks here seem to have woefully inadequate backup to handle what seem to be daily problems. Be it lack of buses, lack of systems to load them quickly, lack of staff to get more lifts running until late in the day. It's not exactly as if the weather hadn't been forecast!
On the mountain, too, the lift system is sparse - there's one vital lift that you MUST ride in order to get from "A" to "B" and it's very prone to sudden closure - leaving anyone who's travelled from "B" to "A" earlier in the day stranded.
I'm sure the whole system works very well on a sunny, calm day but - hey - there ARE going to be snowy and windy days .... we need that snow for ski-ing!
Please forgive my "rant". As a systems person, I find it very frustrating to see something that could run so well and be so much better with just a few tiny adjustments, and I see all those people so inconvenienced by the lack of adequate planning and backup. But that's not to say that there need to be backups for every eventuality.
When we provide a training course, we provide one laptop computer per trainee to use during the course, and we always carry at least one spare just in case of hardware failure, someone messing up the software, or if an extra person wants to attend. The machine that I present from is backed up onto another machine too, so that if that fails we're not "dead in the water". And we carry a spare network hub and cables. Should the main internet connection fail at our training centre, we have a lower speed backup that we can manually switch in so that we remain on line.
BUT ... we don't have a spare tutor always on call in case I'm taken ill. Touch wood, I'm healthy and it's very rare indeed for this to be an issue - twice in 10 years, I think - and the extra cost of providing this backup would far exceed any gain from having it.
In computing terms "backup" usually relates to the backup of data and programs so that systems can be restored in the event of a failure / loss of data. It's a very easy thing to overlook, as things can work perfectly for years and you'll say "I'll take a backup sometime" ... or backup frequencies get less and less. Then you may well have an issue of quite major significance when something goes wrong - far outweighing those problems I've described at Heavenly ski resort earlier in this post.
How will I get my system(s) up and running again if xxxx happens at the worst possible time? - that's the question to ask your self when you check whether you backup scheme is adequate.
Posted by gje at 02:50 PM
January 03, 2006
Keep that image small
Remember to keep image sizes down on websites. I know this is a reminder that has been around since the days that we referred to a 56k modem as a fast connection, but it does still matter. People still access your web site through a modem and if you've a busy website, you'll still have an excess to pay once your traffic exceeds a certain level. On a really fast access, don't you want your pages to appear almost instantly.
Have a look at these three images. On a 56k modem, one of them will take over 15 seconds to download, another will take 8 seconds and a third will take 5 seconds. The final image will come down in under 2 seconds. Can you tell which is which by looking at them?
Image A:![]() |
Image B:![]() |
Image C:![]() |
Image D:![]() |
Answer at the end of the post.
There are two techniques I've used to reduce the size of the image.
Firstly, I've reduced the number of pixels that make up the source of the image from the however-many megapixels that my digital camera takes to 680 pixels wide so that I don't burn up bandwidth sending out over-detailed pictures that our site visitors will never look at. (and in once case above, I've reduced it to 340 pixels wide). Browsers will rescale pictures anyway if they're not supplied with enough resolution. I doubt that you'll be able to tell which is the lowres image on our regular blog page but you may spot it on the printer friendly version where it's displayed much wider.
Second, choose your format as appropriate. I've used a .jpg image for all these photographs, and that has allowed me to select a lossy compression algorithm where I sacrifice a little quality for a lot of space; good image manipulation software lets you make the tradeoff - I used photoshop. For web work, a low quality image is often sufficient. For something that will be printed out to high quality, you may wish to go for medium or even high quality. You'll also find that you may want to choose a higher quality on images with sharp edges or with large areas of subtle toning, where the loss is more noticeable.
Answers.
Image A - 15 seconds. 680x340 pixels, Photoshop's High Quality, 87k
Image B - 8 seconds. 680x340 pixels, Photoshop's Low Quality, 42k
Image C - 5 seconds. 680x340 pixels, Photoshop's "Save for Web", 27k
Image D - 2 seconds. 340x170 pixels, Photoshop's "Save for Web", 9k
Posted by gje at 02:39 PM
January 02, 2006
Keeping Customers Informed

I would rather fly with Virgin Atlantic than with British Airways, and I would rather ski at Mammoth than at Heavenly. That's not necessarily because Virgin have better timekeeping (we were mighty delayed last week, for example), nor that skiing is better at Mammoth than at Heavenly. It all comes down to accurate and full customer information.
At Mammoth, there's a clock on every ski lift to tell you the time; at Heavenly, timepieces are few and far between. Lift information at Mammoth has tended to be accurate ... but here at Heavenly, the online web site seems to tell us what they wish they could be running rather than what they are running. Yesterday, one of their few on-mountain report displays beside "Groove" chair told it was shut down ... no one had told the operators, and it was running!
"What shall we tell the customers?" was an often asked question at the place I used to train under contract when they were cancelling a course or had rescheduled dates. "What's wrong with telling them the truth?" was my reaction. Customers deserve the respect of full and honest information.
I'm off in a few minutes to Heavenly's Gondola station. Signage there is very limited, and the web site tells me that all the lifts (bar one) are open today. Sorry, I don't believe the web site. Experience over the last couple of days tell me that I need to seek out one of their staff and chat with him to find out what's really happening. What a silly system!
And we disagree with it. Hence...
Well House Consultants information updates:
Headline news digest on our news page
Daily update via the Horse's Mouth
News flashes on our home page
Customer support via the Opentalk Forum
.... and course availability on our booking system and in our diary is dynamic.
Posted by gje at 04:05 PM
January 01, 2006
2006 - Making business a pleasure
"Making Business a Pleasure" - a spoken logo for Well House Consultants for 2006.
Whether you're attending a course, staying as a guest at Well House Manor, working for us, or simply visiting our web site, we want you to enjoy the experience.
We don't know exactly what 2006 will bring, but we have some plans and can make some educated forecasts.
Well House Manor
When you book a course, you also book somewhere to stay? The majority of our customers answer "yes", as we provide niche courses and have customers from far and near. In 2006, we'll be bringing "Well House Manor" online - accommodation for the business visitor to Melksham. All rooms will be double or twin, en suite, but willingly let for single occupancy. They'll include wireless and (probably) wired broadband internet access, plentiful desk space and power outlets, and access to printing facilities. Continental breakfast will be provided, and you'll be very welcome to bring in your own take-away for your evening meal - knives and forks, plates, bowls and glasses provided.
Booking a place at Well House Manor if you're attending a course couldn't be easier - we'll simply include it with your booking. If you're not attending a course, we'll be taking bookings online once we have a firm opening date, and also taking advanced bookings by phone. We're looking to provide business accommodation during the week, and a base for adult tourists at the weekend. We'll ask you to guarantee your booking and pay by debit or credit card.
Well House Consultants
We've a full schedule of public training courses running at our Melksham Training Centre, starting with Python Programming on 9th to 11th January and on through to Regular Expressions on 15th December. Other dates, we're available for private courses at our centre or at your offices.
Inevitably, there will be a few changes to the schedule and course content but our policy that we NEVER cancel a course that has a booking remains. We know you need a guarantee that your course will run.
So why do I say there will be "a few changes"?
In the last couple of months, Apache httpd 2.2 was released and although takeup may be slow, our Deploying LAMP and Linux Web Server courses will be revised shortly to include more coverage of the production release.
Perl 6 is also on the horizon - and not so far on the horizon as it used to be. In 2006 we'll certainly see more mentions of the new syntax in our current Perl courses, and there may very well be additional conversion courses announced. You may spot in our schedule that our Perl for Larger Projects and Using Perl on the Web courses are scheduled only for a few months ahead - the OO aspects of Perl 6 will inevitably move into the more regular "Perl" or "Perl 6" courses and the advanced topics courses may need to be lengthened or shortened.
Ruby has been a bit of a "sleeper". No huge call for training and we've been running only private courses in Ruby. It seems the topic is huge in Japan, quite big in the USA and really hasn't made it to Europe yet. However, there's a great interest in "Ruby on Rails". Rails provides a modern, easy to use system for putting interactive web sites together quickly. Embedding code within the HTML, very much in the way that JSPs and PHP does, it lets developers put systems together fast. There's good technical reasons why it scores - in the right circumstances - over both JSPs and PHP. At this stage, I've not scheduled any public "Ruby + Rails" courses ... but PLEASE ASK if you've a group of even just two or three people interested.
Looking further into 2006, we've got one eye on a number of other topics as diverse as Ajax (client side Javascript accessing server side XML data), Applescript (Mac's scripting language) and LDAP (Shared directories for common logins, etc). And we're continuing to watch Open Source web applications from Plone to SMF to OSCommerce.
Coming full circle, we're also looking at Open Source on line booking and reservation software - not only for courses, but for Well House Manor too. We could well end up writing and publishing something under a GPL license ... and that'll open a whole new business facet too.
Whatever 2006 brings, we'll enjoy what we do - and we'll provide services that let you enjoy learning or staying with us - "making business a pleasure".
Happy New Year!
Update - September 2008 - I have added a simple Ajax Example here, and Ajax is now covered on our PHP Techniques Workshop
Posted by gje at 12:45 AM



