Freedom Ride

Snow to 800 metres. 55km/h winds. Possible hail. That was the forecast that greeted us at 4:30am as we met at Tim’s house, all psyched up for our 200km Freedom Ride over the central plateau back to Hobart. As we drove up north in the bus, 11 testosterone fuelled blokes discussed whether or not we would be so soft that we would fall back on the “easy” bad weather backup route. Or whether we would be hard men and tough out the weather.

As each rider spoke up and agreed that they wanted to do the central plateau route, and then also said that it would probably be a bad idea, I recalled the Launceston – New Norfolk race a few years back, that took the same route, when only 7 pro riders finished in similarly atrocious weather.

Amazingly, we had almost unanimous agreement to go the soft option. Still 200km, still over 2000m climbing, but via the east coast, with its generally milder weather. I was relieved: the plateau route was sounding more and more like a really dangerous choice, with freezing cold, wet and gusty descents and general misery!

We were riding for the charity Live Free Tassie, which works to help young people break free from addictions.  It’s not too late to donate — please do!

Preparing to leave Campbell Town.  Weather looks great so far.

At just after 7am, we set out from Campbell Town towards the east coast, immediately hitting the largest climb of the whole ride, which we took gently while we warmed up. The strong winds were behind us at this point, and we were somewhat sheltered on most of the climb. Over the top of the range it was cold, but it was over surprisingly quickly and with little pain.

A tight well-organised bunch, rolling smoothly

The descent into Swansea was great fun and we rolled into the small seaside town well ahead of schedule. With no sense of urgency, and warm and pleasant weather, the brief toilet stop took somewhat longer than originally intended!

Swansea Stop

We rode the whole route in a tight, well organised bunch, with smooth roll-throughs and good communication through the group. No one got left behind and I really felt like we were all working well together. I’ve never been on a ride before where the bunch stayed organised for 50km, let alone 200km!  Well done Tim (our organiser) for his success in motivating the fast boys to support the bunch!

Once we got to Triabunna, the traffic got a little heavier, and we had a couple of impatient drivers attempt to overtake on blind corners and similarly silly places. As we went through Orford, we had our one and only puncture of the day, and the local police stopped by to ask us to ride single file through the narrow gorge out of Orford to reduce the likelihood of more silly moves by drivers. The puncture meant that this became our lunch stop, and again, the beneficial winds meant we were still ahead of schedule.  So again, we were in no rush…

Lunch stop at Orford, 125km in, everyone looks happy!

Then we turned our noses towards Hobart. And hit the cross-headwinds. 50km/h with lots of gusts thrown in for good measure. Our average speed plummeted, and we were riding at less than 20km/h most of the time now. A few of the riders in the group were starting to feel their legs, and we encouraged them to spend as little time on the front as they possible.  As we rode single file through the gorge, a phalanx of probably 200-odd motorbikes roared past the other way, followed by a long line of classic cars.  There was to be no overtaking anyway…

Mechanical — rear wheel change meant a bit of waiting for the group.  Just before the rain!

We struggled against the wind, as the rain and a little bit of hail started to assault us. But we survived. The worst part, for me, was the steep descents in driving wind and rain. They were not much fun.  At this point, Simon experienced a serious cramp that put him in the bus. But only for 5 minutes! He got out again, like a madman, in time for the sketchy descent. Not sure I could have done that…

The rain let up again after the hills and we just worked our way slowly back into Hobart against the winds.  We finally and triumphantly arrived, the last group to finish for the day, all our early time gains destroyed by the ferocious winds and unexpected stops through to the finish.

Personally, I enjoyed the whole day, bar the sketchy descents and the handful of crazy drivers.  I’ve never been as well prepared for a long ride as I was for this one, despite already having done 280km in the 5 days preceding the ride.  Kudos must go out to Trev, Mark D and Mark P as the oldest in the bunch (by some margin, too), and to Tim who did a brilliant job of organising the ride.  The whole bunch was great to ride with, and I’d do the ride again with the same guys without hesitation.  Thanks for an awesome epic ride, Brendon, Dan, Simon, Ben, Tim, Michael, Ant, Trev, Mark, Mark and Mark!  Updated: And massive thank you to Henry and Henry for driving and supporting on the ride.  Sorry I forgot to mention you initially!

