Fair Trade Magic

Craig Maloney - Mon, 11/06/2017 - 16:36

Just realized I've been bamboozled into thinking that Fair Trade is somehow a magic weapon against taking advantage of people.

So I looked up whether or not some of the Hawaiian coffee I like is fair-trade certified.

And then it hit me. It doesn't need to be Fair Trade certified. It's in the USA. Fair Trade doesn't mean anything in this context.

Sometimes we need to check our brand-loyalties, even if they're brands we like.

Categories: LugNut Blogs

Halloween Demo

Craig Maloney - Tue, 10/31/2017 - 12:03

I made a quick Halloween demo on the TIC-80 computer. I started development on my Android phone and then moved it to the computer.

You can view it here: Halloween Pumpkin Demo (alternate link)

Hope you enjoy!

Categories: LugNut Blogs

Social Media Dieting

Craig Maloney - Thu, 10/12/2017 - 17:01

I'm finding myself in more of a spiral about social media these days. I'm finding that I'm getting more and more wrapped around the spokes of social media and I need to cut back a bit so I can focus more on the things that are important.

I'm going to list the networks that I'm currently on and what I'm hoping to do in order to unwind myself:

  • Twitter: I feel like Twitter really doesn't care what sort of shit-show they have over there as long as it makes money. I'm also seeing that Twitter is making me go to the site for notifications that used to be emailed. (Yes, you can get a digest of this). So I'm looking to limit the number of times I'm on Twitter to perhaps once or twice a day (instead of spending more time than I care to on Twitter).
  • Mastodon: Most of my engagement is on Mastodon, but I'm also finding that I'm spending a lot of time in there. So I'm going to work on cutting back a bit. I'm looking into using RSS more for folks that I don't want to miss posts (until Mastodon gets lists implemented). Mastodon feels a lot more organic for me and I really enjoy using it, but I need to spend my time doing other things.
  • Identi.ca: I don't think I engage at all on identi.ca. Maybe once a month at best?
  • Google Plus: Sigh. I think I'm one of the last holdouts on Google Plus in my circle of friends (save for a few folks). I still engage there but not nearly as much as I used to. Checking in once or twice a day is not a problem like it used to be.
  • IRC: IRC is still my social network for real-time conversations. But I should also allow myself more downtime between check-ins.

So now that we know what I've been doing let's see how I'll try to proceed:

  • Twitter: Check once or twice a day. Use email for notifications. Follow people, not things. Use text-based clients and lists in order to see what folks are up to. Reply to posts only and use scripts like feed2tweet to post new content.
  • Mastodon: Check in less times per day. Use text-based clients like tootstream to check in. Use feed2toot to post new content. Use RSS in lieu of lists for following some folks that I want to know what they're posting at all times.
  • Identi.ca: Keep using spigot for posting new content.
  • Google Plus: Check in once or twice a day. Keep doing what I'm doing now.
  • IRC: Disconnect more times throughout the day.

I think this is reasonable. What do you think?

Categories: LugNut Blogs

When the public domain works: Naxos Historic Recordings

Craig Maloney - Fri, 09/29/2017 - 10:36

I have an unreasonable affection for Naxos recordings.

