Reading List

The most recent articles from a list of feeds I subscribe to.

Year of Short Stories

I wrote a short story every week in 2022. My goals were to get better at writing and to have fun. I'll let you be the judge of the former but I sure did have a good time. This is what they look like:

F52 stories

Colorful, right? Technically, there's 53 stories, but that's cause I preloaded up a zeroth story that I'd written a year back so that the site wouldn't look empty and also to trick me into thinking I'd already made progress - you know, the proverbial todo list items you've already done but still jot down so you can cross them out immediately.

Speaking of task management, this is also probably the first "New Year's Resolution" that I really achieved.

#TODO: Fix me later (JIRA CH-4202)

There's always chatter around this time of year about whether or not New Year's Resolutions are a good thing or a bad thing. Maybe we're supposed to be doing goals instead. Or anti-resolutions.

The debate reminds of when we were told by our teachers at St. Leo the Great to switch from "giving something up" in Lent to "doing something new that's also good" - which is actually a good setup for a story!

Regardless, what I like about Resolutions Time is the "resetting" it can bring. Sometimes you gotta blow on that Nintendo game to make it work again. It's also a great opportunity to try new things. Many of us seem to calcify as we age (see Thanksgiving dinner discussion topics). But we can resist, my friends, if we simply follow Merlin's advice. Finally, there's often a health theme around New Year's Resolutions, and hopefully you already know my thoughts on being your own health advocate.

Resolutions-rant aside, I thought I'd share some LEARNINGS (is there a more annoying word in modern business-speak? Yes, probably, but don't you dare tell me it) from my year of writing short stories.

Learn the Learnings Learned by a Learned Learner

Have fun

This one's already part of my life motto (borrowed from children's publisher Klutz Press), and I view it as critical to the success of my short story writing project. I wrote these stories for me, and I like reading them. I think they're fun, and I didn't stress about writing them, even though I did have to carve out time to write them each week. But it doesn't take much time to make a meaningful dent into a short story. I think everyone would be surprised by that - take a phrase or a name or a memory and just start... going.

Clear the cache

I wrote many of these stories to simply get them out of my head (where some of them have been rattling around for years, like what if it's The Young Adventures of Indiana Jones but it's Warren Buffett instead and all his greatest investment ideas came from hijinks and misadventures?). As it turns out, not all of my long-standing story ideas were prize winners, but they're at least OUT of my head now, where I can edit or revise them or, most-likely, just move on! My creative cache is cleared and is feeling very performant now.

Remove technical barriers

I coded up the project's website last December. I made sure that I could deploy it with a simple push to GitHub. I made sure that all I needed to do each week was "write the story" and "git push" (other than the podcast recording, a process which I also kept as simple as possible, partly due to lack of audio editing knowledge but mostly because I knew no one was really listening to them anyway other than Carly and my mom).

Jot stuff down

Write down your dreams, any bits of them that you remember. I use the Drafts iOS app to do this. I dump ideas, character names, dialogue, etc. throughout the day into Drafts, and then process the queue when I'm back at my computer. My phone's always with me, and I'm trying to make it a tool for creativity over pure consumption.

Review the list of things I didn't do good cause I'm no-good

Here's where I would normally write down some "opportunities for improvement" - where I reveal that I'm simply masquerading as a lifelong learner but I'm simply a shameless millenial optimizooor.

However, this is not only a blameless post-mortem, it's also a faultless one, too. I know I could have done a better job of editing and revising my stories. I know I could have written more every single day, and made it a true daily habit. But we are not doing this, okay?

Try to forgive yourself for being human, Charlie, and instead enjoy the fleeting joy of creative fulfillment before the next project begins tomorrow. Have fun, remember!

10 PRINT "HAVE FUN!"
20 GOTO 10

Mini story collections

Lessons be damned, one of the fun things that unexpectedly emerged this year was my use of recurring characters and companies and locations. If I'm allowed to be critical again, it's because this tactic became a shortcut. It was definitely easier to keep developing the same characters versus going full-on tabula rasa each week. But, also, I liked these characters and companies and locations, so there, brain!

If you do give my stories a try, keep your eye out for the megacorp Eagle (can we trust them? do we even have a choice?) as well as several adventures across Old New Jersey and the town of Little Bighill.