A more UTF-32 aware JavaScript String library

One of the hassles I regularly experience with JavaScript is that it does not have native support for supplementary characters.  Internally, JavaScript uses UCS-2 encoding (unlike most of the rest of the web, which uses UTF-8…)  While you can use surrogate pairs to represent Unicode characters between U+10000 and U+10FFFF, this makes string handling with these characters a pain.  In particular, functions such as indexOf and substr have to be very carefully used, both to account for the surrogate pairs in their index parameters, and to avoid cutting them in half when manipulating the string. Of course, when interfacing with third party services, you will need to be aware of how they handle text.  For instance, the Twitter 140 character limit counts Unicode code points, not UCS-2 code units.  But many other products, (for example, Microsoft SQL Server), use UTF-16 or UCS-2 internally and treat supplementary plane characters as 2 code units for the purposes of calculating field size.  Developer beware! Anyway, I have put together a small set of functions that treat surrogate pairs as a single code point, abstracting away surrogate pairs at the basic String level.  Adding support for surrogate pairs is not a complete solution — I haven’t done any work on regular expressions, for example, and this code also does not begin to address more complex requirements around grapheme clusters or normalisation, but this is just one less complexity to worry about. The functions do not replace any existing String functions. This code is not complete: I am missing some boundary conditions and edge cases, and I haven’t yet tested with isolated surrogate code units — but for what it’s worth, here it is.  The kmw prefix refers to KeymanWeb, which will shortly be using the functions (replacing the mishmash of code we currently use…) Some simple examples:

var str="Brave "+String.kmwFromCharCode(0x13027, 0x1314C, 0x1309C)+" world";

alert(str.indexOf("w"));    // Displays 13
alert(str.kmwIndexOf("w")); // Displays 10

alert(str.length);       // Displays 18
alert(str.kmwLength());  // Displays 15

alert(str.kmwSubstr(4,3));  // Displays e U+13027
alert(str.substr(4,3));  // Displays e U+D80C (half a supplementary pair!)

The license on this code is Mozilla Public License 1.1.  A couple of functions were lifted from the proposal Supplementary Characters for ECMAScript by Norbert Lindenberg and tweaked (back) to more closely mimic the functions they replace, warts and all.  These two functions are probably better tested than my ones! Version 1.0 of this library plus a rudimentary test script can be downloaded from http://durdin.net/blog-files/kmwString-0.1.zip. Comments, bug fixes, flames, suggestions much appreciated!

/**
  @preserve (C) 2012 Tavultesoft Pty Ltd
  
  Adds functions to treat supplementary plane characters in the same 
  way as basic multilingual plane characters in JavaScript.
  
  Version 0.1
  
  License
  
  The contents of this file are subject to the Mozilla Public License
  Version 1.1 (the "License"); you may not use this file except in
  compliance with the License. You may obtain a copy of the License at
  http://www.mozilla.org/MPL/

  Software distributed under the License is distributed on an "AS IS"
  basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
  License for the specific language governing rights and limitations
  under the License.

  The Original Code is (C) 2012 Tavultesoft Pty Ltd.

  The Initial Developer of the Original Code is Tavultesoft.
*/

/**
 * Constructs a string from one or more Unicode character codepoint values 
 * passed as integer parameters.
 * 
 * @param  {integer} cp0,...   1 or more Unicode codepoints, e.g. 0x0065, 0x10000
 * @return {String}            The new String object.
 */
String.kmwFromCharCode = function() {
  var chars = [], i;
  for (i = 0; i < arguments.length; i++) {
    var c = Number(arguments[i]);
	if (!isFinite(c) || c < 0 || c > 0x10FFFF || Math.floor(c) !== c) {
	  throw new RangeError("Invalid code point " + c);
	}
	if (c < 0x10000) {
	  chars.push(c);
	} else {
	  c -= 0x10000;
	  chars.push((c >> 10) + 0xD800);
	  chars.push((c % 0x400) + 0xDC00);
	}
  }
  return String.fromCharCode.apply(undefined, chars);
}