One of the series they have is a historical collection. They take 78RPM records that have fallen into the public domain (in the UK, where they're based) and remaster them on CD. They're doing the same thing that the Internet Archive does with their 78 RPM collection.

Unfortunately there are a few kinks with this. The biggest is that these recordings are still under some form of nebulous copyright in the USA, so they are harder to find over here (though not impossible). But Naxos won't sell them to you in the USA.

The other is that they put their standard "All Rights Reserved" on the recording. I find that disingenuous.

What's interesting too is seeing the labels that recorded these recordings do the same thing. It's interesting to see how Naxos' engineers do things differently from RCA's engineers. Same 78RPM recording but slightly different results.

But this is one instance where I find the public domain is working the way it was intended. And I applaud efforts like the Internet Archive 78RPM project for compiling recordings that have long since been out of print or are in versions that are different from the ones we have today.

Categories: LugNut Blogs

Tech Interviews and Hazing: What's the difference?

Craig Maloney - Mon, 09/25/2017 - 13:57

While discussing technical interviews with folks on different social networks I've come to the realization that tech interviews are a lot like my experience with pledging to a fraternity and it's hazing rituals.

While I was at college my friends decided to pledge to a fraternity. Being a smaller school it had its own fraternities so the college had control over all of the fraternities. So pledging to a fraternity at this college wasn't going to involve anything really scary or life-threatening (as some horror-stories of pledging to other fraternities have uncovered). And so I pledged to one of the on-campus fraternities and went through most of the rituals involved. It wasn't too stressful, but as the week of pledging wore on I was looking forward to it being done. I was also taking Calculus II and some other difficult courses and the split attention was starting to get to me.

Then pledge night happened.

Pledge night in this case involved a few rituals and what-not that I won't get into, save for one that ended my pledging to this fraternity.

Picture if you will a line-up of pledges who are in somewhat uncomfortable seating arrangements. They are told to sit stony-faced under penalty of something bad happening to them. All of the current fraternity brothers sit watching the pledges for the slightest infraction, where they can meter out the punishment as swiftly as the infraction took place. No-one is spared, and there is little hope of clemency.

With the pledges all sitting stony-faced and awaiting their fate they proceed with the ordeal.

They proceed to tell jokes.

Now, on the surface this seems somewhat surreal. Here are pledges charged with not showing any emotion being told jokes. On the surface this is not that big of a deal. Why would this be the incident that got me to quit pledging to this fraternity?

If you know me you'll likely know that I have a horrible time hiding emotions with my face. Worse, I have a very long and expressive face so even the slightest twitch shows up rather quickly. Add to that many different folks who are looking for that specific infraction of emotion and upturned lips and you have my downfall.

The sentence? Push ups.

Another thing I should point out is I'm not terribly physical. Sure, I played drums a lot in college but that sort of endurance and exercise is better for the forearms and wrists than it is for the upper-body strength. Add to that my seeming inability to ever do a push-up correctly (much to the dismay and delight of most of my classmates) and you have a task for which I am doomed to fail.

And fail I did. Repeatedly. Often.

One of the underlying pieces of this ordeal was that we were supposed to rely on the rest of the fraternity to pull each other up. We're brothers. We help each other.

I'm an only child. I've never had siblings. The only folks I've had are parents, cousins, aunts and uncles, and grandparents. So I've never had to steel myself for sibling rivalry, or had to ask a sibling for help. I've always had to either rely on myself or ask folks who are in positions of authority to help me. Sure, I get along with others, but when tasked with something that is personally uncomfortable I tend to want to solve it by myself. I got myself into this mess, I'll get myself out of it.

Which is the sort of strategy that is incompatible with a situation where your body is untrained and incapable of handling the task at hand, especially under pressure.

I'm sure it also goes without saying that I wasn't the popular kid at school. So the sorts of mocking and jeering that went on was not fun; it tore into my soul.

This was not a place where I could trust people anymore; this was the playground and every recess. This was the kids at gym wondering why I was struggling. This was the "I tried" and "most improved" trophy at school. This was another instance of everyone seeming to have the advantage and me not measuring up over something silly.

The next day I quit my pledge to the fraternity.

I made up some lame excuse about how it was getting in the way, but later on I also dropped out of Calculus II.

I was still friends with the folks that I knew at the fraternity, but there was this unspoken gap between us. They were able to make it through the ordeal and I couldn't. I had fraternity brothers come up to me and say they were sorry and that I was almost there, but frankly I was done. For the longest time I wondered if it was just my inner weakness or something wrong with me. Maybe. But I also think the whole process was designed to allow a certain person through and I wasn't it.

So, how does this relate to technical interviews?

First, technical interviews don't tend to have candidates sit stony-faced while they tell jokes and then dole out pushups for infractions. But they do tend to be stressful, and they favor a certain candidate. The ones that propose a candidate figure out a number of math problems make the assumption that the candidate is proficient at math. The ones use word problems assume that the candidate is familiar with the terminology and can translate that terminology into a solution. The ones that require a candidate to write some simple code up on a whiteboard assume the candidate is comfortable enough in whatever language to forego such modern conveniences as syntax highlighting, syntax checking, and other IDE aids (not to mention being able to forego keyboard memory and use a dry-erase marker).

In many ways technical interviews are nothing more than ways to put a candidate out of their comfort zone and see how they perform under pressure. Which is great if your job demands it. However I would argue that timed tests, whiteboard challenges, and logic problems don't actually test for how good a programmer is; they only test for how well a programmer has practiced those sorts of challenges.

I once went to a store-front dojo to look at some Karate classes. I was given a tour of the facility by one of the upper-level students and we ended up in the sparring area where folks were hitting bags and each other. During the demonstration of the various pieces of equipment he decided to test my reflexes (or something) by throwing a punch toward my face to see if I would flinch.

I didn't budge.

To be fair I'm not sure if I was just done with this experience or if I just hadn't noticed. But what I mustered was a withering look at him. Seriously? You're going to try to intimidate me and watch me jump. Fuck off! (I think this guy was trying to impress me, but as one of my old friends pointed out "you're stronger than you look", which I took as a compliment.) Also I juggle so having things whiz by my face is not uncommon, so perhaps that was another one of those "it's not going to hit me, so why bother moving for it?" situations.

I'm sure they were trying to impress me with their fast fists and how hard they could hit a bag, but in the end I realized it was all for show. That and my schedule wouldn't have accommodated it.

I came looking for discipline and a good time, and wound up being disillusioned with the whole ordeal.

So does this mean I'm a quitter? Does this mean that I'm just a big baby and need to toughen up a bit?


What I'd rather a technical interview do is show what the company does. Give examples that are close to real work. Rather than displaying a "you must be this clever to enter here" bar why not instead show me the part of your organization that I'm going to work with. Why not show me your hoariest bugs and let me see if I can have a go at them? Why not engage me in technical discussion and see what I am instead of seeing how I'm not like the next person?

I understand there's a sort of algorithmic cleanliness to using online testing to see if folks can make the grade. I understand hiring is difficult and these rubrics have worked for your other employees. But I also think you're making mono-cultures with this sort of testing, and when the real problems hit you'll be less likely to have different opinions.

Sure, shared hiring experiences can be fun to bond over, but wouldn't you rather bond over the difficult problems you've solved instead of that hoary ordeal you all went through to get hired? I know which ones I'd rather have.

Categories: LugNut Blogs

Have a blog? Use it

Craig Maloney - Fri, 09/22/2017 - 12:25

I just noticed some behavior on Twitter that I find rather revolting.

An author decided to post an entire blog-post's worth of material (as replies) to their Twitter stream.

Which under normal circumstances I can appreciate and relate. I've had ideas that were started on Twitter and because a series of @replies to myself. But that was because I was in the heat of the moment and was formulating these replies "in-the-moment". There was a pause in between each @reply.

Not this author. They literally had it set up where the entire posting was scheduled in such a way where my entire timeline was nothing but their post. Worse, it was still coming.


Why would you do this to your ostensible readers?

I'm assuming you, dear author, have a blog or some place where you can post these ideas. And if you, dear author, have such a platform then why the fuck didn't you use it and then use Twitter / other social medium to direct readers to that instead of using Twitter as your diuretic for pushing it out one tweetstorm at a time?

Seriously, Twitter is a shitty blog. Stop using it as such.

(Insert separate rant about not using RSS for your blog either).

Categories: LugNut Blogs

Interview Questions: Tell me about a project you are proud of and why?

Craig Maloney - Wed, 08/23/2017 - 12:15

An interview question I've received a lot during my interviewing is "Tell me about a project you are proud of and why are you proud of it". It's one of those "think about your career and tell me what one project stood out for you, and why it stands out" questions that feels like it is a good measure of interview candidates.

But one of the downsides is it's also a question that gets self-edited to the bits that I can show a potential employer.

At my last job I created a sort of "stylesheet for Excel" using openpyxl. Unfortunately the only thing I can show you is a gist that I posted to the openpyxl mailing list. The maintainer of the project didn't know what to do with it (and frankly I'm not sure the problem translated outside of the project that I was working on) but it worked and helped me style some pretty hoary spreadsheet reports.

