Previously: Part 2 – Ipoh (Banjaran Hot Springs Retreat)

Getting there

Rames picked us up from the Banjaran and we continued our tour of Ipoh sights whilst killing time before our flight. We’d originally planned to head for lunch, but the huge BBQ put paid to that, so we mostly just visited temples that had been built around caves.

Rachel and I at one of the cave temples

Ipoh airport is pretty small and unsophisticated. But that also meant not having to go too far to get everything done.

The flight was on Scoot, Singapore’s low cost carrier, which I’d compare (favourably) to Easyjet. No frills, but a nice modern A320 with comfy enough seats. We were given a ‘snack pack’ with a can of (full sugar) Coke and various food items.

Hotel

We picked The Clan for its location (and good reviews), and on that count it certainly didn’t disappoint.

The Clan Hotel (right of frame)

I was a little worried about squeezing into a (not huge) room after the suite in KL and villa in the Banjaran, but it was fine, partly because we were lucky enough to get an upgrade, and partly due to really thoughtful design.

Ratings:

✓ Accessible HDMI (and Chromecast)
✓ Good WiFi [1]
✓ Bedside power
✗ Human interaction free Room Service
✓ Tea making apparatus

For 4 Bodils

White Lotus potential: nope

Food

Breakfast at The Clan wasn’t included, which meant an opportunity for lie ins followed by brunch in various local places.

On our first evening we just had beer and pizza at The Good Beer Company, but we noticed Ikigai Omakase next door, which we returned to a few days later for some of the best sushi I’ve ever tasted. It was also a pleasure to watch the sushi chef in action, as he was a true artist.

My Untappd checkin photo for a Cheeky IIPA

For our second evening we checked out Amoy Street across the road from the hotel, and whilst enjoying some dumplings at Dumpling Darlings we noticed the line out of the door for GO! K – BBQ. Returning there the following evening we were treated to some of the best beef I’ve ever tasted. The ribeye was just amazing :)

Beef Set B

The final hurrah before heading home was a Cable Car Dinner. I was expecting it to be a fun experience with great views, but the food was also really good.

“Hokkien Mee” main course on a Pokemon themed cable car cabin

The booking site suggested that we’d only get the main course in the cable car, with other courses served in the bistro. But that’s not what happened on the night. It was a bit weird getting the arrival cocktail whilst standing in line to board, but extra good to have three trips around the loop as each course was served.

Cempedak Bread & Butter Pudding as the sun sets

Well… not quite the final thing. We returned to our regular haunt of Blu Jaz for some last cocktails.

Attractions

We’d visited Clarke Quay on our last trip, so it was high on our list for a return. Wandering there during the day we found it pretty dead; but returning at night (via Robertson Quay) it was vibrant and buzzing.

The Art Science Museum gave us an excuse to visit Marina Bay, and the Future World exhibition was a lot of fun.

Lillies on the lake outside the Art Science Museum

Similarly the Van Gough Immersive Experience gave us an excuse to visit Sentosa and walk across the boardwalk from HarbourFront. It took us hours to take the whole thing in, and there was a great variety of ways that the artist’s prodigious work was shown off.

A selfie in front of a vase picture