/**
 * Returns a number indicating the Unicode value of the character at the given 
 * code point index, with support for supplementary plane characters.
 * 
 * @param  {integer} codePointIndex  The code point index into the string (not 
                                     the code unit index) to return
 * @return {integer}                 The Unicode character value
 */
String.prototype.kmwCharCodeAt = function(codePointIndex) {
  var str = String(this);
  var codeUnitIndex = 0;
  
  if (codePointIndex < 0 || codePointIndex  >= str.length) {
    return NaN;
  }

  for(var i = 0; i < codePointIndex; i++) {
    codeUnitIndex = str.kmwNextChar(codeUnitIndex);
	if(codeUnitIndex == undefined) return NaN;
  }
  
  var first = str.charCodeAt(codeUnitIndex);
  if (first >= 0xD800 && first <= 0xDBFF && str.length > codeUnitIndex + 1) {
    var second = str.charCodeAt(codeUnitIndex + 1);
	if (second >= 0xDC00 && second <= 0xDFFF) {
	  return ((first - 0xD800) << 10) + (second - 0xDC00) + 0x10000;
	}
  }
  return first;  
}

/**
 * Returns the code point index within the calling String object of the first occurrence
 * of the specified value, or -1 if not found.
 * 
 * @param  {string}  searchValue    The value to search for
 * @param  {integer} fromIndex      Optional code point index to start searching from
 * @return {integer}                The code point index of the specified search value
 */
String.prototype.kmwIndexOf = function(searchValue, fromIndex) {
  var str = String(this);
  var codeUnitIndex = str.indexOf(searchValue, fromIndex);
  
  if(codeUnitIndex < 0) {
    return codeUnitIndex;
  }
  
  var codePointIndex = 0;
  for(var i = 0; i < codeUnitIndex; i = str.kmwNextChar(i), codePointIndex++);
  return codePointIndex;
}

/**
 * Returns the code point index within the calling String object of the last occurrence 
 * of the specified value, or -1 if not found.
 * 
 * @param  {string}  searchValue    The value to search for
 * @param  {integer} fromIndex      Optional code point index to start searching from
 * @return {integer}                The code point index of the specified search value
 */
String.prototype.kmwLastIndexOf = function(searchValue, fromIndex)
{
  var str = String(this);
  var codeUnitIndex = str.lastIndexOf(searchValue, fromIndex);
  
  if(codeUnitIndex < 0) {
    return codeUnitIndex;
  }
  
  var codePointIndex = 0;
  for(var i = 0; i < codeUnitIndex; i = str.kmwNextChar(i), codePointIndex++);
  return codePointIndex;
}

/**
 * Returns the length of the string in code points, as opposed to code units.
 * 
 * @return {integer}                The length of the string in code points
 */
String.prototype.kmwLength = function() {
  var str = String(this);
  
  if(str.length == 0) {
    return 0;
  }
  
  for(var i = 0, codeUnitIndex = 0; codeUnitIndex != undefined; i++, 
    codeUnitIndex = str.kmwNextChar(codeUnitIndex));
  return i;
}

/**
 * Extracts a section of a string and returns a new string.
 * 
 * @param  {integer} beginSlice    The start code point index in the string to 
 *                                 extract from
 * @param  {integer} endSlice      Optional end code point index in the string
 *                                 to extract to
 * @return {string}                The substring as selected by beginSlice and
 *                                 endSlice
 */
String.prototype.kmwSlice = function(beginSlice, endSlice) {
  var str = String(this);
  var beginSliceCodeUnit = str.kmwCodePointToCodeUnit(beginSlice);
  var endSliceCodeUnit = str.kmwCodePointToCodeUnit(endSlice);
  return str.slice(beginSliceCodeUnit, endSliceCodeUnit);
}

/**
 * Returns the characters in a string beginning at the specified location through
 * the specified number of characters.
 * 
 * @param  {integer} start         The start code point index in the string to 
 *                                 extract from
 * @param  {integer} length        Optional length to extract
 * @return {string}                The substring as selected by start and length
 */