I'll also highlight two recurring characters: Penelope "Thesaurus" Green and Will. Penny's braver than just about anyone, and Will's -- well, Will's me. Anytime you read a Will story, it's an ever-so-slightly-veiled memory. They're the beginnings of my Dandelion Wine.

Penny stories

Will stories

Run Linux on Electric Objects EO1 Wall Computer

Riddle in the dark

What was too early for NFTs, too vertical to be a Samsung Frame TV competitor, kickstarted to life by gifs, and acquired to death by Giphy?

That's right, hobbitses, it's Electric Objects!

Electric Objects app

Electric Objects was a computer company building a computer made for art. That's one of the coolest sentences ever, except for the was part. Founder and CEO Jake Levine (a fellow Morgan Stanley escapee) wrote a great what-happened series of posts in 2018 that are worth a read for anyone interested in hardware startups. But, even better, just re-watch their Kickstarter video and experience the pure joy of the creative act of bringing a computer to life.

Electric Objects art

Electric Objects was gobbled up by Giphy, which in turn was slurped and gorbled into Facebook, and the Electric Objects iOS app is sadly no more. Which, for a computer that was explicly designed to not have a keyboard or mouse, poses a challenge for its owners.

So, why am I still lugging around my EO1?

Because I'm not giving up on the dream, Jake.

Still kicking

The EO1 is a computer, right? Surely, we can boot into its presumably Linux OS somehow, instead of the default Electric Objects app experience thingie?

Turns out, yes, we can! I had to do a fair bit of forum spelunking to figure it out. I was delighted to discover other Electric Object wanderers out there like me. This post was the jackpot.

The long and the short of it is that the company who manufactured the board for the EO1 is called Boundary Devices, and you can download their Linux builds on their website (after making an account, etc, etc). Fling that image onto a USB thumbdrive, attach the thumbdrive and a keyboard and a mouse to a USB hub, connect the hub to a micro-USB adaptor, plug that sucker into the back of the EO1, and then - boom - you've got yourself a weird vertical Linux computer on your dang wall.

It's almost too easy.

Electric Objects

Displaying the New York Times frontpage on your Electric Objects EO1

So, now what? What are you going to do with your wall computer, Charlie?

Lots of stuff, okay?

Like... remember that post from Brian Donahue about displaying the NY Times frontpage on his EO1 (which itself was derived from another post about building a giganto e-ink display to do the same)? How about that?

Much of Brian's repo is about communicating with the Electric Objects API. But we're not going to do that, are we? The real nugget of gold here is the deterministic URL for grabbing a PDF of the NY Time front page:

https://static01.nyt.com/images/$(date +"%Y/%m/%d")/nytfrontpage/scan.pdf

I bet we could make a nice one-liner to download today's front page using today's date and then open it up full screen somehow and then make it run this script every time the computer boots up.

That turned out to be more complicated than expected (typical). I hacked and slashed (and Googled) my way to the following setup, which works (I know it's not a one-liner, but doing it this way really helped me debug why each step - yes, each step - wasn't working at some point in this process):

#!/bin/bash

export DISPLAY=:0

echo "sleeping..."
sleep 60

echo "remove yesterday..."
rm scan.pdf

echo "download today..."
/usr/bin/wget "https://static01.nyt.com/images/$(date +"%Y/%m/%d")/nytfrontpage/scan.pdf"

echo "open fullscreen..."
/usr/bin/evince --fullscreen scan.pdf

echo "done!"

