Category Archives: Projects

Everything’s a trade-off

My hands, damaged from pull-up and hanging practice with callouses I have to file down or risk tearing off.

My fitness goal for 2024 is to be able to do a single one armed pull-up on each arm. I still want to maintain my previous progress of being able to do a pistol squat (and improve it to be less ugly).

This means I now have to do hand maintenance, which is new to me. I have to take a FILE to my hand to sand down callouses or they build up and TEAR OFF.

Every Frame a Wallpaper

Years ago, Tony Zhou and Taylor Ramos made 28 video essays about film form called Every Frame a Painting and it’s incredible in teaching outsiders a whole new way to think about the art of film. The title is perfect. The content is just stunning, simple ways to look at masters of a form at work.

Lots of folks are known for one-shot takes, but this shows how Spielberg sneaks in gorgeous “oners” that do work without calling attention to themselves.

This essay on Fincher is great, but I love the little golden nugget about how spacing shows the evolving relationship between Mills and Somerset

That title always struck me. Every Frame a Painting. That’s gotta be a bar filmakers strive for. Some make it.

Some movies are just so damn beautiful. Just gorgeous.

Like Across the Spider-Verse. Yowza!

Like Sita Sings the Blues! Beautiful.

Like The Fountain

Like the one that you like that isn’t my cup of tea.

Might be nice to see an image from it, right there behind all of your terminals and windows and such, set as your wallpaper. If every frame’s a painting, set a random one as your wallpaper whenever I like it.

So here’s the plan. I want it. So I made it for me. You can have it. But here’s the terms of the deal. I made it for me, so if it doesn’t work for you, you have to make it work for you. If it causes you problems, those are not my problems. If you don’t agree, this isn’t for you.

This will take as an input a movie file, anything that ffmpeg can deal with. You’ll need to install ffmpeg – look on the official site for instructions.

By default, it won’t use the first 5 or last 10 minutes since that’s often the credits. But you can override this.

We’ll find out how many frames are in that remaining part of the movie.

We’ll pick one randomly and extract it from the movie.

Then we’ll set it as your wallpaper. Nice!

Want to change this often? Set up a cron job!

Pulling a single frame out the middle of a movie is CPU intense, so you probably want to use nice in your cron job so it doesn’t interfere with the rest of your work.

Here’s the code, save this in a file called every_frame_a_wallpaper.zsh and then chmod u+x every_frame_wallpaper.zsh

#! /bin/zsh
# This is a pretty processor intensive set of tasks! You should probably nice this script
# as in call it with nice -n 10 "every_frame_a_wallpaper.zsh /path/to/video.mkv"

SCRIPT_NAME=$(basename "$0")

# I like a nice log file for my cron jobs
function LOG() {
  echo -e "$(date --iso-8601=seconds): [$SCRIPT_NAME] :  $1"
}

# set up some options
local begin_skip_minutes=5
local end_skip_minutes=10
local wallpaper="$HOME/Pictures/wallpaper.png"
local usage=(
	"$SCRIPT_NAME [-h|--help]"
	"$SCRIPT_NAME [-b|--begin_skip_minutes] [-e|--end_skip_minutes] [<video file path>]"
	"Extract a single random frame from a movie and set it as wallpaper"
	"By default, skips 5 minutes from the beginning and 10 from the end, but this is overridable"

)

# the docs suck on zparseopts so let this be a reference for next time
# -D pulls parsed flags out of $@
# -F fails if we find a flag that wasn't defined
# -K allows us to set default values without zparseopts overwriting them
# Remember that the first dash is automatically handled, so long options are -opt, not --opt
zparseopts -D -F -K -- \
	{h,-help}=flag_help \
	{b,-begin_skip_minutes}:=begin_skip_minutes \
	{e,-end_skip_minutes}:=end_skip_minutes \
	|| return 1

[[ -z "$flag_help" ]] || {print -l $usage && return }
if [[ -z "$@" ]] {
   print -l "A video file path is required"
   print -l $usage && return

} else {
   MOVIE="$@"
}

if [[ $DISPLAY ]]
then
  LOG "interactively running, not in cron"
else
  LOG "Not running interactively, time to export the session's environment for cron"
  export $(xargs -0 -a "/proc/$(pgrep gnome-session -n -U $UID)/environ") 2>/dev/null
fi

LOG "skipping $begin_skip_minutes[-1] minutes from the beginning"
LOG "skipping $end_skip_minutes[-1] minutes from the end"
LOG "outputting the wallpaper to $wallpaper"
LOG "using file $MOVIE"

LOG "Let's get a frame from ${MOVIE}";