On our trip to Marina Bay we tried (and failed) to find our way to the Gardens by the Bay, so after a rather dismal walk up and down Orchard Road we gave it another go by taking the SMRT to the Gardens by the Bay stop then walking through to Bayfront for the hop back to the hotel. That worked much better, but as it was raining a little I neglected to take any photos :(

Getting around

We used Grab again for airport transfers, and for one trip over to Robertson Quay, but mostly got around on the Singapore MRT.

Note

[1] Though I was shocked to note that the (rather aggressive) filtering blocked TripAdvisor (but only on the main SSID, not the Chromecast network ¯\_(ツ)_/¯ ).


Previously: Part 1 – KL

Background

Our original honeymoon was book-ended with KL and Singapore, with most of the time in the middle spent at a beach hotel in Penang. We came to love one particular restaurant on Batu Ferringhi, but also discovered that we’re not really beach vacation people. So this time we changed things a little, with more time in both KL and Singapore, and a brief break in the middle at the Banjaran Hotsprings Retreat.

Getting there

I considered taking the train from KL Sentral to Ipoh, but there was no service offering nicer seats; and a mundane train could have been the low point of an amazing trip.

Our driver Rames as he dropped us off at Ipoh airport

We could have also just booked a cab from KL to the Banjaran, but that would have been a bit boring. So to make things more interesting I worked with Ipoh based Jaies Chauffeur Service to put together a combined transfer and tour itinerary. Our driver Rames picked us up right on time and then took us to a whole selection of attractions in the Ipoh area, including caves, Kellie’s Castle and temples. We also stopped off for some great local food, and explored some of the colonial architecture of Ipoh Old Town.

Kellie’s Castle

Hotel

The Banjaran is unlike any place I’ve stayed before, as the ‘rooms’ are all standalone villas. We picked a ‘water‘ villa, which had its own hot tub and pool.

The water from our villa

The resort also had plenty of places to get wet (and hot) outside the villa, but the villa was so nice it was super tempting to just hang out there. At one stage we just sat on the balcony by the water reading our books (with occasional interruptions from local wildlife).

The pool

Ratings:

✓ Accessible HDMI
✓ Good WiFi [1]
✓ Bedside power
✗ Human interaction free Room Service
✓ Tea making apparatus

For 4 Bodils

White Lotus potential: oh yes!

Food

The resort markets Jeff’s Cellar as a ‘gourmand’ destination, and it didn’t disappoint. The venue inside a beautifully lit cave is amazing; the ‘inception’ tasting menu was delightful; and the service was tremendous. Certainly one of the tastiest and most memorable meals of my life.

Birthday cake for Rachel after dinner at Jeff’s Cellar

For our second evening we went with their ‘in private‘ in room BBQ as something different and special for Rachel’s birthday. It also proved to be handy as we could watch the Women’s World Cup final whilst we ate (in style). Once again the food was tremendous. It’s just a shame we didn’t have room for all of it – there was easily enough for four, maybe even six.

BBQ just before we got started

Attractions

We didn’t leave the resort during our time there, as there was plenty to do, and it was just too nice. Maybe if we’d stayed another day we’d have joined one of the walks to the Lost World of Tambun attraction next door.

View from one of the hot springs tubs

Getting around

On arrival we were taken to our room in a golf cart, and treated to a tour of the various caves and pools and restaurants etc. We saw other guests being ferried around in golf carts, but chose to just walk.

Next: Part 3 – Singapore

Note

[1] The WiFi was really good for regular surfing, but struggled to keep up with streaming the football over an SSH tunnel. There was a wired connection outlet in the living room, but sadly it didn’t seem to be connected to the switch in the utilities cupboard.


Background

My first deployment in the Royal Navy was the first half of Global ’90, taking me from Plymouth to Hong Kong. Along the way we stopped in Lumut, Malaysia, which led to a side trip to Pangkor Island. It was paradise, so… when Rachel and I married in summer of ’98 I chose to return to Malaysia (and Singapore) for our honeymoon.

That time around we did a packaged trip organised by Kuoni, which took us to Kuala Lumpar (KL), the Cameron Highlands, Penang and Singapore[1]. This series of posts covers the slightly revised itinerary for the (almost) 25th anniversary return trip.

Getting there

I was once lucky enough to fly back from Singapore on Singapore Airlines, and it was one of the nicest flights of my life. So it was an easy choice to pick them for the trip to KL even though it meant a brief stopover in Changi.

Me enjoying my lunch starter on the flight out

Both flights were comfortable, and the service was great.

Hotel

On the original honeymoon we stayed at the Shangri-La KL, and it was lovely. Something that stuck with us was a taxi driver who was almost proud to take us there – “Shangri-La – number 1 first class hotel in KL”. So of course we had to go back.

The Shangri-La KL at night with the KL Tower lit up behind it

There may be newer and shinier hotels in KL these days, but the Shangri-La is still fantastic. It’s like a well maintained classic car – elegant, whilst still functional. The staff there are brilliantly helpful and friendly.

The view from our room

Last time around our package included a regular room. This time we booked a suite, which turned out to be a good choice, not just for the extra space, but for access to the Horizon Club. Evening cocktails at the club became a regular feature of our day, and a couple of Shangri-La KL regulars gave us some excellent tips for nearby places to eat (and many entertaining conversations).

Plotting another trip, from the comfort of the Horizon Club

Ratings:

✓ Accessible HDMI
✓ Good WiFi
✓/2 Bedside power (only on one side)
✗ Human interaction free Room Service
✓ Tea making apparatus

For 3.5 Bodils

White Lotus potential: possible, but unlikely

Food

Each day started with hotel breakfast, and although we could take that in the Horizon Club we generally went downstairs for the broader selection of buffet on offer. That left little room for lunch, so most days skipped straight to dinner.

Eggs Benedict in the Horizon Club for our final KL breakfast

I’d picked out a few nearby places on Google Maps and TripAdvisor before the trip, and we never made it to any of them. Walking to the place I’d chosen for our first dinner we found ourselves on the wrong side of a busy road with no crossings in sight, but a whole side street of restaurants. So we found ourselves in Manja for some tasty modern Malaysian Fusion food. The first recommendation we took from our new cocktails friends was Bar.B.Q.Tonight, which I’d noticed on the way back from Manja, and served up an excellent platter.

Normal proceedings were interrupted a little by the FIFA Women’s World Cup, and the semi-final match between England’s Lionesses and Australia’s Matildas. We needed a pub with the match on, and Healy Mac’s (just around the corner from the hotel) fitted the bill perfectly. I didn’t have huge expectations for the food, but my duck wrap was excellent, and despite the huge crowd the service was great throughout. We might have been in the minority cheering on the victorious Lionesses, but any team rivalries were very good natured.

A return to the regular routine took us to Bombay Palace, and a variety of curry I’ve not seen on a menu before. I think about three different staff told me it was ‘spicy’ in a way that inferred “this is not a white guy curry”; and it was spicy, but not too spicy, and absolutely delicious. We also got a quick Dim Sum fix at Din Tai Fung Pavilion, which had been recommended for its pork soup dumplings, though we preferred the spicy prawn ones. For our final evening we tried Zipangu, a sushi restaurant within the hotel. We went for ‘ghetto omakase’ with chirashi bowls, and they were excellent.

Chirashi bowl at Zipangu

Attractions

Last time around the Petronas Twin Towers were shiny and new, and although we visited the shopping centre there we didn’t get onto the tour. The towers don’t dominate the skyline like they used to, but the view from the tour was tremendous, and let us pick out a few other places to go.

KL tower (R) and Merdeka 118 (L) from the twin tower(s)

The KL Monorail runs right past the Shangri-La, and every time I saw it The Simpsons’ “Monorail Song” popped onto the brain radio. I had to have a ride on it, and looking at the map the KL Sentral terminus was right by one of the largest parks in the city, which hosts a bunch of attractions. Sadly we discovered that one can’t actually walk from Sentral to the park, at least not at all directly. So instead we perused the shopping centre.

The 48m walking route from KL Sentral to The National Museum of Malaysia (which is across the road)

We got our park fix with a walk up to the KL Forest Eco Park, though the hike to the entrance, which is at the base of KL Tower, was a bit hot and sweaty. Once in the park we found it a bit dilapidated, so we didn’t linger. I guess it was better value when it was free.

Entrance to KL Forest Eco Park

For our last full day in KL we took a trip to the Royal Selangor visitor centre for a tour of their pewter factory. We also made some pewter knick-knacks for ourselves as part of their ‘Foundry’ experience.

Pewter pieces at ‘The Foundry’

Getting around

Most things were a short walk from the hotel. For the transfer from the airport we used Grab, which is the Asian version of Uber/Lyft.

Next: Part 2 – Ipoh (Banjaran Hot Springs Retreat)

Note

[1] Sadly there wasn’t a good option that included Pangkor Island.


July 2023

01Aug23

Pupdate

July brought us back to the Lake District, which the boys love as it means more time outdoors for extra long walks (and the odd little swim if they fancy).

Once we were back Milo visited the oncologist for the end of his chemotherapy (at least for now), as he moves to monthly monitoring.

Lake District

We once again returned to Keeper’s Cottage on the Graythwaite Estate, which really felt like a home away from home on this third time staying there. The dogs were really excited as soon as we pulled onto the drive, as I think they recognised it as somewhere they’ve loved before.

Walks

Charlotte and I climbed Scarfell Pike, which deserved its own post. We also returned to a few walks we’d done on previous trips.

The ‘coffin route‘ is a walk that we frequently did with the kids when we used to rent a place in Ambleside, as it’s nice and level, and not too long.

The map above captured a slight detour where we missed the start of the path from the road, and had to double back. From Grasmere we jumped on the bus back to Ambleside, which was a novelty for the dogs.

Another favourite walk from when the kids were small, and we’d stay in Ambleside, was Wray Castle to The Ferry House along the Western edge of Lake Windermere. We’d do it with the Walkers Ticket from Windermere Lake Cruises, using their boats to complete the loop back to Ambleside via Bowness.

The derivative of that walk that we did this time started at the little (free) car park at Red Nab, and looped through the gardens of Wray castle before returning back along the edge of the lake. I always remember that as the best bit of the walk, as our dog at the time could run off the lead. It gets a bit tedious later as it’s on road with the ever present risk of having to get out of the way of cars. The footpath has been upgraded since we last walked it, which seems to be part of a broader programme of improved walking routes along the West shore. That meant (a lot) less mud and puddles to deal with, but also many more cyclists; so unfortunately the dogs had to stay on their lead.

The route around High Dam was one we did a couple of years ago, and returned to as it’s scenic and not too hard on the legs. The circuit of the dam is essentially level, whilst the ascent from the car park certainly isn’t, though there are alternative paths that provide longer routes around the steepest parts.

Paddleboarding

Each time we’ve stayed at the Graythwaite Estate we’ve rented something from their water sports centre. For me that’s generally been a canoe or kayak, whilst Charlotte has usually preferred a paddleboard. I was persuaded to try one myself this time.

I was very happy to make it back without falling in :)

