atomicules

Mostly walking the dogs

Switched to Android

I recently switched to Android. I got a Pixel 7a on contract for a steal - I couldn’t get any new iPhone anywhere near the price. I say switched, but I’m not a die-hard iPhone user. I was coming from an original iPhone SE (after switching back to that from a iPhone 8).

Things I miss from iOS:

  • No easy scroll to top by touching the status bar.
  • No unread count badge indicator on apps.
  • No shortcuts app. But I was mostly using this for running some scripts via ssh and changing my watch faces based on sunset and sunrise (more on that later). Maybe I could use Tasker for the ssh stuff?
  • There is no keyboard shortcut popup for adding “.co.uk”, when entering URLs, just “.com”, etc.
  • Audio transcription doesn’t seem to be as accurate. Has not got my daughter’s name right yet when setting reminders.
  • Notification and vibration settings felt somewhat hidden on Android - took me ages to figure out why Tasks reminders weren’t vibrating. It wasn’t clear from the settings page that I could click/touch on an entry for further settings (I thought it was just a title for a toggle), but that could just be learning Android vs iOS.
  • Not found a good SFTP client yet. But also Panic discontinued Transmit so that was unlikely to remain working forever on iOS. I’m using Ghost Commander which works, is free (and open-source), but isn’t pretty. Definitely had some issues getting ssh keys working.

Things I like:

  • Whoop, I get to use K-9 mail which is great.
  • The Google migration from iPhone is really good.
  • Firefox is better on Android.
  • The Pixel hardware design (camera bump) is my favourite of all phones since the original iPhone SE. All other phones look shite in my professional opinion.
  • 1Password integration seems much better, especially with apps, which is bizarre for an app that started on macOS and iOS.
  • Airmessage is really good. I’m able to use our family desktop iMac for that and I have continued messaging family (all on iOS) via that; I thought I’d have to “meet half way” and use WhatsApp, but nope.
  • I read lots of bad things about the under screen Touch ID, but for me it’s brilliant and way more reliable than the iPhone 8 or iPhoneSE. I am not bothering with the Face ID, maybe I would if I had a Pixel 8.
  • Predictive text seems better (it automatically predicts Gaelic when I’m doing Scottish Gaelic in Duolingo, etc).

Things I am indifferent about:

  • Navigating the UI is mostly the same (despite coming from a ye-olde button iPhone, I’m aware of iOS’s gesture navigation because of A’s iPhone).
  • Most apps are the same. The only unique to iOS apps I used were Panic’s Prompt and Transmit (which as mentioned they discontinued).
  • Siri / Reminders. I now just use Google Assistant and Google Tasks for ad-hoc reminders. This is literally the only thing I ever used Siri for.
  • Connectbot is “good enough”. Had some issues creating ssh keys when I wanted to share those with Ghost Commander. Basically ended up creating a key elsewhere and copying to the phone.

I think basically, nowadays, everything is gravy. Android and iOS are both great. Pixel and iPhone are both great. You are basically being a dick if you hate one over the other.

Apple Watch

Having an Apple Watch did make me think twice about switching, but the main two things I’ve used it for are:

  1. Pagerduty alerts and being able to ack in the shower.
  2. WorkOutDoors (still superb).

Thankfully 1 is no longer a requirement: I have saner on-call rotations now. And for 2 I can carry on using it as I always have, which is mostly using it as a sports watch instead of a smart watch.

I still have my iPhone SE plugged in as a “desktop” phone (with headphones taking advantage of that headphone socket) so whilst at home (which is most of the time) my watch still works exactly as it did before, giving me double the iMessage/Airmessage notifications.

And actually, when out and about, connecting my watch to the Pixel’s hotspot works pretty well and means my watch mostly just works as it did before. The only issue is that sometimes it randomly disconnects and then the hotspot turns off.

