I don’t quite understand how it’s been five years already. Nevertheless, happy birthday to the most fearless and persistent young lady I’ve ever known.

mostly nonsense
I don’t quite understand how it’s been five years already. Nevertheless, happy birthday to the most fearless and persistent young lady I’ve ever known.
If you need something to listen to this weekend or during your next commute, here’s a link to me prattling on for forty-six minutes about how and why I build the software I do.
Brett Terpstra was kind enough to invite me on as the guest of his Systematic podcast this week. And when he says I’m “on about the same level of a geek frequency as” he is, well, that’s a heck of a compliment in my book.
While using one of my favorite iOS Shortcuts the other day, I realized how much things have changed in six years.
I say six years ago specifically because it was in 2014 that I made an iOS app called Upshot.
Sadly, Upshot never saw the light of day because I couldn’t get it past App Review for very dumb reasons. Lucky for you though, after I show the ridiculously simple Shortcut that I now use instead, this gives me the opportunity to tell you my very favorite App Store rejection story.
I subscribe to the whole GTD philosophy – especially the notion of ubiquitous capture. (Although, as usual, Merlin has a really good anti-take on the topic that is worth considering.) It keeps me sane knowing I have a system to record the things I shouldn’t forget when they occur to me.
For a long time, many of the notes, ideas, and reminders I captured were quick cellphone snapshots. Of course, that means my camera roll quickly cluttered up with photos that were only relevant to me for a day or two or maybe even just an hour after I snapped them.
There are a thousand ways (and apps) to solve this problem. For me, my solution has long been a top-level folder in my Dropbox named _Inbox
. (The _
keeps it sorted at the top of the directory listing.) It’s where all my dumb, non-text notes go right away so I don’t have to think about where to put them – before sorting through that folder a few times a week.
I built Upshot for myself to make that process even faster. Because, this was 2013 – 2014, before there were iOS share / action extensions to make moving data between apps easy. Before there was Files.app and file provider apps.
The app was simple. Five giant buttons.
Tap one, capture what you need, and it’s immediately put in your preferred Dropbox folder. It could also (and optionally) automatically generate a Dropbox share link on your clipboard.
And because this was back in the day, it also had full support for x-callback-url
integration. Which means it could tie into other wonderful apps like Drafts.
I loved my little app and hoped other people might, too. Sadly, I could never appease the App Review gods. And because this was back during the Dark Ages where every app submission took an entire week or more to review, after multiple rejections, Apple successfully defeated my desire to share the app with others, so I stopped trying and just used it myself until iOS share extensions and Shortcuts arrived.
But more on that later. First, here’s my incredibly simple replacement Shortcut that I’ve had on my home screen for a while now.
Tap the icon, snap a photo, and choose between
It’s super simple, fast, and lets me quickly send a photo wherever I need it without cluttering up my camera roll.
You can install the shortcut from this link. And here are the steps for posterity.
Back to Upshot’s App Store rejection. It was rejected for two reasons. The first one I fixed, the second one I gave up on.
I’ve been playing this game for a while, so in hindsight I should’ve know better, but Upshot was reject at first because I linked to an “external mechanism for purchases or subscriptions”.
Aha! Silly me, my mistake. I bet the app reviewer visited the FAQ part of the app which linked to the Help page on my website. And then my website, of course, links to, well, the rest of my website which allows people to purchase the Mac app I sell direct to customers because it isn’t allowed in the Mac App Store. That has to be it, right? I mean, it happened two years earlier.
Nope.
The whole purpose of Upshot is to store your photo notes in Dropbox, right? Well, my mistake was that I had “dropbox.com” or something listed in the App Store meta description. And since none of the text you put into the description is actually tappable, I can understand why Apple was worried someone might see a word ending in dot com and think to type that string into their web browser and Apple might be denied a finder’s fee for that customer giving money to another entity they have nothing to do with.
Fair enough. I removed it.
But, the rejection I couldn’t get past because I literally did not have the technical knowledge or google-fu to solve myself, was the audio note recording feature of Upshot.
When you tapped the “Audio” button in Upshot to record your voice, the app made a “beep” to signify that recording had begun.
Except…
…when the phone was in silent mode or the volume turned all the way down.
In that instance, you couldn’t hear the recording beep. And App Review took exception to that.
(The second highlighted paragraph was in response to me pointing out that other apps, including the iOS voice recorder app, didn’t make a beep when the phone was silenced.)
Try as I might, I couldn’t make my app make a noise when the phone was silenced. Audio programming is something I know basically nothing about. And even dropping down into (for me) obscure APIs dealing with HAL Audio Units, I wasn’t smart enough to make it work.
So, I gave up.
On the plus side, by keeping my dumb little app out of the App Store and preventing someone from surreptitiously recording another person, App Review was able to keep the App Store a safe and trusted marketplace for customers who have no choice but to shop there.
(Sorry in advance for the SEO-keyword heavy blog post. I want to make sure Google can do its job.)
After my post last week about the updates I made to my audio app Ears, longtime internet buddy @macrael asked:
@tylerhall Do you use libraries for the hotkey-setting UI or the start-on-launch stuff? I’m putting together my first Mac app and am looking into those parts rn.
I do, actually. In addition to replying to MacRae on the nightmare birdsite, I thought I’d post the two helper projects here for anyone else searching.
(It saddens me that so many of the Mac development resources I used to learn from and rely on have disappeared from Google (and Apple’s developer website) since Mobile swallowed the industry. Ah, well. Here’s my contribution…)
I’ve used the excellent MASSShortcut framework for years to handle global hotkeys in my Mac apps. Here’s the original blog post about the project from Vadim Shpakovski. (By the way, this new app from Vadim looks super helpful.)
When I rebuilt my app CommandQ, I needed a way to trap keyUp
events in addition to the keyDown
events that MASShortcut offered. I modified the framework to allow that, and I’m sorry to say I’m a terrible open-source citizen and never contributed that patch back to the original project. But you can find my fork here.
Here’s a small sample Xcode project I extracted from my existing apps. It shows how to create a helper app inside your main application to launch your app at login. (Hopefully, only if the user consents first!)
I’ll be up-front and say I have no idea if this sample code is the “right way” to do this, if it ever was the right way, or if it’s even the modern way any longer. I cribbed it together from a blog post years ago, and it’s worked fine for me thus far.
If anyone would like to point out a better way, I’m all ears. And if anyone knows the original blog post author I should give credit to, I’d love to know that, too.
One of the best things that have come out of the pandemic for me has been my little Mac app, Ears. I had the idea for it and built it about a month into quarantine because I was in so many remote meetings throughout the day. And depending on the time of day, how much notice I had before the call, if my kids were around, all sorts of reasons – I found myself frequently switching my Mac’s audio between speakers, AirPods, headphones, etc. It was a pain, so I built Ears to make that easier.
Since that first release in June, I’ve been refining the app to fit my workflow even better. And tonight, I’m delighted to push out a new release with additional features for all the work-from-home-warriors out there jumping between calls.
First up, if you don’t know the purpose of Ears or why I think it’s helpful, here’s a quick walkthrough FAQ I wrote that explains the why’s and how’s of the app.
InstaMute is a terrible name for a feature, but I needed something to put in my git
commit message, and that’s what popped into my head.
The client I work with daily uses RingCentral for all their scheduled and recurring meetings. But then, they use Microsoft Teams for ad-hoc meetings and for employees low enough on the food chain that management doesn’t want to pay for their RingCentral account.
But within the company I work for, the developers bounce around between Google Meet and Discord.
I’m saying all this so I can point out that each service – in the browser or their desktop apps – use a different keyboard shortcut to mute/unmute the microphone. Worse, even if you do remember the correct shortcut per app, you have to switch focus to the app to invoke it because it’s not a global hotkey in every case. (And don’t get me started that they all hide the on-screen mute button until you hover over it, so you don’t initially know where to try and click.)
And it drives me crazy because when working from home – or even at the office – I don’t want coworkers or clients hearing my kids screaming, me eating potato chips, or whatever else. But having to jump back to some random app and quickly unmute to speak and then go back on mute was a thousand paper cuts every workday.
I needed a global hotkey that mutes the system audio input, so it works in every app. I’m sure there’s probably a native way to do this or some other app that will solve it for me, but it seemed like a good fit to add to Ears.
InstaMute has three modes of operation:
And to make sure you always know if you’re on or off mute, the Ears menu bar icon will update based on your mic’s current status to show a cross-line when muted.
A customer suggested this next feature.
You can assign a default volume on a per-device basis. Speakers, headphones, or even your microphones. Do you want your iMac speakers to be quiet? But don’t mind blasting your AirPods. Give them each a preferred volume, and when you switch devices with Ears, the app will automatically set the correct volume.
(I know macOS will, in theory, do something like this for you, too. But it’s never worked consistently for me. Hence why the user suggested this feature, and I wanted to build it.)
Ears has a straightforward UI. I’m trying not to clutter up the interface beyond its core functionality. So forgive me for hiding this feature behind a context menu. I don’t expect most users will need it frequently – or at all – so it seemed a fine enough compromise.
Right-click on an audio source to choose a value and enable or disable the setting per device.
This feature was added shortly after Ears’ first release, but I never mentioned it in my earlier blog post.
When your system audio changes – whether Ears makes the change or some other app – Ears will display a notification letting you know the new active devices.
I think it’s a great way to confirm what you think happened really did happen and prevent surprises.
Also, you can choose to have your Mac speak your new audio device selections to you. I’ve added a slight delay between when your device changes and when the audio speaks. This delay gives your new device a quick moment to fully come online. So, in the case of switching to a different speaker or headphones, you’ll hear the change announcement with your new choice to confirm it’s active.
So that’s the new version of Ears.
The app is free to download and use. But you can purchase an optional, pay-what-you-want license to remove the nag screen that appears when you open the app.
I made Ears on a lark because I really just wanted it for myself. But it’s turned into one of the most well received apps I’ve ever built. So if you’ll forgive me for bragging, I thought I’d share a few comments I’ve gotten from customers this Summer, and also say thanks to the thousands of folks who have given it a try. I get so much satisfaction everytime someone takes time to email and say it made their workflow during this crazy time just a little better.
I didn’t know I needed this until today, but this is seriously a great app. I’ve spent so much time fiddling with audio devices the past few months 🙁
I do online teaching for a University (in Australia) and have a stream deck set up with some apple scripts to mute/enable the mic. Your software was the missing link in getting it all together.
Ears is great! Thanks for making it! I use it every day to switch among several devices. I wanted to show my support with more than just words, so I purchased a license a few minutes ago.
As an aside: I did notice that Ears posts notifications for audio source changes done in Ears, which is perfect for my use case. It can give that extra piece of confidence when switching.
I just wanted to say – thanks for Ears! I tried it out after reading about it on your website, and it’s exactly what I wanted to help smooth over many audio devices during Work From Home and otherwise. This is especially helpful in an environment where you don’t want to accidentally have your Mac switch to speakers, like in an open office environment. Anyways, thank you again for a great app! Looking forward to see how Ears evolves 🙂
Ears has been a lifesaver – thanks so much for the program!
A coworker and I have been working crazy hours since March on a huge new product feature – him on Android and myself on iOS. Quite frankly, it’s maybe the best work we’ve done in our careers. And work I, at least, wasn’t sure we were even skilled enough to pull off. When we first pitched it to the client, we asked for eight weeks of uninterrupted dev time to build an MVP. They gave us five.
But we did it. And since then, it’s been layering on more complex interactions, polishing, and performance improvements.
Yesterday we were wrapping up code review of a bunch of new math in my office. He was surprised when I mentioned that on my todo list was to go back and update some earlier code to use the formulas we had just gone over. He thought I had always been using this more performant method.
I told him:
I cheated back in April when I first wrote this. I was too scared of the math to try and do it the right way.
He replied:
I didn’t know enough about it to be scared.
It was a throwaway comment – more of a joke, I think. But it struck me and stuck with me the rest of the day, and now I’m writing this post.
Is this what the old cliché “ignorance is bliss” means?
I don’t know, but it made me think back to past projects I’ve built. Some that succeeded and others that failed spectacularly.
For many of the successful ones, I think his observation was spot-on. I don’t know if I would even have attempted the work if I had had enough experience to know what lay ahead.
On the other side, I might have avoided some of the lowest points in my life if I had been more attuned to knowing what I didn’t know.
I can hardly believe I’m quoting this man, but Donald Rumsfeld had a not-completely-ridiculous moment of clarity in 2002 when he popularized unknown unknowns:
Reports that say that something hasn’t happened are always interesting to me, because as we know, there are known knowns; there are things we know we know. We also know there are known unknowns; that is to say we know there are some things we do not know. But there are also unknown unknowns—the ones we don’t know we don’t know. And if one looks throughout the history of our country and other free countries, it is the latter category that tend to be the difficult ones.
When we started on this project months ago, there were plenty of known unknowns we knew we’d have to face, and we’ve worked with the design and product teams ever since to resolve.
But there have also been many staggering unknown unknowns that we never considered. Some we’ve gotten past, while others have morphed from tickets, to sprints, to their own epics.
If he and I had predicted these challenges upfront, I’m not sure if we would have pitched the work at all. But we missed them. And now I think that’s a good thing. Because, as I said above, unfinished loose ends or not, we now find ourselves mere weeks from shipping the best work we’ve ever done. (We called our feature work this Summer “pure resumé fodder.”)
So now, I see the two sides as a balancing act.
Early in my career (and even before I had a career), I’d jump into a new project without any hesitation or thought given to how big of a challenge it might be. Or if I was even capable of doing it.
That’s a good thing, right? Challenging yourself is the best way to grow. And how many incredible leaps forward in our industry would never have happened if everyone let self-doubt and worries block them from even starting?
But now that I’m into the middle(?) of my career and leading a team of (mostly) younger developers, I find myself looking at the new features and challenges on our roadmap differently than I did before. Am I more cautious? Timid? Wary of wasting time?
Whatever the reasons, as I wrote about in Fear and Light, I need to remind myself to get out of my head, out of my own way, and look to my coworkers to remind me to hold onto that optimistic approach to difficult problems where anything is possible.
As I’ve written about previously, for better or worse, Google Photos is the initial destination of all the family photos and videos we take as well as the source of truth for the albums I sort them into. I’ve tried every consumer photo organization tool/website/app on the market, and nothing comes as close to hitting my feature requirements as Google Photos. (Well, short of building my own solution, but that’s…uh…not yet.)
Photos is the only Google product I use. (Besides search – sigh). I gave up Gmail years ago because even with full backups of all my messages, my email address itself is the key to nearly every other online account. The chance of getting locked out due to an automated flag is too high – even if I am a paying customer. But if I lost access to my photo library stored with Google? That would be bad, but not the end of the world since I have all that data backed up.
However, I’m always playing the long game and thinking about contingency plans with data this important. Chief among them is my looming monthly price increase apocalypse. I’m currently paying Google $99/year for 2TB of storage space. When I hit that limit, the next tier is 10TB for $600/year. That’s a hell of a jump for that next byte. And while I totally get the business reasons behind that pricing, sheesh.
So I’ve been thinking about my eventual exit strategy. The obvious next and most comparable choice is Amazon Photos. (I’m keeping a close eye on PhotoPrism.) They solve the storage pricing problem because they’re Amazon and just charge you an extra 1TB at a time as your needs increase.
I’m perfectly willing to pay for what I use, so that’s great. And Amazon’s website and apps are actually better than Google’s in many ways. But they do fall on their face as soon as you start dealing with videos larger than 2GB (easy to do with kids and a modern iPhone shooting 4K video) or over 20 minutes long.
So, I’m keeping a very close watch on Amazon and hoping they improve enough to be the right solution in the future.
Anyway, the point of this blog post is to say that I’m preparing for an eventual move to another photo cloud service. I’m also trying to keep my local backups neatly organized. So, I wrote a small command-line tool to specifically deal with the Google Photos backup format that you’ll receive if you request a dump of your data.
It takes Google’s directory structure and all their duplicated files, merges, sorts, and deduplicates your photos and videos into a sane folder structure – the one I’ve been using for over a decade.
You can request a dump of all of your Photos or just specific albums/dates using Google Takeout. (Kudos to Google for making this sort of stuff so easy.) It works great, and you’ll get everything. The problem is the backups are structured as if you’ll only ever do a single backup in your life – as opposed to incremental ones. And they also don’t deduplicate your data before sending it to you. (I understand why.)
Once your backup is ready, you’ll get everything split into 50GB .tgz
files. Each one will extract into the following directory structure:
You’ll get a folder for every item’s capture date. If you took 50 photos on August 15, 2020, you’d get a folder named “2020-08-15”. Except, for reasons I don’t understand, you’ll occasionally get a folder named “2020-08-15 #2”, too. Same day, another folder.
Google will also create folders for every album included in your backup. Perfect. But any items in those albums (folders) will be duplicated in their respective date folders, too. So, if you have a 2GB video included in two albums, it’ll be in three backup folders, which means 6GB of space.
And this is totally fine. It’s definitely the most flexible and complete solution and leaves it to the end-user to figure out what to do with all this data. And what I want to do is convert everything into a structure that looks like…
…along with all of my items deduplicated. So, any items that are included in an album are not duplicated in a year-month folder. Those date-based folders only contain items that are not sorted into albums.
I spent a few hours messing around with various bash
scripts and some StackOverflow posts but realized I needed something better than any shell script I could write. (I’m sure someone could write it, though.)
I came up with a tiny Swift command-line tool that scans all of your files and stores a hash of each into a sqlite database. (Thanks, Gus!) Then, figures out where each file belongs, moves it there, and ignores any duplicates it finds.
As you might imagine, it’s not the fastest process, but the results were worth it for me. My iMac Pro was able to scan and process my 1.4TB library (100k+ files) on an external USB3 spinning drive overnight. (Sorry, I should have timed it. I think it was between 4 – 8 hours.)
I’m quite pleased with the results. Not only did it clean up all of the per-day folders into a more sane by-month directory structure, but removing duplicates cut the total file size by 30%.
Running the tool is a two-step process.
First, you need to import your Google Photos’ backups into your library – a shared folder where all of your photos and videos are kept. The reason for this step is that Google’s backup structure will often contain duplicate folder names in addition to filenames. And since merging folders on macOS is a delicate process, the import step will do that for you.
Just run this
photoz import /path/to/google/photos/backup /path/to/library
on each of the .tgz
files that Takeout gives you.
After everything is merged in, run
photoz organize /path/to/library
and wait.
If all goes well, you’ll end up with a sane by-month/album folder structure that uses considerably less space.
The code is open source. Fixes and improvements are welcome. I haven’t cleaned it up much since first writing it, but it’s only three Swift files, so it should be easy to dive into and customize to your liking.
And while it works for me and I did a crap ton of dry-runs and testing building this tool, please, please, please make backups of your data before running an internet stranger’s code over something as important as your photo library.
Oliver Reichenstein, founder of iA Writer, had this to say about his post on Apple and modern software monopolies:
This wasn’t easy to write it to publish. But, today, I just had to hit that publish button and get it over with. I have another hot potato post on subscriptions I’ve been juggling with for some time now. Some thoughts are sketched out in the monopoly post. I’ll drop that one soon, too. These topics are complex and dangerous. Writing about them publicly is simply terrifying.
For me, two highlights were:
Apple are not treating Netflix, Nintendo, and Spotify like iA Writer to be fair with us small devs. Think about it. Apple doesn’t profit much from taking 30% of iA Writer’s sales. It would cost them a smile to cut us off. And, given that from the hundreds of thousands of app, only very few reach our position, it wouldn’t be a big deal to cut us all loose. The benefit of having small passionate devs is not in the money they make from them. The benefit of having us is that we enrich the platform. For years, people have been telling us that they buy Apple gear because of iA Writer and similar apps. The benefit of cutting 30% from the small ones is that they can say “we treat everyone the same” and cut off a major chunk of the big Netflix, Spotify and Fortnite cakes.
and
Apple, a company with California Hippie roots that encourages to think different, has a developer community that is afraid to speak their mind in public.
The entire post is well worth reading. And whether you side with him and the $17.86 billion corporation or the $1.97 trillion corporation, you gotta admit it takes guts to lay out that argument on your company blog when the future of your business depends on the kind of day your next anonymous App Store reviewer is having.
Like I said the other day, Jigsaw is one of those ridiculously fun (dumb?) ideas that come along and smack you upside the head one day and you can’t help but take an afternoon to build.
It’s also such a silly idea that I’d normally open source the code so other folks can tinker around with it. Unfortunately, my CloudKit syncing stack is based on a closed source framework that I can’t distribute. (Ensembles, if you’re curious. It’s basically the greatest thing ever and makes my life as a Mac/iOS developer so easy.)
Instead, Jigsaw is free to download and have fun with.
In case you missed my post about why this app even exists…
Apple already lets you sync the contents of your Desktop using iCloud. But, if you’re a visual person like me who often arranges their Desktop icons in meaningful ways, not having the positions of your files on screen also stay in sync is frustrating as I move between my laptop and desktop throughout the day.
Jigsaw solves that by syncing the positions of your Desktop icons over iCloud. Move a folder on your iMac, and a few seconds later it mirrors itself on your laptop. Here’s a demo…
I’ve tested Jigsaw on Mojave and Catalina. I don’t know of any reason why it wouldn’t also work on Big Sur, but it’s untested for now.
I also haven’t even attempted to think about or solve any of the myriad problems that might arise from using multiple monitors.
Along those lines…
During testing this evening, I thought my sync code had gone haywire. I would move an icon on my iMac and almost immediately it would reposition itself into a random spot somewhere else rather than syncing across to my laptop.
What I finally realized was happening was this:
The position I happened to be moving that one icon on my large iMac screen was beyond the bounds of my laptop’s smaller Desktop window. The icon position was syncing correctly, however Finder on my laptop immediately moved it into a new (random) location onscreen. That new location then synced back to my iMac, which made me think my syncing was off. Turns out, iCloud sync was so fast I didn’t even notice it had round-tripped on me. (Nice work CloudKit folks!)
I mentioned in my previous Jigsaw post that I experimented with syncing the relative positions of icons instead of their absolute positions. It was as interesting solution in that it guaranteed icons would always remain on screen, but it led to odd behavior, so I took out that option.
Instead, Jigsaw’s one and only Preferences setting is to enable debug mode. When turned on, Jigsaw will sync all of your connected Mac’s screen sizes to iCloud, compute the smallest width and height among them, and then draw a red rectangle on your Desktop to show (in theory) the valid area you can safely arrange your icons within. (Again, I’ve tested this feature among my three computers – and only very briefly. YMMV.)
To support various screen sizes, I’m wondering about just ignoring icons that fall outside those bounds. But that presents its own sync challenges for another day.
In any case, that’s Jigsaw. Probably not very practical, but it was fun to build on a rainy day. Download the app and let me know what you think.
Earlier today, I had a short twitter conversation with Lauren Herda (she illustrated my first three Mac app icons).
I tweeted about symlinking my Mac’s Desktop folder into Dropbox to work around some iCloud Drive problems that had been plaguing me. It was a quick, off the cuff conversation, but for some reason it kept bouncing around in my head. A little while later when I was washing dishes, I jotted down the following note into Drafts…
Could we sync desktop icon positions over CloudKit??
Here’s the thing.
For me, my Mac’s Desktop is my staging ground, my active workspace, the digital representation of my mental RAM. I’ll typically have all of the files related to the task I’m currently working on stored on my Desktop. Once it’s complete, I’ll either file them away or delete them and move on to the next thing.
Having the Desktop on my iMac at home stay in-sync with my work laptop eases the transition and context switching as I move between locations. Dropbox has been doing this for years, but actually getting into the correct folder in Dropbox always has just enough friction to keep me from using it with active files the way I do my Desktop. When Apple added the option to sync your Documents and Desktop folders into iCloud Drive a number of years ago, it was a perfect fit for me…
…almost.
I’m a visual learner, and that way of thinking translates to how I work, too. That means, not only do I keep my active files on my Desktop, but I also arrange them visually in meaningful ways.
I’ll often shuffle files around into little groups to denote that they’re related to each other. Sometimes I’ll line a queue of files up on the left side of my Desktop and then move each one to the other side as I process them. My point is, in my workflow, the position of those Desktop items is a special bit of metadata that is often just as important as the contents of the files themselves.
So, it’s always seemed to me like a missed opportunity to not sync that metadata, too. And I realize that keeping the visual positions of files in sync comes with all sorts of thorny problems around different sized screens, multiple monitors, etc. But it seemed like a fun problem to think about on a rainy Saturday evening.
As you might guess, I did more than think about it.
The video above shows a macOS Mojave and Catalina virtual machine side-by-side, signed into my iCloud account. I wrote a small helper app that runs in the background and watches your Desktop for changes, which are then synced over CloudKit. The Mac on the other end, subscribes to those updates and repositions your Desktop icons accordingly.
For no particular reason other than I had to pick a name of some kind, this ridiculous little app is called Jigsaw.
When arranging your icons, Jigsaw has two modes of operation.
I’m not sure which method is better. (Honestly, this whole idea is dumb ????) But that’s Jigsaw. Likely nothing more than an experiment but a fun, nerdy way to spend a Saturday evening.
If anyone is interested in trying it, you can download Jigsaw here.