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.

Looking back at a Year of COVID-19

It seems that it’s time to look back at a year of COVID-19. Scalzi did it. Ars Technica did it. I’m not usually a huge bandwagon jumper, but I thought, “why not?” This has been a huge, disruptive event. It might be therapeutic to write about it.


It was 11 March (I believe) when the WHO officially declared COVID-19 to be a pandemic. One of the first things I remember hearing about COVID-19 was the cruise ship that was stuck offshore because President Trump was so afraid of the numbers rising that he couldn’t let the folks off the ship. Turns out that was going to be a foreshadowing the likes of which we couldn’t quite understand at the time. My first inkling that maybe this was starting to become an issue in the US was in late February or early March when we went to visit relatives in New York City and they were against eating out because they were scared of getting sick. At the time, we thought they were just being a bit germaphobic. In fact, at the end of March we went to a restaurant for what we didn’t know at the time would be our last time to go out to eat for a year. (To date we still haven’t eaten out, not even for outdoor dining)

After that, of course, was the infamous “masks aren’t necessary” phase of the pandemic. So we just tried to limit our trips to the stores, but didn’t really worry about masks. Then work had us wear masks in public areas, but not at our desks. Eventually, it was all masks all the time. Which is where we remain today.

I got something around 1-2 months off of work during peak pandemic. Also, from not going anywhere on vacation, I ended the year with a ton of vacation days I couldn’t carry over. So I was able to dedicate a few days to programming projects and electronics projects. By being able to work continuously for many hours rather than coming to it at the end of a work day and spending a chunk of time remembering what I was working on, I got a lot further with my projects. I also spent a lot of time playing video games with the kids. I didn’t get as much cooking done as I would have thought at first because in the early pandemic there were constant food panics that made finding exactly what I wanted very hard. During the sour dough bread boom it was hard to find flour, for example. We also tackled some time-consuming house tasks like staining the deck or painting the porch columns.

I don’t understand the folks who have been complaining of boredom; of finishing Netflix, etc. Am I the only person in the world who has hobbies?

For me, the biggest negative from the pandemic was not getting to see my family. I usually travel to see my direct family 2-3 times a year and my in-laws another 2-3 times. And they usually each head this way a time or three. That’s basically it. I’m mostly an introvert. I’ll have fun at a work picnic or a family get-together, but I don’t need or crave human interaction. Between work and the wife and kids, I don’t have any needs outside of that. As for restaurants, I go out to eat when the wife desires a different atmosphere, but I don’t really enjoy eating out. Unless we’re spending a ton of money, the food is never better than what either my wife or I could cook. It’s also inevitably going to be less healthy. The only place worth going out to IMHO is Korean because making a ton of ban chan (the little side dishes) is more trouble than it’s worth for just one meal.

I have lots of sympathy for those who have lost their businesses. Marketplace has been featuring interviews with folks who happened to think January 2021 was a great time to open the business they’ve been dying to open their entire lives. I have sympathy for the folks who work in the restaurant and bar industries that have lost their jobs and income. If we put those folks aside, I don’t understand the folks who have been complaining of boredom; of finishing Netflix, etc. Am I the only person in the world who has hobbies? Even with the aforementioned 2 months off of work, I’ve still got TONS I could do if someone were to pay me my current salary and tell me to stay at home.

From various Humble Bundle purchases, I’ve got about 350 video games to play. (If you don’t know – via Humble Bundle you can usually get 10-20 games for about $20) Most of them I’ve never played. Many, like Civilization or Spelunky, are infinitely replayable. I have over 1000 digital books and magazines to read. I have a bunch of programming projects. I have programming languages I’d like to learn. I have a backlog of photos to edit and/or tag. I have electronics projects to work on. There are over 200 new recipes I’d like to try. There are somewhere between 200 and 300 comic book issues I digitally have that I haven’t read yet. I have a bunch of classes to learn how to program video games. Scarlett and I started taking a drawing class. I have TV shows and movies that I wouldn’t mind seeing. Just those things together would probably be a full-time job for a couple years. On top of that, I have kids to raise and play with. A wife to be a husband to. And I know lots of folks are doing the “bubble” thing with their parents – if I were doing that, too then I’d have parents and 5 younger siblings to grow my relationship with. I don’t get it. Are most Americans that caught up in our Puritan heritage that they can’t have fun without work? I see especially see major fulfillment when I program because I’m creating things that others find useful. It’s very interesting.

They always say that folks die soon after retirement because they don’t have anything to do and they almost literally die of boredom. I don’t see that being a problem with me.

Well, a year out it looks like we may be turning the corner on the pandemic phase of COVID-19. Some scientists are saying it may be here to stay with us. COVID-19 may become like the common cold or the flu. Every winter we get some shots to keep us from either getting it or getting a mild case if we do get it. And that might be the best we can do. I’m fine with that if it means I can feel safe traveling to see my parents and my in-laws. It was kinda crappy to see the country fall apart in a time where we should have banded together. I’m hoping (perhaps stupidly) that this was merely a failure of leadership and not a true semi-permanent state of being here in the US. The scientists say these pandemics may become more frequent as climate change pushes different animals into contact with us and zoonotic transfers become more common. I’d like to hope that it doesn’t matter if we have a Republican or Democratic president – next time we’ll do a better job.

We’ll just have to see.

Programming Jan/Feb 2021

I was pretty busy programming at the start of 2021 across a few different languages. Let’s jump right in!

C#

I’m nearing the end of the GameDev.tv online RTS course, and it’s been a lot of fun. Since last time we added player colors to the units, a minimap that can be used to move around the screen, new units, and a Lobby UI. I’m a few lessons away from being able to create binaries I can use to play online with others or via Steam.

MS MakeCode

I wanted to try a new electronic project with Stella, so I fired up the tutorial for the Circuit Playground chairs swing ride. I had her cut out the figures that would go on the ride. Then I used the glue gun to put everything together. After all the parts were ready, I had Stella do the programming since the kids are used to programming in Scratch and MS MakeCode is basically Scratch plus the ability to do Javascript. 

Python

Python Morsels

I completed my final assignment for the Python Morsels exercises. This time we had to take in a list of timestamps and sum them together. This time it wasn’t only a great exercise to learn and practice with Python, but it’s also a utility I can use in various projects. I immediately realized it could have made summing up the times for my end of year video games blog post a lot easier. Here’s the solution I came up with:

import math 
 
 
def figure_out_base_sixty(number: int) -> (int, int): 
    """Figure out the next number up if I have more than 59 seconds or minutes.""" 
    if number > 59: 
        return math.floor(number/60), number % 60 
    else: 
        return 0, number 
 
 
def sum_timestamps(timestamps: list) -> str: 
    """Accept a list of timestamps (in the format of MM:SS or HH:MM:SS) and return a timestamp that is the sum of all 
    given times. 
 
    :param timestamps: A list of timestamps. 
    :type timestamps: list 
    :returns: Timestamp sum of all times in the list. 
    """ 
    split_time = [timestamp.split(':') for timestamp in timestamps] 
    hours = [] 
    minutes = [] 
    seconds = [] 
    for timestamp in split_time: 
        if len(timestamp) == 2: 
            minutes.append(int(timestamp[0])) 
            seconds.append(int(timestamp[1])) 
        else: 
            hours.append((int(timestamp[0]))) 
            minutes.append(int(timestamp[1])) 
            seconds.append(int(timestamp[2])) 
    total_hours_step_1 = sum(hours) 
    total_minutes_step_1 = sum(minutes) 
    total_seconds_step_1 = sum(seconds) 
    minutes_to_add, total_seconds_final = figure_out_base_sixty(total_seconds_step_1) 
    total_minutes_step2 = total_minutes_step_1 + minutes_to_add 
    if total_minutes_step2 > 59 or hours: 
        calculated_hours, total_minutes = figure_out_base_sixty(total_minutes_step2) 
        final_hours = calculated_hours + total_hours_step_1 
        return f"{final_hours}:{total_minutes:02d}:{total_seconds_final:02d}" 
    else: 
        total_minutes = total_minutes_step2 
        return f"{total_minutes}:{total_seconds_final:02d}"

After all this time of learning, my solution was actually pretty close to Trey’s solution, and that really made me feel great.

Pybites