My thoughts were that my watch is four years old now. It’s stuck on WatchOS 8 and so abandoned by Apple. The battery is still pretty good though and I can see it lasting another year, but I’d be surprised if it lasts much longer than that. And this Pixel I can use until 2028. So when my watch dies I plan on getting a cheap running watch (Garmin Forerunner 55, Coros Pace 2, Polar Pacer, etc), especially as I don’t do that much running anymore anyway. As long as I undercut the Apple Watch SE price I’m winning (for my needs); I still think the Apple Watch SE is superb value especially when coupled with WorkOutDoors (also superb value); The watch is Apple’s best product in my opinion. But I can do Pixel plus Garmin, etc cheaper.

And the Pixel 7a is really a superb bit of kit for the price.

Bell Pitched Up At The Top Of An Escalator

"Armed with his $3.5 million Stradivarius violin, Bell pitched up at the top of an escalator in a metro station in Washington DC during morning rush hour, put a hat in the ground to collect donations and performed for 43 minutes... By the end of his performance, Bell had collected a measly $32.17 in his hat."

Hello World: How to Be Human in the Age of the Machine by Hannah Fry

From the Art chapter. Not my kind of gig so I doubt I would have stopped or donated, but it is funny how the value of art is perceived based on the context and the reactions of others.

Bonin Didnt Know How To Fly The Plane Safely

"And that's what happened with Air France flight 447. Although Bonin had accumulated thousands of hours in an Airbus cockpit, his actual experience of flying an A330 by hand was minimal. His role as a pilot had mostly been to monitor the automatic system. It meant that when the autopilot disengaged during that evening's flight, Bonin didn't know how to fly the plane safely."

Hello World: How to Be Human in the Age of the Machine by Hannah Fry

About planes, but from the Cars chapter. And this is kind of how I feel about on-call and runbooks. Runbooks, automation and safety systems (I.e. tooling that tries to stop you doing stupid things) are important, but you do also just need some skin in the game and some understanding of the fundamentals of the systems you are supporting. Runbooks aren’t the be-all and end-all.

Running Taskwarrior via launchd

As (somewhat*) recently mentioned I switched back to Taskwarrior. On my server I just re-enabled my cronjob to rollover incomplete tasks each day. On my work macOS machine I was doing this manually to start with until I found time to figure out launchd (it had been a few years). I ended up with this:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>Label</key>
	<string>org.taskwarrior.rollover</string>
	<key>Program</key>
	<string>/Users/simon/bin/task_rollover</string>
	<key>StandardOutPath</key>
	<string>/tmp/task.out</string>
	<key>StandardErrorPath</key>
	<string>/tmp/task.err</string>
	<key>WorkingDirectory</key>
	<string>/Users/simon</string>
	<key>UserName</key>
	<string>simon</string>
	<key>RunAtLoad</key>
	<false />
	<key>StartCalendarInterval</key>
	<dict>
		<key>Hour</key>
		<integer>0</integer>
		<key>Minute</key>
		<integer>1</integer>
	</dict>
</dict>
</plist>

And not that I needed to for this case, but if you want to run at multiple times then you need to use array:

	<key>StartCalendarInterval</key>
	<array>
		<dict>
			<key>Hour</key>
			<integer>09</integer>
			<key>Minute</key>
			<integer>0</integer>
		</dict>
		<dict>
			<key>Hour</key>
			<integer>22</integer>
			<key>Minute</key>
			<integer>0</integer>
		</dict>
	</array>

(I needed this kind of setup for something else, but might as well include it in these notes/post).

Anyway, the script I was calling was just:

#!/bin/sh

/opt/pkg/bin/task $(/opt/pkg/bin/task rc:/Users/simon/.taskrc status:pending due.before:today ids) rc:/Users/simon/.taskrc rc.confirmation:no rc.bulk:100 modify due:today

I couldn’t figure out getting it working without a wrapper script.

Also, to get it to actually load and run properly I couldn’t use the (deprecated?) load/unload commands:

launchctl load ~/Library/LaunchAgents/org.taskwarrior.rollover.plist
launchctl unload ~/Library/LaunchAgents/org.taskwarrior.rollover.plist

I had to do:

launchctl enable user/501/~/Library/LaunchAgents/org.taskwarrior.rollover.plist
launchctl bootstrap gui/501 ~/Library/LaunchAgents/org.taskwarrior.rollover.plist

