Updated Supermario to Fedora 34

Upgrade the main computer to Fedora 34. The upgrade was uneventful, but left me with a few little annoyances. It’s running Wayland, so there’s no longer a primary monitor. Also, something is slamming my processors and some programs are taking a long time to load. I was hoping things would be in better shape by this point in the life-cycle, but every once in a while there’s a buggier Fedora.

Programming Update for June 2021

June was mostly Python, although I did do chapter 1 of Scratch 3 Games for Kids with Sam. He really, really enjoyed it and I anticipate doing the challenge problems and maybe chapter 2 in July or August.

Books

I read the intro and first couple chapters of both Flask Web Development, 2nd Edition and Data Visualization with Python and Javascript, both from a recent Humble Bundle. The Flask book may be useful for learning more about creating a non-Django site and, even if I mostly stick with FastAPI, it should provide some concepts that are applicable across both frameworks. With the data visualization book, I would love to use that to better visualize my annual Last.fm stats.

Advent of Code

While at my in-laws’ house, I completed days 13 and 14 of 2015’s Advent of Code. Back when I first started working on Advent of Code 2015, I went through all the problems and posted my first stab at a solution into a Google document. For day 13 I’d predicted that a modified version of the Traveling Salesman problem I’d done in 2015 Day 9 might work, using an asymmetrical matrix. That turned out to be exactly the right solution. In Ruby I learned how to do a Ternary expression. In the function “create_guest_hash” see the number = expression.

require "../../input_parsing/parse_input"

def create_guest_hash(lines)
    guest_hash = Hash.new
    lines.each do | line |
        people_and_values = line.scan(/(\w+) would (gain|lose) (\d+) happiness units by sitting next to (\w+)\./)
        if !guest_hash.has_key?(people_and_values[0][0])
            guest_hash[people_and_values[0][0]] = {}
        end
        number = people_and_values[0][1] == "lose" ? "-#{people_and_values[0][2]}" : "#{people_and_values[0][2]}"
        guest_hash[people_and_values[0][0]][people_and_values[0][3]] = number
    end
    guest_hash
end


def create_matrix(guest_hash)
    index_hash = Hash.new
    guest_hash.keys.each_with_index do | key, index |
        index_hash[index] = key
    end
    matrix = []
    index_hash.keys.each_with_index do |index|
        temp_internal_list = []
        current_person = index_hash[index]
        index_hash.keys.each_with_index do |internal_index|
            if internal_index == index
                temp_internal_list.append(0)
            else
                temp_internal_list.append(guest_hash[current_person][index_hash[internal_index]].to_i)
            end
        end
        matrix.append(temp_internal_list)
    end
    matrix
end


def perfect_seating(happiness_graph, starting_person, number_of_people)
    vertex = []
    (0...number_of_people).each do |number|
        if number != starting_person
            vertex.append(number)
        end
    end
    max_happiness = 0
    permutation_list = vertex.permutation.to_a
    permutation_list.each do |permutation|
        current_happiness_weight = 0
        
        outer_array_index = starting_person
        permutation.each do |inner_array_index|
            current_happiness_weight += happiness_graph[outer_array_index][inner_array_index]
            current_happiness_weight += happiness_graph[inner_array_index][outer_array_index]
            outer_array_index = inner_array_index
        end
        current_happiness_weight += happiness_graph[outer_array_index][starting_person]
        current_happiness_weight += happiness_graph[starting_person][outer_array_index]
        
        max_happiness = [max_happiness, current_happiness_weight].max
    end
    max_happiness
end


if $PROGRAM_NAME == __FILE__
    guest_preferences = input_per_line('../input.txt')
    guest_preference_hash = create_guest_hash(guest_preferences)
    guest_preference_matrix = create_matrix(guest_preference_hash)
    starting_person = 0
    total_happiness = perfect_seating(guest_preference_matrix, starting_person, guest_preference_matrix.length)
    puts "With the perfect seating arrangement total happiness is #{total_happiness}."
end

Day 14 turned out to be a very easy solution that was able to use what I’d come up with ahead of time without modification; for part 1, anyway. Part 2 became a bit of a mess that seemed to require create a Reindeer class in order to keep track of which Reindeer to award points to. Since I hadn’t done anything with Ruby classes yet (wasn’t really covered in the Ruby book I read with the kids), I haven’t yet done the Ruby or Perl solutions. You can see my Python solution here.

Prophecy Practicum

I made a bunch of quality of life improvements for my friend, aka The Client. I was pretty happy at my ability to continue to figure out how to make use of Django’s many built-in features.

Extra Life Donation Tracker (eldonationtracker)

I had to do a bug fix for a change in the way the API handled anonymous donations. Overall it wasn’t too hard. Sometime soon I intend to start separating out the Donor Drive API into its own project apart from the Extra Life code.

Impractical Python

After a long hiatus, I returned to Impractical Python and finished the Haiku chapter. It used Markov Chains and the CMU language module to help teach the computer what a valid Haiku was. Here is one of the Haikus it generated:

listen: new year's bell!
bell! standing still at dusk house
listen in far in

This next one is kind of nonsense, but I like it. Seems faux-zen:

oh no! a white swan
butterfly butterflies the
only fluttering

This one is closer to a real Haiku:

let myself pretend
my old sadness winter rain
rain deepens lichened

I’ll leave you with this last one which actually sounds like a human-written Haiku:

closer, quilt and leaves,
enfold my passionate cold!
cold! dry cheerful bright

MxPx – MxPx: You’re Never Too Old to Rock

MxPx Front Cover

Last October I came back to MxPx, as I detailed in this post about how the lyrics for Friday Tonight led me to finally watch Friday. Over the past half year I would return to their self-titled album on Spotify. (I don’t subscribe to Spofity, but I do use the free tier to discover new artists) Eventually I decided to go ahead and buy the Deluxe version of the album directly from MxPx. It doesn’t appear they’re selling the CD anywhere else (at least it’s not on Amazon). 

For the most part, I found the music on the album to sound pretty similar to Teenage Politics, Life in General, and the harder punk songs on Slowly Going the Way of the Buffalo, The Ever Passing Moment, and Before Everything & After (although I hadn’t heard this album last yet at the time). Interestingly, back in 2013, I wrote about relistening to my older MxPx albums. While I did focus on age allowing for appreciation of a slower, less aggressive sound – I think the genesis of that blog post was the (potential) silliness of going back to kiddie lyrics as an adult. Now, much closer to 40 than I was then, I think it probably is even more of a truth. But, I think I was perhaps too harsh on the idea of hard rock itself. It’s just that, up to that moment, a lot of that style of rock hadn’t grown up yet. Most of the bands were hardly older than me and they were also writing towards what they hoped was a more lucrative audience. 

But now we’re all older and I believe the members of MxPx are about 5-7 or so years older than I am. So this album contains lyrics tackling more mature topics. Oh sure, there’s still Rolling Strong which can truly be best appreciated by other musicians. But songs like Let’s Ride, Life Goals, Pipe Dreams, and Moments Like This (especially Moments like This) definitely come from an older songwriter and resonate a lot with me as an older guy and a parent. And YET this is a hard rocking album. This is an album I love to put on while driving and just jamming on the highway. If the wife and I were driving around as much as we used to do before the pandemic, I’d love to get her addicted to some of these songs to jam out with me like we used to do with Anberlin. 

MxPx Back Cover

Let’s look at each track individually:

  1. Rolling Strong – Just like Play It Loud on Before Everything & After, a song about being  a band; this time about touring with hints of “don’t discount us because we’re getting old.”
  2. All of It – Basically, a punk rock love song. The title comes from the chorus, “how much of your love do you think I need? All of it”. Most of the lyrics involve the singer talking about how he’s going to make the relationship a great one.
  3. Friday Tonight – As I mentioned above, the song that got me interested in MxPx again. Definitely a rousing song to play at concerts, especially if they happen to be taking place on a Friday. The opening music is way calmer than the rest and a cause for a somewhat jarring move into the proper song. The lyrics are kind of nonsense, especially compared to the rest of the album. I mean, each verse has a coherent thought, but the song as a whole doesn’t really come together in any real way. Or rather, it’s basically poetic in the same way that sometimes some of the earlier Fall Out Boy songs are poetic; again each verse stringing together logically even if the whole doesn’t cohere as easily as a typical song.
  4. Let’s Ride – a biographical song (or at least that’s the conceit) in which the singer tells his friend and/or partner that they should just experience the joy of driving and leaving things behind. It doesn’t seem to be a “screw the world we’re leaving it all behind” vibe. More like: let’s escape for a while and renew our batteries. 
  5. Uptown Streets – Hard to properly quantify, but I guess it’s a “don’t forget your city areas’ type of song. But I do love the cheekiness of this early verse: “I was truly scared, for the first nine years I ran/ It was a mighty fine day in the USA I bet/ Wrote it on the back of my hand so I wouldn’t forget”
  6. 20/20 Hindsight – The lyrics are a bit vague, but it seems to be a singer lamenting what they will do once they can no longer be in a band. But can be generalized to anyone who’s losing the ability to do what they love.
  7. The Way We Do – Essentially a song about MxPx being happy they have the life they have. They reminisce about some past tour pranks and express an overall gratitude that they get to do what they love for a living.
  8. Life Goals – A somewhat sarcastic song about how life doesn’t always care about the goals you have. Pretty catchy chorus.
  9. Pipe Dreams – Great symmetry with Life Goals it tells you to “hold onto those pipe dreams”. My favorite line in the song, “hold onto those pipe dreams/If I’m wrong/the worst is already happening”. The music has a happy tone and the lyrics just balance so well against the symmetry of the previous song. 
  10. Disaster – It sounds like it’s going to be a negative song or a sad song of unrequited love, but as best as I can tell, it’s essentially the song’s protagonist saying that the effect the object of his love/desire has on him is to leave him stunned. Basically seems like a hyperbolic statement to say disaster, but the rest of the lyrics seem to suggest things are fine, the protagonist is just SO in love. Also, I love what Herrerra does with the vocals on the lyrics: “I have the best time with you…everlasting”. I know it’s a technique I’ve heard on other punk songs (maybe other MxPx songs? I can’t remember) but I’d love the podcast “Why Do I Love This?” to analyze what it’s doing and why it tickles me so much.
  11. Moments Like This – This song is the PERFECT ending to this album. It works so well that I’m *almost* disappointed that it goes on for four more songs in the Deluxe version I bought. I like ¾ of the added songs, but I just think this is the perfect closer for an album that is about punk rockers all grown up. They’ve been a band since high school and are now in their 40s and this song just works so well as the end of this album.It’s about savoring life as it happens. Every time I hear the song I want to make sure I spend more time with the family.
  12. Best Life (Starting from here these are tracks exclusive to the Deluxe edition) – This one almost sounds more like a Aerosmith song or some other non-MxPx band. Also sounds like it could be in a commercial. It’s OK as a drinking song, but it’s my least favorite on this entire album.
  13. The Band Plays As We All Go Down – referencing a (legend? truth?) about the Titanic, the song seems to oscillate between hope and despair. But a good return to an MxPx sound after the previous track.
  14. Forget it All – A song about being frustrated and wanting to get it out of your system. A nice, fast beat – could be great for a concert.
  15. That’s Life – Another track about getting older. Partially about the world changing around you and partially about dreams unachieved. It’s actually not a bad album-ending song, but it’s slightly sadder than Moments Like This. I like Moments Like This a bit better for the last track because it’s slightly more positive. (The next five songs are actually on a second CD if you buy the CD from their merch shop, so I consider them to be a separate acoustic EP)
  16. Let’s Ride (Acoustic) – this one works well as an acoustic song
  17. All of It (Acoustic) – this one’s OK acoustically, but I like the original better
  18. Uptown Streets (Acoustic) – This one ALMOST works better in the acoustic version than in the original version
  19. Rolling Strong (Acoustic) – I really don’t like this one as an acoustic song at all
  20. Moments Like This (Acoustic) – this one works equally well in each version