In the same Humble Bundle where I got the Python Morsels exercise credits, I also got access to Pybites. I’ve done about 7 or 8 of them so far. The platform is nice, with a built-in Python interpreter and a good community. But if I compare it to Python Morsels, I don’t like it as much for learning. They give you a problem and provide unit tests to make sure your code works. But, unlike Trey – if you need help the solution is simply stated. Trey’s solutions, on the other hand, contain a lot of commentary that help to explain why it’s the best answer. He also covers answers that work, but aren’t as pythonic. His bonus questions build on the base problem in a way that really encourages learning. Pybites isn’t bad, but after doing Python Morsels – if I were going to pay for one of them, I’d pay for Python Morsels.

Civilization VI Play by Cloud Webhook

I’m a little late to this, but in the final weekend of February 2021 my brothers and I started playing Civilization VI using Play by Cloud. Previously, the only way to play asynchronously was to use an external service like Play Your Damn Turn. (We used to use another one with Civ V, but Play your Damn Turn works with Civ V, Civ VI, and Beyond Earth). Play Your Damn Turn (PYDT) has a neat little app that runs on your computer to let you know when there’s another turn. Play By Cloud, which Firaxis integrated into Civilization VI in a February 2019 update, just uses Steam updates. Dan and Dave have been using Play by Cloud for their newest games, but this weekend they invited me to start a game on there, too. For some reason, Steam updates didn’t quite work all that well to let me know when it was time to take my turn, but I found out you can set up webhooks to get informed by Civilization when there’s a new turn available. Almost all the examples I found online involved setting up the webhooks to push alerts to Discord. I’ve got a Matrix server, so I spent the weekend writing up a program to handle it for us.

When I was working on it, I didn’t create a perfectly sanitized program without any info I wouldn’t want out there, so I’m not ready to put it on Github, but I can share some sanitized code here. 

When I was trying to develop, it took some searching to find out what data is sent by Civilization VI. It sends JSON:

{
"value1": "the name of your game",
"value2": "the player's Steam name",
"value3": "the turn number"
}

While working on the code, I found out that you can also set up webhooks with PYDT. They actually send even more data (with actually useful names!):

{
"gameName": "the name of your game",
"userName": "the user's Steam username",
"round": the round number (int),
"civName": "the name of your civilization",
"leaderName": "the name of your civ leader (and for some of them the attribute)"
}

The first thing you need when dealing with webhooks, is a place that can handle a POST command on the net. This was absolutely perfect with Flask as Django would be way heavier than we need to just accept some POST requests.

from flask import Flask, request, Response, jsonify 
import json 
import logging 
 
import matrix_bot 
 
app = Flask(__name__) 
flask_matrix_bot = matrix_bot.MatrixBot() 
most_recent_games = dict() 
logging.basicConfig(level=logging.DEBUG, format='%(levelname)s- %(asctime)s - %(message)s') 
 
try: 
    with open('most_recent_games.json', 'r') as file: 
        most_recent_games = json.load(file) 
        logging.debug("JSON file loaded.") 
except FileNotFoundError: 
    logging.warning("Prior JSON file not found. If this is your first run, this is OK.") 
 
 
def player_name_to_matrix_name(player_name: str) -> str: 
    if player_name == "One Oh Eight": 
        return "Dan" 
    elif player_name == "TheDJOtaku": 
        return "Eric" 
    elif player_name == "Wedge": 
        return "David" 
    else: 
        return player_name 
 
 
@app.route('/webhook', methods=['POST']) 
def respond(): 
    logging.debug(f'JSON from Play By Cloud: {request.json}') 
    game_name = request.json.get('value1') 
    player_name = player_name_to_matrix_name(request.json.get('value2')) 
    turn_number = request.json.get('value3') 
    if game_name in most_recent_games.keys(): 
        if most_recent_games[game_name]['player_name'] != player_name: 
            logging.debug("Game exists, but this is not a duplicate") 
            message = f"Hey, {player_name}, it's your turn in {game_name}. The game is on turn {turn_number}" 
            flask_matrix_bot.main(message) 
            most_recent_games[game_name] = {'player_name': player_name, 'turn_number': turn_number} 
        else: 
            logging.debug("Game exists and this is a duplicate entry.") 
    else: 
        most_recent_games[game_name] = {'player_name': player_name, 'turn_number': turn_number} 
        logging.debug("New game.") 
        message = f"Hey, {player_name}, it's your turn in {game_name}. The game is on turn {turn_number}" 
        flask_matrix_bot.main(message) 
    with open('most_recent_games.json', 'w') as file: 
        json.dump(most_recent_games, file) 
    return Response(status=200) 
 
 
@app.route('/pydt', methods=['POST']) 
def respond_pydt(): 
    logging.debug(f'JSON from PYDT: {request.json}') 
    game_name = request.json.get('gameName') 
    player_name = player_name_to_matrix_name(request.json.get('userName')) 
    turn_number = request.json.get('round') 
    civ_name = request.json.get('civName') 
    leader_name = request.json.get('leaderName') 
    message = f"Hey, {player_name}, {leader_name} is waiting for you to command {civ_name} in {game_name}. " \ 
              f"The game is on turn {turn_number}" 
    flask_matrix_bot.main(message) 
    most_recent_games[game_name] = {'player_name': player_name, 'turn_number': turn_number} 
    with open('most_recent_games.json', 'w') as file: 
        json.dump(most_recent_games, file) 
    return Response(status=200) 
 
 
@app.route('/recent_games', methods=['GET']) 
def return_recent_games(): 
    return jsonify(most_recent_games)

First, lines 12-17, I check for the most recent games that I’ve saved out to a JSON file. This allows for persistence if I have to stop the program or it crashes or whatever. Then, lines 20-28, I also created a function to convert from Steam screennames to Matrix names so that when the Matrix bot pushes the data, it’ll come out as a mention to the user and draw their attention to the turn they need to play. Here’s what it looks like:

Hey, Eric, Montezuma is waiting for you to command Aztec in Gathering Storm! 1. The game is on turn 59

Hey, Eric, Gilgamesh is waiting for you to command Sumeria in Mesas Play . The game is on turn 161

Hey, Eric, it's your turn in Eric and Dan Duel. The game is on turn 9

You can see in the first two I can make use of the extra data PYDT gives us. The last one is Play By Cloud, giving us less to work with.

I create two endpoints – one for Civilization VI (starting at line 31) and one for PYDT (line 55).  The Civilization VI endpoint (webhook) has deduplication code because if each person has it set to push out the JSON on all turns, it would end up repeating the alert.

I also added the recent_games endpoints so that I could create another matrix bot that would listen for commands and let users check up on their games. 

"""Provide ability to listen for commands from Matrix.""" 
 
import asyncio 
import json 
import logging 
from nio import AsyncClient 
import requests 
 
# testing 
# URL = "http://localhost:5000/recent_games" 
# production 
URL = "<YOUR SERVER URL>" 
 
