Charlie Park!

(or, rather, his tumblelog)

A mid-twentieth-century carved wooden rocking chair by Sam Maloof.

Sam Maloof’s rocking chaise lounge chair

Much of [being a good] manager is not dissimilar from being a good partner or friend. Both involve active, empathetic listening, and a decentering of one’s own experiences to coach and mentor other folks instead of just waiting for a chance to tell our own stories.

Brook Shelley

A RegEx To Help You Move From Prop-Drilling In React To Using The useContext Hook

I added hooks to my app a while ago, but hadn’t gone through to refactor a number of places where I was drilling props from one component down through to a component many layers deep.

I wanted to see which properties I was passing along a lot, to see what some of the more common offenders were, so I could move them into useContext hooks.

In VSCode there’s a really handy global regex search. Just select the last two options from the search bar ("case senseitive" and “regex”) and paste this in:

(.*)=\{\1\}

The results will look something like this:

A screenshot of VSCode with a search term and its results showing React code.

The regex is doing this:

(.*)"Capture some string of text …"
=\{"… followed by an equals sign and an open bracket …"
\1"… followed by the same exact string of text …"
\}"… with a closing bracket following it."

Obviously, some of the instances that match that pattern will be legit. But if you’re seeing a lot of the same ones over and over, they might be good candidates for moving either into a ContextProvider or closer to wherever you’re using them.

So. Go refactor. Have fun.

(Side note: 485 results in 58 files. Merp. Good news, though: it’s getting better.)

A black-and-white image of four World War 2-era women on a runway, walking away from a B-17 bomber.

Frances Green, Margaret (Peg) Kirchner, Ann Waldner and Blanche Osborn (members of the WASPs) leaving their plane, “Pistol Packin’ Mama”

A Solo Circumtambulation

I watch polls and election returns the way many people watch sports. This year’s been an especially tense one for me — although I had every expectation that Trump would be beaten, I also had every expectation that the counting of ballots would be delayed in critical states, and that I’d be in a constant state of refreshing various news sites, state Board of Election sites, and Twitter.

So I decided to take a few days away from my screens and to head to Mt. Tamalpais for some camping and hiking.

I was especially interested in doing a circumtambulation — a walk around Tam. I first heard of the idea in the book Walkabout Northern California, by Tom Courtney. He outlines a five-day, 56-mile hike that goes from Muir Beach up to Olema, then past Woodacre and south of Fairfax, then to Mill Valley and the Dipsea Steps, back to Muir Beach. Perhaps one day I’ll do that route, but it ends up straying pretty far from Mt. Tam proper.

I wanted to stay entirely on Tam itself, so I charted a one day hike of 18 miles. I didn’t have a camera with me (remember: no screens!), so I didn’t get any photos, but I wanted to describe the hike in case anybody else is looking for a route to circumambulate Mt. Tam.

Because Google Maps doesn’t always know what roads connect to what hiking trails I have to show this as a few different maps, but here’s my route:

Essentially, here’s the route:

Pantoll → Old Stage Road / Old Mine Trail → Forbes Bench → Rock Spring Trailhead → Cataract Trail → Cataract Falls → Mickey O’Brien Trail → Barth’s Retreat → Potrero Meadows → Rifle Camp → Northside Trail → Inspiration Point → [optional side hike up to crest of Tam: Eldridge Grade (up) to East Ridgecrest Blvd and then back] → Eldridge Grade (down) → Indian Fire Rd → Hoo-Koo-E-Koo Rd → Old Railroad Grade → Hoo-Koo-E-Koo Trail → Matt Davis Trail → Bootjack → Pantoll.

All told, it was around 18 miles, but that includes the trip up to East Ridgecrest and back down, which added a little over 2 miles to the journey.

If you aren’t starting at Pantoll, I’d recommend parking at the Rock Spring Trailhead and going the route I outlined above, but after going down the Eldridge Grade for a bit, look for the sign for the Wheeler Trail at one of the turns. Take that down to connect with Hoo-Koo-E-Koo Rd. Wheeler isn’t marked on Google Maps right now, but I’ve marked it on this map. It cuts over a mile of fire roads from the hike, and has you descend through a cool redwood forest. Then, after you get onto the Matt Davis Trail, take the Nora Trail up to the West Point Inn and then take the Rock Spring Trail back to the Rock Spring parking lot. It’d be about 11.5 miles, mostly flat. Here’s a map of that route:

All in all, it was a great day on Tam. Be sure to take a lot of trail food and water — at least a liter for every five or six miles (per person).

Next adventure, I think, will either be biking on fire roads all the way up to Point Reyes Station, or possibly scrambling up some of the creeks on the west side of the Bolinas Ridge. They’re positioned just like Steep Ravine, and I have to imagine they have a similar climate. It’d be so fun to find a secret Muir Woods.

The Milky Way, stabilized, at Crater Lake. By Eric Brummel.

“Every one of us is responsible for the culture and reputation of our Army and the environment in which we work. If you become aware of any individual degrading another, then show moral courage and take a stand against it. No one has EVER explained to me how the exploitation or degradation of others, enhances capability, or honours the traditions of the Australian Army.

I will be ruthless in ridding the army of people who cannot live up to it’s values. And I need every one of you to support me in achieving this. The standard you walk past is the standard you accept. That goes for all of us, but especially those, who by their rank, have a leadership role.”

A gif showing a professor moving blocks to represent buildings of different heights, showing that buildings of different heights respond in different ways to earthquake waves of varying frequencies. A tall building will respond to low-frequency oscillations. A medium building will respond to medium-frequency oscillations. A short building will respond to high-frequency oscillations.

A demonstration of the various responses from buildings of different heights to earthquake waves of varying frequencies.

A set of six black Japanese bowls of different sizes, laid out on a table.

Ōryōki: “vessel that contains just enough”
(From POJ Studio, via Brook Shelley)

Just as we can’t train for a marathon in a weekend, we shouldn’t approach disaster-proofing our houses as a single, massive project — doing so will almost guarantee it doesn’t happen. Even small steps can make a big difference, such as stocking bottled water, changing your flashlight batteries (and knowing where the flashlights are), agreeing on an external meeting place with family members, programming key numbers into your phone. To put it another way: If you know your cholesterol level, you should also know where your water shut-off valve is.

Dan Kessler, CEO at Harbor, in Fast Company

A colorful image from a light microscope: A fluorescent turtle embryo

A colorful image from a light microscope: The dorsal view of bones and scales (blue) and lymphatic vessels (orange) in a juvenile zebrafish

A colorful image from a light microscope: An octopus bimaculoides embryo

The Nikon Small World Competition first began in 1975 as a means to recognize and applaud the efforts of those involved with photography through the light microscope. Since then, Small World has become a leading showcase for photomicrographers from the widest array of scientific disciplines.”

Lovers, 1988

by Félix González-Torres

Two clocks, side by side, showing the same time

Don’t be afraid of the clocks, they are our time, time has been so generous to us. We imprinted time with the sweet taste of victory. We conquered fate by meeting at a certain time in a certain space. We are a product of the time, therefore we give back credit were it is due: time.

