Review: The Great Hunt

The Great Hunt (The Wheel of Time, #2)The Great Hunt by Robert Jordan
My rating: 3 of 5 stars

This book was quite a slow burn. (And I know some of the later books in this series are strongly disliked for keeping the story running in place) About a quarter of the way through the book I was certain this would be the end of my stroll through the Wheel of Time. But, gosh darn it!, Robert Jordan pulled it through at the end. The climax was pretty incredible and we learned some very interesting aspects of the in-world history. I thought the best part was the damane sul’man backstory which reminded me a lot of the backstory to The Handmaid’s Tale. There was definitely some schaudenfreude there.

At this point in my reading journey, I’m OK with a slow burn of a book. Otherwise I wouldn’t read The Stormlight Archive. But the biggest bummer with this book is that there was basically a real lack of character growth. The characters just kept denying what they needed to do. And, yes, many books involve that trope. But this one has essetially been going on for 1.5 books at this point. That makes it a bit tiresome. I’m hoping that, going forward, we can have a bit more character growth and a bit more plot movement per book (even if I know there are a few books later on where things get stuck). This series is still on probabation. Let’s see if they can earn my desire on the next entry. We’ll be back to the world of the Wheel of Time later this year – probably in the fall.

View all my reviews

Review: A Wizard’s Guide to Defensive Baking

A Wizard’s Guide to Defensive BakingA Wizard’s Guide to Defensive Baking by T. Kingfisher
My rating: 4 of 5 stars

Well, that was quite an excellent book! My 9-year-old read it and then wanted to share it with me, so she asked me to read it to her before bed. I must say, this book was a lot more sophisticated than I expected from the title and from the expected audience. It’s quite a mature take at the subject matter; T. Kingfisher definitely believes in the maxim of not talking down to her audience. There are themes of death, PTSD, fantasy racism, wrongful arrest by the state, war, and so much more. It really does prepare kids, mentally, to deal with the fact that the adults don’t have it all together. The key, of course, that it does so realistically. It’s not the cruel or ineffectual adults of British kids novels, these are adults doing their best and still failing; or acting under selfish motives.

On top of all that, Kingfisher played with all the tropes and had quite a few minor plot twists that kept me guessing about which way things were going to go. The way she was dealing with things made me question whether this was the type of book where everyone would make it to the end or what the cost would be if they did.

I highly recommend this book for any young fantasy readers in your life who are ready to deal with some more mature themes (although, not mature as in adult – no real profanity, no sex, or anything like that). My 9-year-old ate it up, but you’ll have to judge if your reader is ready at that age or needs to wait a bit more. I’m definitely curious to see what else this author has written as T. Kingfisher (she has different genres under different pen names).

View all my reviews

Review: The Official Scratchjr Book: Help Your Kids Learn to Code

The Official Scratchjr Book: Help Your Kids Learn to CodeThe Official Scratchjr Book: Help Your Kids Learn to Code by Marina Umaschi Bers
My rating: 4 of 5 stars

Many of you may be familiar with Scratch if you’ve got kids about 15 or so years old or younger. It’s the hot language for the elementary and (in some places) middle school set to teach programming. It’s particularly great for the younger kids because programming takes place using blocks that slot into each other. This allows for the kids not to have to worry about spelling or curly braces or semicolons. You just plug blocks into each other and code. I scoffed at it at first until I saw the complex programs kids can create with Scratch. Scratch Jr is almost exactly the same thing, except it’s for younger kids and it’s a tablet program.

I went through this book with my five year old twins. My son was a bit too impatient and bounced out halfway through. My daughter stuck with it and make it all the way through the final big project at the end. The book is written as if speaking to the children, but each chapter has a “for grownups” section that gives some advice for how to take the chapter’s lessons a bit further. It seems targeted at educators, but shouldn’t be any trouble for parents to use (as I did) as long as you aren’t someone for whom technology seems to be bewildering. There are TONS of images showing you exactly what to do for the base program. From there it should be easy to extrapolate for the challenge programs. The authors have done an amazing job here and I can’t think how they could have done any better.

As I said in a review for another programming book for kids (and on my blog) I believe I tried to get my oldest into programming the wrong way – with a kids book on Python programming. While Python is an extremely easy language to learn, it was a little too much to learn programming concepts at the same time as learning to type and specific syntax. If you have a child in your life who’s about 5-7 years old, this book is a perfect introduction into programming. Almost everyone has a tablet nowadays, so it even works if the family doesn’t have a desktop or laptop computer. If they really enjoy it, feel free to graduate the kid to Scratch. (You can program it online or download offline programs if you have an inconsistent Internet connection) Every kid is different (I began my programming journey when I was 8 (decades ago) with BASIC), but I would wait to introduce them to Python or Ruby until they’re 11 or so.

View all my reviews

Review: Sourcery

Sourcery (Discworld, #5; Rincewind #3)Sourcery by Terry Pratchett
My rating: 3 of 5 stars

This is my second time reading this book

I believe this book marks the inflection point from the retconned books to the more continuity focused books. It appears that Equal Rites has already been retconned away by this book or else Rincewind is ignorant of those events when he tells Conina that no women enter the doors of the university. Although, I guess we can’t trust him too much because I believe even this one mentions that women work in the kitchens and so forth.

This book has a bit of a feel of a sitcom. It’s got guest-stars like Conina (one of Cohen the Barbarian’s daughters) who don’t really have any character growth and are mind-wiped at the end of the book. In fact, the reset button is hit on most of the Discworld at the end. I believe only The Librarian and Rincewind (and maybe some anonymous wizards) have any idea of what happened during the course of this book. And, at the end, Coin (view spoiler).

That said, the narrative structure is getting a bit more conventional by this book. It’s less a series of fantasy Monty Python sketches, and a more coeherent story. That said, we do get introduced to Discworld’s Arabian analogue. Lots of fun there, including messing around with what the point of a harem is (see 1001 Arabian Nights) and having some fun with the Vizier trope. (Definitely a trope Pratchett enjoyed playing with. There was a great scene in Mort with Discorld-China’s emperor and vizier. I believe Pyramids also has that trope as a main bit of the story)

Can it be read standalone? There’s a bit about Rincewind and The Luggage that would be well served by having read the previous Rincewind books. That said, it’s not too important a bit of canon. Pratchett also does a good job introducing the the way wizards feel about each other (and he’s 1-2 books from ending that) so you don’t need that either. You miss the story of why The Librarian is the way he is an the joke about Cohen the Barbarian, but these are tiny Easter eggs. Yes, I do believe you can read this one standalone. I guess it also means you can skip if it you wanted to start further in the Discworld series.

View all my reviews

Review: Mort

Mort (Discworld, #4; Death, #1)Mort by Terry Pratchett
My rating: 4 of 5 stars

This is my second time reading Mort

I dropped the rating from 5/5 to 4/5 because I’m using the tooltips for the ratings. I really enjoyed this book a lot. In my re-read this is the first tone I have enjoyed without any reservations. But it wasn’t “amazing”.

This is the first Discworld book that can be read completely independantly of the others. Are there some Easter Eggs if you’ve read the first 3 books? Sure. There’s mention of Granny Weatherwax’s Discworld version of “marital aides”. You’ll know why the librarian at the Unseen University is an Orangutang. And this will be the second time you meet Death’s adopted daughter. But, outside of that, this really is a great standalone book. If I wanted to do a survey of British fantasy humor (say I was a University professor), I could assign this book and folks would get the idea without feeling that they were being dropped 4 books into a 30-something book series.

The premise of the book is quite simple – Death takes on an apprentice. But Pratchett takes that simple premise and builds up a relatively deep (considering this is part of a fantasy satire series) exploration of the meaning of life, death, nihilism, fate, etc. We get a good look at the last few minutes of various folks throughout the Disc and each provides a little insight. It may seem a bit maudlin, but while I was reading this book I thought more about evaluating how I was spending my time and making sure I made more time for the wife and kids.

At this point in my re-read, I think I would say that if you want to know whether you should consider the Discworld – read this one first. If you like it, then you’ll probably enjoy most of the Discworld books. At that point it’s up to you whether you go back and read the first 3 or just go from here on out. In my memory, once we get to the end of the next book, Sourcery, Pratchett has figured out that he’s going to do Discworld for the long haul and we start to get a more coherent story that maintains continuity. (Although you can see bits of that settling already with this book)

View all my reviews

Review: Equal Rites

Equal Rites (Discworld, #3; Witches, #1)Equal Rites by Terry Pratchett
My rating: 3 of 5 stars

This is my second time reading this book

This is DEFINITELY a book of its times. I remember in the late 80s and early 90s there was a lot of fiction around whether women could really equal men in the workplace. Why then? I guess because it’s one generation removed from the Civil Rights era in the 60s and 70s? I know the backlash had grown by then, leading to Atwood to write The Handmaid’s Tale. Of course, that leads later into the Girl Power movement.

In this book we follow Esk who was accidentally identified as the 8th son of an 8th son. Sourcery, Discworld #5, is the last time Pratchett makes a big deal of ancestry that leads to wizards, I believe. This book also introduces Granny Weatherwax, a witch from the sticks out in the Ram Tops in a city called Bad Ass. If I remember correctly, up until Sourcery, Pratchett was still working through what the final canon of the Discworld would be, so I believe some Granny details (and perhaps this story?) are later retconned. I know there’s a later story once Mustrum has become the leader at Unseen University that is perhaps the next time Granny interacts with wizards. (While this book ends with the current chancellor inviting Granny to part-time teach at UU and to send studends to learn herbology out with Granny in Bad Ass) Also, unless I’m forgetting, Esk is never heard from again – nor do other girls ever matriculate at UU. (But I didn’t read Pratchett’s Middle Grade/YA Discworld books…so maybe she appears there?)

As for the main story – I hadn’t read in over a decade so I forgot that it was almost not at all about Esk being the first female wizard. Instead it’s about Granny raising her and Pratchett introducing us to the fact that most witchcraft is actually psychology. (*this* part is NOT reconned later) Also, a decade before I read any of the books in A Song of Ice and Fire, Pratchett was the first to introduce me to warging (he calls it borrowing) and the perils of losing yourself in the animal you control. Later on, the book transitions to a travel novel where Pratchett gets to introduce us to more of the Discworld. It’s done in a neater fashion than in the previous two books – it’s less a series of pastiches then a story that follows Esk’s journey and allows us to see how a very intelligent girl who has lived her entire life in a small village deals with increasingly larger towns and cities. It’s only the last tiny fraction of the story that involves Unseen University. I think that would be less disappointing if Esk became a recurring character in the Discworld. At least we get Granny out of it and Nanny Ogg is a great foil for her in the later books. Once again, I got a lot more out of the Dungeon Dimensions for having learned about Lovecraft since then.

It’s an OK book. He hadn’t quite hit his stride yet. Granny Weatherwax is pretty awesome, but without anyone else who appears later on in th series, you can probably skip it depending on how you felt about the first two books.

View all my reviews

Review: The Light Fantastic

The Light Fantastic (Discworld, #2; Rincewind #2)The Light Fantastic by Terry Pratchett
My rating: 3 of 5 stars

This is my second time reading this book

This second time around I dropped the rating from 4 stars to 3 stars. The book is definitely an improvement over The Color of Magic. I think, perhaps, Pratchett was starting to consider that Discworld might extend beyond a couple books. That said, from my memory, there’s about 1-2 more books that contain plot points that are effectively somewhat retconned later. A the very least, Equal Rites seems to never be spoken of again – and Discworld seems to revert to male wizards and female witches. And I can’t remember if Sourcery has last consequences or not.

That said, this book retains the random, mostly episodic quality of the first one where the heroes go from place to place and meet fun subversions of fantasy tropes. I used to strongly suggest that people should read the Discworld in order and just power through these first 2-3 books to set the stage for the better books later. Now, I’m kinda ok saying that perhaps the reader could skip this second book. Sure, they’d miss the introduction of Cohen the Barbarian, but it’s not like he’s a HUGE character later – nowhere near as big as Vimes, for instance. And, sure, they’d miss Rincewind taking posession of The Luggage, but I think that’s mostly a non-issue.

It’s a slight bummer not enjoying this as much on re-read. But I think the first few books were just getting by on pointing out the silliness of adhering to high fantasy (mostly Tolkienesque) tropes. Later on (in my memory – hopefully I’m right) the books tend to have more of a plot that allows them to stand on their own even if they continue with the British humor silliness. (Which I love. Those and dad jokes) So we’ll see. It’s on to my re-read of the third book.

View all my reviews

Jonathan Coulton and Paul and Storm at Ram’s Head in Annapolis

On 30 June 2021, I attended my first concert since COVID-19 started. I was masked since the Delta variant is a thing and singing indoors is definitely an activity that increases transmission. Despite that, it was awesome to get to do it again and there was a real sense of joy in the room from both the audience and the performers at once again being able to engage in the ancient human ritual of enjoying music as a crowd. 

Paul and Storm on stage at at Ram's Head in Annapolis
Paul and Storm on stage at at Ram’s Head in Annapolis

This concert, which had already been delayed some 18ish months, was the first time I saw Jonathan Coulton and Paul and Storm live in person. Daniel introduced me to JoCo somewhere around 10-15 years ago when he was mostly making songs satirizing nerd and office culture. Or just pop culture with songs like Tom Cruise Crazy or Ikea. His biggest claim to fame is the ending music to Portal and Portal 2. More recently he released Solid State a concept album that splits the difference between his nerdier lyrics and regular pop/alternative lyrics. This was then followed up by an album of 1970s covers. 

I can’t fully remember if Paul and Storm came to my attention by way of the Jonathan Coulton kickstarter for Solid State or from Randall Munroe of XKCD who did the cover of their last album, Ball Pit. I then binged their songs on Spotify for a while and discovered various videos of their performances on the JoCo Cruise and told myself I’d see them live if I could.

Naturally, for a band with a song called Opening Band, Paul and Storm opened the night.

Looking at the ladies' underwear thrown at the band
Looking at the ladies’ underwear thrown at the band – a joke that stems from the lyrics to Opening Band

They revealed this was their second performance since COVID as a play for sympathy from the audience. It was also a segue into their song Write Like the Wind:

They mentioned the only lyric that was inaccurate (9 years after having debuted the song) was that GRRM’s slow writing style did NOT hold up the Game of Thrones TV show. From there, the set proceeded as a musical comedy show. Between each song was a comedic riff or tangent that showcased how good the band is at playing off the audience. This turned out to be both a good and a bad thing. Ram’s Head On Stage in Annapolis has seating like a comedy club. Everyone’s at a table and it’s an extremely small venue. It led to some great intimate moments with the band and some great riffing, but give a crowd an inch and they’ll take a mile. By the end, maybe because of drinking or maybe just people being people, some folks in the crowd were starting to get a little annoying with their constant attempts to make themselves the center of attention. Both Paul and Storm and JoCo have been doing this for 20 or so years so they can quickly regain control. Also, they don’t have the fragile egos you sometimes see when comedians are getting interrupted. They just redirected the flow like comedy kung fu masters. As per usual, the ended with The Captain’s Wife’s Lament which took about 15-20 minutes to get through. I’d see them live again anytime.

Jonathan Coulton on stage at at Ram's Head in Annapolis
Jonathan Coulton on stage at at Ram’s Head in Annapolis

After a short intermission it was time for Coulton to take the stage. He had, in my opinion, the perfect set for someone that’s been making music as long as he has. He performed songs from all over his catalog and I knew all but maybe 3 of them by heart so it was fun to sing along. He wasn’t as chatty between songs, but there were still some pretty funny segues. For the older songs, this was Coulton as I had experienced him most – with just an acoustic guitar. (For a while now he’s done some recording and touring with a full band). For the newer songs it was a nice little change; pared down. He did a fun medley with Paul and Storm near the end that was reminiscent of this song from The Axis of Awesome:

Essentially a bunch of songs that either had a similar melody or similar enough for him to seamlessly transition. 

A real rocker moment during the Creepy Doll song

When the concert first started, Paul and Storm asked the audience to raise their hands if they’d never heard of the band. Somewhere between 15 and 25% of the audience raised their hands. I heard them laughing as they heard the various punchlines in the songs so I’d say if they’re in town it’s ok to bring friends and family who’ve never heard them before. While they can be as silly as Weird Al (or in JoCo’s case darkly humorous), the songs aren’t parodies of pop songs so you don’t need to know the original song to get all the enjoyment out of it. 

All in all, a great outing (now that we can have outings) and I’ll definitely keep an eye out for them when they swing by again. Now, all of this happened (and I wrote all of this blog post) way before the COVID-19 Delta Variant was raging through America and making us rethink whether things were going to re-open. However, I thought this monologue that Jonathan Coulton gave about how COVID-19 has made him appreciate his pre-COVID life and not get so annoyed at the little things involved in being a traveling musician was great and I wanted to use it to close out the blog post.

Appreciating life as a musician

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.