The 501 you can get from running id. Then you should see the launchagent listed via launchctl list.

To run it once:

launchctl kickstart gui/501/org.taskwarrior.rollover

To disable:

launchctl disable user/501/~/Library/LaunchAgents/org.taskwarrior.rollover.plist
launchctl bootout gui/501 ~/Library/LaunchAgents/org.taskwarrior.rollover.plist

You need to disable and re-enable if you make changes to the plist file. I like how Apple streamlined that from two unload and load commands to needing four commands. Thanks to stumbling across this Reddit post for those.

Also, the StandardOutPath and StandardErrorPath didn’t actually help at all with debugging why it wasn’t running so those can be removed.

Give me the simplicity of NetBSD’s cron any day.

* - I wrote this up ages ago and forgot to post it

Note: Marika Hackman's is probably my favourite so far. Just.

Note: Wonder if The Reytons will release an album next January as well?

Note: In lieu of an actual post: Albums from Sprints, Marika Hackman, The Reytons and NewDad. All in January!

Even If You Have Been Diagnosed With Breast Cancer

"And it's Bayes' theorem that explains why - even if you have been diagnosed with breast cancer - the level of error in the tests means you probably don't have it."

Hello World: How to Be Human in the Age of the Machine by Hannah Fry

Got this book for Christmas from Little M. It’s very readable and interesting. This quote actually comes from the Cars chapter which is after the Medicine chapter; The opening page of the Medicine chapter is mind-blowing.

Rust Notes