We are synchronized, now and forever.

I love you.

Roadtrip

I’ve been meaning to get away for a solo roadtrip for a while. I’ve had a couple of short trips over the last couple of years, but they kept getting cut short — three- or four-day trips that were reduced to a single night away.

I made time at the end of last week for a solo trip, though, and had a great adventure. (Unfortunately, as you’ll see, my camera wasn’t the best. Even with a good camera, capturing the scale of the national parks I visited is tough. When you’re taking photos with a potato, good luck.)

A map of my trip, from San Francisco to a number of national parks, then back up along the coast.
Roughly the route I took, covering 2,200 miles, four national parks, and a trip up the coast, over four days.

I love being around people, and — especially during quarantine — miss being with friends more. But there’s also something great about getting away by yourself. I wish I could say that I had some sort of deep contemplative epiphany, but it’d be unfair to set that up as an expectation of a trip like this. Mostly, I just wanted to see some national parks that I haven’t seen since I was a teenager. (We’re planning another cross-country drive this winter as a family, so this was also a bit of a scouting run.)

I got accustomed to long days of driving this summer, during our inagural cross-country trip (which I should write up notes on at some point; it was great); this trip only reaffirmed that, yes, I like driving, and no, long distances aren’t a problem. The four days of this trip saw drive times of 12 hours, 4 hours, 17 hours, and 8 hours. That third day was a doozy.

Day One: SF to Zion

I’d intended to leave at the crack of dawn, but had a few projects to wrap up before I could leave. I finished them up around 10, and was able to pack up and get out the door just after lunch. Driving on Route 5 was easy, but — hoo, buddy — was it boring. The entire span from Tracy through Bakersfield is a whole lot of nothing. And then you get to the desert. It was getting dark when I crossed into Nevada, and fully dark by the time I passed through Las Vegas. Upside to that, though: have you really seen Las Vegas if you haven’t seen it at night?

I continued on, and made my way to some Bureau of Land Management land outside of La Verkin, UT, where I camped for the night.

Cool thing a lot of people don’t know: Almost all Bureau of Land Management land and National Forest land is available for you to camp on — no cost, no reservation needed. (Check out the “Dispersed Camping” section of this BLM page on camping on public lands for more.) If you go the route of dispersed camping, two good resources: the website freecampsites.net and the iOS app Outly.

Although I’d normally take a tent and set it up to sleep in, I tried something new this time. I brought a trifold foam mattress and a comforter, and just set them up in the back of my car (back seat down) and slept there. It actually worked really well, and meant that — in the morning — I didn’t have to pack anything up. Just fold up the foam mattress, flip the back seat back up, and get going. (Side benefit: the ground around here was extremely dusty — I mean … it is a desert — so a tent would have been covered in red dust. This was a lot cleaner.)

I’d definitely try this approach again, though I think a thinner mattress would be a bit easier to work with. Although the mattress I had was really comfortable, it took up a lot of space in the back of the car, and when you’re working with the trunk and back seat of a Prius, the bulk of a mattress like that can make things difficult.

The BLM campsite had a few more people than I was expecting — mostly RVs or fifth-wheel trailers — but I was able to find a spot pretty easily. And, again, since I was in my car, I was really just looking for something level and not too close to other people.

Day Two: Zion, Cedar Breaks, and Bryce Canyon

Upon waking up, I could see that, yes, there was some pretty great geology surrounding me. It was pretty nice to go from “it’s getting dark and you’re in the Mojave Desert” to “it’s dawn and you’re in the middle of some giant mesas and buttes.”

The sun, rising over some mesas and rock formations.
Dawn. Again, apologies for the poor camera.

I drove to Springdale, UT to get breakfast and start my trip in to Zion. A ham and cheese omelette at MeMe’s cafe. Parking at the long-term parking in Springdale ($12 for the day). Biking in to the Zion walking/biking entrance gate.

Our “America the Beautiful — National Parks and Federal Recreational Lands Pass“ had expired, so I got a new one. $80 to get in to any national park or monument is such a deal. And I think — kind of like a gym membership — once you have it, you’re more inclined to just go. I’m a fan of anything that reduces the friction that stands between you and adventure.

Once in, I biked the 7 miles along the canyon floor to get to the Temple of Sinawava. Side note: The rock formations at Zion have some pretty amazing names — The Court of the Patriarchs, The Spearhead, The Great White Throne, Mountain of Mystery, The Sentinel. The biking in was pretty easy. I wish I could share photos with you of the bike in, but my camera just couldn’t capture the scale of the canyon or the formations at Zion.

Now at the Temple of Sinawava, I locked up my bike and “hiked” along the Riverside Walk, up the side of the canyon along the Virgin River. (It’s really a paved path.) After a mile or so I got to the trailhead for the Zion Narrows, which is one of my favorite hikes in the world. BUT! There’s currently an algae bloom in the Virgin River, where a cyanobacteria called Tychonema is releasing a neurotoxin in the water. So I didn’t do the Narrows hike. Plenty of other people were, though! And, odds are good that they were totally fine. But I was solo, didn’t have quite the right gear for a water-up-to-your-thighs hike, and didn’t want to run the risk of neurotoxin exposure. (Apparently, symptoms include “skin rash, salivation, drowsiness, tingling, burning, numbness, pain, incoherent speech, muscle contractions or twitching, vomiting, and diarrhea.” Goiks!) Hopefully the algae blooms and neurotoxins will have cleared up when I bring the family.

Anyway, I walked the mile back to my bike, then biked back to Springdale. Mostly downhill on the trip out of the canyon, so the bike ride back was easier and faster. Downhill return trips are always nice.

Back in Springdale I grabbed a slice of Bumbleberry Pie and ice cream, then headed to the car.

From Springdale, the drive up to Cedar Breaks was pretty easy. Highlight was the climb out of Zion Canyon, where several switchbacks gave some amazing views of different peaks in the park. After about two hours I made my way to a few overlooks at Cedar Breaks.

Various rock formations at Cedar Breaks National Park.
Cedar Breaks

I’d never heard of Cedar Breaks before a few weeks ago, when I saw a blurb in the AAA magazine about it, as a less-busy version of Bryce / the Grand Canyon. I’m glad I went, but would only recommend going if you’re trying to see something different, or you want to go somewhere with fewer people than the other parks. If you do a similar trip but have to cut one, it’d be the one I’d suggest dropping. (I’m happy to hear from any Cedar Breaks apologists on why I missed the coolest part of it. If that’s you, please let me know.)

I then proceded on to Bryce Canyon, which was probably my favorite of the parks this trip.

Oh — quick aside. When driving in to Bryce from the west, you go through Red Canyon, which is a relatively short section of the highway where you feel like you’re in the middle of a Road Runner cartoon. The rocks are, as you’d expect, a bright reddish-orange, and have some pretty great shapes. No photos, unfortunately, as I figured I’d get some photos on my way out (and then it was dark when I departed in the morning). (Lesson from that: don’t assume you’ll be revisiting a cool spot later and put off grabbing photos now. If it’s neat, grab a photo.) Anyway, Red Canyon is absolutely worth swinging through, and if I’d planned my trip a bit better, I might have added some mountain biking on the trails here.