String.prototype.kmwSubstr = function(start, length)
{
  var str = String(this);
  if(start < 0)
  {
    start = str.kmwLength() + start;
	if(start < 0) {
	  start = 0;
	}
  }
  var startCodeUnit = str.kmwCodePointToCodeUnit(start);
  var endCodeUnit = startCodeUnit;
  
  if(length == undefined) {
    endCodeUnit = str.length;
  } else {
    for(var i = 0; i < length; i++, endCodeUnit = str.kmwNextChar(endCodeUnit));
  }

  return str.substring(startCodeUnit, endCodeUnit);
}

/**
 * Returns the characters in a string between two indexes into the string.
 * 
 * @param  {integer} indexA        The start code point index in the string to 
 *                                 extract from
 * @param  {integer} indexB        The end code point index in the string to 
 *                                 extract to
 * @return {string}                The substring as selected by indexA and indexB
 */
String.prototype.kmwSubstring = function(indexA, indexB)
{
  var str = String(this);
  
  if(indexA > indexB) { var c = indexA; indexA = indexB; indexB = c; }
  
  var indexACodeUnit = str.kmwCodePointToCodeUnit(indexA);
  var indexBCodeUnit = str.kmwCodePointToCodeUnit(indexB);
  if(isNaN(indexBCodeUnit)) indexBCodeUnit = str.length;

  return str.substring(indexACodeUnit, indexBCodeUnit);
}

/*
  Helper functions
*/

/**
 * Returns the code unit index for the next code point in the string, accounting for
 * supplementary pairs 
 *
 * @param  {integer} codeUnitIndex   The code unit position to increment
 * @return {integer}                 The index of the next code point in the string,
 *                                   in code units
*/
String.prototype.kmwNextChar = function(codeUnitIndex) {
  var str = String(this);
  
  if(codeUnitIndex < 0 || codeUnitIndex >= str.length - 1) {
    return undefined;
  }
  
  var first = str.charCodeAt(codeUnitIndex);
  if (first >= 0xD800 && first <= 0xDBFF && str.length > codeUnitIndex + 1) {
    var second = str.charCodeAt(codeUnitIndex + 1);
	if (second >= 0xDC00 && second <= 0xDFFF) {
	  if(codeUnitIndex == str.length - 2) {
	    return undefined;
	  }
	  return codeUnitIndex + 2;
	}
  }
  return codeUnitIndex + 1;
}

/**
 * Returns the code unit index for the previous code point in the string, accounting
 * for supplementary pairs 
 *
 * @param  {integer} codeUnitIndex   The code unit position to decrement
 * @return {integer}                 The index of the previous code point in the
 *                                   string, in code units
*/
String.prototype.kmwPrevChar = function(codeUnitIndex) {
  var str = String(this);

  if(codeUnitIndex <= 0 || codeUnitIndex > str.length) {
    return undefined;
  }
  
  var second = str.charCodeAt(codeUnitIndex - 1);
  if (second >= 0xDC00 && first <= 0xDFFF && codeUnitIndex > 1) {
    var first = str.charCodeAt(codeUnitIndex - 2);
	if (first >= 0xD800 && second <= 0xDBFF) {
	  return codeUnitIndex - 2;
	}
  }
  return codeUnitIndex - 1;
}

/**
 * Returns the corresponding code unit index to the code point index passed
 *
 * @param  {integer} codePointIndex  A code point index in the string
 * @return {integer}                 The corresponding code unit index
*/
String.prototype.kmwCodePointToCodeUnit = function(codePointIndex) {
  var str = String(this);
  
  var codeUnitIndex = 0;

  if(codePointIndex < 0) {
    codeUnitIndex = str.length;
    for(var i = 0; i > codePointIndex; i--, 
	  codeUnitIndex = str.kmwPrevChar(codeUnitIndex));	
    return codeUnitIndex;
  }

  for(var i = 0; i < codePointIndex; i++,
    codeUnitIndex = str.kmwNextChar(codeUnitIndex));
  return codeUnitIndex;
}

Updated 11 May 2012: Removed script formatting code as site hosting it was unreliable. Back to good old <pre> for now.
Updated 29 May 2014: Fixed broken script text, damaged when inserted previously.

Cruelly Tricked by the Library

So I borrowed a high brow British crime novel from the library. Ruth Rendell, An Unkindness of Ravens. Okay, maybe not very high brow. Here’s a picture.