But is that the project that I tell people about? Nope. Why? Because there isn't that much code there to show folks. And frankly it isn't an interesting story. "I made a configuration system to style Excel Spreadsheets so people could take these and pass along to our customers" isn't the sort of thing that excites people.

So what story do I tell? I tell them about the time when I created some photobooth software for a friend's wedding. He was getting married and wanted some more features for his Raspberry Pi project. Unfortunately it was taking longer than he anticipated so I wrote a new photobooth for him in Pygame. You can take a look at the code right now (Pygame Photobooth) and see what I did. Why am I proud of it? Because I helped out a friend during his time of need and it was cool to see people playing with it. It's still in use today.

That's a story! It has conflict! Drama! A climax! A happy ending! Exclamation points! And you can see the code!

Is it the project I'm most proud of? Possibly. There's a few other projects that I've done over the years that I can't show people. Projects like the system that completely automated mailing surveys for a customer. Projects that rewrote a Visual Basic system that was never going to work as written (and re-wrote it for the web). Projects like the imagemap that showed rooms that needed service.

But I can't show you the code that I wrote. You'll just have to take my word that they're awesome and made people happy. All of that code sits on disks behind firewalls; save for the little bit that I liberated on a mailing list.

And that's why you get the project that did make people happy; the project that made a friend's wedding all the better. Did it save the company money? Who cares? Did it surprise and delight the customer? I'd like to think so. Did it arrive on-time and under-budget? Well, they used it for their wedding so you tell me.