Berlin

The start of the month found me back in Berlin for Fluttercon (as part of Droidcon). It was a great gathering of the Flutter community, which is one of those vibrant groups that hasn’t (yet) had the fun squeezed out by men in suits.

The trip was cut short due to travel expense limits, as flights back on Friday evening were silly prices, but it was still long enough to take in some parts of the city I’d not seen before. The Zoologischer Garten area chosen for the speaker hotel was lots of fun, with a cornucopia of restaurants, bars and shops; so I was able to get my fix of currywurst and various other local delicacies without straying too far.

Comedy

Most years (at least before Covid came along) we’d go to Edinburgh in August for the Fringe. Sadly that won’t be happening (again) this year due to some other plans (more on that next month).

Thankfully we were able to catch up with some of our favourite comedians by going to a preview show for Rachel Parris and Marcus Brigstocke at The Clapham Omnibus Theatre. Those going to their Edinburgh shows are in for a treat – they were both great. I’m also hoping that we might catch some post Fringe tours as they pass through London or Brighton.

Veteran’s Railcard

It’s been a couple of years since I got my Veteran’s Railcard. In that time it’s saved me £680 on train fares, which includes £184.95 on work trips[1] and £18.95 on trips with my wife where she also qualifies for a discount by travelling with me.

The best bit (and the part that distinguishes the Veteran’s Railcard from other Railcards I might buy) is that discounts also apply to First Class tickets; so I’ll often treat myself to a comfy seat (and some included snacks), particularly on long trips like seeing friends and family up in Newcastle. It’s also pretty handy that it covers peak fares, where many other Railcards are just for off peak travel.