It is sad that library technology has forced barcodes to be put on top of book titles or authors. 
I’m not very good at reading barcodes

Then I opened the book.

Note how classy that title is: the curlicue on the V is chopped off…

Um, what was that again? The Vampire’s Betrayal: Raven Hart? Trashy vampire romance? Twitch. Yeuch. The writing makes Twilight look sophisticated. I checked the cover again to make sure I hadn’t somehow, insanely, picked up the wrong book. But to no avail.

On page 27, the sloppy supernatural drivel miraculously transforms back into the erudite and innately British crime novel. But I am forever scarred.

I couldn’t bear to read page 27.  Who knows what I have missed so far?

I shall never again be able to open a Ruth Rendell novel without fear and trepidation.

Exploring with Hannah

We went exploring on Mount Nelson. We went to a little fence.

We saw some cairns.


We saw a strange metal loop hanging on a tree.

We saw rosellas.

YouTube Video

We saw a jack ant.

We walked up a steep track.

We saw some poisonous berries.

We saw the fence again!

We saw the signal station.


We saw an old hook and a great view. We might have a sorbet if they have some here!
The End

Wallaby Frogger, or how to interpret Strava performance graphs

This morning I rode to work early, leaving home before 5:30am.  This meant it was still dark and the wallabies were still out clubbing.  Hundreds of them.  It was just like riding past a cinema when a movie finishes, with the happy cinema-goers (or in this case wallabies) crossing the road oblivious to traffic, easily stunned by bright lights.

I would have seen at least 100 wallabies in the first half hour of the commute.  Most of the wallabies were on the side of the road and I just watched them warily as I rode (slowly) past.  But 5 wallabies decided to cross right in front of me.  These wallaby interactions can be seen on the graph below.

Note the spike in heart rate coupled with the sudden drop in speed.  One way of getting a cardio workout I guess.  It really felt like a game of Frogger, albeit with a role reversal.

Discovering Old Farm Road

Old Farm Road

Yesterday I discovered a beautiful road climb within a few minutes of the city centre.  I’m amazed I’ve never ridden it before.  Tucked away behind Cascade Brewery is a little road called Old Farm Road that follows Guy Fawkes Rivulet (does anyone know how it got its name?) straight towards the base of Mount Wellington.

The entrance to the climb is unprepossessing, passing the industrial complex of Cascade Brewery.  But tucked away to the left of the complex, Old Farm Rd beckons, first of all gentle rising as it passes a grassy park, ducking through some trees with Mt Wellington glowering above, and then tucking around and over the little rivulet before starting to climb in earnest.

This little road is just one lane wide, and you could be way out in the bush — there’s no sign of the city.  After the bridge over the rivulet, you ride past a few houses before a couple of fantastic hairpin bends that lead into a steep ramp.  Watch it on the descent — you’ll smoke your brakes coming into those corners!

Old Farm Road is also an access road for mountain bikers heading towards some of Hobart’s best tracks.  But this blog post is for skinny tire bikes!

It’s a steep little climb, 1.8km at 9.0%, making it a Category 3 climb in Strava’s estimation.  It has steep ramps, hairpins, a bridge, and is just one lane wide.  I love it!

Old Farm Road
Distance 1.8km
Category 3
Elevation 162m
Gradient 9.0%
Maximum Gradient 22%
Time from city 5 minutes
Traffic low
Strava http://app.strava.com/segments/1212891

How to get to the climb: Take Macquarie St, and turn right after Cascade Brewery.

There’s Old Farm Road, off to the left.  Ignore the trucks…

Mt Wellington in the distance as the road narrows to a single lane

A gentle gradient here, but enjoying the scenery too much to smash the climb!

Crossing Guy Fawkes Rivulet!

Now we start climbing.  If it wasn’t for the gum trees, we could be in Europe somewhere.

Steep hairpin bends

22% here we come!

Is that the Old Farm ahead?

Mt Wellington towers over the climb

Just for fun!

This post has been written in the style of my Top Ten Climbs Around Hobart series. Here are some other cycling climbs around Hobart:

Heroes of Yore