Questions like this favor people who can tell good stories about their projects. They also have a high bias towards projects where the person involved felt happiest while doing the project. They also tend to favor projects where the person can show you the code.

What about the times when the developer was on a death-march and everything was going wrong for them? What about the projects where the customer said "that's nice" and when the developer left the project died (that was the Visual Basic project that I worked on). What about the times when the developer didn't listen to management and took advantage of a brief window where they re-wrote the whole system and put it up on the web (That Visual Basic project again).

You're not going to get those stories out of an interview question like this. You're only going to get the highlight reel. And much like sports highlight reels you're going to get the stories that have the best visuals. You're going to get the ones that have the best stories to tell, with code that can be shared.

What are some of the stories that you have about developing projects?

Categories: LugNut Blogs

Facebook's React patent grant is disingenuous and harmful

Craig Maloney - Sun, 08/20/2017 - 15:34

I had some word-spew on Twitter about Facebook and their React.JS patent grant and decided to put it into a blog post:

Find it super interesting that the discussion about the React License has boiled down to resharing two Medium articles. The "Paper Tiger" and the "Startups should avoid React" articles. Depending on what you believe reflects which article gets reshared. Unfortunately I think both articles don't concentrate on the point of the patent exemption and why it's a real sticking point for developers and that's this: Facebook is trying to take their software and carve out a competitive edge in the software patent minefield. It's not that Facebook will steal your patents, or that Facebook will make you have to rewrite your software if they compete with you - It's that Facebook is taking a popular library / framework they wrote and are using it to deflect some of their legal pain. They're taking a nominally open source product of theirs and neutering patent lawsuits against Facebook (or at least diffusing them); giving folks pause about using their software patents because they could run afoul of a patent grant. I'm no fan of software patents (I think they're anathema to software development) but Facebook's Patent Grant does not solve the problem - it exacerbates the problems between intellectual property and intellectual freedom. It carves an exemption for Facebook alone. It's disingenuous of Facebook and creates a "I've got mine; sucks to be you" mentality that I find abhorrent in FL/OSS. This is not liberty.

Categories: LugNut Blogs

Raindrops puzzle on Exercism

Craig Maloney - Tue, 08/15/2017 - 11:28

One of the puzzles on Exercism is the Raindrops Puzzle. In this puzzle you find the numbers that divide into the original number (aka: factors). An example of this is the number 28 where 28 can be divided by the following numbers: 1, 2, 4, 7, 14, 28. (Remember that 1 divides into all numbers, and all numbers are divisible by themselves).

The challenge is to output one of the following:

  • If 3 is one of the numbers that are divisible by the original number then display "Pling"
  • If 5 is one of the numbers that are divisible by the original number then display "Plang"
  • If 7 is one of the numbers that are divisible by the original number then display "Plong"
  • If the number is not divisible by any of the above display the original number.

So in the case of 4 we factor that (1, 2, 4) and see that 3, 5, or 7 are not in those factors and display 4. For a number like 5 we note that (1, 5) are its factors and since 5 is in that set of factors we display "Plang". In the 28 example above we note that 7 is one of the numbers, and display "Plong".

Where it gets interesting is a number like 15. 15's factors are (1, 3, 5, 15). In this case we first check if the number 3 is one of the factors. 3 is present in the factors so we display "Pling". But note too that 5 is also one of the factors, so we also need to display "Plang". The correct output is "PlingPlang", and we display "PlingPlang" instead of the number 15.