logging.basicConfig(level=logging.INFO, format='%(levelname)s - %(asctime)s - %(message)s') 
 
 
class ListenerMatrixBot: 
    """A bot to send alerts about the game to Matrix""" 
    def __init__(self): 
        try: 
            with open('matrix.conf') as file: 
                self.config = json.load(file) 
                logging.debug("Listener Matrix Config loaded.") 
                file.close() 
        except FileNotFoundError: 
            logging.warning(f"Settings not found.") 
 
    async def login(self): 
        client = AsyncClient(self.config.get('server'), self.config.get('username')) 
        response = await client.login(password=self.config.get("password")) 
        logging.info(f"Listener Login response: {response}") 
        logging.debug(f"Listener Room would be: {self.config.get('room')}") 
        return client 
 
    @staticmethod 
    def get_current_games(): 
        """Get the list of games from the recent games endpoint. 
 
        :returns: A dictionary of the games, next player, and turn number. 
        """ 
        response = requests.get(URL) 
        return dict(response.json()) 
 
    def format_current_games(self): 
        """Format the list of current games for display in Matrix server.""" 
        return_text = "Here is a list of the games currently known about on the server:\n" 
        response_dictionary = self.get_current_games() 
        for key in response_dictionary: 
            game = key 
            player = response_dictionary[key].get('player_name') 
            turn_number = response_dictionary[key].get('turn_number') 
            return_text += f"{game} awaiting turn {turn_number} by {player}\n" 
            logging.debug(return_text) 
        return return_text 
 
    def format_blame_games(self, player_name: str) -> str: 
        number_of_games = 0 
        return_text = "" 
        response_dictionary = self.get_current_games() 
        for key in response_dictionary: 
            game = key 
            turn_number = response_dictionary[key].get('turn_number') 
            if response_dictionary[key].get('player_name') == player_name: 
                return_text += f"{game} awaiting turn {turn_number} by {player_name}\n" 
                number_of_games += 1 
        if number_of_games > 0: 
            return f"There are {number_of_games} games waiting for {player_name} to take their turn:\n" + return_text 
        else: 
            return f"There aren't any games waiting for {player_name}. Great job!" 
 
    async def main(self): 
        my_client = await self.login() 
        with open('next_batch', 'r') as next_batch_token: 
            my_client.next_batch = next_batch_token.read() 
        while True: 
            sync_response = await my_client.sync(30000) 
            with open('next_batch', 'w') as next_batch_token: 
                next_batch_token.write(sync_response.next_batch) 
            if len(sync_response.rooms.join) > 0: 
                joins = sync_response.rooms.join 
                for room_id in joins: 
                    for event in joins[room_id].timeline.events: 
                        if hasattr(event, 'body'): 
                            if event.body.startswith("!Civ_Bot current games"): 
                                data_to_send = self.format_current_games() 
                                logging.debug(data_to_send) 
                                content = {"body": data_to_send, "msgtype": "m.text"} 
                                await my_client.room_send(room_id, 'm.room.message', content) 
                            elif event.body.startswith("!Civ_Bot help"): 
                                data_to_send = ("""Current Commands: 
                            !Civ_Bot help - this message 
                            !Civ_Bot current games - the list of games Civ_Bot currently knows about. 
                            !Civ_Bot blame <Matrix Username> - list of games waiting on that person.""") 
                                content = {"body": data_to_send, "msgtype": "m.text"} 
                                await my_client.room_send(room_id, 'm.room.message', content) 
                            elif event.body.startswith("!Civ_Bot blame"): 
                                player = event.body.lstrip("!Civ_Bot blame ") 
                                data_to_send = self.format_blame_games(player) 
                                logging.debug(data_to_send) 
                                content = {"body": data_to_send, "msgtype": "m.text"} 
                                await my_client.room_send(room_id, 'm.room.message', content) 
 
 
my_matrix_bot = ListenerMatrixBot() 
asyncio.run(my_matrix_bot.main())
 

For the weekend or evening, I could get to the game soon after getting notified. But on weekdays, my brothers might play their turns while I’m at work and then by the time I get home (or even a few days later) I might forget whether there are games waiting for me. So I set up the listener to allow me to either ask it about all the games outstanding or just my own by using !Civ_Bot blame Eric.

Overall, I was pretty darned happy with how it came out for just a weekend’s worth of work.

Impractical Python Chapter Projects

I did a few more chapters of the Impractical Python book. Specifically we worked on Genetic Algorithms for breeding mice and cracking safes; Haiku in which we implemented syllable counting and Natural Language Processing with NLTK. You can see the code I wrote and what I learned in these chapters by going to my Github repo.

ELDonation Tracker

I refactored all the Python files into submodules to better separate what each file does. It is much cleaner now. Plus I finally released 6.0 – there will be a separate blog post covering that.

NASA Background Photo Downloader

Sometimes there’s more than one photo per day on the NASA feed so I changed the code to grab the last 3 images.

Scratch Jr

I also finished the Scratch Jr book with Stella. I enjoyed the book. It appears Goodreads is having some issues now, but I’ll try to remember to add a link to my review when I’m able to.

How Desktop Environment Tweaking Helps Me Be More Productive

A few months ago, someone asked about whether the rices*/modifications/tweaks people displayed on reddit.com/r/unixporn (where people show off their desktops, not human pornography) were actually useful. Someone commented they’d like to see a post on how someone uses their mods. So I decided to write this up.

*I know the term ricing could be considered racist or insensitive. In this context, it’s simply the term of art used on the subreddit.

To start off, I’m using KDE Plasma on Fedora. In the past I’ve been a huge fan of Fluxbox and XFCE. On my netbook I’m also using Qtile to great effect because the monitor is sub-SD resolution. I’ve been using KDE for something like 10 years, ever since around the 4.5 release. What I really like about KDE is the ability to use both Virtual Desktops and Activities. Think of activities as collections of virtual desktops. Or, if virtual desktops extend your desktop in 2 dimensions, activities push it out to the third dimension. What benefit do they give me? There are two main benefits: First of all, it allows me to keep my virtual desktops to a minimum so I don’t have to flick and flick to find where some program is. I have my video editing suite in the video editing activity. VERY easy to find. Second, with KDE apps (and limited success with non-KDE apps), activities can keep track of what you had open in each. So I can have some programs open to certain files whenever I open up the Programming activity rather than having to open it up each time.

I’m using Latte Dock in place of KDE’s default panel. It essentially works the same as the normal panel except I can have different launchers for different activities. I also added a Latte Dock panel at the top to provide an activity switcher .I find that generally faster to use than pulling up the native switcher. It also gives me an overview of what I’ve got open on each one.

So, I’ll take you activity by activity into how my setup helps me get more work done. One thing you’ll notice is that I try to use themed background images so that I immediately know what activity I’m in.

Audio Activity

Audio Activity (20210215)
Audio Activity (20210215)

The main thing I’ve done here is to add 2 Folder View widgets and 1 “now playing” widget. (I lost the now playing widget on an update and forgot to re-add it so you wont’ see it in the above image) The now playing widget is just for fun/looks. Most of the time I’m going to either use my multimedia keys on my keyboard or the now playing widget I put into my top Latte Dock. The folder view widgets facilitate my Audio workflow. I’m one of those folks who still believes in having your own music collection. Sometimes (although rarer than in the TV/movies world) there are rights issues that keep music off of Spotify (or other music streamers). Sometimes the band just hasn’t put it up or there are a few other reasons why the music has to be learned. Also, sometimes you just don’t have access to the Internet. So the lower folder view is where I put audio files that need some work. Maybe I’ve just recorded from a vinyl album or maybe I bought, ripped, or downloaded a new album that doesn’t quite have all the tags I want it to have. So I make sure everything is nice and fixed up with either Picard or (if the music isn’t in MusicBrainz) Kid3. The upper folder view allows me to quickly jump to an artist in fewer clicks than first launching my file viewer and then navigating to the artist.

Books Activity

Books Activity (20210215)
Books Activity (20210215)

Here I have 3 folder views. The top left is an Unimported folder for eBooks and magazines I haven’t imported into Calibre yet. It has folders for various magazines I’ve subscribed to or book series that I’ve supported on Kickstarter. This allows me to use Calibre’s “import from folder” setting that combines all the files in one folder into 1 Calibre entry. So I put the PDF, EPUB, and Mobi entries into the appropriate folder and then import. The bottom left folder is a folderview to my Downloads folder with a filter on it to only show book file types. I use this when I download books from Humble Bundle. I grab them all from Downloads and put them into a folder in the upper folderview. Then I import them as stated before. On the bottom right is my Dropbox ebooks folder. For some places that I buy my eBooks, I have to download them with a Windows app. So I download them and then pop them into this folder. From there I can follow the previous workflow to get the files into Calibre.

Comics Activity

Comics Activity (20210215)
Comics Activity (20210215)

Once again, my flow is around folder views as well as a launcher for two of the programs I use most often in this activity. I use Tellico to keep track of the comics I have, their ratings, URIs to find them on the system, etc .QComicbook is my comic reader of choice if I’m reading a CBZ/CBR. For PDFs, I just use Okular. I think the folders on view here are pretty self-explanatory. The revolve around the fact that, to remind myself of what I have yet to read, I do not move my comics into the Publisher-based folders until I’ve read them. Mostly I read Image and Dynamite published comics, so those are featured with their own folder views. There’s another for all the Humble Bundle comics I’ve bought over the years. I’ve still got a lot of those to read.

Comms Activity

Comms Activity (20210215)
Comms Activity (20210215)