I suppose, if asked to name a hero from the Bible, that many people would choose David. After all, he killed giants, wrote inspiring poetry, and became a glorious king. He represents the pinnacle of Old Testament Israel. But is that really what makes him a hero?

Over the last few months, I have been listening to Charles Swindoll’s book David, A Man of Passion and Destiny, on my bike commutes, and it has been an illuminating experience. David is, like just about every significant person recorded in the Bible, all too human. His passion is his strength and his downfall. The narrative in no way glosses over these failures, which is a big part of what makes the history so compelling. However, as a historical account, it is easy to miss the emotion and the import of key events.

Buried in the middle of a paragraph are a handful of words which I think represent David’s most heroic moment. These few words are uttered by David during the height of his reign as king, after the following story is related to him:

There were two men in a certain city, the one rich and the other poor. The rich man had very many flocks and herds, but the poor man had nothing but one little ewe lamb, which he had bought. And he brought it up, and it grew up with him and with his children. It used to eat of his morsel and drink from his cup and lie in his arms, and it was like a daughter to him.

Now there came a traveler to the rich man, and he was unwilling to take one of his own flock or herd to prepare for the guest who had come to him, but he took the poor man’s lamb and prepared it for the man who had come to him.

Do you know who told this story and why? It was told to David by Nathan, a prophet, after David slept with a married woman and subsequently had her husband killed (read the full story).

Now David was at the height of his power. His wrongdoing has just been uncovered by Nathan. It would have been well within his ability to have had Nathan killed. But he didn’t kill Nathan. Instead he stopped and said: “I have sinned.” Just step back for a moment and think about that. When is the last time you heard one of our political leaders take responsibility for their actions like that? How hard is it to admit that you are wrong; and even harder when you have every facility within your grasp to avoid it?  David didn’t even have an opposition party to denounce him: he was king and could do whatever he wanted.

That’s heroism.

Another go at Longford – Campbell Town

I’m not sure which hurt more: the race, or the ride back.  I know which hurt longer.  Today was the day of the Longford – Campbell Town race, which was the first bike race I ever entered last year.  The day dawned fine, with the hint of rain on the horizon.  I woke early as I have been doing recently, but tiptoed out of bed and quietly ate two big bowls of muesli.  Now happily and heavily bloated, I checked all my gear, and double checked.  Figured if I had my helmet and my shoes I’d be ok.  It was still early, so I drove to Salamanca and had a coffee, read the paper, before I headed over to pick up Barry who would be racing with me today.  Barry was recovering from a nasty cold and had a bung knee, and just wanted to race for the fun of it, without real expectations of great results.

The 180km drive to Longford was uneventful, except that the hint of rain turned into real rain as we drove through the Midlands — both of us fervently hoping it would clear well before 1pm so we’d be able to race on dry roads.  Happily, it did.  The sky cleared up, the roads dried up, and the temperature was about 18 degrees.  Perfect.  Except for the wind.

When we arrived in Longford to get ourselves organised, at about 11am, the wind was a NNW at about 30km/h.  Not too gusty but still pretty strong.  We put our bikes together, pumped our tyres, checked various bits and bobs, ate some more, and headed out for a 4km warmup.  I felt like I was in great form as we headed down the road towards Campbell Town on the warmup, feet and heart barely ticking over and sitting on 40 km/h.  Then we turned to ride back to the start line and I realised it was all down to the wind.

Barry chose the wrong wheels for the day!

As I hadn’t raced for quite some time, I asked the handicapper to help me select a grade.  “What grade do you ride in Hobart?” he asked.  “B”.  “Ok, that’ll be D grade here.”   OK…  I guess?  I went back to the registration desk and told them that Phil has put me in D grade.  “They won’t need transponders, will they?” one of the people at the desk asked the other as Barry and I gave our details.  Great, so the assumption is that we won’t even get a placing.  Way to put my ego back into the box!  Good for me.  I’d say it lit a fire in my belly, except it didn’t.

There were two important pieces of information given at the pre-race briefing: first, that we’d have to walk across a wooden bridge in order to prevent accidents, and second, that riders caught on the wrong side of the road would be fined, disqualified and potentially even banned.  Apparently, over the previous races, there were a number of cars forced off the road by racers taking risky tactics.  I’ve never been one to spend much time on the wrong side of the road, so I wasn’t too bothered by this information.

