Category Archives: Technology

Sleep: What am I trying to measure?

My last post about analysing my sleep data had plenty of caveats, but despite my caution I started to wonder whether I was taking an interest in the right variables.

I’m aiming to sleep better for health and to feel more alert during the day. My first thought was to find out what influences how many hours I sleep each night. This was a guesstimate of my hours of sleep based on roughly when I fell asleep and woke up, minus any trips to the bathroom or time spent starting at the ceiling in frustration. Then I’d compare this to various lifestyle measures like how much I’d eaten, exercise, screen time, etc to see what, if anything correlated with a long sleep. Despite buying a gadget to help measure it, I’m not sure I have a more accurate measure of sleep quality, so approximate time asleep is what I tried.

However, I’ve realised that there are several ways in which “Hours that night” as I call it might not be the most useful measure. For example, there are times when I can’t get a full night’s sleep no matter how well prepared my body is for it. Sometimes I have to get up early for work, to go on holiday or because I have an audax that starts at 6am. Occasionally my daughter is ill and will wake me up several times. These things are thankfully rare, but could skew the results. I could simply delete any results where my maximum possible sleep was less than six hours, but this leaves less extreme cases.

I also recorded the maximum possible hours I could get each night. In my spreadsheet I subtracted the “Hours that night” from this to get “Missed sleep”, thinking that would be a better measure. On the other hand, if I can only get three hours maximum and I miss none, is that really better than having a Saturday lie-in for up to nine hours, but only sleeping for eight, meaning missed sleep is one hour? Who knows how many hours I might have got if I’d tried to sleep for more than three hours?

So I tried working out some kind of scaling adjustment, so that “missing” one hour out of a possible nine gives a better score than missing one hour out of a possible seven. I could ignore anything over eight hours as most people are unlikely to sleep that long unless they’ve missed out on sleep the night before. But that makes a hard cut-off, which feels wrong.

So I’ve come up with a simple scaling algorithm which looks like this:-

def missed_sleep_scaled(row):
    useful_max = min(target_sleep, row['Max possible (hrs)'])
    if useful_max == float(0):
        # result is invalid.
        return -1
    max_expected_hours = min(target_sleep, row['Max possible (hrs)'])
    useful_missed_sleep = max_expected_hours - min(row['Hours that night'], target_sleep)
    if useful_missed_sleep <= hours_noise_threshold:
        useful_missed_reduced_noise = float(0)
    else:
        useful_missed_reduced_noise = useful_missed_sleep
    return float(10) * useful_missed_reduced_noise / useful_max

This “sleep score” correlates less strongly with “Max possible (hrs)” than “missed sleep” did (0.104 vs 0.198). That seems like a step in the right direction. I’m uncertain about whether I should tweak it until it doesn’t correlate with “Max possible (hrs)” at all.

Some sleep correlation data

You may have read my previous post that I’m trying to use data to work out why I’m sometimes not sleeping well and how I might sleep better. I’ve been doing that now for some 86 days and I’m excited enough to look at the data and see if anything interesting has shown up. Ideally I’d like a year’s worth of data to get reliable results, but I’m impatient.

You may be wondering why the title of today’s post is so undramatic, prosaic even. Well, I’m rather a newbie when it comes to data science and I don’t want to leap to conclusions from the first thing I try. As you’ll see from my GitHub project, all I’ve done so far is to read in the data and use Python Pandas to produce the correlation results. I then pasted this into a spreadsheet, sorted and highlighted some rows.

I used to think that correlation implied causation. Then I took a stats class. Now I don't. Sounds like the class helped. Well, maybe.

I’m also wary that correlation does not imply causation. But it does make for an interesting start.

With those caveats out of the way, this is what I’ve got so far.

Screenshot of spreadsheet showing potential influences on the "hours that night" variable.

Plain correlation from the first 86 days of data

The factor I’m hoping to maximise is “Hours that night” – how many hours I sleep on a night after all those potential influences have been measured. So I’m interested in things which might be positive or negative influences on that.