I actually only use this for communications programs, so there isn’t really anything I changed with this activity. I did make use of Latte Dock’s ability to have different launchers per activity – this may result in me eventually getting rid of the launcher I have on the desktop of the Comics activity. This activity usually has Kontact (KDE’s version of MS Outlook) and Choqok (twitter/GNU Social/Mastodon client) on one desktop. The other usually runs Discord, Konversation (IRC), and Element. The fourth screen usually has a web browser.

Main Activity

Main activity (20210214)
Main activity (20210214)

I use this activity when I’m running programs that don’t fit into any of the other categories. Since I usually don’t have as many long-running apps on this desktop, this is the one where I have my system monitors. Yeah, back in the day I played with Conky and lots of other similar system monitors. But these are all about functionality for me. When I’m having issues with the system I take a look at these and try to figure out what’s going on. I’ve been able to pinpoint lots of issues where something had a memory leak and was eating all the RAM as well as when something was going wrong with my network. It’s not perfect since, if the system is that borked it won’t update them, but it’s helped me a lot. The weather widget is nice for a quick view vs a few clicks on my smartphone. The older one was a little better as it showed the forecast a little further out. But the weather isn’t that reliable around here, so I guess it doesn’t matter. The drawing tablet widget is something I’m using for the first time now. If you have a Wacom tablet (or compatible with the Linux Wacom software) you can select various profiles on there as well as its orientation – making it quite useful.

Photography Activity

Photography Activity (20210215)
Photography Activity (20210215)

This one is pretty self-explanatory – a few folder views to get me exactly to where I want to go when I’m loading photos to the computer.

Programming Activity

Programming Activity (20210215)
Programming Activity (20210215)

In the past I’ve had widgets here for selecting KDevleop or Konsole profiles, but I didn’t really find that all that useful. I’ve usually got all four screens full of full-screen programs, so I don’t have too much use for widgets. For example, when I’m coding in Python I usually have (from left to right) Firefox, Pycharm, Konsole, and GitQlient open – each fullscreen on a monitor. 

Video Editing

Video Editing activity (20210214)
Video Editing activity (20210214)

Once again, same theme as usual – Folder views that go to the folders I use often.

Video Games Activity

Video Games Activity (20210215)
Video Games Activity (20210215)

To be honest, I don’t use this activity too often. I’m usually gaming on my Windows computer. But sometimes I need to run some games or test something and don’t want it mucking up my work on the other screens, so I open them up in here.

Videos Activity

Videos Activity (20210215)
Videos Activity (20210215)

A folderview for an easy way to reach the NFS shares that hold the videos I’ve painstakingly ripped from DVDs and Blurays or recorded via MythTV. 

Virtual Machines Activity

Virtual Machines Activity (20210214)
Virtual Machines Activity (20210214)

This one usually has Virt-manager running as well as fullscreen views into the various VMs I’m running. They might be views into local VMs or remote VMs. If you use libvirt/KVM – I’d like to make a plug for remote viewer which is awesome as it lets you run multiple virtual monitors

Web Activity

Web activity (20210214)
Web activity (20210214)

Finally, there’s Web Activity. Since I usually like to run my browser on the fourth monitor and shared across all activities, you might wonder what I do in the web activity? This is for the KDE File Downloader – KGet – which is really nice at downloading if you feed it a text file with a list of URLs to download. Also KTorrent where I literally download my Linux ISOs. I try to be a good Linux user and always download via torrent and seed until the version is outdated. I usually get some pretty good ratios on my Fedora, CentOS, and Raspberry Pi torrents – 5 at a minimum and usually double-digits. Here I make use of a launcher widget to remind me of all the web browsers I have. Since I don’t use the equivalent of the bottom-left icon used in Windows and vanilla KDE to launch programs (I just use alt-F2 and type the name of the program), I often forget some of the lesser-used programs. I installed all these browsers last year as I started exploring what they had to offer. Currently I’m starting to get more and more in love with Vivaldi and its features. (It also launches a lot faster on my resource-constrained laptop) Qutebrowser (which has vim bindings built-in) also works very well on my netbook with Qtile because I’m able to do a lot without using the mouse. 

So, there you go. MOSTLY at this point in time my mods revolve around the folder view for greater productivity. I also use KDE’s activities to spread my programs around so it’s very easy to alt-tab between them and reduce clutter. 

One tiny hitch with the Fedora 33 upgrade

It messed with DNS resolution for my local network, at least temporarily. I couldn’t resolve any websites that needed to hit our local DNS server. I did some Googling and saw that the resolver tech was changed from Fedora 32 to Fedora 33. I change a setting for my NIC and then changed it back and either that fixed it or (some websites mentioned just needing to give it some time). Either way, that was it. Relatively smooth.

Upgrading Supermario to Fedora 33

While new versions of Fedora have been pretty darned stable for a few years now, I usually wait a while after a release to upgrade. This year waiting ended up turning into just leaving it alone. But with February half-way done, we’re actually starting to get kind of close to the Fedora 34 release date. So I figured President’s Day was as good a day as any to do the upgrade.

Years ago, I became interested in a music player called Tomahawk. The latest package I had was a Fedora 31 package. This was causing the upgrade to fail because it needed an older library to stick around. Since I haven’t used Tomahawk since a month or so after writing that article (about 5 years ago), I just did a dnf remove tomahawk. That also got rid of some dependencies that were probably just sticking around for that package.

The more complicated issue was summarized by dnf as: package python3-pytest-relaxed-1.1.5-10.fc33.noarch requires (python3.9dist(pytest) < 5 with python3.9dist(pytest) >= 3), but none of the providers can be installed. For that one I tried it with –allowerasing. That allowed the upgrade to go on.

After that it was 6GB of packages to update (thankfully I’m not on a metered connection) and then a reboot. If nothing goes awry, this’ll be the only post related to upgrading my main computer to Fedora 33. The only holdout now is my oldest’s laptop, but I think I’ll do that one today, too.

Vivaldi Part 4, Brave Part 2, Qutebrowser Part 1

This post continues a series on exploring new browsers:

Vivaldi vs Brave on Windows

Brave didn’t last very long for me on Windows. I just don’t do enough on there to make use of their ad blocking and ad replacing tech. On the other hand, I’ve been using more and more of Vivaldi’s features. I just started using their Web panels – this allows you to have a web page on the left that loads up in a small section – great for pages that you would like to reference here and there without cluttering up your tabs. I’m using it on my Windows computer to keep some Web panels with notes on what I’d like to do in some games – like Civ VI, Darkest Dungeon, and Cities Skylines.

Qutebrowser

Meanwhile, on Kuribo, one of my netbooks, I’ve moved to using Qutebrowser. This is the same netbook where I’m using Qtile as the Window Manager. Qtile is working very well for this since it maximizes all windows and allows me to be keyboard based. Qutebrowser (like QTile is also programmed in Python) is also keyboard-based with lots of vim keybindings. I’ve only just started using it, but with how annoying it it to use the mouse on this netbook, it’s great using a keyboard based web browser.

Five Iron Frenzy – Until This Shakes Apart

Over its long tenure as a band, Five Iron Frenzy has had some really silly songs. Songs like “Arnold, Willis, and Mr. Drummond”, “Oh, Canada”, “Blue Comb ‘78”, “The Untimely Death of Brad”, “Where is Micah?”, and many others. But they’ve also always been a really political band. On their first album, Upbeats and Beatdowns, they had the song “Anthem” which spoke about politicians wrapping themselves in themes of nationalism. “Milestone” also dealt with racism and prejudice. “Beautiful America” tackled both politics and another constant theme across FIF’s albums – rampant capitalism. Over the rest of the discography there was:

  • Banner Year – mistreatment of Native Americans
  • Most Likely to Succeed – doing anything to become rich
  • Get your Riot Gear – about police abuse
  • Giants – rampant capitalism
  • The Day We Killed – mistreatment of Native Americans
  • American Kryptonite – rampant capitalism
  • Zen and the Art of Xenophobia – racism, nativism
  • Someone Else’s Problem – looking the other way at how capitalism means exploitation
Five Iron Frenzy - Golf Courses of America
Five Iron Frenzy – Golf Courses of America

