flwyd: (mathnet - to cogitate and to solve)
In the winter of my funemployment I didn't expect to receive a research project and homework, but then the Trump administration announced it intended to "dismantle" NCAR, the National Center for Atmospheric Research. The National Science Foundation published a Dear Colleague Letter requesting input and proposals for splitting up work done by NCAR. Notably absent from that letter was the word "climate," despite the OMB director's announcement that NCAR was a leading source of "climate alarmism."

This proposal to disrupt a key institution in my home town led me to spend weeks researching NCAR's organization structure, mission, computing infrastructure, and data sets so I can craft a persuasive letter to NSF and (more importantly) be useful if someone spins up an effort to save NCAR's data and provide a plan B organization for its valuable services. So far I haven't gotten wind of such an effort, but I'm keeping my ears to the ground. Maybe we'll need to enlist the help of Woody Allen to exfiltrate the data on magnetic tape.

Also, personal message to LinkedIn: if I search for NCAR I do not want to see posts about cars or the auto industry.
flwyd: Ham radio on cliffs overlooking Keauhou Bay, Hawai'i (ham radio hawaii parks on the air)
The radio frequency spectrum is organized in bands (ranges of frequencies), with each band dedicated to one or more radio services (purposes and licensing systems). For example, U.S. broadcast radio is in two bands: the AM broadcast band is from 535 kHz to 1.705 MHz and the FM broadcast band is from 88 MHz to 108 MHz. (Here's a nice chart.) In many radio services, each frequency is assigned to a specific station in a specific area. For example, KOA in Denver is the only station allowed to transmit on 850 kHz with significant power at night in the continental US, and in the daytime in most of the western US.

The amateur radio service (ham radio) doesn't assign frequencies to specific stations. Amateur bands are open to anyone with an appropriate license, and it's up to amateur operators to avoid operating on a frequency that's already in use. This is normally fairly straightforward: listen first, then ask if anyone's using the frequency, then you can call CQ (ask people to call you). High frequency radio waves have a limited range though, and also a short-range "skip zone" where they can't be heard. So sometimes two people are calling CQ on the same frequency, but can't hear each other. I occasionally run into this situation with single sideband: one station in Florida and one station in Georgia might both be seeking contacts. If their timing is such that I can make out which is which by the sound of their voice, I can sometimes work both stations and tell them that another station is on the same frequency.

I've been practicing Morse code lately, and while some operators have a distinct "fist" (keying rhythm), often the only way to tell the dits and dahs of two transmissions apart is by the signal strength, if that. Today in the weekly K1USN SST slow speed contest I was listening to several rounds until I worked out the operator's callsign before calling them. An exchange is information given by the two parties in a contact. If K1USN is calling CQ and W1AW contacts them, the full sequence would be something like
CQ SST DE K1USN
W1AW
W1AW GA WATSON MA
TU WATSON HIRAM CT
TU HIRAM ES 73
with DE short for from, ES for and, GA for good afternoon, TU for thank you, MA/CT are state abbreviations, and 73 stands for kind regards, end of conversation. After a few passes, I'd written down W6RIF, called him, and got his exchange as WARREN IL (Warren in Illinois). I said TU WARREN TREVOR CO and moved on. I typed up my log file at home and ran it through a script I wrote to double check callsigns and states against the FCC database. I was surprised to discover that W6RIF is named Reed and lives in Virginia; neither the names nor the states sound similar in Morse code. I was pretty sure I'd copied the callsign correctly, and I relied on my phone to pick up the name. I searched QRZ for several variants with wildcards in various places, none of which turned up a more promising operator. I tried searching QRZ for just warren but in a hobby dominated by old white guys, there are a few thousand. I recalled finding a text file of SST operators and their exchanges, only one of whom is Warren from Illinois: KC9IL. I could confuse IF for IL (L and F both have three dits and a dah, with the dah one position different), but it's implausible that I misheard KC9 as W6R; none of those letters sound like the other. I had the insight to check the Reverse Beacon Network where people run software to automatically spot (announce that they heard) stations calling CQ in CW (Morse code) or digital modes. I looked up both callsigns, and saw they were both calling CQ on the same frequency in the same time range. It's possible that both of them responded to me at the same time, but I only picked up Warren's exchange. Maybe I ended up in both of their logs. I'm surprised they didn't notice each other on the same frequency: Virginia Beach and Chicago are far apart to be well out of the skip zone on 20 meters, but close enough to have a clear signal.

High frequency and medium frequency amateur radio is a curious hobby. In an era where you can place a phone call or send a short message to almost anyone on the planet for cheap, hams have to concentrate to pull out callsigns, names, and other details in the spaces between simultaneous transmissions, over atmospheric noise and static from thunderstorms, and signals fading in and out. Before I got my General class license, I was curious why someone would do this. The answer: it's fun in part because it's hard to communicate. It's a bit like a game of chance, strongly influenced by skill and appropriate use of technology.
flwyd: (cthulhufruit citrus cephalopod)
As Boxing Day is to Christmas, so Shadow Boxing Day (February 3rd) is to Groundhog Day. Shadow Boxing Day is a day to get shit done that you've been putting off. [previously] Although I've been funemployed for five months, there's a lot of tasks that seem like a good idea, but I just don't get around to them. Like, why haven't I brewed anything yet? Shadow Boxing Day is close enough to Imbolc that making mead will count as celebration of Brigid the brewer.

We spent July 4th of last year bottling four carboys that had been sitting on the counter for years; the newest from 2021 and the oldest from 2018. Part of the problem was that home brewing is mostly "clean your kitchen" and then a little bit of "mix stuff in a pot." I would occasionally clean the kitchen on a Saturday, be too tired to brew on Sunday, and by the time there was another clear weekend the kitchen would be dirty again. Now that I've got counter space back and I can summon the energy to clean on something other than a free weekend, the zymurgy hobby is back on the table (so to speak).

Kelly and I made a honeymoon mead starting in late 2015. We were inspired by a mead shared at Dragonfest that year made from Brazilian wildflower honey, so we ordered a 60 pound bucket of the stuff. That's enough for three or four 5-gallon batches, and I've used it a few times since. But the results were coming out with a fairly harsh off-flavor, likely a result of fermenting at too high of a temperature: the yeast are stressed out, and you taste the result of them not doing their best work. I also wasn't getting inspired with new ideas for that particular honey, so it sat all lonely in a corner.

Honey is a pretty amazing substance. I can't think of many other foods that can sit half-empty in a closet for a decade and still be worth eating. But honey is anti-microbial, so the only challenge is that a lot of it had crystalized. Fortunately, our house has a nice low-tech way to get honey flowing: I left the bucket on our sun porch for a week, occasionally digging around with a spoon to shift the crystal clumps. The flavor is still nice: not too sweet and with a bit of a mysterious taste to match the dark amber color. I decided it could do well as a pomegranate mead, and found some unfiltered, unsweetened 100% pomegranate juice from Armenia at our local Middle Eastern shop. Having learned the yeast-fermentation-temperature lesson from my initial wine yeast brews, I picked up an English Ale yeast with an ideal temperature range of 64° to 79°F. Room temperature sits in the middle, and now that we've got a heat pump we might be able to keep the kitchen below 80° in the summer. My 2021 cyser with British Ale yeast turned out well, and was able to survive into the 12% alcohol range.

I normally take fairly precise measurements while home brewing, but not today. (Relax, don't worry, have a homebrew.) This melomel has "about 7 pounds" of honey, measured by lifting the honey bucket with an analog luggage scale, then lifting the empty bucket afterwards. I added "about a gallon" of warm water by filling a quart jar four times, then four liters of juice ('cause it's imported), then "about four liters" of water in those juice jars, so I could get the last bits of sediment into the brew. There's also somewhere between an extra 3 quarters to one whole cup of water from mixing the yeast and nutrient, plus rinsing the last of the must from the pot into the carboy. That gives "a little more than three gallons of liquid," plus the volume of honey. This should work perfectly; it's got plenty of surface area for primary fermentation in a 5-gallon glass carboy, and I can then rack it to a 3 gallon carboy for secondary, leaving behind what I expect to be rather a lot of trub: the pomegranate juice was quite cloudy.

The Internet has a bunch of opinions about fermentation vessels, with most commentators discouraging using a carboy for primary fermentation; the narrow neck increases the risk of blow-outs and reduces surface area for the initial aerobic phase. My theory is that "3.5 gallons in a 5 gallon carboy" solves both of those risks, and since I'm not planning to rack to secondary for two months I'd rather it sit in glass than plastic. Plus, I think this one will be fun to watch.

The pre-fermentation taste of the must is more subtle than I expected: a little sweetness at the front, followed by subtle pomegranate flavor—including a hint of the white pith—and then back to honey flavor at the finish. If you didn't know it was pomegranate, it might take a bit to place it. We'll see if this turns into a lovely dry melomel (just 12% potential alcohol), or if that fruit flavor disappears through primary. I got a couple jars of pure pomegranate syrup which I might add in secondary fermentation if necessary; that stuff is tart and tangy on pancakes.

I've got a couple other jugs of honey waiting for a round tuit now that I'm re-building my zymurgy reflexes. I got some wildflower honey from a Rocky Ford farmstand in 2024, and should probably start that fermenting now so we can add some fresh melons to secondary this summer, giving a better shot of retaining the cantaloupe flavor than starting with fruit chunks in the must. I also stopped for a hand-made "LOCAL HONEY" sign along highway 16 in the Arkansas Ozarks in 2022, not too far from Ben Hur and the Pedestal Rocks trailhead. I'm really not sure what to make with that one, so maybe I should start it as a traditional and see what the flavor suggests. I think there are also some Palisade peaches in the freezer waiting for a project…
flwyd: (daemon tux hexley)
Last December was the 11th annual Advent of Code programming event. Each day a new puzzle is released. The puzzle describes what you need to compute, provides an example input and output, and provides participants with a personal input file. After figuring out the answer for your input file, a second part of the puzzle unlocks, generally with a tougher or more involved version of the first part. The big change this year was only 12 days of puzzles, rather than a full 25-day advent. There was also no global leaderboard, because people were expending immense amounts of angst about people using AI to solve puzzles in a few seconds.

In the previous five years I've used AoC to learn a new programming language: Kotlin, Raku, Elixir, Julia, and PostScript. This year, I wasn't getting inspired with a single language I wanted to spend the month learning. I also thought I would be driving across the southwest and might end up programming on my phone at a campsite in the desert, so I started looking at languages I could edit and run in a Linux terminal on my Android phone without a huge install dependency. This led me to the theme of glue languages you might already have on your system. While most of them needed to be installed on my phone, the idea was that glue languages like AWK or jq are designed to be written quickly without too much typing, and don't need a memory-intensive compilation process. I've used a lot of these glue languages before, but I often find myself cargo cult programming and not really understanding the language's conceptual framework. For example, I used AWK for 20 years before I realized it could do something more than "print the Nth column of a space-separated input."

The glue languages theme worked out pretty well. I didn't end up programming on my phone (though I did a little shell exploration on my phone while riding transit), and instead spent the first week solving problems on my Chromebook in the living room of a youth hostel in San Francisco, where "Let's find something hacky that will solve things in an amusing way" was still a good fit. Thanks to funemployment I had plenty of time in October and November to build my standard "runner" infrastructure in several languages I wanted to use, which stretched some of my standing runner design choices. "Read the file, break into a list of lines, and pass the list to part1 and part2 functions" is, er, awkward in AWK, and neither Jsonnet nor jq can measure time.

Languages and Thoughts


AWK: day 5, day 7, day 12
AWK is a simple language for transforming text—particularly multi-field delimited text—frequently used when sed would be too painful. The general structure is "run this block of code when the current line matches this pattern," it automatically converts between strings and numbers, and it's got global variables so you can accumulate results and print them at the end. In recent years I've written some AWK code that's more complex than "print just the second column of ps", so I thought this might not involve as much language learning as I like to do in AoC, but AWK is just so good at what it does that it seemed prudent to build some runner infrastructure so I could whip a quick program out and go to bed. I did end up learning some things about AWK arrays, and I think the day 7 solution is kind of elegant.


dc: day 1 and day 6
dc is a stack-based "desk calculator" from back when people had reverse-Polish HP calculators on their desks. It's one of the oldest Unix programs (predating the C programming language), and writing code for dc feels a bit like writing in assembly. It's got two data types: numbers and strings. 256 memory registers are available, each identified by a single character. The registers are themselves stacks. Operators are one or two characters and spaces are only required to separate number literals, which is reasonable for arithmetic like 1 2 3 4*/+ but challenging to read for something like [la1+sa]sz, which is "store a macro in register z that increments the number in register a." My practice with stack programming in PostScript last year was helpful, but programming in dc is still a bit of a mind twist. Fortunately the f operator prints the stack, so it's easy to try out part of a program and see what effect it has on the stack. Since dc doesn't have a "read from standard input" operator, I used sed to turn my input file into a dc program, with macros declared at the start and a few print operators at the end. After my trip I discovered that dc is still under active development, with GNU dc gaining r and R operators to rotate several items on top of the stack. I'd used these in my program, but the macOS version on my 11-year-old Mac Mini hasn't upgraded yet, so I worked out how to implement top-3 rotation manually: [S1S2S3L2L1L3]sR [S1S2S3L1L3L2]sr.


gvpr: day 8, day 11
gvpr is an "AWK-like" language for processing graphs in Graphviz format. The dot and neato tools are very handy for visualizing your input file in AoC problems that can be represented as a directed or undirected graph. I became aware of gvpr on day 25 when I solved the main part of the problem by staring at a graph, and then wanted code to determine the size of graph subcompoents. The concept of "AWK for graphs" is appealing, but the execution is pretty painful. You know you might be in trouble when half of the time you Google for something about the language one of the top hits is a forum post titled I'm trying to use gvpr. Is that a mistake? with project devs basically saying "yes, it's poorly designed." I felt a weird sensation of writing code that looks at first like it's AWK, but as I got into details, it started to look more like programming in C. Sharp edges included a lack of safe defaults for missing attributes, awkward naming (which end of an edge is the head and which is the tail? the answer may shock you!), functions that don't respect variable scope, and the inability to use the AWK-like matching constructs if you build the graph programmatically rather than piped in as DOT. Oh, and it's kinda slow (or I could only figure out how to write an inefficient version for day 8).


jq: day 3, day 4
jq is a terse language for processing JSON input, in the tradition of tools like sed and awk. I've used jq a lot in recent years—it's great for playing with new APIs or pulling the one piece of data you need from a JSON download—but I still felt like I didn't entirely get it, particularly in correctly working with nested array data. jq is a functional language structured as pipelines, and if there's one thing a functional language loves it's small programming puzzles. On day 3 I got twisted up and spent a bunch of time banging my head on incorrect approaches. Day 4 I'd already solved inefficiently with shell pipelines, so it was a matter of functional translation and then recursive iteration. The language is still a little brain-twisty, but I think I've got the hang of it now.


Jsonnet: day 10
Jsonnet is a different purely functional language for transforming JSON input. It's inspired by an internal configuration language at Google, having removed some features that are widely considered a bad idea. Jsonnet is lazily evaluated and allows for infinite data structures: you can have an infinite array, but if you only ever access a few specific elements it won't try to figure out all the other values. It's written declaratively, and allows prototype-style inheritance: "make an object like that one, but override this property." Contrary to many of my former colleagues, I happen to enjoy the internal config language, and "find an excuse to use Jsonnet for something clever" was one of the reasons I chose to focus on glue languages this year. Part 1 of day 10 seemed like a good fit for Jsonnet's ability to make inferences, but I thought up an overcomplicated approach and kept overflowing either Jsonnet's internal stack or the underlying Go maximum stack size, depending on just how I ended up with excess recursion. I switched to Go (a language that's efficient and good at making coding mistakes obvious) and solved part 1, but then got stuck on part 2 for a couple weeks of trying to re-learn linear algebra. I still wanted to work out a Jsonnet implementation, but didn't want to figure out how to do recursive lazy matrix reduction on immutable objects, so I was pleased to read through an excellent tutorial on a bifurcation approach which reduced the problem search space in ways I was grasping for but couldn't figure out the first time. It still took some careful work to get this to work in Jsonnet, including discovering the undocumented tailstrict keyword and figuring out how to structure a tail recursive function with lazy evaluation and multiple if clauses. I fortunately chose to implement this on my Mac which had the Go Jsonnet implementation rather than the original C++ one on Debian-derived Linux. The Go interpreter finishes in a tedious minute and a half but the C++ interpreter gets completely stuck, as far as I can tell. (One downside of a lazy functional language is that the "print a debug message" function only outputs after the recursive function it wraps finishes, so "where is my program getting stuck" is tough to figure out.


Lua: day 10
Lua is a small language designed to be embedded in other programs that need an interpreter for user-written code. After two weeks of day 10 and linear algebra as my white whale, I finally got my Go implementation working. The code was full of failed attempts and half-commented-out functions, so I decided to transcribe the working solution to Lua and clean up the original Go later. I'm really glad I didn't try to do the whole month in Lua: it's got just enough to be a real language, but not enough to be very productive. Lua's only compound data type is the "table," an array that can have strings or numbers as keys. I've used languages like this before—PHP arrays are also "indexed arrays or hash maps" and JavaScript arrays are technically objects with indices as string property names—but this gets extra awkward in Lua. Integer indices are treated specially, so if you want to use it as a sparse hash map with numeric keys, you might not get all your data back when iterating. Object orientation is available, but if you want to use an object as a table key you need to go back and forth with string conversion, which gets slow. The standard library has a few useful string functions, but misses a lot of really handy utilities that you'd find in a language like Perl, Python, or Ruby. If "write your vimrc and plugins in Lua" is the compelling reason to switch to Neovim, I'll stick with Vimscript.


Perl
Perhaps the pinnacle of glue languages, Perl was the first programming language I ever got comfortable with. In high school and college I really enjoyed writing Perl code, and the quirky community around the language. In the last two decades I don't think I've edited a Perl file, but I've used it for plenty of one-liner scripts at the command line. I wrote a runner script for Advent of Code in Perl, but didn't end up using it this year. I was struck with how clunky some things felt. A simple Perl script is really slick at doing something for each line of all input files, but treating each argument as an independent list of lines—and reading stdin if no files were specified—was surprisingly verbose. Needing to explicitly use a reference (pointer) to pass a list as an argument (rather than having an operator to explicitly splat a list into multiple arguments) also felt awkward coming from any other programming language.


Ruby: day 12
Ruby was clearly inspired by Perl, but brings a strong object-oriented philosophy and borrows heavily from the functional programming community. This is a questionable inclusion as a "glue language," and many companies run multi-million user websites with just Ruby. But like other glue languages it's got functions to simplify common tasks, easy string processing, and a quick iterative development cycle. I wrote a bunch of Ruby a decade ago as part of a replacement for a Burning Man system, but then abandoned that effort. I had Ruby in my toolkit in case I encountered something that was going to be complicated, and when I read day 12's space packing puzzle while still exhausted from day 10, I decided I needed a language with a full suite of composite data types. The puzzle has a trick that I found distasteful: the example input is really hard, but if you add the right check the actual input is easy. I spent a long time trying to come up with potential optimizations and shortcuts for what I recognized was an NP-complete problem, but the code always seemed to run for an unreasonably long time on the example input. Once I realized the input trick (some lines were getting processed a lot faster than others), I got grumpy and posted a couple cheeky implementations in other glue languages. A couple weeks later I came back to the problem, since I had been enjoying trying to optimize the placement of puzzle pieces on a grid, and the ASCII art output was fun to look at. After some time learning to use the Ruby profiler, I ended up with a solution that only takes about 3 minutes on the example input, though it does leave out one axis of permutations that could in theory find a solution. Coming back to Ruby a decade later, I still like the language. It's got a few sharp edges, but I think it's still a good language to have in your toolkit. The irb interactive environment has also gotten really nice, providing syntax highlighting and autocomplete despite Ruby's very-dynamically-typed nature.


SQL (spatial): day 9
SQL is the world's most popular database query language, and there are several folks who use it to solve all AoC problems, though sometimes things get pretty awkward. The last couple years at work I spent a bunch of time working with spherical geometry, and got to know the ST_ (spatio-temporal) functions of the Simple Features standard. Google's SQL dialect and systems support these, and I even wrote a SQL function to compute the angle of the sun at the start of each GPS track in our dataset. I hadn't played with other spatial databases, though, so I bent my "you might already have installed" theme and my "standard library only" rule a bit and installed PostGIS for PostgreSQL and SpatiaLite for SQLite. When you've got a geometry library at hand, this puzzle is quite simple :-) Runtime is kinda slow, since it's doing a cross join of every point in the input. It's also important to remember that the "S" in "SQL" stands for "Structured" and not "Standard", so I had to write the query twice: SpatiaLite doesn't consistently follow SFS naming. My first attempt at day 9 was a fun use of ImageMagick a glue tool for image processing, but creating a 100,000 pixel square image (10 gigapixels) and taking slices of it was not a task my old Mac Mini was up to. I also tried using rsvg-convert in the hope that staying in vector space for image slicing would work, but it seemed to be rasterizing as well.


Z shell: day 2, day 4, day 6, day 12, and runner infrastructure for niche languages
I've been using zsh as my login shell for more than a quarter century, but I still need to look at the man page whenever I need to do something more complex than a foreach loop. Day 2 was solved entirely with zsh builtins. Day 4 launched a pipeline of 6 commands within a loop, using head | tail | cut | tr | xargs printf to extract 3x3 sections of a grid. This took 45 seconds to run on part 1 (and 12 minutes on Android: forking a process is expensive, kids!), so I switched to jq for part 2. Day 6 used a grep | cut | pr | sed pipeline, but the loop didn't have as many iterations, so it wasn't untolerably slow. The use of dc in day 6 was just so I could be cute and not do arithmetic in the shell.


Go: day 10
This definitely doesn't count as a "glue language that might already be on your system," but it's my fallback for puzzles where I get stuck or my approach is too slow in an interpreted language. Day 10's second part requires finding the minimum number of steps to reach a goal in a rather large possible search space. I experimented with a lot of approaches to reducing the search space, and took advantage of Go's treatment of fixed-size arrays as value types to optimize performance as much as I could. Most of my approaches were some variant of "keep a priority queue of states to explore," and memory use would often grow to tens of gigabytes. Some of the lines in the input could reach a solution pretty quickly, and other lines were amenable to different approaches to space exploration. I kept a cheat map of the answer for lines I'd previously found, which let me run my program for several hours on lines I hadn't yet solved, then stop when it hit a troublesome line and try a different approach without spending hours redoing old work. Running for days is a clear sign that I didn't have the right solution, but "find a solution and then optimize" is usually a good strategy. In the end I only had half a dozen unsolved lines out of 191, but those didn't seem amenable at all to any form of state-space exploration. In the solutions thread for another day, I saw a tangential reference to day 10 as a system of equations and said "Of course!" I'm not very good at recognizing linear algebra problems, and very shaky at writing code to solve them. One challenge for linear programming in Advent of Code is that everything is an integer (and in this problem, no negative numbers), while most matrix solvers assume real numbers. Over the course of a couple days I re-read my linear algebra textbook and Wikipedia pages about Gaussian elimination. I adapted it to an integers-only system of linear equations implementation, but still got hung up on some of the inputs because the scalar factor between two rows would result in non-integer values somewhere. Through more Internet research I learned that integer linear programming (rather than the more general linear programming) is what I was doing, and wound up writing code to compute the Hermite normal form, though I then realized that making full use of the HNF matrix would get complicated. I also tried Octave and Scilab (two open-source Matlab-like languages) which count as more "glue-like." Octave refused to do matrix solving on integer-typed data. I found a library for Hermite computation for Scilab but decided that path was getting too complicated and went back to writing Go code. Eventually I realized that I could produce a triangular matrix by just repeatedly subtracting rows with a value in the column; eventually it'll end up with 1-1=0 to eliminate a cell. This finally got an answer to the whole input with just a few minutes of runtime, and later profiling and tweaking got it to the 2-digit seconds range after realizing I could swap column positions and reduce the number of free variables. I definitely spent way too much time on this bugbear of a problem, but it at least it was educational, and I'm funemployed with lots of time.


Languages I wanted to try
I've encountered a few glue languages that looked pretty interesting, but I didn't get a chance to try them out. dt is billed as "duct tape for your Unix pipes," clearly a glue language. I'd encountered it last year when researching stack-based languages; unfortunately the Nix packaging system wouldn't compile on my old Mac, so I gave up on the install. Clearly it's not yet at the "might already be on your system" level. I've seen someone (turns out to be the language's maintainer) in the r/adventofcode subreddit solving all problems with the m4 macro language, which I've mostly encountered as "the language used to generate your Sendmail config file." I spent some time reading an m4 language guide, and learned that doing math is complicated. I considered setting up in case there was a good text-transformation puzzle, but seeing that even loop constructs need a library I decided to save that bit of brain-bending for a future date. I also wanted to try Noulith, a language that wasn't actually written for the purpose of Advent of Code, but just as well could have been. I spent some time reading the docs while traveling, but didn't have time to get the interpreter set up to try it out. Maybe I'll give it a shot in 2026.

Hypothesis 假設

Tuesday, December 2nd, 2025 04:03 pm
flwyd: (Taoist goddess Doumu)
Chinatown in San Francisco has changed less in the last 20 years than any town in China.

This probably holds true for any number between 1 and 100.
flwyd: (step to the moon be careful)
… and I just spent $500 at City Lights Bookstore.

Buying books and reading books are separate hobbies, as my coworker pointed out.
flwyd: (big animated moon cycle)
16 years ago on November 30th I titled a post Persimmons, Not Parsimony because I'd been tickled orange to find a bowl of persimmons in Charlie's Café, the largest eatery on Google's Mountain View campus. It was the first day of Noogler Orientation and an inflection point in my life. 24 years later I attended an improvised Dickens performance at San Francisco's BATS Theater at which the audience answer to "What reminds you of the holiday season" was "persimmons!" and it sent the story off to a sweet yet tannin-infused evening of long-form improv comedy.

To round the night out, across the street I spotted The Interval, part cocktail bar/artisan café, part museum for The Long Now, an organization devoted to thinking 10,000 years in the past and 10,000 years in the future. I recall hearing vaguely about this group around 2009, and it's fitting that I landed in their bar after sixteen rotations of Earth's celestial gears: on display was a model of a component to compute the equation of time in their 10,000 year clock. Some of the code I wrote in my final months at Google computed the sun's elevation above the horizon at a given instant…in SQL. Over the last several years I've toyed with the idea of writing a book about the various ways humans keep track of time, but I'd forgotten about the Long Now folks… perhaps they could be a human element that weaves a narrative into my nonfiction tome.

There's an alternate history to my professional and personal life. In the fall of 2009 I had no long-term commitments. I had assumed that Google's hiring process involved choosing a location after passing the interview, not realizing that my acquaintance had referred me to a specific Google Boulder position. After quitting my job in early 2009 and traveling for the summer I had imagined that I might end up in the Bay Area, the center of gravity for the computer programming world and a place that hadn't yet lost the luster of early 21st Century techno-utopianism. San Francisco seemed like the hip place to be when I was 30, and I was curious if I would choose to live in biking distance of an office in Silicon Valley and commute to The City By The Bay for cultural enrichment, or whether I'd try a life in the dense urban space and make US-101 my daily journey. (I also interviewed with a company in DUMBO, Brooklyn, near the hipster haven of the other coast, Williamsburg). I wasn't upset to stay in Boulder ("You're already from there," Molly quipped), and as I watched Googlers complain about everything in the Bay Area from traffic to housing to taxes to rain ("You live in a place affected by drought and you're complaining about the rain" I memeed) I got to feel pretty good about sticking to my mile-high xeric roots. I continue to chuckle whenever someone moves to Boulder and is wowed about how cheap the housing is and how efficiently traffic flows.

Geography is destiny; where we are determines so much of the course of our lives. Had I moved to California I wouldn't have connected with Kelly in 2010, we wouldn't have lived through the 2013 flood, we wouldn't have gotten married on Talk Like A Pirate Day, we wouldn't have bought a house, we wouldn't have our cats. I'm in the Bay Area again this week because we visited Kelly's sister and our nephew, neither of whom I would've recognized as anyone special in this alternate history. I would have met other people in San Francisco and around this saucer of mountains. I would have partied with Burners more than once or twice a year. I would have picked up different hobbies, fallen in love with different people, built community in different places. Who knows if I would've stayed at Google for a decade and a half—over the last 10 years Facebook and Amazon kept trying to recruit me to Seattle for some reason, but I imagine a Bay Area software engineer gets lots more unsolicited job inquiries, ones that don't involve a change in homes too. At Google Boulder I made friends with the sourcing team, the folks who identify those potential candidates who aren't looking for a job. Engineering and People Ops had lunch on the porch together, went to the same office parties, and a pair even got married. That cross-organizational connection doesn't happen as much in Mountain View: there are far too many Bay Area Googlers to put unrelated jobs together in the same building. All things considered, I'm happy with the happenstance that kept me at 40 degrees north, 105 and a quarter degrees east, rather than sending me on a long-term assignment to 37 and a half degrees north and 122 degrees east. The weather here is pleasant year round, but that's not a great way to keep time.
flwyd: (farts sign - Norway)
I signed my Google separation agreement today. I'd been sitting on it because one clause seemed a little weird, but I wasn't able to find any discussion of it. Most of the agreement is set up to limit future legal risk to Google based on my employment there, in exchange for paying me a bunch of money. For example, it says I won't sue them for workplace harassment or unfair labor practices I might have experienced there. But the no cooperation clause doesn't seem to be limited to just events related to my employment:
11. No Cooperation. Other than in connection with filing a charge or participating in any investigation or proceeding conducted by the Equal Employment Opportunity Commission, the National Labor Relations Board, or other comparable federal, state, or local agency, or under a valid subpoena or court order to do so, or otherwise as permitted by applicable law, you will not counsel or assist any attorneys or their clients in the presentation or prosecution of any disputes, differences, grievances, claims, charges, or complaints by any third party against the Company, Alphabet Inc. or any Released Party. For attorneys, nothing in this Section (No Cooperation) will restrict or limit your right to practice law or represent future clients, as described in the state bar rules of professional conduct of the state in which you are licensed to practice law (“the Rules”); provided, however, that you must honor all of your other continuing ethical obligations to the Company and the Released Parties under the Rules, including as to client confidentiality and privilege. Notwithstanding the foregoing, consistent with applicable law, nothing in this Agreement prevents you from disclosing the facts or circumstances underlying your claim or action for sexual assault, sexual harassment, workplace harassment or discrimination, the failure to prevent workplace harassment or discrimination, or retaliation for reporting or opposing harassment or discrimination.

This stands in contrast to the cooperation clause, which follows next and is specifically tied to topics "that relate to matters within your knowledge or responsibility during your employment with the Company."
12. Cooperation with the Company. You agree to cooperate with the Company regarding any pending or subsequently filed internal investigations, litigation, claims, or other disputes or legal proceedings involving the Company that relate to matters within your knowledge or responsibility during your employment with the Company. Without limiting the foregoing, you agree: (a) to meet with the Company’s representatives, its counsel, or other designees at reasonable times and places; (b) to provide truthful testimony to any court, agency, or other adjudicatory body; and (c) to provide the Company with notice of contact by any adverse party or such adverse party’s representative except as may be required by law. The Company will reimburse you for your time at a reasonable hourly rate and other reasonable expenses in connection with the cooperation described in this Section.

To my non-attorney reading, the no cooperation clause attempts to prohibit me from assisting an attorney with a lawsuit regarding facts which occur far in the future from now. For example, if ten years from now I work at Acme Inc and am involved in a contract dispute regarding business conducted between Acme and Google it seems surprisingly restrictive to claim I can't work with Acme's lawyers on a lawsuit against Google just because I took an exit package from Google a decade before the matter in dispute arose.

Since this bug in the contract is hypothetical—I don't have any particular plans to get involved in a lawsuit against Google—it's not worth six figures to me not to sign the agreement, or to go track down an employment lawyer to explain why the paragraph doesn't work the way I'm reading it. If the issue comes up, I'll let the attorney who wants my input figure out what it means.

Catter's Box

Thursday, October 30th, 2025 09:51 am
flwyd: (smoochie sunset)
The thrashing tail and butt wiggle before they pounce on a toy is a cat's batting stance.
flwyd: Google logo (google logo)
Two identical-looking envelopes came in the mail today from Health Equity/Wage Works. One contained information about open enrollment in Google's health plan. The other was information about signing up for COBRA coverage once the Google-paid insurance stops at the end of October.

(COBRA would cost a little over $2,000 per month in just premiums for the two of us. That's as much or more than the total estimated annual cost of marketplace plans we've seen. "You can keep your insurance when you leave your job if you pay the full cost" isn't a great deal when your employer used "we have fancy health insurance" as a way to attract employees.)
flwyd: (intense aztec drummer DNC 2008)
People sometimes say that the last age-based American authorization—after being able to vote at 18 and buy alcohol at 21—is being able to rent a car at 25 (without extra insurance, anyway). They miss out on a later rite of passage: at age 45 health insurance will pay for a cancer-screening colonoscopy, once a decade.

The anesthesia used for a colonoscopy keeps the patient awake and responsive (cooperation is needed when sticking a camera up someone's butt), but the patient isn't able to form any memories for the duration. Since folks can't remember the actual experience of the procedure, the main thing they talk about is the preparation period, which requires making sure your whole digestive tract is clear enough to have a camera see the walls of your intestines. This involves a couple days on a low-fiber diet followed by a "clear liquids only" diet for a day and a half until the procedure. Starting the night before, the patient drinks medication mixed in Gatorade to accelerate the bowel movement process. So the main thing people remember about their colonoscopy is usually running to the toilet and sitting there while liquid poop shoots out their butthole.

I had a colonoscopy a decade ago when I was having mysterious issues swallowing and with acid reflux, so we were fishing around for any gastrointestinal trouble. I only recall a little of the liquid-poop experience. The main thing my long-term memory cached was feeling really weird about the fact that I was sitting up and talking in recovery and suddenly started forming memories again, like waking up without having been asleep. I also recall flying to Minnesota for a family reunion with a box of saltine crackers and a pound of lard. The reunion is famous for my dad's cousins making a huge amount of delicious food. And even though it's the upper midwest so it was probably low-fiber (they certainly don't use whole wheat for the pasta salad), the fact that certain foods seemed to mysteriously trigger symptoms and the likely presence of loads of milk products meant I was spreading lard on crackers while everyone else was eating the best of Norwegian-american cooking.

Now that I'm 46, I've got a routine colonoscopy today. With my swallowing problem solved, I was able to plan a much more enjoyable low-fiber diet. I hosted a birthday games party on Sunday, and made a big pot of chili with ingredients on the approved list: ground pork, wax beans, and carrots plus bell peppers and crushed tomatoes which weren't clearly excluded. Corn, onions, and (presumably) most beans were out, but it turned out quite delicious despite the untraditional mix. With good forward-thinking I opted for mild hatch chilis rather than any hot peppers :-) I also decided that birthday cake counts as low-fiber.

My day and a half of eating only clear liquids has been interesting. Monday night I was still digesting chili and barbecue, so I sipped Gatorade, chicken broth, and tropical Otter Pops while catching up on Burning Man email. I found it interesting that when I got up and wandered around I kept noticing all the snacks, with an almost-unconscious desire to reach into the bag and grab a pretzel or cracker. Snacking is a background process, and it felt unusual to keep blocking snackd from respawning.

After staying up way too late writing an email, I woke up at almost noon on Tuesday. I figured having only half a day out of bed was probably a reasonable way to avoid getting too hungry. Red and purple liquids are verboten, so my afternoon featured four cups of green or yellow Jell-O, plus water and a little apple juice. You can tell I'm 46 and not 4 or 6 because wow did my mouth feel overwhelmed by that sugar. Following that up with 28 ounces of Miralax Gatorade was pretty intense; a bottle of Gatorade on a hot road trip is refreshing, on an overhydrated stomach and a sugary tongue it's sickeningly sweet. For the "drink two 8-ounce cups of clear liquids" follow-up I went with warm water; I suppose all the sugar heightened my tongue's ability to notice the subtle tastes of city water.

One quirk of my body these days is that moving my back in a weird way can sometimes lead to an uncomfortably queasy feeling in my stomach and some acid reflux because my esophageal sphincter opens. My usual solution is to eat food until things settle down, either because my stomach has something to digest or because there's a piece of something blocking the sphincter. I was a little worried I wouldn't have this solution available during clear-liquids, but it only happened once and seemed to accept Gatorade as a solution.

Once in "liquid poop could come at short notice" mode, I decided to stay standing: I'd spent enough time on the toilet, and I didn't want my butt to be in a comfortable position in a chair for any sudden exits. I also decided to not start any tasks that would be difficult to suddenly break away from, so spent the evening and morning closing seven years worth of Chrome tabs on my work laptops so I can uncover any "oh, that's an interesting article I left open and should read later" tabs. I was reminded that I'd searched for some lyrics in March 2020 so I could write filk songs "I Just Touched My Face" (apologies to the Beatles) and following the Talking Heads' opening line "Home… is where I want to be." The early pandemic was too hectic to make time to actually write those songs, though, and by the time things settled down a joke about not touching your face was passé. I also realized that although I took a picture with some paracord in a hotel safe this July, I never did make a "Writing thread-safe code" meme.

Googlegeist

Tuesday, September 9th, 2025 11:01 am
flwyd: Google logo (google logo)
For many years, Googlegeist was Google's annual employee survey, asking about everything from productivity to feelings of inclusion. To make the survey as much of a census as possible, and thus have meaningful data at even the line manager level, Google leadership would make big and eye-catching gestures to encourage participation, from delivering cupcakes to the microkitchen with Googlegeist logos in icing to announcing they would dress up as a bear and ask a question at TGIF if their team had at least 90% 'geist participation. Googlegeist results drove real change; teams would form a committee to act on significant negative feedback, processes could change if "I'm not slowed down by unnecessary bureaucracy" or "Google is hierarchical in ways that affect me negatively" scored high enough in a team. Some of Google's early DEI work was driven by answers to the question "Google is a place where all types of Googlers can succeed," particularly when those results were sliced by self-identified race and gender categories.

In 2023, Googlegeist was changed from an annual survey to a weekly email, with two questions from the original survey presented weekly. This provides an ongoing "quick read" of employee sentiment, so leaders don't need to wait a year to discover their team isn't feeling productive. But it also meant that taking Googlegeist was no longer a shared cultural experience, something we were all doing together. Product area or team leads might share some Googlegeist results at a quarterly all-hands meeting, but we didn't have a company-wide TGIF devoted to how the company is feeling about itself.

Sometimes the weekly Googlegeist email timing has been pretty amusing, though. This week I was asked "Over the past month, my work gave me a strong sense of purpose." My work the past month has been (1) tell people that they're wonderful and I'll miss them after I leave Google and (2) volunteering at Burning Man to ensure people have a good time safely. So yeah, that's a pretty good sense of purpose. I think it asked the same question at the start of January 2024 when my work "over the past month" had been climbing volcanoes and swimming with manta rays and walking through botanic gardens in Hawaii.

Google Filk Songs

Wednesday, August 13th, 2025 01:27 am
flwyd: Google logo (google logo)
Google has several mailing lists where a very specific type of humor is considered on-topic. One of my favorite is dedicated to filk, parody lyrics to popular songs. I've archived my humorous songwriting and poetry, some of which has appeared previously on this blog. And of course I had to write a song about my own departure.
flwyd: Google logo (google logo)
Yesterday I announced that I am leaving Google through the Voluntary Exit Program offered to my division. I don't think I've cried this much in one week since I was a kid. I hadn't been intending to leave just yet, and I'm going to miss a lot of people and activity very dearly. But my tenure level means I'll get nearly a year's worth of salary to not work, which sounds to me a whole lot like a year of paid vacation.

I know that I was pretty well regarded at Google (I've made more memes than any human at Google, and I've got a colorful reputation in the Boulder office). But I didn't expect over 1,700 people to follow the link to my farewell essay in the first 24 hours. I've gotten dozens of email and chat and meme comment replies to my message, and my farewell message seems to have resonated with a lot of my colleagues. It makes me cry and smile at the same time.

When Google's first large-scale layoffs happened in January of 2023, I was pretty upset. All these people suddenly disappeared, and I couldn't say goodbye to them. And imagining what I would feel in that situation, I would be totally distraught to leave without being able to tell everyone what was on my mind and share a moment with each other one last time. I doubt I'd get a better opportunity to leave on a high note, so here I go into the unknown. In 2009 I quit my job with a plan to travel for the summer, which was a great experience. This time I haven't had any time to make plans beyond what I already had in place—I'm driving to Burning Man on what would be my last day—but after 15 years at a high-growth tech company I've got enough time to both plan some adventures and then have them.

As time goes on, I'll share some more reflections about my time at Google, the changing techno-social landscape, and whatever else is on my mind. For all the Googlers who are now following me via RSS, welcome to my blog and keep doing excellent work.
flwyd: (1895 Colorado map)
Last week was Citzens' Climate Lobby's annual lobby day on Capitol Hill. 850 volunteers held over 400 meetings with Congressional offices in one day. Our approach to lobbying is built on respect and relationships. Even when we're working with an office that's opposed to the policies we support, we want to make sure they have a good impression of our organization. Staffers in DC move around a lot, so we never know where we'll next meet with someone.

I was part of a team last week that benefited from this relationship-building work. Meeting with a new Member of Congress, we had a few signals about their position based on bills they'd been involved with in the first six months, but we weren't sure how our organization and our message would go over. But when we sat down the staffer and asked if they were familiar with CCL, they said they'd spent four years with another Congressional office that had a reputation for climate leadership in the Republican party. That member retired, and this staffer was interested in learning more about issues in the American West, so jumped on the opportunity to work with a new western office. Although none of the people in the room had met this staffer, we already had their respect. We were able to quickly find common ground, and believe this is going to be a great office to work with into the future.
flwyd: (cthulhufruit citrus cephalopod)
Most of this four-day weekend was devoted to bottling homebrew. Since yeast do the real work, most of the human labor in home brewing is cleaning. There have been four carboys sitting on the kitchen counter for four years and change because every time I would clean the kitchen on a Saturday with the goal of bottling on a Sunday, I wouldn't end up with the energy to follow through the next day. Then a week later, the kitchen would be dirty again, and it would be a month or two before there was time to consider the project again. Since this is the first Independence Day weekend in three years that we haven't gotten a shelter cat, we coordinated with Kelly's friend Jim to come over on Saturday to help. Having an external party deadline, plus two weekdays off work, helped motivate some house cleaning, and we were almost ready to go when he arrived.

The pending potables dated back to 2018. I made a cyser with apple cider from a community pressing that fall. I didn't really procrastinate on bottling this one: I siphoned out several bottles over time, but they all had too strong of an alcohol flavor that I like to describe as "The yeast are angry." I think this is due to fermentation at too high a temperature (my house doesn't have a great cool place), which releases a lot of unwanted esters. Advice from the Yeastherders Gatherum had been to just give it more time;. After six years on the counter, when I brought a bottle last year, it was really well received. Good things are worth waiting for.

While the cyser was in its early stages of aging, I successfully bottled at least twice. The straight cider from that year was bottled with no drouble. And the next fall I bought an all-grain system from a coworker. I made a dunkel weizen to learn how to do an all-grain brew, and bottled a month later. Awkwardly, I haven't done a whole grain beer since…

The bottling procrastination began with my red braggot misadventures in 2020. At the start of COVID lockdown I headed to the homebrew store for beer ingredients, figuring that being stuck at home would be a great opportunity to try some brewing. March and April 2020 turned out to be pretty distracting, and I didn't get around to cleaning the kitchen plus energy to brew until late May. I put the hops and red malt in the pot for half an hour, then discovered that my liquid malt extract had gone moldy while sitting around for two months. Not wanting to waste part of a brew, I switched my plan from a 50%/50% malt/honey braggot to a 3:1 or 4:1 mix with a little less volume and no aroma hops. 2020 continued to be distracting (remember doomscrolling?) so June rolled by without bottling, then July, and then the onset of "ugh, I cleaned the kitchen, I can't possibly accomplish anything else this weekend.

2021 brought a return to "go out in the world and do things. It was also a good year for apples in Boulder County, so I spent a weekend with good folks first shaking apple trees, then squishing apples. I got home Sunday night and put sulfites in five gallons of apple cider in a bucket and started a three gallon batch of cyser with a different honey. Monday night I pitched yeast in the cider, Tuesday we packed for Element 11, Utah's regional burn. Normally I would rack from the bucket to the carboy after a week or two. "We just got back from a Burn" is clearly not enough energy to clean the kitchen. The next weekend was also in energy recovery mode. And once again the cycle began. I finally had the time and energy to rack it to secondary two months later, probably on Thanksgiving weekend. And then I discovered that either the sulfites hadn't killed all the wild microbes, or the several inches of headroom in the fermenting bucket and a little unsanitary spot had allowed a significant layer of pellicle to form on top of the liquid. I was worried the project was ruined, but I racked it to a carboy anyway and planned to check the Internet for solutions. I put a quart of it in a separate bottle for investigation. I drank that over the ensuing weeks and it wasn't terrible, nor did I get sick. So now I just needed a plan for dealing with the pellicle.

2022 through 2024 continued to be distracting. I had a lot of vacation time saved up coming out of the pandemic, so I spent a lot of 2022 planning for, at, or returning from a fun adventure. In 2023 I got really into Parks on the Air, so any weekend with good weather was a lot more tempting to spend an afternoon playing radio than cleaning and bottling. 2023 and 2024's 4-day weekends in July were filled with Dead shows and new cats, and the November 4-day weekends had turned into "get ready for Advent of Code." I was at least responsible enough not to start any new homebrew projects while there were four carboys awaiting.

After twelve hours of moving fluids around, resterilizing equipment, and "relax, don't worry, have a homebrew," the complete bottle array looks kind of smaller than I'd imagined. The contents are pretty good, though. The previous night I racked the cider to the bucket, leaving the pellicle layer behind. I put a quarter teaspoon of potassium metasulfite in overnight, so hopefully that prevents anything from redeveloping in the bottle. The taste is quite dry and a little funky; it won't be to everyone's liking, but Jim liked it. The red braggot came out a dark amber, almost brown, with about 9% alcohol. It also left some interesting colors and shapes at the bototm of the carboy, and it's going to take several attempts to scrub the carboy completely clean. The 2018 cyser has mellowed pretty nicely and has a decent flavor, while packing a punch at 15% alcohol. The 2021 cyser is probably the best of the bunch: it started at 14% potential alcohol, but finished with 3% remaining: I used a British ale yeast instead of a wine yeast, so it can't hit ABV in the teens. This means it's remarkably sweet, preserving a lot of they honey flavor (though not so much of the apple). It also finished remarkably clear, a light gold color you can see through, while the 2018 cyser is a dark orange. I suspect the color difference is due to the honey: an American blend for 2021 and Brazilian wildflower in 2018.

Making mead with ale yeasts is something I'll have to pursue further. I'd been following the practices of other yeastherders and brewing with wine yeasts, which can generally process all the sugar you can pack in with honey. But a beer-strength yeast lets more sugars remain, better preserving the sweetness and character of the honey. Plus, I think there are more high-temperature ale yeasts than there are wine yeasts, for those of us without a cellar.
flwyd: melting clock detail from The Persistence of Memory (melting clock)
Last year I noticed that almost all the velcro hooks on my Timex Expedition watch band had been torn out. This wasn't entirely surprising; I've been taking the watch off every night and putting it on every morning for more than a decade. At one point I thought the battery had died, so I unscrewed the back to find out what coin cell number it had; when I reassembled it I discovered that merely repositioning the battery gave it several years more life.

I checked the Timex website, which has product listings for dozens of straps, almost all of which were marked as unavailable. I entered my email to be notified when the strap was back in stock, but six months later the velcro had become dangerously un-clingy and still no luck, so I bought a new watch of the same model. I think it cost $50, and I'm pretty sure I paid about $20 for the original in the early 2010s, so there's an inflation datum for you.

The new watch works the same, except I noticed the Indiglo feature wasn't very helpful: it illuminated the LCD, but just as a big glowing rectangle: no digits were visible. Still, a functional watch in daytime or dusk.

Earlier this month I attended a pagan event in the California redwoods. Wanting to check the time while singing songs around the campfire, I hit the Indiglo button on my year-old watch, but this time it erased most of the LCD segments on the face, leaving behind something resembling an inverted L|. Fortunately, I kept the non-clingy watch in my ham radio bag, with time set to UTC. I was able to switch watches for the remainder of the trip, careful to ensure that disconnecting velcro didn't come off my arm entirely.

Back at home, I unscrewed the back of the new watch. I removed the battery, which has a significantly more complicated placement than the previous decade's model. It also requires shorting the battery to the rest of the watch, which I've yet to successfully do, so I've now got a non-functional watch. But fortunately, this meant I had a new watchband I could put on my perfectly-functional old-watch. Still waiting for an email on Timex about the ability to do this the easy way…

Head Cold

Saturday, May 3rd, 2025 10:29 pm
flwyd: (intense aztec drummer DNC 2008)
I think the worst thing about having a head cold all week isn't the sinus pressure on my skull, or the way the tip of my nose now feels like sandpaper. It's having spent a whole week breathing through my mouth.

I'm now on the "feeling better, will be ejecting mucus for another month or two" stage. The home test says I don't have covid or influenza. But this is the second time in four months that I've been absolutely hammered by this nastiness. Did the common cold get stronger, or did I just get weaker?

Morse or Less

Monday, March 31st, 2025 09:48 pm
flwyd: (parks on the air)
Amateur radio operators are probably the only folks who regularly use Morse code in the 21st Century. Long distance communication today generally happens by voice or digital data; and often voice encoded as data. Militaries stopped training radio operators in Morse code. The final US telegram was sent in 2006; in India it was 2013. Britain's service ended in 1981. Those articles report that in 1920, Western Union charged 5 cents per word (when a nickel was worth something) and the Royal Post Office charged a penny per word, with an exchange rate of about 3 pence per nickel. Back when phone plans didn't just bundle unlimited SMS, it seemed 5 cents (at 2005 value) was the going rate… with space to fit about 20 short words. And anyone with access to the Internet has been able to send thousands of words for free via e-mail for more than three decades.

A couple things keep the dits and dahs of Morse code flowing on the amateur radio airwaves. One is tradition: it's a hobby stereotypically practiced by old dudes, and they had to demonstrate Morse code proficiency to get their license (prior to 2007), so there's a comfortable feeling to it, even if they're not banging out the QSOs with a Vibroplex bug on a Hallicrafters solid-state transmitter.

But it's not just nostalgia that keeps Morse code alive. There are practical advantages to Morse and Continuous Wave. CW puts all the transmitter's power into a narrow bandwidth which is either on or off, and the duration of those emissions create the code pattern. This makes CW ideally suited for low-power long-distance transmissions, also known as "weak signal". While clear-channel AM broadcasters used 50 kilowatts to carry Art Bell's voice across the Great Plains, Art as ham operator W6OBB could have conveyed a message just as far with a one or two watt CW signal. It would've taken a lot longer to relay the caller's story about an alien abduction, though. The AM signal spends half its power on the carrier wave, and the other half is split between two identical modulated waves above and below the carrier frequency, spreading out 5 kilohertz in each direction. The CW signal fits in 100 hertz or so, so it's more like a laser pointer than like a lightbulb.

That narrow bandwidth also means the receiver can listen with a really tight filter. Lower-frequency radio bands often have a lot of static; for an example listen to your AM radio during a summer night with a lot of thunderstorms, or listen to the 75 meter band almost any night of the year. (If you enjoy eavesdropping on colorful characters, the latter offers hours of free entertainment.) The wider the bandwidth of the receiver, the more atmospheric static you'll get in your audio signal and the harder it will be to hear what anyone's saying. But with a CW filter that's only a few hundred hertz wide, you can pick out enough of the dits and dahs to understand the transmission.

Finally, the technology for a CW radio transmitter is about as simple as you can get. A straight key or an iambic paddle closes an electric circuit to send a signal; releasing the lever opens the circuit to stop transmitting. The rest of the circuitry doesn't need to modulate or demodulate the signal, so a student or tinkerer could conceivably start from scratch and end up with a working radio. The cheapest CW transceiver kit I've seen is $15 (but it doesn't have the ability to change frequency). And any mechanism you can think of to complete a circuit can be made into a CW key. (I'm interested in trying the QLF sewing machine pedal, and the nail clipper key should be quite portable.)

I realized the value of CW when I was preparing for a trip to Hawaii. It took a lot of work to pull off ten single-sideband (2.5 kHz bandwidth) contacts in two hours with a 45-watt amplifier, since it's 2500 miles to California. I realized I could probably have lightened my load and still pulled off the activation with a 5 or 10 watt radio and morse code. I even got a light-weight paddle and spent time on the airplane with a Morse code tutor. I didn't end up sending any CW from the island, which is probably just as well… I might have been able to copy at five words per minute.

Last year I set a Parks on the Air goal of making at least one CW contact with each activation. I definitely didn't hit the "every activation" goal (particularly in the fall and winter months when I preferred keeping my gloves on to hit the mic's PTT button), but I did manage to make over 133 CW contacts from more than 20 parks. Sunday evening POTA activations also proved a good opportunity to participate in the weekly K1USN SST slow-speed CW "contest". I was pretty reliant on a decoder app, but I could reliably send at 12 to 15 WPM and a healthy Farnsworth spacing. I can recognize my own WT0RJ callsign by ear with no problem, and CQ SST stands out quite clearly. Visually following the app makes it hard for me to also focus on listening, so recently I've taken to tuning to a station calling CQ, getting their callsign from the app, and then waiting until I can pick out all the characters by ear before responding.

I've also recently gotten a chance to be hands-on with the hardware side. Last year at a hamfest I bought both a Brown Bros CTL-B combined paddle and straight-key crafted in the late 1970s (photo) and a light-weight 3D printed paddle kit made my a local ham. The former doesn't have an output jack, just screw terminals. This February I finally got around to taking it to my office's maker space to wrap three wires around the terminals and inside a 3.5mm jack. The hefty base and hard plastic paddles make for a noticeably different feel when operating. I need to experiment with the screws to find my ideal motion range, but it definitely feels more precise. A few weeks ago I also finally got around to constructing the 3D printed kit. I almost screwed it up by soldering too long a tip on the short wires, but I managed to route everything in the box without impediment. For a base I picked up a very thin sheet of steel which seems to stay with half sitting under a radio, so I can stick the magnetic feet to it and keep the paddle from sliding all over the place while I swipe left and right to call CQ.

Now I've got all the technology, I just need to make time for dedicated practice…
flwyd: (red succulent)
An edited version of this article appeared in this moth's BARC Bark, the Boulder Amateur Radio Club newsletter.

At the beginning of February the Parks on the Air website informed me that I’d made contact with one thousand parks. This milestone is celebrated with the Western Prairie Fringed Orchid Hunter Award, complete with a colorful PDF I can download, print, and frame at my own expense. It could take a position on the wall on my shack next to my Wiggins Acalypha Hunter award for 700 parks, my Oasis Activator award for doing 20 activations at Sawhilll Ponds, and my Rover Warthog award for activating five parks in a single day. There’s only one problem: my shack is whatever picnic table I’ve found to set up my radio gear, so there’s no walls to hang a frame. Maybe I could nail my Howell’s Spectacular Thelypody Hunter award (500 parks) to a tree and hang my end-fed from it.

In the 2010s “gamification” was a hot term in the tech world. Using elements from video games like high scores, streaks, profile avatars, badges, and leveling up tickled the human brain in ways to remain focused on using the app. Anyone who’s stuck with language practice because the Duolingo owl doesn’t want you to lose your streak has experienced the subtle nudge of gamification.

Amateur radio is of course no stranger to gamification. The first DX Century Club (DXCC) members were honored almost 90 years ago, and the hope of getting a few new countries in the log has driven many hams to innovate improvements in their antennas and station design. What’s new with the POTA awards system is the onramp: operators receive a digital award on their profile with just 10 parks, DX awards start at 5 countries, and the parks and QSOs counters go up every time they load their profile, and the page has more than a dozen charts showing progress towards different awards. Progress is tracked almost instantly and with minimal bookkeeping requirements: no need to wonder when your QSL card from Rhode Island will arrive so you can finally claim Worked All States.

When people ask about my hobby, I often answer that I go to a state or national park, set up a ham radio, talk to people, and earn Fake Internet Points. The real reward, of course, is having fun outdoors. But I would be lying to myself if I said the fake internet points weren’t an effective motivator. With the Diamond Activator award (activating 50 parks) and over 5000 QSOs under my belt, I’ve been striving for some of the more challenging awards. The N1CC Activator award is my current target: activate 10 parks on 10 different ham bands. It may just be fake internet points, but it convinced me to experiment with portable 80 meter antennas and get my CW skill into good enough shape that I can work 30 meters. I’ve also made sure to get out to a park at least once each month for the last two years, just in case POTA adds a new award for that. Not bad for a pile of PDFs.
flwyd: (parks on the air)
2024 was my second year of frequent participation in Parks on the Air, a ham radio activity that involves setting up a radio and antenna in a state or national park, talking to people around the country and sometimes internationally, and earning fake internet points. I once again managed to do multiple activations each month and hit a few fun milestones.

I operated from 36 parks from 23 counties in Colorado, Kansas, Oklahoma, Arkansas, West Virginia, and Washington, DC. (I also joined two clubs in Virginia for Field Day.) In addition to over 3,000 contacts with stations in the mainland U.S. and Canada I talked to people in Australia, Barbados, Brazil, Ceuta, Chile, Dominican Republic, Easter Island, Ireland, Italy, Japan, Martinique, Mexico, Portugal, Puerto Rico, Spain, Sweden, Venezuela, Alaska, Hawaii, and boats and planes over the ocean. I made at least three contacts with every state and DC, and finally got a park-to-park with Rhode Island to fill the 51st slot on Worked All States. I made a park-to-park with every state but North Dakota and every Canadian province but Newfoundland and the territories in the north. And clever county-line positioning allowed me to get a pretty wild number of fake internet points in the West Virginia and Colorado QSO Parties.

On a trip to Hawaii in 2023 I realized the benefit of CW for weak-signal long-distance radio communication, so I set a 2024 goal of getting good enough at Morse code to make at least one CW contact with each POTA outing. I didn't stick to this practice in the latter part of the year, partly because I was worried about how well I could operate a paddle with gloves on, but I did manage 112 POTA CW contacts, plus a handful of contacts from home or work in the K1USN weekly Slow Speed Contest.

CW operating also enabled me to work the 30-meter band, which doesn't allow voice or other wide-band modes. This in turn helped me to get about half way to the POTA N1CC award: 10 parks with contacts on 10 bands. 80 meters has been tricky there: the usually high noise floor means my 45 watt portable station is challenging to hear. I got a shortened vertical antenna for 80m for easy deployment in parks without good trees, but have only really been able to make good contacts when I can loft over a hundred feet of wire into trees. I got some arborist throw weights and proper slick ropes, which has worked a lot better than my original "eye-bolts on fishing line" that was remarkably good at getting tangled. I still use an adjustable vertical when I'm doing a quick activation—throwing a wire antenna over trees and getting it back down again at the end can easily add an hour of "not on the air" time to an activation. But when I've got both time and good trees, the elevated wire makes a significant difference in the number of contacts I can achieve. Shout out to the wide-branch deciduous trees in Arkansas and West Virginia: Colorado's ponderosa pines are a challenge.

Some stats, generally counting "2-fers" as a single contact:
ModeCount
CW112
FM27
SSB2943

BandCount
80m30
40m500
30m12
20m1687
17m223
15m182
12m114
10m304
2m22
70cm8

My StateCount
AR129
CO2267
DC12
KS46
OK59
WV569

UniqueCountMost common
Stations2203N6HU (12)
Parks663US-4559 & US-4572 (8 each)
Frequencies43314.242 (215)
States / provinces / regions85California (235)
CQ Zones144 (1601)
flwyd: (mathnet - to cogitate and to solve)
At the end of December I read Visual Thinking by Temple Grandin. Grandin is one of the most famous people with autism, or perhaps it would be better to say that she's one of the people most well-known for having autism. Grandin thinks in pictures, and Visual Thinking draws on her own mind, her experience working with others, and psychological research to talk about three different types of thinking.
  • Object visual thinking involves mental images of specific things or scenes. Thinking about airplanes involves recalling mental images of specific airplanes the person has seen, in person or in a photograph: perhaps a Boeing 737 or a Cessna 182. Temple Grandin is an object visual thinker, and famously designs livestock handling facilities by visualizing what an animal would see from a particular location.
  • Visual-spatial thinking involves thinking in relations, abstractions, and patterns. Thinking about airplanes might involve thinking about the general structure of an airplane—the fuselage connects to wings, the cockpit, tail, etc.—without thinking about any specific plane.
  • Verbal thinking involves words and sequences rather than images. Thinking about airplanes might involve the process of flight: boarding, taxiing, acceleration on the runway, liftoff, and so on.

The book's focus is on visual thinkers, people whose main mode of thought is either object-visual thinking or visual-spatial thinking, particularly the former. People on the autism spectrum are often visual thinkers, though not all visual thinkers are autistic or vice versa and neither has a bright-line diagnostic. As an autistic child, Temple Grandin didn't learn to speak until later than many children, and she struggled in many classes in school because the material was presented for verbal thinkers and folks who could do abstract reasoning. She talks about finally connecting with coursework that made sense to her when she got to shop class, which is about working with physical objects. Another key educational experience was going to a boarding school which involved chores like caring for animals; lacking language, animals are naturally visual thinkers.

Grandin talks about the kinds of work that the three types of thinkers do well. You'll often find object visual thinkers in roles that require hands-on work: mechanics, machinists, drafters, builders, equipment operators, repair people. They're excellent at troubleshooting machinery, and they're able to tinker and build things with whatever supplies may be at hand. Visual-spatial thinkers are often drawn to engineering, mathematics, and computers; they design complex systems and find patterns in the world. Verbal thinkers are, naturally, drawn to work that's focused on words or sequential thinking. Lawyers, politicians, authors, and journalists are often verbal thinkers, and project managers can apply sequential thinking to make sure things happen on time. Grandin likes to talk about how the two types of visual thinkers are complimentary when designing something. Abstract visual thinkers can do all the modeling and calculations to ensure a factory building will be sturdy and that the machinery runs reliably. But a factory designed only by abstract thinkers likely won't run very effectively because they tend to overlook problems in the specific details of things work on the factory floor: the awkward movements a worker needs to do at the assembly line, or poor lighting of a workbench because something's blocking the lamps. Visual-spatial thinkers can make great electrical engineers, but you might want an object visualizer as an electrician. In the software space you might want an object visual thinker for a UI designer, a visual-spatial thinker writing code, and a verbal thinker as product manager, figuring out the user journeys the system will support.

A lot of the book talks about how modern American society is letting object visual thinkers down. A lot of schooling is designed for verbal or abstract thinking, and object visualizers struggle. Grandin reports that object visual thinkers often have a very difficult time with algebra, which they find too abstract and this challenge prevents many people from graduating from high school. However, many of these same people excel at geometry and trigonometry because their visual cortex can make sense of the relationships. "Let students take trigonometry if they fail algebra" might sound weird to folks used to the traditional progression of high school, but it might result in having a lot more Americans who are good at math, at least some parts of it. Grandin highlights George W. Bush's No Child Left Behind Act for making this problem worse: schools are graded and funded based on students' standardized test scores, so the incentive is to focus instruction on what will be tested. There's no standardized test that gives subjects a pile of lumber and a box of tools and asks them to assemble a chair, so when budget cuts come, classes like shop and music get taken away. Colleges and universities tend to make things even more abstract and more verbal, and the availability of trade schools, apprenticeships, and other hands-on education has been dwindling. Companies often have a college degree requirement, not realizing they may be cutting object visualizers out of the employment pool. Grandin decries that the result is an America where we're losing the ability to fix things.

This has political implications, too. (Here I'm building on Temple Grandin's foundation, she doesn't frame the book this way.) There are fewer narratives in American politics stronger than the middle class dream of success. After World War II, a man with no education beyond high school could get a good-paying job as a factory worker, a miner, an auto mechanic, doing appliance repair, or many other roles that object visual thinkers do well. These jobs offered the chance to own a home, raise a family, and enjoy leisure time; a combination that was uncommon for their parents' generation. As the 20th Century drew to a close, and accelerating in the 21st Century, the American economy shifted strongly to jobs that reward abstract or verbal thinking. Globalization sent a lot of the manufacturing jobs to lower-cost countries while domestic production became increasingly automated. (Fun fact: the U.S. is still the world's leading manufacturer, even though we employ a fraction of the manufacturing workforce we once did: American manufacturing is mostly done by machines.) Computers and the Internet gave powerful tools to abstract and verbal thinkers who are able to thrive in a service and information economy. High-tech manufacturing also made hands-on work more difficult: in the 1960s and '70s, buying a Heathkit stereo system and assembling it yourself could save significant money and teach you something useful at the same time, and you could easily fix it if a component failed. Today with high-tech automated assembly and microprocessors running everything, the cost to pay someone to fix a damaged Sonos speaker system is probably higher than the price of buying a new one. Starting in 2015, America saw Donald Trump's messaging resonate with older voters who work in these object visualizing jobs, and especially among voters who identify with such work that's been in decline like coal mining and assembly lines. Should it be any surprise in 2024 that Harris outperformed Trump by 13 points among college-educated voters, but Trump was up 24 points among men without a college degree? Millennials living in their parents' basements and playing video games all day was something of a running joke in the late aughts, but that also describes visual thinkers who've been left out of the modern American social structure and have grown to resent folks who were able to follow the abstract and verbal path through college and the modern hands-off economy.

I'd watched Temple Grandin talk about this book at Google, so I was curious how the ideas of a highly visual thinker would come across in a book, a naturally verbal and sequential medium. At times reading the book felt like listening to Temple Grandin give a talk; she often communicates in specific anecdotes, and related stories recur throughout the book. One of the big themes of the book is how people with different thinking styles can collaborate, and in the book she gives praise to her editor who's able to apply strong verbal thinking to organize the scattered notes and fragments that Temple gives her. This is certainly helpful in making this information about visual thinking accessible to verbal thinkers and readers. I found it interesting, though, that a book which is all about thinking in images and spatial relationships contains 400 pages of words and no photographs, illustrations, or diagrams. As a visual-spatial thinker, I was hoping to see some kind of 2D representation of how a visual thinker might operate. I wonder how many visual thinkers would benefit from learning this information, but get turned off by a book that's nothing but words.

I think I first heard about visual-spatial thinking, as distinct from object visualizing, from a previous Temple Grandin talk. I've considered myself on the autism spectrum for over 20 years, since I learned about Asperger's syndrome. When I heard Temple Grandin explain how her brain works I said "that's definitely not how mine works." While I can build intricate and elegant software systems, I'm perennially bad at building physical things. Cognitive tasks like mentally rotating a cube are challenging for me, but I can visualize a map of the whole world or specific areas, and at talent shows I like to recite every country in the world in geographic order. Unlike many kids with autism I didn't have any trouble learning language, and I always read above grade level. But I think my language use shows signs of spatial and abstract thinking: I've always loved puns, which feel to me like I'm demonstrating a multi-dimensional linkage between words that aren't present in the normal linear version. As a kid I often focused on the literal meaning of a set of words, much to the consternation of verbal thinkers who would say "you know what I mean!" (I still do this as an adult sometimes, but I have four decades of building a database of what people actually mean when they say something that a program would interpret differently.) I also tend to be very long-winded: an excellent verbal thinker can convey an idea without using a lot of words, while I tend to say or write down every sentence that comes to my mind related to a topic. Someone might mention a topic at lunch and I'll spend three minutes talking about all the things I learned from Wikipedia that are tangentially related. This is a bit like reading a map out loud: the river we were talking about touches another river, so let's row up stream and see where that one goes.

It's important for people creating tools and products to design with the different modes of thinking in mind. Much as a product that was designed and tested entirely by right-handed people is likely to be awkward for lefties, a product or process that was designed around the way verbal thinkers operate is likely to be frustrating to visual thinkers. Google Maps is an interesting example here. At the core, the data is inherently spatial: where is everything? But there are ways to expose that data that fit different thinking patterns. If someone wants directions from one place to another, Maps could show a path on a map and instructions like "take 6th Avenue to Broadway and turn south, then turn west on Alameda." This is great for spatial thinkers like me; I might ignore the written instructions entirely and just look at the lines on the map; if I take a different turn I can still reach the destination because I've formed a mental model of the space between here and there. Verbal thinkers might focus on the step-by-step instructions, but when they come to each intersection they'll have to figure out "which way is south?" So instead of cardinal directions, let's use left and right turns. Object visualizers still might have trouble, though: the map is an abstract set of lines and rectangles that can be hard to turn into 3D space, and the turn-by-turn instructions are a bunch of street names and numbers that need to be kept in order: "do I turn on Alameda before Broadway, or is it the other way?" So Google Maps recently added navigation by landmarks: "turn right after the McDonalds" and "turn left at the second traffic light." To get even more context, object visualizers can drop into Street View and see what all the buildings look like at an intersection. This multi-modal approach to directions is a big win over paper maps, when everyone but the spatial thinkers was faced with a daunting puzzle. The old stereotype of a woman in the passenger seat complaining that the man in the driver's seat didn't pull over and ask for directions might have been a conflict between verbal and visual thinking…

I was pleased to learn that object visual thinkers do share a trait with visual-spatial thinkers: we organize things by keeping track of their physical location. It might look like a random pile of papers on a desk to a verbal thinker, but ask a visual thinker to retrieve a particular document and they can probably find it quickly. But if a verbal thinker comes in and tries to be helpful by organizing all the papers into an efficient filing system the visual thinker will be unable to find anything, because it's not where they last put it. These two organization approaches are "piling" and "filing." My coworkers are often confused about how I can manage having 20 browser windows open with 50+ tabs in each. I find it quite easy: each window has a loosely-related theme, and I remember where on the desktop each window sits. When my workstation switched to Wayland, Chrome was unable to restore windows to their original locations when it opened and I was completely flustered; I had to spend 20 minutes a week figuring out which window was which and moving them back to their original location. On the other hand, I always wonder how someone who's only got one browser window open can keep track of what they were working on :-)
flwyd: (dogcow moof!)
The 80s kid in me thinks it's pretty weird that I spent more than half an hour downloading a LEGO Super Mario app, connecting to Luigi and Princess Peach via Bluetooth, and then installing software updates on large lego figures. By the time this was done, my nephew had lost interest in this activity.

Puts on grumpy old man pants When I was a kid, you could have set up a Nintendo and beat the first level of Super Mario Brothers in that half hour. Or you could've built half a lego castle.
flwyd: (1895 USA map)
Hey, I've got a favor to ask you. Please call your Member of Congress and ask them to support including the Energy Permitting Reform Act in the budget continuing resolution. This legislation is moving fast, so please make the call this weekend. I hear that House Democrats particularly need to hear from constituents about this. If you don't have Congress on speed-dial you can use the tool at https://cclusa.org/take-action. It will take approximately one or two minutes total.


Background: Democrats passed the biggest climate bill in U.S. history, the Inflation Reduction Act, this congress. But only about 20% of the IRA's potential benefits will be realized if we can't build clean energy projects and connect them to the U.S. electric grid faster. It currently takes federal agencies an average of 4.5 years to complete environmental impact assessments for large energy projects. This timeline can be sped up without negatively impacting quality: we want the same decisions to be reached—yes to good projects and no to bad projects—faster. This July, the Senate Energy & Natural Resources Committee introduced a bipartisan bill to address some of the problems which unnecessarily delay energy project; this bill passed through committee on a 15 to 4 vote and has broad support in the Senate. With a divided Congress the bill is naturally a compromise, and does have some provisions about fossil fuel permitting. This led many environmental groups to reflexively oppose the bill when it was announced. However, more than 95% of projects waiting to be built are clean energy projects, so if we make the process for permitting (or rejecting) all projects faster, clean energy will outcompete and replace fossil fuel energy. Careful modeling indicates that the Energy Permitting Reform Act will have between a modest climate benefit and a large climate benefit by 2050, the typical target date for net-zero emissions. Additionally, many of the fossil fuel pieces of the bill are things that the Trump administration is likely to do anyway, so please encourage your Democratic House members to support this bill, rather than getting the fossil fuel parts without the clean energy parts next year.
flwyd: Colorado I voted sticker (I voted Colorado)
It’s poetic that U.S. elections happen in the autumn: the civic work we did throughout the year gets harvested, the campaign leaflets are raked up, and the promises of the old year are composted to provide fertile soil for the policies of the new year. Following Celtic traditions, many Neopagans see Halloween/Samhain as the time when the king dies, to be born once again on the winter solstice. In the American political calendar, the time between the two is the lame duck session, when the old symbols of The People’s Will harvest the last of their legislative crops before this political will is reborn, sometimes into the same physical body and sometimes into a new human who shall carry the charge.

As Joe Biden's hero's journey draws to a close America begins a journey through the underworld. If we support each other through the time of darkness we will emerge we will emerge stronger, ready to till the fields of democracy once again.
flwyd: (daemon tux hexley)
It's October, which means I'm now allowing myself to start scheming about Advent of Code 2024. The last four years I've taken it as an opportunity to learn a new language. This year for some reason I'm inspired to learn a stack-oriented language, so I've been playing with PostScript. The world has generally moved on from PostScript: it gave birth to the wildly-popular PDF format without quite as much "Anything goes in this Turing-complete document presentation language," and even the latest version of macOS Preview.app can't read PostScript files. But if you set aside the fact that a majority of the language builtins are designed for using graphics, text, fonts, and printer hardware, it's a pretty slick language. You've basically got two things available: a stack of data and operands and a stack of dictionaries for dynamic name lookup. Both the programmer and the computer use basically the same model for evaluating code: read a token; if it's data then push it on the stack, if it's executable then run it, reading from the operator stack and writing to the same stack.

Programming language tutorials, particularly for functional languages, have a strong affinity for calculating the n'th Fibonacci number, but let's generate the whole sequence by just calling the same "function" over and over again (== is "print the source representation of the object on top of the stack and GS> is the Ghostscript prompt):
GS> /fib { 2 copy add } bind def
GS> [ 1 1 fib fib fib fib ] ==
[1 1 2 3 5 8]
GS> [ 1 1 15 { fib } repeat ] ==
[1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597]

Stack-based languages can have pretty simple syntax rules. That [ ] array syntax isn't "parse elements between the brackets as an array." Instead, the [ operator pushes a mark onto the stack and the ] operator builds an array with all the items on the stack until the first mark. Everything between the brackets is just normal PostScript code being executed on the stack. The following code builds an array of increasingly nested empty arrays by copying the whole array so far:
GS> [ 5 { counttomark [ exch 1 add copy pop ] } repeat ] ==
[[] [[]] [[] [[]]] [[] [[]] [[] [[]]]] [[] [[]] [[] [[]]] [[] [[]] [[] [[]]]]]]
% Or if you prefer some non-empty values to help read
GS> [ 42 5 { counttomark [ exch 1 add copy pop ] } repeat ] ==
[42 [42] [42 [42]] [42 [42] [42 [42]]] [42 [42] [42 [42]] [42 [42] [42 [42]]]] [42 [42] [42 [42]] [42 [42] [42 [42]]] [42 [42] [42 [42]] [42 [42] [42 [42]]]]]]

I've heard that some functional programming devotees might think of the non-negative numbers as a sequence of nested empty lists…

In PostScript, procedures are just arrays with the executable bit set, and you can construct and manipulate them as arrays. {} is syntax for an executable array, [] is syntax for a regular array, and cvx converts its operand to executable:
GS> { (hello world\n) print } exec
hello world
GS> % same thing:
[(hello world\n) (print) cvx] cvx exec
hello world

Since a procedure is just a mutable array of things to do, you can replace things in that array. Here's a self-modifying procedure that increments the first value inside itself, similar to a static int in a function in C:
GS> /selfmod { 1 (caller #) print == currentdict /selfmod get dup 0 get 1 add 0 exch put } bind def
GS> selfmod
caller #1
GS> selfmod
caller #2
GS> selfmod
caller #3

Page 115 of Thinking in PostScript defines a procedure by name including some initialization code; it then redefines itself without the initialization code the first time it's run. (The fact that the book is PDF file instead of a PostScript one says something indicative about the status of PostScript in the modern world.)

While PostScript has a couple hundred operators that are part of the language, a lot of those are for doing things like drawing on the page and selecting fonts. The parts of the "standard library" for working with strings and arrays is pretty spartan: even concatstrings is a Ghostscript addition, and I think people copy/pasted their own concatenation function all over the place for years. Since my Advent of Code interests don't include "Let's re-implement parsing a variable-width text file into fixed-size mutable strings each night," I've been getting some practice with the language by writing some core library functions that I'm certain will be used frequently.

I was about to work on the functional programming standbys like map and reduce, but I realized that with arrays constructed by "run all the code between brackets, then move everything from the stack between those brackets into an array" that having a separate function for map would just be extra noise and the basic iteration operator does the trick. Here's the PostScript equivalent of myarray.map { x -> x + 1 } and mydict.mapValues { i -> x * x }.
% Add 1 to each element of an array:
[ myarray { 1 add } forall ]
% Create a dictionary with the same keys as mydict, but square the values:
<< mydict { dup mul } forall >>

reduce (or fold depending on your dialect) is similarly straightforward if you supply with the accumulator rather than using the first array value. Here's myarray.reduce(0) { x, acc -> x + acc } (sum) and an implementation of myarray.all { x -> x % 2 == 0 } (are all items are even?).
0 myarray { add } forall
true myarray { 2 mod 0 eq and } forall

None of these need special handling for empty collections. They also work to iterate through bytes of a string (though there doesn't seem to be a short way to construct a string from an array of bytes). The all implementation can become an any by switching true to false and and to or. all becomes none by adding not before and. Short-circuiting can be added with dup { exit } if after the and/or.
flwyd: (McCain Palin Abe Maude Simpsons)
Civilization, in fact, grows more and more maudlin and hysterical; especially under democracy it tends to degenerate into a mere combat of crazes; the whole aim of practical politics is to keep the populace alarmed (and hence clamorous to be led to safety) by menacing it with an endless series of hobgoblins, most of them imaginary.
H. L. Mencken, In Defense of Women
flwyd: (farts sign - Norway)
My employer-sponsored health plan has a "specialty pharmacy" insurance which is separate from the ordinary pharmacy benefits. Painkillers for surgery post-op, antibiotics when you're sick, prescription NSAIDs for chronic inflammatory disease, and all those other medicines that come in an orange plastic container are reliably dispensed by my local King Soopers pharmacy with what I would describe as a high level of competency. Other than "we haven't filled it yet, can you come back in an hour" I haven't had any problems acquiring or paying for any of these medications for fifteen years.

The "biologic" disease-modifying drug I take for psoriatic arthritis, on the other hand, is considered a "specialty medication" which means it's paid for by CVS Specialty Insurance, filled and delivered by CVS Specialty Pharmacy, and picked up at my local CVS Pharmacy. Despite all having the word "CVS" in the name, as far as I can tell they're three separate entities who are almost incapable of coordinating with each other.

Drug manufacturers have learned that they can charge a lot of money for biologics. But if they charge too much money, patients with a 10% copay will balk at the price, avoid filling the prescription, and the drug company will miss out on the other 90% that would've been paid by insurance. So they came up with a way to hack the U.S. health payment system: offer patients a "co-pay assistance" card, which is basically a persistent coupon lowering your out-of-pocket costs to almost nothing. Patients will then keep filling the prescription because it's basically free, leading to something of a principal–agent problem where the person making buying decisions has no incentive to consider the cost of the item. My employer ends up footing the bill, but I'm only annoyed with this situation in principle: in practice I get free drugs. (My employer benefits too, because I was not very productive when my symptoms were causing problems and I wasn't taking the drugs.)

In late January or so of this year, I received notification that starting April 1st, our CVS Specialty Insurance plan would no longer cover Humira—the name-brand adalimumab—and would instead be covering Hyrimoz, a cheaper generic adalimumab. This seemed like a bit of an unfair move, since employees can only change decisions about health care plans near the end of the year, but as a fan of generic medicines this seems like a sensible choice. However, although this change was announced in January so people could start worrying about it, we couldn't actually take any action like getting a doctor to change prescriptions for more than a month. Come mid-March I called CVS Specialty Pharmacy to fill my new Hyrimoz prescription, but was told that since CVS Specialty Insurance didn't cover it until April 1st I couldn't actually place an order until April (including "place an order in March for April delivery"). This was rather inconvenient, since I was leaving town for two weeks starting April 1st and didn't want to spent my road trip vacation arguing with pharmacy customer service people when things would eventually go awry. The customer service rep did inform me that I could set up the co-pay assistance card in advance, though. After several attempts to use the drug manufacturer's website that had some technical hot mess I can't recall, I finally got a PDF that had two sets of discount code numbers on it, one "for NDC starting with 61314" and one "for NDC starting with 83457." As a health insurance policy holder I still have no idea what NDC stands for, nor how I would figure out which of those two apply to me. I relayed this to the person at CVS Specialty Pharmacy who suggested she take down both sets of numbers and put them both in their system so they could figure it out once the prescription actually gets filled.

Come April I was able to order a 3-month supply of Hyrimoz, plus a bag of alcohol wipes and a sharps container. I was somewhat surprised that the medication was delivered without much issue, given my prior experience of organizational incompetence ordering Humira. When I tried to pick everything up, though, the retail CVS Pharmacy folks were getting some indication in their system that they shouldn't hand over the sharps container and alcohol swabs, so I walked away with a couple thousand dollars of medicine and not ten dollars worth of common medical supplies ¯\_(ツ)_/¯ (It only took a day or two for them to realize I could take a sharps container to dispose of the future medical waste they handed me the previous day.)

A few weeks later, someone from CVS Specialty Pharmacy billing department called and informed me that I still hadn't paid my copay for that order. I was surprised, since I'd given them all the information on the card which claimed my copay would be zero dollars. I think we discovered that there wasn't a card on file, so I gave both sets of numbers again and the rep said she would rebill. Problem solved? Hardly. I don't recall the exact timeline, but when I attempted to refill the prescription in the early summer I discovered it was on hold because the prior order hadn't been paid. So I called CVS Specialty Pharmacy; we went through the numbers again, and she determined that based on the diagnostic code from CVS Specialty Insurance the code for the wrong NDC was in their system and she didn't have the other code, so I re-provided all the digits. After some time on hold she confirmed the order had been rebilled.

So imagine my surprise this weekend when I was sorting through an accumulated pile of mail and discovered that the charge from April had been sent to collections. I called CVS Specialty Pharmacy this morning, and pointed out they had a discount card on file. The representative said they would rescind the bill from collections and rebill insurance. Will CVS manage to pay itself this time? Who knows! The two companies seem to share the same name but otherwise lack the ability to communicate effectively.

Payment aside, order fulfillment and delivery is also a comedy of errors. In early September I received a text message from CVS Specialty Pharmacy that said my prescription was ready to be refilled, but when I went to CVS Specialty Pharmacy's website it said I couldn't refill for another week and a half, and once that time passed I could only schedule delivery for another week and a half later. When I arrived at the retail CVS Pharmacy I was handed a large paper bag that was wet and soggy on the bottom. This contained a cold bag with three ice packs and a single box of medicine, 90 alcohol swabs, and three sharps containers. It's unclear to me whether the Specialty side (which distributes this temperature-controlled medication from a warehouse somewhere) or the retail side (which keeps medicine in the refrigerator until I pick it up) were the ones who decided to keep sharps containers and alcohol swabs should be kept refrigerated, but I'm quite glad I didn't pick this one up on a bicycle commute day because that bag was a wet mess. More importantly, I was rather miffed at CVS Specialty for taking my "Please send me three months worth of medicine, alcohol swabs, and a sharps container" into one month of medicine, a year's worth of sharps disposal, and three years worth of swabs. The order sheet says "2 ml" of Hyrimoz, and each box contains two 0.4 ml pens, so it would take two and a half boxes to match two milliliters of medicine; I only got 0.8. I attempted to call CVS Pharmacy retail about this problem, but every attempt to use their phone tree's "Leave a voicemail and we will call you back" feature resulted in the computer voice saying they were sorry. So I stopped by the pharmacy in person to tell them (1) file a ticket to get your phone system fixed and (2) you didn't give me my whole order. The pharmacist explained that they could view and dispense CVS Specialty Pharmacy orders but couldn't do anything else like investigate why it was wrong, so she gave me the phone number for Specialty. You guys are both CVS Pharmacies, why can't your computers talk to each other? Another call to the other CVS turned up the fact that two prescriptions, one for a one-month supply and one for a three-month supply, were both in the computer system, and the system automatically selected the first and billed insurance for it. She said she put a note on my record to do the three-month supply next time, and assured me that I would be able to place that order in October. I've a rather sneaking suspicion that they'll manage to fumble something again and I'll have to take another adventure through their customer support lines to convince their computer that I'm eligible for more drugs before December. (I discovered my previous order sheet this evening which says it was filled for 6 ml, which would be a 10 week supply rather than a 6 week supply. I guess I shouldn't be surprised that CVS Specialty can't even get arithmetic right.)

I wonder if it's occurred to the folks who run my company's benefit plan that I'm not doing anything productive for the company if I spend half a day getting derailed by systematic incompetency every few months.
flwyd: (playa surface)
Between a sudden December in Hawaii, a two-week road trip for the eclipse, and two weeks lobbying about climate change and running around the hills of West Virginia, I used up all my vacation this year and could not go to Burning Man. One consequence of this decision is that this has been probably my most laid-back non-pandemic August since 2007. "I think I'm going to screw around on the Internet this evening" feels almost transgressive when I'm used to spending a week and a half between Dragonfest and Burning Man working on a long list of things that need to be packed, and another long list of things that need to be found and then packed. (Last year I realized I had no almost no unaccounted weekends for four months.)

After my first burn in 2004 I said "That was fun, but I don't know if I'll do it every year. But I'm going to make sure that if I don't go to Burning Man, I'll do something else cool instead." Usually the other-cool thing has been on or around the same week (visiting Iceland, getting married, taking photos of DNC protests, going to Norway…), so it's extra weird having already done the cool thing, and having burn week as just an ordinary time. I played a great softball game on Tuesday, and got a blinky lights, bicycles, costumes, and electronic music experience tonight with Boulder's Happy Thursday cruiser ride.

It's been so low-key that I didn't decide what I'm doing Labor Day weekend until a couple days ago. For months I'd been considering watching a different giant wooden man get set on fire, with Zozobra marking his hundredth anniversary in Santa Fe. I wasn't excited about how the logistics were looking, and have some things going on next week that would be awkward if I was fighting COVID after hanging out with 40,000 people.

This means instead I get to spend Saturday sitting on the Gilpin/Clear Creek county line so I can double my fake Internet points for the Colorado QSO Party, a ham radio event where Colorado stations try to contact other counties plus other states and outside hams try to contact as many Colorado counties and stations as they can. I got over 40,000 points by operating from a triple-county line in West Virginia in June; I'll see if I can beat that with more power and more operating time on just a double-line. In 2021 I hung out in the NCAR parking lot and then went for a hike with my handheld and later received a certificate for first place in the Single-operator portable QRP power category with a whopping score of 36. With high enough cardinality, everyone can be a winner.

I've heard that this year's Burning Man weather has been quite pleasant, after last year's adventure with rain and mud and 2022's excessive heat and dust storms. I would've been bummed to miss the paradise built in mud last year, but I'm feeling pretty okay with missing out this year. And as we say, next year was better.
flwyd: (smoochie sunset)
… the void cat stares back at you.

On the first weekend of last July we got Pearl from the Boulder Humane Society. A slim gray cat with splotches of white and dull orange, she might camouflage well in a boulderfield. They told us she'd probably had a litter of kittens, and had been sent from Texas, which apparently is the source of a lot of shelter cats. Yet another teen mother fleeing Texas for Colorado for better reproductive health care. A teen in cat years, she was long and lanky, with an unusual running gait of paws crossing in front of each other. It took some time to get her comfortable with close human contact.

As an adult Pearl is still long, but looks less like a teenager trying to grow into her own body. She's comfortable with her two humans, but on her terms: she doesn't like to be picked up and hardly ever sits on a lap, though she often sleeps next to us in the bed. A cat with strong boundaries, like Kelly's first cat Joan. She rarely meows. She's a clever problem solver and a determined huntress: she caught four mice in two days this winter. She'll do incredible acrobatic maneuvers to catch a hair tie, and after defeating it in fierce battle she may carry it to her food bowl before eating a bit. This cat is not food motivated, she's hunt motivated.

We've long thought that Pearl would do well with a kitten adopted sibling as a partner in play. Humans can only shoot so many hair ties before they need to go to work or keep fussing with a laptop. Two cats can chase each other up and down the hall any time of day or night. We needed to wait for the right time though, "We'll be out of town for two weeks later this month" isn't good "introduce a new cat" timing. As coincidence would have it, "the first weekend of July" is apparently cat acquisition time around here. Maybe it's because the 4-day weekend provides enough time to clean enough of the house that a cat's not immediately going to get into object-oriented trouble.

The first kitten we played with was very into us, determined to play, fine with being held, and even hung out in my lap despite all the excitement. Black with a white toe, a white patch on her belly, and two white whiskers like a Fu Manchu beard. It seems odd to decide to live with a mammal for more than a decade after just half an hour of play, but she's worked out well so far. She didn't make much noise at the shelter but boy howdy did she holler whenever we left the room as she was adjusting to the house. She's the least hesitant cat when exploring new spaces that I've ever seen: as soon as she can break through the threshold she's never passed before she makes a beeline for who knows where, only stopping to sniff around once she's well beyond familiar territory. Our catsitter dubbed her Little Miss Runs-Like-Water." Time cycles are shorter for juvenile mammals and she can quickly transition from chase-every-toy-around-the-room to curl-up-and-purr-on-your-feet. During the first night her territory expanded from the closet to the bedroom she tried to nurse my beard, longing for the mother cat she didn't have. She realized the beard won't bear milk, but she still goes after my armpits. Curling up and purring on my chest while I lie in bed is absolutely adorable, though.

I've long thought that philosophers would make good cat names. This rambunctious kitten didn't seem like a Lao Zi, but Nietzsche seemed like an excellent choice for a void cat intent on fearlessly seeking discoveries in a world much different than what her parents knew.

Integration of the cats took a couple weeks. Pearl isn't very food-motivated, so attracting her to one side of a baby gate with treats wasn't a reliable strategy. Nietzsche's first several adventures outside the bedroom featured a lot of exploring while Pearl watched with suspicion and disapproval. They would tolerate each other's presence for awhile, then Nietzsche would do something rambunctious like jump towards her, Pearl would start bapping, and hissing would ensue; back to the bedroom. Wrangling cats took up most of the energy of the evening, and would've been completely overwhelming without two people.

Over the last week they've finally warmed to each other. There's still a lot of wrestling and bapping, but it seems to be claws-free and neither cat seems particularly upset about it. Nietzsche still has no fear and will charge Pearl in surprise, Pearl will strike back, Nietzsche adopts a submissive position, they reach an agreement, then Nietzsche withdraws and plans her next move. They'll both chase each other and can happily relax within a few feet of each other. They've got some time before they start snuggling each other, but there was some motherly forehead licking last night.

So now we've got a cat with strong boundaries and a cat that loves to break on through to the other side. A watcher cat and a doer cat. An independent cat and a lap cat. A cat that will chase any toy and a cat that wants the hair ties to fly just so. We've got a yin cat and a yang cat.
March 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 2026

Most Popular Tags

Expand Cut Tags

No cut tags

Subscribe

RSS Atom
Page generated Wednesday, March 18th, 2026 08:40 am
Powered by Dreamwidth Studios