<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Goodbye Please</title>
  
  <subtitle>Amtrak, B-Movies, Web Development, and other nonsense</subtitle>
  <link href="https://blog.goodbyeplease.com/atom.xml" rel="self"/>
  
  <link href="https://blog.goodbyeplease.com/"/>
  <updated>2026-03-13T02:35:43.936Z</updated>
  <id>https://blog.goodbyeplease.com/</id>
  
  <author>
    <name>Charles Fulton</name>
    
  </author>
  
  <generator uri="https://hexo.io/">Hexo</generator>
  
  <entry>
    <title>Downgrading devenv.sh</title>
    <link href="https://blog.goodbyeplease.com/2026/03/12/Downgrading-devenv-sh/"/>
    <id>https://blog.goodbyeplease.com/2026/03/12/Downgrading-devenv-sh/</id>
    <published>2026-03-13T02:03:18.000Z</published>
    <updated>2026-03-13T02:35:43.936Z</updated>
    
    <content type="html"><![CDATA[<p>I upgraded <a href="https://devenv.sh">devenv.sh</a> on my work laptop to 2.0.3 today and immediately ran into a fatal error with all commands:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Threads explicit registering is not previously enabled</span><br></pre></td></tr></table></figure><p>This is a <a href="https://github.com/cachix/devenv/issues/2576">known issue</a> and it’s fixed in 2.0.4, but that version wasn’t available via the standard upgrade path yet. On reflection, I decided that I wasn’t quite ready to jump to <a href="https://devenv.sh/blog/2026/03/05/devenv-20-a-fresh-interface-to-nix/#and-more">devenv 2.0</a> and decided to downgrade to 1.11.2.</p><p>After some fiddling, I followed this process:</p><ol><li>Download the 1.11.2 release from Github: <a href="https://github.com/cachix/devenv/releases/tag/v1.11.2">https://github.com/cachix/devenv/releases/tag/v1.11.2</a>.</li><li>Extract the download, then rename the extracted directory to <code>devenv</code>.</li><li>Point <code>nix-env</code> at the download:</li></ol><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">nix-env --install --attr devenv -f ~/Downloads</span><br></pre></td></tr></table></figure><p>This kicked off a fairly long process that recompiled various packages but left me with a working installation.</p>]]></content>
    
    
    <summary type="html">&lt;p&gt;I upgraded &lt;a href=&quot;https://devenv.sh&quot;&gt;devenv.sh&lt;/a&gt; on my work laptop to 2.0.3 today and immediately ran into a fatal error with all commands:&lt;/p&gt;
&lt;figure class=&quot;highlight bash&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;1&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;Threads explicit registering is not previously enabled&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/figure&gt;
&lt;p&gt;This is a &lt;a href=&quot;https://github.com/cachix/devenv/issues/2576&quot;&gt;known issue&lt;/a&gt; and it’s fixed in 2.0.4, but that version wasn’t available via the standard upgrade path yet. On reflection, I decided that I wasn’t quite ready to jump to &lt;a href=&quot;https://devenv.sh/blog/2026/03/05/devenv-20-a-fresh-interface-to-nix/#and-more&quot;&gt;devenv 2.0&lt;/a&gt; and decided to downgrade to 1.11.2.&lt;/p&gt;</summary>
    
    
    
    <category term="Web Development" scheme="https://blog.goodbyeplease.com/categories/Web-Development/"/>
    
    
    <category term="Nix" scheme="https://blog.goodbyeplease.com/tags/Nix/"/>
    
  </entry>
  
  <entry>
    <title>The Hi-Line wins again</title>
    <link href="https://blog.goodbyeplease.com/2025/12/30/The-Hi-Line-wins-again/"/>
    <id>https://blog.goodbyeplease.com/2025/12/30/The-Hi-Line-wins-again/</id>
    <published>2025-12-30T19:50:25.000Z</published>
    <updated>2025-12-30T22:05:54.125Z</updated>
    
    <content type="html"><![CDATA[<p>The rail route between the Twin Cities and Seattle/Portland goes by many names. It was the main line of the Great Northern Railway. BNSF calls it the <a href="https://en.wikipedia.org/wiki/Northern_Transcon">Northern Transcon</a> (“Transcontinental”). Most locals call it the “Hi-Line.” Amtrak’s <em>Empire Builder</em> crosses it daily in each direction.</p><p>It’s the northernmost main railway line in the United States. Cut Bank, in Montana, is only 20 miles from the Canadian border. In the winter, there is significant snowfall all along the route. Sub-zero temperatures freeze switches and pipes. It’s legendary in railfan circles that the <a href="https://en.wikipedia.org/wiki/Superliner_(railcar)">Superliners</a>, first ordered in the mid-1970s, were designed with the harsh conditions of the Hi-Line in mind. It’s certainly true that the <em>Empire Builder</em> received the new cars first, in 1979.</p><p>In my first trip on the <em>Empire Builder</em>, in January 2009 (see “<a href="/2023/11/22/My-worst-best-trip-on-the-Empire-Builder/" title="My worst best trip on the Empire Builder">My worst best trip on the Empire Builder</a>”), I experienced everything the Hi-Line could throw at me: equipment failures, a frozen switch, crew-service-time issues, and freight trains. We were 12 hours late into Spokane and bussed the rest of the way. My return trip was canceled by mudslides. My wise and tolerant wife forbade me from taking the <em>Empire Builder</em> in the dead of winter again, until she relented for this holiday season. How’d that work out for me? Well, let’s say there were some challenges amidst a good trip…</p><h2><span id="outbound">Outbound</span></h2><p>I took the <em>Lake Shore Limited</em> out of New York. I was in coach as a cost-saving measure, and I’d bought pop-tarts and oranges (a great choice) at the <a href="https://www.google.com/maps/place/Ideal+Marketplace/@40.7501801,-73.9989878,17.78z/data=!4m6!3m5!1s0x89c259b0e1b07b0b:0x53300326d471f645!8m2!3d40.7500302!4d-73.998974!16s%2Fg%2F12hqhfkdg?entry=ttu&amp;g_ep=EgoyMDI1MTIwOS4wIKXMDSoASAFQAw%3D%3D">Ideal Marketplace</a> on Ninth Avenue in Manhattan. I skipped the cafe car for takeaway dinner inside the station at Albany-Rensselaer. Even with earplugs and a sleep mask I slept fitfully. In Chicago, I fortified myself at <a href="http://www.loumitchells.com/">Lou Mitchell’s</a> for the long day ahead.</p><p>The Portland sleeper was full of people heading out to the Pacific Northwest to visit family. There was Gene, across the hallway from, whose son was a fisherman. He’d actually been on the <em>Lake Shore Limited</em> with me, out of Syracuse. This was his first time on a train and I took him under my wing for the next few days. At dinner I met Paula and Michael, first-timers visiting an adult child. Amtrak does a good steak in a traditional dining car, and this one didn’t disappoint.</p><p><img src="/2025/12/30/The-Hi-Line-wins-again/berthold.jpg" alt="The horizon recedes" title="Flat horizon with tracks leading away through snow"></p><p>At breakfast I met Joe and his son PJ. They were connecting with the <em>Coast Starlight</em> in Portland to head down to Sacramento to visit another son and help him move into his new house. Joe’s a fellow railbuff and we had a lively conversation then and at lunch.</p><p>The trip went as well as you could hope for. We were never later than 30 minutes, and arrived early into Portland after a lovely run along the north side of the Columbia River. I spent a restful week with my wife (who had flown ahead) and my in-laws, about which perhaps more later. Then it came time for the return trip.</p><p><img src="/2025/12/30/The-Hi-Line-wins-again/fog-on-the-columbia.jpg" alt="Fog over the Columbia River" title="Pine trees loom over a river shrouded in fog"></p><h2><span id="inbound">Inbound</span></h2><p>I had the same sleeping car (Superliner I #32032) as the outbound trip, though not the same attendant. We did have the same lead attendant in the dining car (Josh), who would be hard-pressed by the last day of the trip. Across from me in the car were Eric and Mary, from Minneapolis. They’d been on my trip out but we hadn’t interacted. I also met Diane, retiree from Olympia visiting her friend in Milwaukee for New Year’s. This was her first train trip.</p><p><img src="/2025/12/30/The-Hi-Line-wins-again/hoth.jpg" alt="Morning in Hoth" title="Snow-swept landscape"></p><p>We had plenty of snow as we crawled through Glacier National Park, but we passed out of it as we headed east. Central Montana had almost no snow at all. It was a languid day. By the time I went to bed near Minot I’d read three books since we left Portland: Arthur C. Clark’s <em>Prelude to Space</em>, Rex Stout’s <em>The Second Confession</em>, and John le Carre’s <em>The Pigeon Tunnel</em>. We were on time and I was starting to look forward to an on-time arrival and quick transfer in Chicago the next day. In my other two eastbound trips on the <em>Empire Builder</em> (in 2011 and 2022), I’d been 3 hours 48 minutes and 1 hour 41 minutes late, respectively. As I mentioned, a third trip, in 2009, was wiped out by mudslides.</p><p>Veteran rail travelers recognize the sensation of waking up on a train that hasn’t moved in a while. The 1974 <em>Murder on the Orient Express</em> captured that quiet exactly. The <a href="https://www.mprnews.org/story/2025/12/29/snowfall-totals-in-minnesota-and-wisconsin-for-holiday-blizzard">storm</a> that hit Minnesota as we entered it messed up roads, closed airports, …and froze some switches on our route through the state. We’d left Devils Lake (scene of my frozen switch adventure in 2009) down 55 minutes from freight interference. We lost four hours sitting just outside Grand Forks, before BNSF was able to thaw the switch. We lost another hour between Grand Forks and Fargo because of a second frozen switch. Having arrived 6 hours and 15 minutes late, we then lost close to two hours because our operating crew reached their limit and we had to wait for the new crew to drive up from St. Cloud.</p><p><img src="/2025/12/30/The-Hi-Line-wins-again/frozen-switch.jpg" alt="Two trains waiting on a frozen switch" title="Snow-swept landscape with two trains in sight"></p><p>We never really made the time up after that, owing to weather and freight. A seven-hour delay means an extra meal service, including free dinner for coach passengers via the (in)famous beef stew kept around for just such an occasion. I met some new people, including two (one from Minot, one from Minneapolis), who’d booked late because of canceled flights. It was an odd thought that even with our lateness, we were still getting through while other folks weren’t. It didn’t sound like the Minneapolis airport was a fun place to be the evening of December 28! A note of humor was injected when the dining car had to delay the coach meal because both the primary and replacement can openers were unequal to the task. I never did ask Josh how they sorted it.</p><h2><span id="where-to-stay-in-chicago-when-youre-late">Where to stay in Chicago when you’re late</span></h2><p>As a final insult, CPKC held us in Milwaukee for an hour because of heavy freight traffic. Morale had managed to stay fairly high around the train up until that point, but incurring another hour when we were so close hurt. Climate of rising expectations (“I expect to get off the train”) and all that. We finally straggled into Chicago at about 1:08 AM, or 8 hours and 23 minutes late.</p><p>The last outbound train was the <em>Lake Shore Limited</em>, which departed at 9:30 PM. There probably 40-50 of us who misconnected. I knew vaguely what Amtrak’s procedures were for these situations but I’d never experienced it before. This is what happens:</p><ol><li>When you detrain, all affected passengers are gathered in the south concourse at Union Station. Amtrak has your names and has already rebooked you. In my case, my connection to Philadelphia and Pittsburgh was moved back a day.</li><li>Amtrak has a block of rooms at the Sleep Inn near Midway Airport. You’re given a food voucher and placed on a coach out to the hotel. At the hotel, you give the night manager your name and she gives you a room key. We don’t bother with any of the other formalities because Amtrak’s already vouched for us.</li><li>At 11:00 AM, the coach comes back to haul everyone to Union Station. If you’re on an earlier train, you’re responsible for your own transport. Not wanting to experience a very full coach again, I took a bus to Midway and caught the Orange line to the Loop.</li></ol><p>We arrived at Union Station around 1:10 AM. By 3:00 AM, I was asleep at the Sleep Inn. The process felt chaotic at the time, but on reflection it went smoothly enough. I’m grateful for what Amtrak did, which is more than what an airline would do. The next morning I dropped my stuff at Union Station and headed down to the Museum of Science and Industry, but that’s also another story.</p><h2><span id="lessons">Lessons</span></h2><p>The lesson here is simple and doesn’t require belaboring. You might be on-time on occasion, but nature cannot be fooled and the Hi-Line wins in the end. Plan accordingly.</p>]]></content>
    
    
    <summary type="html">A trip report from the Empire Builder in December.</summary>
    
    
    
    <category term="Travel" scheme="https://blog.goodbyeplease.com/categories/Travel/"/>
    
    
    <category term="Amtrak" scheme="https://blog.goodbyeplease.com/tags/Amtrak/"/>
    
    <category term="Empire Builder" scheme="https://blog.goodbyeplease.com/tags/Empire-Builder/"/>
    
  </entry>
  
  <entry>
    <title>LANTA January 2026 service cuts</title>
    <link href="https://blog.goodbyeplease.com/2025/12/19/LANTA-January-2026-service-cuts/"/>
    <id>https://blog.goodbyeplease.com/2025/12/19/LANTA-January-2026-service-cuts/</id>
    <published>2025-12-19T21:45:23.000Z</published>
    <updated>2025-12-19T22:04:58.651Z</updated>
    
    <content type="html"><![CDATA[<p>Back in June LANTA <a href="/2025/05/28/LANTA-June-2025-changes/" title="LANTA June 2025 changes">LANTA June 2025 changes</a> introduced a number of service changes. The most important, to my mind, was the refactoring of the service between the West Ward and College Hill in Easton. The 106 bus was extended through the Downtown up to Forks Plaza (location of a Giant grocery store ), and the frequency was doubled to half-hourly, with every other bus short-turning at Easton Hospital. Folks traveling from the West Ward to College Hill gained a guaranteed half-hourly connection.</p><p>No longer. LANTA, like every other transit agency in Pennsylvania, is stuck with rising costs and a flat budget. The state is allowing it (and other agencies) to raid capital funds, but there’s still a gap, leading to service cuts in January and a <a href="https://www.mcall.com/2025/12/17/lanta-to-cancel-some-bus-service-starting-next-year-proposes-fare-increase/">fare hike in March</a>.</p><p>LANTA has a <a href="https://lantabus.com/january-2026-service-changes/">full breakdown of changes</a> posted. Many of these aren’t very significant. One or two frequencies removed, various stops retimed. These are the most significant (I’m looking at weekday changes only):</p><ul><li>106: service goes back down to hourly, though the service through the downtown is maintained. The short-turns at Easton Hospital are gone.</li><li>322: drops from ten to six trips per day.</li><li>323: drops from nine to four trips per day.</li><li>601: all weekday service eliminated (20 trips per day).</li><li>613: drops from every 45 minutes to every hour; nine of 25 trips eliminated.</li></ul><p>LANTA characterizes this as a 5% cut and I’ll take them at their word, considering the full scope of their services, including demand response and paratransit. In terms of weekday regular bus service, my back of the envelope math puts it at 12%.</p><p>The biggest change is the elimination of 601, which was a free circulator in Bethlehem and according to LANTA “<a href="https://lantabus.com/routes-and-schedules/route-601/">sponsored by the Bethlehem Parking Authority &amp; City of Bethlehem</a>.” The halving of service on the 322 and 323 reduces the options for people living in the Center Valley and Macungie. The apparent end of the 106 experiment is disappointing. I found it useful, but I admit that I didn’t see many people on the College Hill section. If you have to cancel a bus, cancel one that doesn’t have many people on it.</p>]]></content>
    
    
    <summary type="html">Service cuts on LANTA in January 2026</summary>
    
    
    
    <category term="Travel" scheme="https://blog.goodbyeplease.com/categories/Travel/"/>
    
    
    <category term="LANTA" scheme="https://blog.goodbyeplease.com/tags/LANTA/"/>
    
  </entry>
  
  <entry>
    <title>Fourteen hours in Detroit</title>
    <link href="https://blog.goodbyeplease.com/2025/12/19/Fourteen-hours-in-Detroit/"/>
    <id>https://blog.goodbyeplease.com/2025/12/19/Fourteen-hours-in-Detroit/</id>
    <published>2025-12-19T15:22:00.000Z</published>
    <updated>2025-12-19T15:22:26.125Z</updated>
    
    <content type="html"><![CDATA[<p>When I was growing up, my parents had season tickets to Central Michigan University football games. We tailgated in a small grassy area near Kelly/Shorts Stadium with other faculty. My education in football was on the big, grassy hill that used to mark the northern end of the stadium before the big expansion in the late 1990s. This was at the tail end of Herb Deromedi’s tenure as head coach. He didn’t really hold with the forward pass. I can still hear the announcer intone “Smith, the ball carrier, brought down by…” Mid-American Conference (MAC) football is in my blood.</p><p>The MAC created a championship game in 1997 when it split into divisions. It’s been played at Ford Field in Detroit (home of the Lions) since 2004. CMU made it there in 2006, 2007, 2009, and 2019, winning all but the last. Before 2024 I’d never gone to the game, but I’d always wanted to. When we lived in Kalamazoo it was just a few hours to the east. Now that I’m in the Lehigh Valley, it takes a bit more effort. Nevertheless, the itch didn’t go away.</p><p>I made my first trip to the game in December 2024, and had such a good time that I went back again in 2025. I took notes during the first trip but never got around to blogging about it. This post discusses both trips, and my ideas about a 2026 trip.</p><h2><span id="outbound">Outbound</span></h2><p>The <a href="/2017/02/22/The-Toledo-Option/" title="The Toledo Option">Toledo option</a> is my key to getting to Detroit (and back): bus to New York, <em>Lake Shore Limited</em> from New York to Toledo, bus from Toledo to Detroit. Going back I take the bus from Detroit to Toledo, and then get on the <em>Floridian</em> (a temporarily renamed <em>Capitol Limited</em>). I can then either get off Pittsburgh, the <em>Pennsylvanian</em> from Pittsburgh to Philadelphia (which I did in 2024), or stay on the <em>Floridian</em> to Washington, DC, and take a connecting train up to Philadelphia (which I did in 2025). The bus from Toledo arrives in Detroit at 7:30 AM. The game kicks off at noon. The bus back to Toledo leaves Detroit at 9:30 PM. I have fourteen hours.</p><p>In 2024, I started early on Friday morning with the 6:35 AM Trans-Bridge Lines bus from Easton to New York. This alloeds me to put in a full workday from the pleasant confines of the Metropolitan Lounge at Penn Station before heading out on the <em>Lake Shore Limited</em> in the late afternoon. Amtrak now limits you to three hours in the lounge prior to departure, so in 2025 I took a half day off work and headed in a bit later.</p><p>I have time before leaving to do a little Christmas shopping–the <a href="https://itsugar.com/">IT’SUGAR</a> candy store near Times Square, and <a href="https://usa.kinokuniya.com/">Kinokuniya</a> near Bryant Park. The latter is a true gem–it’s Japanese, and in addition to books and magazines it sells high-quality stationary and writing utensils. Although I didn’t go there on either trip, <a href="https://www.bookoffusa.com/bookoff-49-w-45th-ny-store/">BOOKOFF</a> over on 45th is an incredible used media store.</p><p>The <em>Lake Shore Limited</em> leaves New York on time at 3:40 PM. It’s my third outbound trip this year. I like to have dinner early, around 5 or 5:30, before we reach Albany. In Albany, the power is off for a while (and food service suspended) while we couple on to the Boston section for the trip west. After leaving Albany, I settle down to an evening of podcasts and development work before turning in somewhere west of Utica.</p><p>I made my peace with the Toledo option years ago. It’s the fastest way to reach Michigan on the ground, and the nature of the bus connection means there’s no danger of a missed transfer. That said, the arrival is early enough that there’s no coffee brewed yet on board the <em>Lake Shore Limited</em>; any such activity will have to await my arrival in Detroit.</p><h2><span id="detroit">Detroit</span></h2><p>Detroit’s Amtrak station is located in the New Center neighborhood at the corner of West Baltimore Street and Woodward Avenue. It’s not far from Wayne State University, and about 2.5 miles from the downtown. It is also at the northern end of the <a href="https://en.wikipedia.org/wiki/QLine">QLine</a>, a 3.3-mile streetcar line that runs up and down Woodward on a 15-minute headway. The line operates in mixed traffic and is probably more useful for tourists than commuters. Fortunately, I’m a tourist today.</p><p>The streetcar drops me off at <a href="https://en.wikipedia.org/wiki/Campus_Martius_Park">Campus Martius Park</a> and I walk over to the <a href="https://www.cadillacsquarediner.com/index.html">Cadillac Square Diner</a>. I’m looking for a hearty breakfast and my first round of coffee, and the diner delivers on both counts. Compared to diners in the tri-state area the Greek influence predominates, and menus tend to be simpler. I’ve been to diners in New Jersey with larger menus than Jimbo Fisher’s playbook. This one’s a one-pager, front and back, and I get the Cadillac Square Omelet with hash browns. Passing up the grits was hard, but I really wanted potatoes.</p><p>In 2025, I had breakfast in Toledo, because a late-arriving eastbound <em>Lake Shore Limited</em> delayed our departure to Detroit. Two blocks from the Toledo station, on Broadway Street, is the improbably-named <a href="https://www.google.com/maps/place/Green+Lantern+Lunch/@41.6392793,-83.5467469,17z/data=!3m1!4b1!4m6!3m5!1s0x883b86ddffd0d039:0x3fe4a1dbd66c04d8!8m2!3d41.6392793!4d-83.5441666!16s%2Fg%2F1tk6wl1h?entry=ttu&amp;g_ep=EgoyMDI1MTIwOS4wIKXMDSoASAFQAw%3D%3D">Green Lantern Lunch</a>. The food is decent, the coffee, is hot, and they’re open at 6 AM on a Saturday.</p><p><img src="/2025/12/19/Fourteen-hours-in-Detroit/green-lantern.jpg" alt="Green Lantern in Toledo" title="Mural of the Green Lantern super hero on the exterior wall of a nondescript building"></p><p>There’s plenty to do in downtown Detroit besides the football game. You might visit the <a href="https://easternmarket.org">Eastern Market</a>, an enormous open-air farmers market that’s open from 6 AM-4 PM on Saturdays, with additional Sunday hours in December. While there, you can get your picture taken with the Robocop statue, finally installed in 2025 after years of wrangling.</p><p><img src="/2025/12/19/Fourteen-hours-in-Detroit/robocop.jpg" alt="&quot;Stay out of trouble&quot;" title="Man standing in front of a statue of Robocop"></p><p>Or, you could walk down Lafayette street toward Corktown and visit <a href="http://www.johnkingbooksdetroit.com/">John K. King Used &amp; Rare Books</a>. It’s in an old warehouse, and it bills itself the largest used book store in Michigan. It’s an incredible place, floor after floor packed with books, magazines, anything you might want.</p><p>After the game, I like to hang out at <a href="http://www.docr.coffee/">Dessert Oasis Coffee Roasters</a> over on Griswold. Good coffee and atmosphere and free WiFi. Excellent location for a digital nomad (which I’m not exactly on these trips, but close enough). In 2025, I went to <a href="https://www.zsvilla.com/">Z’s Villa</a> for dinner. I cannot recommend Z’s highly enough. Great food, great atmosphere (it’s in a converted house), and it’s two blocks from the Amtrak station. <a href="http://www.baobabfare.com/">Baobab Fare</a> is also great but you definitely need reservations ahead of time.</p><h2><span id="ford-field">Ford Field</span></h2><p>I’ve been to Ford Field three times now: once for a Panthers-Lions game in 2011, and now twice for the MAC Championship. It’s a great atmosphere and the game draws well. This year we drew 19,000 fans, aided I’m sure by the presence of Western Michigan University.</p><p>In 2024 it was Miami (Ohio) vs Ohio. This year, Miami returned to face Western. Both games were fun, and both years Miami really struggled to do things on offense. The 2024 game got out of hand by the end of the first half. This time around, Miami had chances but just couldn’t get things going.</p><p>In 2024, I sat next to an Eastern fan from Ypsilanti who, like me, was just there for the fun of it. This year, an older man and his adult daughter who had driven over from Kalamazoo. I also saw a guy with a <a href="https://www.easternecho.com/article/2025/11/the-maccoon-chain-how-a-youtube-comment-birthed-eastern-michigan-football-s-newest-tradition">Maccoon</a> sweatshirt (my Maccoon shit was hidden under a sweater).</p><h2><span id="midnight-in-toledo">Midnight in Toledo</span></h2><p>It’s strange being back in Toledo the same day you arrived. It was dark when I got in and it’s dark as I’m leaving. Almost a liminal quality to it. The station itself is fine. It’s well-lit, there are bathrooms, places to sit, vending machines. Greyhound still stops here but withdrew its ticket agent years ago, so the Amtrak folks pull double-duty answering questions.</p><p>Relevant to 2025, there is a small (&lt; 30&quot;) TV mounted on the ceiling. It’s tuned to the Big Ten Championship Game. As we arrive from Detroit that game is in the 4th quarter, and Ohio State is losing to Indiana 13-10, to the bemusement of those present. The Amtrak ticket agent, a proud Buckeye, grows increasingly horrified as the game winds on. I eventually reveal my Michigan fandom and she doesn’t <em>quite</em> threaten to throw me out of the station.</p><p>Eventually the <em>Floridian</em> arrives, and we depart Toledo. The scheduled departure is 11:49 PM. Leaving before the clock strikes midnight is a victory.</p><h2><span id="pittsburgh">Pittsburgh</span></h2><p>If everything’s on time it’s a five-hour trip from Toledo to Pittsburgh, with a two-and-a-half hour layover in Pittsburgh before the eastbound <em>Pennsylvanian</em> departs. What I <strong>want</strong>, and never get, is an on-time departure from Toledo <strong>and</strong> some delays in Ohio so I can get more sleep. Instead, it’s a little before five and I’m walking into the waiting room at Pittsburgh. It’s relatively spacious, the overhead fluorescents don’t buzz, there are bathrooms and vending machines. Because of my travel patterns I’m almost always here on a Sunday morning, and you don’t have many options in the wee hours of a Sunday morning in downtown Pittsburgh. I haven’t found a better solution than the <a href="https://locations.dunkindonuts.com/en/pa/pittsburgh/601-grant-st/348993?utm_source=google&amp;utm_medium=local&amp;utm_campaign=localmaps&amp;utm_content=348993&amp;y_source=1_MTIxMDY3NDItNzE1LWxvY2F0aW9uLndlYnNpdGU%3D">Dukin’ on Grant</a>. It opens at 6 AM.</p><h2><span id="washington">Washington</span></h2><p>In 2025, I stayed on until Washington, DC. This had several advantages. One, I could sleep a little longer. Two, breakfast <em>and</em> lunch served in the dining car. Three, beautiful scenery as we run along the Potomac River. Four, time to bum around DC if I feel like it (didn’t this time around). This does make a later arrival in Philadelphia: 5 PM vs 3 PM. The Martz bus to Allentown is still an option, though a little riskier. I can also take a SEPTA regional to Lansdale and beg for a lift back to the valley. The lack of good Philadelphia-Lehigh Valley connections is a real issue. Going all the way to New York to get Transbridge is an option but it really lengthens the day.</p><h2><span id="next-year">Next year</span></h2><p>I’m planning on doing this again next year. One thing I really wanted to do this year, but didn’t have the time for, is to visit the restored <a href="https://michigancentral.com/">Michigan Central station</a> over in Corktown. I pass the <a href="https://dia.org/">Detroit Institute of Arts</a> on the Q-Line; haven’t been since the Whistler exhibit. I also haven’t eaten in Greektown in over 20 years, when I was down for the Business Professionals of America state competition.</p>]]></content>
    
    
    <summary type="html">A (comparatively) quick trip to Detroit for a football game.</summary>
    
    
    
    <category term="Travel" scheme="https://blog.goodbyeplease.com/categories/Travel/"/>
    
    
    <category term="Football" scheme="https://blog.goodbyeplease.com/tags/Football/"/>
    
    <category term="Amtrak" scheme="https://blog.goodbyeplease.com/tags/Amtrak/"/>
    
    <category term="Detroit" scheme="https://blog.goodbyeplease.com/tags/Detroit/"/>
    
  </entry>
  
  <entry>
    <title>Transforming GPS log data in a Jupyter notebook</title>
    <link href="https://blog.goodbyeplease.com/2025/11/07/Transforming-GPS-log-data-in-a-Jupyter-notebook/"/>
    <id>https://blog.goodbyeplease.com/2025/11/07/Transforming-GPS-log-data-in-a-Jupyter-notebook/</id>
    <published>2025-11-08T02:01:01.000Z</published>
    <updated>2025-11-08T02:56:49.489Z</updated>
    
    <content type="html"><![CDATA[<p>I spend a lot of time on long-distance trains. In the United States, those trains pass through areas with little or no cell signal, leading to long stretches of limited internet access. I’ve written about that challenge over years; the <em><a href="/2024/11/10/Fifteen-years-on-the-Capitol-Limited/" title="Fifteen years on the Capitol Limited">Capitol Limited&#x2F;Floridian</a></em> and <em><a href="/2023/11/22/My-worst-best-trip-on-the-Empire-Builder/" title="My worst best trip on the Empire Builder">Empire Builder</a></em> stand out for their long stretches of signal loss.</p><p>This week I took the <em>Floridian</em> from Pittsburgh to Washington, D.C., by way of Harpers Ferry. It’s a beautiful route, following the Youghiogheny and Potomac rivers, and I decided to try measuring signal strength using the onboard WiFi.</p><h2><span id="uptime">Uptime</span></h2><p>First, I set up <a href="https://github.com/louislam/uptime-kuma">uptime-kuma</a> on my laptop. I’d used it before to monitor my ISP’s nameservers. I configured two monitors, each running once a minute. One tried to resolve <a href="http://amtrak.com">amtrak.com</a> using Cloudflare’s DNS, while the other tried to load this blog within a normal timeout (a harder task). The app is built on Javascript and writes to SQLite, which is ideal for my low-connectivity testing.</p><p>This part worked well. I generated 654 rows over approximately six hours. The relevant table in the database is <code>heartbeat</code>, and <a href="https://sqlitebrowser.org">DB Browser for SQLite</a> has an option for dumping a table to a CSV. I then used a Jupyter notebook to pare the data down to the ping times from the DNS resolver and the timestamp:</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> pandas <span class="keyword">as</span> pd</span><br><span class="line">df_ping = pd.read_csv(<span class="string">&#x27;../inputs/ping.csv&#x27;</span>)</span><br><span class="line">df_ping = df_ping[df_ping[<span class="string">&#x27;monitor_id&#x27;</span>] == <span class="number">1</span>]</span><br><span class="line">df_ping = df_ping.drop(columns=[<span class="string">&#x27;id&#x27;</span>, <span class="string">&#x27;status&#x27;</span>, <span class="string">&#x27;important&#x27;</span>, <span class="string">&#x27;msg&#x27;</span>, <span class="string">&#x27;monitor_id&#x27;</span>, <span class="string">&#x27;utc&#x27;</span>, <span class="string">&#x27;duration&#x27;</span>, <span class="string">&#x27;down_count&#x27;</span>, <span class="string">&#x27;end_time&#x27;</span>, <span class="string">&#x27;retries&#x27;</span>])</span><br><span class="line">df_ping[<span class="string">&#x27;Time&#x27;</span>] = pd.to_datetime(df_ping[<span class="string">&#x27;time&#x27;</span>])</span><br><span class="line">df_ping = df_ping.drop(columns=<span class="string">&#x27;time&#x27;</span>)</span><br><span class="line">df_ping</span><br></pre></td></tr></table></figure><p>This gives me a <a href="https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.html">DataFrame</a> like this:</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">pingTime</span><br><span class="line"><span class="number">0</span><span class="number">83.0</span><span class="number">2025</span>-<span class="number">11</span>-03 06:<span class="number">22</span>:08</span><br><span class="line"><span class="number">1</span><span class="number">198.0</span><span class="number">2025</span>-<span class="number">11</span>-03 06:<span class="number">23</span>:08</span><br><span class="line"><span class="number">2</span><span class="number">61.0</span><span class="number">2025</span>-<span class="number">11</span>-03 06:<span class="number">24</span>:08</span><br><span class="line"><span class="number">3</span><span class="number">68.0</span><span class="number">2025</span>-<span class="number">11</span>-03 06:<span class="number">25</span>:08</span><br><span class="line"><span class="number">4</span><span class="number">276.0</span><span class="number">2025</span>-<span class="number">11</span>-03 06:<span class="number">26</span>:08</span><br></pre></td></tr></table></figure><h2><span id="geolocation">Geolocation</span></h2><p>I hadn’t thought ahead about how I would geolocate the data, so I fell back on exporting my timeline information from my Android. I don’t think you can use Google Takeout for this now because it’s stored directly on the phone. See <a href="https://www.androidauthority.com/android-google-maps-location-history-3491255/">this article from Android Authority</a> about how to create an export.</p><p>The export contains your full history in a large JSON file, while for this project I want six hours. I used the <a href="https://github.com/Scarygami/location-history-json-converter">Location History JSON Converter</a> python script to transform the JSON file into a CSV containing only the day of the trip.<sup class="footnote-ref"><a href="#fn1" id="fnref1">[1]</a></sup> I used the same Jupyter notebook to create a DataFrame with time, latitude, and longitude.</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> pandas <span class="keyword">as</span> pd</span><br><span class="line">df = pd.read_csv(<span class="string">&quot;../inputs/timeline.csv&quot;</span>)</span><br><span class="line">df[<span class="string">&#x27;Time&#x27;</span>] = pd.to_datetime(df[<span class="string">&#x27;Time&#x27;</span>])</span><br><span class="line">df</span><br></pre></td></tr></table></figure><h2><span id="combining-the-data">Combining the data</span></h2><p>At this point I have two data sets: the ping data, indexed by time, and the location data, also indexed by time. However, the timestamps are dissimilar. I tried a few techniques before landing on pandas’ <a href="https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.merge_asof.html">merge_asof</a> function:</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">combined_df = pd.merge_asof(df_ping, df, on=<span class="string">&quot;Time&quot;</span>, direction=<span class="string">&quot;nearest&quot;</span>, tolerance=pd.Timedelta(<span class="string">&quot;15m&quot;</span>))</span><br><span class="line">combined_df[<span class="string">&#x27;ping&#x27;</span>] = combined_df[<span class="string">&#x27;ping&#x27;</span>].fillna(<span class="number">0</span>)</span><br><span class="line">combined_df.to_csv(<span class="string">&#x27;../outputs/output.csv&#x27;</span>)</span><br></pre></td></tr></table></figure><p>The important part is <code>direction=&quot;nearest&quot;</code>; this compensates for non-matching timestamps. To avoid matching two wildly dissimilar points, I set the outer boundary to fifteen minutes. The result is a DataFrame that combines the ping and geolocation data:</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">pingTimeLatitudeLongitude</span><br><span class="line"><span class="number">0</span><span class="number">0.996860</span><span class="number">2025</span>-<span class="number">11</span>-03 06:<span class="number">22</span>:08<span class="number">40.213511</span>-<span class="number">79.768900</span></span><br><span class="line"><span class="number">1</span><span class="number">0.992509</span><span class="number">2025</span>-<span class="number">11</span>-03 06:<span class="number">23</span>:08<span class="number">40.213511</span>-<span class="number">79.768900</span></span><br><span class="line"><span class="number">2</span><span class="number">0.997692</span><span class="number">2025</span>-<span class="number">11</span>-03 06:<span class="number">24</span>:08<span class="number">40.213511</span>-<span class="number">79.768900</span></span><br><span class="line"><span class="number">3</span><span class="number">0.997427</span><span class="number">2025</span>-<span class="number">11</span>-03 06:<span class="number">25</span>:08<span class="number">40.160347</span>-<span class="number">79.746285</span></span><br><span class="line"><span class="number">4</span><span class="number">0.989558</span><span class="number">2025</span>-<span class="number">11</span>-03 06:<span class="number">26</span>:08<span class="number">40.160347</span>-<span class="number">79.746285</span></span><br></pre></td></tr></table></figure><h2><span id="next-steps">Next steps</span></h2><p>I’m playing with <a href="https://kepler.gl">kepler.gl</a> to visualize the data. This has exposted a few issues:</p><ol><li>I need minute-by-minute geolocation data for more accurate mapping of the pings. I’m testing <a href="https://gpslogger.app">GPSLogger for Android</a> for this purpose. It writes GPX files, which are easier to work with. I’ve had good results with the <a href="https://pypi.org/project/gpxpy/">gpxpy</a> library.</li><li>With ping, lower numbers are better, but I probably want the opposite for visualization, with total absence of data meaning there was no cell signal whatsoever.</li></ol><p><img src="/2025/11/07/Transforming-GPS-log-data-in-a-Jupyter-notebook/kepler.gl.png" alt=" Visualization of ping data" title="Map showing relative signal strength between Pittsburgh and Washington"></p><p>I have a few trips coming up where I can play around with this.</p><hr class="footnotes-sep"><section class="footnotes"><ol class="footnotes-list"><li id="fn1" class="footnote-item"><p>As of November 7, 2025, you need to use the patch on <a href="https://github.com/Scarygami/location-history-json-converter/pull/65">Add support for encrypted location history from devices</a>. <a href="#fnref1" class="footnote-backref">↩︎</a></p></li></ol></section>]]></content>
    
    
    <summary type="html">Mapping WiFi and cell signal strength on an Amtrak train.</summary>
    
    
    
    <category term="Web Development" scheme="https://blog.goodbyeplease.com/categories/Web-Development/"/>
    
    
    <category term="Amtrak" scheme="https://blog.goodbyeplease.com/tags/Amtrak/"/>
    
    <category term="kepler.gl" scheme="https://blog.goodbyeplease.com/tags/kepler-gl/"/>
    
    <category term="Jupyter" scheme="https://blog.goodbyeplease.com/tags/Jupyter/"/>
    
  </entry>
  
  <entry>
    <title>A thousand miles without leaving the ground</title>
    <link href="https://blog.goodbyeplease.com/2025/08/02/A-thousand-miles-without-leaving-the-ground/"/>
    <id>https://blog.goodbyeplease.com/2025/08/02/A-thousand-miles-without-leaving-the-ground/</id>
    <published>2025-08-03T01:35:00.000Z</published>
    <updated>2025-08-03T01:34:17.074Z</updated>
    
    <content type="html"><![CDATA[<p>Even before we left <a href="/2025/05/01/Brunswick/" title="Brunswick">Brunswick</a> in May we were determined to come back for the <a href="https://www.bowdoin.edu/arctic-museum/exhibits/2025/printed-textiles-from-kinngait-studios.html">ᖃᓪᓗᓈᖅᑕᐃᑦ  ᓯᑯᓯᓛᕐᒥᑦ   Printed Textiles from Kinngait Studios</a> exhibit before it closed at the end of October. Separately, we got invited to a friend’s birthday party in Rochester, New York, toward the end of July. Now, Rochester and Brunswick are in opposite directions from each other, but they’re both reachable by rail, and for us that’s enough. Over a period of nine days we took six Amtrak trains (covering 1400 miles), several commuter buses, and innumerable local buses and subways.</p><p>We saw textiles, vintage games, and the director’s cut of a <em>Captain America</em> movie (not one with Chris Evans!) Ate Indian food in two different states and BBQ in an old train station. Found a Frank Lloyd Wright tribute in a warehouse. Gave some books away and bought more than enough to replace them. Read on.</p><h2><span id="rochester">Rochester</span></h2><p>Our train to Rochester is the 10:20 AM <em>Empire Service</em>, leaving on Friday. That would make for a pretty early morning out of Easton so we head in Thursday evening on <a href="https://www.fullingtontours.com">Fullington</a>, staying at one of the many Hilton properties in Midtown Manhattan. Dinner was at <a href="http://www.patialany.com/">Patiala Indian Grill</a> on 34th and 9th. It’s small, but fast, and pretty good to boot. I discovered it in 2022 while looking for decent restaurants within a stone’s throw of Penn Station.</p><p>Urban renewal hasn’t reached the area around Rochester’s Amtrak station. Things change once you get south of Main Street. After getting off the train we have dinner at <a href="https://dinosaurbarbque.com/locations/rochester">Dinosaur Bar-B-Que</a>. They’re a regional chain, with six locations in Upstate New York. They don’t hew to a particular style. One of their trademarks is repurposing old buildings for their restaurants. In this case, it’s the old Lehigh Valley Railroad station, the northern terminus of the <a href="https://en.wikipedia.org/wiki/Rochester_Branch">Rochester Branch</a> and long abandoned. A friend had recommended this place and I didn’t know about the railroad connection ahead of time. Lovely building and a pretty good meal. For railfans and urban explorers, the long abandoned <a href="https://en.wikipedia.org/wiki/Rochester_subway">Rochester Subway</a> tunnel under Broad Street is adjacent to the restaurant.</p><p><img src="/2025/08/02/A-thousand-miles-without-leaving-the-ground/lehigh-valley-bbq.jpg" alt="Dinosaur BBQ in the old Lehigh Valley Railroad station." title="Brick building with tower. A chain-link fence in the foreground."></p><p><img src="/2025/08/02/A-thousand-miles-without-leaving-the-ground/subway.jpg" alt="The abandoned Rochester subway beneath Broad Street." title="Columns line a trackless tunnel."></p><p>In the morning, we met a friend for brunch at <a href="http://www.owlhouserochester.com/">The Owl House</a>, a vegan-friendly restaurant on the south side of downtown. Afterward, we walked over to the <a href="http://www.museumofplay.org/">Strong National Museum of Play</a>, which I cannot recommend highly enough. It’s <em>enormous</em> and full of fun and interesting things to see and do. I could have spent hours with the old video games on the second floor. One hands-on-activity on the first floor had you color in a fish (on paper), which would then be scanned and instantly projected with other scanned fish on a wall. Very creative use of technology!</p><p><img src="/2025/08/02/A-thousand-miles-without-leaving-the-ground/projected-fish.jpg" alt="Scanned images of paper fish float on screen" title="Scanned images of paper fish float on screen."></p><p>In the evening, we gathered with a group of friends to celebrate a double birthday. We were at the <a href="https://artisanworks.net">ARTISANWorks</a>, an event space on the east side of Rochester. Imagine an antique mall, the type where many different vendors have their own spaces. Now imagine that there’s also room for a dance floor and dinner. Finally, there’s a block of rooms in the back done up arts-and-crafts style in homage to Frank Lloyd Wright. That’s ARTISANWorks, and it made for a memorable evening.</p><p>In the morning, it was time to start heading east toward Brunswick. On the way out we visited <a href="http://www.javascafe.com/">Java’s Cafe</a>, where a local wag greeted us a “travelers from a distant land” (we gently corrected him that we weren’t <em>that</em> distant). I should mention that we used the <a href="https://www.myrts.com">RTS bus network</a> for all but one trip and found that it was clean, fast, and reliable.</p><h2><span id="providence">Providence</span></h2><p>On the way out to Rochester I passed 130,000 lifetime miles on Amtrak. I’ve more mileage on the Chicago-New York/Boston <em>Lake Shore Limited</em> than any other train (26,005 miles), so that felt appropriate. The scenery between Rochester and Albany is pretty and unremarkable. You get some views of the Mohawk River. South of Albany the line follows the Hudson River all the way to New York, and that’s much more interesting.</p><p>Our final destination was Providence in Rhode Island. We needed to break the journey somewhere, and Boston’s a little expensive for a simple break-of-journey. Our original plan, to take the <em>Lake Shore Limited</em> to Worcester, fell through after CSX embargoed the line through the Berkshires <a href="https://www.nepm.org/regional-news/2025-07-22/berkshire-flyer-train-service-disrupted-by-sinkhole">because of a sinkhole</a>. As a good friend and fellow railfan observed, “that train can’t get a break.” Not wanting to spend hours crossing Massachusetts on a bus, we switched our itinerary to Providence via New York City.</p><p>After an uneventful run on a <em>Northeast Regional</em> we reached Providence after the dinner hour. We stayed in the Homewood Suites near the station, and discovered that the primary benefit of doing so was an opportunity to do laundry. We decamped to <a href="http://www.layaliprovidence.com/">Layali</a> for a late dinner. Excellent flatbreads and a good vibe all around.</p><h2><span id="portland">Portland</span></h2><p>Providence is 41 miles from Boston as the crow flies. Take you an hour and twenty minutes to drive it via I-95 and I-93. The <em>Acela</em> needs 43 minutes. We took an MBTA <a href="https://www.mbta.com/schedules/CR-Providence/timetable">Providence/Stoughton line</a> train, which needs 1 hour 11 minutes. The train to Brunswick isn’t until 11:50 AM, and unreserved commuter rail is easier for this kind of short hop.</p><p>The connection in Boston is an unusual one. Boston has two principal railway stations: South Station and North Station. There is no direct connection between the two. The <em>Downeaster</em>, which runs from Boston to Brunswick via Portland, is Amtrak’s only train that runs out of North Station. Amtrak through bookings include a “self-transfer” in which you get off at Back Bay and take the Orange Line subway up to North Station.</p><p>We get off in Portland to pay a repeat visit to <a href="http://www.duckfat.com/">Duckfat</a>, which we’d visited the last time. Got the poutine and milkshake again, and it’s still excellent. From there, an easy ride on the <a href="https://www.gpmetro.org/routes-schedules-services/">Metro Breeze</a> up to Brunswick.</p><h2><span id="brunswick">Brunswick</span></h2><p>We stayed at <a href="https://www.onesixtyfivemaine.com">OneSixtyFive</a> again, but for three days instead of two, and in the detached cottage. Excellent experience. The cottage is cozy and well-equipped, though we didn’t do our own cooking this time.</p><p>We tried some new restaurants and had a good time everywhere. The breakfast sandwiches were so good at <a href="http://www.bohemiancoffeehouse.com/">Bohemian Coffee House &amp; Deli</a> we went back a second morning. We did a late dinner and mocktails at the <a href="https://theabbeymaine.com/">Abbey</a>, then came back for breakfast. We tried the <em>other</em> Indian restaurant in Brunswick, <a href="http://sherepunjabme.com/">Shere Punjab</a>, where I had an unusually good mango lassi and then mango chicken, a new experience for me. The Marsala Porcini at <a href="https://pomelia.restaurant/">Pomelia</a>, located in the same building as the train station, was outstanding.</p><p>The main event was our return to the <a href="https://www.bowdoin.edu/arctic-museum/">Peary–MacMillan Arctic Museum</a> for the textile exhibit. This was everything we’d hoped for and more. Most of pieces were from the 1950s-1960s, though there were also some modern examples of Inuit art. Many were on loan from the <a href="https://www.westbaffin.com">West Baffin Cooperative</a>. There’s a <a href="https://harpswellanchor.org/2025/06/forgotten-for-decades-unearthed-inuit-textiles-tell-compelling-story-at-brunswick-museum/">good write-up</a> in the <em>Harpswell Anchor</em> with photos from the exhibit. The only thing missing was a catalog of the exhibit, but we ordered one from the <a href="https://textilemuseum.ca">Textile Museum of Canada</a>. Incidentally, they’ve been closed since February 2025 and are soliciting donations.</p><p>We also returned to <a href="https://curtislibrary.com/twice-told-tales/">Twice-Told Tales Book Store</a> to both donate books and buy books. We will left with more books than we started with, especially after we visited <a href="http://gulfofmainebooks.blogspot.com/">Gulf of Maine Books</a>. The owner’s a real character and we chatted a while.</p><p>One morning we did the <a href="https://www.androscogginriverwalk.org">river walk</a> along the Androscoggin. There’s a path along the Topsham side of the river between Main Street and a swinging bridge. The swinging bridge, refurbished in 2006, takes you back across to Brunswick at Cushing Street. While crossing the the swiging bridge we were treated to a large gathering of ducks, possibly for their 10:30 AM standup. The meeting broke up almost immediately in a flurry of quacking. One sympathises.</p><p><img src="/2025/08/02/A-thousand-miles-without-leaving-the-ground/duck-standup.jpg" alt="The ducks arrive for the 10:30 AM standup on the Androscoggin." title="Ducks on a blue river beneath a walking bridge. There is a tree in the foreground."></p><h2><span id="boston">Boston</span></h2><p>On leaving Brunswick we headed to Boston. Because of various trackwork issues and stops in Portland, this was the first time we made the Brunswick-Boston trip in one go, entirely by train. We stayed at the <a href="http://www.theportersquarehotel.com/">Porter Square Hotel</a>, which has become something of a standby for us. The rooms are comfortable, it’s near the Red Line, and it’s convenient to our friends in the Boston area.</p><p>We met a friend of ours for dinner at <a href="http://www.dragonpizzasomerville.com/">Dragon Pizza</a>, an old Somerville standby chiefly notable for getting on Dave Portnoy’s bad side a few years ago. In this as in many things, our experience did not match his. Go there. The slices are generous, and don’t skip the garlic knots.</p><p>In the morning we wandered around with time to kill before the 1:05 PM <em>Acela</em> back to New York. We had coffee at the <a href="http://www.cafezingcambridge.com/">Cafe Zing</a>, located in a former bookstore in the Porter Square shopping center. There we split up. Liz took a bus up to <a href="http://www.playtimecrafts.com/">Play Time</a>, a craft store in Arlington. They’ve got everything, including her favorite fabric dye. On our last visit I got a bunch of Woodland Scenics supplies. I went down to the <a href="http://www.brattlebookshop.com/">Brattle</a>, my favorite bookstore in Boston, and then up to <a href="https://www.wardmaps.com/">WardMaps</a> for an MBTA tote bag.</p><p>The only real travel hiccup occurred leaving Boston. A brushfire damaged trackside communications between Back Bay and Route 128, leading to single tracking and cascading delays. We left Providence 40 minutes late on what it supposed to be a 43-minute trip. Ah well. Lovely day outside, and we made some of it up by the time we reached New York.</p><h2><span id="new-york-new-york">New York, New York</span></h2><p>I never book bus tickets back from New York in advance. Trans-Bridge Lines is all-reserved now, and I don’t like to commit to a particular return. Part of that is protecting myself against a late Amtrak arrival, but also the knowledge that I might want to stay over in New York for one reason or another.</p><p>That reason arrived in the form of the <a href="https://www.aaiff.org/aaiff48/captain-america">Friday night screening</a> of the “director’s cut” of <a href="https://letterboxd.com/film/captain-america-1990/">Albert Pyun’s <em>Captain America</em></a> at the Asian American Film Festival. Menahem Golan produced this shortly after leaving Cannon Films. It was released in 1990 and starred Matt Salinger in the lead role. It’s famously bad, and never got a theatrical release stateside. Golan chopped it up for the release, and Pyun lugged around film cans containing his preferred version up until his death.</p><p>First, we had some time to kill, and after dinner we made our way on foot down to the Regal at Union Square. We love taking the subway but it was a nice night out and Manhattan’s a very walkable city. We wandered down Fifth Avenue–new territory for us–past the Empire State Building, and parked at Madison Square Park for a while. It’s a pleasant space, extending from 26th to 23rd, and from Fifth to Fourth. There’s a lily pond on the north side and a fountain on the south side. Couple dog parks. There’s a temporary installation by Lily Kwong called <a href="https://madisonsquarepark.org/horticulture/exhibitions/view/gardens-of-renewal/">Gardens Of Renewal</a> that diverted us for a few minutes.</p><p><img src="/2025/08/02/A-thousand-miles-without-leaving-the-ground/lily-pond.jpg" alt="Lily pond in Madison Square Park" title="Buildings reflected in a pool with lily pads as the light falls."></p><p>I may write a full review of <em>Captain America</em> in the future. The cut we saw at the Regal has some flaws but it’s an impressive effort and doesn’t deserve all the opprobrium heaped (perhaps rightly) on the theatrical cut. Hopefully the restoration work continues and a proper release takes place.</p><p>After that, we were done. Back to the hotel, and home on Trans-Bridge Lines the next morning. 1,406 miles on Amtrak. Two commuter trains in the Boston area. The New York City Subway. Local and regional buses in the Lehigh Valley, Rochester, Boston, and Greater Portland. Only took two cabs, one in Rochester and one in Boston. Hung out with a lot of cool people, relaxed, ate good food, bought books, read books, saw <em>Captain America</em> as Albert Pyun intended it. Good trip all around.</p>]]></content>
    
    
    <summary type="html">A week traveling around the Northeast United States.</summary>
    
    
    
    <category term="Travel" scheme="https://blog.goodbyeplease.com/categories/Travel/"/>
    
    
    <category term="Brunswick" scheme="https://blog.goodbyeplease.com/tags/Brunswick/"/>
    
    <category term="Rochester" scheme="https://blog.goodbyeplease.com/tags/Rochester/"/>
    
    <category term="Providence" scheme="https://blog.goodbyeplease.com/tags/Providence/"/>
    
    <category term="Boston" scheme="https://blog.goodbyeplease.com/tags/Boston/"/>
    
  </entry>
  
  <entry>
    <title>The Pillars of Hercules</title>
    <link href="https://blog.goodbyeplease.com/2025/06/23/The-Pillars-of-Hercules/"/>
    <id>https://blog.goodbyeplease.com/2025/06/23/The-Pillars-of-Hercules/</id>
    <published>2025-06-23T23:58:58.000Z</published>
    <updated>2025-06-24T01:27:15.740Z</updated>
    
    <content type="html"><![CDATA[<p>I was always aware of Paul Theroux growing up. I was raised in a family that traveled (and travels) by train and had read Theroux’s travel books. There was also a VHS of <em><a href="https://letterboxd.com/film/the-mosquito-coast/">The Mosquito Coast</a></em>, with a crazed Harrison Ford staring back at you, and a tagline proclaiming that “He planned a paradise. He created a Hell.”</p><p>I think the first Theroux I read on my own was the delightful <a href="https://www.goodreads.com/book/show/130511.Riding_the_Iron_Rooster"><em>Riding the Iron Rooster</em></a>, about his travels (mostly by train) through the People’s Republic of China in the mid-1980s. The thing about Theroux is that he’s interested in the world around him and in seeking out new experiences. When he travels to a new place, he talks to people and asks penetrating questions. His books weren’t banned by Singapore and apartheid South Africa for nothing.</p><p>I read <em>Riding the Iron Rooster</em> while on study abroad in Germany in 2003. My father probably gave it to me. I have an email listing five books I’d read in the first month:</p><ul><li><a href="https://www.goodreads.com/book/show/12331767-high-rise"><em>High-Rise</em></a></li><li><em><a href="https://www.goodreads.com/book/show/656.War_and_Peace">War and Peace</a></em></li><li><em>Riding the Iron Rooster</em></li><li><a href="https://www.goodreads.com/book/show/671957.Finding_Your_Religion"><em>Finding Your Religion</em></a></li><li><a href="https://www.goodreads.com/book/show/168668.Catch_22"><em>Catch-22</em></a></li></ul><p>I know <em>High-Rise</em> was Dad’s suggestion and <em>Finding Your Religion</em> Mom’s. Dad later mailed out two books by Thomas Mann: <em><a href="https://www.goodreads.com/book/show/80890.Buddenbrooks">Buddenbrooks</a></em> (John Wood’s translation and a personal favorite), and <a href="https://www.goodreads.com/book/show/34440.Doctor_Faustus"><em>Doctor Faustus</em></a> (still haven’t read it).</p><p>It’s an eclectic group of books. Thing is, when you’re spending hours on trains running around Europe in the era before smartphones and WiFi, and you’re traveling by yourself, you can read, you can write, and you can look out the window. Theroux is often striking up interesting and insightful conversations, but that’s why he’s a published writer and I’m not.</p><p><img src="/2025/06/23/The-Pillars-of-Hercules/In-the-gangway.jpg" alt="Sitting in the gangway of a train in France reading Buddenbrooks. May 2003." title="A man sits in the gangway of a train and reads Buddenbrooks"></p><p>I’m not having a Luddite moment of any kind, well no more so than usual, but as I’ve been traveling this year I’ve tried to set the devices aside and read more. To make it serendipitous, I’ve bought the books along the way. Thus I picked up <em><a href="https://www.goodreads.com/book/show/3398625-the-lost-city-of-z">The Lost City of Z</a></em> in the Newark airport on my way out to Denver in April, and <em><a href="https://www.goodreads.com/book/show/1898.Into_Thin_Air">Into Thin Air</a></em> at the <a href="https://www.tatteredcover.com">Tattered Cover</a> location in Union Station.</p><p>In late May my wife and I were in Greenport, New York, as part of a trip that took us across Long Island Sound to New London and Boston, and then up to <a href="/2025/05/01/Brunswick/" title="Brunswick">Brunswick</a>. My feelings on Greenport are mixed (<a href="https://suffolktimes.archive.timesreview.com/2020/05/should-greenport-silence-its-fire-alarm/">they have a siren</a>), but <a href="https://www.burtonsbooks.com">Burton’s Bookstore</a> on Front Street has an excellent selection. I picked up two books there: Ben Macintyre’s <em><a href="https://www.goodreads.com/book/show/203767605-the-siege">The Siege</a></em>, and Paul Theroux’s <a href="https://www.goodreads.com/book/show/130512.The_Pillars_of_Hercules"><em>The Pillars of Hercules</em></a>.</p><p>I didn’t start it until we got back, brought it with me during trips to Swarthmore and Michigan, and finally finished it a few days ago. Theroux’s goal was to re-create the <a href="https://en.wikipedia.org/wiki/Grand_Tour">Grand Tour</a> in the 1990s, circling the Mediterranean. I lost track of his timetable but I think he was at it–with one large break–for the better part of the year. It’s a fun and engrossing read. One thing that stands out in my memory is Theroux traveling through former Yugoslavia at a time when that was not at all safe. One night he’s shacked up in a hotel full of refugees and UN aid workers. There’s also his time in the Middle East, then as now wracked by war and political uncertainty.</p><p>As always, he meets various people. Some interesting, some not. Some polite, some rude. On a ferry from Haifa to Piraeus he meets a man who deals with his mental health by refusing to make a permanent home and alternating between Brussels and Tel Aviv. He’s taken this route so many times that he’s got everything down to a well-ordered routine, even where to buy fruit in Limassol. This could be bizarre, but the thing is Theroux <em>likes people</em> and wants to know more about them.</p><p>He’s also traveling during the last gasp of the pre-internet age. <em>The Pillars of Hercules</em> was published in 1995. There is no mention of computers or email. Few people have cellular phones. Theroux gets his news from newspapers or his shortwave radio, or from talking to people. Train and ferry tickets are bought in cash. Sometimes he has a hotel in mind when he arrives in a new city, but he almost never has a booking ahead of time. He’s often making decisions based on incomplete information. The digital backend may be growing in the mid-1990s, but it’s still an analog age. Traveling into the unknown as he does requires a courage (and facility with languages) that I do not possess.</p><p>Next up: <em><a href="https://www.goodreads.com/book/show/198283571-some-men-in-london">Some Men in London: Queer Life, 1945–1959</a></em></p>]]></content>
    
    
    <summary type="html">&lt;p&gt;I was always aware of Paul Theroux growing up. I was raised in a family that traveled (and travels) by train and had read Theroux’s travel books. There was also a VHS of &lt;em&gt;&lt;a href=&quot;https://letterboxd.com/film/the-mosquito-coast/&quot;&gt;The Mosquito Coast&lt;/a&gt;&lt;/em&gt;, with a crazed Harrison Ford staring back at you, and a tagline proclaiming that “He planned a paradise. He created a Hell.”&lt;/p&gt;
&lt;p&gt;I think the first Theroux I read on my own was the delightful &lt;a href=&quot;https://www.goodreads.com/book/show/130511.Riding_the_Iron_Rooster&quot;&gt;&lt;em&gt;Riding the Iron Rooster&lt;/em&gt;&lt;/a&gt;, about his travels (mostly by train) through the People’s Republic of China in the mid-1980s. The thing about Theroux is that he’s interested in the world around him and in seeking out new experiences. When he travels to a new place, he talks to people and asks penetrating questions. His books weren’t banned by Singapore and apartheid South Africa for nothing.&lt;/p&gt;
&lt;p&gt;I read &lt;em&gt;Riding the Iron Rooster&lt;/em&gt; while on study abroad in Germany in 2003. My father probably gave it to me. I have an email listing five books I’d read in the first month:&lt;/p&gt;</summary>
    
    
    
    <category term="Books" scheme="https://blog.goodbyeplease.com/categories/Books/"/>
    
    
    <category term="Paul Theroux" scheme="https://blog.goodbyeplease.com/tags/Paul-Theroux/"/>
    
    <category term="What I&#39;m Reading" scheme="https://blog.goodbyeplease.com/tags/What-I-m-Reading/"/>
    
  </entry>
  
  <entry>
    <title>Empty tags in a thumbsup album</title>
    <link href="https://blog.goodbyeplease.com/2025/06/20/Empty-tags-in-a-thumbsup-album/"/>
    <id>https://blog.goodbyeplease.com/2025/06/20/Empty-tags-in-a-thumbsup-album/</id>
    <published>2025-06-20T23:59:06.000Z</published>
    <updated>2025-06-21T01:25:37.851Z</updated>
    
    <content type="html"><![CDATA[<p>I’m migrating my older galleries from Flickr to my self-hosted <a href="https://galleries.goodbyeplease.com">static gallery site</a> based on <a href="https://thumbsup.github.io">thumbsup</a>. This is a slow process because I’m reconciling my local copies with Flickr; for some of the older albums I don’t have local copies. In those cases, I download the originals and rewrite the metadata.</p><p>I ran into one interesting problem. With my configuration thumbsup usually generates three top-level containers:</p><ul><li>Tags</li><li>Years</li><li>Albums</li></ul><p>Instead, it was generating <em>four</em> containers, with Tags repeated:</p><ul><li>Tags</li><li>Years</li><li>Albums</li><li>Tags</li></ul><p>This second “Tags” contained only seven images, all of which I’d downloaded from Flickr. The first “Tags”, meanwhile, was effectively overwritten by the second, so I couldn’t just leave it. After false starts, I got on the right track when I realized that <a href="https://www.lynapp.com">Lyn</a>, which I use for desktop gallery browsing, didn’t recognize my custom tags.</p><h2><span id="metadata">Metadata</span></h2><p>There are a dizzying number of metadata formats and tags. The <a href="https://exiftool.org/TagNames/index.html">ExifTool documentation</a> recognizes 17,676 unique tag names spread across 150 formats. The two most prominent for this use case are <a href="https://en.wikipedia.org/wiki/International_Press_Telecommunications_Council#Photo_metadata">IPTC</a> (which stands for International Press Telecommunications Council) and <a href="https://en.wikipedia.org/wiki/Extensible_Metadata_Platform">XMP</a> (Extensible Metadata Platform). Each defines their own tag for keywords. XMP uses <code>Subject</code>, while IPTC uses <code>Keywords</code>. Both expect a comma-separated list of strings. Thumbsup supports both, plus <code>keywords</code>, which <a href="https://www.organizepictures.com/2013/09/everything-you-need-to-know-about-picasa-metadata">Picasa used</a>.</p><p>My PHP wrapper script invokes <a href="https://exiftool.org">ExifTool</a> and uses the <code>-keywords</code> argument. I briefly thought this meant I was using the Picasa tag. In fact, the <code>-keywords</code> argument in ExifTool will populate the correct tag(s) based on the existing metadata in the file.<sup class="footnote-ref"><a href="#fn1" id="fnref1">[1]</a></sup> For my images this means the IPTC tag, so examining them reveals that <code>Keywords</code> is set.</p><p>The problem is that the files I downloaded from Flickr had an empty <code>Subject</code> tag, which conflicted with the custom value I was writing to <code>keywords</code>. My immediate fix was to remove <code>Subject</code> from the files:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">exiftool -Subject=/path/to/file*.jpg</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>That did resolve the immediate issue, by removing the erroneous second “Tags”.</p><hr class="footnotes-sep"><section class="footnotes"><ol class="footnotes-list"><li id="fn1" class="footnote-item"><p>See this <a href="https://exiftool.org/forum/index.php?topic=15344.0">forum post</a> and <a href="https://exiftool.org/exiftool_pod.html#TAG---VALUE">related documentation</a> for more information. <a href="#fnref1" class="footnote-backref">↩︎</a></p></li></ol></section>]]></content>
    
    
    <summary type="html">Resolving conflicts between Subject and Keywords</summary>
    
    
    
    <category term="Web Development" scheme="https://blog.goodbyeplease.com/categories/Web-Development/"/>
    
    
    <category term="thumbsup" scheme="https://blog.goodbyeplease.com/tags/thumbsup/"/>
    
    <category term="exif" scheme="https://blog.goodbyeplease.com/tags/exif/"/>
    
  </entry>
  
  <entry>
    <title>LANTA June 2025 changes</title>
    <link href="https://blog.goodbyeplease.com/2025/05/28/LANTA-June-2025-changes/"/>
    <id>https://blog.goodbyeplease.com/2025/05/28/LANTA-June-2025-changes/</id>
    <published>2025-05-28T23:52:31.000Z</published>
    <updated>2025-05-29T00:23:52.018Z</updated>
    
    <content type="html"><![CDATA[<p>The Lehigh and Northampton Transportation Authority (LANTA) is <a href="https://lantabus.com/june-2025-service-changes/">restructuring its routes</a> at the end of June this year. Some interesting changes within Easton:</p><ul><li>West Ward / College Hill: <a href="https://lantabus.com/june-2025-service-changes/route-106/">Route 106</a>, which currently runs from downtown  Easton north to the Palmer Industrial Park via PA 248, is being extended from Easton up Cattell and Sullivan Trail to Forks Plaza. In addition, it’s frequency is increasing to half-hourly between Easton Hospital and Forks. <a href="https://lantabus.com/routes-and-schedules/route-214/">Route 214</a>, currently running from dowtown Easton to the Forks Industrial Park on an hourly schedule, goes down every three hours and meanders around in Forks.</li><li>Downtown / Northampton Crossings: <a href="https://lantabus.com/routes-and-schedules/route-216/">Route 216</a> was running on a not-quite-hourly schedule from downtown up PA 248 to Northampton Crossings and making local stops on Northampton Street. It loops on Greenwood now and doesn’t go up 248, with a reduced schedule.</li></ul><p>The big change here is the vastly improved access between the West Ward and College Hill. In theory you could make a connection with the 216 downtown but (a) buses weren’t held for it and (b) it was hourly. Now the bus becomes a viable option for reaching campus. Losing some local service on Northampton is offset by the more frequent service on Lehigh/Washington, and I was already using it more often anyway.</p>]]></content>
    
    
    <summary type="html">Thoughts on LANTA service changes for June 2025.</summary>
    
    
    
    <category term="Travel" scheme="https://blog.goodbyeplease.com/categories/Travel/"/>
    
    
    <category term="LANTA" scheme="https://blog.goodbyeplease.com/tags/LANTA/"/>
    
  </entry>
  
  <entry>
    <title>Brunswick</title>
    <link href="https://blog.goodbyeplease.com/2025/05/01/Brunswick/"/>
    <id>https://blog.goodbyeplease.com/2025/05/01/Brunswick/</id>
    <published>2025-05-01T14:37:17.000Z</published>
    <updated>2025-05-01T15:50:40.540Z</updated>
    
    <content type="html"><![CDATA[<p>Ahead of our trip, most of the conversations around Brunswick involved specifying that we meant the one in Maine, and then turned to some variation of “Oh. Why?” Admittedly, we didn’t have much of an answer for “What’s in Brunswick?” beyond Bowdoin College. We went here because it’s the northern terminus of Amtrak’s <em>Downeaster</em>, and I wanted to scratch it off the list. Besides, we have friends in Boston. Following the philosophy of never spending more time traveling to a place than you’re in the place itself, we did two nights, and I’m now prepared to give a partial answer to the question of “What’s in Brunswick?”</p><h2><span id="people">People</span></h2><p>Wednesday morning I went for a walk around town, mostly looking at railroad infrastructure. The first thing I noticed, however, is that when you come to a crosswalk as a pedestrian the cars actually yield to you. This kept happening throughout the day. Later, we went to <a href="https://curtislibrary.com/twice-told-tales/">Twice-Told Tales Book Store</a>. It’s run by volunteers, and proceeds go the local library. Everyone there was genuinely friendly and helped an out-of-towner find a book–<a href="https://openlibrary.org/books/OL2227684M/Making_tracks"><em>Terry Pindell’s Making tracks: an American rail odyssey</em></a>. Before we left I lightened my luggage by dropping off two books that I’d bought and read during our trip and wasn’t likely to re-read, though I’d enjoyed them: Ben Macintyre’s <a href="https://openlibrary.org/works/OL37762665W/Siege"><em>The Siege</em></a> and Douglas Preston’s <a href="https://openlibrary.org/works/OL17876084W/The_Lost_City_of_the_Monkey_God?edition=key%3A/books/OL36223774M"><em>The Lost City of the Monkey God</em></a>.</p><h2><span id="the-north-pole">The North Pole</span></h2><p>Bowdoin claims two prominent Arctic explorers as alumni: <a href="https://en.wikipedia.org/wiki/Robert_Peary">Robert Peary</a> and <a href="https://en.wikipedia.org/wiki/Donald_Baxter_MacMillan">Donald Baxter MacMillan</a>. Closely associated with them is <a href="https://en.wikipedia.org/wiki/Matthew_Henson">Matthew Henson</a>, son of a sharecropper and possibly the first man to reach the North Pole. On the campus of Bowdoin is the <a href="https://www.bowdoin.edu/arctic-museum/">Peary–MacMillan Arctic Museum</a>, part of the Center for Arctic Studies. It’s free and open to the public. When we visited one exhibit, “<a href="https://www.bowdoin.edu/arctic-museum/exhibits/2023/at-home-in-the-north.html">At Home in the North</a>,” was open, while work was underway to install  to “<a href="https://www.bowdoin.edu/arctic-museum/exhibits/2025/printed-textiles-from-kinngait-studios.html">ᖃᓪᓗᓈᖅᑕᐃᑦ  ᓯᑯᓯᓛᕐᒥᑦ   Printed Textiles from Kinngait Studios</a>.” We’re planning a return visit.</p><h2><span id="trains-and-transit">Trains and transit</span></h2><p>We’re here because Brunswick is the northern terminus of Amtrak’s <em>Downeaster</em>, which makes multiple daily trips from Boston. The station is located on the old Maine Central Railroad main line (the “lower road”), between two wyes. While I was out and about I saw something I hadn’t seen before–poles with arms over the tracks, with ropes/chains. They resembled catenary poles, but they’re actually tell-tales: an old, manual way for a train crew to know if they’re too tall for a bridge or tunnel.</p><p><img src="/2025/05/01/Brunswick/Tell-tales.jpg" alt="Tell-tales sit above both forks in the wye." title="Two railroad tracks surrounded by trees and leaves. There are poles standing next to the tracks, and from the poles hang chains."></p><p>Besides Amtrak, <a href="https://concordcoachlines.com/stop/brunswick-me/">Concord Coach Lines</a> has a daily bus running between Bangor and Boston, and Greater Portland Metro runs the <a href="https://www.gpmetro.org/local-and-express-routes/">BREEZ express bus</a> on a regular schedule (not clockface, alas) between Brunswick and Portland via Freeport and Yarmouth. There’s also the <a href="https://brunswicklink.org">Brunswick Link</a>, a free circulator shuttle in Brunswick itself.</p><h2><span id="food">Food</span></h2><p>Brunswick has a permanent population of about 21,000. That is (in the case of Easton, Pennsylvania, where I live), and is not (in the case of Mt. Pleasant, Michigan, where I grew up ) enough to support a varied and interesting dining scene. Happily, it’s the former case here. We only scratched the surface, and one highlight was <a href="https://www.bombaymahal.com">Bombay Mahal</a>, which claims to be Maine’s oldest Indian restaurant. Another was <em>Taco the Town</em>, a food truck parked on the Maine Street Mall.</p><h2><span id="cormorants">Cormorants</span></h2><p>Brunswick sits on the Androscoggin River and was once a mill town. We wandered down to the US-201 crossing a few times. On the west side is the Androscoggin River Reservoir and a dam. It reminds me a little of Turners Falls in Massachusetts. On the east side is a small, rocky outcropping home to a large number of water birds we tentatively identified as cormorants. Several of them had the engaging habit of drifting backwards under the bridge.</p><p><img src="/2025/05/01/Brunswick/Cormorants.jpg" alt="The Androscoggin River. On the left is the Frank J. Wood Bridge. At enter, Cormorant Island." title="A tree stands in front of a river."></p><h2><span id="whats-next">What’s next?</span></h2><p>We’re planning to come back to see the new exhibit at the Peary museum. Other local museums include the <a href="https://pejepscothistorical.org/visit/the-joshua-l-chamberlain-museum/">Joshua L. Chamberlain Museum</a> and the <a href="https://www.bowdoin.edu/events/stowe-house/index.html">Harriet Beecher Stowe House</a>. A docent at Twice-Told Tales told me the local joke that the Civil War started (<em>Uncle Tom’s Cabin</em>) and ended (Chamberlain receiving the Confederate surrender) in Brunswick. Portland and Freeport are day-trips from here. Belfast and Bangor are out of reach–Concord runs one bus per day and no return is possible.</p>]]></content>
    
    
    <summary type="html">A fun few days in Brunswick, Maine.</summary>
    
    
    
    <category term="Travel" scheme="https://blog.goodbyeplease.com/categories/Travel/"/>
    
    
    <category term="Brunswick" scheme="https://blog.goodbyeplease.com/tags/Brunswick/"/>
    
    <category term="Downeaster" scheme="https://blog.goodbyeplease.com/tags/Downeaster/"/>
    
    <category term="Bowdoin College" scheme="https://blog.goodbyeplease.com/tags/Bowdoin-College/"/>
    
  </entry>
  
  <entry>
    <title>Mercury in Retrograde</title>
    <link href="https://blog.goodbyeplease.com/2025/04/16/Mercury-in-Retrograde/"/>
    <id>https://blog.goodbyeplease.com/2025/04/16/Mercury-in-Retrograde/</id>
    <published>2025-04-16T15:40:00.000Z</published>
    <updated>2025-11-10T00:35:42.914Z</updated>
    
    <content type="html"><![CDATA[<p>The filming locations for <em>Mercury in Retrograde</em> are variously given as Allegan, Fennville, and Saugatuck. All three are towns in Allegan County, Michigan, a corner of Western Michigan known for being on Lake Michigan and for producing <a href="https://wwmt.com/news/local/perrigo-sells-prescription-business-to-altaris-in-15b-deal-allegan-michigan-grand-rapids">your prescription drugs</a>. <a href="https://en.wikipedia.org/wiki/Saugatuck,_Michigan">Saugatuck</a>, on the mouth of the Kalamazoo River, is an art colony and incongrous gay mecca in the middle of Dutch Reformed country. My family rented a cabin there for decades, and I knew the area well even before I went to college in nearby Kalamazoo. Holland, the setting of the recent, eponymous <em><a href="https://letterboxd.com/film/holland-2025/">Holland</a></em>, is just over the county line to the north.</p><p>This accounts for my interest in <em>Mercury in Retrograde</em>, which is a movie about three couples in a cabin in the woods for the weekend but is <em><strong>not</strong></em> a horror movie. It’s a low-key drama about three couples who loosely know each other and who spend a weekend together away from the city. There are no creatures, no mysterious forces at play. To misquote Sartre, in this film horror is other people. I don’t usually watch this sort of movie, and I’m really glad I did.</p><p>The cabin in question is the <a href="https://glampinghub.com/unitedstatesofamerica/midwest/michigan/fennville/vacation-cabin-rental-saugatuck-michigan/">Fern Hollow Cabin</a>, which is available for rental. At the risk of a digression, it’s not really in Fennville. To my mind it’s in Ganges, west of the Blue Star Highway and south of the I-196 interchange. Never made it to the What Not Inn for dinner but was always curious. The location is  a <em>perfect</em> distillation of cabin life in that part of the state. You’re in dune country, with the trees so thick that the light barely penetrates. Myrtle covers the ground. In the evening rain patters on the cabin’s roof. I was having feelings before the action even got going.</p><h2><span id="the-film">The film</span></h2><p>Our three couples live in Chicago and have made a house party in Michigan for the weekend. They’re Peggy and Wyatt (Najarra Townsend and Shane Simmons), Isabelle and Richard (Roxane Mesquida and Kevin Wehby), and Golda and Jack (Alana Arenas and Jack C. Newell). Peggy is the odd one out; she’s the new girlfriend and she’s meeting this friend group. Jack and Golda are married and Jack’s family owns the cabin. Isabelle and Richard are in a long-term relationship.</p><p><img src="/2025/04/16/Mercury-in-Retrograde/a-cabin-in-the-woods.jpg" alt="The cabin in the woods. Classic Western Michigan setting." title="Six people walking over a pine needle-covered path to a cabin. Tall trees block out the sun."></p><p>The film opens with everyone seated around a fire pit as Peggy reads everyone’s horoscopes. Astrologists contend that when the planet <a href="https://www.thecut.com/article/mercury-retrograde-march-2025-what-to-expect.html">Mercury is in retrograde</a> (appearing to travel backward), communication suffers, and miscommunication is the theme of the film. The film takes its time with this opening scene, slowly panning around the firepit as Peggy reads. Inevitably, parts of each horoscope miss the mark, and some hit too close to home. Some will feel very relevant as the weekend progresses. This is a continous tracking shot and it’s really impressive.</p><p>The characters are sharply-drawn and well-acted. Peggy is eager to please, but you sense trouble under the surface. Wyatt isn’t a bad person but he’s young and seems unaware that someone <em>could</em> be concealing things. Isabelle, originally from France and played by a French actress, is that curious mix of fun, intelligent, lofty, and outright rude that you sometimes meet. Richard is self-involved to the point of parody. Golda is the earth mother who seems to be the most together. Jack, the Libra, takes it all in stride. Golda and Jack appear to be in their early forties; the others feel a little younger. Still, these are all people who were born in the 1980s or maybe the early 1990s.</p><p>In the morning, the couples all split up. The menfolk head off to play disc golf while the women, after doing yoga together in the woods, walk into town to visit the farmer’s market and then get coffee. This is all good character work. Let’s start with the men. Richard, with his headband and beard trimmed <em>just so</em>, is a veteran player and immediately starts trashing the quality of the course. Jack, who has played before and doesn’t take things nearly so seriously, starts fucking with him. Wyatt has never played before but seems happy to be outside. When Richard starts lecturing him about how to play he takes it in good grace. A later scene where they search for a missing disc rings true to anyone who’s played. Richard’s probably too proud to stick a Tile on the underside of his disc and ruin the aerodynamics.</p><p><img src="/2025/04/16/Mercury-in-Retrograde/three-men-on-a-golf-course.jpg" alt="Wyatt, Jack, and Richard on the golf course. Richard needs to take it down a few notches." title="Three men standing outside preparing to play disc golf. One's taking it much more seriously than the others."></p><p>Back at the cabin, you sense a connection developing between Golda and Peggy. Yoga is Golda’s thing and she’s sharing and Peggy is responding to that. Isabelle participates but you can tell she thinks some of this stuff is total bullshit and she’s above that. Over coffee in Allegan, you start to sense distance between Golda and Isabelle and the reason for it. Isabelle probably bitched about Richard to Golda, Golda told Isabelle to dump his ass, and Isabelle knows she should but she wants to make it work for reasons that she probably can’t explain to anyone, least of all herself. Raise your hand if you’ve never given unwelcome advice. Being “correct” makes it worse.</p><p>The couples unite in the afternoon to go swimming in Lake Michigan, though most of them stay on the beach. You sense that it’s warm enough that people are in shirtsleeves, but that water’s still a tad cold. The <a href="https://www.fennvalley.com">Fenn Valley Vineyard</a> would have been another good choice for a couples activity. 10-minute drive from the cabin, great wine tastings. For years, I gave the Lakeshore Demi-Sec as a wedding gift.</p><p>In the evening the couples divide again. I find this an odd dynamic personally, but it feels natural given the characters. The men have a boys’ book club; they sit around, drinking scotch and smoking cigars, discussing Dashiell Hammett’s  <a href="https://en.wikipedia.org/wiki/The_Glass_Key"><em>The Glass Key</em></a>. Personally, I’m kinda appalled, but I’ve probably got a skeleton that pompous in my closet, so I’ll move on. This goes the way you expect–by the end, everyone’s had too much to drink and is barely making any sense. Jack is falling asleep. Richard is insisting on his point long after everyone else lost interest.</p><p>Meanwhile, the women have hit a bar that looks like every townie bar in that part of the state. They shot this scene in Chicago, but it reminds me of the Sand Bar Saloon in Saugatuck. We established earlier that Peggy doesn’t drink because her father was an alcoholic. Isabelle starts getting pushy as the night goes on, and eventually guilts Peggy into a beer, after which, giving in to her annoyance with Richard, she goes off to hit on a local. This man is the most Michigan man this side of Paul Walter Hauser I can imagine. He went to Ferris State to learn welding and pulls for Sparty on Saturdays.</p><p><img src="/2025/04/16/Mercury-in-Retrograde/three-women.jpg" alt="Golda, Peggy, and Isabelle confront their fears." title="Headshots of three women in dark lighting."></p><p>Something I noticed when writing this post is that you rarely see any of the women together during these bar scenes. The camera focuses either on who’s speaking or someone’s reaction to it, and it lingers. This is a good choice–all three actors are doing an excellent job and all three characters have some emotional baggage that they’re dealing with. Isabelle’s we know about: her relationship with Richard has failed and she’s finally admitting that to herself. Whether she feels like telling him is another matter. A later interaction between the two establishes that Isabelle being a mean drunk isn’t new behavior.</p><p>Back at the table Golda apologizes for Isabelle’s behavior, at which point Peggy opens up to her. This is fast, but not implausiblely so–you could feel the trust developing between the two, and sometimes you need to confess to someone you don’t know. There can be relief in exchanging vulnerabilities. Peggy has a long, bad history of substance and sexual abuse that she hasn’t been able to discuss with Wyatt. Golda, for her part, shares that she and Jack are trying to get pregnant, but she had an abortion (with Jack’s knowledge) a decade ago and is worried that she can’t have children but hasn’t confided in Jack yet. Meanwhile, Isabelle is making out with the townie but they don’t get to second base before it’s time to go back.</p><p><img src="/2025/04/16/Mercury-in-Retrograde/the-morning-after.jpg" alt="Rise and shine, campers!" title="Four men and three women gather around a room to make cinnamon rolls"></p><p>In the morning Jack’s dad (Jack senior) swings by to make cinnamon rolls as everyone nurses a hangover. There’s a familiar, weary politeness. Saturday night, what everyone can remember of it, anyway, was fucked up but we’re too tired to argue about it. The film closes with Peggy narrating the fate of our characters after the weekend. The friend group gradually breaks up. Isabelle breaks up with Richard and returns to France. Wyatt dumps Peggy. Golda and Jack <em>do</em> get pregnant, and grow closer to Peggy, who babysits for them. This feels a little perfunctory, and maybe unnecessary, but Peggy’s telling the story and this is how the story of the weekend ends.</p><h2><span id="some-thoughts">Some thoughts</span></h2><p>I was surprised at how much I enjoyed myself. This was a blind watch in a genre that I usually avoid: all I knew going in was the location and a rough outline of the plot. I like it when a movie feels grounded in a location. The grounding doesn’t have to be that strong; <em><a href="/2024/07/04/Foes/" title="Foes">Foes</a></em> did it very simply while <em><a href="/2023/11/22/Blood-Hook/" title="Blood Hook">Blood Hook</a></em> never quite managed it, despite the longer running time (and giant fish).</p><p>It’s a little disconcerting to watch a movie and see yourself, or parts of yourself, on screen. I’ve been Jack–slowly drinking and nodding off during a discussion that no longer interests me. I’ve been Wyatt, emotionally obtuse at the wrong moment (and also wrongly attired for disc golf). To my real chagrin, I’ve been Isabelle, unable to comprehend that why someone chooses not to drink isn’t my business. I’ve been Peggy; feeling my way into a group of friends who are not (yet) my friends.</p><p>The acting in this movie was a revelation. All six leads deliver rounded, believable performances. It doesn’t feel fair to pick a standout, but I do want to mention Najarra Townsend and Alana Arenas. Their scenes together at the bar are the heart of the movie and they both do incredible work. Liz and I went and hunted up some of the horror shorts that Townsend’s been in like <em><a href="https://letterboxd.com/film/feeding-time/">Feeding Time</a></em> (fun) and <a href><em>Play Violet for Me</em></a> (less so) and she ought to break out given the right role. We’re also planning to give some of director Michael Glover Smith’s other movies a go, our genre preferences notwithstanding. This was fresh and exciting and we were never bored.</p>]]></content>
    
    
    <summary type="html">Review of the 2017 movie Mercury in Retrograde.</summary>
    
    
    
    <category term="Movies" scheme="https://blog.goodbyeplease.com/categories/Movies/"/>
    
    
    <category term="Mercury in Retrograde" scheme="https://blog.goodbyeplease.com/tags/Mercury-in-Retrograde/"/>
    
    <category term="Najarra Townsend" scheme="https://blog.goodbyeplease.com/tags/Najarra-Townsend/"/>
    
    <category term="Roxane Mesquida" scheme="https://blog.goodbyeplease.com/tags/Roxane-Mesquida/"/>
    
    <category term="Shane Simmons" scheme="https://blog.goodbyeplease.com/tags/Shane-Simmons/"/>
    
    <category term="Jack C. Newell" scheme="https://blog.goodbyeplease.com/tags/Jack-C-Newell/"/>
    
    <category term="Alana Arenas" scheme="https://blog.goodbyeplease.com/tags/Alana-Arenas/"/>
    
    <category term="Kevin Wehby" scheme="https://blog.goodbyeplease.com/tags/Kevin-Wehby/"/>
    
    <category term="Michael Glover Smith" scheme="https://blog.goodbyeplease.com/tags/Michael-Glover-Smith/"/>
    
  </entry>
  
  <entry>
    <title>Silver Bears</title>
    <link href="https://blog.goodbyeplease.com/2025/03/19/Silver-Bears/"/>
    <id>https://blog.goodbyeplease.com/2025/03/19/Silver-Bears/</id>
    <published>2025-03-20T00:14:27.000Z</published>
    <updated>2025-03-20T02:08:54.277Z</updated>
    
    <content type="html"><![CDATA[<p>I keep a list on Letterboxd of what I call my “<a href="https://letterboxd.com/mackensen42/list/saturday-morning-crime-and-heist-movies/">Saturday morning</a>” movies, so named because I’m a much earlier riser than my wife on the weekends. My criteria for these movies is somewhat loose, but in general they’re crime or heist movies shot on location in Europe in the 1970s. The vibe is this: some recognizable actors went somewhere nice and made a movie.</p><p>The criteria are flexible. <a href="https://letterboxd.com/film/harry-in-your-pocket/"><em>Harry in Your Pocket</em></a> was shot in the Pacific Northwest; <a href="https://letterboxd.com/film/gold/"><em>Gold</em></a> in apartheid South Africa. <em><a href="/2024/07/14/Target-Harry/" title="Target: Harry">Target: Harry</a></em> was made (for American television, no less) in 1969, and then re-edited with superfluous nudity in 1979. <em>The Day of the Jackal</em> probably shouldn’t be on the list at al–it’s far too well made–but it does a fabulous job of evoking a place and time.</p><p>That brings me to <em>Silver Bears</em>, a little-seen Michael Caine vehicle from 1978, which meets every criteria perfectly. Our actors are in Las Vegas, Switzerland (mainly Lugano), Italy, the United Kingdom, and Morocco (standing in for Iran). Our actors include Caine, Louis Jourdan, Cybill Shepherd, Stéphane Audran, David Warner, Tom Smothers, Jay Leno (<em>before</em> he made it big), Joss Ackland, and Charles Gray.</p><p>We begin in Las Vegas with Caine as “Doc” Fletcher. He’s the financial advisor to mobster Joe Fiore (Martin Balsam), and Doc has convinced Joe that for $3 million he can buy a Swiss bank and then use the bank for money laundering. Doc heads off to Switzerland to meet with Prince Gianfranco di Siracusa (Louis Jourdan), a dispossessed Italian prince. With Doc are Joe’s wayward son Albert (Jay Leno) and Marvin (Tony Mascia), a button-man with a sideline in counterfeiting.</p><p><img src="/2025/03/19/Silver-Bears/four-bankers.jpg" alt="Jay Leno, Tony Mascia, Michael Caine, and Louis Jourdan arguing in Lugano." title="Four men arguing"></p><p>The “bank” turns out to be some offices above a pizza restaurant in Lugano, with about a thousand dollars of assets. The “prince” talks his way out of getting whacked by Marvin and Doc, and manages to convince Doc to accompany him to Iran for inspect an exciting new opportunity. This new opportunity turns out to be a newly-discovered silver mine, run by the brother and sister team of Agha and Shireen Firdausi (David Warner, never looking more disreputable, and Stéphane Audran). They just need capital to exploit their find. Doc borrows $5 million, then loans it right back, with an option to take control of the mine if they default.<sup class="footnote-ref"><a href="#fn1" id="fnref1">[1]</a></sup></p><p><img src="/2025/03/19/Silver-Bears/firdausis.jpg" alt="Louis Jourdan, Stéphane Audran, and David Warner are totally not on the make." title="Two men and a woman"></p><p>Back in Switzerland, Marvin and Albert, having gotten stir-crazy, used Marvin’s counterfeiting expertise to bankroll a few good nights at the local casino. Doc returns to Switzerland to find Marvin and Albert moved into a nice villa overlooking the lake, and the bank on firmer footing. It’s at this point that the plot becomes even more complicated, and the bank faces threats from two directions.</p><p>In London, obsessive silver magnate Charles Cook (Charles Gray) is disturbed by the appearance of the Firdausis’ silver on the market. In San Francisco, an American bank headed by Henry Foreman (Joss Ackland) is looking to establish a presence in Europe. Foremen sends analyst Donald Luckman (Tom Smothers) to Europe to evaluate this new upstart bank in Switzerland. Luckman, unwisely, brings his wife Debbie (Cybill Shepherd).</p><p><img src="/2025/03/19/Silver-Bears/conspiracy.jpg" alt="Joss Ackland, Tom Smothers, Charles Gray, and Jeremy Clyde hatch a conspiracy." title="Four men drink scotch and plot"></p><p>What follows is an elaborate game of musical chairs. Cook wants Foreman to act as a straw purchaser of the bank. Once he owns the bank, he can call in the loan and close the mine. Luckman writes the prospectus but–crucially–disguises the silver mine asset as “oil storage tanks” to keep things quiet. Doc enjoys the independence that comes from running a bank and wants to hang on to it. Back in Las Vegas, Joe Fiore is inclined to take the $60 million Cook is offering and walk away rich. Meanwhile, Doc is also carrying on an affair with Debbie who tells Doc far more than either Luckman or Foreman would like.</p><p><img src="/2025/03/19/Silver-Bears/cybill.jpg" alt="Michael Caine and Cybill Shepherd at the villa. She's just threatened him and will sleep with him in about two minutes. Her primary character beat is &quot;ditz&quot;." title="A man and a woman flirt"></p><p>Matters come to a head when Doc discovers that the “silver mine” is an elaborate sham. The Firdausis are smugglers; the silver is from India and there is no mine to foreclose on. He goes through with selling the bank to Foreman but cuts a deal with Cook; Foreman winds up selling the bank back to Doc. Joe gets paid off, the prince marries Shireen, Agha turns out to be a debauched actor, and Donald Luckman is thrown in jail for three years for falsifying details in the prospectus.</p><p><em>Silver Bears</em> remains a little obscure (under 1000 watched on Letterboxd). I don’t believe it had a DVD/Blu-ray release until Studio Canal <a href="https://www.studiocanal.com/title/silver-bears-1978/">put one out</a> in 2020. The video and audio quality is excellent. The plot is ridiculous and both over- and under-explained, but that’s not why you watch a movie like this. You’re watching a bunch of familiar actors clowning around somewhere fun. To see what the Italian-speaking part of Switzerland looked like in the late 1970s. The studio work was obviously done in England; the presence of old hands Shane Rimmer (various James Bond movies and <em>Star Wars</em>), Bruce Boa (General Rieekan in <em>The Empire Strikes Back</em>), and legendary bit player Reg Thomason evoke an age.</p><p><img src="/2025/03/19/Silver-Bears/thomason.jpg" alt="Reg Thomason (right, with the mustache) enjoying a party as Caine and Balsam walk by" title="An older gentleman with a neat mustache at a party"></p><p>Movies like this are fun when you’re of the mind to relax. They don’t push you. On successive rewatches you enjoy the cinematography, and notice little details, like the prince correcting Agha (an actor) when he misstates part of the conspiracy. You admire the desperate grandure of Jourdan’s prince, who still knows everybody but is so destitue that he’s burning old chairs to heat his empty palace.</p><hr class="footnotes-sep"><section class="footnotes"><ol class="footnotes-list"><li id="fn1" class="footnote-item"><p>No, this doesn’t quite make sense, and no, it doesn’t matter. <a href="#fnref1" class="footnote-backref">↩︎</a></p></li></ol></section>]]></content>
    
    
    <summary type="html">Review of the 1978 heist film Silver Bears</summary>
    
    
    
    <category term="Movies" scheme="https://blog.goodbyeplease.com/categories/Movies/"/>
    
    
    <category term="Louis Jourdan" scheme="https://blog.goodbyeplease.com/tags/Louis-Jourdan/"/>
    
    <category term="Silver Bears" scheme="https://blog.goodbyeplease.com/tags/Silver-Bears/"/>
    
    <category term="Michael Caine" scheme="https://blog.goodbyeplease.com/tags/Michael-Caine/"/>
    
    <category term="Jay Leno" scheme="https://blog.goodbyeplease.com/tags/Jay-Leno/"/>
    
  </entry>
  
  <entry>
    <title>Mileage problems on the Long Island Rail Road</title>
    <link href="https://blog.goodbyeplease.com/2024/12/06/Mileage-problems-on-the-Long-Island-Rail-Road/"/>
    <id>https://blog.goodbyeplease.com/2024/12/06/Mileage-problems-on-the-Long-Island-Rail-Road/</id>
    <published>2024-12-06T19:42:44.000Z</published>
    <updated>2025-02-20T03:07:34.792Z</updated>
    
    <content type="html"><![CDATA[<p>Back in July/August 2022 I made a circuit of New York and New England (<a href="https://galleries.goodbyeplease.com/album/Albums-2022-Northeast.html">photo gallery</a>). I had a memorable encounter with a <a href="/2023/11/17/A-warehouse-in-Albany/" title="A warehouse in Albany">a warehouse in Albany</a> on the <em>Ethan Allen Express</em>, drove a boat on Lake Champlain, took my first trip on the Long Island Rail Road, and finally rode the <a href="https://en.wikipedia.org/wiki/Mattapan_Line">Mattapan Line</a>. About a thousand miles by rail: 913 on Amtrak, 66 on the Long Island Rail Road, and uncounted on the New York and Boston subways. Calculating that number led me on a wild side quest similar to the problem I had <a href="/2024/08/26/Measuring-the-Raritan-Valley-Line/" title="Measuring the Raritan Valley Line">with the Raritan Valley Line</a>.</p><p>Calculating mileage for commuter railroads can be tricky because they often don’t publish that information in public schedules. Amtrak did until they stopped putting out printed timetables, and those numbers don’t change often. The 2022 version of the MTA website <em>did</em> publish that information for each station. Here’s <a href="https://web.archive.org/web/20221001204837/http://lirr42.mta.info/stationInfo.php?id=60">Huntington</a>, for example. 34.7 miles from Penn Station. If I travel between two intermediate points I can just diff the numbers and I’m good to go, right?</p><p>I don’t remember exactly when I realized there was a problem. It might have been when I was looking at <a href="https://web.archive.org/web/20220521045251/http://lirr42.mta.info/stationInfo.php?id=9">Woodside</a>, which the MTA website placed at “3.1 miles” from Penn Station. That felt wrong given that Manhattan itself is about two miles wide, and sure enough, some quick playing with the measurement tool on Google Maps showed that 3.1 miles from Woodside didn’t even get you to the East River.</p><p><img src="/2024/12/06/Mileage-problems-on-the-Long-Island-Rail-Road/woodside-to-east-river.jpg" alt="The answer is not 3.1 miles" title="Map of Long Island showing the distance from Woodside to the East River is 3.2 miles. Penn is even further west."></p><p>Before delving into what the right answer is and how I got there, a little sidebar about the topology of the Long Island Rail Road, which is somewhat complicated. There are four western termini: Penn Station and Grand Central Madison in Manhattan, Long Island City in Queens, and Atlantic Terminal in Brooklyn. There are two main lines proceeding east from Long Island City: the <a href="https://en.wikipedia.org/wiki/Main_Line_(Long_Island_Rail_Road)">Main Line</a>, terminating in Greenport, and the <a href="https://en.wikipedia.org/wiki/Montauk_Branch">Montauk branch</a>, terminating in Montauk. The connections to Manhattan diverge from the Main Line prior to Long Island City. Physically, both the Main Line and the Montauk branch run to Jamaica, but the latter does it via a different route that has been freight-only since 2012 and is therefore not shown on public maps.</p><p><img src="/2024/12/06/Mileage-problems-on-the-Long-Island-Rail-Road/LIRR_schematic.svg" alt="Schematic map of the Long Island Rail Road. Original map by User:NE2 with later modifications by users listed below, Public domain, via Wikimedia Commons" title="Schematic map of the Long Island Rail Road"></p><p>A further complexity is the <a href="https://en.wikipedia.org/wiki/Central_Branch_(Long_Island_Rail_Road)">Central branch</a> between Bethpage and Babylon. If you’re reckoning physical distance between Long Island City and Montauk, you have to account for the following variables:</p><ol><li>Are we using the Main Line between Woodside and Jamaica, or the Lower Montauk branch between Long Island City and Jamaica?</li><li>Are we using the Montauk branch between Jamaica and Babylon, or the Main Line via Bethpage?</li></ol><p>Meanwhile, the MTA site simply said that <a href="https://web.archive.org/web/20220527114046/http://lirr42.mta.info/stationInfo.php?id=138">Montauk was 115.8 miles</a> from Penn Station. I’m pretty sure that’s not true, but I wasn’t sure how wrong it even was.</p><h2><span id="measurements">Measurements</span></h2><p>There are good sources for these distances. I looked in two places: employee timetables for the Long Island Railroad (<a href="http://www.trainsarefun.com/lirr/lirrhistoricaldata/LIRRTimeTable4_5-14-2012.pdf">here’s one from 2012</a>), and Official Guides of the Railways from the period when the LIRR was owned by the Pennsylvania Railroad.</p><p><img src="/2024/12/06/Mileage-problems-on-the-Long-Island-Rail-Road/194503-310.jpg" alt="They haven't moved Penn since 1945" title="1945 timetable showing the distance from New York Penn to Jamaica"></p><p>From these we some very useful building blocks:</p><ol><li>It’s 9.3 miles from Atlantic Terminal to Jamaica.</li><li>It’s 9.3 miles from Long Island City to Jamaica via the Main Line.</li><li>It’s 9.0 miles from Long Island City to Jamaica via the Lower Montauk branch.</li><li>It’s 11.3 miles from Penn Station to Jamaica via the Main Line and East River Tunnels.</li></ol><p>It became clear to me as I examined the website that it was using the figures from the internal employee timetables but misrepresenting them as the distance to Penn, where they were actually the distance to Long Island City. They were wrong by either 2 miles or 2.3 miles, depending on whether the mileage of the physical branch the station was on was reckoned via the Main Line or the Lower Montauk branch (an MTA employee confirmed as much to me via a support ticket I opened).</p><p>Given that, I was able to accurately compute the distances I traveled:</p><ul><li>31.6 miles from Woodside to Huntington</li><li>25.4 miles from Huntington to Jamaica</li><li>9.3 miles from Jamaica to Atlantic Terminal</li></ul><p>As an aside, physical distance isn’t really relevant to traveling public. You need to know where a station is and when the trains are. The revised website (<a href="https://new.mta.info/stations/huntington">example</a>) doesn’t include the faulty distance information at all, probably for the best. How the distances are calculated is a reminder that the Long Island Rail Road was built in the 19th century, and that the tunnels under the East River were a later innovation.</p>]]></content>
    
    
    <summary type="html">Another abstruse exercise in calculating railroad mileage</summary>
    
    
    
    <category term="Travel" scheme="https://blog.goodbyeplease.com/categories/Travel/"/>
    
    
    <category term="Long Island Rail Road" scheme="https://blog.goodbyeplease.com/tags/Long-Island-Rail-Road/"/>
    
  </entry>
  
  <entry>
    <title>Pushing to GitHub over 443</title>
    <link href="https://blog.goodbyeplease.com/2024/12/06/Pushing-to-GitHub-over-443/"/>
    <id>https://blog.goodbyeplease.com/2024/12/06/Pushing-to-GitHub-over-443/</id>
    <published>2024-12-06T18:33:39.000Z</published>
    <updated>2025-02-20T03:07:34.804Z</updated>
    
    <content type="html"><![CDATA[<p>I’m working from New York Penn Station today before heading out on the <em>Lake Shore Limited</em> to Michigan. In general this is a positive and productive work environment. My only challenge is that Amtrak WiFi blocks port 22 outbound, so I can’t push my work back to my CI environment on GitHub?</p><p>(What am I working on? A <a href="https://github.com/LafColITS/moodle-local_ws_enrol_manual">Moodle local plugin</a> that exposes the add_instance method of the manual enrollment plugin.)</p><p>Happily, GitHub <a href="https://docs.github.com/en/authentication/troubleshooting-ssh/using-ssh-over-the-https-port">has anticipated</a> this scenario and I don’t have to do anything tricky. I added the following to my local <code>~/.ssh/config</code>:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">Host github.com</span><br><span class="line">    Hostname ssh.github.com</span><br><span class="line">    Port 443</span><br><span class="line">    User git</span><br></pre></td></tr></table></figure><p>That’s it! All my existing remotes work the same as before, and I’m in business.</p>]]></content>
    
    
    <summary type="html">How to push to GitHub over SSH if port 22 is blocked.</summary>
    
    
    
    <category term="Web Development" scheme="https://blog.goodbyeplease.com/categories/Web-Development/"/>
    
    
    <category term="GitHub" scheme="https://blog.goodbyeplease.com/tags/GitHub/"/>
    
  </entry>
  
  <entry>
    <title>Packaging a Lambda with Nodejs 20 and AWS SDK for JavaScript v2</title>
    <link href="https://blog.goodbyeplease.com/2024/11/19/Packaging-a-Lambda-with-Nodejs-20-and-AWS-SDK-for-JavaScript-v2/"/>
    <id>https://blog.goodbyeplease.com/2024/11/19/Packaging-a-Lambda-with-Nodejs-20-and-AWS-SDK-for-JavaScript-v2/</id>
    <published>2024-11-19T23:26:12.000Z</published>
    <updated>2025-02-20T03:07:34.801Z</updated>
    
    <content type="html"><![CDATA[<p>Following <a href="/2024/11/13/Devenv-python-and-packaging-Lambdas/" title="Devenv, python, and packaging Lambdas">last week&#39;s fun</a> with packaging Lambdas that use Python, here’s a little puzzle with Node.js.</p><p>I have an outdated project that uses a Lambda originally built on v2 of the <a href="https://docs.aws.amazon.com/sdk-for-javascript/v2/developer-guide/aws-jsdk-reference.html">AWS SDK for JavaScript</a> and which ran on the Node.js 12.x runtime. The minimum supported runtime now is Node.js 18.x, and starting with that version <a href="https://stackoverflow.com/questions/74631684/lambda-function-cant-load-aws-sdk-after-switching-to-18-x">v3 is shipped instead of v2</a>. I spent some time digging into migrating the functionality from v2 to v3, determined that the change wasn’t trivial, and decided to buy myself some time by shipping v2 of the SDK with my Lambda function. I didn’t find any guides on how to do that within an <a href="https://docs.aws.amazon.com/lambda/latest/dg/lambda-cdk-tutorial.html">AWS CDK project</a>, hence this post.</p><p>The root of my project isn’t the Lambda function, but the project’s entire infrastructure, of which the Lambda function and its code is but a small piece. This is the typical structure:</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">bin/</span><br><span class="line">lib/</span><br><span class="line">lib/folder-containing-lambda-function/</span><br><span class="line">lib/folder-containing-lambda-function/index.js</span><br><span class="line">test/</span><br><span class="line">package.json</span><br><span class="line">yarn.lock</span><br></pre></td></tr></table></figure><p>CDK will zip up the contents of a specified directory and handle deploying it:</p><figure class="highlight typescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> yourFunction = <span class="keyword">new</span> lambda.<span class="title class_">Function</span>(<span class="variable language_">this</span>, <span class="string">&#x27;LambdaFunction&#x27;</span>, &#123;</span><br><span class="line">  <span class="attr">code</span>: <span class="keyword">new</span> lambda.<span class="title class_">AssetCode</span>(<span class="string">&#x27;./lib/folder-containing-lambda-function&#x27;</span>),</span><br><span class="line">  <span class="attr">handler</span>: <span class="string">&#x27;index.handler&#x27;</span>,</span><br><span class="line">  <span class="attr">runtime</span>: lambda.<span class="property">Runtime</span>.<span class="property">NODEJS_20_X</span>,</span><br><span class="line">  <span class="attr">role</span>: <span class="keyword">new</span> iam.<span class="title class_">Role</span>(<span class="variable language_">this</span>, <span class="string">&#x27;LambdaRole&#x27;</span>, &#123;</span><br><span class="line">    <span class="attr">assumedBy</span>: <span class="keyword">new</span> iam.<span class="title class_">ServicePrincipal</span>(<span class="string">&#x27;lambda.amazonaws.com&#x27;</span>),</span><br><span class="line">      <span class="attr">managedPolicies</span>: [</span><br><span class="line">      iam.<span class="property">ManagedPolicy</span>.<span class="title function_">fromAwsManagedPolicyName</span>(<span class="string">&quot;service-role/AWSLambdaBasicExecutionRole&quot;</span>),</span><br><span class="line">    ],</span><br><span class="line">  &#125;),</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><p>It feels ugly, but I solved this by creating a stub <code>package.json</code> inside the <code>folder-containing-lambda-function</code> directory and running <code>yarn add aws-sdk@2</code> from there (thus avoiding the problem of it trying to use the <code>package.json</code> from the parent directory). Here’s the package.json:</p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="punctuation">&#123;</span></span><br><span class="line">  <span class="attr">&quot;dependencies&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">    <span class="attr">&quot;aws-sdk&quot;</span><span class="punctuation">:</span> <span class="string">&quot;2&quot;</span></span><br><span class="line">  <span class="punctuation">&#125;</span></span><br><span class="line"><span class="punctuation">&#125;</span></span><br></pre></td></tr></table></figure><p>This creates a second <code>node_modules</code> within <code>lib/folder-containing-lambda-function</code>. Unlike the one at root, I actually want to version this for deployment purposes, so I modify the main <code>.gitignore</code> to only exclude the top-level <code>node_modules</code>:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">/node_modules/</span><br></pre></td></tr></table></figure><p>Through this entire process I’m not altering the actual code in my Lambda function at all. The SDK (v2) will be unzipped at the root and available in the expected place:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> <span class="variable constant_">AWS</span> = <span class="built_in">require</span>(<span class="string">&#x27;aws-sdk&#x27;</span>)</span><br></pre></td></tr></table></figure><p>Under this approach <code>node_modules</code> is 110 MB uncompressed and 15 MB compressed. I want to emphasize that this isn’t a great solution, but I was in a rush and needed to restore functionality, and it worked like a charm. For a proper resolution, I’m considering a few options, including building a Lambda layer with v2 SDK, or refactoring the whole thing using the boto3 library in Python.</p>]]></content>
    
    
    <summary type="html">Including the old AWS SDK in a Lambda function</summary>
    
    
    
    <category term="Web Development" scheme="https://blog.goodbyeplease.com/categories/Web-Development/"/>
    
    
    <category term="AWS" scheme="https://blog.goodbyeplease.com/tags/AWS/"/>
    
    <category term="CDK" scheme="https://blog.goodbyeplease.com/tags/CDK/"/>
    
    <category term="Lambda" scheme="https://blog.goodbyeplease.com/tags/Lambda/"/>
    
    <category term="Nodejs" scheme="https://blog.goodbyeplease.com/tags/Nodejs/"/>
    
  </entry>
  
  <entry>
    <title>Devenv, python, and packaging Lambdas</title>
    <link href="https://blog.goodbyeplease.com/2024/11/13/Devenv-python-and-packaging-Lambdas/"/>
    <id>https://blog.goodbyeplease.com/2024/11/13/Devenv-python-and-packaging-Lambdas/</id>
    <published>2024-11-14T02:49:11.000Z</published>
    <updated>2025-02-20T03:07:34.770Z</updated>
    
    <content type="html"><![CDATA[<p>One of the first things I did with Nix flakes and then <a href="https://devenv.sh/">Devenv.sh</a> was standardize the Node environment for my AWS CDK deployments. A related issue that I let slide at the time was Python dependencies for when a project has Lambda functions with Python runtimes.</p><p>My comfort level with Python isn’t very high, and the variety of Python dependency tooling (<a href="https://pypi.org/project/pip/">pip</a>, <a href="https://python-poetry.org/">Poetry</a>, <a href="https://github.com/pyenv/pyenv">pyenv</a>, <a href="https://docs.python.org/3/library/venv.html">venv</a>) leaves me bewildered on a good day. The Lambda functions that I ship aren’t complicated and don’t need many dependencies, although they need to be compatible with the given runtime. A further complexity specific to Lambda functions is that AWS expects the function and its dependencies to be <a href="https://docs.aws.amazon.com/lambda/latest/dg/python-package.html">zipped up together</a>.</p><p>My preferred way to handle that pre-devenv was to use pip with the <code>-t</code> flag, which lets me choose the installation directory. This will install the requested package and its dependencies in that directory, which is perfect for my packaging needs. Devenv has excellent <a href="https://devenv.sh/supported-languages/python/">support for Python</a>, and getting Python 3.12 is easy:</p><p>devenv.nix:</p><figure class="highlight nix"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">l<span class="attr">anguages.python</span> <span class="operator">=</span> &#123;</span><br><span class="line">  <span class="attr">version</span> <span class="operator">=</span> <span class="string">&quot;3.12&quot;</span>;</span><br><span class="line">  <span class="attr">enable</span> <span class="operator">=</span> <span class="literal">true</span>;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>devenv.yaml:</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">inputs:</span></span><br><span class="line">  <span class="attr">nixpkgs-python:</span></span><br><span class="line">    <span class="attr">url:</span> <span class="string">github:cachix/nixpkgs-python</span></span><br><span class="line">    <span class="attr">inputs:</span></span><br><span class="line">      <span class="attr">nixpkgs:</span></span><br><span class="line">        <span class="attr">follows:</span> <span class="string">nixpkgs</span></span><br></pre></td></tr></table></figure><p>Trouble is, that configuration leave me with working python (good) but no pip (not so good). After some unhelpful googling I started playing around with Poetry, but it felt like overkill for what I was looking to accomplish. Ultimately I decided to try <code>venv</code>:</p><figure class="highlight nix"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">l<span class="attr">anguages.python</span> <span class="operator">=</span> &#123;</span><br><span class="line">  <span class="attr">version</span> <span class="operator">=</span> <span class="string">&quot;3.12&quot;</span>;</span><br><span class="line">  <span class="attr">enable</span> <span class="operator">=</span> <span class="literal">true</span>;</span><br><span class="line">  <span class="attr">venv.enable</span> <span class="operator">=</span> <span class="literal">true</span>;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>Without venv, this is what my python environment for this project looked like:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">(nix:devenv-shell-env) (devenv) $ <span class="built_in">which</span> python</span><br><span class="line">/nix/store/6z1qpvp2pyafhkvzsgfh8ivsy8p27c7m-python3-3.12.7-env/bin/python</span><br><span class="line">(nix:devenv-shell-env) (devenv) $ python --version</span><br><span class="line">Python 3.12.7</span><br><span class="line">(nix:devenv-shell-env) (devenv) $ <span class="built_in">which</span> pip</span><br></pre></td></tr></table></figure><p>With venv, it looks like this:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">(nix:devenv-shell-env) (devenv) $ <span class="built_in">which</span> python</span><br><span class="line">/path/to/project/.devenv/state/venv/bin/python</span><br><span class="line">(nix:devenv-shell-env) (devenv) $ python --version</span><br><span class="line">Python 3.12.7</span><br><span class="line">(nix:devenv-shell-env) (devenv) $ <span class="built_in">which</span> pip</span><br><span class="line">/path/to/project/.devenv/state/venv/bin/pip</span><br><span class="line">(nix:devenv-shell-env) (devenv) $ pip --version</span><br><span class="line">pip 24.3.1 from /path/to/project/.devenv/state/venv/lib/python3.12/site-packages/pip (python 3.12)</span><br></pre></td></tr></table></figure><p>The good news is here that I have pip now, so the immediate problem is solved. I did find myself a little curious about what’s happening in the root <code>.devenv</code> directory:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">-rwxr-xr-x 1 user group  271 Nov 12 22:35 pip</span><br><span class="line">-rwxr-xr-x 1 user group  271 Nov 12 22:35 pip3</span><br><span class="line">-rwxr-xr-x 1 user group  271 Nov 12 22:35 pip3.12</span><br><span class="line">lrwxr-xr-x 1 user group   10 Nov 12 22:35 python -&gt; python3.12</span><br><span class="line">lrwxr-xr-x 1 user group   10 Nov 12 22:35 python3 -&gt; python3.12</span><br><span class="line">lrwxr-xr-x 1 user group   77 Nov 12 22:35 python3.12 -&gt; /nix/store/6z1qpvp2pyafhkvzsgfh8ivsy8p27c7m-python3-3.12.7-env/bin/python3.12</span><br></pre></td></tr></table></figure><p>That’s about what I expected. A symlink back to the same immutable python binary, and the usual pip module (module?) in the project directory. This gets around problems I’d had earlier with enabling pip, which tried to put it in the immutable /nix/ store, which didn’t work. This may have been the obvious solution for someone experienced with Python, but I’m not.</p>]]></content>
    
    
    <summary type="html">Packaging Lambda functions in a Devenv.sh environment</summary>
    
    
    
    <category term="Web Development" scheme="https://blog.goodbyeplease.com/categories/Web-Development/"/>
    
    
    <category term="AWS" scheme="https://blog.goodbyeplease.com/tags/AWS/"/>
    
    <category term="Nix" scheme="https://blog.goodbyeplease.com/tags/Nix/"/>
    
    <category term="Python" scheme="https://blog.goodbyeplease.com/tags/Python/"/>
    
  </entry>
  
  <entry>
    <title>A visit to the Bridgeview</title>
    <link href="https://blog.goodbyeplease.com/2024/11/10/A-visit-to-the-Bridgeview/"/>
    <id>https://blog.goodbyeplease.com/2024/11/10/A-visit-to-the-Bridgeview/</id>
    <published>2024-11-11T00:44:58.000Z</published>
    <updated>2025-02-20T03:07:34.750Z</updated>
    
    <content type="html"><![CDATA[<p>The <a href="http://bridgeviewbnb.com/">Bridgeview Bed and Breakfast</a> in Marysville, Pennsylvania, is a unique institution. It’s a B&amp;B designed specifically to cater to railfans and their trailing spouses. It’s located on the Susquehanna River, about 700 feet down river from the <a href="https://en.wikipedia.org/wiki/Rockville_Bridge">Rockville Bridge</a>, in the very heart of Norfolk Southern’s operations in Pennsylvania. Norfolk Southern freight trains pass frequently, and once a day in each direction Amtrak’s silvery <em>Pennsylvanian</em> cruises past. Just behind the B&amp;B is the Port Road Branch and Enola Yard. Across the river is the old Pennsylvania Railroad line to Buffalo.</p><p>Everything at the B&amp;B is organized around appreciating this location. There is WiFi, but no telephones nor televisions in the rooms. There’s a sitting room-cum-library facing the Susquehanna, packed with comfortable chairs and railroad books and magazines. There’s a display in that room, with a repeater outside, showing active movements in the vicinity. All the <a href="http://bridgeviewbnb.com/rooms.php">rooms</a> bear names (“Juniata”, “Lehigh”, “Lackawanna”) rich in railroading tradition. It’s quiet at night, if train horns don’t bother you. On that note, the Bridgeview is surely the only hotel whose <a href="http://bridgeviewbnb.com/rates.php">policies</a> state that “Under no circumstances should guests trespass on railroad property, including the embankment across Main Street from the B&amp;B.”</p><p>They advertise in <em>Trains</em> magazine, and we finally decided to try them out in June 2023. The operation itself is decidedly low-tech. The website itself is HTTP only, no HTTPS. You make a reservation by emailing or calling Keith, the proprietor. You mail a check for a deposit and pay the rest on-site. This all worked very smoothly but I’ll cop to some trepidation. I shouldn’t have felt any; Liz and I had a blast. The environment is incredibly chill. You sit on the big deck, watch the river, watch the trains go by. You can read a bit. There are plenty of things to do around Harrisburg. We found the <a href="https://www.theantiquemarketplaceoflemoyne.com/">Antique Marketplace of Lemoyne</a>, <a href="https://www.cupboardmaker.com/">Cupboard Maker Books</a>, and <a href="https://www.home-231.com/">Home 231</a>.</p><p>We meant to go back this year but the summer got away from us. I did finally upload all my pictures: <a href="https://galleries.goodbyeplease.com/album/Albums-2023-Harrisburg.html">https://galleries.goodbyeplease.com/album/Albums-2023-Harrisburg.html</a>. Spoiler: it’s mostly trains and rivers.</p><p><img src="/2024/11/10/A-visit-to-the-Bridgeview/View-from-the-porch.jpg" alt="View of the bridge from the porch." title="Stone masonry bridge crossing a river"></p>]]></content>
    
    
    <summary type="html">A visit to the Bridgeview B&amp;B outside Harrisburg, Pennsylvania.</summary>
    
    
    
    <category term="Trains" scheme="https://blog.goodbyeplease.com/categories/Trains/"/>
    
    <category term="Travel" scheme="https://blog.goodbyeplease.com/categories/Travel/"/>
    
    
    <category term="Norfolk Southern Railway" scheme="https://blog.goodbyeplease.com/tags/Norfolk-Southern-Railway/"/>
    
    <category term="Harrisburg" scheme="https://blog.goodbyeplease.com/tags/Harrisburg/"/>
    
  </entry>
  
  <entry>
    <title>Fifteen years on the Capitol Limited</title>
    <link href="https://blog.goodbyeplease.com/2024/11/10/Fifteen-years-on-the-Capitol-Limited/"/>
    <id>https://blog.goodbyeplease.com/2024/11/10/Fifteen-years-on-the-Capitol-Limited/</id>
    <published>2024-11-10T16:01:29.000Z</published>
    <updated>2025-02-20T03:07:34.774Z</updated>
    
    <content type="html"><![CDATA[<p>2009 was my year of discovery on Amtrak. That January, I made my first run on the <em>Empire Builder</em> (as recounted in <a href="/2023/11/22/My-worst-best-trip-on-the-Empire-Builder/" title="My worst best trip on the Empire Builder">My worst best trip on the Empire Builder</a>) from Chicago to Portland. In June, I took the <em>Lake Shore Limited</em> to Springfield, Massachusetts, starting a long and <a href="/2024/03/16/Fifteen-years-on-the-Lake-Shore-Limited/" title="Fifteen years on the Lake Shore Limited">somewhat complex history</a> with that train. Then, that October, I made my first trip on the <em>Capitol Limited</em>, traveling from Chicago to Washington and back. I’ve made 34 trips on the <em>Capitol Limited</em>, the most I’ve made on any American long-distance train. 23,622 miles is almost enough to circle the globe.</p><p>Today the <em>Capitol Limited</em> disappears from Amtrak’s timetables. This change is meant to be temporary, and is driven by two needs. One, Amtrak is conducting maintenance on the East River Tunnels over the next year and needs to <a href="https://media.amtrak.com/2024/09/amtrak-launching-the-floridian-with-daily-service-between-chicago-and-miami/">reduce the number of movements</a> between Sunnyside Yard and Pennsylvania Station in New York. Two, Amtrak has an <a href="https://www.trains.com/trn/news-reviews/news-wire/amtrak-may-be-planning-to-combine-capitol-limited-and-silver-star-analysis/">on-going shortage</a> of its bilevel Superliner cars. Amtrak’s solution is to take the <em>Silver Star</em>, one of its two New York-Florida trains, and change its northern terminus from New York to Washington. This new train is called the <em><a href="https://en.wikipedia.org/wiki/Floridian_(train)">Floridian</a></em>, and it uses the <em>Silver Star</em>’s single-level equipment.</p><p>I understand the decision and I can’t argue with the logic. The Superliner shortage, whatever its root causes, is real. I have concerns about the timekeeping. It’s a long way from Miami to Chicago–47 hours; 2,076 miles–and there are many opportunities for delays. On the other hand, eliminating the engine change for the <em>Silver Star</em> in Washington probably helps. Running single-level cars on the <em>Capitol Limited</em> may open the door to the long-discussed idea of through cars conveyed in Pittsburgh to the <em><a href="https://en.wikipedia.org/wiki/Pennsylvanian_(train)">Pennsylvanian</a></em>.</p><h2><span id="memories">Memories</span></h2><p>On October 6, 2009, I was in Milwaukee, attending my first-ever HighEdWeb (another venerable institution <a href="https://digicol.org/">going through a rebrand</a>). I left Tuesday afternoon, before the big social event, because I had to be in Washington the next day to prepare for the annual German Studies Association conference. Back then I didn’t have a smart phone and wasn’t carrying a digital camera. My memories are vague. I know I saw <em>some</em> of the <a href="https://en.wikipedia.org/wiki/2009_American_League_Central_tie-breaker_game">American League tie-breaker game</a> between Detroit and Minnesota, but it would have ended well after the <em>Capitol Limited</em> departed Chicago. That pitch hit Inge. Fight me. My strongest memory is sitting in the Sightseer Lounge the next morning, marveling at the fall color along the Youghiogheny and Potomac rivers. My notes say we were six minutes late. On the way back, Liz and I had an encounter with a roughneck in the lower level of the lounge which inspired the “Sharing With The Class” event of the <a href="/2022/11/15/Amtrak-Olympics/" title="Amtrak Olympics">Amtrak Olympics</a>.</p><p>I was back on the <em>Capitol Limited</em> in January 2010 for a trip out to Lafayette College. The next calendar year that I <em>didn’t</em> make at least one trip on it was 2023–yes, even in 2020, I was on it in January before the pandemic struck. It was on a <em>Capitol Limited</em> that I met the late <a href="/2024/04/11/RIP-Jim-Loomis/" title="RIP Jim Loomis">Jim Loomis</a>. I did the early morning transfer to the <em>Pennsylvanian</em> in Pittsburgh for the first time in 2012. Saves a few hours off the Washington-Philadelphia leg, and there’s slightly more cell signal around Altoona than Cumberland. Not as pretty though.</p><p><img src="/2024/11/10/Fifteen-years-on-the-Capitol-Limited/Amtrak_30_on_the_Magnolia_Cutoff.jpg" alt=" The Capitol Limited exits Graham Tunnel and crosses the Potomac River in Magnolia, West Virginia, in 2011. Photograph by John Mueller, CC BY 2.0." title="Silver and blue locomotive leading cars out of a tunnel surrounded by trees"></p><p>The <em>Capitol Limited</em> of my imagination is the mid-2010s train with a baggage car, 2-3 sleepers, a full diner, a Sightseer Lounge, and 2-3 coaches. The scenery between Pittsburgh and Washington demands an observation car, and it was one of the main reasons I <a href="/2013/03/10/Leaving-the-Lake-Shore/" title="Leaving the Lake Shore">preferred that train</a> to the <em>Lake Shore Limited</em>. Going out to Chicago in a sleeper, you made your dinner reservation from the Metropolitan Lounge. You dined as the darkness fell between Chicago and South Bend. When you wake up in the morning, you’re somewhere near Connellsville, Pennsylvania, following the Youghiogheny. After breakfast you decamp to the Sightseer Lounge and watch the scenery. You pass through horse country heading in to DC. Westbound, dinner’s around Harpers Ferry, parked right on the bridge. In the morning, there’s a ground fog in northern Ohio and Indiana as you rush west to Chicago.</p>]]></content>
    
    
    <summary type="html">Remembering the temporarily gone Capitol Limited</summary>
    
    
    
    <category term="Trains" scheme="https://blog.goodbyeplease.com/categories/Trains/"/>
    
    <category term="Travel" scheme="https://blog.goodbyeplease.com/categories/Travel/"/>
    
    
    <category term="Amtrak" scheme="https://blog.goodbyeplease.com/tags/Amtrak/"/>
    
    <category term="Capitol Limited" scheme="https://blog.goodbyeplease.com/tags/Capitol-Limited/"/>
    
    <category term="Floridian" scheme="https://blog.goodbyeplease.com/tags/Floridian/"/>
    
    <category term="Silver Star" scheme="https://blog.goodbyeplease.com/tags/Silver-Star/"/>
    
  </entry>
  
  <entry>
    <title>Migrating my galleries to GitHub and DigitalOcean</title>
    <link href="https://blog.goodbyeplease.com/2024/10/29/Migrating-my-galleries-to-GitHub-and-DigitalOcean/"/>
    <id>https://blog.goodbyeplease.com/2024/10/29/Migrating-my-galleries-to-GitHub-and-DigitalOcean/</id>
    <published>2024-10-30T02:43:35.000Z</published>
    <updated>2025-02-20T03:07:34.792Z</updated>
    
    <content type="html"><![CDATA[<p>I use <a href="https://thumbsup.github.io/">thumbsup</a> to generate my <a href="https://galleries.goodbyeplease.com/">galleries</a>. That’s worth a whole other post–the short version is that the metadata is written to the images themselves, and then that metadata generates a series of static html pages for albums, tags, and categories. The resulting site is easy to host–no database and a minimum of CSS and Javascript. I’ve used Cloudfront and S3 on Amazon for several years but as I <a href="/2024/10/26/Moving-from-S3-Cloudfront-to-GitHub-pages/" title="Moving from S3+Cloudfront to GitHub pages">previously mentioned</a> I’m moving my stuff off Amazon.</p><p><a href="https://pages.github.com/">GitHub pages</a> isn’t suitable on its own: I have about 13 GB of images. The generated site structure looks like this:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">album/</span><br><span class="line">media/</span><br><span class="line">public/</span><br><span class="line">index.html</span><br></pre></td></tr></table></figure><p>The album directory contains the various generated HTML pages for the albums, categories, and tags. It’s all text and about 20 MB. That can go to GitHub. The public directory is the CSS and Javascript assets from thumbsup and it’s another 1.1 MB. That leaves media.</p><p>I decided to put the images on <a href="https://www.digitalocean.com/products/spaces">DigitalOcean Spaces</a>. I’ve admired DigitalOcean’s documentation for years, though I’ve never used them for anything. Their Spaces offering is very similar to S3, though they built their own solution using <a href="https://docs.digitalocean.com/products/spaces/details/features/">Ceph</a>. I’ll say upfront that the pricing; as I’m using it now, <em>isn’t</em> competitive with Amazon S3. It’s $5/month upfront to “subscribe” to Spaces, which gets you 250 GB of storage. That’s $0.02 per GB, which is what <a href="https://aws.amazon.com/s3/pricing/">S3 costs</a>, but without a minimum commitment. Price isn’t the reason I did this, and I may find other uses. Spaces does have CDN support, but the offering isn’t a full-fledged offering like AWS CloudFront or Cloudflare, so I still needed GitHub for the web hosting.</p><p>To sync the files to Spaces, I used <a href="https://s3tools.org/s3cmd">S3cmd</a>. It can be installed with homebrew. DigitalOcean has <a href="https://docs.digitalocean.com/products/spaces/reference/s3cmd/">good docs</a>. It can actually be used with either Spaces or S3. I’ve run into two minor gotchas:</p><ul><li>Files aren’t publicly readable by default (good), and I need them to be for my use case. I didn’t worry about this before because S3 and CloudFront handled this with an Origin Access Identity. S3cmd supports setting an ACL when synchronizing (<code>--acl-public</code>).</li><li>Full synchronizations feel slower than when going to S3.</li></ul><p>The final issue to solve is that thumbsup doesn’t support an external CDN out of the box. This was tricky, especially as I like testing my galleries locally and didn’t want to hard-code the CDN there. That would lead to a lot of unnecessary remote requests and mean I couldn’t test new albums until I’d synchronized. Ultimately, I customized the GitHub Actions workflow to run a few sed commands against the artifact before it was deployed:</p><figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">name:</span> <span class="string">Rewrite</span> <span class="string">image</span> <span class="string">URLs</span></span><br><span class="line"><span class="attr">run:</span> <span class="string">|</span></span><br><span class="line"><span class="string">  sed -i &quot;s/url(&#x27;media/url(&#x27;https:\/\/galleries-goodbyeplease.nyc3.digitaloceanspaces.com\/media/&quot; index.html</span></span><br><span class="line"><span class="string">  sed -i &#x27;s/..\/media/https:\/\/galleries-goodbyeplease.nyc3.digitaloceanspaces.com\/media/&#x27; album/*.html</span></span><br></pre></td></tr></table></figure><p>This is after the Checkout step and before the Setup Pages step. This is hacky, but it’s not a production example of <a href="https://stackoverflow.com/questions/1732348/regex-match-open-tags-except-xhtml-self-contained-tags">using a regular expression to rewrite HTML</a> since it’s merely URL replacement. That’s my defense, and anyway it’s working.</p>]]></content>
    
    
    <summary type="html">Rebuilding my static galleries using GitHub and Digital Ocean.</summary>
    
    
    
    <category term="Web Development" scheme="https://blog.goodbyeplease.com/categories/Web-Development/"/>
    
    
    <category term="DigitalOcean" scheme="https://blog.goodbyeplease.com/tags/DigitalOcean/"/>
    
    <category term="GitHub" scheme="https://blog.goodbyeplease.com/tags/GitHub/"/>
    
  </entry>
  
  <entry>
    <title>Moving from S3+Cloudfront to GitHub pages</title>
    <link href="https://blog.goodbyeplease.com/2024/10/26/Moving-from-S3-Cloudfront-to-GitHub-pages/"/>
    <id>https://blog.goodbyeplease.com/2024/10/26/Moving-from-S3-Cloudfront-to-GitHub-pages/</id>
    <published>2024-10-26T18:04:42.000Z</published>
    <updated>2025-02-20T03:07:34.794Z</updated>
    
    <content type="html"><![CDATA[<p>I’ve used <a href="https://hexo.io/">Hexo</a> to build this site for <a href="/2022/10/30/Adding-a-poster-to-movie-reviews-in-Hexo/" title="Adding a poster to movie reviews in Hexo">two years</a>. At the time, I kept my existing S3+Cloudfront hosting stack with a few minor tweaks. Yesterday I moved the whole thing over to <a href="https://pages.github.com/">GitHub pages</a>.</p><p>I had a few reasons for doing this. One, I’m doing a project at work to roll out GitHub Campus and I want to get more familiar with the architecture. Two, for various reasons I want to be less dependent on the Amazon environment. I figured moving a static site from one architecture wouldn’t be a big deal, and I was right.</p><p>Hexo has a few deployment options. When I was using an S3 bucket I just rsynced the generated output, which won’t work here. The “right way” of handling the deployment would involve pushing source files and letting a GitHub Action build the site.  My local environment is a little unclean–I have some uncommitted package dependencies–so that’s not a great option. I can however use the one-command deployment option with <a href="https://github.com/hexojs/hexo-deployer-git">hexo-deployer-git</a>. Per <a href="https://hexo.io/docs/github-pages#One-command-deployment">Hexo’s documentation</a>, you add this to <code>_config.yml</code>:</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">deploy:</span></span><br><span class="line">  <span class="attr">type:</span> <span class="string">git</span></span><br><span class="line">  <span class="attr">repo:</span> <span class="string">https://github.com/&lt;username&gt;/&lt;project&gt;</span></span><br><span class="line">  <span class="comment"># example, https://github.com/hexojs/hexojs.github.io</span></span><br><span class="line">  <span class="attr">branch:</span> <span class="string">gh-pages</span></span><br></pre></td></tr></table></figure><p>You then run two commands:</p><ul><li><code>hexo clean</code></li><li><code>hexo deploy</code></li></ul><p>It’s important to run both commands. This approach creates a clone of the GitHub repository in a new <code>.deploy_git</code>  directory in the root of your project folder containing the generated static output, and then push to the remote directory. The clean command deletes and re-creates this directory, allowing the deploy command to push changes as a new commit. If you don’t do clean first, it’ll amend and force-push the last commit.</p><p>In terms of infrastructure, the site <em>almost</em> just worked after I cut over DNS to point at GitHub instead of Cloudfront. I needed to place a <code>CNAME</code> file containing my custom subdomain inside the <code>source/</code> directory; otherwise it was removed on every deployment. Next steps are to think about a better build pipeline, and whether GitHub is a reasonable choice for my <a href="https://galleries.goodbyeplease.com">gallery site</a>.</p>]]></content>
    
    
    <summary type="html">Moving a static site from S3+Cloudfront to GitHub pages.</summary>
    
    
    
    <category term="Web Development" scheme="https://blog.goodbyeplease.com/categories/Web-Development/"/>
    
    
    <category term="Hexo" scheme="https://blog.goodbyeplease.com/tags/Hexo/"/>
    
    <category term="AWS" scheme="https://blog.goodbyeplease.com/tags/AWS/"/>
    
    <category term="GitHub" scheme="https://blog.goodbyeplease.com/tags/GitHub/"/>
    
  </entry>
  
</feed>