Solar Diary

After such a glorious June, July was always going to be a step back. But with Atlantic weather fronts rumbling over the country like a freight train it’s been dark and wet, and not so good for generating.

585.5 kWh generated in July

The datalogger also stopped sending for a while, and took a router reboot to get reconnected, which explains the even bars towards the end of the month.


Scafell Pike

01Aug23

The Lake District has been a frequent holiday destination since I was a kid, but I’ve never climbed England’s highest mountain there. Partly that’s because it has a reputation for being a tricky climb, which it’s really not (unless you choose to make it tricky). Partly because it’s not so easy to get to (versus say Helvellyn, which I’ve climbed more times than I can remember, because it’s ‘right there’ from Patterdale or Glenridding).

Planning

There are a bunch of great resources offering routes and other advice:

After checking them all out I decided on Wasdale Head as the starting point, then a (hopefully) gentle descent down to Great Langdale. This essentially combined two different routes, with the Scafell Pike summit as the connection point.

Having different start and end points was made possible by family members offering lifts. Sadly neither point is particularly easy to get to by public transport.

Getting there

The scafellpike.org.uk site has an amusing graphic showing estimated driving times to Scafell Pike, but even though we were already in the heart of the Lake District it took 90m to get to Wasdale Head. The drive took us through parts of the National Park I’d never been to before, and there was plenty of natural beauty to soak up along the way.