Anyway, through Red Canyon and on to Bryce. Will let the photos speak for themselves. No filters on these, by the way, though I can’t say why the color looks so different from shot to shot.

Looking into Bryce Canyon. Another shot, looking down into Bryce Canyon. More of Bryce Canyon, showing a number of delicate spires with stratified layers of earth.

Fun word — those spires are called “hoodoos”.

I know the image of Bryce might look a lot like Cedar Breaks, but know that the scale of the two is very different, and the view you get at Bryce is much better.

I’m hoping to hike on into the canyon next time I go to Bryce. Hitting the view points is lovely, but I bet the views inside the canyon are ridiculous. So: biking at Red Canyon, hiking at Bryce.

A tree with roots exposed by wind, looking like it's slinking away.
Also at Bryce was this fun tree that looks like it might moonlight as a character in a Miyazaki film.

The sun was setting, so I headed off to some more National Forest land for another night of car camping. I haven’t seen a more star-filled night sky since I camped across the country back in high school. It was pretty incredible.

Day Three: The Grand Canyon and an Epic Day of Driving

I woke up on the early side and figured I’d see what I could fit in to the day. So. Up and at ’em.

I first made my way to Kanab, Utah, which was apparently used as a backdrop for a number of western films back in the day. A breakfast burrito and latte from a foodtruck run by a nice Mormon lady, and then to the North Rim of the Grand Canyon.

I was a little unsure about whether to hit the North or the South Rim. The Grand Canyon’s shaped a bit like a crescent, with the two points pointing up. So the view from the North Rim is a bit more constrained, but for the route I was traveling, it seemed to make a bit more sense.

At the North Rim there’s a lodge and a visitor center, though with COVID, it wasn’t set up the way I expect it normally is. There were mostly just some sandwich boards noting different recommendations from park rangers on how to enjoy the park.

Sandwich boards showing advice for how to visit the park.

I especially liked the boards' advice to “take a photo of this and go enjoy the canyon”.

I walked to Bright Angel Point to get a view of the Grand Canyon. It’s amazing to think about how long the weathering took to erode the canyon down … and then to realize that it’s not like the ground started built up, but that those sedimentary layers had to all form over millions and millions of years. It’s … humbling.

Looking into the Grand Canyon. Another shot of the Grand Canyon, looking into the distance. One more shot of the Grand Canyon, showing lots of sedimentary layers.

Little did I know it, but I still had a massive day ahead of me.

I had a decision to make. I had wanted to see Zion and Bryce canyons. (Check!) I had hoped to see the Grand Canyon as well. (Check!) Cedar Breaks had been a “well, maybe?” … and I’d now seen that one, too. (Check!)

So now what? I could have maybe spent more time in the Grand Canyon, hiking down from the rim. Or I could head to the Southern Rim to check that out? Or, to be honest, I was missing the family, so I considered heading back home early. But, again and again, we’ve seen the value of optimizing for story. So that steered the ship. I decided to head down to check out Sedona, and then head west to LA and up the coast.

A friend of mine, Jamie, loves Sedona, so I figured I’d see what the deal was. I … didn’t see what the deal was. To be fair, COVID time is weird, and so I wasn’t able to go to cool shops, or cool bars, or whatever else it is that she loves so much about it. So I’ll have to head back some time we’re on the other side of this and check it out again.

So I get through Sedona, and then, several hours later, I skirt Phoenix, and pass through San Bernadino, Pasadena, Los Angeles, Santa Barbara, and on to a rest area on Route 101 between Gaviota and Las Cruces. I found a good spot in the parking lot, pulled the comforter around me, and slept in the driver’s seat for about six hours.

Day Four: Up Route 1

When I’d hit LA the night before, I had a few choices on route. Up the boring-but-straight-shot Route 5? Up the more-interesting-but-still-a-highway Route 101? Or the hug-the-coastline-and-pass-through-cute-small-towns-and-farms Route 1? Friends! We optimize for story around here! Up the 1 it was!

Sadly, I didn’t get any photos of my trip up the 1. But it was a great trip, with a number of moments packed into the day:

  • Watching the fog roll in over the hills outside of Lompoc.
  • Smelling something like jasmine mingling with the normal marine layer scents of eucalyptus, bay laurel, and coyote brush in the morning fog.
  • Getting an undrinkable push-button latte at a local donut store, and then redeeming it with an actual latte from Quintessa Coffee, outside Pismo Beach.
  • Passing a few previously-adventured locations, like Julia Pfeiffer Burns State Park (the trip that reinforced the value of Side Quests), or the old Coast Road that winds around from Big Sur up to the back side of the Bixby Canyon Bridge (I stayed on the 1 this time).
  • Getting a blackened snapper sandwich from the Seabright Deli in Santa Cruz for lunch.
  • Looking (unsuccessfully) for whales off the coast north of Santa Cruz.
  • Enjoying the contrast of a bright blue sky when the rest of SF was gray and overcast.

Driving up the 1 was a lovely way to end the trip.

What’s Next?

This was a great trip, and I’m glad I was able to finally make it happen.

My next solo adventure, I think, will be a circumambulation around Mt. Tam. I think about three days of hiking will let me more leisurely approach the trip, rather than blitzing through the locations like I did with this one. I have a bit of planning to do for it, but I think it could be an amazing few days.

And I’ll hopefully have a better camera next time.

Fun with RegExes (AKA: How to Get Smartquotes in Eleventy)

I’m working on turning this tumblelog into a more fully-fleshed-out tool that anyone can use to quickly spin up a tumblelog of their own. One of the things I wanted to nail down was smartquotes.

Since — so far — this is just my personal blog, I’ve gone to the trouble of hand-typing all of the smartquotes in my posts. I know that’s a bit excessive. How nice would it be, though, if you could just write regular quotes in Markdown, and if Eleventy would just know which quote to put down, and do it for you?

Before I get into that, a quick bit of background for those of you who aren’t typography nerds.

Smart whatnow?