With that in mind I started to attack the problem. This problem was part of the Scheme track so I started thinking how I'd approach this.

The first part was getting the factors out. That suggested "recursion" but my recursion is rusty. I knew that I could easily blow the stack with larger numbers so it would need to be tail-recursive. And that's about where my brain said "do you know how to write a tail-recursive routine because I sure don't?". So I checked Google and found a few examples (one of which lead me down figuring out how to use let to create a loop, so that was interesting).

Just for grins I wrote an iterative version in Python:

def factor(n): factors = [] for i in range(1, n+1): if (n % i == 0): factors.append(i) return factors def main(): print(factor(28)) print(factor(34)) if __name__ == "__main__": main()

Hmm, maybe I don't need recursion after all. This seems to be quick and does the trick. But is that Scheme? Scheme tends to favor recursion over looping (in my experience) so I needed a different approach, and with code that I could ultimately understand.

I found a Prime Decomposition in Scheme on Rosetta Code:

(define (factor number) (define (*factor divisor number) (if (> divisor number) (list number) (if (= (modulo number divisor) 0) (cons divisor (*factor divisor (/ number divisor))) (*factor (+ divisor 1) number)))) (*factor 2 number)) (display (factor 28)) (newline)

Ah, that sort of does what I want. I played with it a bit and came up with my own factorization algorithm / program:

(define (factor number) (define (*factor divisor number) (if (>= divisor number) (list number) (if (= (remainder number divisor) 0) (cons divisor (*factor (+ 1 divisor) number )) (*factor (+ divisor 1) number)))) (*factor 1 number)) (display (factor 28)) (newline)

They may look similar but the key difference is in the (cons divisor (*factor (+ 1 divisor) number )) line (and the (*factor 1 number) instead of 2 line). The original algorithm cut the space for searching in half (which is great if you're looking for primes). But in the case of 28 I wanted 2 * 14 = 28. I wanted 4 * 7 = 28 (7 being one of the factors that causes "Plong" to occur). Instead I got '(2 2 7 1) which sort-of-works, but isn't what I wanted. With the re-worked algorithm I got what I wanted:'(1 2 4 7 14 28).

Next came learning how to append strings in Scheme. That wasn't nearly as difficult as I thought it would be ((set! outstring (string-append outstring "Foo")), but what was slightly non-obvious to me was determining if an element is in the list.

Scheme has a function called memq which will find an element and return the rest of the list. So if I have a list '(1 2 3 4 5) and I want to see if 4 is in that list I can use (memq 4 '(1 2 3 4 5)) and get '(4 5) as the result. If I do the same for 6 ((memq 6 '(1 2 3 4 5))) I get back #f. In Scheme the presence of a list can be tested using if, so checking if we have a list or don't becomes (if (memq 3 factors) ...).

Appending a string in

Here's the completed code (and a link to comment on Exercism):