The top two I’ve put in grey, as I think they’re not very interesting, except to show that the correlation function seems to be working as expected.

  • “Max possible” is low when I have to get up very early, say to travel somewhere, so it’s always going to limit my sleep.
  • “Av hrs past 5 days” is a rolling average of “Hours that night” over the last 5 days. That I’m more likely to sleep if I’ve built up a huge sleep debt recently is unsurprising, but also confirms that the model seems reliable.
  • ZMA and FOS are two supplements I’ve been taking recently which are said to help with sleep, the ZMA particularly for those doing a lot of exercise. Evidence is limited and I’m not keen on trying every eccentric treatment “because you never know”, but they’re cheap and the side-effects are trivial. However, I’ve only been taking these for a couple of weeks, so I don’t think there’s enough data to say if they have helped me.

Eating

If I had guessed I would’ve expected “Evening meal finish” – the time at which I finish dinner to have had the greatest negative effect on my sleep as I often wake early feeling boated if I’ve eaten late. It does seem to be a negative factor, along with “Evening meal size (0-5)”. I’ll aim to eat earlier and keep recording results.

Alcohol

This wasn’t a significant factor for me. This is supposed to make you fall asleep later but wake up too early, losing sleep overall. Anecdotally, I have found to be true for me. However, I drink quite rarely and haven’t had more than four units a day in any of the last 86 days, so my stats so far may not say much about that.

Daylight, Sugar, Screen time, Fasting

I’m recording these as they’ve either been blamed for bad sleep or hailed as a helpful thing. They don’t seem to be a big deal for me. I may consider stopping recording them so I have more time/space for other data.

Worry, Excitement

It interesting that these have some negative effect on my sleep, but as they’re all day values, there’s probably not a huge amount I can do to control them.

Exercise

I am surprised and, if I’m honest, disappointed to see “Exercise (1-5)” as such an apparently bad influence on my sleep. Studies have suggested that exercise should have a positive effect on sleep, but that may depend on intensity.

For me, and exercise score of 1 indicates a day where I didn’t walk for more than 15 mins and did no other exercise, 2 a normal day where I cycle to/from the station, about ten minutes each way, 3 is a bike ride of up to 3 hours or a 20-min weights/callisthenics session, 4 is a 3-6 hour bike ride, 5 is reserved for the all-day and sometimes all-night rides I occasionally do.

Perhaps this isn’t enough data on what, for me, may be an important question. Questions I’d like to answer might include.

  • Is morning exercise better or worse for sleep than evening exercise?
  • Is moderate exercise better for sleep than either extreme?
  • Does taking ZMA (or something else) mitigate the apparently negative effects of exercise on sleep?

Finally, instead of simply “Hours that night” should I be measuring the sleep I got as a fraction of the “Max possible” sleep? That might account for strange circumstances where I was still cycling at 1am and inevitably scored a 5 for “Exercise”.

Conclusions

I shouldn’t be drawing any firm conclusions yet, I think. 86 days is not that much data and there are many confounding factors that could be influencing things. I have a lot of thinking, learning and tweaking to do.

I plan to keep recording the data, expand my exercise data to include AM/PM and separate short intense efforts from longer endurance ones.

Why you may not want to hire passionate people

In my industry, “Passionate” is one of the most overused words in job adverts. Recruitment blogs are overflowing with advice on how to find these precious employees. It seems every company wants to hire people who are not just enthusiastic, but passionate about their work. The assumption is that people who describe themselves this way will produce better quality work and go the extra mile to get things done. A person’s passion can often be infectious, boosting morale for the team. In my experience these differences in attitude are real and I can see why they’re attractive to an employer, but they’re not the whole story.

There’s already some debate about whether it’s reasonable or healthy to expect passion from employees or if it is simply a way to demand more work for less remuneration. Maybe “we’re looking for passionate people” is code for “unpaid overtime is expected”. Could the idea of passion for a job be counter to achieving a healthy work-life-balance? I’m sure most modern companies would say that people can and should be passionate about their work and have a fulfilling home life. Hence well worn phrases like “work hard, play hard”.

Let’s assume employees can be “harmoniously passionate“, have a healthy lifestyle and devote a good portion of their time to friends and family. Would you necessarily want to employ them?

Passionate employees care more about what they do. They care about how it’s done. They may even care about the overall mission of the company. Often companies encourage people to get involved and to care deeply about these things. Not everyone takes this to heart, of course. For some this kind of talk is like water off a duck’s back. They roll their eyes as the CEO stands in front of PowerPoint slides depicting the moon landing or how they’re going to use quantum computing to cure cancer.