Until recently, I didn’t know this was a historical trend in Ska music. At the time I discovered Five Iron Frenzy, I didn’t listen to secular music. The Supertones and The Insyderz were more concerned with themes of Christianity. When I did start listening to all music, I didn’t see much political in any of the No Doubt songs that made it to the radio. It wasn’t until years later that I heard all of The Mighty Mighty Bosstones’ Let’s Face It album which has a song against racism and two songs against drug use. 

FIF Concert (Nov 2013)
FIF Concert (Nov 2013)

All of that preamble is to say that Until This Shakes Apart is a deeply political album. I’m not sure Reese, Dennis, and Scott could have written anything else in the shadow of the Trump presidency. Overall, the first impression I got from listening to the album was that it was definitely a darker album with lyrics that would sometimes make me a bit sad that we were still dealing with these issues in our country. As I continued to listen, I’ve definitely come away feeling that some of these songs will end up being in my top 10 Five Iron Frenzy songs. I was a Kickstarter backer on this album and so I’ve been listening to it for nearly a week now. Here are my thoughts and impressions on the individual tracks:

  1. In Through the Out Door – A song about xenophobia. Contains a great reference to Gil Scott Heron’s “The Revolution Will Not be Televised”. More towards the rock with horns  sound that Five Iron Frenzy (and many other 90s ska bands – like the Rx Bandits) has mostly moved towards.
  2. Lonesome for Her Heroes – A song about a lack of regard for the environment and rampant capitalism, including gentrification. After the previous song being such a strong rock with horns song – this one is a return to a classic ska sound. I don’t know enough about the history of ska to place its era, but it definitely has a different sound than the Third Wave Ska of the 90s. It seems to mix a bit with an older style.
  3. So We Sing – This was the song to advertise the Kickstarter. It’s a real banger that I’d love to hear live when we start being able to go to concerts again. Lyrically, it’s somewhat of a spiritual successor to “See the Flames Begin to Crawl”. Love the reference to Peter Pan/Captain Kirk at the end of the chorus. Back to rock with horns.
  4. Bullfight for an Empty Ring – another political one that tackles lots of issues, but mostly the hypocrisy of Christians who are aligned with the political right in America. Ska-punk with a bit more emphasis on the punk part. 
  5. Renegades – this time about the politics of gun control as well as once again excoriating Christians who support the party of guns all over the place. Once again a journey to a more traditional ska sound, but with some interesting effects on the track.
  6. Tyrannis – A song against the continued existence of those who build monuments to the losers of the American Civil War. Very strong, fast-paced rock with horns.
  7. Auld Lanxiety – A spiritual successor to songs like “At Least I’m Not like all those Other Old Guys” and “Battle Dancing Unicorns with Glitter”. It’s about getting older and nostalgia. Unlike those songs, the theme is a little less in your face. I really like this song a lot with its music falling halfway between ska and rock with horns. It’s got great backup vocals that work so well.
  8. Homelessly Devoted to You – the first purely fun song on the album. It reminds me a bit of “Vendetta!” from Reese’s side band, Roper. Another good mix of ska and pop music sensibilities. 
  9. One Heart Hypnosis – About being obsessed with social media and getting likes (hearts). Reminds me a bit of “Beautiful America” from Upbeats and Beatdowns. Once again contains a mix of ska and pop/rock music.
  10. While Supplies Last – This one has to have been written during the COVID lockdown as it mentions hoarding of Lysol and diapers. Another song about the hypocrisy of the Religious Right and the fact that they aren’t actually acting as Jesus would. Strongly ska – almost throwback to 1st or 2nd wave. (I don’t know enough to be able to nail it down – but there’s definitely a stronger reggae sound to it.) That said, it does go a bit more into hardcore territory near the end (A la “Fistful of Sand” in Out Newest Album Ever!)
  11. Wildcat – a song about blue collar workers. Definitely back to rock with horns.
  12. Like Something I Missed – I can’t tell just from the lyrics if this is meant to be a couple that’s gone beyond being able to come back together or are just at a very low point in their relationship, but I *love* the chorus with “I need a low dose of you believing in me/ I need a sheet cake made of victory”. It’s sung with such emotion and it’s definitely how I feel sometimes, whether that’s at work or with various relationships. Once again rock with horns. Musically it reminds me of what they were doing on The End is Near, particularly “It was Beautiful”. 
  13. Huerfano – A spiritual sequel to “Suckerpunch” from Our Newest Album Ever!. It’s about being bullied and the chorus is a call to come together with others and be hopeful. Sonically – rock with horns.

Listening to it again as I wrote this, I have to say that my favorite song is “So We Sing” followed by “Homelessly Devoted To You” and “Auld Lanxiety”. I like a lot of the other songs, like “Like Something I Missed”, “Bullfight for an Empty Ring” and “Lonesome for her Heroes”. But this is probably not an album I’d listen to a lot in order because it’s just so depressing to remember where we were at in 2020. The older I get (and I think Roper’s around 10 years older) – the more frustrated I get at how long it takes to move society in the more progressive direction. We’re still fighting forces that would take rights away from women or folks who don’t look like them. We’re still so far from finding a post-scarcity society like Star Trek. Almost everything I hate about social media has to do with putting short term profits over the health of the world. Shoot, even the police situation is still a mess.

So, it’s a good album. No, it’s a great album. If it’s not their best, it’s in the top three. I’m glad Reese turned these thoughts into music. Like the political songs he (and the others in FIF) wrote before, they’re important. And they may use the power of music to move folks to action. But some days I need the music to be an escape. So I’ll listen to my favorites and save the whole album listen for when I’ve got the stamina for it. May the next album find us all in a better place.

FIF
FIF

Programming in the first two weeks of 2021

It’s been a pretty busy 2 weeks. I’ve basically either been finishing up end of year blog posts or programming. Let’s jump in!

Extra Life Donation Tracker

I have the 5.3 release of my Extra Life Donation Tracker. I had a few minor refactoring goals for that release, but also a few user-facing enhancements. I added in the ability to grab the user’s avatar as well as their team’s avatar. They can now use that as an input in either XSplit or OBS. During these two weeks I also fixed a user-reported bug on crashes if a donor had emoji in their name. Oh emoji, you’re the bane of my programming existence!

On the more developer side, I decided to get rid of the devel branch. Others online had told me it was a bad idea to have 2 long-running branches. It’s been less of an issue since there really isn’t anyone else developing with me. But, it was really there as a stopgap before Github’s CI system came out. I started to realize there wasn’t really any point to it. When I would work on a new branch, I would run a bunch of Pytest against it and the CI system would create a Windows executable I could use for testing. So having a separate devel branch no longer made sense.

Impractical Python

I finished the English Civil War chapter and learned a bit more about encryption and Python. You can see my solutions and what I learned on my Github repo.

NASA Background downloader

I’m sure there are tons of scripts in every language to accomplish the same thing, but I customized mine to the way I work. Essentially, each day I go to NASA’s image of the day. I download the image and analyze whether it’s square, long, or tall. Based on that, I put it in the proper backgrounds directory. As you can see, I like to use it on my main desktop:

Supermario Main Activity_20201025
Supermario Main Activity_20201025

I’m not quite ready to share the code yet as I’m still working out some of the kinks, but I hope it will soon help me to clear up some of the clutter in my news reader.

RTS Unity Game

Progress continues on the GameDev.TV online multiplayer RTS class I’m taking. Here’s a video with my latest progress:

As I said in my end of year programming blog post, I’ve learned a lot, but when it comes time to create my own online multiplayer game, I’m definitely going to have to come back and revisit this class. Luckily, a lot of the concepts are very repetitious. That helps both with learning and also with figuring out what to do. I’ve also learned how to do IPC in C# (or at least one way of doing it).

Scratch Jr with Stella

I really prefer vanilla Scratch to Scratch Jr. I really hate working on tablets. That was solidified today when I was trying to create a new character in Scratch Jr and the cursor kept being offset from my finger. That said, the book we’re using, The Official Scratch Jr. Book, is really well written. Next time Stella and I will be making actual games. That should be a lot of fun.

Software I used for Programming in 2020

I last wrote about the software I’m using while programming back in March.  I think at the time I was thinking of writing quarterly updates, but my preferences didn’t change with that much regularity. I decided to make it one of my annual posts instead. So here is the software I used in 2020 to program.