The ascent to the summit

From Wasdale Head it’s a pretty steady climb all the way to the top. We chose the Mickledore approach, as Charlotte likes climbing.

From there, the approach to the summit is a bit of a rocky moonscape.

As we neared the summit we rejoined with the masses who’d chosen the Hollow Stones route, and it all got a bit busy. We’d made good time, arriving at the summit 2h after starting out.

Chambers Crag

From the summit we should have continued on to Broad Crag and Ill Crag, running along the top of the ridge line. But Charlotte fancied a different route, and asked if we could go down Chambers Crag. We had time on our hands, conditions were good, and so I happily changed the plan.

This got us an interesting descent into the valley, which of course meant more ‘up’ later. There was also some more scrambling :)

I’ve only found one resource online describing a route via Chambers Crag, Scafell Pike – The Crazy Route! It wasn’t so crazy, but it certainly got us away from the crowds. We saw two people coming up that way, and got to Knotts of the Tongue before bumping into anybody else.

Down again

The descent was pretty mundane, and perhaps less gentle than I’d hoped, with pretty much constant steps down all the way to the ford marking the entry into Langdale Fell valley. From there it was a level (and often waterlogged) stroll to the car park next to the Old Dungeon Ghyll Hotel.

The drive home from there was 45m, and we were back in time to freshen up before dinner after a full day of activity.

It’s pretty obvious when we stopped for lunch on that final chart ;)


After 6 months of chemo Milo has hit a major milestone – the end of his CHOP protocol.

A rare picture of Milo without Max

His most recent scan showed some improvement, and the specialist recommended ending his chemotherapy for now and moving to monthly scans to monitor the situation. The general idea is that the chemotherapy drugs will be more likely to be effective when needed again if he’s not continuously taking them. I should note that the Doxorubicin (the H in CHOP) can only be administered 6 times, and he’s had 4 already.

After being a fat boy, we’ve also managed to stabilise his weight at 5.6kg.

In the week before his final treatment Milo also discovered that there were car rides that didn’t end at a vets’ surgery. More on that to follow in my July end of month post.

Costs

As I mentioned in counting the cost the specialist estimated that chemo would cost £8,000-£10,000. I now know that the total was £7,118.31, though as previously mentioned we were over £2100 in before starting chemo.

Going from previous bills I’m expecting the scans and consultations for the monitoring phase we’re now in to run at £420/month, so the ongoing costs are still far from trivial (especially as those scans can’t be done at my local vet, which is where much of the chemo happened).

Insurance renewal

At least those costs should be covered by insurance. I’ve got a renewal quote from ManyPets, which is twice his premium last year, but still a good deal.

Past parts:

1. diagnosis and initial treatment

2. first setback

3. back on track

4. second setback

5. easing the pace

6. counting the cost

7. fat boy


It’s been a while since the last entry here, because not much has been happening, which is mostly a good thing.

Milo and Max enjoying a ‘puppachino’ at a local sausage dog meetup

Ileal wall changes

Milo was back at the specialists NDSR at the start of June for the Doxorubicin that marked the end of his third cycle of the CHOP protocol for chemotherapy. He also had a scan to check progress, and that scan identified ‘Ileal wall changes’, which were a new finding and a cause for concern.

So… he was back at NDSR two weeks later for another scan (and the Vincristine to start his forth round of CHOP). That scan didn’t note any changes, so we’ll check again at the end of this round.

At this stage we’d be hoping for no evidence of disease, meaning a complete response (CR) to the chemo; but sadly that’s not where we’re at. He’s had a partial response (PR), and seems happy and healthy on the surface. But palliative chemo can only be expected to hold off the cancer rather than cure it, which means we’re probably looking at months of extra time with Milo rather than years.

Gained weight

At the start of treatment Milo slipped below 5kg and was looking pretty skinny (his normal weight is 5.5kg), and we were having to give him extra meals just to hold onto that.