Django vs Flask vs FastAPI

Over the 16 years that this blog spans I must have, at some point, mentioned that I believe sometimes we get knowledge when we’re not ready to receive it.This isn’t some spiritual or new age thing (although you’ll hear Chopra and/or Tony Robbins talk about the phenomenon). It’s simply my lived experience. Sometimes you come across some knowledge, but there’s some underpinning knowledge missing or maybe some life experience you don’t yet have to put your new knowledge into context. So sometimes this leads to a difficulty in learning the concept and other times you just don’t get the point of it and file it away or throw it away – no need to waste neurons on this!

The same thing has happened to me with Python and Web Frameworks. I already mentioned this a bit in my March 2021 Programming update. But I wanted to elaborate on it in its own blog post. A bit of background – back in the late 90s and early 2000s I created lots of web pages using HTML and, sometimes, a bit of Javascript. Right around the time of HTMLX and other initiatives to get the web to be more interactive (what would eventually lead to Web 2.0 within a half decade), I moved on to using blogging platforms and mostly left web programming behind. Sure, I did a couple things here and there like my Vietnamese Zodiac page (which, at one point, was getting tons of hits on Google), but mostly I left the web behind. Some time in the last 5 years (or maybe more?) I looked at both Django and Flask, but found them inscrutable. Django, especially, just seemed overkill and a huge learning curve just to get started. I left them behind and continued to create command line and GUI programs (mostly with PyQT bindings). 

About 3 or so years ago someone from work approached me asking about a way to automate a part of his spiritual practice. It would clearly benefit from a web interface, but I remembered things being too hard with Flask and Django. Then COVID happened and I had lots of free time to learn things. I took a look at the books and videos I’d bought from various Humble Bundles. I tend to learn best from curated experiences like books and classes as opposed to just reading framework tutorials. I had a video class from Pakt focused on using Flask to create an API-based site. This would be one of the most common workflows in modern web design: an API backend written in Python, Ruby, Go, or Java interacting with a front-end written in Javascript. With this class as my guide, Flask finally made sense. I understood what routes were and how they interacted with the user. I gained a better understanding of how to write a site that would interact with a database. This was great! After taking the class I started working on my colleague’s site. After I had the database schemas set up, we started discussing the user workflow he anticipated. There was a lot of admin backend to construct and, once again, I stopped writing websites back before CSS and all that. Also, unfortunately, the class was focused on an exceedingly simple website and I used the Flask tutorial to try and shore up how to handle user logins and so forth, it all started getting way too complicated. I lost interest and the project floundered.

Then, for some reason – I think I was flipping through my Python books – I decided to look at one of the Django books and found that Django comes with an admin interface built-in. And making changes to the admin pages are somewhat trivial. I was rejuvenated in my desire to help my colleague. So I started recreating the site with Django. There is indeed still a higher cognitive load to Django. The simplest Flask site with its app.route is still infinitely simpler than Django with its views, models, forms, settings, etc. And yet, if you’re already going to go for a more complex site and do your user interface in Python, suddenly all that complexity pays off. The ability to set up your models and forms with ease makes a model-heavy workload so much easier. And I had a better understanding of what all this meant now that I’d work on Flask.

What I find most interesting, and what led me to write this post, is that I recently got O’Reilly’s Flask Web Development from another Humble Bundle. Just as having worked on Flask helped me better understand what Django is trying to do, having worked on Django is feeding back into helping understand Flask. Having worked with models and forms in Django has cemented in my head how web backends (particularly if written in Python) are thinking about the web and separation of concerns; it’s all forming this virtuous cycle. And so while I anticipate perhaps having some momentary screwups where I try to think Flask-y while working Django or Django-y while working on a Flask site, each is helping me become a better Python web developer no matter the framework being used.

So, to the implicit question in my blog post (assuming you’re still reading after that preamble of sorts), I think you’ve probably guessed by now that I’m not an absolutist when it comes to these major Python web frameworks. Django, as I recently learned, was born to power a news website when the idea of a CMS was in its infancy. If you’re looking to create a website with a Python backend that needs a strong admin interface, strong database dependencies, and a more batteries included workflow – you’re going to want to use Django. If you just need an API that’s going to interact with mobile apps or Javascript, then (at my current level of understanding) it’s a toss-up between Flask and FastAPI. I think MOST apps nowadays use a database of some sort, but if you’re not using one, then you’re definitely better off using Flask or FastAPI instead of Django. They’re both barebones with a lower cognitive load to get started. Flask is older and may have more plugins and add-on packages to help with features you might want to add on. FasAPI is newer and Async native as well as getting some input validation “for free” thanks to Pydantic. It also has a really easy way to write Pytest Unit Tests. It’s almost too easy! FastAPI’s website maintains a page comparing it to alternatives as an explanation of why the original dev put it together. It seems written in a fair manner although it’s obviously going to be at least slightly biased in favor of FastAPI. As I said, I am just a baby dev when it comes to Python web frameworks, so I’m not the best person to comment on when to choose Flask over FastAPI, but I’d probably lean towards the latter if I were starting a site fresh. It really does a lot of great things with JSON automatically and is self-documenting. 

The important thing is not to be dogmatic about things. There are occasions where each is best. I LOVE FastAPI for my Civilization VI Play By “Email” webhook server. As I spent lots of digital “ink” above describing, Django works perfectly for my colleague’s web app. Using Django freed me from coding and maintaining all the admin code and database handling. And on the other side, my webhook server just needed to have some REST API points. Even if I eventually add database support, I still don’t need any kind of admin or real user account service with that app. So when you’re ready to write your next Python web app, think about your needs and think about what the strengths and weaknesses of all the frameworks are.

MxPx – Before Everything & After: What if MxPx made a Good Charlotte album?

(the first 3 paragraphs are a slight modification of what I wrote for an Amazon review)

cover of MxPx Before Everything & After
Album front cover

The headline kind of gives it away, but this album definitely sounds like a cross between early/late MxPx and Good Charlotte. You can see on Wikipedia and other places that this was part of a 3ish album trend where MxPx moved more towards the pop part of pop punk. Kind of interesting coming back to it now. I was listening to MxPx albums as they came out in the 90s, but fell off with The Ever Passing Moment. I even briefly joined the fan club and still have the shirt. Because of Reese’s interview on Mike Herrerra’s podcast, I recently started listenign to their self-titled album, which sounds like their early stuff except with lyrics that match grown men the grown men they now are vs kids they were when writing Teenage Politics.

back of CD for MxPx - Before Everything & After
Album back cover

While you’ll find tons of folks complaining about this stretch of pop-ier albums, I don’t think there’s anything inherently bad about it. This album is a good album on its own. And it could be a great gateway album to get someone into MxPx with this “softer” sound; afterwards they could move on to the more punk sounds of either their earlier or later albums. I will say, this album is a really big improvement (for me) over The Ever Passing Moment. I wish I’d hung on to my fandom a bit longer to hear this album. I might have stayed along with them all this time. Rather than rediscovering them after 15 years. At the time, though, I was moving on towards a more club sound as well as rap and was moving away from exclusively Christian music to listening to everything. 

So, to sum up – if you’re a new MxPx fan, you *may* find this album to be too strong on pop. It’s also VERY rooted in the time it came out. Then again, if you’re like me and literally like “everything” (eg my top artists last year were, in order: Five Iron Frenzy, Billie Eilish, Relient K, Anberlin, The PDX Broadsides, I Fight Dragons, Vampire Weekend, The BeeGees, and Childish Gambino) then you may not mind a different sound. If you ONLY like hard punk, this is not for you AT ALL. If you’re randomly coming across this album, I think it’s a good album that kind of tracks what a lot of pop-punk was doing in the early 2000s.

Here’s a track-by-track analysis:

1. Before – a bunch of clips from the album, including one that doesn’t appear on the album and appears in a different form on one of their B-Sides collections.

2. Play it Loud – MxPx seems to have at least one of these songs per album: a song about being in a band. Like other songs they’ve written on the same topic, they reject the allure of being famous, they just want to have their music career. This one sounds manifestly the most like Good Charlotte mixed with MxPx. This one’s a banger that I’d love to hear in concert.