But some people do feel passionate about their company’s mission or technical vision. They will understandably have stronger feelings about how things are done or whether they are done at all. It’s unlikely that they’ll always agree with leadership on the direction the company takes or decisions that are made in their behalf. Sometimes the inspiring promises that the company makes don’t pan out.

“Sorry, but the quantum computing solution turned out to be too expensive, so we’ll be using 1970s mainframes instead.”

Any​ employee who is professional and responsible would say, “we’re doing this wrong, this is what we should do instead”. If management decide to ignore their advice many would shrug their shoulders and get on with the next task. A truly passionate employee will campaign for change, research the best options in their own time and make the case for improvement as forcefully as they can.

“It looks like we won’t be directly curing cancer, but gathering statistics on the cancer drugs prescribed over the last ten years.”

Whether it is the leaders or the employee who has the better argument, the difference of opinion can become a serious impediment to progress and morale. The employee may become disgruntled and start looking for a new job or, if they’re making a lot of noise about it, be forced leave the company.

This is unlikely to happen with less passionate employees. Those who work to live rather than living to work. Plenty of my valued colleagues over the years are not at all passionate about their work and I don’t think they should feel guilty about that. I would say they are professional. They want to do a good job, because doing a good job is more satisfying than doing a shoddy one. Being liked by your colleagues means being helpful and responsible. However, they’re not so wedded to the company mission that they’ll feel any great loss if the decisions of senior management put the project or even the company at risk.

The professional rather than passionate person may move on, of course, but it will likely be for more practical reasons – salary, benefits, location or career development. Those things are probably easier to measure and manage than factors like how realistic the company mission is or how inspiring the technical challenges.

“I know you guys are master carpenters hired to carve unique furniture, but we urgently need you to assemble flat pack wardrobes.”

To be clear, I’m happy to work with anyone who is responsible and ethical at work, whether they’re passionate or not. I think it takes all sorts to make a good team. What I dislike is the obsession with passion at the expense of the merely professional.

Passion may be a great motivator, but it is hard to manage properly and can become a destructive force when it is not.

What is the point of code reviews?

In most of the jobs I’ve had peer code review was an essential and regular part of the software development process. My experience is that it improves code quality and is well worth the effort. I’d also say that at least half of what I learnt in that time was through code review. Either someone would suggest improvements to my code, or I’d discover new ways of doing things from reviewing other people’s work. It’s a great way to share knowledge. This is not only true in specialist domains where the answers are not always easily found by searching the web, but any time someone is not aware of a better way of doing things. You won’t search for something if you don’t know it exists.

That’s my opinion, but there is also plenty of evidence that code review improves code quality, helps find bugs early and ultimately saves money. The numbers vary between studies, but finding bugs early is not just cheaper, it’s significantly cheaper.

What about testing?

No doubt some people will say that the purpose of unit testing is to find bugs early or, in the case of TDD, prevent them ever being created. So why do we need code review as well?

I agree that unit testing is powerful, indeed I’ve used TDD thoroughly to tame some seemingly intractable problems, but I still highly value code review. I think testing and code review achieve different things. Both are important.

Unit tests are great for quickly checking that everything that worked previously still works after a recent change. They provide confidence to refactor or experiment with code in the knowledge that the essential functionality can be quickly checked and rechecked. Achieving this via a code review would be slow, boring and error-prone.

Code reviews on the other hand can ask bigger questions, like:-

  • Is the code understandable?
  • Are the unit tests testing the right requirements?
  • Is there a more efficient way to do this?
  • Does it increase unplanned technical debt?

In fact, any check that can’t be automated. Coding style, static analysis, spell checking etc can all be automatic and the most a human reviewer should do is check the results.

Code review suggestions