E grade took off, with my mate Rob and 20 others, and it was a five minute wait for D grade.  Then we started, and the shock of race pace set in.  It wasn’t excruciating, like last year’s B grade start, but we weren’t standing around.  Some sort of organisation of the bunch started, with the front half of the bunch swapping turns on the front, but it was never very tidy.  Along this section, I was working hard but never really in danger of being dropped.

The wind was alternately a tail wind and a cross tail wind.  In the first cross wind section, the bunch split and I made the front selection, riding in the gutter in about 8th position.  I wasn’t very comfortable there and made an effort to form a second echelon, which actually felt easier than trying to focus on riding on the edge of the road with the wind trying to blow me off.  When we arrived at the bridge, I was feeling comfortable and made sure I was at the very front of the group before dismounting to avoid nasty surprises at the other end of the bridge!

After the bridge, I was on the front, and the bunch seemed to lose interest in moving quickly, and I soon found myself about 100m off the front of the bunch.  I wasn’t prepared to try and ride the next 40km solo, so I didn’t put an effort in to establish a real gap, and instead just focused on riding smoothly and consistently.  A couple of minutes later, the bunch closed up the gap and I happily rejoined them.

Each time the road turned a corner and put us into a different wind, a few more riders would disappear until I realised that there were only 4 of us left.  I was starting to feel tired, and I knew I needed to eat something.  It took me probably 5 minutes before I turned that knowledge into action, and in that time, the other three riders went up the road, and I was on my own!

This seemed eerily familiar.  We were only 30km into the race and I was looking at the prospect of riding the rest of it solo, just like last year.  The only difference being, I was near the front of the grade instead of having fallen off the back!  I settled into a rhythm and as the food (gel) made its presence known I found that I was slowly catching the rider ahead of me.  I got onto his wheel and recovered for a couple of minutes, before swapping to the front.  I was surprised a moment later to see that he didn’t stay with me but happy also — I was now in 3rd place on the road!  That’s a podium position…

I caught the next D grade rider (I was passing E grade riders regularly at this point) just before the road made a sharp turn east on the final 15km into Campbell Town.  As we swung around the corner, the road got very bumpy.  And the wind was, for the first time, on the front quarter and not the back quarter.  My speed dropped from 50km/h to under 30km/h, and I was working hard.  We worked together for a while, along with my mate Rob who we caught on this section, as we approached the one small climb in the race, and as we went over the top of the climb I looked back and saw a bunch approaching.  A grade.

A minute later and they swept past us, and I was able to jump into the front half of the bunch.  Exhilerating feeling!  I was now sitting on 60km/h and it wasn’t really hurting.  I didn’t try to take a turn on the front but anxiously checked the numbers on the other riders in this fast moving bunch.  No other D graders — I was happy!  Only one thing annoyed me — this bunch persisted on riding on the wrong side of the road!  Yes, we passed a couple of other riders, but it wasn’t necessary.

I didn’t contest the sprint, happy to roll over the line in the back of the bunch.  Second place in D grade.  My first ever podium finish!  I had to notify the race volunteers that I’d finished with a placing as I had no transponder…  Cloud nine time: my fastest ever 60km; I rode the race at a 45km/h average speed!  I’d won something!  Some cash!  It turns out the first place D grade rider, Glenn Myler, took out the whole race, having caught all of E grade.  Kudos to him — his first ever 1st place finish and he was pretty happy.  Barry was content just to finish, I think, with his head cold and bung knee.

Then Barry and I had to ride back to the car.  The wind was a little stronger, the gusts a little more pronounced.  And we were riding right into it, for the whole 60km.  We averaged a measly 23.5km/h on the return trip.  A couple of other riders came back with us, one of them bonking badly.  He’d had two Weetbix for breakfast — that’s all.  Sounds like what I did for the Grindelwald Challenge!  It was painfully slow and not helped by other cyclists going back in cars and giving us “helpful” comments out the window as they went past!

The only consolation on the return trip was roads devoid of traffic

It took forever, but we finally rolled into Longford.  All in all, a satisfying day!  Big thanks to Barry for the great company and to Iain for lending me some lighter wheels.