LOG "What's the duration of the movie?"
DURATION=$(ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 \
  $MOVIE);
DURATION=$(printf '%.0f' $DURATION);

LOG "Duration looks like ${DURATION} seconds";

LOG "what's the frame rate?"

FRAMERATE=$(ffprobe -v error -select_streams v:0 \
  -show_entries \
  stream=r_frame_rate \
  -print_format default=nokey=1:noprint_wrappers=1 $MOVIE)




FRAMERATE=$(bc -l <<< "$FRAMERATE");

FRAMERATE=$(printf "%.0f" $FRAMERATE);

LOG "Looks like it's roughly $FRAMERATE"

FRAMECOUNT=$(bc -l <<< "${FRAMERATE} * ${DURATION}");
FRAMECOUNT=$(printf '%.0f' $FRAMECOUNT)
LOG "So the frame count should be ${FRAMECOUNT}";


SKIP_MINUTES=$begin_skip_minutes[-1]
SKIP_CREDITS_MINUTES=$end_skip_minutes[-1]

LOG "We want to skip $SKIP_MINUTES from the beginning and $SKIP_CREDITS_MINUTES from the end".

SKIP_BEGINNING_FRAMES=$(bc -l <<< "${FRAMERATE} * $SKIP_MINUTES * 60");
LOG "So $SKIP_MINUTES * 60 seconds * $FRAMERATE frames per second = $SKIP_BEGINNING_FRAMES frames to skip from the beginning."
SKIP_ENDING_FRAMES=$(bc -l <<< "${FRAMERATE} * $SKIP_CREDITS_MINUTES * 60");
LOG "So $SKIP_CREDITS_MINUTES * 60 seconds * $FRAMERATE frames per second = $SKIP_ENDING_FRAMES frames to skip from the ending."

USEABLE_FRAMES=$(bc -l <<< "$FRAMECOUNT - $SKIP_BEGINNING_FRAMES - $SKIP_ENDING_FRAMES");
UPPER_FRAME=$(bc -l <<<"$FRAMECOUNT - $SKIP_ENDING_FRAMES")
LOG "That leaves us with ${USEABLE_FRAMES} usable frames between $SKIP_BEGINNING_FRAMES and $UPPER_FRAME";

FRAME_NUMBER=$(shuf -i $SKIP_BEGINNING_FRAMES-$UPPER_FRAME -n 1)
LOG "Extract the random frame ${FRAME_NUMBER} to ${wallpaper}";
LOG "This takes a few minutes for large files.";
ffmpeg \
  -loglevel error \
  -hide_banner \
  -i $MOVIE \
  -vf "select=eq(n\,${FRAME_NUMBER})" \
  -vframes 1 \
  -y \
  $wallpaper


WALLPAPER_PATH="file://$(readlink -f $wallpaper)"
LOG "Set the out file as light and dark wallpaper - using ${WALLPAPER_PATH}";
gsettings set org.gnome.desktop.background picture-uri-dark "${WALLPAPER_PATH}";
gsettings set org.gnome.desktop.background picture-uri "${WALLPAPER_PATH}";

In my crontab I call it like this:

# generate a neat new background every morning
0 4 * * * nice -n 10 ~/crons/every_frame_a_wallpaper.zsh -b 5 -e 12 /home/mk/Videos/Movies/Spider-Man_Across_the_Spider-Verse.mkv >> ~/.logs/every_frame_a_wallpaper/`date +"\%F"`-run.log 2>&1

Automated export of your goodreads library

Goodreads used to have an API but they stopped giving access and it looks like they are shutting it down. A real garbage move.

I like to be able to use my data that I put in so I wrote a script to automatically download my data regularly. Then I can do stuff like check to see if books I want are in the library or keep my own list or analytics, etc.

Here’s the python script to export your good reads library, hope it helps you. I’ll put it in the public domain.

Updated to add: I got tired of dealing with places that do garbage moves. I left GoodReads for BookWyrm and it’s better.

Week 2206

Politics

I donated money to the Alex Morse campaign, a progressive candidate who’s trying to unseat Richard Neal, a greedhead Democrat. That happened earlier, but recently it appears that there was a sex scandal accusation against Morse. He’s accused of having consensual sex with adult students at the university he teaches at that are not in his class and also messaging people he’s met on Tinder. Sexual harassment and consent are incredibly important, but weaponized accusations are exactly the sort of thing that conservatives have professed concern over. In Alex’s case, the investigation by the Intercept certainly makes it seem like people who want to work for Richard Neal have been manufacturing a scandal instead of uncovering one.