Others have already written good things about how to conduct code reviews without annoying people or what tools you should use, so I won’t repeat that. Here are my observations and suggestions about how to get the most out of code review:-

  • The most important thing for a code review to check is whether the code is functionally correct. Does it do exactly what it says on the tin? Are the code and tests fully implementing the requirements of the story/ticket? Or has the developer misunderstood what’s needed in some way? If so then they’ve probably written the unit tests with the same misunderstanding, so they all pass fine. Yes, this is a hard thing to check – it takes some time to fully understand, but it is important. Get this wrong and nothing else matters.
  • Code review is a great way to share knowledge. Again, this does mean you have to take the time to properly understand the change, but it develops the team and mitigates risk.
  • There should be no reviewer hierarchy. Different perspectives are useful. More than once a more “junior” developer has reviewed my code and asked a “naïve” question only for me to scratch my head and say, “You’re right, I’ve done that totally wrong”. Even when it doesn’t happen quite like that, reviews tend to stimulate questions and the transfer of ideas.
  • That said, it can be worth making sure the local domain expert is one of the reviewers of any important change, but they don’t have to be the only reviewer.
  • Applying more engineer hours to the review does find more bugs, but each additional hour will be slightly less valuable on average than the last, so there’s a balance to be struck.
  • Don’t get bogged down in matters of opinion. When it comes to how to make code understandable and maintainable, there’s a big slice of judgement involved. “I wouldn’t do it that way” is not sufficient justification for raising a comment. There’s a danger of getting into “tomayto/tomahto” arguments. Be open-minded, take a step back and think about how important your point is.
  • Following on from the last point, it’s OK to have no comments. It might seem like you haven’t done your job as a reviewer, but it’s better than nitpicking for the sake of feeling productive.
  • If possible, do not manually check anything that can be automated. Style guidelines should be agreed across the project and checked quickly and automatically. Reviewers are human beings; they’re above that stuff and anyway they’re not very good at it.
  • Pair programming can function as a kind of instant review, but there are also risks. The reviewer can be too “close” to the code to be impartial or may make the same false assumptions about the requirements. A slower or more timid engineer might not want to question the other’s work without the time to think it through properly. So, while pairing can find bugs very early, I don’t think it should be the only kind of review a change receives.

Why I want to encrypt everything

When I suggest to people that we should communicate using encryption, I get the impression they don’t take me seriously.

Am I paranoid? Do I think I’m interesting enough to be the subject of surveillance? Maybe I want to play at being a spy? OK, maybe the last one is partly true, but seriously, I think there are good reasons to encrypt all information by default.

To be completely clear, when I suggest we use encrypted communication:-

  • I don’t have any classified information to share
  • I’m not buying or selling anything illegal
  • I am not planning to have an affair with anyone
  • I’ve got no intention of overthrowing any governments or hacking anything

I don’t think I have anything to hide. However, I don’t want to have to think, every time I send a message to a friend, family member or whoever, about who might see it, now or in the future and what the consequences might be. Maybe one day one of us will be famous and our embarrassing utterances may be of interest to the masses.

I’d just like every message between us to be between us. It’s easy to unthinkingly assume that the messages we send are only read by the intended person or persons. I want that assumption to be reasonable.

Email is not usually encrypted and is easy to fake

For a popular example, email has often been described as about as secure as a postcard. In practice I think it’s a bit worse than that. Firstly, because it’s easy to intercept and read millions of emails automatically. Secondly, with a postcard you can probably recognise the sender’s handwriting which would take some effort to fake. Email senders can easily be spoofed. By default there’s no way to verify that the address in the “From:” field is the person who sent the email.

It shouldn’t take too much imagination to see how the insecurity of email could lead to problems. It’s already been exploited via a simple scam in the UK.

To summarise the link above… A couple had some building work done and had agreed with the builder to pay via bank transfer as many people, myself included, do regularly. They received an invoice from the builder via email which included his bank details. They duly transferred £25k to the account, but the builder never received it. The email appeared to come from the builder’s email address, but was in fact from a scammer who had sent their own bank account details in place of the originals.

This would not have been possible if the email sender’s identity could be verified and the email encrypted. Another solution would be to share the bank account details in person or, if you recognise the person’s voice and know their number already, over the phone. A phone number in an email could also be faked.

There are ways to improve on email security, in fact it’s fairly simple if both parties can use the same service. Other solutions get a bit more complicated.

Encryption is getting easier

The good news is that it’s getting easier to encrypt everything by default. Google are now encouraging all websites to be delivered via HTTPS (the S standing for SSL or Secure), making websites harder to fake and adding to the reliability of online data.

Many email services now offer some level of encryption and verification within their service. So a GMail user writing to another GMail user can expect their communications to be encrypted. Facebook messages are encrypted, as are WhatsApp. In some cases it may be possible for employees of those organisations to access clients’ communications, or to change the application for a user so that their data can be read.

