My teammate Fatih Ozkul wrote about the process that was used to convert the Doximity app newsfeed from UIKit to SwiftUI. Read more about it here:
Author: mike
DALMAC is complete, I made it a total of 335 miles from Lansing to the Mackinaw Bridge! Today was a relatively short 56 miles, but had over 2,000 ft of climbing! The steepest hill I went up was over 11% grade.
I reached Mackinaw City around 3pm where Katrina and the girls were waiting for me. ? It was so nice to see them again.
I’m finding the ending bittersweet. I’m glad to have made it and my body is asking for some rest (and it’s great to be back together with the family). On the other hand, it was so much fun that I wouldn’t have minded going another few days riding instead of going back to work on Tuesday. On a bike tour, even though it’s hard work, you can just relax and take in the sights. I didn’t have to think about anything except pedaling, and that was refreshing. I loved it!
Thanks to all my family and friends who have followed along and offered support and words of encouragement. It makes a huge difference to help me through the tough moments. I appreciate you.

















DALMAC Day 4 is finished…just one day to go! I biked 74 miles today with a total of 2700 ft of elevation gain.
This was the day where my bike just about broke. After the heavy rain two days ago, my gears have been grinding progressively worse. The suspect was a worn out chain and cassette, and the only chance at a fix would be to make it to the bike shop in Petoskey before they closed through the rest of the holiday weekend. If I didn’t make it, at best tomorrow would be really annoying with gears grinding constantly, and at worst the chain would break and I wouldn’t finish the trip.
This afternoon I pretty much went straight through without stopping (much) so I could get there. I made it at 4pm. They ended up replacing my freehub (the part that the gears on the back wheel mount to) in about 30 minutes and had me back on the road. Shout out to Mike at Latitude 45 Cycles.
I still had plenty of great times along the way. I wish I could have stopped longer in Charlevoix, because that’s a great downtown area. Maybe some other time.
Just 56 miles left of the tour! It’s hard to believe it’s almost over. Check the photos below for more stories from the day.

















Looking forward to one more great ride tomorrow.
DALMAC day 3 is done, and we’re more than halfway to the bridge! Today at 54 miles was much shorter than the previous two 75 mile days, but the hills were a force to be reckoned with. I logged 1800 ft of ascent, and most of it was during the second half of the ride. I was cruising this morning only to run out of steam mid-day in the hills. I took some breaks and got back on track, reaching Kalkaska around 3pm.
This afternoon is the first time I’ve felt sore at the end of the day on this tour. Trying to do some stretches and feel better by tomorrow morning. While Thursday (day 2) was the longest day with respect to number of miles, tomorrow is almost as far and over 2400 ft of ascent, so I suspect it will be the toughest day of the week. It’s also going to be the most beautiful day though while we ride along Torch Lake, so I’m looking forward to it!
As always, more comments in the photos…













DALMAC Day 2 was the training check. I clocked 78 miles today, from Vestaburg (near Alma) to McBain (near Cadillac). This will be the longest day of the tour.
The mileage and almost 2000 ft of elevation gain wasn’t the biggest struggle though: the biggest hurdle was the weather. I managed to miss the morning thunderstorms (see photo comments below), but the afternoon ones were unavoidable. I was riding in rain and thunderstorms for over 3 hours. The rain gear kept me dry for awhile, but it eventually saturated through (and even just dripping off my helmet down my back). It was a wet slog for about 40 miles. Tonight, I’m trying my best to dry out my cycling shorts, shoes, and everything else.
Looking forward to knocking out an easier 50 miles tomorrow, if the weather holds. The last two days look much nicer.











DALMAC Day 1 is complete! It was supposed to be a 72 mile ride, but I clocked 74. It was hot and humid all day, with heat indices in the mid-upper 90s. Fortunately we didn’t get rained on though, so I’ll take it.
It was really something to be pulling into Alma this afternoon after starting the morning in Lansing. I still had another 13 miles to go at that point, but that struck me as a long way to ride.
Tomorrow is a few miles longer than today, but it should be 10 degrees cooler. Rain could be an issue though so we’ll see.
Check the photos below for comments about the day.











DALMAC Day 0: The family brought me down to MSU to check in and help me setup camp so I can get started first thing in the morning.
Tomorrow I’ll be riding 72 miles to Vestaburg. I’ll likely start around 7am in an attempt to beat the heat. It’s really humid here tonight with a dew point of 73, so hopefully I’ll be able to sleep.



The red containers in the top right corner are PB&J sandwich kits. I have two slices of bread, a single serving of peanut butter, and a couple of jelly packets in each. Convenient quick meal halfway through the day.
Yesterday I biked 70 miles—one last training ride before the DALMAC. Starting Wednesday I’ll be biking 325 miles over 5 days from Lansing, MI to the Mackinaw Bridge, camping along the way. Feeling a little anxious about the ride, but it’s going to be a fun week.
https://www.youtube.com/watch?v=87DyyMV0kCY
This is terrifying. Offline AI agents not only discovered a vulnerability to gain online access (and communicate between each other in the process), but then further was able to use that access to break in to a third party service. The fact that all of this was an unrelated side-effect to the active task is also very disturbing. Imagine the possibilities for agents actually instructed to find and exploit vulnerabilities.
Today I passed 2,000 miles on my road bike since I bought it in April of last year. Riding again has been a great way to reduce stress and get some fresh air.