Then, you can use crontab to setup this script to run every time the computer boots with the @reboot keyword (which I didn't know about before and works as valid cron syntax - depending on your cron version). Don't forget to chmod +x your script first!

Well, does it work?

Electric Objects

It does!

For the curious, migrating my one-liner/script to cron had a bunch of challenges (e.g. cron doesn't like % without escaping them; I needed to add sleep to ensure networking/wifi had loaded; I needed to add the DISPLAY env var so that cron knew how to talk to the display, etc). Also, I needed to install postfix so that I could read cron's error logs, which amazingly are emailed to your computer.

After all that, I connected the EO1 power cable to a Wemo smart outlet plug thingie, which integrated with Apple Homekit. Using the Apple Home app, I set this outlet to turn on at 6 AM and then turn off 2 hours later.

Hello darkness, my old friend

After a few evenings, I thought this "5 minute" project was done until I noticed that the screen was going dark at the 1 hour mark.

This particular Ubuntu distro's Power settings did not provide me the option of "never going to sleep". More Googling led me down many failed paths (e.g. masking stuff in systemctl, trying gnome-tweaks) until I finally got something that keeps the EO1 display "awake" - the caffeine utility.

I added this line to the end of my script, and now we're awake and jittery... at 6 AM. But at least we have today's paper to read.

caffeinate sleep 9999999

Are we done puttering yet?

Never!

Now I'm adding Tailscale so that I can officially disconnect the keyboard and mouse and still be able to easy SSH into this wall computer. And I think I broke something else running sudo apt-get update, cause it's not booting up right now. Sigh...

Also, this whole caffeine thing makes me realize that I don't want to read anything before coffee, so I think automating morning coffee has got to be the next step.

I hope this little project reinvigorates your faith in the EO1, noble carriers of this wonderous device. Here's to even more people starting computer companies!

This Song Also Wrote Itself

Careful readers of this site may recall that I'm the first person in the history of the world to play guitar and sing a song in the back of a self-driving car (TODO: insert "prove me wrong" meme here).

Well, friends, my "talents" were requested again by Cruise.

Thank you to my pal Paul Rosevear for the blues-y, groovin' strummin' tips last week (please teach me more guitar stuff)! Thanks also to the great Chuck Berry (all albums should probably include this thank-you)! And thanks to Carly for tolerating all the practicin' I've been doing in preparation (and also for the bouncy-ball lyrics idea in the video)!

Music is the best!

Studio action photo

Surfing the Gopherspace

A recent Daring Fireball post about the (super cool) Playdate handheld gaming system mentioned Gopher, which I'd never heard of before! Here's the referenced tweet:

Gruber mentions he used curl to read the Gopher site, which you can try yourself:

curl gopher://stevenf.com:70/0/journal/2022/04/18/first-playdates-shipping.txt

You should see the full text of the Playdate post as a response. Intriguing, right? Where's the https:// part of the url? What's this gopher thing all about?

Caddyshack

It's time to learn something weird about the Internet again.

Protocols

You've probably heard of protocols before. Maybe you're even an expert in human-cyborg relations. Hopefully, this explainer sits well with all parties:

Protocols are a formalized series of interactions to transmit information between two or more parties.

That's my own homespun definition - so I'll happily accept edits or suggestions (an RFC, if you will). A potentially helpful analogy for protocols that I've seen is a Japanese tea ceremony - a bunch of formal procedures to govern a specific shared experience.

Your favorite network - the Internet - has its own set of protocols that orchestrate its communication, with foundational ones like TCP/IP, as well as ones for things like email, file sharing, and hypertext - aka HTTP - aka the World Wide Web, the protocol that pretty much powers all your apps and sites and whatnots that you like so much.

But the Web -- and its Hypertext Transfer Protocol -- wasn't always top dog for sharing text on the Internet. There were rivals. Competitors. Gophers.

I'm no historian (despite being a history major -- how exactly does that work, anyway?), my folk-understanding-slash-Wikipedia-reading tells me this: while Tim Berners-Lee was inventing HTTP and the Web on a NeXT cube inside of a particle accelerator, a bunch of University of Minnesota (go Golden Gophers!) students and their professor were working on something they, of course, called the Gopher protocol.

Their RFC (RFC 1436) is worth a skim. Gopher is a plaintext protocol well-suited for sharing text documents in a file system-like hierarchy - a distributed document delivery system, in their own words.

When you interact with a Gopher server, you'll typically first receive an odd-looking "ls"-style directory listing of contents, where the first character of each line tells you what type of item it is (e.g. 0 means file, 1 directory, 9 binary file, 8 is a telnet session, g is a gif image, and so on - read them all here).

Here's the example from their RFC:

 0About internet GopherFStuff:About usFrawBits.micro.umn.eduF70
 1Around University of MinnesotaFZ,5692,AUMFunderdog.micro.umn.eduF70
 1Microcomputer News & PricesFPrices/Fpserver.bookstore.umn.eduF70
 1Courses, Schedules, CalendarsFFevents.ais.umn.eduF9120
 1Student-Staff DirectoriesFFuinfo.ais.umn.eduF70
 1Departmental PublicationsFStuff:DP:FrawBits.micro.umn.eduF70

Looks like something out of War Games, which makes me like this protocol very much, Dr. Falken. How about a nice game of chess?

As you may have guessed, Gopher did not win the war with HTTP. Wikipedia gives us a few supporting statements for this conclusion that I'd like to jam into my 5 paragraph essay.

  1. U of Minn tried to charge for their Gopher server implementation for a while, before finally open sourcing it (1993 until 2000)
  2. The Mosaic web browser could act as a Gopher client -- in addition to its main purpose of being a web browser
  3. Gopher is just more rigid than freewheelin' HTML

Also, there's probably more reasons, including that it's not supes secure, being a plaintext protocol and all.

So, yeah, we're not surfing Gopherspace right now. But we can be! There are still devotees to Gopherdom, maintaining phlogs (which is a blog aka weblog, but taking the ph from "gopher" instead of the "bl" from "webblog", ugh, enough).

Anyway... let's set up a Gopherhole!

Running a gopherhole on Replit

I'll assume you're familar with Replit (I've written about my affinity for Replit before) - but, if you're not, it's a service that lets you easily spin up little environments for running code, servers, etc. I run my ROAPI Google Sheet to SQL book library on a Replit repl, for example. More importantly, Replit seems to be an increasingly great place for folks learning how to code and sharing tutorials, so I'm always keen to use it and contribute to the "learning to code" community.

Back to business. Some Googling reveals that the pygopherd project seems like a nice, credible, easy way to get a Gopher server up and running. But spelunking the Github issues tells us that this project is another victim of the Python2/3 migration. Luckily, there's a relatively recent Python3 fork we can try!

So, create a new Python repl and pip install pygopherd. Because we're using Replit and not our own fully controlled machine, we're going to have to do some fiddly stuff with the library's config to get this working. I copy/pasted the pygopherd's config file and mime.types file from the repo into my repl's root directory. I did have to comment out a bunch of the default config settings - it's probably easier for you to just fork my repl, rather than go through everything here. Click "Show files" and view the "config.conf" file.

The actual interesting bit worth chatting about is the "gopher" folder. You can call this folder anything you want (just adjust that line in the config file), but this is where your phlog or gopherhole lives! Every folder will need a "gophermap" plaintext file to share its contents. Here's my directory structure:

gopher/
   gophermap
   stories/
       christmas-at-grants-tomb.txt
       plastic-man-on-the-moon.txt
       gophermap

And here's my top-level gophermap:

Welcome to my gopherhole - this is weird, right?!

nav:
1Fahrenheit52    ./stories

My gopherhole lets you click into a "stories" folder and then click into two of my short stories from my Fahrenheit 52 weekly writing project.

Here's the gophermap for the stories folder:

0Plastic Man on the Moon    ./plastic-man-on-the-moon.txt
0Christmastime at Grant's Tomb    ./christmastime-at-grants-tomb.txt

Note the 0 as the first character on the lines for text files and the 1 for the directories, as specified by the RFC. Double note - you literally a literal "tab" character between the file name and its location. I had to open up TextEdit, hit tab, and then copy/paste it into Replit to make this work.

Now, with your files in place, and your config adjusted (like I said, just use mine), you can start your Gopher server:

pygopherd /home/runner/{YOUR_REPL_NAME_HERE}/config.conf

You should see this Gopherspace pop up in the Replit browser window! Here's mine, in our third iframe of the blog post thus far:

Very cool! Go ahead, click stuff. You can navigate to and read my story about an action figure on the Moon.

However, it looks like we're just interacting with a Web interface rather than accessing my gopherspace via the actual gopher protocol. That's no good. It does give a link to "view with gopher", but this doesn't work, even when you try it with curl. I suspect there's something blocking this on the Replit side - I've tried adjusting the ports many times, but haven't been able to figure this out. Any Replit folks out there who might have an idea, let me know.

Still, this is decent progress. Words of affirmation. But I really do want to view my stuff through Gopher itself. Let's try it out on our own home server.

Running a Gopherhole on a Raspberry Pi on your Tailscale network

I've got one of those cute Raspberry Pi keyboard computers at home, because its the perfect machine, connected via Tailscale (another one of my favorite services/companies/tools in the world).

We can do a fairly identical setup to Replit to get this working. Create a new project folder on your Raspberry Pi, spin up a virtualenv, pip install the pygopherd package, add the same files from the Repl and you're basically done! There's a few slight changes to the config file (again, these changes are mainly just commenting out a few lines and adjusting the filesystem location of a few files, like the config). I posted my setup to Github if you want to follow along on your own machine.

After we start up pygopherd again (same command as before, with Replit - just provide the location of your config file), we can try curling our gopherspace:

curl gopher://charliesraspberrypi:4444/1/

iWelcome to my gopherhole - this is weird, right?!    fake    (NULL)    0
i    fake    (NULL)    0
inav:    fake    (NULL)    0
1Fahrenheit52    /./stories    pit    4444    +

Woot! We're finally gophering over here. I'm not sure what these "fake" and "NULL"s are all about. Something for later. You may also note that the port is 4444 which I arbitrarily picked (this is another thing you'll want to adjust in your config file), and the host name will be the IP of your Raspberry Pi.

Let's try to fetch one of our stories next.

curl gopher://charliesraspberrypi:4444/1/stories/plastic-man-on-the-moon.txt

It works again! Now, we're not exposing our Tailnet to the Internet, so this will only work when I'm on the VPN, but hey -- I've got a gopherspace now, and you can, too.

The future of gopher

I wouldn't go betting the family farm on this protocol, but if you're into computer history like me, this can be a fun thing to poke around with. There are others like us out there. Actually, I learned that, for a while, you could run a Gopherhole directly in Redis!

As for me and my gopher future, I'd like to keep dabbling. Maybe write my own terminal client? Maybe set up an actual gopher server on a cloud provider to mirror my blog?

The possibilities here are... limited.

iPad Terminal Setup

Sometimes magical thinking works out just fine.

Once I get an iPad, I'll do that thing I've been procrastinating forever, cause, you know, the iPad has this app that's really good at...

Well, we got an iPad. And I love it. Productivity-boosts are yet to be observed (please disregard the alarming Screen Time usage reports), but this honeymoon phase is strong.

Now, much of this love stems from the fact that my 2016 MacBook Pro laptop cannot, in fact, act as a laptop -- the screen turns black once you open it past, give or take, 10 degrees. The friendly Geniuses offered to replace my entire screen for almost $900 buckeroos, which I politely declined. So, it's clam-shell mode for me, at least until the (please-be-colorful) new MacBook Airs come out sometime this year.

Having a little machine to do stuff on the go is pretty cool. I've reset my Anki deck and my daily flashcards are going pretty well for the first time in months (tapping the screen with the little Pencil is part of the appeal). Procreate is just as cool as everyone says and I'm excited to get better at it. I've also been dabbling with different apps to SSH into my various Raspberry Pis and mostly just running sudo apt-get update && sudo apt-get upgrade, which has been made insanely easier thanks to Tailscale. So far, I dig Termius the most. Once nice thing that I setup was a little script to auto-download all the cool monthly Raspberry Pi maker magazines on a cron, and then I can use Tailscale's Taildrop to send them over to the iPad (haven't automated this last bit yet!).

SSH-ing is cool and all, but what if I'm on airplane mode and want to do some coding. That's where iSH comes in.

iSH is a tiny little Alpine Linux environment in an iOS / iPadOS app. No, you're not getting a shell to your actual iPad's OS or filesystem - it's all sandboxed, as per App Store regulations, but it's still pretty cool what you can do with it. Given that I've been wanted to try out following the kilo Build Your Own Text Editor in C tutorial, iSH is perfect for this. But not right away - the initial setup is bare bones, which is how Alpine is designed. Maybe you've noticed that many Docker containers start with an Alpine base image - just like those Dockerfiles, you'll need to install most of your handy CLI tools here. I found some useful guides on iSH setups for C and bash, and here's what I'm working with now:

On top of this, I also set up my git config and copied over some of my dotfiles. Here's how things look on the ol` new iPad now:

iPad with iSH

I'm ready to do some C, on the go!

My only gripe, at this point, is the lack of support for alphanumeric key-repeat in iSH and Termius. Very odd, and makes vim navigation much harder.

Now, with the exception of Procreate, none of this stuff is better than having a real-deal laptop, but it's pretty cool how close we can get to a decent dev environment on an iPad. And it's great for watching stuff, too, but you already knew that.