Other campaigns I’m looking closely at:

  • The State Slate – The great slate didn’t do great in 2018, but I still like these ideas and I’m willing to give again. These candidates are all good chances to flip a district and any campaigning they do is good for upballot races.
  • Donna Imam – an engineer who might be able to flip a texas district.
  • Dani Brzozowski

Family

The fam out at the Esopus Creek trail

We’ve been doing more hikes again. I’m trying to make sure the little monsters leave the house every day. We’ve been going out to the village a little bit as well. I haul the kids in our expandable wagon and we can eat at an outside restaurant called The Partition.

We’re getting an eensy bit more social (in safe and measured ways).

ZZ had an extended encounter with a nice lady named Alexa and her dog Chacho. They spent an hour hanging out and I can’t recall having a nicer meal in ages. Here’s pro tip – if you hang out with the children and amuse them while we have drinks and dinner I’m grabbing your bill!

Beer Club had a mini executive retreat when Ray showed up in Rhinebeck! We took the Ho’s to the FallingWater trail where I finally got to meet Finley! He loves Max and Zelda loves him.

The Scott’s dropped by! We took them out to Fallingwater as well, where Max and Ben got along really well and explored up the waterfall all the way to its source. Zelda is in love with Zoe and asks about her.

Max and Ben never usually play together, but for some reason this day was just perfect. Everyone got along famously.

DIY

Around the house, we’ve been struggling a little to knock out more projects. It just seemed like we lost steam. So we dug out the back yard next to our house and put in a bunch of marble rock chips over garden cloth. Now things are better looking and won’t require any weeding – instead of a dirt patch next to the house we have clean white stone which doesn’t need maintenance.

We cleaned out the trampoline, which had been under a mulberry tree, trying to become a mulberry jam strainer. Yecchh.

We spent a couple of meeting looking at adding solar panels to our roof – I really like it for a lot of reasons including my predilection for distributed systems over centralized ones. Sadly, the tradeoffs right now don’t seem worth it. Even with incredible financing and all sorts of incentives it would take forever to pay off the panels and require trimming trees.

This helped me feel like we can really start getting going again. I’m gonna finish that Patio!

Code and nerdery

Great news here! I’ve been thinking at work about ways to better handle and test documentation across multiple languages. The key here is to make sure that you can extract code samples from documentation and then push it out to a testable format.

I found mkcodes, an excellent tool for pulling code out of markdown documents. It worked great, but only for Python. I submitted a pull request extending it to work with multiple language code blocks and it was a real treat to work with Ryne Everett on getting this live. Which is to say, now it can handle java, dotnet, any other language you like that’s embedded in your docs. Expect more on this as I make progress building a docsite with eleventy.

I also type this on the linux laptop as I managed to resize partitions without destroying anything. I thought 80 gigs would be enough for my Ubuntu partition, but it seems to be growing and I had to give it a few hundred more gigabytes to grow.

Week 2202

In the past week, the federal government used some very flimsy excuses to send federal “police” into Portland and take protestors into unmarked vans without identifying themselves. The scary times have gotten even scarier, the authoritarianism even more blatant. There is so much awful stuff going on that I can’t even take in all of it, much less do meaningful work on it. I’m trying to just do small things often. I’m trying to do things like donate to campaigns that will help, sign petitions, elevate small things that are going to turn into big things.

Since we’ve donated some large sums in the past, I sometimes get directly called by candidates. I resolved to take time to ask them specific questions about things that matter here since I often get called by them when I’m changing diapers or doing other family stuff. I spoke with Alex Morse, who is a Justice Democrat who is running for congress – he’s endorsed by Jamaal Bowman (who just beat Eliot Engel). We talked about his work as a mayor in western Massachusetts, dealing with police unions, restorative justice and combating systemic racism when you are the executive – he’s notable I think for actually working on these things. I also took some time to petition Nextdoor, a social network where local racism is really evident, to halt work with Police departments. Features like “send this to my police” really don’t take into account what happens after the police show up, and why this isn’t something to do lightly.

Family

We paid off the ticket from the fourth, met with a guy about solar panels ( we don’t use enough energy to justify the cost even with multiple incentives from the state). We’re also looking for electricians to add some outside outlets and a ceiling fan in the living room.

We sorted out better schedules for me to work and be with the family predictably during the day. It’s easy to both work forever when it’s in the house or to bunk off when something cute is happening. Trying to be balanced, so we solved it with a gCal that Sam can see with times that are marked out of office on my work calendar. That way it’s easier to know when “I’m definitely working, don’t bother me” and when “let’s take a break and play”. Making it visible to work lets folks there plan around when they shouldn’t expect me to be available.

We got Swale and Zebus some bikes! They rode them! It is cute!