(define-module (raindrops) #:export (convert)) (define (factor number) (define (*factor divisor number) (if (>= divisor number) (list number) (if (= (remainder number divisor) 0) (cons divisor (*factor (+ 1 divisor) number )) (*factor (+ divisor 1) number)))) (*factor 1 number)) (define (convert number) (let ((outstring "") (factors (factor number))) (if (memq 3 factors) (set! outstring (string-append outstring "Pling"))) (if (memq 5 factors) (set! outstring (string-append outstring "Plang"))) (if (memq 7 factors) (set! outstring (string-append outstring "Plong"))) (if (string=? outstring "") (number->string number) outstring ) ) )
Categories: LugNut Blogs

100 day challenge: Final results

Craig Maloney - Sat, 08/12/2017 - 08:48

In the spirit of the 100 day challenge I wrote a quick program to parse the tags of the 100day challenge and note which tags were most often used.

#!/usr/bin/env python from collections import Counter def main(): tag_counter = Counter() with open('100day_tags', 'rt') as infile: for line in infile.readlines(): line = line.strip().lower() (filename, spacer, tag_string) = line.split(':') tags = [x.strip() for x in tag_string.split(',')] for tag in tags: tag_counter[tag] += 1 del tag_counter['a day in the life'] del tag_counter['100day'] for i in tag_counter.most_common(): print("{tag}: {counter}".format( tag=i[0], counter=i[1])) if __name__ == '__main__': main()

The tags are from a simple grep 100day *.md > ~/100day_tags command in my Pelican directory.

programming: 39 scheme: 29 racket: 16 javascript: 10 python: 5 godot: 3 guile: 3 pyohio: 2 css: 2 c: 1 html: 1 html5: 1

It looks like Scheme / Racket were the ones that got the most attention. After that is JavaScript, then some Python and a few mentions of Godot.

Not sure if this means anything in particular but it's interesting to me.

Categories: LugNut Blogs

Day 70ish/100: Fin?

Craig Maloney - Thu, 08/10/2017 - 22:30

Apparently this is the second time that I can't count, and have double-counted days.

It's also another day where "life has become rather chaotic and programming was the last thing on my mind".

So I'm thinking about calling this done for now. I'm not planning on abandoning daily programming for now. But putting it as part of the daily challenge? That's becoming a bit much.

That and I'm feeling guilty about not blogging about other things that are happening.

So, it's done for now. Won't say this is the last time this will happen, but frankly I think it's run its course.

Categories: LugNut Blogs

Day 69/100: More reading / more Exercism / Hacker Rank

Craig Maloney - Wed, 08/09/2017 - 22:28

Worked a little on Exercism today. One of the problems I was working on required the use of factoring a number to find all of the divisors (eg: 4 can be divided by 4, 2, and 1). It's a recursive solution but I didn't know offhand how to write it in Scheme (shameface) and looked one up online. That got me down a rabbithole of trying to figure out what the solution I found was doing. That lead to trying to figure out how the debugger in Guile worked, which lead me to try the debugger in DrRacket instead (pro-tip: The IDE debugger in Racket is quite good.).

I also played around a bit with HackerRank. Expect a blog post on why I think HackerRank has its heart in the right place but the implementation needs a lot of work.

Categories: LugNut Blogs

Day 68/100: Reading / Exercism

Craig Maloney - Tue, 08/08/2017 - 22:23

Did a quick play around with Exercism and some reading.

Here's my solution for RNA Transcription in Python:

def to_rna(dna): dna_rna_trans = {'G': 'C', 'C': 'G', 'T': 'A', 'A': 'U'} rna_strand = [] dna_list = list(dna) for dna_nucleotide in dna_list: if dna_nucleotide not in dna_rna_trans: return '' else: rna_strand.append(dna_rna_trans[dna_nucleotide]) return ''.join(rna_strand)
Categories: LugNut Blogs

Day 68/100: Off my game / Reading

Craig Maloney - Mon, 08/07/2017 - 23:23

Today I was pretty well off my game. Did a lot of administrative work for MUG and what-not, but didn't get to doing much programming. Hoping to rectify this tomorrow (before the MUG meeting. :) )

Did a little reading here and there. Did a little reading of the Guile Manual. Still love this manual.

Categories: LugNut Blogs

Day 67/100: ...

Craig Maloney - Sun, 08/06/2017 - 23:34


(Yes, not a lot happened today).

Categories: LugNut Blogs

Day 66/100: Just some reading

Craig Maloney - Sat, 08/05/2017 - 23:03

Did some more reading, but not a whole lot else.

Categories: LugNut Blogs

Day 65/100: More Godot

Craig Maloney - Fri, 08/04/2017 - 22:31

Today I watched a few introductory videos to learn more about Godot. The more I look at this engine the more I'm falling in love with it. I can't wait to put together and release a game with it. Thinking about doing a Kaboom-style game with it.

Categories: LugNut Blogs

Day 64/100: Pangram

Craig Maloney - Thu, 08/03/2017 - 22:12

Today I worked on the Pangram solution for Exercism. Didn't quite get an hour in programming today but close enough.

Categories: LugNut Blogs

Day 63/100: Off-by-one error?

Craig Maloney - Wed, 08/02/2017 - 23:26

I think I managed to have two day 59s. Not sure if this means something is screwed up but whatever. I'm willing to call it good if you are. ;)

Today I worked on the Exercism problem called "Bob". This was a hard problem for me but I think I managed it well.

Here's a link to my solution to the Bob problem.

Categories: LugNut Blogs

Day 62/100: Working on other things

Craig Maloney - Tue, 08/01/2017 - 23:06

Today I had a few other things to work on, so I didn't get to programming. More to come.

Categories: LugNut Blogs