Python Projects

PyCharm

For my Python projects I transitioned fully to PyCharm Community Edition. I documented my reasons for moving towards Pycharm in this post with a followup here. As I was writing this, I learned of a Real Python guide to Pycharm that taught me a few things I didn’t know about how to make better use of PyCharm. PyCharm has made Python programming a real joy. For any libraries I have imported (or standard libraries), it provides excellent code completion as well as context for function or method arguments that saves me time vs looking it up in documentation. The git integration is also great and I’ve recently started exploring usage of the lower git window which may make GitQlient obsolete for my Python projects. I haven’t made the best use of the debugger yet, but I’m slowly learning how to take advantage of it in my larger projects. If you’re a Python programmer I can’t imagine a better IDE. I did have access to Pycharm Professional for a while in 2020, but I wasn’t doing any Flask or Django work, so I didn’t really notice anything useful over the community edition.

Pycharm

Mu

I use Mu when I’m working with Circuit Python for my Adafruit boards. Mu would probably be really awesome if I hadn’t started using Pycharm. It’s about equivalent to Kate as I’m using it in Fedora 32 (more on that in another section below). It will provide word completion for words that I’ve already typed, but has no understanding of the libraries installed on the board. Also, (and I have no idea if there’s a reason it’s implemented this way) I’d love it if the programming was a little more Arduino-like. That is so say, programming on my computer and then transferring it to the device whenever I asked it to. Instead, the default is to edit the code on the device and reload the device when I hit save. This means to save my files and put them under git control, I have to keep remembering to copy the file off the circuit board and onto my system. 

This may seem that I’m really hating on Mu. Don’t view it that way. I’m merely wishing there was something with the power of Pycharm that could do what Mu does. Because Mu does provide some valuable services when programming in Circuit Python. It provides easy access to the board’s REPL without having to do any work to figure out how to connect to the REPL in the Linux console. It also provides the ability to graph outputs from within Mu. I used it quite a bit this year on my Circuit Python projects and expect to use it quite a bit in the coming year.

mu editor
mu editor

Unity/C#

Rider

If you’ve read through this blog post in order, you know that I really love using PyCharm. So when I got back into C# programming with Unity this year, I figured I’d give Rider a shot. I blogged about my experience setting up Rider and Unity on Fedora (using flatpak). I didn’t end up getting much use out of it because Unity decided not to open my project once I added in the inputs plugin. In the end it doesn’t matter because, from what I can tell, Rider does not have a community edition. That is fine. I’m sure *most* folks programming on Unity are either real studios like Ghost Town Games (makers of Overcooked) or bedroom coders, since that’s a thing again thanks to the indie scene. JetBrains deserves to get money for their product. Since I’m not developing for money – just for fun – it doesn’t make sense to spend professional IDE money, especially when there are free IDEs that work just fine with Unity. IDEs like Microsoft Visual Studio.

JetBrains Rider with my Block Destroyer program open
JetBrains Rider with my Block Destroyer program open

MS Visual Studio

I continued to use MS Visual Studio on Windows when doing Unity C# programming. In the latest class I’m taking the professor is using Visual Studio Code, but the shortcuts seem to be the same, so I didn’t see a need to install VSC when plain old Visual Studio was working just fine. I’m just barely taking advantage of any of the Visual Studio features – definitely not using any of their git features. But it works perfectly fine. If I were doing my Unity programming on Linux, I’d probably use VSC since it’s cross-platform.

Visual Studio
Visual Studio

Arduino

Arduino “classic”

I didn’t do too much Arduino programming in 2020, but when I did – the classic Arduino code editor was just fine.

Arduino classic
Arduino classic

Arduino Pro

I really, really want to use Arduino Pro. It has a much nicer looking interface and is version control aware. That said, it’s still in alpha or beta and never quite worked for me in 2020. I always ended up going back to the classic editor.

Arduino Pro IDE
Arduino Pro IDE

Language-Independent IDEs

Kate

In 2020 I mostly used Kate for learning Ruby. It’s also a lot faster and less complicated for my short Python programs than Pycharm. In fact, for short scripts, Pycharm’s project-focused workflow actually gets in the way. So I have used it a bit for short Python scripts as well as for the practice problems in various Python books. It’s always great for a shell script, too. However, I usually end up writing those in a vi clone. They almost never seem complicated enough to spin up a GUI program for.

Last March I mentioned that the Kate developers were working on making Kate more of a Visual Studio Code competitor. They were working on implementing a good LSP Client (if I understand correctly, this is what allows Pycharm to make suggestions based on the packages I’ve imported) as well as better git integration. As I write this, I still haven’t upgraded my main desktop to Fedora 33 and the LSP software needed to make this work with Kate and Python hasn’t been ported to Fedora 32. So I can’t speak to how well this works. I suspect it could only make things even nicer when working with these shorter Python scripts. As for other languages I’m thinking of learning, like Go and Rust, as far as I know they aren’t supported especially well in KDevelop. So if Kate ends up with better LSP tech, I may end up using it for those languages.

Kate
Kate

Vim

In 2020 I went all in on my conversion to becoming a vim native. I haven’t used Emacs in ages and vi or vim was always conveniently there on any server I sshed into. I started reading the O’Reilly Vi/Vim book that I got in a Humble Bundle so that I could get a little more proficient at the command line. I also set up powerline so that it could be a little more immediately clear to me which mode I was in.

vim
vim

Neovim

When I was doing a lot of research into Vim, I discovered Neovim, which was developing at a faster pace (and more openly) than Vim. So I installed it to check it out. I should probably alias vim to nvim because I keep forgetting to use Neovim. I should also probably install a syntax highlighter like Semshi and maybe an LSP plugin. Right now, for *my* use case, I don’t really get any benefits over vanilla vim.

Neo Vim
Neo Vim

Chrome for MS Make Code

I’m including this only for completionist reasons. When MS Make Code is done in the browser and works best with Chrome (or a Chromium-based browser). So I used it when working on MS Make Code projects with the kids.

MS Makecode with the Sibling Chooser Code
MS Makecode with the Sibling Chooser Code

Git

gh CLI 

I touched this once or twice in 2020. I’m sorry to say I haven’t quite figured out what I’d want to do with github in the CLI that I wouldn’t want to go to the website for. If anyone comments with some use cases, things may change in 2021.

github cli interface showing open issues in ELDonationTracker
github cli interface showing open issues in ELDonationTracker

GitQlient

GitQlient continued to be useful to me for visualizing what’s going on with my most complex projects. Those have many branches, tags, etc. That said, at the moment, my most complex projects on Linux are Python projects. So I may start using Pycharm’s git features a lot more and GitQlient may fall to the wayside for a while.

Git Kraken

On Windows I have fully moved over to Git Kraken for my git needs. There is really only one thing that’s a pain compared to SourceTree – starting up my repo. Unity doesn’t want to go into a folder that already has files. Git Kraken seems to have similar issues when I try to create a repo into a Unity folder. Outside of that, everything works great. 

GitKraken
GitKraken

Gitea

I continued to use Gitea to host code locally when I wanted to be able have a Github-like interface, but didn’t want the code to be public. For now, I continue not to see a need or reason to self-host a public Gitea instance instead of just using Github. Any contributors will already have a Github account and it’s just simpler this way. That said, Gitea continues to improve and add great features.

gitea
gitea

Continuous Integration/Continuous Deployment

Drone

As I did last year, I am still using Drone for CI/CD of my private code. It allows me to do automated checks with a clean environment upon check-in of my code. And for one bit of code, allows me to publish to PyPi. 

Drone-CI
Drone CI

Github Actions

I make heavy use of Github Actions on my big, public projects. It allows me to not only run unit tests, lint, and code coverage, but also to create binaries for Windows and push my code to PyPi. I don’t have any compiled code projects on Github yet, except for Unity. Apparently this exists. I think that would be interesting for cross-compiling for various build targets. I think it’d be interesting to see how well Github actions would work with Rust or Go. 

2020 Video Games and 2020 Game of the Year

Because the pandemic left me at home for a couple months, this year I played about double the amount of games from my previous record. You can watch the video below or read the text below that to find out what I thought of the games I played this year and which game I named as my 2020 Game of the Year.

