Firstly, and technically belonging to last week, a couple of photos from the SVP that show (a) how parched the landscape is at the moment, and (b) how pleased I apparently was to finish.
After that extended hot dry spell, I suppose it was inevitable that when we had our planned work get-together in the park on Tuesday afternoon, it clouded over and actually rained a little. Not enough to really do any good though. We sat around for a bit, got visited by various friendly dogs, had an ice cream, and played Faye’s Viking stick-throwing game again.
Somewhat surprisingly, my legs survived both Tuesday evening’s club training and Wednesday’s “Two Rivers” race – a social club handicap race with runners setting off at various times from Landguard Fort, choosing our own routes and converging on the Ferryboat Inn for a few beers, around five miles later. Admittedly I was a couple of minutes slower than last time it happened (pre-pandemic), but there was a tailwind that day, and it was very much against us this time. Excuses excuses …
More boring running stuff: Run for Coffee first thing Friday, what turned out to be my course best at Chantry Park parkrun (where my boss turned up to take part for the first time), and a long slow one out to Martlesham today to grab this month’s hollow tree photo (I need to find four more trees now, to finish the year). It’s also nice to be able to describe 14 miles as “long” again!
I bought a cheap blood pressure monitor so I could take part in the ZOE blood pressure study. My three readings came in at 131/86, 134/87 and 121/85, which I just assumed was normal, but now I’ve looked it up might be slightly on the high side. Probably not to the point of worrying about it though.
At the pub on Friday lunchtime someone complimented my bike, which apparently they remember seeing “outside Crown Pools” (which is technically true, although I was in the pub next door rather than swimming). Seemed odd, as it’s not really anything special other than being fairly purple.
A pretty uneventful week, for the most part. Although there was the small matter of the SVP50 on Saturday, which I’d entered a couple of weeks ago for reasons best known to myself, despite the distance being well out of my comfort zone, and before it turned out it would be taking place in a 32°C heatwave.
The race is the relatively new little brother of the SVP100, and covers 50km of the Stour Valley Path, from Sudbury to Brantham. Definitely not an event to treat as a race, especially in this weather, and I ran it with Emma, who’s done a few ultras before. I left her in charge of setting the pace (including walking the uphill bits, and deciding to switch to 25 min run/5 min walk by about halfway), which meant all I had to worry about was keeping up. Both of us have something of a reputation for poor navigational skills, but somehow we managed to cancel each other out, never both missing a turn at the same time. I managed to trip over 2½ times, but without doing any damage to either my body or my Garmin.
The heat was definitely the main feature of the day, and the excellent volunteers on the three aid stations with food, drink and hosepipes were very welcome, as were the occasional churchyard taps which gave extra opportunities to soak caps and flexible sports head pipes1 in cold water. We finished in about 6 hours 37 (oddly the tracker shows a two minute difference between our times, despite crossing the start and finish lines together. Not sure whether the actual results will be more accurate when they come out, but anyway it definitely wasn’t a day to worry about times).
Overall it was much less unpleasant than I thought it might have been, and there wasn’t really any point where I’d have said I definitely wasn’t enjoying it (or maybe I’ve already blocked the memories out). To be honest I don’t really think I felt much worse than the last time I was at Brantham Leisure Centre, after finishing the Friday 5 there a couple of weeks ago. Maybe there’s something in this long distance malarkey after all, but I’m definitely not going to start calling myself an ultra runner yet!
Another half day of greyhound-sitting this week. Apart from occasional bursts of manic activity, she seems admirably lazy (I see why people compare them to cats). Here she is relaxing (?) after having refused to go for a walk:
The trail camera I ordered finally arrived, and the first night I put it out it picked up a pair of badgers passing through the garden. And some impressive weeds.
On Thursday evening I got a phone call from someone up the road who’d found a friendly hungry cat wandering round and thought it might be Shadow, but when I went to check it wasn’t her. They seemed pretty convinced it was a stray, but couldn’t take her in as they had several cats and a dog and nowhere to shut her away, so I said I’d take her for the night and find out whether she had a microchip. I went home and got a cat carrier, at which point she suddenly became a whole lot less friendly, and shut her in the utility room (which she also wasn’t too happy about) with some food and water and a litter tray.
I took her to the vet on Friday morning and it turned out she did have a chip, so they contacted the owner to go and collect her. Apparently she only lives just round the corner from where she was “found”, so clearly not a stray at all. Hopefully she’s not too emotionally scarred from an unexpected night of incarceration!
A bit of a bike-run-bike type weekend. Ipswich parkrun was cancelled yesterday because of travellers on Chantry Park, so a few of us rode out to Alton Water to give that event a try. It made a nice change, although I didn’t do a great job of saving my legs for today’s race, finishing in 21:36. Then today we got back on our bikes to head out to Woodbridge for the post-covid return of the Ekiden Relay. This is a great event in which teams of six run a marathon as a relay on a 2.5km loop (the legs are 7.2km, 5km, 10km, 5km, 10km and 5km). About 150 teams take part, from pretty much all the running clubs in the area (our club had ten teams across the various categories).
This year was the first time I got to run the 7.2km leg, which meant (a) it wasn’t quite as hot as later in the day (but still boiling, as is traditional), (b) I didn’t have to stress about being ready at the right time to take the baton from the previous runner, and most importantly (c) half an hour after the event started I was free to indulge in ice cream, beer (an extra incentive to cycle there instead of driving!) and the mountain of cakes etc that people had brought along.
I learnt a lesson I’ve already learnt many times at work, spending most of a day trying to implement something in too big a chunk, driven only be tests at the boundary of the module I was working on. It felt like it was just about simple enough to get away with doing that, but then I realised I’d misunderstood the requirement, and it was actually even more complex. At least at that point I had enough sense to stash my changes, start again, and build it up in smaller chunks, with more focussed unit tests. As you’d expect, the resulting code was simpler, more modular and easier to understand. Don’t do as I do etc.
A mostly low-mileage running week, with a 5k race on Tuesday, a 5 miler on Friday, parkrun on Saturday and very little else … until today, when I decided to make up for it with a long run. I did a loop of Alton Water, but also ran there and back, and after a few route tweaks (some intentional; others less so) I ended up doing just over a marathon distance. Oops.
On Thursday I got to dog-sit for Sky the greyhound, who was very well-behaved (mostly she just lazed around, which I think is pretty much par for the course for greyhounds). I also took her for a walk in the evening, and I’ve never known a dog so good at walking to heel. She pretty much spent the whole time with her head level with me, and the lead hanging loosely. Very impressive.
I very rarely watch any sport, but decided on a whim to stick the telly on for the England/Germany game. As far as I could tell the standard was extremely high (but then I used to get subjected to watching the occasional Ipswich Town match, so I might just be easily impressed). I’d just about got to the point of assuming England would lose on penalties (I thought that was the rule when playing Germany), so that third goal was a nice surprise. Well done group of people who happen to live on the same side of arbitrary historical map lines as me, I guess.
The fox has been back again, but I haven’t seen the badgers again yet. I was hoping to have cameras set up by now, but I made the mistake of ordering them from somewhere cheap on the internet, and they seem to have sent me a random battery pack instead.
Like a lot of people, I spent the beginning of the week hiding indoors with the curtains closed trying to avoid the ridiculous heat (and it was only mid-30s here, so we had it easy). The cats seemed to enjoy being out in it though.
Another race-free week, and despite the weather I managed to get a reasonable mileage in again. A few social runs – running round Paul’s field in lieu of Tuesday’s club session before relaxing in the finally tolerable evening temperature with beer and chilli, a Run for Beer in Felixstowe on Wednesday evening, a Run for Coffee on Friday morning, and another of Justin’s “trolley dash” five mile informal races today – plus a couple of slow solo trail outings (13 miles on Thursday and 17 yesterday, with the latter including parkrun in the middle). My, that was a long sentence.
Jane’s just got a retired greyhound, and I offered to dog-sit next week when she (Jane) has to go into the office for a day, in case she (the dog) doesn’t like being left alone. I went round to see them yesterday, to check she (the dog again) didn’t take a dislike to me, but when I arrived she greeted me excitedly like a long-lost friend, and was quite happy just lying around when Jane popped out for a while as an experiment.
I’ve now made my way through all seven series of Buffy. I almost timed it perfectly for the Buffering podcast, which I’ve been listening to in parallel, but having experienced that as a fast-forwarded journey through all the travails of 2016 to the present day, I need to wait for the last five episodes to be released. I guess it’s time for Angel/Angel on Top in the mean time!
I got home today to discover that a large branch on my apple tree had apparently decided to take on a more ground-based role. The number of living branches is slowly reducing – I don’t know how long the tree’s been alive (or how long apple trees generally live) but it looks pretty old.
Every time I come to my blog to post a new set of weeknotes it asks me to log in, and every time I tick the “remember me” box in forlorn hope that it actually will. Thanks to lethargy this is all still the same self-hosted WordPress installation on Dreamhost that it’s been since 2006, so presumably I could fix that, but … yeah, lethargy.
On Monday I actually had to do a scheduled upgrade to the EE network monitoring application that I’m responsible for (ie design, develop, test and support. I know, single point of failure and all that, but I haven’t failed yet). Normally I just deploy changes as soon as they’re ready (usually at least once a day), but this one involved a fairly major change to the main dashboard, switching over to the reworked version we’ve been building up as a beta for a while, so they went through the official change process so the network operations people weren’t taken by surprise. Naturally an hour beforehand my broadband went down, but fortunately it returned in time (and actually tethering to my phone would have been fine), so all went well. Also, no-one complained about the change, and one person said they liked it, so I’ll count that as a win. Still a few performance kinks to iron out, but the GenServer actor model makes it relatively easy to reason about and benchmark the way messages sometimes backup.
Also two rare trips to the office, both for completely separate interview/assessment processes (I was on the assessing side of the table). One was for a group of applicants for a new cohort of women developers in conjunction with Code First Girls, and the other for an internal promotion. Thankfully these things are generally pretty informal these days, as I used to find interviewing almost as stressful as being interviewed.
Friday evening saw one of the big Ipswich races – the Twilight 10k – with the temperature already starting to ramp up (though nowhere near as bad as it could have been). It didn’t feel great, but it turned out I’d got my fastest time yet for that event (though a way off my PB time). We went for a couple of beers (literally just two, mainly thanks to the rather glacial service in Wetherspoons) afterwards, but it felt like I’d had far more when I woke up on Saturday, which I guess was probably dehydration.
I got woken in the night by some loud scuffling outside, which didn’t quite sound right for the fox or the cats, and when I shone a torch out of the window there was a badger on the patio. I went down to have a proper look, and it turned out there were two or three cubs running around, which was pretty cool. They didn’t hang around for long as I couldn’t see them in the dark and they didn’t like it when I turned a torch on (hence no photos), but I’ve ordered an infrared trail cam to see what else it detects in the garden.
Not looking forward to the heatwave, and glad it’s not going to be quite as bad here as in other parts of the UK. It’s funny how when you say you don’t like the heat people tell you you shouldn’t complain, as though they somehow haven’t grasped the concept of not liking something.
Oops, completely forgot to write up any notes on Sunday. Or Monday. It must be because my life’s so eventful and busy …
So, um, what did I do last week? Hmm.
We’ve started running an agile development primer thing for some colleagues in India, based on the one we used to (and may soon again) do for new graduates. We cover the basics of clean code, refactoring, automated testing, test-driven development and so on, with a mix of talking, demos and hands-on exercises. We’re using Java because that’s what people are familiar with, although “people” doesn’t really include me (last used the language in anger around 15 years ago) or Anders (who had to learn it specially). It’s harder to do this kind of thing remotely, but unavoidable, at least for now. At least doing it one morning a week is less intensive than three or four days straight.
With no racing this week I managed to run 57 (slower) miles, which is my highest weekly total since last October. I also added graphs to ytd.kerryb.org, so I can see my cumulative mileage starting to move towards the target line again rather than away.
Some of those miles were a massive group run round the Big Hoot Trail owls in Ipswich (and then to the pub). I took my usual “hiding at the back” position for the group photo, but as we were on the town hall steps I ended up less well-hidden than usual, on the apex of a pyramid.
I made some ginger nuts for the first time in ages. In a remarkable display of restraint, I still haven’t finished them.
Well I successfully made it into the office on Monday and Tuesday, for the first two full days since March 2020. I remembered how to get there, I eventually found the old lock I’d left in the bike shed, and I forgot neither my laptop nor its power supply (although a 15″ Macbook is a bit less wieldy than the 13″ one I had two years ago, especially as I had panniers then and only a rucksack now). What I did forget though, at least on Monday, was my pass card. Particularly annoying given that security on my building has been tightened up even more, so I couldn’t even escape without someone letting me out. Also, thanks to some bizarre design decision, the toilets are outside a door that needs a card to get back in.
The office itself has been “upgraded” in the intervening time, so now instead of having our own desks where we can leave whatever possessions we see fit, it’s now first come, first served for any of a whole roomful of identical sterile desks, all lined up in neat rows, with stupidly wide monitors that block your view of whoever’s on the other side. Anyway, it was a nice change to see people, and at least I got a few games of table football in.
A surprisingly successful week on the running front, starting with the second of the Ipswich Summer Series 5k races in Christchurch Park. These seem to be getting less and less popular (probably thanks to a combination of the price creeping up and them no longer handing out bottles of wine as prizes), but I’d already paid for all four in one go, and with only 50 entrants I finished in a frankly ridiculous fifth place, picking up another age group trophy.
Then we had the last of the Friday 5 [mile] races, and despite it being on a fairly flat course at Great Bentley, and not too hot for once, I didn’t feel particularly optimistic. I was quite surprised, then, to still see a 33 on the clock as I turned the last corner to the finish line, and just about managed to sprint to a 33:59, which I then realised was a PB. Maybe I’m not quite getting irredeemably old and slow quite yet!
For some reason I then decided not to take it easy at parkrun, and managed a half-reasonable time, then ignored my original intention to skip today’s planned 13 slow miles, instead accidentally extending it to 18 (well mostly accidentally – some of that was a slight detour at the far end to a pub to refuel with a pint and some crisps). The main purpose was to get this month’s hollow tree photo – it’s an excellent tree that you can actually climb up the inside of, but that doesn’t really come across in the picture.
Nearly forgot to post something this week. It feels stubbornly like a Saturday for some reason, which doesn’t bode well for me remembering that tomorrow I’m actually supposed to be going into the office for the first time in ages. It’s not that I’ve particularly avoided it up to now, but I’ve got into such a routine that it doesn’t usually cross my mind that I could go in until I’ve already made a coffee and started work. Anyway, my boss’s boss is in the country at the moment and in our office tomorrow (and Tuesday I think), so it’s probably a good idea for us to actually be there to meet him.
I’m not really sure much has happened since last time. I spent a couple of hours working out how to make Chartkick.js play nicely with Phoenix LiveView, and because I was feeling public-spirited and there wasn’t much detail around of how to do it (I think it’s one of those things that’s just simple enough that if you look on forums you see people asking, being given a hint then coming back saying “thanks, that made sense” without explaining exactly what they did) I decided to write it up.
Other than that, I think everything’s just running. We’ve got a trail of giant painted owls in Ipswich at the moment, so I went out to run round them on Wednesday. I missed a few, and still managed to go a couple of miles further than the planned 10. Then Stowmarket Friday 5 (much less roasting this week, but ended up slower than it felt), parkrun yesterday, and a nice chatty 14 mile trail run today on the Stour Valley Path, including a few wrong turns and a stop for an ice cream and a little paddle in the river. My Garmin is now recommending 3.5 days’ rest, which seems a bit excessive (especially as I have another 5k race on Tuesday).
I was converting some “old-fashioned” Phoenix code to a LiveView today, and got stuck for a while trying to get a Chartkick graph to render properly. I found various hints online about how to do it, and I assumed it was a case of phx-update="ignore" and some kind of Javascript hooks, but it took a bit of time to figure out the details. I thought I’d be helpful and write up an example, as it turns out it’s not that hard.
First let’s create the application. I skipped Ecto because we don’t need a database for this example.
So far, so good. Time to try it with a live view! Replace the root route in lib/my_app_web/router.ex with live "/", PageLive, and create the module in lib/my_app_web/live/page_live.ex, rendering exactly the same html as we had before:
defmodule MyAppWeb.PageLive do
use MyAppWeb, :live_view
@impl true
def render(assigns) do
~H"""
<%= "{foo: 1, bar: 4, baz: 2, qux: 3}"
|> Chartkick.bar_chart()
|> Phoenix.HTML.raw() %>
"""
end
end
When this renders, we see the chart flash up briefly, then … hmm.
The reason we see the chart appear then disappear is that LiveView renders the page twice when it’s loaded – once statically, for search engines etc, then a second time, when it swaps in its dynamic Dom. Here are the elements that Chartkick initially creates (a placeholder div and a bit of javascript that will call the library and swap in the generated graph):
<div id="b5b7b558-1220-4546-a3e8-15e2e607b312" style="...">
Loading...
</div>
<script type="text/javascript">
new Chartkick.BarChart(
'b5b7b558-1220-4546-a3e8-15e2e607b312',
{foo: 1, bar: 4, baz: 2, qux: 3}, {});
</script>
The problem is that a script tag inserted dynamically into the Dom, unlike one in the original page source, doesn’t get executed. There’s also a potential issue with LiveView and Chartkick both trying to manipulate the same elements, leading to unpredictable behaviour when the page data is updated. We can address the latter issue by telling LiveView to ignore the chart when updating the page:
defmodule MyAppWeb.PageLive do
use MyAppWeb, :live_view
@impl true
def render(assigns) do
~H"""
<div id="chart" phx-update="ignore">
<%= "{foo: 1, bar: 4, baz: 2, qux: 3}"
|> Chartkick.bar_chart()
|> Phoenix.HTML.raw() %>
</div>
"""
end
end
This actually works in our simple case, but what if the chart wasn’t always shown, or was part of a component that was live patched in? As the simplest possible illustration of this, let’s add some show/hide buttons and only render the element when we toggle @show to true:
defmodule MyAppWeb.PageLive do
use MyAppWeb, :live_view
@impl true
def mount(_params, _session, socket) do
{:ok, assign(socket, show: false)}
end
@impl true
def render(assigns) do
~H"""
<input type="button" phx-click="hide" value="Hide"
disabled={not @show} />
<input type="button" phx-click="show" value="Show"
disabled={@show} />
<%= if @show do %>
<div id="chart" phx-update="ignore">
<%= "{foo: 1, bar: 4, baz: 2, qux: 3}"
|> Chartkick.bar_chart()
|> Phoenix.HTML.raw() %>
</div>
<% end %>
"""
end
@impl true
def handle_event("hide", _params, socket) do
{:noreply, assign(socket, show: false)}
end
def handle_event("show", _params, socket) do
{:noreply, assign(socket, show: true)}
end
end
Initially the chart isn’t there, as expected:
But when we click “show”, we’re back to our perpetual loading indicator:
We need a way of triggering the Chartkick script when the view’s updated, and that’s where hooks come in. First define a hook in assets/js/app.js (I’m not entirely sure this is the best way of running the javascript, but it works!):
let Hooks = {
RenderChart: {
mounted() {
console.log("RenderChart")
console.log(this.el)
eval(this.el.getElementsByTagName("script")[0].innerHTML)
}
}
}
let liveSocket = new LiveSocket("/live", Socket,
{hooks: Hooks, params: {_csrf_token: csrfToken}})
There are other hooks as well as mounted – If we were dynamically updating the chart element itself we’d probably want to also execute the script on updated, for example.
And that’s it! The code’s here, and I hope it helps someone avoid a bit of head scratching.