The Brooklyn apartments are getting some interest on the market – 25H at least has some people viewing it. 25J is where the bigger mortgage sits, so I hope that it pans out quickly as well.

Nerdery

I added some better color settings to Jumpstart – and made installing ruby gems safe, similar to what I did earlier for node.

Also set up 2 way syncing on the Synology NAS drives in brooklyn and upstate so that everything is backed up everywhere. For the meantime at least, the upstate is the new primary and brooklyn is the secondary. I tried out Ranger as a terminal file manager. Also, I made a dumb little script to make memes easier.

After I told folks about Pingplotter on the cesspool/hobby network reddit, it inspired Toazd to write an even more complete and colorful version of pingplotter.

Work

Highs and lows in the ladder of abstractions, highs and lows success wise.

I worked very high in the ladder of abstractions, transforming a large backlog of tasks into a program of new product features and a big revenue opportunity. At the same time I had a pull request submitted and accepted to fix a client issue. I got a great review ( we use OKRs to have quarterly conversations around progress, so it is sort of like a review), and then my laptop died!

It’s a sweet little lenovo yoga 920 and was running Ubuntu and Windows, I was loving using it. But it’s really disappointing for it to die hard after 2 years. To get it replaced involves shipping it out, going through a 3 day quarantine, up to 9 business days to fix, then 5-7 business days to ship back. I’m lucky to have enough spare laptops in the house that we were able to get Sam’s macbook hooked up. My 2013 macbook air would have been fine, but the thunderbolt port apparently doesn’t work (first time I’ve ever tried it!)

I hope when I get the Yoga back it won’t be wiped and I don’t have to go through a whole setup process again.

Consciousness is a scale, not a binary

When my son Max was born, my sense of who I am blossomed to include this tiny wet lump screaming flesh. He is me, more important than the part that goes to work in Manhattan.

But he didn’t do a whole lot. Even when he grabbed my finger, it was a reflex operating. There wasn’t much internal life or reflection. Like all of us he was on a journey to develop into a person. He’s on the acceleration part of that trip now, so every week he develops something new, connecting concepts and creating abstractions. Now I can hear him babbling stories to himself where he used to just experiment with the noises his mouth could make. The curve of his growth has a near vertical slope as he becomes aware of who he is and who his parents are. He knows he has a baby sister coming in May and is dimly aware she will be boring at first.

He will watch her grow into her own consciousness and expand his self to his family. If we’re lucky, they will both grow to include something bigger than themselves in their consciousness.

I’m still growing in wisdom and experience, but I’m no longer accelerating. My growth happens in smaller chunks and less often. I have to push myself to learn and escape comfort to grow. My epiphanies are shallower and less frequent. The slope of my growth curve is flattening before it peaks and descends. Then I will be more like my father.

The smartest man I’ve ever met is learning fewer things and his stories repeat and loop and meander. He tells me “You might not be aware of this, but…” and then he tells me something again. He might be forgetting things like what it is to be poor or disregarded faster than he learns his latest passions. Someday I’ll be telling stories to my kids that they already know and I hope they will love me enough to listen closely for what I’m saying underneath my words.

So I see intimately a scale of consciousness, introspection, reflection that flows through my past and future. I was a flat sheet, then the world made impressions on me until I’ve become crinkly enough make new interfering patterns in myself. Some day I will lose my flexibility and start to flatten again.

If consciousness is a scale in people, how conscious is a dog. Sorta? They seem to think and plan. They hide and deceive and love and grieve. How conscious is a kitten vs a cat? How much of a soul does a mouse or parrot or gorilla have? They have some consciousness, as does a mosquito. Consciousness becomes a lot easier to talk about when you can say “sort of” conscious instead of talking about a binary, as Daniel Dennett proposes.

So I’m a self reflecting system, my son is self organizing into a more crinkly experience of the world, my father is smoothing out and my soon to be daughter is barely there. Surely she sits in Sam’s belly as more of a possible mind than the concrete though simple plans and dreams of my neighbor’s dog.

If you’ve stuck through this far, sorry this is how I’m announcing that we’re having a baby daughter in May.  I couldn’t figure out a saner way. So let’s also talk about something crazy but probably true: Pan-psychism. Once you let go of consciousness as a binary, you can realize that everything sorta thinks to some degree.

Most of the pan-psychic folks come at it from a place of duality, thinking that if the meat that types these words has a soul, why couldn’t a calmer version of that soul inhabit a rock or a tree or a table? I come from a different perspective. Any system that reacts to stimulus and then modifies itself or reacts to changes within itself is practicing some sort of consciousness or soulness. That perspective is useful when you think about corporations or economies or earthquake resistant buildings or networks of trees and fungus communicating and sharing resources in forests.