The extra meal at lunch got discontinued months ago, but he’s still been getting extra kibble with breakfast and dinner. He’s also been finishing off Max’s dental food, which the vet warned might make Max gain weight.

Every recent trip to the vets has been accompanied by ‘has gained weight since last time here’, and suddenly we were at 6kg (from 5.7kg two weeks earlier), and a harness that just fitted. So it was time to cut back the extras, and get him back to a normal weight. A diet of just (his favourite) Butternut Box meals seems to have got things back to where they should be, and maybe some kibble can now be added to keep him stable.

Past parts:

1. diagnosis and initial treatment

2. first setback

3. back on track

4. second setback

5. easing the pace

6. counting the cost


June 2023

30Jun23

Pupdate

The weather has been so nice that some days we’ve had to keep the boys to shady routes so that they don’t get too hot. But they’ve also been able to enjoy some extra long walks and running about off the lead.

Back to the Big Apple

Speaking at QCon NY gave me the opportunity to return to the city for the first time since (well) before the pandemic. It had been over 5y since my last trip, which seems a little weird given that I used to be there many times a year.

Much had changed, and much has stayed the same. It was cool to use the Subway with contactless payment, but a shame that it doesn’t work on the JFK AirTrain :/ It was also nice to return to old haunts like Barcade, but also check out places I’d not seen before in Brooklyn.

One of the visual highlights was the InfoQ staff dinner after the conference, which was at a rooftop area in the conference hotel.

Flight report: Virgin Upper Class

I used some points to book my flights (though the taxes still hit nearly £1000, eating most of my speaker travel stipend). When I first looked it was possible to get Premium Economy out, and a day flight home, but by the time I was confirmed to speak there were slim pickings left, so I had to splurge extra points for Upper Class both ways.

Out – VS9 I took the train and Elizabeth Line to the airport for the first time, which worked OK (despite some delays). Virgin’s dedicated Upper Class security line was quiet, and I was swiftly in the lounge. Somehow it seemed less hip than before, and the power outlet at my seat didn’t work. The service was great though, and I got a light lunch to tide me over until flight service. The flight itself was on a 787, and I’m afraid to say that the ‘hard product’ is every bit as bad as the reviews say – mostly for being hard. It didn’t matter much on a day flight, but I’ll be avoiding Virgin’s 787s in Upper until they do a refurb[1]. The service from Tom was amazing, and I was really pleased to see English wines on the menu[2]. The really good news was a super early arrival (and actually getting to a gate). I’d hoped to be at the hotel between 7-8, and I was there just after 6 :)

Back – VS138 Given a free choice I’d not have picked the 11pm flight. But it was a chance to try out Virgin’s new A350 Upper Class suite, and I spent the dead time enjoying dinner, a few cocktails, and the final episodes of The Peripheral in the lounge. Things got off to a bad start, with an hour delay caused by a broken Delta flight, which meant we also had to be bussed to the aircraft. Once on board though everything was good. The ergonomics of the new ‘suite'[3] are great – probably the best business class offering I’ve experienced so far. I got a good comfortable night’s sleep, and woke just in time for one of the best breakfasts I’ve had when flying. Sadly the late arrival meant a pitstop in the arrivals lounge to freshen up was off the menu, but it was good to be home.

Solar diary

With the summer solstice June is obviously the best month for solar, but we’ve also been blessed with amazing weather, so it’s been a bumper solar harvest.

794.8 kWh generated in June

Quite a few days there with 32kWh of generation, and in amongst that I did see a peak of 4.2kW, which is the nominal output of my system.

SEG

EDF have finally got back to confirm that I’m set up for Smart Export Guarantee (SEG), though I won’t see any money until September, as that’s when the next quarterly reading is dues. So it will just about be at the anniversary of my application :/

Part of the issue there seems to be that they can’t get data from my ‘smart’ meter, which sadly is one of the first generation ones. Weirdly though, they seem to have my gas meter readings, which are sent through the electricity meter.

Beating Beat Saber

There’s a Queen music pack :)