For a higher standard of encryption people look to “zero-knowledge” solutions in which the service providers don’t have the ability to read user data or access their private encryption keys, even if they wanted to or were forced by law, blackmail, bribery, etc. Zero-knowledge email systems include Tutanota and ProtonMail. They’re not perfect. I won’t go into all the pros and cons here except to say that at the time of writing neither are securely interoperable with other email services, but can still be used for unencrypted plaintext emails to/from any address. Of course all this is pointless unless you have a good password.

For text messaging the most respected zero-knowledge solution is Signal, which is available for free on iOS and Android. WhatsApp also offers “end-to-end” encryption, but unlike Signal the code is not open source, so not subject to public scrutiny. Researchers have already shown that WhatsApp can allow Facebook and possibly others to read private messages. Furthermore there’s some controversy over the sharing of user data with Facebook.

Secure messaging is not paranoia, it’s good practice.

Script for Garmin eTrex 30 barometer

If you use Strava and a Garmin eTrex 30 and care about that the climbing figures you get are accurate, then you may be disappointed that Strava is ignoring the barometric data the eTrex 30 gives you and working it out roughly by itself, presumably through the average elevation of large map tiles or similar.

There is a simple fix for this, as pointed out by tubbycyclist of yacf:-

A generic “with barometer” device is provided to force the system to use the elevation data from TCX and GPX file types. One only needs to add “with barometer” to the end of the creator name.

Easy enough with a text editor, but a bit of a faff to do every time you upload.

So I’ve created some scripts to make it easier. My idea is that these scripts will be kept in the root directory of the GPS so that they’re always accessible at the same relative path to the file(s) they are editing. There are different scripts for different operating systems, so they should work even on unfamiliar computers. So when travelling and using other people’s computers, they should still work.

Windows

This Windows Script uses PowerShell 1.0, so should work on  Windows XP SP2 or later. I’ve tested it on Windows 8 and 10. It’s the first bit of PowerShell I’ve written, so any comments are welcome.

Opening up a powershell window and running this script isn’t a lot quicker than editing the file manually, so I’ve also created a clickable shortcut to the script as described here. This avoids having to change the script execution policy on the machine, making an exception for this script only.

  • In Windows Explorer, create a new shortcut in the root folder of the GPS device (this might be E:\ or F:\).
  • Right-click on the new shortcut, and choose “Properties”.
  • Change the shortcut’s Target to the following:
    %SystemRoot%\system32\WindowsPowerShell\v1.0\powershell.exe -ExecutionPolicy Bypass -File "add_barometer.ps1" 
    
  • You may also want to name the shortcut something like “windows_add_barometer.ps1.link”.
  • Click “OK”.

Linux

This Linux script uses generic linux shell commands and has been tested on Ubuntu 14.04 and 16.04. It can be run from the command line with: sh linux_add_barometer.sh or possibly by double-clicking the file if you use one of the methods described here. I’m certainly not a bash expert, so again, your comments are welcome.

Mac

I’m told that it’s possible to run *nix shell scripts under Mac OS, so the Linux solution may work with some tweaking. I’ll update this post when I’ve tried it.

A stitch in time saves nine

A non-technical description of technical debt

In software engineering, “technical debt” is a feature of an application’s code which makes future changes more difficult.

Technical debt takes many forms, but it can be as simple as methods with misleading names, outdated documentation or large sections of repeated code.

dash_gaugesAs an analogy, imagine that an indicator bulb fails on the dashboard of your car. You buy a new bulb and, pop out to replace the old one. Your spouse warns you that dinner will be ready soon. “Don’t worry,” you say, “it’s only a ten minute job”.

When you climb into the driver’s seat however, you can’t find any way to open the dashboard; in fact there are no screws visible at all. So you open the bonnet and look for suitable screws there. The screen wash reservoir is in the way, so you carefully remove that, but due to the way the pipe is connected, this means spilling all the washer fluid on the ground. Your spouse calls that your dinner is on the table. “Nearly there.” you reply. Now you can see some screws which look like they might release the dashboard, but they’re completely inaccessible. The only way is to get the engine out, so you replace the screen wash reservoir and drive the car around to a friend who has an engine-lifting winch. Luckily it comes out without any nasty surprises and you undo a screw labelled “DB release” – simple!