Taking a break from Orbital

My hack-night project for a long time was Orbital Feed Reader. I’ve been slacking on it a lot recently. Especially after the election, I feel like I need to find things to work on that have a more direct impact on people that I can help.

I worked on a project called Donate the Difference  – it wasn’t as successful as I wanted it to be, though it did raise $25K for some charities. I learned a lot, and I’ll write some of that up here later. But it made it clear to me that I need to work on projects that make a bigger difference than a feed reader plugin.

I’m not certain what that is yet, but if you were hankering for updates to Orbital, that’s why they haven’t been coming. It’s open source, and I’m happy to take pull requests or turn it over if someone wants to do more with it. I just don’t want to lead folks on.

Mistakes were made, tears were shed

Orbital 0.2.2 – Mistakes Were Made

 

This is a tweak to fix some problems people told me about on the Orbital Feed Reader GitHub Issues page.

Some folks were getting a very bad experience during the install – everything goes blank – or they were able to install and then couldn’t add feeds or read feeds. Not good for a feed reader!  I traced down a problem where if you had a specific new default collation on your database, the way I initialized the database tables made everything go boom.  It’s fixed now, but it’s part of the problem of supporting a lot of different configurations without a giant automated test lab.

The other was that someone pointed out there is an improved PressThis page in the latest version of WordPress.  Everything was working, but you’d get a nudge message saying that there was a new way to use PressThis and why are you going this old way?  Updated and I think it’s a really good experience now!

I also did some cleanup and logging improvements so that I can work with folks who have problems in a better way.

Quick TV Pillar Mount Project.

early assembly with TV

Now that Maximum Baby is crawling I wanted to get our huge tv off of the rickety cart it was sitting on. Sam had a tv fall on her as a child and one is enough for us.

The tricky thing here is that we wanted to mount the TV on a concrete pillar.

Trying to attach a flat thing to a curved thing is tricky.  My solution was this:

  1. Got a 2×8 of Douglas Fir from my local Home Depot. They usually have crappy wood, but I managed to find a piece that looked quarter-sawn, so that’s good.
  2. Cut it to length based on the height of my TV, the height of my soundbar and allowing room for attaching some shelves later.
  3. At the base trim each side 45°, then angle the saw blade to 45 and make a cross cut. Makes a nice beveled end instead of a dramatic right angle.
  4. Use some of the scrap at the top to increase the depth so the TV mount screws get a lot of purchase depth. I used wood glue and 8 screws.
  5. Prime and paint.
  6. Attach hardware.
  7. For attaching it all to the pillar I decided to go with a friction mount. I ordered 3 endless loop ratchet straps and ratchet them tight against the pillar.

Using a friction mount is a dicey thing. Materials have two kinds of stickiness – or friction coefficients. One is how sticky two things are when they are at rest (static friction coefficient) and the other is how sticky two things are when they are moving (kinetic friction coefficient). Friction works great right up until you overcome the static friction coefficient and then it works very poorly because the kinetic friction coefficient is always lower than the static friction coefficient.

Good news is we can calculate how much force our friction mount should support! Friction is dependent on the pressure between two surfaces (the normal force) and the stickiness between them (the friction coefficient). The frictive force is going to be our normal force times the static friction coefficient.

How much normal force do we have? I’m estimating that I can ratchet around 150lbs of pressure on one of those ratchet straps. Let’s cut that a little bit because I haven’t been working out and I am an optimist. Let’s call it 120lbs. I’m using 3 ratchet straps so that adds up to 360lbs of pressure.

There’s a table on that page with friction coefficients for common materials. Looks like they say the static friction coefficient between wood and concrete is 0.62. 360lbs * 0.62 = 223.2lbs.

I’m around 175lbs – I should be able to do a pullup on this!

me doing a pull up on a ratchet strapped wood.

And I CAN!

My TV weighs 50.8 lbs, the tv mount weighs 8lbs,  my shelves weigh 11lbs and they can support 22 lbs per shelf. I forget how much my soundbar weighs. Let’s call it 10 lbs.

50.8 + 8 + 11 + 22 + 22 + 10 = 123.8 lbs. I’ve got around 99 lbs of spare capacity before we hit the limit of  my static coefficient of friction!

I feel like I can trust this not to drop on Max for a while!  How long until Max might hang off of this and make it drop? Hmmm – when is he likely to be around 100lbs? Wolfram Alpha tells me a 10 year old American is around 94lbs. I should be able to teach him not to do it by then or get another ratchet strap.