I finally got around to writing a teeny Rust program. As ever for me, I needed a itch that I could scratch before I could write something. I’ve dabbled in Rust before, but mostly as build fixes for NetBSD. Unfortunately/stupidly I wrote this at work so I can’t share it in full here, but I can write up my notes much like I did my Golang ones.

  • As a rough guide for my brain I like to think of Rust as an imperative version of Haskell, specifically Haskell via Stack
  • …because when creating new things you should use cargo to get started. I.e. cargo new my-project instead of just creating a new file with a *.rs extension and trying to use rustc.
  • The error messages when trying to build/compile are very Haskelly - yes, they probably do tell you exactly what is wrong, but in general they aren’t any help (and you will just end up searching) unless you are an expert and then you probably aren’t making those mistakes anyway; rustc --explain is cool though.
  • Need to use the keyword mut if you want a mutable variable.
  • The amount of dependencies scare me a bit. I used reqwest. Just adding that one dependency to my project resulted in about 90 crates being compiled. Maybe there is something lighter-weight than reqwest? Perhaps ureq. Nothing built-in? Also, I had to explicitly enable a blocking/non-async client by setting reqwest = { version = "0.11", features = ["json", "blocking"] } in the [dependencies] section of my Cargo.toml because I didn’t need the complexity of async; Although it seems difficult to actually escape.
  • A lot of Rust examples are out of date. This can be true for any language, but I guess Rust has evolved rapidly. E.g. I started looking at this example reqwest code, but found out error_chain was no more.
  • Box<dyn Error> is super useful, specifically using fn main() -> Result<(), Box<dyn Error>> otherwise you can’t get out of complier errors as you can’t appease all the expected error types.
  • The ? operator and error propagation stuff makes me think of Haskell’s Data.Maybe.
  • Related: the use of unwrap() for quick/lazy getting at of values is like Haskell’s fromJust. In both cases you probably shouldn’t really use it, but it’s fine for quick/little programs.
  • serde_json works really similar to Haskell’s Aeson. I like this a lot.
  • Especially using the #[derive(Serialize, Deserialize, Debug)] stuff:

      use serde::{Deserialize, Serialize};
    
      #[derive(Serialize, Deserialize, Debug)]
      struct NotificationRuleList {
          total: i32,
          notification_rules: Vec<NotificationRule>,
      }
        
      #[derive(Serialize, Deserialize, Debug)]
      struct NotificationRule {
          id: String,
          #[serde(rename = "type")]
          rule_type: String, // Needed to rename this field as `type` is a reserved keyword
          start_delay_in_minutes: i32,
          urgency: String,
          contact_method: ContactMethod,
      }
        
      #[derive(Serialize, Deserialize, Debug)]
      struct ContactMethod {
          id: String,
          #[serde(rename = "type")]
          method_type: String, // Needed to rename this field as `type` is a reserved keyword
      }
    
      [...]
    
      let response = client
      .get(format!(
          "https://api.pagerduty.com/users/{pd_userid}/notification_rules?urgency=low"
      ))
      .header(AUTHORIZATION, format!("Token token={pd_token}"))
      .header(ACCEPT, "application/json")
      .send()?
      .text()?;
    
      let notification_rule_list: NotificationRuleList = serde_json::from_str(&response)?;
      # Maybe there is probably a way to use `.json()` instead of `.text()` and go straight to `serde_json`?
    
      for mut notification_rule in notification_rule_list.notification_rules {
    
      [...]
    

    These examples are for parsing the PagerDuty notification rules response.

  • Using Debug is handy for printing out the structure: println!("deserialized = {:?}", notification_rule_list);.
  • I still don’t understand String vs &str. I just know you can’t pattern match on String so have to do match method_type.as_str().
  • The wiki page is a really good introduction and I should have read that first.
  • The book is also very good (already linked to bits of it here).
  • Cross compiling doesn’t seem to be as easy as Golang, although this could be because I was trying to go from macOS arm64 to NetBSD amd64:
    1. Need(?) rustup
    2. rustup target add x86_64-unknown-netbsd
    3. cargo build --target=x86_64-unknown-netbsd (rustc --print target-list is handy as wasn’t sure what it was called, had tried with amd64-unknown-netbsd)
    4. But then I hit errors with openssl
    5. So then I tried rustls-tls, but then hit:

       error occurred: Failed to find tool. Is `x86_64--netbsd-gcc` installed?`
      
    6. I gave up

That’s it for now, hope I manage to find reasons/excuses to do some more.


[EDIT: 2024-02-15] Added some further notes on cross-compilation.

LINK: My 2023 Spotify playlist in a bottle

Forgotten I’d done this. The playlist doesn’t show the categories for the songs, but they were:

  • Spinn: Stargazing - A song that reminded me of my favourite person.
  • Let’s Eat Grandma: Strange Conversations - A song that I thought should be here just because (good choice).
  • Nia Archives: So tell me… - A song to I needed to hear live (oh, crushingly heart-breaking. So close).

Nobody I Know In My Age Group Who Remotely Likes This Kind Of Thing

"Now John’s gone there’s nobody I know in my age group who remotely likes this kind of thing. I don’t understand why. I’m driven by it."

Incorrectly, she wasn’t as big a deal for me as John Peel. I don’t really know why. I’ve listened to her last and most recent show from just before Christmas - the BBC have re-released her fiftieth anniversary shows on Sounds, which I will try to listen to, but those didn’t immediately feel in the spirit of Annie Nightingale who was very much about new music and looking forward.

Note: On-call capability: Fine unless it involves WebEx

LINK: My Music Picks Of The Year

Until I get bored, I am enjoying doing this. Here’s this year’s to go with the last two.

I say “bored”, but this is actually somewhat important to me: How would I cope without music? How amazing is it that there is this much great new music this year? It would be so easy to just listen to my formative years instead of trying to make all years my formative years.

Even with this I am sure I’ve missed some great music from this year; Afterall, I missed Cristale and ShaSimone from last year’s playlist.

Album of the year

On a related note, it’s strange that I couldn’t pick an album of the year this year, but although there was a lot of good music there wasn’t one album that grabbed me emotionally. The nearest I got was (in no particular order):

  1. Jadu Heart: Derealised
  2. Cleo Sol: Heaven
  3. CASISDEAD: Famous Last Words

Since each feature three tracks in this picks list. I re-listened to all three recently to try to decide between them. I couldn’t.

Note: Boursin, Ritz crackers and a glass of red wine: Peak Christmas.

LINK: Glastonbury 2023: What actually happened

And to go hand in hand here’s a playlist of what actually happened.

These are the ten most recent posts (not counting any note drivel), for older posts see the Archive.