I’ve been putting a new 16″ MacBook Pro with M5 Max through its paces. It’s about 20% faster across the board when compiling a large project in Xcode than my Mac Studio with a 28 core M3 Ultra.
The drawback? While the Mac Studio is completely silent all day long, the fans in the MBP ramp up pretty quickly (to 3500 rpm in automatic mode, and 5000 rpm in high power mode). I’ll miss a quiet office, but the speed improvement is too big to ignore.
Switching to high power mode increased the compiling speed by only a fraction of a percent, so I’ll stick with the quieter automatic setting.
Our oldest daughter learned to drive about a month ago. This evening I took her out to teach her how to drive a manual transmission. She did great, even with the sharp clutch engagement on the WRX.
Watched Project Hail Mary last week. Thoroughly enjoyed it so I started reading the book. About halfway through it and, as expected, it’s even better than the flick.
There’s no turning back now…I just registered for the DALMAC bike ride this August. I’ll be biking 325 miles from Lansing all the way up to the Mackinac Bridge over the course of 5 days, camping each night along the way. Should be fun!
Welcome to DALMAC 2026 – Michigan’s Epic Labor Day Weekend Bicycle Tour
The end of an era, but we knew this was coming ever since Apple decided not to support PCIe GPUs on Apple silicon. With hardly any supported PCIe cards of real value, the Mac Studio is just the better option, period.
My WRX is in the shop for a check engine light. It threw the same code as it did 3 months ago when I supposedly had it fixed. The shop looked at it for a couple of days and still can’t find the problem.
Only thing left to do is pull the engine and check all the timing components they can’t get to with it in the car.
Been planning to buy a new car sometime this year, but was hoping the kids could learn to drive on this one. Here’s hoping the fix is reasonable and that can still happen.
Just saw the Studio Display XDR. $3300 for a 5K 27” display? No thanks. The brightness, mini-LED pixels, and 120Hz are nice, but there are tons of other options with similar features for a third of the cost.
I bought the Pro Display XDR years ago. It was outrageously expensive, but at the time it was the only 6K display on the market (and had a 32” size to match). That extra resolution and size made it worth it to me. I’m kind of surprised that Apple is replacing it with a smaller model.
I updated Seasonality Core to version 2.9 to fix Particle Mode (to use the new Grib Filter server that Seasonality Pro now uses). I removed it for sale from the App Store, so you can download it free from the website directly:
https://getseasonality.com/core/
I gotta say, it feels liberating to be distributing Seasonality outside the App Store again. No more stressing about App Review.
Last month I decided it was time to sunset Seasonality apps. It’s been years since I’ve updated the apps, and I don’t have time to maintain the project anymore. It was a tough decision to make, but I decided it was time to walk away (post with more details here). Unfortunately, shortly after making that decision, I learned that NOAA decided they were going discontinue the OpenDAP servers that Seasonality Pro uses to download model data. This presented a pretty big problem. I didn’t want the apps to stop working just weeks after discontinuing them, but building up an entire new data source is very time consuming. It took me weeks working full-time on it to get things just right when I wrote it in the first place.
I played with the idea of hosting a my own OpenDAP servers on Gaucho Software hardware. That would allow me to continue offering the data without changing the app code. The drawback is that it’d also likely use tens to hundreds of gigabytes of bandwidth every day. That might have been doable, but it wasn’t a great option long-term, so I started thinking about other options. NOAA was suggesting OpenDAP users to move to their Grib Filter API. That would save me the hosting cost, but wouldn’t be an easy task.
First I would need to figure out the Grib Filter API and find a way to translate between OpenDAP model variables to Grib Filter variables, which are named differently and referenced by atmospheric levels in a different way.
After the data is downloaded, it would need to be parsed. Grib is a binary data format that isn’t particularly easy to work with. I spent about 2 weeks writing an parser in Objective-C over a decade ago. It wasn’t a complete parser though, it only supported the model variables I was interested in at the time. I wasn’t keen on using that code this time around.
Finally, I would need to adapt the data to my model drawing code and make sure the performance was still good. I estimated it would take me 6-8 weeks of evenings and weekends to get everything right—a heck of a lot of work to put into a product that I’ve just discontinued.
But what if AI could help? Could I possibly vibe code this functionality; and would the code be good enough to want to include in the project? I decided I didn’t have much to lose, so I signed up for a $20 Claude Code account to give it a shot.
First up was figuring out the API details. I wrote up a prompt with as many details as possible, linked to all the documentation I could find, and then pointed Claude at the site for the GFS model and let it loose. Claude took about 45 minutes, asking me questions along the way, but ended up with some code to download Grib data that looked pretty reasonable and was ready to start testing. I spent another 45 minutes having it add all the other weather models Seasonality supports and create a few Swift CLI apps to test downloading the data so it could be unit tested. I ran out of my first 5 hour usage limit, but I finished about a week’s worth of work in one evening. Things were looking good so far.
The second night I wanted to work on the Grib decoder, in order to see whether the data I was able to download was even correct. I pointed Claude to the Grib spec and gave it some guidance along the way. I was impressed that it read through all the Grib code tables to try and cover decoding all the different parameters stored in the file. I remember this being particularly time consuming when I implemented my own decoder. The first draft of Claudes code wasn’t perfect, but it was better than expected. There were a couple of crashes along the way, most of which were from assumptions made about the size of the data. I asked Claude to add range checking and other guards in order to avoid that. With those bugs fixed, I asked Claude to download samples of all the weather models and to compute average/min/max values to see if they were reasonable. Then I told it to write unit tests for everything. That took up the rest of my second 5 hour time block, but saved me 1-2 weeks of tedious coding if I had done it myself. Up until this point, the Grib decoder was the biggest question mark to me. So the fact that Claude created a reasonable implementation in about an hour was the turning point where I started to think this whole process might just work.
The third day I spent most of the time cleaning up the implementation created during the first two days. I reviewed the code and told Claude to work on several improvements to make it more managable. Another 5 hour limit hit, but the code from the first two days was much cleaner at the end.
Day four was focused on translation. I have my own gridded data model that I use in Seasonality, so I needed to write code to convert the Grib data to a Seasonality grid. It was this day that I learned that one of the models (the HRRR) wasn’t being decoded correctly. Claude dug into the problem and determined that Apple’s ImageIO framework wasn’t decoding the JPEG2000 format used in the Grib for that model correctly. Looking into solutions, it looked like the best option would be to bring in a third party package that was written in C, and write a wrapper around it to use from the Grib decoder. Claude finished the code more quickly than it took to research alternatives to ImageIO. Another 5 hour limit hit, but HRRR data was now working.
Day five I got to see data in Seasonality Pro for the first time. Claude worked on some code to interface with the Grib filter client that was written above, download the data, decode it, convert it to a Seasonality grid, and pipe it through to the mapping engine. When it actually worked, I was geniunely excited. We needed a cache for the downloaded grids, so I had Claude work on that too using a Swift Data architecture. After a couple of tweaks, it seemed to be downloading smoothly, but there was a performance problem in the display code somewhere. I was at my 5 hour limit, so that would need to wait until the next day.
Day 6 started in Instruments, trying to figure out where the bottleneck was. I determined that it was taking a long time for the decoder to process one of the Grib data formats when it’s run on device. I asked Claude to look into it and a few minutes later it made changes for a 10x performance improvement. I followed up by asking Claude to optimize the other Grib data format decoders, which improved performance but weren’t quite an order of magnitude faster. I also ran into an issue with map projections that day. OpenDAP reprojected everything to an equirectangular projection automatically on the server before returning the data, but Grib files don’t do that. I needed a way to convert the Lambert Conformal data in the Grib to equirectangular. Again, I could have spent a few days working on on the geometry to accomplish this, but Claude had something working within minutes. At the end of day 6 I had maps with real data performing well in the app.
I’d like to say that on day 7 I rested, but the job wasn’t quite done yet. This was the day that I hit the 5 hour limit twice. Now that I had Grib data being displayed, I wanted to know which other places in the codebase were still using OpenDAP. I asked Claude what tasks remained to complete the OpenDAP to Grib Filter migration. It came up with a laundry list of places in the code that referenced OpenDAP, and ordered them by descending impact. Some of the items were easy for me to fix myself, others were more involved where I asked Claude to do it. Either way, I had over a dozen commits to the codebase that day and was finally ready to upload a test build to App Store Connect. I wrapped up the project on day 8. Finished the last bits of polish, and submitted the app for review.
Eight days. That’s all it took to completely replace the data layer in Seasonality Pro using Claude Code. That’s probably the best $20 I’ve ever spent. Is it perfect? Not really. OpenDAP allowed me to save bandwidth on cell connections by striding the data, which Grib Filter doesn’t allow. But that’s a server limitation, not a client one. On the client side, the code is arguably better than the code it replaced. I now have a data layer that pulls using async URLSession and decoding methods instead of multiple layers of Objective-C completion handlers. It feels so much more reliable.
I still have some work to do to clean up some lose ends before finally cutting my final ties to Seasonality. But I feel like I can leave the project on much better terms now than where I was at just a few weeks ago. Thanks for the help, Claude.
With 1Password’s price increase, I’ll likely start looking for another solution. It’d be one thing if it would reliably fill out password fields, but half the time it doesn’t even work. The price increase just gave me the extra push I needed to find something else.