Zack Apiratitham

2023 Default Apps


Inspired by Rebecca Owen's post and over 130 others from the community as of this writing, I am also joining the trend of sharing my current default apps list. I've done something similar back in 2017 with my checklist of apps and configurations when starting fresh on a new Mac, and my About page also contains a smaller list of software. But this will be a more complete and up-to-date list at the time of this publication.

As far as I understand, the initial intent of this from the Hemispheric Views podcast episode (which admittedly I haven't listened to) was to look at how many of these categories are the built-in default apps that come with the OS such as Apple Mail, Notes, Reminders, etc. But it seems like this has evolved quite a bit and people have thrown in their own categories that may not have platform default counterparts. So I'm separating them into main categories and a list of additional ones of my own.

Main categories:

  • Mail Client: Spark
  • Mail Server: Fastmail (referral link)
  • Notes: Notion and occasionally Apple Notes
  • To-Do: Apple Reminders
  • iPhone Photo Shooting: Camera app for most things, Halide if I want to get serious
  • Photo Management: Apple Photos
  • Calendar: Fantastical
  • Cloud File Storage: iCloud Drive
  • RSS Reader: NetNewsWire
  • Contacts: Apple Contacts
  • Browser: Safari
  • Chat: iMessage, WhatsApp, LINE, Telegram, and Discord
  • Bookmarks and Read It Later: Matter (but I'm bad at actually going back to read them)
  • Word Processing: Pages
  • Spreadsheets: Numbers
  • Presentations: Keynote
  • Shopping Lists: Apple Reminders and Grocery for groceries
  • Meal Planning Recipe Manager: Mela
  • Budgeting and Personal Finance: Copilot
  • News: Not any one place, but I guess Mastodon, RSS, and very rarely Apple News (used to mostly be Reddit, but RIP)
  • Music: Apple Music
  • Podcasts: Overcast
  • Password Manager: 1Password

Additional categories:




Adventures on Mount Bierstadt


Since we moved to Colorado, I had this goal to one day hike one of the state's numerous fourteeners. Jess and I go hiking often around here, but we'd never attempted one of these. The closest one to us is Mount Bierstadt which is considered one of the easiest fourteeners to climb. From the Denver metro area, it only takes about an hour and a half to drive there. Due to that, this is probably the most visited fourteener in the state.

So that's what we set out to climb a few weekends ago. We planned be at the trailhead by 5am to make sure we got one of those coveted parking spots as we didn't want to hike any longer than we needed to. The trail starts near Guanella Pass at almost 11,700 ft (3,566 m) and climbs about 2,700 ft (820 m) to the summit at 14,065 ft (4,287 m). According to AllTrails, the out-and-back length of this trail is 7.2 mi (11.6 km) and should take around 3-5 hours to complete.

We knew that it would take us longer than average for a hike like this, probably closer to 6-7 hours. So we planned to start around 5am and be back down by noon-ish and get lunch afterward. With this being the biggest hike either of us had ever attempted, we weren't sure if we would make it to the summit. I gave us about a 50/50 chance of making it up there.

Coincidentally, I had just bought the new Apple Watch Ultra 2 a couple of days before we went on this hike, so this was the perfect testing ground for it. I also had just recently learned of this beautifully-designed indie app called Landscape that was made specifically for a hike like this. So I was looking forward to trying it out.

The temperature was right around freezing when we got there and we came prepared with plenty of warm layers and headlamps. Including food and water plus the camera gear, my pack probably weighed close to 15lbs. The parking lot was already filling up but we got a spot. From there we could barely see a faint silhouette of the imposing mountain with a field of stars in the backdrop. I thought it looked quite intimidating. A scattered trail of flashlights from people who started even earlier than us could be seen snaking up the mountain.

We hit the trail at 5:30am and the first mile or so was pleasant as it was mostly flat, and even downhill a bit. The second mile was when the switchbacks began and the trail started to climb with tall bushes flanking us. It was a gradual incline but we made sure to go slow to not tire ourselves out.

It was an early fall day without a single cloud in the sky. And of course, the sunrise was magnificent.

Mountains with early morning sunlight shining on the summits
The sunrise as seen from about 1.8 miles in and just above 12,100 feet. The parking lot can be seen in the bottom right corner.

A range of mountains with early morning sunlight shining on them
A south-facing view of the sunrise over the mountains.

A black & white silhouettes of hikers on a mountain ridge

A black & white image of a sun shining through a crack of a mountain ridge
The Sawtooth ridge as seen from about 2.3 miles in and 12,600 feet up

It's almost 8am and we had been hiking for about two and a half hours. We still had about 1.5 miles and 1,500 feet to go. We were well above the bushes now and the landscape became a lot more rocky with little vegetation. But up in this environment was where we saw some cute wildlife to distract us from the physical exertion.

Close up of a rocky surface with four ptarmigans
Four sleeping white-tailed ptarmigans. They were incredibly hard to spot—especially the fourth one—but Jess somehow spotted them.

A marmot on a hill
A yellow-bellied marmot staring us down

A pika sitting on a rock with a blurred view of mountains in the distance
A pika who was very vocal as it came close to the trail. I don't think it liked seeing us humans in its home very much.

Rocky mountain summit with hikers on top. An airliner can be seen flying above
The summit as seen from 3.2 miles and 13,700 feet up

It's 10:30am, five hours after we set off. We were tantalizingly close, just over 300 feet of elevation to go. The effective oxygen at this altitude is a little above 12%.

As you can see from the photo above, the last bit of this was a scramble up a boulder field. It was a kicker for us but we pushed through. And after nearly seven hours, we finally made it to the summit!

Me and Jess standing on top of Mount Bierstadt

View of the mountain range from top of Mount Bierstadt

We spent less than an hour at the top. There was a big group up there with us and they were quite loud. Plus it had taken us much longer than planned to get up there, so we knew we had to get going. Looking down to the parking lot and seeing how tiny and far away it looked was incredibly discouraging for me. Getting up there really was only half the battle. I almost wished I had a glider.

But not long after we started climbing down, another distraction came our way.

A lone mountain goat standing on a hill with mountains in the background

It was more than just a single distraction. We got a herd of them.

Five mountain goats walking down a rocky hill

Two mountain goats on a rocky hill facing left

A straight-on profile of mountain goat

A mountain goat on a rocky hill with mountains in the background

I spent way too long taking way too many photos of these mountain goats. But they made the extra work carrying the heavy camera gear up the mountain all worth it.

The next few hours were not at all enjoyable. It wasn't as physically demanding as going up in terms of cardio effort, but our legs and knees hurt from stepping down on these rocks that seemed to just go on forever. Plus we were hungry as we only packed enough food for breakfast and light lunch.

After what felt like an eternity, we eventually made it to the car at 5:30pm, four and a half hours since we left the summit, and exactly twelve hours since we started. There was almost nobody left on the trail or in the parking lot. Looking back at the peak, I couldn't fathom how we made it up there to begin with. The hike up felt like a distant memory or a fever dream. It didn't feel like it really happened. We were that exhausted. We didn't get back home until 7:30pm, sixteen hours after we left that morning.

As for my new Apple Watch Ultra 2, I ended up draining its battery more than I expected as it had about 10% left when we got back home. It was running both AllTrails and Landscape the entire time and I didn't enable low power mode on it. My old Apple Watch Series 6 would have died not halfway up the mountain. My phone was also running AllTrails all day and it died halfway down the mountain.

In hindsight, what we really should have done was to take note of our pace on the way up, and figured that it was going to take us way too long to complete the hike. That was a rookie mistake that we'll be sure to not make again. We should have turned around when we saw that it's been over two hours and we were barely halfway up. We were lucky we went there in the fall. Had we gone in the middle of the summer, we would surely have been hit by afternoon thunderstorms. And with the lack of any tree cover on this trail, we would have been in trouble. Also, it's always a good idea to pack more high-calorie food and snacks than you think you'll need.

Sitting here now in the comfort of my home, I'm glad that we went on this hike, even though it turned out to be more of an adventure than we were prepared for. I know I'll attempt more of these in the future.




WWDC 2023 Wish List


All my other WWDC wish list posts: 2016, 2017, 2019, 2020, 2021, 2022.

I've been closely following WWDCs and their announcements for at least ten years now. And every year I wish I could visit the conference in person, but due to various reasons I never made it happen. Well, this year is going to be different as I will be traveling to Cupertino for the WWDC23 week!

Though unfortunately I was not one of those lucky few who got the golden tickets to Apple Park (maybe next year 🤞), I figured it would still be fun to go meet fellow Apple nerds and join in on all the communities events happening that week in the area. So far I know I'll be attending RevenueCat's pre-WWDC Barcade Bash, iOSDevHappyHour, and perhaps the Dub Dub Climb.

Before we get to all that fun, as per tradition, here is my wish list for updates and announcements:

VR/AR Headset

All the reports around this have picked up so much in recent months that I think we'll really see it this year. At this point, it would be the biggest story of the week if Apple did not announce the long-awaited headset. I am for sure excited to see this finally, but sitting here right now I honestly don't exactly know why I would want one. The only experience I have with VR headsets is the original Oculus Quest, and that was mostly just for gaming. And we know how Apple is with gaming. What I'm expecting is for Apple to wow us in this regard like they did many times before when they introduced new product categories and give us compelling reasons why we might want one.

The rumored price tag of up to US$3,000 is unfathomably high and I will almost certainly not get one if that ended up being accurate. Perhaps we will be pleasantly surprised like with the original iPad where the actual price was half of what was rumored at the time.

iPhone Security Issue

If you've been following Apple-related news at all, you would have surely come across this bombshell report from WSJ of how thieves shoulder surf for people's iPhone passcodes before stealing them. And with just the passcode, they were able to change the Apple ID password and effectively locking the owners out of their iCloud accounts.

The implication of this goes deep and can really mess up more than just your digital life. Not only would thieves get access to all your iCloud stuff (photos, email, files, etc.), but if you also use the built-in password manager, the thieves could gain access to your bank account and other sensitive information. They really should not let people change the Apple ID password just by using the iPhone passcode. The chain is only as strong as its weakest link, and a 6-digit passcode is too weak for something as important as the iCloud account. I know that people forget their Apple ID passwords all the time and I can kind of get why Apple decided that it is worth the risk to make it easier for those people to gain back access to their accounts. But I think the risk here is too great.

I do hope they address this flaw in the system and come up with a mechanism to make this less likely to happen. For now given how we do so much on our phones, we would be better off switching to an alphanumeric password and treating typing it in on our phones as a sensitive operation, like for ATM PIN or bank account password, so that people can't easily shoulder surf for it.

Apple Music and Music App for macOS

Apple Music the service and Music.app on macOS are in dire need of some big improvements. The macOS app is just overall a terrible app (iOS app isn't much better either): songs would refuse to play for no apparent reason, navigation is incredibly slow and clunky, searching feels broken and slow. For the Apple Music service itself, it needs to improve on the recommendation algorithms, playlist curation, and just the overall stability and reliability of the service. I think it fails to meet some basic baseline-level features that its biggest competitor, Spotify, has been doing so well for years. Having said all that, with the recent release of Apple Music Classical, I am not holding my breath that they will do much, if anything at all, about this.

Safari Tab Groups Improvements

I really want to use this feature more as I always have so many Safari tabs and windows open at any given time. But the most annoying issue with this for me is the fact that if I am actively browsing using a specific tab group, opening a link from another app will always open it using a non-tab group window. I just want a way to control where I want links to be opened in. I have countless times run into this and then had to move that tab over to the tab group window I want. In the end I just gave up and stopped using tab groups entirely. I know that you can associate a Focus with a tab group and make external links open in that tab group, but I have a lot of tab groups and they don't nicely map one-to-one with Focus modes I have.

Home App and HomeKit

One thing about HomeKit that I would like to see is the ability to create more complex conditionals for automations. Right now automations are still based on simple and limited set of triggers, but I would very much like to be able to create conditionals to perform certain automations. For example: if the humidity is below 30% and somebody is home, turn on the humidifier, except between 10pm and 8am.

And strangely the Home app still doesn't have Home Screen widgets. I hope to see these in iOS 17.

Lightning Round

  • Something needs to be done with Siri with how terrible and unreliable it is. I want to see some meaningful and substantial changes to it this year.
  • The Photos app does a pretty good job with facial recognition for people. But unlike Google Photos, it still does not recognize pets. I just want to assign names to photos of my pets.
  • The Apple Silicon Mac Pro is still a thing right? It's been well over a year since John Ternus teased us that it's coming. I believe.
  • I find Spotlight on iOS really useful and frequently utilize it for things like unit/currency conversions or dictionary. But what's missing for me is the ability to quickly translate words (or maybe even sentences) to another language. I want to just type in "Tuberculosis in Thai" and get an answer that way. Plus now that iOS comes with Translate app, I don't see why they can't do this.
  • The workout streaks should not have to be every day. Give us the ability to define weekly streaks for workouts.



2023 Thai Election


Reuters:

Thailand's opposition secured a stunning election win on Sunday after trouncing parties allied with the military, setting the stage for a flurry of deal-making over forming a government in a bid to end nearly a decade of conservative, army-backed rule.

The liberal Move Forward party and the populist Pheu Thai Party were far out in front with 99% of votes counted, but it was far from certain either will form the next government, with parliamentary rules written by the military after its 2014 coup skewed in its favour.

Incredible result for progressives and those of us who believe the military has no role in a democratic government. The current dictator prime minister's party only received 13% of the total votes. It’s clear that the majority of Thai population does not want military rule to continue.

But we can’t celebrate too soon. The system is rigged in favor of the pro-military camp and a minority government is within the realm of possibility.

The New York Times:

As of early Monday, it remained unclear who would ultimately lead the country. The junta rewrote the country’s Constitution in 2017 so that selecting the prime minister would come down to a joint vote between the 250-member military-appointed Senate and the popularly elected House of Representatives. The decision could take weeks or months.

Such is the story of Thai politics. We’ve had more military coup d’états than any other country in the world. Since absolute monarchy was abolished in 1932, there have already been thirteen successful coups, averaging one for every seven years. I’ve had the pleasure of living through two of those myself.

On Thursday, Narongpan Jitkaewthae, Thailand’s army chief, took pains to assure the public that things would be different this time.

He said that the country had learned its lessons from its past, and that “politics in a democratic system must continue,” although he added that he “cannot guarantee” that another coup would not happen.

What a fucking joke.




Photos from Thailand


At the end of last year, I went on a long overdue trip back to Thailand after three years. Like any other big trip, I lugged my Canon EOS 6D with me all the way there, but this time I barely used it (the reason for which is a topic for another day). So all of these were taken on my iPhone 14 Pro.

I suppose it's about time I share some photos from the trip, only just four months after I came back as per tradition. A large portion of these are, unsurprisingly, photos of food and they deserve their own separate post. So for now, these are the non-food photos that I like the most:

Picture of Phra Thinang Chakri Maha Prasat
Phra Thinang Chakri Maha Prasat (พระที่นั่งจักรีมหาปราสาท) at the Grand Palace in Bangkok

A view down the Chao Phraya river with the sun close to the horizon
The Chao Phraya river (แม่น้ำเจ้าพระยา)

A view of 4 small islets out in the ocean

A close-up view of little sand pellets on a beach
Sand pellets from sand bubbler crabs

A view of a beach with limestone cliff in the background

A view of two mountains on both banks of a river
Khao Khanab Nam (เขาขนาบน้ำ) with the Tiger Cave temple on top of a peak to the left

A bow of a long-tail boat in a mangrove forest
On a long-tail boat in the mangrove forest

A view from an airplane with a sea of cloud and mountains below it at sunset

A long-tail boat traveling in the distance with mountains in the background

A sea of yellow tents of a night market seen from a high vantage point
Weekend night market in Krabi town




Back to Tournament Golf After Eight Years


Now that it's finally getting warm again after a brutal winter here in Colorado front range, I'm really itching to do more outdoor activities. One of those activities with the lowest barrier of entry for me is golf. I recently played at a nearby city-owned golf course and quite enjoyed it. So as a way to incentivize myself to play more this season, I figured I should sign up for their men's league.

Last time I played in anything resembling tournament golf was over eight years ago in college. I also hadn't swung a club since last July, so I'm definitely quite rusty. Now with this league, I also get my USGA handicap properly established with my current index at 8.5. Today was the first event I participated in and the format was a 2-Man Modified Stableford. My team didn't do too well, finishing tied for last in our flight with -23 points.

My own performance was quite poor: I hit 39 out 48 in for an 87 (+15). The worst offender by far was the tee shot. I could not hit a tee shot to save my life at pretty much every single hole as I kept hitting it thin or not anywhere near the fairway. I hit fairways only five times (36%) and that in turns had a cascading effect to my green-in-regulation, which I only hit seven times (39%). Even though I hit one stroke better than the last round I played here, that round I had 64% fairway hits and 61% GIR.

One saving grace today was that I didn't putt as atrociously as I did last time out: my per-hole average today was 1.9 (35 putts) compared to 2.5 (45 putts). I only three-putted 3 times today, and while that should be zero, it was at least much better than 3 four-putts and 5 three-putts.

A golf scorecard showing a score of 87

Today was frustrating at times, but it was still a fun day out on the course and I met some interesting people in the community. Getting to play in a tournament again put me in a bit of a different mindset and also helped exercise my golf rules muscles (and real muscles too as I walked the whole round). I'll definitely be back doing this some more in the coming months.




My Top 5 Books of 2022


See my other top books of the year posts: 2020, 2021.

Since I began setting concrete reading goals in 2018, I was always able to meet and exceed those goals of around twenty books per year. In the past couple of years, I even felt that I was setting a pretty low bar for myself and that I should increase the number. But last year I failed to even meet my typical twenty-two-book goal, having only read sixteen books by year’s end. I’m not trying to make excuses for my shortcoming here, but my reading habit fell by the wayside in the summer due to my move to Colorado and a new job. I also read a few big novels which took me a long time to get through.

The sixteen books I read in 2022 translate to a 30% drop from 2021. But a better comparison would be the number of pages which came to 7,053, a 13% decrease.

A line graph showing the number of books and pages read since 2017

While I did not meet my expectations for the amount of reading, I did better at my other goals: to read more fiction and physical books. Last year I read six novels which made up 38%1, a healthy jump from recent years. And all but one book I read last year were physical books.

An area chart showing the split between fiction and nonfiction books read each year since 2017

On the topic of physical books, last year I also set a goal to stop buying books and focus on reading the ones I already owned to eliminate unread books on the shelves. So how did I do with that goal? Well I definitely did not stop buying books and ended up adding nine more books to my library2. But I did pare down the number of unread books by reading seven out of eight I had at the start of 2022. Accounting for new books I bought and haven’t read, the number of unread books is now down to five. I was on track to complete this goal by having already read those seven unread books by the summer, but I lost sight of that and ended up buying and reading new books from then on. We’ll revisit this again and see how I do with this in 2023.

Anyway, enough with all the numbers. Here are the top five books I read in 20223.

A stack of five books mentioned in the blog post

The Lord of the Rings by J. R. R. Tolkien (1954–1955)

This came as no surprise to me. I love the Peter Jackson’s films and have watched them through many times but I never read the book. Going into this already knowing all the main story beats did not take away from my enjoyment of the book. I was enthralled from start to finish and there was rarely any dull or slow moment. For years I had been avoiding reading this as I had this preconceived notion that it was going to be difficult to read and the plot would proceed at a glacial pace, and that it would take me months to get through it. I was happy to not find that to be the case.

"I wish it need not have happened in my time," said Frodo. "So do I," said Gandalf, "and so do all who live to see such times. But that is not for them to decide. All we have to decide is what to do with the time that is given us." (p. 51)

Braiding Sweetgrass: Indigenous Wisdom, Scientific Knowledge, and the Teachings of Plants by Robin Wall Kimmerer (2013)

You normally wouldn't find me reading a book about botany or indigenous experiences but putting those two together and combine with the author's background as a scientist made me curious enough to check it out. And I'm really glad I did.

In this book, she tells stories from her life and work as a botanist and member of the Citizen Potawatomi Nation while interleaving with insights into indigenous ways of thinking about ecology and other species on this planet. Her writing really shows off her deep love for nature and the land. I loved when she talks about how the scientific community generally ignore and look down on indigenous knowledge but they are often proven wrong, as told in her discussions of sweetgrass thriving more if harvested and trees talking to each other. A constant theme throughout the book is the emphasis on the importance of generosity and gratitude for what the land gives us, and the responsibility we bare as a species benefiting from — or, more accurately, exploiting — that generosity. It wasn't the easiest read, certain chapters could be quite a slog, but the perspectives I gained from this book really made this worth the read.

In the Western tradition there is a recognized hierarchy of beings, with, of course, the human being on top—the pinnacle of evolution, the darling of Creation—and the plants at the bottom. But in Native ways of knowing, human people are often referred to as “the younger brothers of Creation.” We say that humans have the least experience with how to live and thus the most to learn—we must look to our teachers among the other species for guidance. Their wisdom is apparent in the way that they live. They teach us by example. They’ve been on the earth far longer than we have been, and have had time to figure things out. (p. 9)

Rationality: What It Is, Why It Seems Scarce, Why It Matters by Steven Pinker (2021)

I read both The Better Angels of Our Nature and Enlightenment Now, and personally found his writing style and topics right up my alley. Rationality is a follow-up to the series and it takes a deep dive into rationality and related fields of study. A large part of this book reads like a college textbook and requires intense focus. The chapter on logic — with discussions of concepts like truth tables and "modus ponens" — took me back to my freshman year when I took "Intro to Logic" course. Same thing can be said with most of the other chapters covering probability, Bayesian reasoning, statistical decision theory, game theory, and more. Surprisingly, I still found reading those chapters engaging as I tried to keep up with them.

After nine highly technical chapters, the last two discuss the effects rationality, or the lack thereof, have in our society. He discusses conspiracy theories and offers psychological and sociological explanations into why people believe them and how they seem so widespread in today's hyperconnected world. This book is not what I expected going into it but it still taught me so much in the end.

The dream at the dawn of the internet age that giving everyone a platform would birth a new Enlightenment seems cringeworthy today, now that we are living with bots, trolls, flame wars, fake news, Twitter shaming mobs, and online harassment. As long as the currency in a digital platform consists of likes, shares, clicks, and eyeballs, we have no reason to think it will nurture rationality or truth. (p. 316)

Immune: A Journey into the Mysterious System That Keeps You Alive by Philipp Dettmer (2021)

Overall a very informative and approachable book for such a mindblowingly complex subject. The text is easily digestible and engaging in the Kurzgesagt style I’ve come to know and love. Throughout the book he uses a lot of analogies to illustrate scale or purpose of certain features of the immune system like helpful bacteria living on our skin as barbarian horde outside of the gates, the lymphatic system as superhighways and megacities, and the flu virus as soldiers in the Trojan horse. Some chapters can be long and involve multi-step in-depth explanations, but he also does not shy away from shorter chapters when the topics require it. Highly recommended for those wanting to get a better understanding of such a critical part of you staying alive.

Right now your Adaptive Immune System has a specific weapon against every possible enemy in the universe. For every single infection that has ever existed in the past, for all of them in the world right now, and for every single one that might emerge in the future but does not even exist yet. In a way, the largest library in the universe. (p. 103)

Numbers Don’t Lie: 71 Stories to Help Us Understand the Modern World by Vaclav Smil (2020)

This book is a collection of essays the author originally wrote for the IEEE Spectrum magazine which are grouped into seven main themes: people, countries, inventions, transportation, food, and environment. Full of numbers and graphs, this is a very fact-based book with no lengthy philosophical ruminations. The chapters are all succinct with no more than a few pages each which made for a quick and easy read. I cannot count how many new facts and understandings I gained from this book as it covers such a wide range of topics. Some really interesting ones are: why electric container ships are still not viable, diversity of animals vs. human-made artifacts, rational meat-eating, and better home insulation4.

Human minds have many irrational preferences: we love to speculate about wild and crazy innovations but cannot be bothered to fix common challenges by relying on practical innovation waiting to be implemented. Why do we not improve the boarding of planes rather than delude ourselves with visions of hyperloop trains and eternal life? (p. 136)


  1. Eight if you count The Lord of the Rings as three separate books, making the share of fiction 50%. ↩︎

  2. Not counting three cookbooks. ↩︎

  3. I know picking five out of sixteen isn’t that much of a curation but I’m sticking to that same number for consistency’s sake. ↩︎

  4. Brick and stone walls do not provide anywhere near as good insulation as "flimsy North American wooden things with hollow walls". And the easiest thing we can do to improve insulation and reduce energy consumption is to simply replace single pane windows with triple-paned ones. ↩︎




Focuses for Thailand Trip


The last time I traveled outside of the US was late 2019 in the beforetime, but earlier this month that thankfully came to an end. I am now spending the last month of 2022 in Thailand. To make the long journey and the stay in Thailand more streamlined, I created a few Focuses on my Apple devices to help with that.

Travel

Traveling between Colorado and Thailand takes at least 24 hours, so it was essential for me to set up my devices in a way that will help make that arduous journey less stressful. For this I created a “Travel” Focus with the following Lock Screen and Home Screen1:

iPhone screenshots of the Travel Focus

From the top, the Lock Screen shows the time in Bangkok. The widgets are Flighty, Battery, and CARROT Weather. I find the battery one to be especially useful as it’s set to automatically switch to show battery status on different devices like the Apple Watch, AirPods, and their case, depending on the context. Flighty‘s Live Activity UI also helps with more detailed information of current or upcoming flight.

For the Home Screen, on the top stack I have Delta’s widget to show my trip information and CARROT widget. The top small widget stack contains Find My to keep track of my luggage with AirTags, and Flighty for my flight status. The bottom widget stack is for time zones and battery status for my different devices.

I think the coolest part about this Focus is the “Astronomy” wallpaper which I have set to “Earth Detail” variant so it shows a close-up of my current location on the Lock Screen. It’s not that I need the Lock Screen for me to know where I am on my journey but I just think traveling across the globe is the perfect use case for this wallpaper.

Apple Watch Face screenshot of the Travel Focus

For the Watch Face, there isn’t a lot of things I could put that I don’t already have on the Lock Screen. The top left complication is for sound levels which isn’t that useful, but I didn’t know what to put there. Nonetheless it’s interesting to see the sound levels on my flights, and how much the AirPods Pro were able to cancel out.

For the middle complication, I wish I could put Flighty there but surprisingly Flighty does not have a watch app so I put CARROT there instead. On the bottom row: left is for the watch battery, middle is for TrayMinder to keep track of my Invisalign wearing time, and right is a Watchsmith complication for the current time in Thailand.

Thailand

As I am spending over a month in Thailand, the apps I use regularly here are different from apps I have on my default Home Screen in the US. And so I created a “Thailand” Focus.

Screenshots of the Thailand Focus

Similar to the “Travel” Lock Screen, the top shows the time in Denver. The widgets are:

  • Temperature, to help me make sure the apartment doesn’t get too cold for the cats
  • Flighty, to show when my next flight is
  • Google Maps, to quickly launch the app to search for places
  • Halide as an app launcher

I use the “Weather” wallpaper to show the current condition.

Also similarly, the Home Screen has the CARROT widget on top and Flighty below it. The apps here are the ones I know I’ll use most frequently while in Thailand:

  • Home app to help check on the apartment while we’re away
  • Rover for our cat sitter
  • A folder for food-related apps like Line Man and Food Panda
  • Translate since my Thai is garbage these days
  • SCB Easy is my Thai bank’s app and it gets used a lot to initiate bank transfers to pay for stuff
  • myAIS is for my AIS SIM I use while I’m here
  • Line because that’s the app everybody here uses for messaging
  • Grab for finding rides while in Bangkok

For the Watch Face, the main differences are the Activity rings on the top left and the Watchsmith’s step count complication on the bottom right.

Singapore

I will also be visiting Singapore for a quick weekend trip so I figured why not set up another Focus for it.

Screenshots of the Singapore Focus

The Lock Screen isn’t all that different from Thailand: it still uses the weather wallpaper, and the widgets are CARROT, Activity, and battery status. I have humidity on top and the widget below is set to show current temperature, precipitation chance, and air quality index.

As we will be mainly using public transportation, Citymapper widget is prominently featured on the top of the Home Screen. This should hopefully help with quickly finding transit directions. Below it are the usual CARROT and battery widgets. As for apps, I just threw in some Singapore-specific apps I may or may not use while I’m there plus the usual: Google Maps, Photos, and Halide.

The Watch Face again is very familiar with the main difference being the Citymapper complication in the middle.


Focus is now such a powerful and useful feature so I think it’s definitely worth the time and effort to set up my devices to best suit my needs for these different situations. This is becoming my favorite feature Apple has introduced in recent years.


  1. Shoutout to Federico Viticci’s incredible Shortcut to put Apple device frames around these screenshots. ↩︎




Migrating from Heroku to Linode


Back in August, Heroku announced that they will no longer offer a free tier for their services starting on 28 November. That would become an issue for me since I have a small Spring Boot service with a Postgres database deployed there, and they would end up costing more per month than I wanted to pay for.

In the past few months, I have been hearing more good things about Linode, so I decided to check them out. I don't need anything powerful for this purpose, so their cheapest $5/month shared CPU "Nanode" plan is more than enough. And since this is just a regular Linux server unlike Heroku's "dynos", I'm not required to use the managed database solution, making it cheaper. Plus the cheapest managed Postgres database on Heroku has a limit of 10,000 rows.

So I took on the challenge of migrating my Heroku setup over to Linode, and I'd like to share how I accomplished that here.

Table of Contents


Configuring the Server

Linode put together a very helpful guide on the basic initial configurations one should do when setting up a new instance. For the distro, I went with Ubuntu 22.04. I then just followed the guide and ran the system updates, created a limited user account, and set up SSH access from my local machine. I also set up an A record to point my custom domain to the server's IP address.

Configuring Cloud Firewall

Linode comes with a free firewall service which made it easier than configuring all these rules on the server itself. I set up the following rules to limit access to only SSH and HTTP/HTTPS traffic.

Screenshot 2022 11 26 at 11 34 12 AM

Installing Docker and Docker Compose

To help with deploying this little service, we will use Docker and Docker Compose. Installing these was easily done by following this guide for Docker and this for Docker Compose.

Docker Files

The Dockerfile I had previously for Heroku didn't require a lot of changes: it just copies the JAR from the build directory and sets up the startup command for the image:

FROM amazoncorretto:11-alpine VOLUME /tmp COPY build/libs/*.jar app.jar CMD ["java", "-Xmx300m", "-Xss512k", "-jar", "/app.jar"]

Now we need to create a new docker-compose.yml file to set up both the application image and Postgres database:

version: '3' services: estel: image: 'estel:latest' build: context: src/main/docker container_name: estel depends_on: - db ports: - 127.0.0.1:8085:8085 restart: unless-stopped environment: - SPRING_DATASOURCE_URL=jdbc:postgresql://db:5432/estel - SPRING_DATASOURCE_USERNAME=${DB_USER} - SPRING_DATASOURCE_PASSWORD=${DB_PASSWORD} db: image: 'postgres:15.0-alpine' container_name: db ports: - 127.0.0.1:8955:5432 restart: unless-stopped volumes: - ${DATA_DIR}:/var/lib/postgresql/data/ environment: - POSTGRES_DB=estel - POSTGRES_USER=${DB_USER} - POSTGRES_PASSWORD=${DB_PASSWORD}
  • The Postgres container is named db and is added to depends_on in the Spring application (estel) container to make sure the service starts after the database.
  • The SPRING_DATASOURCE_URL environment variable points to the db service at estel database as specified in POSTGRES_DB variable.
  • The username and password are specified via a .env file on the server, and are used in both containers.
  • The DATA_DIR variable points to a directory on the server to ensure data persistence between database restarts. Without this, all the data would be lost when we rebuild the database container.
  • I'm specifying the container ports with 127.0.0.1 to ensure that they are not exposed outside of the server. I'll take care of proxying the API using Nginx below.

Configuring Nginx

For the web server, I opted to use Nginx. Here I'm setting up the api.liftoffapp.space subdomain to have it point to the Spring service I set up previously by using the proxy_pass directive. Requests coming in to api.liftoffapp.space will now get routed to port 8085 that the service is running on.

server { server_name api.liftoffapp.space; location / { proxy_set_header Host $host; proxy_pass http://127.0.0.1:8085; proxy_redirect off; } }

Configuring SSL

One thing I couldn't do on Heroku was enabling SSL on my dyno as that was only available with the paid plans. But now that's easily done with our plain old server. I was blown away by how easy setting up SSL was using Certbot. It configured everything correctly with my Nginx configurations, and was up and running in just a few minutes. It's also all free thanks to Let's Encrypt!

Accessing the Database

As you can see in the docker-compose file, the database is only accessible locally on the server. This made it impossible to connect to it from my local machine. I don't want to expose the database to the entire world, so the approach I went with is to connect to it via an SSH tunnel.

I use TablePlus as my database client and it supports connections over SSH. This is what my connection looks like:

Screenshot 2022 11 26 at 10 58 26 AM

If you'd like to connect via command line, the SSH tunnel can first be set up by running:

ssh -L 9955:localhost:8955 <SSH User>@<Server IP Address>
  • 9955 is the port on our local machine we will need to connect to.
  • 8955 is the port on the remote server that the database is running on.

We can then connect to the database using psql:

psql -h localhost -p 9955 -U estel estel

Configuring SSH Access with GitHub

As the docker-compose.yml is part of the project repo, to ensure we use the most up-to-date version of the file for deployments, we need to be able to pull down the latest from GitHub onto the server. This requires setting up SSH access with GitHub by following this guide. I cloned mine to ~/estel/ directory.

Creating a GitHub Actions Workflow for Deployments

Now that we have the infrastructure set up, the last thing we need is a strategy for deploying the Spring service. I came up with a GitHub Actions workflow to handle deploying this service with pushes to the main branch.

1. Setting up SSH Access

First off, we need a new SSH key so that our workflow can interact with the server. Navigate to ~/.ssh/ directory on the server and run the following to generate a new SSH key pair:

ssh-keygen -t rsa -b 4096 -C "your-email@domain.com"

When prompted, name it something different from the default "id_rsa" as to not conflict with existing key. I named mine "github-actions".

We need to add the new public key to the authorized_keys file so that the workflow using this key can access our server. In the same directory, run the following to append it to authorized_keys:

cat github-actions.pub >> ~/.ssh/authorized_keys

Now that we have a new SSH key for our workflow, we need to add this to the repository's secrets. In the repo, navigate to "Settings" > "Secrets" > "Actions" and select "New repository secret". I named it "SSH_PRIVATE_KEY" and the value is the private key created earlier (in ~/.ssh/github-actions).

2. Adding Other Secrets

While we're here adding secrets, we need to add a few more to be used by the workflow:

  • HOST: the IP address of the Linode server
  • SSH_PORT: the SSH port on the server
  • SSH_USER: the SSH user

Here's what my Actions secrets look like now:

Screenshot 2022 11 26 at 2 10 42 AM

These three aren't necessarily secrets but I find it easier to manage them here. You can choose to hardcode these in the workflow file itself as environment variables.

3. Building the Workflow

This deployment workflow will only have one job called "build-and-deploy" which will take care of building the JAR, Docker image, transferring the image to the server, and rebuild the container with the latest image.

First we configure the environment to use Ubuntu, actions/checkout@v3 to check out our repo, and actions/setup-java@v3 for our Java environment:

jobs: build-and-deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - uses: actions/setup-java@v3 with: distribution: corretto java-version: 11

Next we install the SSH key we added to the secrets earlier:

steps: # ... - name: Install SSH key uses: shimataro/ssh-key-action@v2 with: key: ${{ secrets.SSH_PRIVATE_KEY }} known_hosts: unnecessary

We're leaving known_hosts as unnecessary here as we will configure that in the next step:

steps: # ... - name: Add Known Hosts run: ssh-keyscan -p ${{ secrets.SSH_PORT}} -H ${{ secrets.HOST }} >> ~/.ssh/known_hosts

We're generating this using ssh-keyscan command and appending it to the known_hosts file.

With that setup out of the way, we now run the Gradle build:

steps: # ... - name: Setup Gradle uses: gradle/gradle-build-action@v2 - name: Execute Gradle build run: ./gradlew build

This will create a JAR file to be used in building our Docker image, which is done with the following step:

steps: # ... - name: Build the Docker image run: docker build . --file Dockerfile --tag estel

Now to get this image to our server, we could publish this to Docker Hub and have our server pull down the latest image. Unfortunately the Docker Hub free plan only allows public repositories and we'll need to upgrade to the $5/month Pro plan to publish private repositories. Instead, we're going to save the Docker image as a tar archive to be directly transferred to the server:

steps: # ... - name: Create tar archive run: docker save --output estel.tar estel

This creates an estel.tar file in our working directory. We then transfer this over to the server using scp:

steps: # ... - name: scp tar archive run: scp estel.tar ${{ secrets.SSH_USER }}@${{ secrets.HOST }}:/home/estel/docker-images/estel.tar

Lastly, we execute some commands to deploy this image:

steps: # ... - name: Execute remote commands to deploy the image uses: appleboy/ssh-action@master with: host: ${{ secrets.HOST }} username: ${{ secrets.SSH_USER }} key: ${{ secrets.SSH_PRIVATE_KEY }} port: ${{ secrets.SSH_PORT }} script: | docker load --input docker-images/estel.tar cd /home/estel/estel git fetch && git pull docker-compose up -d
  • The docker load command creates a Docker image using the tar archive we transferred over in the previous step.
  • The git commands ensure that we have the most up-to-date docker-compose.yml file from the repo.
  • docker-compose up -d then rebuilds the estel container using the latest image.

And that's it! Now every push to main branch will trigger this workflow and deploy our Spring service to the server automatically. The final workflow file can be found here.




iPhone 14 Pro


As I said in my Apple's Far Out event post, this year is my iPhone upgrade year. Coming from iPhone 12 Pro, the iPhone 14 Pro is not that huge of an upgrade. But it's different enough for me to have a few things to say about it.

Pre-order

The pre-ordering experience itself appeared to have gotten quite an update. After the announcement, I could pre-configure the phone with all the details from obvious ones like color and storage to carrier and even the payment method to use. This pre-order "staging" flow gets a big thumbs up from me.

As for the pre-order itself, I seemed to have won the CDN lottery which let me in right at the top of the hour. So I had the phone arriving on release day. I went with a Deep Purple one with 256GB of storage.

Setup

The conventional wisdom these days when it comes to setting up a new iPhone is to do the direct iPhone-to-iPhone transfer. I had used up about 180GB on the old phone and the initial estimate for the transfer was 50 minutes. Not too bad. Turned out that estimate was surprisingly close to reality: it was done in just over an hour and pretty much everything came over just fine. Apps needed to be re-downloaded but all of the login info, preferences, and game progresses were in place, except a couple of stragglers.

Two iPhones side-by-side doing a migration

What did not go so well was the Apple Watch transfer. I decided not to upgrade this year so I just needed to transfer over my Series 6. During the setup process, it asked me if I wanted to transfer my watch over to the new phone which I promptly said yes to. After the transfer was done and the phone was usable, I got this alert saying that there was an important software update to address iMessage and FaceTime activation issue. Wanting to avoid this and then forgetting that my watch was being transferred, I foolishly went ahead and ran the update. And sure enough, that completely messed up the watch. So I had to hard reset the watch and re-paired it from scratch. Fortunately all the watch faces I had previously were restored.

Chassis

The Deep Purple color looks pretty muted, you wouldn't be able to tell it's purple unless it's in bright sunlight. I really hope one day Apple will make pro iPhones in fun colors.

The back of a purple iPhone 14 Pro

Comparing to my iPhone 12 Pro, the iPhone 14 Pro is 0.8mm (0.03") taller, 0.45mm (0.02") thicker, and 17g (0.61oz) heavier. The increase in weight was noticeable right away and I wish the iPhone would stop getting bigger. But that's not even the worst part. This phone is 7.85mm thick, which honestly isn't that thick, but that is only for the phone body, ignoring the camera "mesa" and the lens "turrets" protruding out of it. The height of that "bump" alone is more than half the thickness of the phone body! There is no way to lay this phone flat even with the case on. I hate it so damn much.


Display

The first time I noticed the dimmed always-on lock screen, I thought that the phone wasn't locked. So I instinctively pressed the lock button expecting the screen to turn off but instead it lit back up. And when I was aware that it's supposed to be on, I expected that I could interact with the lock screen widgets or swipe down for Control Center, but in reality I first have to tap it to wake up the screen from the dimmed state, and then I could interact with it. So that took a bit to get used to. One exception to this is that if you swipe up to unlock the phone when it's in a dimmed state, it will try to do the Face ID unlock, so that's a nice touch. All these I have since gotten used to in about a week.

One aspect of the always-on display that I had forgotten to consider was around bedtime. As I put the phone on my nightstand when I go to bed, the always-on display would be entirely too bright even in its dimmed state. One easy solution is to just put the phone screen side down. But that would be impractical if you use a MagSafe charger or a regular Qi wireless charging pad. The best solution to this is to enable the Sleep Focus mode as it will automatically disable the always-on display. Oddly enough, while there is a Shortcuts action to set the Apple Watch always-on display mode, there is none for the iPhone. This is quite a glaring miss on Apple's part and I do hope they will add this in a future software update. It would be nice to have for those who don't want to use the Sleep Focus mode.

The ProMotion display was immediately obvious as soon as I picked up the phone. This was something I always noticed and wished I had every time I had to use Jess's iPhone 13 Pro Max. I love it, everything just looks and feels so smooth. The difference feels almost to the level of going from non-Retina display to Retina display.

The 2000 nits peak brightness was also really handy the handful of times I was out in super bright sunlight.

Dynamic Island

The outline around the Dynamic Island and the instruments inside were more noticeable than I expected, even with indoor lighting. But I have since gotten used to that and don't see it anymore.

Since the introduction of the notch with the iPhone X, I formed a habit of tapping on that area as a shortcut to scroll to the top of a list or webpage. But now if I have an active Live Activity session like music or timer, tapping on the Dynamic Island just sends me to the app for that activity instead of scrolling up to the top which was pretty jarring. I had to adapt to tap on either side of it instead.

Unfortunately the Live Activities API wasn't available until iOS 16.1 which was just released earlier this week. So there wasn't much interaction with Dynamic Island in the weeks I've had this phone. I'm sure in coming weeks and months we'll start to see a lot more apps utilizing this.

Camera

The new camera system is a substantial upgrade from my iPhone 12 Pro. The picture quality and low light performance are noticeably improved. I love that the 48MP sensor allows for a decent 2x digital zoom at 12MP. So now we have four focal lengths we can shoot at with 0.5x, 1x, 2x, and 3x at a good resolution.

Shooting 48MP is limited to the ProRAW mode and when doing so I could notice some sluggishness with the camera. I sometimes have to wait for a split second between shots for it to process, so I can't shoot them in as quick succession as I'd like. And previewing the photo usually takes a few seconds to become available. I'm a bit disappointed by the performance here given how great Apple touted their new A16 chip to be. I don't know what the bottleneck could be, perhaps it's the memory bandwidth. The phone also gets hot pretty quickly after shooting several 48MP photos in quick succession. This definitely will affect battery life.

But that is by no means a deal-breaker, I still love the fact that with 48MP I could crop and reframe the photo to how I like it. The size of these ProRAW DNG files comes out to around 80-90MB which is pretty hefty. I'm used to working with my 20MP Canon EOS 6D's 20MB RAW files so I'm gonna have to be a bit more mindful of how fast I'm filling up my phone storage with these.

Overall I am really happy with the incredible image quality this camera system produces. Below are some of the photos I took over in Rocky Mountain National Park using Halide. These are straight out of the camera with no post-processing done by me.

IMG 4505
Main Camera, f/1.8, 1/7000s, ISO 100

IMG 4510
Telephoto Camera, f/2.8, 1/270s, ISO 32

IMG 4549
Ultra Wide Camera, f/2.2, 1/460s, ISO 40

IMG 4603
Telephoto Camera, f/2.8, 1/99s, ISO 250






© 2012-2023 Zack Apiratitham