Gwent (73 hours 24 minutes): Other than playing the beta a few years ago, the last time I played a CCG was Magic the Gathering back in the mid-1990s. I had no idea I would end up so addicted to this game for the first half of 2020. Eventually what took me away from the game is the fact that to maximize your experience with the game, you have to play every day. And I just have so many other games I want to play, books I want to read, the kids and wife to hang out with. I couldn’t give that much to a game. I do still have it on my rotation, so I get to it now and again. When I play, I find it quite fun, so I think Gwent will be with me for a while.

Darkest Dungeon (36 hours 20 minutes): I continued to have faith in Rogue-alikes and Rogue-lites to provide lots of entertainment for me. So I decided to grab Darkest Dungeon during a GOG sale. Darkest Dungeon is one of the most punishing in the rogue* bunch of games I play. FTL is just as hard, but Darkest Dungeon has the permadeath of customized and leveled up characters as in X-Com, making the deaths sting a little extra hard. Of course, the harder the game, the more rewarding when you succeed at a tough dungeon or boss.

Spelunky 2 (35 hours 15 minutes): The original Spelunky is one of those games that slowly grew on me over its existence. When Dan first introduced me to it, I mostly just found it chaotic and not much fun. But, by the time Spelunky 2 was announced, I was in quite a bit of anticipation for the release. Once it finally came out, it was a blast to learn the new mechanics and to play with the kids, who’d been honing their platforming skills on the original for a few months at that point. It’s interesting that lots of people have complained that Spelunky 2 is too hard when I’ve been able to consistently make it out of the caves (and even to Olmec) while I rarely made it past the grass levels in the original Spelunky.

Stardew Valley (28 hours 12 minutes): This year I continued working on finishing the community center. ConcernedApe also released an update that added fish ponds, giving me something else to work on while waiting for the fall to catch my last fish. Then, during the quarantine the kids (and eventually wife) started playing Animal Crossing. My eldest’s favorite thing to do was to beautify the island and that made me inspired to make my farm look a little nicer. So that became my new goal while waiting to finish the game. 

Overcooked 2 (26 hours 30 minutes): This was one of those Humble Bundles that turned out to be a huge success. There are many times that I think a game in Humble Bundle will appeal to the kids, but it ends up flopping. This one, however, was a constant request from the kids until we finished the main game. They still ask to play some of the expansion packs now and again, but those can be pretty tough. The kids do awesomely for being 8, 4, and 4, but there’s only so much we can do. For me, most of the time it’s a huge blast unless one or more of the kids decide to grief the rest of us. Then it becomes intolerable.

The Baconing (26 hours 13 minutes): Somehow, most likely through Humble Bundle, I ended up with the third game in a trilogy in my Steam library. After all this time accumulating games, I decided I would need to be disciplined about playing new games the way I was with my reading or I’d never play any of these games. So I started going through Steam alphabetically and ended up here. I must say, it was a great game to come across early in this experiment. It’s a combination of a point and click adventure game and an action RPG with the humor of a Monkey Island game. 

Civilization VI (23 hours 28 minutes): As usual, I played a lot of multiplayer Civ VI with Dan and Dave. There’s always something that draws me back into single player Civ VI. I’ve always loved it since the first Civ, but with the vast array of games I have thanks to Humble Bundles (and my kids now being old enough to ask me to play with them), I often forget about Civ. This year, with the new expansion pack coming out, I decided to try and win as Catherine the Great. After looking at her bonuses, I decided that I was going to try to win religiously or by tourism. Both are, in my opinion, among the harder win conditions. If nothing else, they tend to be later stage wins and you can end up getting beaten by someone who gets to a science victory or diplomatic victory first. I actually came close a few times, but Aminatore was my constant foe – pushing everyone around to me to Judaism and costing me victory that I might have had with just a few more turns. (Also talk about Cleopatra game)

Sonic Racing (17 hours 14 minutes): The majority of the time I’ve played Sonic & Sega All-Stars Racing with the kid occurred in 2020. For a chunk of time, it was their favorite thing to do every single day. We unlocked all of the characters and, eventually, all the tracks and music. We even moved on to the battle modes. While I think that Mario Kart tends to have better power-ups and a more chaotic and fun Grand Prix mode, I haven’t really enjoyed battle mode since the Nintendo 64. I think Sonic & Sega All-Stars racing has a more dynamic set of battle modes that made for more varied gameplay.

Super Mario 3D World (15 hours 58 minutes): I was looking for a Mario game we could all play and which I hadn’t already played, so I ended up playing Super Mario 3D World with the kids. I think this game is the perfect synthesis of the 2D games like New Super Mario Bros and the 3D games in the vein of Super Mario 64 and Mairo Sunshine. The 3D games tend to have an open area and almost infinite possibilities for traversal. This can be freeing, but it can also make it a lot harder to know exactly what to do. SM3DW, on the other hand, retains the general left-to-right progress of the 2D Mario games while just having a sections where the players go into or out of the screen. I think it provides a much clearer path for more casual gamers. I think I also prefer the golden tanuki to other Mario games where they just do the level for you if you keep failing.

Worms: Reloaded (14 hours 45 minutes): I used this game to introduce the kids to the Worms franchise and it led to quite a number of chaotic sessions. This game and the others Worms games we played in 2020 function as a great example of how the twins were better able to strategize as they went from 4 to 5 years old and more capable of understanding the consequences of their actions. At the same time, there are still moments when even Scarlett doesn’t quite look forward enough.

Cities: Skylines (14 hours 19 minutes): Before I say anything else, I want to point out just how incredibly beautiful this game is. Of course, living through the computer games’ young years to now, there’s been a constant improvement where each game has looked better than the last. I remember thinking that Sim City 4 looked “so real”. But this game, when you zoom all the way in, just looks like a real, working city.  So, getting to this year’s game – it’s no surprise to me that the same publisher and developer who make Cities in Motion would make a city sim with more realistic transportation lines and a seemingly more realistic model for citizen flow throughout the city. Coupled with some expansion packs (DLC in modern parlance) I got as part of a Humble Bundle, this game truly allows you to make cities that are realistic on the level I *wished* Sim City 4 and the Travel Expansion pack had done (without needing fan mods). If there’s one thing I still am not truly taking advantage of in Cities: Skylines, it’s the ability to make more realistic or creative cities. Sim City 1 trained me to think of city blocks and my lamentations of real life cities that don’t have perpendicular blocks ( a la NYC or many downtown areas) have given me a mental block to work through. By contrast, this city looks both more realistic to the real world AND fantastical and beautiful. This year, in addition to making use of the new DLC, Scarlett also got very involved and became my unofficial Jr. City planner.

Worms WMD (10 hours 10 minutes): In my mind, this is the epitome of what a 2D worms game should be. The developers have created a great item set as well as the ability to craft more weapons. The random assortment of vehicles and guns throughout the levels also add a high level of chaos. Many of the other 2D worms games are the same game with a new coat of paint, but this one really elevates the gameplay. 

Spelunky (9 hours 10 minutes): This continues to be the Rogue-lite that teases me the most. I almost always seem just about to get to the last level, but since I’ve been playing with only one life for the past 3 levels, it’s only a matter of time before a slip-up kills me. Overall the kids are getting better and are more helpful to me as long as they’re not trying to use their ghost status to kill the shopkeeper.

The Witcher 2 (8 hours 33 minutes): Early in COVID I decided I was going to make use of extra time to allow for longer sessions in The Witcher 2. Oftentimes, like other RPGs, it isn’t easy to just save whenever you want. If you’re in the middle of a key battle or some other sequences, the game may not allow for interruption. I did alright for a while, but then the kids used up all my game time with Spelunky 2, Super Mario 3D World, Worms, and asking to watch me play Darkest Dungeon.

Mario Kart 8 (5 hours 10 minutes): I have a pretty long history with the Mario Kart series. My brother and I had the original on Super Nintendo and I’ve had all the games since (at least on the non-handheld consoles). It was even the reason the wife and I bought a Gamecube when we were dating in college. So eventually I decided to get Mario Kart 8 for the Wii U to play with the kids. It turned out to be a huge blast. We went through every level to unlock everything. And now that the twins were between 4 and 5 years old they were actually able to stay on the track. Not only that, they were also able to get into 4th and 5th place. More recently on the Switch they’ve even been able to get 1st-3rd place.