Inside the car however, the dashboard is not at all released and you notice one of the wipers is hanging loose. You re-attach the wiper and locate the correct screws. Remove EngineFinally, the dashboard opens! But it’s not over yet – the bulb you bought, after consulting the car manual, doesn’t fit. As the car is still in bits you take a taxi to the car dealer who supplies you with the correct bulb. When you vent your frustrations, he explains that the bulb you had was for an earlier model and when the new car was designed they weren’t given time to update the manual. Apparently the dashboard is made of a single piece of solid plastic because that makes manufacturing easier and cheaper. No one ever checked the screws were labelled correctly as the release date was brought forward to compete with a car from another manufacturer. Maintenance costs are usually down to the end user and rarely feature in reviews…

So eventually you get the bulb replaced, the engine back in and take the car home. By now your dinner is not just cold, it has things growing on it and your spouse is threatening divorce.

The car in my analogy has terrible technical debt. The “interest payments” needed to modify or fix it are huge. But in other ways it might still be a good car – good handling and fuel consumption and it’s black, everyone likes black. To anyone who has never opened the bonnet, the car is fine – it works, so what’s the problem?

If the occasional hassle of changing a bulb doesn’t seem like a big deal, bear in mind that software is changed a lot. No sooner is an application released than new features are needed, bugs may be discovered or perhaps an external system changes that requires the application to change to keep up. A code file is created once, but will likely be changed hundreds or thousands of times over the lifetime of the application. Most of these changes are not anticipated from the outset and the cost of making them can be dramatically affected by how well-designed, well-documented and testable the code is.

Sometimes code is made well in the first place – that takes an upfront investment of time. Sometimes existing code is improved to be more maintainable – the time to improve it is like paying off the debt. In either case the investment saves time down the line.

There is more on writing maintainable software here. For a deeper look at technical debt, read Martin Fowler’s piece.

Improving PC cooling with water

I’ve had some very occasional crashes with my PC a self-built Intel i7 system. These happened in both Linux and Windows, suggesting that it was a hardware issue. I checked and regularly saw temperatures in excess of 80 degrees C, which apparently is way too hot. When it occasionally gets even higher the CPU shuts down to prevent damage. Sensible, but annoying.

So recently I took the plunge* into water cooling with the simple, self-contained H60 system from Corsair.

Corsair H60 water coolingI’m really pleased with the results. It’s also really satisfying to be able to measure the difference so easily.

Win7, launching L4D2 with stock cooler.

Win7, launching L4D2 with stock cooler.

 

L4D2_Temps_WC

Win7, launching and playing L4D2 with H60 water cooler.

* – pun intended.  🙂

Admitting defeat

A few months ago I tried to fix an old monitor that had gone, literally, on the blink. As it was an intermittent fault, it seemed to have worked, but it didn’t last. I tried one more trick, replacing the large cylindrical capacitor in the centre of the beige circuit board below, but that didn’t help. I think the larger ones can break more subtly, rather than bulging or popping like the little ones.

ViewsonicCircuitSo it’s been taken to the tip household recycling centre.

ViewsonicScrappedI could’ve carried on replacing components at little cost, but you do have to admit defeat sometime!

 

Hope are a great company or maybe the others are rubbish

Hope Vision 1 - still a good light.

Hope Vision 1 – still a good light.

Not content with making some great bike lights, Hope have proven themselves by providing a free light-fixing service to our three-year old light.

We were given a Hope Vision 1 as a present some three years ago. It was described as an entry-level mountain biker’s light, which makes it more than adequate for pitch-black lane riding. We’ve used it a lot on the tandem and more recently for commuting and have always been pleased with it.

More recently I’ve been doing some rather soggy audaxes, usually starting in the pre-dawn dark. The Vision 1 did a great job in these conditions until I noticed later in the day that it kept turning itself back on. This was annoying as I expected to do a bit more riding in the dark at the end of the day, so wanted to conserve battery power.

When I got back home and dried off I opened up the light to see a few droplets of water on the inside. Not good news. I tried a little silicon grease on the main seal, but the same thing happened again. As if often the case a little Googling suggested that Lancashire-based Hope are great at fixing lights with these kinds of issues. A little skeptical, I nevertheless downloaded the returns form from their website and sent the light off in the hope of a fix (see what I did there?).

Less than a week later, the light was back and fully working, free of charge. I was surprised and impressed, but really this is how all companies should work and I’d be happy to pay a bit more if they did.

The bottom line - fixed for free - thanks Hope!

The bottom line – fixed for free – thanks Hope!