I’ve not done all the tracks yet, and I thought I was on for a first time full combo with One Vision – right up until the last four blocks :(

‘Stone Cold Crazy’ was a new one for me, as it doesn’t feature on either of the Greatest Hits compilations, and I’ve never properly explored their back catalogue. It’s a great Beat Saber track though, and does exactly what it says on the tin.

Notes

[1] I’d also note that the economy seats in Virgin’s 787s are awful. A few years back I bought an inflatable cushion for when I found myself in those seats after suffering them on a trip to Seattle. Premium Economy is definitely the pick for these aircraft.
[2] The Hambledon Classic Cuvee sparkling, and a still Bacchus.
[3] It might be a bit of a cheek to call it a ‘suite’ as the door doesn’t close – it moves a few inches, reducing the gap by about a third.


May 2023

01Jun23

Pupdate

Towards the end of the month it started staying dry enough to start returning to some of the longer ‘summer’ walks.

The end for ‘Trigger’s AirPods’

In a previous post I’d mentioned that I probably should have spent my money on some new AirPods Pro rather than keeping on replacing parts of my old ones. That was borne out by yet another failure, with the right earbud going all crackly. I’ve now got myself some AirPods Pro Gen 2.

RISC-V dev board

I have a talk on Dart/Flutter on RISC-V coming up at Fluttercon in July, so I wanted to get some hardware to play with (rather than just QEMU emulation). After a bit of poking around the StarFive VisionFive 2 seemed like the way to go, and took a couple of weeks to arrive (when ordered from Amazon).

The initial experience with Debian was a little lumpy, but then an Ubuntu image came along, which easily does everything I want – running Dart and Docker.

Solar diary

May brought another substantial jump in solar output, which came just in time for getting the hot tub out for the half term break. So far it looks like it’s running almost entirely on generated electricity rather than imported. That means I’m missing out on Smart Export Guarantee (SEG) income, but that’s pretty measly, so the tub isn’t costing too much to run.

677.3 kWh generated in May

On the topic of SEG, I called EDF to chase up my application, and it was stuck for no reason. I was told that I’d be contacted in a few working days to get the final pieces set up. That was three weeks ago, so I fear another call is needed to chivvy things along. On the positive front they said they’d pay for export from the original meter reading at application all the way back in October.

Beating Beat Saber

I didn’t spend much time on Beat Saber this month, but the short time brought a decent handful of Full Combos on the remaining Lady Gaga levels.


One of my favourite features of Dart is its ability to create executables (aka ahead of time [AOT] binaries)[1].

Creating binaries for the platform you’re running on is very straightforward, just dart compile exe but Dart doesn’t presently support cross compilation for command line binaries, unlike Rust and Go, which have also surged in popularity. This is a great shame, as Dart clearly can cross compile when it creates Flutter apps for iOS and Android[2].

For stuff we release at Atsign we often need to create binaries for a wide variety of platforms and architectures. In part that’s because we make things for the Internet of Things (IoT) market, and there’s a wide variety of dev boards etc. out there to suit different needs and (power) budgets. Our SSH No Ports tool is packaged for:

  • macOS
    • arm64
    • x64
  • Linux
    • arm
    • arm64
    • riscv64
    • x64

There are things where we might also add Windows (x64 and maybe even arm64) to that list.

x64 is easy

Using GitHub Actions it’s relatively easy to build the x64 stuff. All I need is a matrix:

jobs:
  x64_build:
    runs-on: ${{ matrix.os }}

    strategy:
      matrix:
        os: [ubuntu-latest, macOS-latest]
        include:
          - os: ubuntu-latest
            output-name: sshnp-linux-x64
          - os: macOS-latest
            output-name: sshnp-macos-x64

and then I can run through the steps to build something e.g.:

    steps:
      - uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2
      - uses: dart-lang/setup-dart@d6a63dab3335f427404425de0fbfed4686d93c4f # v1.5.0
      - run: mkdir sshnp
      - run: mkdir tarball
      - run: dart pub get
      - run: dart compile exe bin/activate_cli.dart -v -o sshnp/at_activate
      - run: dart compile exe bin/sshnp.dart -v -o sshnp/sshnp
      - run: dart compile exe bin/sshnpd.dart -v -o sshnp/sshnpd
      - run: cp scripts/* sshnp
      - run: tar -cvzf tarball/${{ matrix.output-name }}.tgz sshnp
      - uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2
        with:
          name: x64_binaries
          path: tarball

Everything else needs a bit more effort

At the moment GitHub Actions only supports x64. Arm64 for MacOS is on the roadmap for public beta in Q4-23, but that leaves a bunch of other platform:architecture combinations that can’t be done natively in a hosted Actions runner.

Of course we could use self hosted runners, but that throws up a bunch of other issues:

  • They’re not recommended for open source projects, due to security issues.
  • We’d be running a bunch of VMs (or even hardware) full time, and hardly using it.
  • RISC-V isn’t supported yet.

I also took a look at Actuated, which makes use of ephemeral Firecracker VMs to get around security concerns. It certainly helped with arm64, but wasn’t able to move the needle on armv7 and RISC-V.

For Linux at least Docker Buildx can help

Multi-platform images provide a convenient way to harness QEMU to build Linux images for a variety of architectures, and is obviously the way to go for Docker stuff. But in this case we want a binary rather than a Docker image. It turns out that Buildx can help with this too, as it has a variety of output formats. So I can construct a multi stage build that results in a tarball:

FROM atsigncompany/buildimage:automated@sha256:9abbc3997700117914848e6c3080c4c6ed3b07adbd9a44514ce42129a203a3c5 AS build
# Using atsigncompany/buildimage until official dart image has RISC-V support
WORKDIR /sshnoports
COPY . .
RUN set -eux; \
    case "$(dpkg --print-architecture)" in \
        amd64) \
            ARCH="x64";; \
        armhf) \
            ARCH="arm";; \
        arm64) \
            ARCH="arm64";; \
        riscv64) \
            ARCH="riscv64";; \
    esac; \
    mkdir sshnp; \
    mkdir tarball; \
    dart pub get; \
    dart compile exe bin/activate_cli.dart -v -o sshnp/at_activate; \
    dart compile exe bin/sshnp.dart -v -o sshnp/sshnp; \
    dart compile exe bin/sshnpd.dart -v -o sshnp/sshnpd; \
    cp scripts/* sshnp; \
    tar -cvzf tarball/sshnp-linux-${ARCH}.tgz sshnp
    
FROM scratch
COPY --from=build /sshnoports/tarball/* /

What I actually get there is a bunch of architecture specific tarballs, inside a tarball, but it’s easy enough to winkle them out with an Actions workflow job:

  other_build:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2
      - uses: docker/setup-qemu-action@e81a89b1732b9c48d79cd809d8d81d79c4647a18 # v2.1.0
      - uses: docker/setup-buildx-action@4b4e9c3e2d4531116a6f8ba8e71fc6e2cb6e6c8c # v2.5.0
      - run: |
          docker buildx build -t atsigncompany/sshnptarball -f Dockerfile.package \
          --platform linux/arm/v7,linux/arm64,linux/riscv64 -o type=tar,dest=bins.tar .
      - run: mkdir tarballs
      - run: tar -xvf bins.tar -C tarballs
      - run: mkdir upload
      - run: cp tarballs/*/*.tgz upload/
      - uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2
        with:
          name: other_binaries
          path: upload

The main problem with this is that emulation makes things super slow. Each AOT binary takes about 10m to compile, leading to a 30m build process for a package with 3 binaries. As this guide illustrates, things would be much faster with a tool chain that supports cross-compilation (like Golang). We work around this by sending a chat notification when the building is done:

  notify_on_completion:
    needs: [x64_build, other_build]
    runs-on: ubuntu-latest
    steps:
      - name: Google Chat Notification
        uses: Co-qn/google-chat-notification@3691ccf4763537d6e544bc6cdcccc1965799d056 # v1
        with:
          name: SSH no ports binaries were built by GitHub Action ${{ github.run_number }}
          url: ${{ secrets.GOOGLE_CHAT_WEBHOOK }}
          status: ${{ job.status }}

If you’ve got this far you might also want to check out Bret Fisher’s guide to multi-platform-docker-build, which opened my eyes to a few things.

Notes

[1] I’ve talked about this (and some of the trade offs) at QCon Plus in my Full Stack Dart presentation, and QCon SF in my (yet to be published) Backends in Dart.
[2] J-P Nurmi has documented how the SDK can be hacked for Cross-compiling Dart apps, but it’s not something I personally want to spend time maintaining.