Vertical Drop Heroes HD (5 hours 38 minutes): While I still enjoy playing this game, most of my game time this year came from the twins really wanting me to play with them. They love playing it on their own and they like that they can get further when I play with them. I’m quite impressed that at their age/gameplay level they are starting to make meaningful contributions when they play with me. 

Scribblenauts Unlimited (3 hours 45 minutes): I remember hearing about this game (well, the original game) back when I still used to listen to the Giant Bombcast. I always thought the idea was pretty neat, and having done a fair bit of programming (and even video game programming), I can truly appreciate how miraculous this game is and how much code must have gone into the parser. The kids enjoyed it a lot and I expect them to perhaps request it again once they see the wrap-up video.

Worms: Forts Under Siege (2 hours 54 minutes): This 3D worms game was certainly unique – especially with its focus on building up a base. However, while 2D worms is incredibly intuitive (like its predecessors/early siblings Scorched Earth and Gorilla Game), the 3D game makes it a lot harder to aim, to know what to do, and to  hit anyone. In fact, with the world so large compared to the 2D games we mostly ended up staying at our bases until the timer ran out and started hitting us with various random effects.

Rocket League (2 hours 17 minutes): Rocket League was one of the first video games the twins ever played – somewhere around 3 years old. Mostly they just enjoyed making the cars drive around. Now that they were good enough to play Mario Kart, I figured they could handle some Rocket League. Overall, it was a fun time, which everyone enjoyed. That said, whoever is on my team has a major advantage (not that I’m any good at Rocket League, but I’m way better than any of the kids), so eventually people start complaining about not being able to win.

TF2 (2 hours 13 minutes): The biggest thing that keeps me from playing more TF2 is that most rounds take quite a lot of time so I need to have blocked out at least an hour or so if I want to play. Compare that to Spelunky where, if I’m having a GOOD run, it takes me maybe 10-15 minutes.

Stellaris (2 hours 13 minutes): Due to an upgrade in Stellaris, my previous save was incompatible and I had to start a new empire. This is probably a good thing as it had been a long time since I last played Stellaris and probably wouldn’t remember what had been going on. I’d like to think that if I’d been playing a little more consistently throughout that there would have been an opportunity to upgrade my save file. This game continues to be complex on a level that makes Civilization seem like a kid’s game. Stellaris is a game I think I would probably dive deeply into if it was the only game I was playing. 

Super Smash Bros. Ultimate (2 hours): Sam loved playing Smash for the Wii so we got him Smash on the Switch. I played enough to unlock a few characters and then mostly played with the kids whenever they’ve asked me to join them.

Mario Kart 8 Deluxe (2 hours): As I mentioned above, Mario Kart is a series that my wife and I enjoy playing against each other. So we’ve played a few rounds on the Switch. The difference in playing with her – we can trash talk without hurting each others’ feelings. The kids aren’t quite ready for that yet.

Beckett (1 hour 50 minutes): Another Humble Bundle game; another game I got to alphabetically. A detective story that takes place in what seems to be a British dystopia full of visual metaphor. The game is a very odd duck. Part of me appreciates the artistry that went into it as a video game art piece. And it definitely seems to be Saying. Something. I’m happy that the internet and marketplaces like Steam and GOG allow this stuff to exist. That said, I’ve been mostly underwhelmed by the game. I’d hoped to finish it in 2020, but I’ve still got a hopefully small chunk left.

FTL (1 hour 45 minutes): I think, of all the Rogue-lites and Rogue-alikes I play, I feel the pain of defeat hardest in FTL when I seem to have accrued a nice, large crew and a decent set of offensive and defensive hardware for my ship. I think maybe it’s because unlike, say, Spelunky, it’s very unlikely for me to die early in the game by mistake. I always end up at least a couple star systems in before my mistake catches up to me – whether that’s not enough fuel or not enough bullets or letting too many guys board. 

Worms Clan Wars (1 hour 40 minutes): A pretty decent entry in the Worms franchise, it’d probably be my favorite if I hadn’t played Worms WMD.

Overcooked (1 hour 35 minutes): I got this game when it was on sale because we’d had so much fun with Overcooked 2. It really puts into stark relief the upgrades, gameplay changes, and visual changes they made between the two entries. We haven’t played it nearly as much as Overcooked 2. In fact, we still haven’t finished story mode.

Road Not Traveled (1 hour 30 minutes): Unlike many of the other Rogue-a-likes and Rogue-lites that I play, I think my enjoyment of this one really suffered from a large gap since the last time I played. I think it may be because this one is a little more story-based than others. Or it may be because the gameplay is a little more complex than Spelunky or Vertical Drop Heroes HD, but I didn’t quite have the pleasure playing it that I expected I would when I last left off after my second play session. 

Super Mario Strikers (1 hour 3 minutes): I decided to revisit this game with the kids to introduce them to the idea of sports video games. I think it was a success, although I hadn’t played the game in literally over a decade, so it took me a while to remember the controls so that I could explain it to the kids. Maybe in 2021 I’ll introduce them to the Mario baseball game.

Sonic Generations (38 minutes): When this game first came out, I’d wanted it to relive some of my early Sega Genesis nostalgia. I wasn’t really wild about the 3D Sonic games as those came out for systems I never had, but it still looked pretty awesome. But then there was a Humble Bundle that included it. I think it’s the same one where I got Sonic Racing. I’ve done a heckuva lot more Sonic Racing with the kids and only played Sonic Generations once. I will probably get back to it … someday.

Rogue Legacy (37 minutes): Continuing the Rogue-lite/Rogue-like trend of the past few years, I continue to enjoy playing this game. I especially love the humor involved. I’ve reached the point where I’ve started to gain power ups and familiarity with the game that led me to get further into the castle in 2020 than in prior years. 

Yooka-Laylee (30 minutes): I was a huge fan of Donkey Kong Country and I believe a good chunk of former Rare programmers made Yooka-Laylee. I wasn’t a fan of Banjo-Kazooie, or really most of the 3D games that came out in the wake of Mario 64, but I wanted to see if this game would appeal to the kids. The sequel certainly seems more of a descendent of Donkey Kong Country. Instead what I got was a game that was pretty neat and had lots of jokes that went over the kids’ heads. I look forward to putting this on my rotation in the future. 

Grim Fandango (17 minutes): Scarlett requested for me to return to the land of the dead for this game. Of course, I had to go to a walkthrough because this is an Old School point and click adventure game where the solution is often incredibly unintuitive. I do want to keep going, as the characters are pretty neat and the story is pretty funny. But we’ll have to see when I put this back into my rotation. 

Battlepaths (6 minutes): I got this game as part of a Humble Bundle. I started playing during this year’s COVID time at home as I went through my Steam library in alphabetical order. I did not like this game at all. Nothing about it appealed to me and I haven’t played it since the few minutes I played to try it out.

Total: 370 Hours 50 minutes

2020 Game of the Year

Even though Spelunky 2 was my third-most played game in 2020, it was the one that had the most replayability and the most fun. Not only was it a ton of fun to play alone, but it was also a blast to play with the kids. Towards the end of the year, the online multiplayer was released and I got to have a fun, if somewhat frustrating for the lack of communication, session with Dan. It took all the best of Spelunky and amped it up and I can see myself continuing to play it for many, many years to come.

2020 Runner Up

Darkest Dungon almost made my Game of the Year for 2020. I really enjoyed the battles, the character set, and the challenge of it all. Yet, just like X-COM, it really wore me down on when I could spent over an hour getting through a dungeon to lose everyone at the last minute. It did (as most challenging games, puzzles, etc) mean that when I won, it felt awesome. But near the end of 2020 I moved it down to my secondary rotation of games, meaning it’ll come up less often. I still enjoy it, but it just didn’t have what it took to unseat Spelunky 2.

2020 Surprise Loss

I went into 2020 so hyped for Gwent as you either read or saw above. But, in a different way than Darkest Dungeon, it ended up wearing me down. I just couldn’t make my entire gaming life about Gwent and that meant I would have trouble rising above my current status or even earning all the trinkets and in-game money that I wanted to earn. I said above that I’d return to the game and I think it’s possible I will. We’ll have to see what happens.