So if you look on your keyboard, just to the left of your return key, you’ll see the key you’d press to add a single quotation mark (') or, with the shift key modifying it, a double quotation mark (").

In programs like Google Docs, the software typically converts those into “smart” (or “curly”) quotes for you. Smart quotes are the traditional way you’d see quotes when set in type, like in a book, magazine, etc.

There’s a problem, though! By default, Eleventy doesn’t change your quotes in Markdown files to smartquotes. So, unless you wrote each quotation mark in manually (option + [ for left double quote, shift + option + [ for right double quote, plus a similar process for apostrophes), you’d be left with straight quotes.

I haven’t minded hand-writing them, but surely there’s an easier way?

Horrors. How do we fix it?

Thankfully, Eleventy lets us run custom filters, which can process the files we’re saving. We just have to create one that does what we want.

In our .eleventy.js file, we’ll add a new filter, called “smartquotes”. Before we add anything in, it looks like this:

eleventyConfig.addFilter("smartquotes", (post) => { return post; });

And we’ll call it in our main template file (like index.njk) like this:

<main>
{{ content | smartquotes | safe }}
</main>

(Normally, it’d just say content | safe, without the smartquotes bit in the middle.)

Okay. Now we basically need to add some regular expressions to swap out our various quotation marks.

Regular “double” quotes

Nunjucks converts normal double quotes (that aren’t inside a <code> block) into &quot;, so we’re going to want to add a find-and-replace regular expression looking for that string.

const openDoubles = new RegExp(/(?<=<(h|l|p[^r]).*)(?<=\s|>)&quot;/g);
const closeDoubles = new RegExp(/(?<=<(h|l|p[^r]).*“.*)&quot;(?=(\s|\p{P}|<))/gu);

If you aren’t familiar with regular expressions, that syntax can look kind of strange. Here’s what it means:

?<=(…): This is a “lookbehind” command. Basically: make sure that the sequence inside the parentheses occurs before the thing we’re looking for.

<(h|l|p[^r]): This is the sequence inside the parentheses. We need to see an angle bracket with either an h, an l, or a p (but not pr, as we don’t want to match <pre> blocks). (The h is for h1s, h2s, etc. The l is for label and li elements. The p is for p tags. We can add more if we like, but these were a good starting point.) (I tried a negative lookbehind, but the variations I tried kept breaking my test cases, so I’ve kept it like this for now.)

.*: There can be characters between the thing we’ve already said we’re looking for and the next part of the regex.

(?<=\s|>): Another lookbehind! This is what we need to see immediately before the thing we’re looking for. Either a whitespace character or a closing angle bracket. (Remember, Eleventy is just going to be parsing the text of the file, so it’ll treat it as a string, not as an HTML node.) By including this as a lookbehind, we simplify our replace() call, which we’ll get to in a second. (Otherwise, we’d need to include a “capture group” in the replace(). Don’t worry. We’ll get to capture groups in a second.

$quot;: The thing we’re looking for!

Okay. That was openDoubles. What about closeDoubles?

Some of this might look familiar. Try to parse it before I tell you what’s what.

(?<=“.*)&quot;(?=(\s|\p{P}|<))

Okay. Here’s what’s what.

(?<=“.*): Another lookbehind. This time, we need to see an open quote followed by any number of characters. (We know we’ll have open quotes available because we’ll run the openQuotes replacement before running the closeQuotes replacement.

&quot;: Again, the thing we’re looking for.

(?=(…)): This is a “lookahead” command. The string of text needs to include whatever’s inside the parentheses, but only after the thing we’re looking for.

\s|\p{P}|<: This is what’s inside the lookahead section. Whitespace (\s), or a punctuation mark (\p{P}), or a left-hand angle bracket (<). Note that for that \p{P} part to work, we need to tell the regex that we’re including some unicode instructions. We do that with the u flag at the end of it (look back up at the code block at the top of this section, and find the /gu.)

Okay, great. What do we do with those two consts?

We add them in to the return statement, calling replace() on the post string:

eleventyConfig.addFilter("smartquotes", (post) => {
const openDoubles = new RegExp(/(?<=<(h|l|p[^r]).*)(?<=\s|>)&quot;/g);
const closeDoubles = new RegExp(/(?<=<(h|l|p[^r]).*“.*)&quot;(?=(\s|\p{P}|<))/gu);
return post
.replace(openDoubles, "“").replace(closeDoubles, "”");
});

Okay, so! We got our double quotes taken care of.

Regular ‘single’ quotes

Like the double quotes, we’ll need to put together some regular expressions to get the single quotes.

This should look kind of familiar:

const openSingles = new RegExp(/(?<=<(h|l|p[^r]).*)(?<=\s|>)'/g);
const closeSingles = new RegExp(/(?<=<(h|l|p[^r]).*‘.*)'(?=(\s|\p{P}|<))/gu);

See if you can read through that line and figure out what each one does. If you need help, look up at the section before this.

It’s actually exactly the same, except we’re looking for the straight single quote instead of the string &quot;.

The only difference on the replace() call is that we’ll use smart single quotes:

.replace(openSingles, "‘").replace(closeSingles, "’")

So now our full filter looks like this:

eleventyConfig.addFilter("smartquotes", (post) => {
const openDoubles = new RegExp(/(?<=<(h|l|p[^r]).*)(?<=\s|>)&quot;/g);
const closeDoubles = new RegExp(/(?<=<(h|l|p[^r]).*“.*)&quot;(?=(\s|\p{P}|<))/gu);
const openSingles = new RegExp(/((?<=<(h|l|p[^r]).*)(?<=\s|>)|\n)'/g);
const closeSingles = new RegExp(/(?<=<(h|l|p[^r]).*‘.*)'(?=(\s|\p{P}|<))/gu);
return post
.replace(openDoubles, "“").replace(closeDoubles, "”")
.replace(openSingles, "‘").replace(closeSingles, "’");
});

Okay, great. So that’s single and double quotes. We haven’t gotten apostrophes set, yet. Let’s do that next.

Apostrophes

Apostrophes are pretty straightforward. A “word boundary” (0-9, a-z, A-Z, or the underscore character, represented by \b), then an apostrophe, then another “word boundary”. This will pick up things like can’t, they’re, it’s, and so on.

const apostrophes = new RegExp(/(?<=<(h|l|p[^r]).*)\b'\b/g);

We’re going to want to run the apostrophes before replacing the double and single quote replacements. We could probably do it after, but this feels cleaner to me.

As before, we keep building up our string manipulation:

eleventyConfig.addFilter("smartquotes", (post) => {
const apostrophes = new RegExp(/(?<=<(h|l|p[^r]).*)\b'\b/g);
const openDoubles = new RegExp(/(?<=<(h|l|p[^r]).*)(?<=\s|>)&quot;/g);
const closeDoubles = new RegExp(/(?<=<(h|l|p[^r]).*“.*)&quot;(?=(\s|\p{P}|<))/gu);
const openSingles = new RegExp(/((?<=<(h|l|p[^r]).*)(?<=\s|>)|\n)'/g);
const closeSingles = new RegExp(/(?<=<(h|l|p[^r]).*‘.*)'(?=(\s|\p{P}|<))/gu);
return post
.replace(apostrophes, "’")
.replace(openDoubles, "“").replace(closeDoubles, "”")
.replace(openSingles, "‘").replace(closeSingles, "’");
});

Are we good, then?

Not yet!

Abbreviated years

Believe it or not, the apostrophe in shortened years is supposed to point to the left. That is, the “pointy bit” of the quotation mark always points to the thing that got removed. So if you shorten “2020”, you’d want it to look like ’20, not ‘20.

So how do we do that?

We want to capture a single quote sandwiched between a whitespace character and a digit. There are two ways we could do this. First, let’s look at a “capture group”:

const years = new RegExp(/(\s)'(\d)/g);

Those parentheses indicate “capture groups”. When we run the replace() function, we’ll use the capture groups to insert the proper values back in. $1 is the first capture group’s contents. $2 is the second.

.replace(years, "$1’$2")

“But wait,” you say. “We didn’t pass in capture group variables for the “word boundaries” (\b) earlier. Why not?

It turns out that the \b marker doesn’t actually match any characters. It just marks that liminal space between the word and the not-word.

An alternate method is just like the earlier “lookbehind” and “lookahead” approaches:

const years = new RegExp(/(?<=\s)'(?=\d)/g);

And the .replace() call would be just the smart quote — no capture group variables.

.replace(years, "’")

We will definitely want to run that one before the openSingles replacement, so those quotes get switched over and aren’t caught by the later replacement.

At the risk of being repetitive, here’s what our smartquotes filter looks like at this point:

eleventyConfig.addFilter("smartquotes", (post) => {
const apostrophes = new RegExp(/(?<=<(h|l|p[^r]).*)\b'\b/g);
const years = new RegExp(/(?<=\s)'(?=\d)/g);
const openDoubles = new RegExp(/(?<=<(h|l|p[^r]).*)(?<=\s|>)&quot;/g);
const closeDoubles = new RegExp(/(?<=<(h|l|p[^r]).*“.*)&quot;(?=(\s|\p{P}|<))/gu);
const openSingles = new RegExp(/((?<=<(h|l|p[^r]).*)(?<=\s|>)|\n)'/g);
const closeSingles = new RegExp(/(?<=<(h|l|p[^r]).*‘.*)'(?=(\s|\p{P}|<))/gu);
return post
.replace(apostrophes, "’").replace(years, "’")
.replace(openDoubles, "“").replace(closeDoubles, "”")
.replace(openSingles, "‘").replace(closeSingles, "’");
});

Okay, great! Surely there aren’t any edge cases?

Oh, but there are.

Edge cases — slang and Hawaiʻi

As we just saw in years, the “pointy bit” of the quotation mark points at the elided content.

When “them” gets cut down to “em”, or “it was” gets smushed into “twas”, we want the quotation marks pointing at the beginning of the word: ’cause, ’em, ’til, ’twas.

Fortunately, there aren’t that many special cases, so for now I’ve hardcoded them. Odds are good I’ve missed a few. Please feel free to ping me and let me know!

const slang = new RegExp(/'(cause|em|til|twas)/g);

We also have an interesting case where — in the Hawaiian language — the official name of their land is Hawaiʻi. The character in between the two is is called an ‘okina, and it’s a diacritic that indicates a glottal stop. When writing an ‘okina, the “pointy bit” points up — instead of down — regardless of where it occurs in a word. (You can read more on the ‘okina over at Wikipedia.)

The ‘okina is technically present in many Hawaiian words, like Oʻahu or Kauaʻi, but it usually gets dropped when the words are being written in English. In fact, the actual name of the US state is “Hawaii” — no ‘okina. This filter catches Hawaiʻi, but doesn’t attempt to catch all Hawaiian words with ‘okinas. (My assumption is that if you’re paying attention to ‘okinas, you’re going to be hardcoding them in anyway.)

const hawaii = new RegExp(/(?<=<(h|l|p[^r]).*)Hawai'i/g);

And with that, for now, we’ve got our filter.

The final filter

Here’s what goes in your .eleventy.js file:

eleventyConfig.addFilter("smartquotes", (post) => {
const hawaii = new RegExp(/(?<=<(h|l|p[^r]).*)Hawai'i/g);
const slang = new RegExp(/'(cause|em|til|twas)/g);
const apostrophes = new RegExp(/(?<=<(h|l|p[^r]).*)\b'\b/g);
const years = new RegExp(/(?<=\s)'(?=\d)/g);
const openDoubles = new RegExp(/(?<=<(h|l|p[^r]).*)(?<=\s|>)&quot;/g);
const closeDoubles = new RegExp(/(?<=<(h|l|p[^r]).*“.*)&quot;(?=(\s|\p{P}|<))/gu);
const openSingles = new RegExp(/(?<=<(h|l|p[^r]).*)(?<=\s|>)'/g);
const closeSingles = new RegExp(/(?<=<(h|l|p[^r]).*‘.*)'(?=(\s|\p{P}|<))/gu);
return post
.replace(hawaii, "Hawaiʻi").replace(slang, "’$1")
.replace(apostrophes, "’").replace(years, "’")
.replace(openDoubles, "“").replace(closeDoubles, "”")
.replace(openSingles, "‘").replace(closeSingles, "’");
});

And, then, like I said up top, the “content” part of your index.njk file should look something like this:

<main>
{{ content | smartquotes | safe }}
</main>

A few tests:

Abbreviated years work: ’97, ’01, ’04, ’07.

Apostrophes and contractions work: I can’t wait to see if anyone actually uses this. If you’ve got suggestions or improvements, please shoot me a note.

Quotes work: “I just don’t think I have it in me,” said the dog that definitely didn’t eat the bacon off the countertop, no siree.

“Quotes” should “work”: even when there are multiple “quotes” per “line”.

Internal quotes work, even with curious punctuation: “She didn’t say ‘You did this’! She said ‘Hugh did this’!”

‘single quotes’ ‘work’, at the ‘beginning’, ‘middle’, and ‘end’

“So do” “double” “quotes.”

But not inside 'pre' blocks, or in multi-line code blocks:
<code>
These should *not* be "smart".
</code>

Oh, and thanks to how Nunjucks and Eleventy process HTML, if we have some hardcoded HTML with a class or an inline style — like this one — the quote marks inside the brackets won’t get messed up, and your HTML will still work as expected.

JSON Feeds in Eleventy

I’ve wanted to set up an RSS/JSON feed for this tumblelog for a little bit, but hadn’t made the time. I just took care of it, and it was really straightforward.

I started with Andy Bell’s quick intro on making a JSON Feed in Eleventy, but then made some modifications to help it conform more to the JSON Feed spec.

Here’s what I ended up with, in a file called feed.njk in my root directory:

---
permalink: "/feed.json"
---
{
"version": "https://jsonfeed.org/version/1.1",
"title": "Charlie Park!",
"home_page_url": "https://charliepark.org/",
"feed_url": "https://charliepark.org/feed.json",
"icon": "https://charliepark.org/images/arrow_for_feed.jpg",
"favicon": "https://charliepark.org/favicon.ico",
"language": "en-US",
"items": [
{% for item in collections.post | reverse %}
{
"id": "https://charliepark.org{{ item.url }}",
"url": "https://charliepark.org{{ item.url }}",
"title": "{{ item.data.type }}: {{ item.url }}",
"content_html": "{{ item.templateContent | replace(stet'stet"stet'stet, "\"") | replace("\n", "") | replace("\\", "\\\\") | safe }}"
}{% if not loop.last %},{% endif %}
{% endfor %}
]
}

That string of replace()s in the last line of the for loop is to handle some string transformations so that the post content better functions with the JSON spec. Since I use smart quotes in my posts, it won’t mess up my quotation marks. Just be aware that you might need to keep an eye out on those.

Our dog, Fern, looking noble.

Fern is a very good girl.

Tutorials Over Libraries

Andy Bell published a new tutorial today, on how to build a responsive media browser with CSS. It’s a great runthrough of how he did it, and I especially like his 16:9 aspect ratio trick for the media object. It’s clever, while still being clear — a line that’s surprisingly hard for many developers to walk. And Andy does a great job talking through some of the reasoning behind different decisions, like some choices he made in the service of universal design.

So the article’s great, but what I really want to write about here is how much I appreciate that he wrote it up as a tutorial and not as a library.

An aspect of “the old web” that I miss is people writing up how they solved different technical challenges. I’m guilty of this, too. To be sure, people still do write things up, but it seems like it’s far more common for people to create a JavaScript module and to release it on NPM these days. “Hey, world. Here’s a ready-to-go responsive media browser! I’ve hidden the complicated parts so you don’t need to worry about them.”

Matthew Crawford — motorcycle mechanic and philosophy/sociology research fellow at UVA — talks about this principle (and how damaging it can be) a fair amount in his book Shop Class As Soul Craft. In his case, he talks about the evolution of the dipstick in the car. When cars first came out, you couldn’t own one unless you knew how the internal parts worked together. Over time, car mechanics began to take on that work, and car owners only needed to check their engine oil level every once in a while. Then came the “check engine” light. Later, the OBD-II monitor, which required not only specialized knowledge, but specialized hardware and software. Ultimately, some cars didn’t even have a dipstick accessible to the owner, and it could only be serviced by taking it in to the dealer. (Rent-seeking isn’t only present in the SaaS world.)

Yes, being freed from having to deal with “the complicated parts” meant that people were freed to do other (presumably more valuable) things with their time. And there’s something to be said for an external library that’s properly tested versus your own homespun version. But that external reliance comes at a cost of knowing your own tools and honing your craft. Of understanding the bespoke decisions that go into developing the particular thing you’re making, and of learning about both common pitfalls and edge cases to account for. Of knowing how to fix things when the externally-provided library doesn’t work any longer.

So I think there’s a lot to be said for getting your hands dirty and — yes — duplicating work that others have done.

Tutorials, like the one that Andy wrote, are one of the best things about the web, and are so much richer than a comparable package/module/component. I’d love to see more people writing up their processes, and showing off how they build things. And, ultimately, showing the rest of us how we, too, can build something similar.

Think of all the time and energy we all must presently devote to the outbursts driven by Trump’s bottomless appetite for attention. Imagine having that psychic burden lifted. Envision the name Trump appearing only in the headlines of below-the-fold stories about criminal investigations and civil lawsuits. Now vote, and make that dream a reality.

Eugene Robinson — Imagine what it will be like to never have to think about Trump again

Was just wondering last week about the Gregory Brothers and what they’re up to these days. Here we go.

SF Voting Cheatsheet

I’m a big fan of The League of Pissed Off Voters and the guides they make each year. They have a more comprehensive guide on the way, but they’ve posted a cheatsheet in case you’re voting early.

I look forward to their more nuanced writeups on some of the propositions, but it’s good to have a general sense of their positions. I’m really hoping folks in District 1 pay attention and vote for Connie Chan.

Get You a Coach for Great Good!

So I’ve benefitted greatly from working with a therapist over the last year. (This is mine.) He asks great questions, has helped me better understand both myself and my relationships, and has helped me train my ability to get work done more effectively. I highly recommend working with a therapist or coach if you can.

A good friend of mine is also an excellent coach, and has recently opened up a few slots for new clients. If you’re interested, she’ll give you a free session to see if you click. You can check her out and sign up for a free session here: Coaching With Lane. It’s kind of incredible how insightful she is, and how quickly she picks up on little things you say / don’t say, and follows up with just the right amount of curiosity to make you pause, reflect, and open a new door of understanding. It’s pretty wild, to be honest.

If you’ve been thinking about finding a coach, but have been waiting for a sign, consider this the sign and check out her coaching. There are few uses of your precious time that’ll be more useful than reaching out to see if she can help you get unstuck.

There is no place on earth so beautiful as Tamalpaias.

Robert Louis Stevenson, from the top of Mount Tam

A painting of a sun setting over a river, with a mountain in the distance. The clouds are illuminated in reds and blues.

Frederic Edwin Church — Twilight in the Wilderness

In the first chapter, a disagreement develops between the narrator and his riding companions, John and Sylvia, over the question of motorcycle maintenance. Robert performs his own maintenance, while John and Sylvia insist on having a professional do it. This posture of non-involvement, we soon learn, is a crucial element of their countercultural sensibility. They seek escape from “the whole organized bit” or “the system,” as the couple puts it; technology is a death force, and the point of hitting the road is to leave it behind. The solution, or rather evasion, that John and Sylvia hit on for managing their revulsion at technology is to “Have it somewhere else. Don’t have it here.” The irony is they still find themselves entangled with The Machine—the one they sit on.

Today, we often use “technology” to refer to systems whose inner workings are assiduously kept out of view, magical devices that offer no apparent friction between the self and the world, no need to master the grubby details of their operation. The manufacture of our smartphones, the algorithms that guide our digital experiences from the cloud—it all takes place “somewhere else,” just as John and Sylvia wished.

Yet lately we have begun to realize that this very opacity has opened new avenues of surveillance and manipulation. Big Tech now orders everyday life more deeply than John and Sylvia imagined in their techno-dystopian nightmare. Today, a road trip to “get away from it all” would depend on GPS, and would prompt digital ads tailored to our destination. The whole excursion would be mined for behavioral data and used to nudge us into profitable channels, likely without our even knowing it.

Matthew Crawford, Why Robert Pirsig’s ‘Zen and the Art of Motorcycle Maintenance’ Still Resonates Today

Let us not hedge about one thing. Donald Trump may win or lose, but he will never concede. Not under any circumstance. Not during the Interregnum and not afterward. If compelled in the end to vacate his office, Trump will insist from exile, as long as he draws breath, that the contest was rigged.

Trump’s invincible commitment to this stance will be the most important fact about the coming Interregnum. It will deform the proceedings from beginning to end. We have not experienced anything like it before.

The Election That Could Break America

The Mackenzie Time Inventory

In the management classic The Time Trap, R. Alec Mackenzie has several solid recommendations, including getting a sense of where your time goes. He recommends creating and using a time inventory:

From the earliest efforts to log their time, executives have found that their time allotments were not going where they thought they were. …

Peter Drucker’s remarks about the time log are enlightening. He observes that approaches to getting more work done always begin with planning. However, effective executives do not start this way. They know that if you start with a plan, it ends up in the bottom drawer. Other plans will follow, winding up in the same place. Instead, according to Drucker, the astute executive begins by finding out where [their] time is really going.

The time inventory, or log, is necessary because the painful task of changing our habits requires far more conviction than we can build from learning about the experience of others. We need the amazing revelation of the great portions of time we are wasting to provide the determination to manage ourselves more effectively in this respect.

In the book, Mackenzie lays out a chart that you can use to log your time. It wasn’t a bad layout for 1972, but as we have some more tools at our disposal, I figured it’d make for a solid spreadsheet.

So! I made one, using Google Sheets. If you’re interested, you can copy (and use) The Mackenzie Time Inventory.

Let me know if you use it, and how it could be improved!

If doing the right thing were always easy, there wouldn’t be so many people doing the wrong things. Doing the right thing even when it has negative personal consequences is the mark of good character.

jimmyjrdanceparty

No browsers support it yet, but there’s a useful pseudo-class in the CSS spec that I just stumbled on: :has()

Say you have a style that applies to links, but you don’t want it to apply to links when they contain an image (like an image that links to a gallery). You could do something like this:

a { border-bottom: 1px solid #000 }
a:has(img) { border: none }

So this is pretty cool.

A wearable device to help identify decision moments.

Annouk Wipprecht is a fashion designer / engineer who creates wearable devices like the one above. That one in particular is interesting to me, as it focuses on helping identify moments when kids with ADHD “engage”. From a writeup on “Agent Unicorn”:

I decided to focus on what is known as the P300 event-related brain potential signal. P300 is a frequent focus of clinical exams and BCI research. It is a voltage pulse, often thought to be connected to attention and decision making, that occurs a few hundred milliseconds after an external stimulus. The P300 signal is often measured when diagnosing children with ADHD because the signal takes longer to manifest and isn’t as strong as it is in children without ADHD.

ADHD is commonly treated with stimulants such as Adderall that can boost concentration and focus while reducing hyperactive and impulsive behaviors. But while medication might help soothe symptoms, it doesn’t help in understanding why a child with ADHD is more prone to react to certain stimuli, or how their symptoms might be treated in a way that reduces reliance on drugs.

My goal was to create a device that would provide the data needed for such insights by monitoring both the brains of children and their environments. The result was Agent Unicorn—a headpiece with a projecting horn. The horn contains an 8-megapixel camera that records video during states of heightened P300 activity, as detected by an EEG built into the headpiece itself. The headpiece has a shape that automatically positions the electrodes at the correct locations on the skull.

Here’s what it looks like when it’s going on a child:

The device’s inventor, Annouk Wipprecht, putting the Agent Unicorn device on a child in a classroom.

Annouk Wipprecht has some more cool photos of her work in a gallery on her site.

In a great thread on Twitter, Kieran Snyder shares some great management insights:

The second mistake: Getting the balance wrong between managing up (working w your managers), managing down (working w your team), and managing over (working w your peers).

Most managers do one of these very well. Some do 2 out of the 3. Few get all 3 right with equal facility.

But all 3 of these working modes (managing up, down, and over) are important to achieving your main accountability as a manager: Delivering high-impact work on time and growing people in the process.

If you don’t spend enough time with your team, you fail to set accountabilities and priorities properly and you miss coaching opportunities.

If you don’t spend enough time with your management, you fail to set priorities properly, and you are likely missing context that can help your team. You also miss chances to be coached.

If you don’t spend enough time with your peers, your execution will suffer. You won’t know how your team is performing or perceived. You will lack organizational support for initiatives that matter to you.

At most stages of my early management career, I spent plenty of time with my team and with my management, but I didn’t spend enough time with my peers. That was an Achilles heel that I was only able to see after the fact.

This is really insightful. I’ve talked with folks before about managers usually only being good at one, maybe two of “politics, product, process, or people”, but I think the look at managing up, down, and across is a great one.

In my last role, I nailed the “working with your team” piece, and did a really good job with the “peers” bit as well. In hindsight, that “managing up” piece was one I should have paid more attention to. Something learned for next time.

Smarter Permalinks in Eleventy

I’m continuing to enjoy Eleventy. The other day I noted that I was having trouble getting the dates to work correctly, and was hoping for some smarter autoslugging.

I figured out both, and wanted to share what I did.

I had been naming the date and permalink in the file’s header …

---
date: "2020-09-21"
permalink: "smarter_permalinks_in_eleventy/"
---

… but that’s duplicating the data in the filename (which was 2020-09-21_smarter_permalinks_in_eleventy.md. This would be easier if eleventy just knew what the date and slug should be, right?

The date part was pretty easy. I removed the date line from the frontmatter data, and, as long as the filename had that YYYY-MM-DD formatting, it worked properly. (Thank you, eleventy, for being smart about that!) I’m still a little unsure that the UTC / PST timezones will play nicely, but it hasn’t shown to be a problem yet. (For some reason the “eleventy will automatically handle filenames with YYYY-MM-DD in them” wasn’t working for me a few days ago. Now it’s fine. ¯\_(ツ)_/¯ )

For the permalink, I created a new line in my eleventy.js file …

eleventyConfig.addFilter("getPermalink", (page) => page.fileSlug.slice(11));

… and then added a line to my posts/posts.json file:

"permalink": "{{ page | getPermalink }}/index.html",

Now the data and autoslug are generated off of the file name, and my post frontmatter only needs to exist if I’m specifying the post “type” (image, quote, poem, etc.). No more duplicated data.

A panel of the Moomin comic, showing characters sitting around a table. The mother figure says “Isn’t this quiet family life wonderful, dear?” The father figure, looking bored, says “Yes … … … but it would be even more wonderful if something exciting and awful happened!”

This is one of my favorite comics of all time, and it only takes about five minutes to read.

Every time I read it, it makes me a better person and a better partner.

You Should’ve Asked

Late last night, inspecting Santa’s handiwork, a simple thought occurred to me. A decade or so from now, when, say, I’m waiting for my son to come home from college for his winter break, and, when he does, he wants to spend his time going out with his friends — how much will I be willing to pay then to be able to go back in time, for one day, to now, when he’s eight years old, he wants to go to movies and play games and build Lego kits with me, and he believes in magic?

How much then, for one day with what my family has right now? How much? Everything.

John Gruber

A picture of Ruth Bader Ginsburg's iconic collar, but in black.

She fought. And fought. And fought.

We have to do the same.

Three Days In

I’m three days into using this tumblelogging tool, and am pretty happy with it. Obviously, the test is how I’ll use it over time, but things are going well so far.

A few things I love

It’s great how low-stress it is

I don’t worry about whether things are “good enough” to post. I just post them. That’s a big improvement over what I had before, where I let the perfect be the enemy of the good, and, consequently, didn’t post.

The different formatting types are fun

I love being able to come up with new post types, and then to style them independently. For example, yesterday, when I added the “poem” type. I’ll come up with a few more, for sure. I still haven’t come up with the “link” format, but look forward to the occasion where I do.

Posting and hosting are both easy

It’s really easy to add a new post right now. Create a file with the right Markdown format and frontmatter, run eleventy --serve to see what it looks like, and then commit to git and push remote. (TBH, I actually just leave an iTerm window open with eleventy --serve going all the time.)

The workflow is a little dependent on VS Code, where I’m writing these, and running eleventy on my local machine. And I have a few ideas around requiring less of the template in the Markdown file that I need to play with. But it’s working for now.

Some things to work on

Less metawork

Right now I have a bit of duplication of effort, in that I name the file something like 2020_09_18_three_days_in.md and then add metadata like

---
date: "2020-09-18"
permalink: "three_days_in/"
---

The eleventy docs say that it’ll use any YYYY-MM-DD in the file name as a date, but I haven’t found that to be the case (I know my date in the filename is using underscores; even when using dashes it doesn’t seem to quite work). It’d be nice to add something to the compiler / preferences that interpreted the filename correctly and then just used it for the date and permalink. Perhaps there’s a way to configure that, and I just haven’t found it yet.

Mmmmmaybe a posting interface?

I can imagine a Svelte app that gives an easy posting input. Name the permalink, adjust the date if needed (but default to now), and give an input field for posting the content. Write the .md file on submission, then run eleventy to process it. At that point, you could just add a button that pushes it to GitHub as well. That’d be pretty cool.

RSS, or posting to Twitter, etc.

Right now, hardly anybody knows about this tumblelog, and that’s fine. (Hi, folks who are here!) But I could see it being useful to have some sort of “push this content to Twitter”. I’m not sure how that works with eleventy, and it’s possible there isn’t a convenient hook to do that. But it’d be cool to have that as an option. Maybe it’d be another bit of metadata in the header — if post_to_twitter: true, push it.

Social?

I’ve realized that one of the things that Tumblr did well was to give you a place to both create and consume. Twitter, too. Right now, this is just a place where I publish stuff. If I ever decide to make this more of a thing, it’d be helpful to have a place where I can read other people’s stuff, too. (I’ve always wondered why RSS readers don’t also give you a way to publish your own stuff. [Or maybe they do! Dunno!])

Separating my instance of this from the tool to let you do it yourself

When I wrote my two-times-ago blog, in Jekyll, a lot of people cloned it on GitHub, I believe to help them with a tagging issue that I solved. The problem was that I began to get worried about changing my blog (because it might mess up other peoples’ stuff?). That’s kind of silly. But if I ever do make this a more general-purpose tool for folks, I’ll want to figure out the best way to split them up. Very do-able; I just haven’t had to think through that piece yet.

So.

So that’s where things are right now. It’s still fun, and I’m enjoying it. And I have a few clear ”next thing to work on”s.

If you have any feedback, let me know! My DMs on Twitter (@charliepark) are open, though I’m on a bit of a Twitter break at the moment. Nevertheless, say hi!

There are fires during wartime, too.

There’s a scene in the film Hope and Glory that I think about a lot. Thirty seconds of DDGing haven’t brought up either a clip or a quote, so you’ll have to take my word for what goes on in the scene.

The film takes place during World War II, in London. Some of the more exciting bits of the film take place during air raids, where German planes drop carpet bombs on the city.

One night, the family’s out, at a play, or something. They return home, and their house is completely engulfed in flames.

The mother, horror-struck, turns to the fire chief. “But I didn’t hear the air raid sirens!”

“There wasn’t an air raid, Ma’am.”

“But the fire?!”

“There are fires during wartime too, Ma’am.”

There are fires during wartime, too.

It’s tempting — in the middle of a global pandemic AND historic wildfires AND an impending consitutional crisis — to say “Well, damn. It can’t get worse, right?”

Here’s the thing. Geology doesn’t care about any of that, and we’re just as likely to have a major earthquake during a global pandemic as we are at any other time. The odds haven’t improved just because everything else has gotten terrible.

If you live in California, I highly recommend the following podcast. It’s nine episodes, each a little over half an hour, produced by KPCC, Southern California Public Radio. It’s sobering, and could save your life.

Also, connect with your local CERT / NERT group and get trained!

Egg

by C.G. Hanzlicek

I’m scrambling an egg for my daughter.
“Why are you always whistling?” she asks.
“Because I’m happy.”
And it’s true,
Though it stuns me to say it aloud;
There was a time when I wouldn’t
Have seen it as my future.
It’s partly a matter
Of who is there to eat the egg:
The self fallen out of love with itself
Through the tedium of familiarity,
Or this little self,
So curious, so hungry,
Who emerged from the woman I love,
A woman who loves me in a way
I’ve come to think I deserve,
Now that it arrives from outside me.
Everything changes, we’re told,
And now the changes are everywhere:
The house with its morning light
That fills me like a revelation,
The yard with its trees
That cast a bit more shade each summer,
The love of a woman
That both is and isn’t confounding,
And the love
Of this clamor of questions at my waist.
Clamor of questions,
You clamor of answers,
Here’s your egg.

One of my philosophies as a designer is that you should first start with the patterns that exist, and only break the rules little by little, in the right places. When [you] don’t break enough patterns, you end up with something boring and predictable. But when you break too many, you end up with something chaotic and confusing. There is a sweet spot, and it contains both the familiar and the new.

Jack Cheng (here, though post is only available to Kickstarter backers)

The Library: A good place to get checked out.

It being September 15th, we remember four little girls from Birmingham — Addie Mae Collins, Cynthia Wesley, Carole Robertson, Carol Denise McNair — and twenty years later, a man from Spanish Town, Prince Far I.

Hello, tumblelog

This is just a quick afternoon project I threw together, to play a bit more with Eleventy (11ty) and Netlify.

The goal was to create a very basic tumblelog, which most of the world knew as “the kind of microblog that Tumblr made”. Which isn’t wrong. But there were tumblelogs before Tumblr, and, I guess, after Tumblr as well.

I think I’ve been hesitant to do much with my main website because … it feels like my homepage should be SeRiOuS. Which, yeah, maybe. But it’s also kind of dead right now.

So! I’m going to try this out and see if it works. If it does, I’ll look into moving my main blog over to this.

Development went pretty well. I’ve built a few things with Eleventy before. I have to say, every time I start fresh with it I have to wrestle with the docs a fair amount. A lot of it’s really straightforward and clear. But something as basic as “how do I post a copy of each post’s content on the main page?” is somehow hard to search for. (The answer, by the way, is something like this:

{%- for post in collections.all | reverse -%}
<article class="{{ post | setClasses }}">
{%- if post.data.date %}
<time class="postdate" datetime="{{ post.data.date | getISOString }}">
<a href="{{ post.url }}">{{ post.data.date | getHumanDate }}</a>
</time>
{%- endif %}
<div class="postbody">
{{ post.templateContent | safe }}
</div>
</article>
{%- endfor -%}

Oh! And that datetime format is handled like this, in your eleventy config file:

const setDateToMidnight = (date) => (new Date(date)).toUTCString();

const getISOString = (date) => {
const midnight = setDateToMidnight(date);
return new Date(midnight).toISOString();
};
const getHumanDate = (date) => {
const midnight = setDateToMidnight(date);
return new Date(midnight).toLocaleString('en-us', {
month: 'long',
day: 'numeric',
year: 'numeric',
timeZone: 'UTC'
});
};

module.exports = function (eleventyConfig) {
eleventyConfig.addFilter("getHumanDate", (date) => getHumanDate(date));
eleventyConfig.addFilter("getISOString", (date) => getISOString(date));
}

Note the timeZone: ‘UTC’ bit in the toLocaleString() options! It’s pretty important!