3. Well Adjusted – Another song that sounds like Good Charlotte. (I could also maybe hear some eras of Green Day) This song is VERY 2000s. It’s about taking pills to be alright. Aligns with a lot of what was in the air at the time that we were being overprescribed pills to make us conform. Jimmy Eat World’s “Pain” tackles a similar topic. I think now, in 2020, we’re much more in a place of acceptance that some people need chemical help for their issues. (Even if pharmaceutical companies continue to prove themselves to be untrustworthy). But back then fair game for a bit of a poke.

4. It’s Alright – This one sounds a bit more like MxPx as in their previous two albums. That “voice sounding like it’s coming from a crappy radio” sound is definitely a 2000s thing.

5. Brokenhearted – First of a trio of songs about things going wrong with relationships. Wonder what was going on with Herrerra or whoever wrote the songs. Sounds very originally MxPx and would probably be a standout along with track 2 for a song that would probably be acceptable to a modern MxPx fan. Least immediately 2000s song on the album.

6. First Day of the Rest of Our Lives – This song makes me think of a song that could have been on Blink-182’s “Enema of the State”. Some of the chords, the way it ends, and the way Herrerra sings some of the verses seem similar. The song’s about the day after a breakup.

7. Everything Sucks (When You’re Gone) – Continuing the breakup triptych, a song about life having less meaning now that the breakup has happened. Doesn’t remind me of any particular band, but definitely feels of its time.

8. Quit Your Life – A spiritual successor the “Move to Bremerton”, but way slower. It’s funny, with some of the background (a synth or mandolin or something?) it sounds like The Beatles by way of Pop Punk. In an album full of longer songs (earlier MxPx songs rarely went past the 2:30 mark), this one is definitely on the longer end. I think that may be part of what some fans were rejecting in this era of MxPx.

9. More Everything – Interestingly after the respite of track 8, this one seems to present a relationship teetering on the edge. It might fall back into happiness or it might lead to a breakup. This one sounds mostly MxPx, but a little (maybe 5%) mixed with Blink-182.

10. Kings of Hollywood – For a band SO known for being from Bremerton, WA – this is a strange song. I guess the band either lived there for a while or recorded one or more of their albums there? Or maybe the narrator is fictitious? Topically, this seemed to be in the air in the 2000s with Weezer also writing a similar song, among others. In fact, this song has an early Beach Boys lick to the guitar in parts that sometimes were reminiscent of Weezer and other similar bands. I’d be surprised if this song didn’t end up on the radio back when the album was new. “Left Coast Punk Rock, that’s our scene” interesting lyrics in a song that’s almost the least punk on this album. Especially compared to early and later albums. 

11. The Capitol – This song sounds almost EXACTLY like the MxPx songs I know. This could have been on the latest album, sonically. Lyrically – it seems to be their Christian song for this album. Written before Herrerra had lost his faith or perhaps even if struggling, wrote it because it was expected of the band.

12. On the Outs – ANOTHER breakup song. Or at least a big fight with your significant other. Were things going really badly for Herrerra and crew at this point? Another MxPx song – that is to say, it sounds like them and not like any other bands making music at the time.

13. Don’t Walk Away – The previous song rolls into this one in a way that doesn’t quite work as well when listening digitally – none of programs get it quite as seemlessly as CDs do. The opening with the cymbals makes me think of Shaft, but I don’t know if it’s just a common cymbal pattern that I’ve associated with Shaft. The music, especially with the piano, almost sounds like a lost U2 song that they gave MxPx to play. It’s VERY odd. Also, very in line with 2000s. This is around when that U2 iPod commercial came out. Seems to work very well with On the Outs (which I guess is why one song rolls into the other). Basically, your girl was fighting with you (your stuff on the lawn – in the previous song) and now he’s begging her not to leave. 

14. You Make Me, Me – Another MxPx sounding song, even if it’s a bit more pop than their usual. It’s about how great the person (maybe the one from the previous two songs) makes him feel. It’s got a lot of lyrics relating to Christianity – having recently heard another of their older songs where he rewrote those words, I wonder how they’d sing this one nowadays.

15. You’re Not Alone – A classic MxPx song from the drum beats to the guitars. I think the only thing that makes it not like those older songs is that it doesn’t switch to another song halfway through. 

16. After – same as Before. (track 1)

My favorite songs on the album:

  • Well Adjusted – if the lyrics are a bit politically incorrect nowadays, the music is fun and I can hang with the irreverant lyrics.
  • Play It Loud – a great song to get the blood pumping in the morning
  • Don’t Walk Away – I like the music in this song even if I hope to never have to feel like the protagonist in the song
  • You Make Me, Me – I just like everything about this song even if nothing about it rises up beyond most of the others.

Overall, as I said before looking at each track individually, I think it’s a good album and I think it might have sustained my interest in MxPx if I’d discovered it at the time. The future wife and I (or maybe already wife – depending on exactly when it came out) were mostly listening to Relient K and Anberlin. (Plus a random assortment of other bands) But writing this out also makes me realize a good nearly half of the songs are very MxPx-like. So maybe it’s the songs they chose for singles or promotions that make people think the album was a huge departure. Or maybe, like when I was listening to this album the first couple times, it’s those first few songs that sound the most like MxPx was trying to fit into 2000s pop-punk that sets the listener into a certain frame of mind even if later songs on the album sound like classic MxPx. It’s hard to say for sure. What’s not hard to say is that I bought this album and MxPx (2018) at the same time and I replay MxPx a lot more than I replay this album.

Programming Update for May 2021

Advent of Code 2015 Problem Set

Day 10

There’s a lot to be said for doing the Advent of Code in December along with a few thousand other programmers. It’s fun to be part of something with others and you get to all the neat and wacky solutions that others come up with. 

On the other hand, going at my own page with the 2015 problem set allows for interesting little coincidences to form. What I did one day (when I was at about Day 7) was to go through all the remaining days and write some first impression ideas at solutions. This got my brain thinking about what I needed for each day. One day, before getting to the Day 10 problems, I was idly flipping through the book Learn You a Haskell for Great Good! As I was trying to decide if it would be one of the languages I’d add for 2016. I ended up coming across a built-in library that would have made solving Day 10 a real breeze. Day 10 is the Look and Say sequence. I’m sure by paying close attention to that Wiki entry I could have figured out an algorithm. But, basically I just needed to group together each repeated number and then I could take the length of that list/array to find out how many numbers. That becomes part of the new number. Unfortunately, as far as I could see, that functionality was not built into Python. So my Python code looked like this:

"""Find length of the a number after a look-and-say game."""
 import copy
 def create_number_lists(game_input):
     current_number = 0
     number_count = 0
     return_list = []
     for number in game_input:
         if len(game_input) == 1:
             return [(1, int(number))]
         if int(number) != current_number:
             if number_count != 0:
                 return_list.append((number_count, int(current_number)))
             current_number = int(number)
             number_count = 1
         else:
             number_count += 1
     return_list.append((number_count, int(current_number)))
     return return_list
 def recombine(number_list):
     return "".join(
         str(number) for num_tuple in number_list for number in num_tuple
     )
 if name == "main":
     puzzle_input = '1321131112'
     loop_count = 0
     puzzle_output = ""
     while loop_count < 40:
         puzzle_output = recombine(create_number_lists(puzzle_input))
         puzzle_input = puzzle_output
         loop_count += 1
     print(f"The length of puzzle_output ({puzzle_output}) is {len(puzzle_output)}")

Meanwhile look at how much cleaner this is in Ruby using chunk_while:

def look_and_say_round(game_input)
     game_input_array = game_input.split(//)
     game_input_array.chunk_while { |a, b| a == b }
     .flat_map { |chunk| "#{chunk.size}#{chunk.first}" }
     .join('')
 end
 if $PROGRAM_NAME == FILE
     input = "1321131112"
     loop_count = 0
     until loop_count == 40
         puzzle_output = look_and_say_round(input)
         input = puzzle_output
         loop_count += 1
     end
     puts "Length of output after 40 roundes of look and say is #{puzzle_output.length}"
 end

Revisiting the code to write this blog post, I think I can probably reduce that code down to one line (in the look_and_say_round function) if I wanted to sacrifice a bit of readability. The Perl code falls somewhere in the middle. I easily found a CPAN module to do the equivalent of chunk_while. However, I’m not as conversant in Perl so I don’t know if I’m being a little extra verbose here:

!/usr/bin/perl
 use v5.20;
 use warnings;
 use Array::GroupBy qw(igroup_by);
 sub look_and_say_round{
 my $game_input = $_[0]; my @numbers = split("", $game_input); my $number_iterator = igroup_by(data => \@numbers, compare => sub{$_[0] eq $_[1]},); my $look_and_say_text = ''; while (my $grouped_array = $number_iterator->()) {     my $length = @{$grouped_array};     my $number = @{$grouped_array}[0];     $look_and_say_text = $look_and_say_text . "$length$number"; } return $look_and_say_text;
 }
 my $puzzle_input = "1321131112";
 my $loop_count = 0;
 my $puzzle_output;
 until ($loop_count == 40){
 $puzzle_output = look_and_say_round($puzzle_input); $puzzle_input = $puzzle_output; $loop_count++;
 }
 my $output_length = length($puzzle_output);
 say "The final number is $puzzle_output with a length of $output_length";

Day 11

Day 11 wasn’t too hard for any language. It basically gave some password generation rules and required you to increment passwords in a certain way. However, there was a bit of elegance in the Ruby solution that I guess points towards part of the reason why folks tend to REALLY love this language. First, let me show you my Python code:

import re
 def rule_one(password: str) -> bool:
     """Check if a password includes a straight of at least 3 letters."""
     for index, letter in enumerate(password):
         if index == (len(password) - 3):
             return False
         current_letter_ascii_value = ord(letter)
         if ord(password[index + 1]) == current_letter_ascii_value + 1 and\
                 ord(password[index + 2]) == current_letter_ascii_value + 2:
             return True
 def rule_two(password: str) -> bool:
     """Check if a password contains i, o, or l."""
     return 'i' not in password and 'o' not in password and 'l' not in password
 def rule_three(password: str) -> bool:
     """Check for at least two different, non-overlapping pairs of letters."""
     rule_three_regex = re.compile(r'(\w)\1')
     all_pairs = re.findall(rule_three_regex, password)
     if len(all_pairs) < 2:         return False     if len(set(all_pairs)) > 1:
         return True
 def increment_password(password: str) -> str:
     """Given a password, increment the last letter by 1."""
     if password[-1] == 'z':
         return increment_password(password[:-1]) + 'a'
     return password[:-1] + chr(ord(password[-1]) + 1)
 def find_next_valid_password(password: str) -> str:
     """Find the next password that meets all the criteria"""
     while True:
         if rule_one(password) and rule_two(password) and rule_three(password):
             return password
         password = increment_password(password)
 puzzle_input = "hxbxwxba"
 first_new_password = find_next_valid_password(puzzle_input)
 second_new_password = find_next_valid_password(increment_password(first_new_password))
 print(f"Santa's first new password is {first_new_password}")
 print(f"Santa's second new password is {second_new_password}")

Both rule_one and increment_password are a little inelegant. I spent a bunch of time trying to figure out a better rule_one with regex and I couldn’t. And for the password incrementing, I had to convert it to asii to get the next letter and then come back to string. Ruby, however, was so nice!

def rule_one(password)
     characters = password.split(//)
     triple_straight = characters.chunk_while { |i, j| i.next == j }.filter{|chunk| chunk.length >= 3}
     triple_straight.length >= 1
 end
 def rule_two(password)
     !password.include? "i" and !password.include? "o" and !password.include? "l"
 end
 def rule_three(password)
     pairs = password.scan(/(\w)\1/)
     pairs.length >= 2
 end
 if $PROGRAM_NAME == FILE
     current_password = "hxbxwxba"
     puts "Santa's starting password is: #{current_password}"
     until rule_one(current_password) and rule_two(current_password) and rule_three(current_password)
         current_password = current_password.next
     end
     puts "Santa's next password should be: #{current_password}"
     puts "Then Santa's password expired again!"
     current_password = current_password.next
     until rule_one(current_password) and rule_two(current_password) and rule_three(current_password)
         current_password = current_password.next
     end
     puts "Santa's next password should be: #{current_password}"
 end

First of all, the return of chunk_while allows rule_one to work SO, SO well. But the best part is that Ruby’s “something.next” method just works so perfectly both here and in the password incrementing code. This works especially well because it does the right thing where “az” increments to “ba”. It just is so beautiful for doing this and I love the resulting code! Looking back at this now, I see that there is some code there in the “main” loop which I could have refactored out into a function.

Day 12

Usually part 2 of an Advent of Code problem is just a bit more complex, introducing complications that may mess with shortcuts or assumptions the programmer made in part 1. But every once in a while, the code needed for part 2 is radically different than the code for part 1. For part 1 I was able to use a simple regular expression to get the answer. The code is simple (as usual I’ve actually over-complicated things a bit with my code so that I can use unit tests to test against the examples given)

import re
 from sys import maxsize, path
 path.insert(0, '../../input_parsing')
 import parse_input
 def find_numbers(line: str):
     regex = re.compile(r'(-*\d+)')
     numbers = re.findall(regex, line)
     return [int(number) for number in numbers]
 def sum_number_list(number_list: list[int]) -> int:
     return sum(number_list)
 if name == "main":
     lines = parse_input.input_per_line('../input.txt')
     total = sum([sum_number_list(find_numbers(line)) for line in lines])
     print(f"The sum of all numbers in the document is {total}")

But for part 2, I actually had to create a JSON parser of sorts.

import json
 from sys import path
 path.insert(0, '../../input_parsing')
 import parse_input
 def find_numbers(elf_json):
     summation = 0
     if isinstance(elf_json, list):
         for item in elf_json:
             summation += find_numbers(item)
     elif isinstance(elf_json, int):
         return elf_json
     elif isinstance(elf_json, str):
         return 0
     else:
         for key, value in elf_json.items():
             if "red" in elf_json.values():
                 return 0
             elif isinstance(value, int):
                 summation += value
             elif isinstance(value, list):
                 summation += find_numbers(value)
             elif isinstance(value, dict):
                 summation += find_numbers(value)
             else:
                 # this is a color string
                 summation += 0  # this used to be a print statement
     return summation
 if name == "main":
     json_string = parse_input.input_per_line('../input.txt')
     total = json.loads(json_string[0])
     print(f"The sum of all numbers in the document (unless it's got a red property) is {find_numbers(total)}")

Prophecy Practicum

This is a project I’m working on for a buddy in order to fulfill a need he has with a spiritual practice he’s involved in. As I mentioned before, moving from Flask to Django allowed me to make lots of progress on the project. In May I finally reached the v1.0 milestone and it was ready for users to try out. As I write this in June, the first cohort has gone through it and I’m waiting to see what modifications we need to make. Additionally, I have a couple features I’m trying to figure out.

ELDonation Tracker for Extra Life

I started off May fixing a bug where DonorDrive had changed their API output and it messed up  my Avatar image output. While investigating the API changes, I found out they had added in APIs for milestones, badges, and incentives. This led to the release of v6.1. Next up for this project will be v7.0 where I move the API code out to its own project so that it can be useful as a Python reference API for DonorDrive, independent of Extra Life.

Harry Potter Word Frequency Calculator

I had a conversation with Scarlett about how puzzle solvers (cryptographers) use word frequency to help solve their puzzles. And I told her that the most often used word in English is “the”. She was a little skeptical, so I wrote a program to do word frequency analysis on Harry Potter and the Philosopher’s Stone. Since it was my first time using my chosen epub library, I just took it one chapter at a time to get a better understanding of how it works. 

from collections import Counter
 import ebooklib
 from ebooklib import epub
 import re
 philosopher_stone = epub.read_epub("/home/ermesa/eBooks/J.K. Rowling/Harry Potter and the Sorcerer's Stone (441)/Harry Potter and the Sorcerer's Stone - J.K. Rowling.epub")
 items = philosopher_stone.get_items_of_type(ebooklib.ITEM_DOCUMENT)
 items_list = list(items)
 remove_html_tags_regex = re.compile(r'<[^>]+>')
 chapter_one = remove_html_tags_regex.sub('', items_list[6].get_body_content().decode())
 chapter_one_words = chapter_one.split()
 print(Counter(chapter_one_words))

And here’s the output:

Counter({'the': 187, 'a': 105, 'and': 95, 'to': 93, 'he': 87, 'was': 84, '.': 81, 'of': 72, 'his': 66, 'in': 55, 'He': 49, '—': 49, 'that': 48, 'on': 44, 'as': 41, 'had': 39, 'Dursley': 38, 'it': 36, 'have': 32, 'at': 32, 'Mr.': 30, 'said': 28, 'Professor': 28, 'be': 27, 'I': 27, 'al
l': 25, 'were': 23, 'Mrs.': 21, 'you': 21, 'didn’t': 21, 'but': 21, 'out': 21, 'It': 21, 'been': 21, 'she': 20, 'for': 20, 'her': 19, 'they': 18, 'Dumbledore': 18, 'very': 17, 'people': 17, 'over': 17, 'into': 17, 'cat': 17, 'McGonagall': 16, 'with': 15, 'not': 15, 'The': 14, 'him': 
14, 'Harry': 14, 'up': 13, 'this': 13, 'back': 13, 'if': 12, 'so': 11, 'it.': 11, 'about': 11, 'couldn’t': 11, 'down': 11, 'know': 11, 'their': 10, 'would': 10, 'could': 10, 'what': 10, 'never': 10, 'even': 10, 'them': 10, 'just': 9, 'man': 9, 'there': 9, 'no': 9, 'like': 9, 'somethi
ng': 9, 'thought': 9, 'by': 9, 'see': 9, 'owls': 9, 'looked': 9, '“I': 9, 'Dumbledore,': 9, 'Privet': 8, 'did': 8, 'think': 8, 'Potter': 8, 'seen': 8, 'street': 8, 'around': 8, 'little': 8, 'who': 8, 'eyes': 8, 'are': 8, 'number': 7, 'because': 7, 'which': 7, 'Dudley': 7, 'got': 7, '
corner': 7, 'when': 7, 'from': 7, 'next': 7, 'can': 7, 'he’s': 7, 'Hagrid': 7,... it keeps going, but I've cut it off here

It’s actually not that surprising to see “Harry” so low in chapter one. It’s more about describing the nature of Privet Drive and Dumbledore and the other wizards than it is about Harry. I may do a bit more with this code to create some fun graphs. If you want to expand on this, the first thing you’d want to do is force every word to lowercase before counting it so that ‘a’ and “A” are counted as the same word.

DragonRuby

I took a look at the idea of participating in the DragonRuby game jam. But it’s WAY more work than using Unity or Unreal so I chose other tasks over this one. But it was neat to play around with and I may return to it someday.

Podcasts I’m Listening to in 2021

I’ve both added and dropped some podcasts since last time around. Where I’m listing the same podcast as last year I may use the same description as in the past with slight (or no) variation.

Public Radio

Radiolab – Heard about them because sometimes their stories are used on This American Life. Radiolab is a lot like TAL except with a much bigger focus on sound effects. It is, in a way, the descendant of the old radio shows of the 30s and 40s. (Approx 30-45 min)

Marketplace – This is a really good economics show.  They talk about news that happened that day as well as stories that have been pre-prepared.  (Approx 30 min long)

Codebreaker: A tech podcast. Season 1 asked the question “Is it Evil?” of various technologies. still on my feed, but hasn’t release a new episode since Dec 2016.

On the Media –  Although not always perfect and although it leans a little more left than moderate, On the Media is a good podcast about media issues.  Examples include: truth in advertising, misleading news stories on the cable networks, debunking PR-speak from the White House, and other media literacy items.  I tend to enjoy it nearly all the time and it’s a good balance to news on both sides of the spectrum, calling out CNN as often as Fox News. (Approx 1 hour long)

Fresh Air – Fresh Air is one of NPR’s most famous shows. It tends to have a heavy focus on cultural topics (books, movies, etc).  Terry Gross has been hosting Fresh Air for decades and is a master at interviewing her guests.  Every once in a while there is a guest host or the interview is conducted by a specialist in that industry.  (Approx 1 hour)

Freakonomics – Essentially an audio, episodic version of the eponymous book. If you enjoyed the insights of the book, you’ll really enjoy this podcast. (Approx 30 min)

The Infinite Monkey Cage – a BBC radio show about science. A panel of scientists (and one media star who is interested in science) talk about a topic. The only bummer is that the shows are quite infrequent. Something like 4 weekly episodes per quarter (Approx 30 min)

Planet Money – my dad had been trying to get me to listen to this for a while and I finally did. 21-25 minutes on an economic topic that usually helps you see something about it in a slightly different way.

The Experiment – A team-up between The Atlantic and WNYC Studios that explores topics about American culture and history. Somewhat similar to Throughline. (Approximately 20 minutes)

The Indicator from Planet Money – A quick episode on a news-related financial story. Usually somewhat jokey in tone. (Approximately 9 minutes)

Throughline – A podcast that ties current social and political events to history. (Approx. 1 hour)

History

Dan Carlin’s Hardcore History – if you’re a history buff you really need to be listening to this podcast. Dan’s well-researched podcast presents bits of history you never heard of in ways you never thought of it. He does a great job of making ancient societies relate-able. The only bad thing is that there is a long gap between episodes due to the research involved. (Varies. Approx 1.5 – 4 hrs)

Hardcore History Addendum – Meant to bridge the gap between Hardcore History episodes, it focuses on interviews and smaller topics.

The Dollop – A very funny and very profane look at American history. The premise: The host tells a story of American history to the other guy, who doesn’t know ahead of time what the story’s about. It’s a premise that leads to some great reactions from the person not in the know (usually Gareth, but sometimes they do a Reverse Dollop). Also, listening to this podcast is a great reminder that the past is full of some really messed up people and situations.

History Unplugged – I found this podcast when I was looking for Dan Carlin’s Hardcore History Addendum. I enjoy his question and answer episodes. (20 minutes)

Tides of History – I liken this podcast to the other side of Hardcore History. Dan Carlin tends to focus on the big movers and shakers in history. So far, in Tides of History the host has focused a lot on the experience of the common man (or woman) in the time period he’s exploring. Very entertaining and, unlike Hardcore History, it’s not on a George RR Martin update pace. (Usually 20-40 minutes)

The History Chicks – Focused on women’s history, they usually tell the story of an important figure from birth to death. I really enjoy the style, especially since, like The Dollop it involves more than one person so they can play off each other, even if it’s not as comedic as the other show.

Comedy

WTF with Marc Maron – This is a pretty solid podcast which mostly consists of Marc Maron interviewing comedians.  As with any interview-based show, the episodes are hit or miss, although more often than not they are really good.  Occasionally he does a live show in which he’s still interviewing people, but with 4-6 per episode it’s much less in-depth.  And, since it has an audience, the guest is performing more than being open.  The only irritating thing is that Marc starts off each episode with a rant/listener email reading.  Most of the time this is neither interesting nor funny.  I wish he’d do his rant at the end of the episode so that those of us who just want to hear a great interview with a comedian we like can easily skip the monologue.  (Approx 1.5 hours long)

Conan o’Brien Needs a Friend – It’s kind of like WTF, but much, much jokier. Most of the time, Conan has a really great conversation with a comedian that just goes off in random directions. Every once in a while it’s more like a commercial for whatever the comedian has recently released. (Approx. 1 hour long)

Science Fiction Short Stories

Clarkesworld Magazine

Escape Pod

There isn’t much to differentiate these two podcasts.  They both feature great selections of short stories.  I added them to my podcatcher to get a dose of fiction among the more non-fiction podcasts I usually listen to.  Also, there’s something great about short-form fiction where you have to build the world AND tell the story in a very concise way.  The main difference between the two podcasts is that Clarkesworld has pretty much just one narrator who’s quite incredible.  Escape Pod tends to have a group of narrators.  Most of them are great – every once in a while there’s a less than stellar one.  Clarkesworld tends to end the story with the narrator’s interpretation and Escape Pod tends to end with reader comments from a few episodes ago. (varies. 15 min to 45 min)

Movies

How Did This Get Made – Paul Scheer, June Diane Raphael and Jason Mantzoukas (plus the occasional guest) watch movies from the last few decades that will probably be in the future’s version of Mystery Science Theatre 3000. The movies are often incredibly baffling and full of strange plot points. One of the best parts of the show is “Second Opinions” where Paul goes to Amazon.com to get 5 Star ratings for the movie they just spent about an hour lambasting. Every other episode is a mini episode that previews the next show, has a section called “Corrections and Omissions”, and Qs and As. The first two sections are great. The last one varies depending on the quality of the questions and answers. It can be pretty funny, but most times I just skip it. (Approx 1 hr)

Unspooled – Paul Scheer’s serious movie podcast. He teams up with Amy Nicholson to talk about movies from the AFI Top 100 best American movies list. It’s pretty neat to hear them really dissect these movies and they usually have an interview with someone involved in the movie. (Approx 1.5 hours long)

Zoom – Amy Nicholson goes in depth into various movie topics and how they fit into our culture. Last season’s greatest episode was about the history of zombies throughout human history and film. I don’t even like Zombie movies and I found it absolutely fascinating. (Approx 30 minutes)

Twinsies – Andy Wood from Probably Science and another guy who might just mention that he has a film degree from Arizona State talk about two movies that came out around the same time and are almost the same movie – at least superficially. For example Antz v A Bug’s Life or The Illusionist v The Prestige. Good for film/pop culture nerds. (approximately 45 minutes)

News

Political Gabfest (from Slate) – This has taken the role that Talk of the Nation’s Wednesday slot left vacant when the show went off the air. They talk about politics (usually swinging heavily left or sometimes libertarian while ToTN was more neutral) and I get a dose of what everyone’s talking about in politics. (Approximatly 1 hour)

Common Sense with Dan Carlin – If you like the attention Dan puts towards Hardcore History, then you’ll probably love this take on the news. Usually Dan takes one (max 2) topics from the news and by the time he’s done with it, I’ve seen 2-3 different points of view. Sometimes there’s a clearly right point of view (the sky is blue), but other times each side has valid points and neither one has the complete high ground. Dan is a complex creature, like many of us. On some topics he’s more likely to agree with Dems, other time Republicans, and sometimes neither. Other times he agrees with their Platonic Ideal Version, but not their RealPolitik version. Either way, I’m always overjoyed when it shows up – which is somewhere between biweekly and monthly. (Approximately 45 minutes) still on my feed, but it’s been 21 months since the last episode

FiveThirtyEight Elections – a great, wonky podcast from the guys that brought you the most accurate election predictions. Has continued beyond the elections due to the odd circumstances of the Trump administration.

What Trump can teach us about Con Law – Hosted by Roman Mars of 99% Invisible and Elizabeth Joh, a constitutional law professor, it explores issues of constitutional law around statements, executive orders, etc that Trump has made. Very informative and explains a lot about how certain things that affect other politicians don’t affect the present. (15 minutes)

Culture

Give Me Fictionnote: I’m still subscribed to this podcast, but it’s on hiatus. A pretty hilarious (to my sense of humor) super short story podcast. It’s recorded live (which often spices up comedy) and seems to skew Gen X/Millenial in its humor.  (Varies, but usually under 15 minutes)

Talkin’ Toons with Rob Paulsen – The great voice actor behind two Ninja Turtles, Pinky, Yakko, and many, many other cartoon characters interviews other voice actors. It’s like WTF,  but without the annoying self-reflection 10-15 minutes that I always skip on Maron’s podcast. If you enjoy voice acting nerdom or want a place to start, check this out. (Approximately 1 hour)

Boars, Gore, and Swords: A Game of Throne Podcast – two comedians (and sometimes some friends) discuss each episode of A Game of Thrones and each chapter of the books. While it’s primarily funny, it does sometimes lead me to some deeper insights into each episode. Since the show is over and there aren’t any more published books, they’ve branched out to include a lot of “What You Should Be Watching” episode where they cover different movies and TV shows. They’ve introduced me to a lot of shows that I’ve ended up really loving, like Counterpart.

The Allusionist – a podcast about words, where they come from, and how we use them (Approx 15-25 min)

Imaginary Worlds – a look at what makes science fiction and fantasy so enjoyable whether as books, film, or music.

Decoder Ring – they take a look at a cultural mystery or meme and where it came from and how it’s affecting culture. Examples include: Truck Nutz, Sad Jennifer Aniston, The Incunabula Papers, and Clown Panic.

Spanish Aqui Presents – a Latinx improv group spends the first half of the show on a topic that’s front of mind to one of the members. Then they interview someone from the Latinx entertainment world, culminating in doing an improve sketch based on what they learned about that person in the interview.

Our Opinions Are Correct – Annalee Newitz (science journalist and science fiction author) and Charlie Jane Anders (science fiction author) discuss a topic from science fiction (eg a particular trope) and where it came from and how it applies to stories past and presesnt. Somewhat similar to Decoder Ring, but where that one is very journalistic, this one is more of a conversation between two people. (Approximately 30-40 minutes)

Smartless – Jason Bateman, Sean Haeys, and Will Arnett interview a celebrity. It’s similar to Conan O’Brian Needs a Friend or WTF, but tends to go off on tangents a lot more often. (Approx 1 hour)

Writing Excuses – Brandon Sanderson and other famous SFF authors talk about the craft of writing. Even though I’m not an author, I find it fascinating. (Approximately 15 minutes)

Science

You Are Not So Smart – the host, who wrote an eponymous book, tackles topics of self-delusion. Examples include placebos, alternative medicine, and conspiracy theories. (Approximately 45 min)

Probably Science – some comedians who used to work in the science and tech fields bring on other comedians (of various levels of scientific knowledge) to discuss pop science and where the articles might be misleading.

Star Talk Radio – Neil DeGrasse Tyson’s official podcast feed. Some episodes are a show hosted by him in which he either interviews a guest or answers listener questions. Others are Chuck Nice and another guy talking about the science of sports.

Misc

99% Invisible – Similar in scope to the NPR podcast Invisibilia, this one was there first. It explores the things that are in the background of life. Examples include architectural details we often miss or stories that tell how regions came to be. Production is similar in sonic greatness to RadioLab.  (Approx 15 min)

Politically Reactive – W. Kamau Bell and Hari Kondabolu discuss politics with some jokes and some interviews with people mostly on the left, but sometimes on the right. They are respectful and always provide context to what’s being said.

More Perfect – Explores Supreme Court rulings and how they affect America.

Song Exploder – they pick a song and a member from that band explains how they put it together. They usually look at each layer of the track – vocals, drums, guitar, etc and talk about why each decision was made. Can range from interesting to revealing.

Business Wars – focuses on business rivalries like Netflix v Blockbuster, Nike v Adidas, or Marvel v DC. Usually 4-6 episodes per topic and a reasonably deep dive into the subjects.

My Brother, My Brother, and Me – “An Advice Show for the Modern Era”. The McElroy brothers come up with answers to Yahoo Questions and Listener Questions. Also a bunch of random recurring skits. My favorite is “Munch Squad” where they make fun of restaurant press releases. (Approximately 1 hour)

Cautionary Tales – Similar to You Are Not So Smart in that we often learn the wrong lessons from things that happen in history. The host takes a few seemingly unrelated historical events and ties them together to see how we can use them all to learn the same lesson.

Computers

Command Line Heroes – A podcast produced by Red Hat that tackles different tech topics, organized around a seasonal topic. Season 2 was about programming languages and introduced me to the Python podcasts that I listen to. Season 3 is about the history of computer hardware. (Approximately 30 minutes)

Talk Python to Me – A podcast about the Python programming language in which the host interviews a Python programmer about their project. Some of the neat interviews have been about climate change and programming, open-source in academia, and Python packaging in 2020.

Python Bytes – A short Python news show in which the hosts talk about news and new modules (sometimes just new to them). I often learn quite a bit of bits of functionality I never knew about related to Python.

Open Source Security Podcast – Approximately 30-45 minutes on a security topic that’s either on the minds of one of the hosts or in the news recently. Fun to listen to and I usually learn something.

The Real Python Podcast – A podcast to go along with The Real Python website. They cover new articles on the site and then a weekly topic. (Approximately 1 hour)

Cooking

Proof – a short podcast by the folks at America’s Test kitchen that looks at various food culture stories. Previous episodes include Fair Foods, Bowls, and Ketchup. (usually about 15-20 minutes)

Programming Update for April 2021

I had a lot less variety in my programming month, but still had a lot of fun doing it. In fact, Programming consumed most of my leisure thoughts. More about why I was doing it below, but I’ve been reading Programming Perl as well as skimming through Introducing Go and Learn You A Haskell for Great Good!. Ever since some folks used Haskell during last year’s Advent of Code and this guy’s videos that I mentioned in an early 2021 blog post, I’ve been very curious about the language. In fact, at this point I’ve decided that Go and Haskell will be the next two languages I learn. 

Python

I continued working on the Django app I’m making for a friend. I finally started to get the hang of how Django works, especially when passing information around in the app. I got to a minimal viable product (MVP) in April, but I’m hoping to finally get a 1.0 that meets all his needs within the first couple weeks of May.

Advent of Code 2015 Problem Set

So the activity that gave me the most fun in April was working through the 2015 Advent of Code problem set. I chose to use it to cement my understanding of Ruby, which I learned in 2020. But that wasn’t enough for me on its own. I decided to also solve each problem with Perl. I tried learning Perl for the second time about a decade ago. I ended up abandoning it for Python when I wanted to contribute to GRAMPS, which was written in Python. So I had some understanding of the strange sigils before the different types of variables, but I didn’t have a great understanding of the more complicated things that could be done with Perl. There’s also something I haven’t mentioned in this blog in a long time, but I think sometimes we come across knowledge before we’re ready for it. This isn’t some mystical woo-woo thing. It’s just a fact, sometimes you don’t have the underlying knowledge necessary to take advantage of new knowledge that you’re being presented with. A great example is hashes. I just couldn’t truly get my mind around it at the time (10 years or so ago). But now that I’ve done a ton of work with Python dictionaries, I realize they’re the same thing and hashes make sense to me now.

I’ve been extra happy in the fact that, by the end of April I had reached Advent of Code Day 10 and hadn’t had to skip any days. Yes, there were a couple days during the 2020 event where I skipped an entire problem or part 2 of a problem because I ran out of time, but I also had to skip a few problems because I had no idea how to solve them. So far that hasn’t happened with the 2015 problem set. I wanted to draw attention to some of the things I learned so far thanks to AoC 2015.

require "../../input_parsing/parse_input" 
 
def parse_directions(parenthesis) 
    floor = 0 
    parenthesis.each do |paren| 
    if paren == "(" 
        floor += 1 
    elsif paren == ")" 
        floor -= 1 
    end 
    end 
    return floor 
end 
 
 
 
input_text = input_per_line('../input.txt') 
puts parse_directions(input_text[0].split(//))

For my Day 1 entry to Ruby, I just practiced going over arrays with each. I also used string.split(//) to split the text into an array of each character. I made a comment on Reddit and someone suggested a more Rubyist solution:

require "../../input_parsing/parse_input" 
 
def parse_directions(parenthesis) 
    parenthesis.reduce(0) do | floor, paren | 
        if paren == "(" 
            floor + 1 
        elsif paren == ")" 
            floor - 1 
        end 
    end 
end 
 
 
 
input_text = input_per_line('../input.txt') 
puts parse_directions(input_text[0].split(//))

This simplifies the code by eliminating the need to initialize the floor variable to sum things up. Instead it becomes the input for an array that is reduced. (I would make more use of reduce later in 2015)

Day 2 

Just last year I started learning about what map and reduce mean in computer science. Such is the situation for someone who is primarily self-taught. Turns out that a pretty big chunk of Advent of Code (and other programming challenges) solutions can be summed up as map, filter, reduce. Of course, that hides the fact that figuring out the map and filter functions is often the whole point of the challenge. Day 2’s Ruby code was the first time I explicitly used map (see line 5 where I convert all the array members to integers) in any language (although a Python list comprehension is almost always an implicit map or filter)

require "../../input_parsing/parse_input" 
 
def get_dimensions(dimension_line) 
    dimensions = dimension_line.split('x') 
    dimensions.map(&:to_i) 
end 
 
 
def calculate_box_area(dimensions) 
    2*dimensions[0]*dimensions[1] + 2*dimensions[1]*dimensions[2] + 2*dimensions[0]*dimensio
ns[2]  
end 
 
def calculate_small_area(dimensions) 
    sorted_dimensions = dimensions.sort 
    small_area = sorted_dimensions[0] * sorted_dimensions[1] 
end 
     
 
input_text = input_per_line('../input.txt') 
all_box_areas = [] 
all_small_areas = [] 
input_text.each do |box| 
    all_box_areas.append(calculate_box_area(get_dimensions(box))) 
    all_small_areas.append(calculate_small_area(get_dimensions(box))) 
end 
 
summed_box_areas = all_box_areas.reduce(0) {|sum, num| sum + num} 
summed_small_areas = all_small_areas.reduce(0) {|sum, num| sum + num} 
 
puts "The Elves need #{summed_box_areas+summed_small_areas} square feet of wrapping paper!"

Day 2’s Perl code was the beginning of learning how to use groups in regular expressions to get values for variables in line 13. (This would become important in many future 2015 puzzles) Also the first time I used sorting on line 17

#!/usr/bin/perl 
 
use v5.14; 
 
open(PRESENTDIMENSIONS, , "../input.txt") || die "Can't open input.txt: $!\n"; 
 
my @present_dimension_list = <PRESENTDIMENSIONS>; 
 
my @accumulated_areas; 
 
for my $present_dimension (@present_dimension_list){ 
 
    my($length, $width, $height) = $present_dimension =~ /(\d+)x(\d+)x(\d+)/; 
     
    push (@accumulated_areas, 2*$length*$width+2*$width*$height+2*$height*$length); 
     
    my @temp_dimensions = sort{ $a <=> $b }($length, $width, $height); 
     
    push (@accumulated_areas, $temp_dimensions[0] * $temp_dimensions[1]); 
} 
 
# reduce is not in the standard Perl library 
 
my $total_area = 0; 
for my $area (@accumulated_areas){ 
    $total_area += $area; 
} 
 
say "The Elves need $total_area square feet of wrapping paper"

Day 4

Day 4 was pretty interesting for showing how a regular expression could make code very simple. Compare my Python and Perl code for that day:

import hashlib 
 
 
def calculate_hash(text_to_hash): 
    return hashlib.md5(text_to_hash.encode('utf-8')).hexdigest() 
 
 
def does_it_lead_with_five_zeroes(hash_string): 
    zero_count = 0 
    for character in hash_string: 
        if character == "0": 
            zero_count += 1 
        if character != "0": 
            break 
    return zero_count >= 5 
 
 
def find_special_number(puzzle_text): 
    decimal_number = 1 
    found_it = False 
    while not found_it: 
        decimal_number += 1 
        calculated_hash = calculate_hash(puzzle_text + str(decimal_number)) 
        found_it = does_it_lead_with_five_zeroes(calculated_hash) 
    return decimal_number 
 
 
if __name__ == "__main__": 
    puzzle_input = "iwrupvqb" 
    answer = find_special_number(puzzle_input) 
    print(f"The number to add is {answer}")
#!/usr/bin/perl 
 
use v5.14; 
 
use Digest::MD5 qw(md5_hex); 
 
my $puzzle_input = "iwrupvqb"; 
 
my $number = 0; 
 
my $hex_test = md5_hex("$puzzle_input$number"); 
 
until ($hex_test =~ /^00000/){ 
 
        $number++; 
        $hex_test = md5_hex("$puzzle_input$number"); 
} 
 
say "Santa's magic number is $number";

It’s pretty incredible how much simpler that is, right? It’s not that I couldn’t have done that with Python, it’s just that I didn’t have the idea until I was thinking about how I’d do the problem with Perl.

Day 7

Last year during the 2020 AoC I learned about memoization, but had trouble implementing it. This time I finally figured it out. It was built-in to Python via lrucache, but I had to implement it manually in Ruby. That really helped me prove to myself that I had learned how to do it.

from datetime import datetime 
from functools import lru_cache 
import re 
import sys 
sys.path.insert(0, '../../input_parsing') 
import parse_input 
 
all_wires = {} 
 
 
def create_dictionary(instructions): 
    """Take in instructions and place the connections into a dictionary entry for the wire. 
    eg: 123 -> x would lead to a key of x and a value of 123. 
    """ 
    wires = {} 
    for instruction in instructions: 
        pattern = re.compile(r'(.*) -> (\w+)') 
        regex = re.findall(pattern, instruction) 
        connection = regex[0][0] 
        wire = regex[0][1] 
        wires[wire] = connection 
    return wires 
 
 
def break_up_equation(equation): 
    """Figure out the operand(s) and operation and return them.""" 
    two_operand_regex = re.compile(r'(\w+) ([A-Z]*) (\w+)') 
    one_operand_regex = re.compile('([A-Z]*) ([a-z]+)') 
    if re.match(two_operand_regex, equation): 
        result = re.findall(two_operand_regex, equation) 
        return result[0][0], result[0][1], result[0][2] 
    elif re.match(one_operand_regex, equation): 
        result = re.findall(one_operand_regex, equation) 
        return result[0][0], result[0][1] 
    else: 
        print(f"{equation=}") 
        return [equation] 
 
 
@lru_cache() 
def find_value_on_line(wire_to_find): 
    """Figure out what the final value is on a wire.""" 
    if all_wires[wire_to_find].isnumeric(): 
        return int(all_wires[wire_to_find]) 
    equation = break_up_equation(all_wires[wire_to_find]) 
    if len(equation) == 3: 
        if equation[0].isnumeric(): 
            operand_left = int(equation[0]) 
        else: 
            operand_left = find_value_on_line(equation[0]) 
        if equation[2].isnumeric(): 
            operand_right = int(equation[2]) 
        else: 
            operand_right = find_value_on_line(equation[2]) 
        operation = equation[1] 
        if operation == "AND": 
            return operand_left & operand_right 
        elif operation == "LSHIFT": 
            return operand_left << operand_right 
        elif operation == "OR": 
            return operand_left | operand_right 
        elif operation == "RSHIFT": 
            return operand_left >> operand_right 
    elif len(equation) == 2: 
        return find_value_on_line(equation[1]) ^ 65535 
    else: 
        print("one went straight through") 
        return find_value_on_line(equation[0]) 
 
 
if __name__ == "__main__": 
    print(f"Starting at {datetime.now().strftime('%d-%b-%Y %H:%M:%S')}") 
    bobby_instructions = parse_input.input_per_line('../input.txt') 
    all_wires = create_dictionary(bobby_instructions) 
    wire_a = find_value_on_line('a') 
    print(f"The value on wire a is {wire_a}") 
    print(f"Ended at {datetime.now().strftime('%d-%b-%Y %H:%M:%S')}")
require "../../input_parsing/parse_input" 
 
def create_dictionary(instructions) 
    wires = Hash.new 
    instructions.each do |instruction| 
        match_results = instruction.scan(/(.*) -> (\w+)/) 
        connection = match_results[0][0] 
        wire = match_results[0][1] 
        wires[wire] = connection 
    end 
    wires 
end 
 
def break_up_equation(equation) 
    if equation.match?(/(\w+) ([A-Z]*) (\w+)/) 
        broken_equation = equation.scan(/(\w+) ([A-Z]*) (\w+)/) 
        #puts "A 3 way match: #{broken_equation[0][0]}, #{broken_equation[0][1]}, #{broken_e
quation[0][2]}" 
        return broken_equation[0][0], broken_equation[0][1], broken_equation[0][2] 
    elsif equation.match?(/([A-Z]*) ([a-z]+)/) 
        broken_equation = equation.scan(/([A-Z]*) ([a-z]+)/) 
        #puts "A 2 way match: #{broken_equation[0][0]}, #{broken_equation[0][1]}" 
        return broken_equation[0][0], broken_equation[0][1] 
    else 
        return [equation] 
    end 
end 
 
@all_wires = Hash.new 
@cache = Hash.new 
 
def for_cache(wire_to_find) 
#def find_value_on_line(wire_to_find) 
    int = Integer(@all_wires[wire_to_find], exception: false) 
    return int if int 
    #puts "#{@all_wires[wire_to_find]}" 
    equation = break_up_equation(@all_wires[wire_to_find]) 
    #puts "equation is #{equation[0]} #{equation[1]} #{equation[2]}" 
    if equation.length() == 3 
        operand_left = Integer(equation[0], exception: false) 
        if operand_left 
            #puts "L: #{operand_left} is a number" 
        else 
            #puts "L: #{equation[0]} is not a number" 
            operand_left = find_value_on_line(equation[0]) 
            #puts "Now operand_left is #{operand_left}" 
        end 
        operand_right = Integer(equation[2], exception: false) 
        if operand_right 
            #puts "R: #{operand_right} is a number" 
        else 
            #puts "R: #{equation[2]} is not a number" 
            operand_right = find_value_on_line(equation[2]) 
            #puts "Now operand_right is #{operand_right}" 
        end 
        operation = equation[1] 
        case operation 
        when "AND" 
            return operand_left & operand_right 
        when "LSHIFT" 
            return operand_left << operand_right 
        when "OR" 
            return operand_left | operand_right 
        when "RSHIFT" 
            return operand_left >> operand_right 
        end 
    elsif equation.length() == 2 
        return find_value_on_line(equation[1]) ^ 65535 
    else 
        return find_value_on_line(equation[0]) 
    end 
end 
 
def find_value_on_line(wire_to_find) 
    #puts "Cache value is #{@cache[wire_to_find]}" 
    @cache[wire_to_find] ||= for_cache(wire_to_find) 
end 
 
 
if $PROGRAM_NAME == __FILE__ 
    instructions = input_per_line('../input.txt') 
    #instructions = ['123 -> x', '456 -> y', 'x AND y -> d', 'x OR y -> e', 'x LSHIFT 2 -> f
', 'y RSHIFT 2 -> g','NOT x -> h', 'NOT y -> i'] 
    @all_wires = create_dictionary(instructions) 
    answer = find_value_on_line('a') 
    #answer = for_cache('a') 
    puts answer 
end

Day 9

Solving Day 9 was an oddessy that took me a couple days to fully solve. When I first read the problem, it reminded me of something I remembered from undergrad. I couldn’t remember if it was from the second semester of programming or discrete math, but I knew that once upon a time I’d been taught the algorithm to solve this problem. Some searching revealed that it was Djikstra’s Algorithm that I’d been thinking of. That turned out not quite to be what I wanted because Djikstra is for when you have a specified start and end node. So I did a little more sleuthing and thought perhaps what I wanted to solve for was a Hamiltonian Walk. That tells you if there’s a path that will reach every node and what the length is. So that got me most of the way there, but what I wanted was the shortest path. So that could be accomplished via the Traveling Salesman solution except that the Traveling Salesman comes back home and in this problem, Santa was only supposed to visit each city once. The solution in that case is to create a fake city that has 0 distance to all other cities. (basically, take the matrix that defines the city distances and add an extra row and column of zeroes to the bottom and right side).

My AoC code for all years can be found at this Github repo.

Microsoft MakeCode

Stella wanted a little wheeled bot of her own so I got her some assorted pieces to build a similar bot to Sam’s without it being exactly the same. I also wanted to take advantage of the Circuit Playground Express and Cricket we already had. Unfortunately, I haven’t been able to figure out the ultrasonic sensor yet. But I hope to have her robot working in May.

Sam’s Thought Processes

As I’ve mentioned on this blog before, I always find it fascinating how the kids interpret the world. Here are a couple examples of how Sam is seeing things at this point.

LEGO Ban

Last weekend I was sitting at the computer, working on some code when my wife came into the room. “Did you tell Sam that he couldn’t play LEGOs?”

“Of course not,” I retorted.

“Did you tell him he couldn’t be in the basement, then?”

“Nope”

After a couple more questions, she cuts to the chase. “What exactly did you tell Sam when he came in to see you?”

“I told him no more screen time.” Sam had been playing video games for a while as well as watching some TV.  Well, now that LEGO doesn’t include instruction manuals for their large sets, you have to look up the instructions online. So he interpreted no screens as meaning he couldn’t use the tablet to look up the instructions for his LEGOs. Instead of asking if the tablet was OK for LEGOs, he was just complaining that I was banning him from LEGOs, leading to the confusion.

Peep and Egg

Now that the twins can read, they’ve been re-reading some of the books we’d previously read to them. One of the ones they’ve been returning to is called Peep and Egg: I’m not Hatching. It has a series of pages like these:

The takeaway is supposed to be that the egg is comfortable with the way things are, but could be having so much more fun if they’d come out of their comfort zone. Sam’s told us that the lesson is that Peep should learn to be more patient with Egg and let him do things at his own pace.

Mozilla’s Legacy

A few days ago I read this article over at Tech Republic about how, Mozilla’s greatest achievement is not Firefox, but the Rust programming language. They point to Firefox’s declining numbers in the face of Chrome and Chromium-based browsers and I’m inclined to agree with the author. There is, of course, a kind of poetry to this. Although Netscape was one of the first dot-com companies and beat Microsoft to the punch at creating the first mainstream web browser, it’s not Netscape Navigator which is its greatest legacy. Instead it’s spinning off into Mozilla and, the most poetic part, the creation of the Javascript programming language. (Javascript was written in just a week and a half and this episode of Red Hat’s Commandline Heroes podcast does an excellent job documenting it)

It’s also not unprecedented in the tech world – Bell Labs, the research arm of AT&T’s greatest contributions to tech have nothing to do with telephones. Their researchers invented transistors (basis of modern computers), the C programming language (pretty much every operating system and most video games until recently were written in C), the UNIX operating system (between UNIX and its kinda-descendent Linux – a good portion of the research computers and the Internet run on these OSes), and many other technologies. So it wouldn’t be the worst legacy for Mozilla to have. 

Rust, in case you’re unfamiliar, is a low-level language like C but it has safety mechanisms that should help reduce the number of bugs that can be exploited by the bad guys – at least at the operating system and driver level. Google has indicated it will begin using Rust in Android. Linus Torvalds has mentioned he’s not opposed to it in the Linux kernel. I believe I’ve also seen articles saying that Microsoft is considering using it for future versions of Windows. 

I don’t think it would be a good thing for us to end up back in a place where there’s only one browser – Chromium and its clones, but if Firefox dies, at least Mozilla will have given the world Rust. (Also, Firefox was originally called Phoenix… just as it rose from Netscape’s ashes, maybe something else would rise from Firefox)

OMG: All Your Base is 20 Years Old

As I was going through my feed reader recently, I came across an article from Ars Technica, that I’d skipped over when it first came out, which announced that the All Your Base Meme is now 20 years old. I couldn’t believe it. It was my first meme, a few years before Numa Numa would be the meme that crossed over into regular pop culture. It led me to The Laziest Men on Mars’ page on Mp3.com, which was a kind of proto-Bandcamp in the early 2000s where indie bands (and some commercial bands) would put up MP3s to gain followers. (This ended up being my favorite song from The Laziest Men on Mars) Here is the video that took over all of us on the Internet 20 years ago:

Yeah, I’m sure you’re wondering how in the world that was a thing anyone cared about. But, much in the same way that I wonder how anyone could ever enjoy most of early cinema, it was a different time on the Internet then. A time when putting together an amateur video and getting it to everyone was just starting to be feasible. And it got so embedded into my brain that about six so years ago I got the following shirt when I went to the Defcon conference:

all your base shirt_
all your base shirt

Yeah, there’s a lot of geekiness contained in that one shirt.

Anyway, hope you enjoyed that trip down memory lane or, if you’re a young millenial or Gen Z are shaking your head at what we late Gen X/early millenials found entertaining.

Programming Projects: March 2021

I started off the month thinking it was going to be Python heavy and ended up doing a lot more micro-controller programming. To be fair, I was mostly programming in CircuitPython, but it definitely came out of nowhere.

Python

Civilization VI Webhook in FastAPI

Last month I created a webhook program in Flask to generate notifications when it was someone’s turn in our multiplayer Civilization games. When I posted about it on reddit, someone suggested that I would be better off using FastAPI instead of Flask. I’d been hearing about FastAPI for months on Talk Python to Me and Python Bytes, but I always got the impression that it would only be useful if I was writing my website to be async. 

Instead what I got was a much cleaner interface, an automated documentation system, and better use of types to validate data. I’m only using a fraction of what’s nice about FastAPI and I find it much nicer to use for this use case than Flask. After I got it working as well as when I was using Flask, I started working on enhancements and bug fixes. 

The work that drove me nuts until I figured it out was how to clean up my code (that is, refactor to reduce code reuse) and still maintain the ability to not have duplicate notifications from the Civilization Play By Cloud service. It turned out that I needed to be faster than 0.01 seconds to handle the code. So I had to write the new turn to the dictionary that’s functioning as a sort of bootleg database BEFORE posting to Matrix. It was quite satisfying to figure that out.

I then focused on moving some items (like usernames) out to config files so that it would be easy for someone to take my code and use it for themselves. I’m almost done with that. Afterwards I’ll create a PyPi package.

The github repo is here.

Django 2 by Example and Prophecy Practicum Django Rewrite

On the other end of the Python web frameworks, I also did some work with Django. When I first tried to learn Django a few years ago it was just too complex for me to understand. I was trying to learn too many concepts at once. Now that I understand decorators and, thanks to my work with Flask and FastAPI, the concepts of routes, it’s a lot easier for me to learn Django. The MVC framework still separates things a lot, causing a higher cognitive load. However, I can see the beauty in how it separates things and makes it easier for teams to work on the code. 

Once I had enough of the basics under my belt, I took another look at the Prophecy Practicum app I was writing for a friend. My work on creating it with Flask ground to a halt under the weight of all the extra work I was doing to develop things like an admin view. Eventually, I realized that Django may be a heavy framework for the way a lot of web development is done nowadays (feed APIs to phone apps and Javascript libraries), but for what I wanted to do, it would reduce a lot of the work I was doing because it came with those libraries built in. So I’ve been able to almost get to a working first stab at things with only a couple hours’ work. It’s a lot nicer to focus on what I want the app to do rather than having to build up a bunch of scaffolding. Also, I love the way it handles creating databases from classes.

CircuitPython

Play Dough Piano

When reading through the Adafruit Python on Microcontrollers mailing list, I found out about a Play Dough Piano (unfortunately I couldn’t figure out how to download that presentation). I copied their CircuitPython code since I don’t have any experience with CircuitPython HID. But I developed the Scratch code on my own thanks to all the experience I gained last year with Scratch. I also used my recent experience with soldering to add the pins to the QTPy. If you decide to do this yourself, it’s important to note that you cannot use a breadboard because the capacitive touch pins on the QTPy reads as a key being pressed. The kids had a lot of fun and it finally gave me an idea of what to make with a QTPy. I bought 2 of them when they were half off during John Park’s show on Adafruit. The code is available here.

QTPy Streamdeck

I don’t need a slick Streamdeck, just the ability to be able to take a few actions while in-game.

Working on the Circuit Python Piano with Sam combined with seeing someone make a Streamdeck using Cherry MX keys make me consider that perhaps I could use my QTPy to create a Streamdeck. I’d previously been focused on recreating the ElGato Streamdeck, so I was going to use a PyPortal. However, a PyPortal is $50-ish and I don’t have a 3D printer to make an enclosure. Meanwhile I already had the QTPy and some buttons. I didn’t need the buttons to change or have images on them, so I went ahead and created a nice, simple Streamdeck. My first version only worked if I had OBS in focus which defeated the purpose. I was using key.send. Afterwards speaking to someone in the Adafruit Discord, I learned that I had to do press and release. Now it works awesomely and I can start recording and pause/unpause the recording without leaving the game.

The repo is available here.

Microsoft MakeCode

Sam’s car

I got tired of waiting for the BBC Micro:Bit V2 to be in stock at Adafruit. It’s the same price as the BBC Micro:Bit V1, but with more features, so it felt silly to get the earlier version. But I got tired of not being able to build the CuteBot with Sam, so I bit the bullet and bought the version 1. It was very easy to program in Microsoft MakeCode because there are special blocks for programming the car. We were able to program the car to “dance like a bee”, avoid obstacles, and follow a path. The latter was particularly impressive to the wife. The kids were amused that their stuffed penguins were invisible to the car’s eyes. That is, when in obstacle avoidance mode, it would still crash into the penguins. I thought that was a little odd myself. But then I did some research and realized the “eyes” were an ultrasonic sensor. Since it’s using echo-location, it doesn’t work on furry objects – the same reason that padding is used to improve the acoustics in a room by dampening the noise. The object needed to be reasonably solid to let the car know it was there. I still have some more tinkering to do with Sam to add some more options to the examples the car’s manufacturer printed in the manual.

C#

GameDev.Tv Multiplayer class

I finished up the online multiplayer video game class I was taking through GameDev.Tv. As I’ve said in previous updates – I now truly appreciate the work that goes into an online multiplayer game. It’ll be a while before I add multiplayer to the game I’ve been working on, but I’ll definitely be studying what I did in this class when the time comes. I highly recommend it if you’re considering making an online multiplayer game for the first time – especially if you want to do it over Steam.

My Extra Life Donation Tracker reaches v6.0 (feature complete)

This is my seventh year raising money for Johns Hopkins Children’s Center via the Extra Life gaming charity. When I started back then I was brand new to streaming or recording video game play. In fact, just a few years before that I hadn’t even understood the point. I found out that you could somehow display your progress towards fundraising on your screen while you played. I had no idea how to do that and, at the time, I’d only done commandline programs. So I found bfinleyui’s web-based program. I set up XSplit (which I was using at the time) to capture the web pages and was able to have a great first year. The following year he created an app with Adobe Air that was even better. The GUI for this app would become the inspiration for ElDonationTracker; what I aspired to eventually build. My first commit to the repo for ElDonationTracker was that year. I was exploring how to get the API data via the commandline, but I wasn’t too hurried because I had the Adobe Air app. Unfortunately, the following year Adobe killed Adobe Air. So it was now time for me to try and make my own app. Unfortunately, I’d never done GUI programming before and my experiment with the TKinter GUI framework didn’t quite work.

I spent a year or two perfecting the API part of the code. I would run it on the commandline and use the output for my streams. It worked on both Linux and Windows and things were pretty good. But I still didn’t have the GUI. This meant I still didn’t have the “you got a donation” notification with an image and sound file. This was what I missed most from bfinleyui’s GUI app.

Extra Life Donation Tracker Donation Alert window
Extra Life Donation Tracker Donation Alert window

Finally, a few years ago I discovered how to easily code with the QT GUI framework thanks to a book I’d read and the discovery of the QT Designer program. All I had to do was create a GUI with drag and drop and then use pyuic to turn it into Python code. From there I could add my logic and the first GUI was born.

I then spent the next few years perfecting the code. There are a few issues in the Github repo documenting various bugs I’ve had to iron out. I’ve also added unit tests to try and capture regressions and other issues.

With 6.0 I have finally met all the goals I set out to reach 6 years ago. It’s a great-working GUI that provides everything I need for streaming for Extra Life. I have other users (evidenced by bug reports) and that really makes my day. During the 2020 Extra Life Day, the Streamlabs integration (which has displaced the need for programs like this) failed, but my program continued to work. Huzzah!

Extra Life Donation Tracker main GUI window
Extra Life Donation Tracker main GUI window

One thing I made a key goal for 6.0 was structuring the project so that others could use the Donor Drive API I’ve built to create other Python Projects. In order to really drive this home, I may end up separating that code out into another package, but I hadn’t decided at this point.

Now that I’ve finally reached my goal, it may be a while before I reach 7.0 or even anything past 6.1. I will focus on improving the unit tests and, if anyone requests it, new outputs. It’s been incredible to work on a project for 6 years and finally reach a finishing point. It’s my longest running, most complex, and most used project and it’s the one I’m most proud of.