Hello, my name is Tim Parsons.


I am a software engineer that is currently employed by the Naval Information Warfare Center (NIWC).

I went to Clemson University and graduated with a bachelors of science in Computer Engineering in 2018. You can view my resume by clicking the link in the top right corner.

Clemson Paw



After seeing a bunch of homelab builds at /r/Homelab, I was inspired to make my own. Two months later, I finished making own homelab, which is still my heating system for my bedroom today.

Grafana Dashboard

Network Diagram

Network Topology

After a couple of weeks of researching the network topology diagram to the left is what I came up with (made with draw.io).

My main goal was to have my PC, the FreeNAS server, and the virtualization playground (labeled as ESXi playground) separate from one another and connected by a switch.

One of my early desires was to have a 10GbE network. It would have been cool, but I would have had to buy a new network card for my PC, the Dell servers, and each NUC. In addition, at least with the NUC models I purchased, a 1kΩ resistor needed to be soldered at some link for 10GbE to work properly.

With the risk of failure and the investment needed for 10GbE, I decided to stick with 1GbE.

Makeshift Rack

All of the equipment I either got on eBay or Amazon. One tool I found very useful when looking for servers is LabGopher. Once everything came in, I made custom-length Cat 5e cables and got to work.

Since the only rackable equipment I purchased are the Dell servers, I decided to not look for a small dedicated rack. When I visited my parents over Thanksgiving, my Dad had a spare wooden box that ended up working pretty well.

There are only two enhancements I made to the box. The first are wireless RGB lights that are mounted to the ceiling of the inside of the box to give it lighting source. The second are couple of holes (1-in diameter) that were drilled to make cable management easier.



Platforms and Services

This is the best part of the homelab. The R420 and NUCs combine to form a Proxmox cluster. A pfSense, Minecraft, Grafana, Plex, OpenVPN, and PiHole server are running on separate VM's in this cluster.

The PiHole VM is unfortunately non-functional (for now), as it is not possible disable the DHCP server running on my ISP's router.

Lastly, the R320 is running FreeNAS on baremetal. There were two reason for doing this: countless issues of people running into HBA issues while virtualizing, and to keep the server active if I decide to shutdown the Proxmox cluster.

Future Implementations

While I currently use Proxmox for virtualization, I would like to eventually switch to VMware. I would use the VMware User's Group license (VMUG) so that I can get all the enterprise capabilities that VMware provides. For now though, I'll stick with Proxmox as it fulfills my current needs.

A more attainable goal would be to get Kubernetes integrated into the stack. My plans would be to stick it onto a Debian 10 VM and go from there. Problem again though is that Proxmox VE already has LXC management capabilities.

Future Plans

Casual Programming Problems

This section is dedicated to Leetcode, HackerRank, and Advent of Code problems that I've found interesting. A majority of these problems are solved with Python (and sometimes C).

Invert Binary Tree

Binary Tree Recursion

I added this problem due to its popularity in the IT community. It is known for being asked in interviews. At first, it sounds a little bit daunting, especially if you haven't touched up on binary trees recently. Figure 1 illustrates what it means to invert a binary tree.

Though it might seem tough, the answer is surprisngly simple (though it's easy to say that after you see the answer to any question, right?). It can be solved with a for-loop or recursion. Figure 2 is my implementation written in C.

Invert Binary Tree visualization

Figure 1: Invert Binary Tree visualization

The main idea is to continue traversing a node until the node we are passed is NULL or None. While the node is valid, we simply swap the left and right children, and then call our recursive function on both of those nodes.

Invert Binary Tree in C

Figure 2: Implementation in C

Coin Change

Dynamic Programming Memoization

Coin Change is one of my favorite problems. It requires dynamic programming (DP) and memoization to solve it in a realistic amount of time. It's a great problem for training your brain to use recursion to solve subproblems.

There is an excellent article that has the visualization in Figure 1 of how the coins should be widdled down, with a subproblem spawning from each iteration. At the start of a new iteration, a check is made to see if the same scenario is already in the memo so that repetitive subproblems can be dealt with efficiently.

Coin Change visualization

Figure 1: Problem Breakdown and Subproblem Example

There are two constraints of this problem that stood out to me: the first being that there can be an infinite amount of types of coins, and the second being to remember the previous work we've done. These two facets point towards using DP and memoization, respectively. In Figure 1, the two circled portions are the exact same subproblem. Memoizing the value of that subproblem would drastically speed up search results.

Figure 2 illustrates why memoizing is so important. In this specific test case, there are 15 billion different ways the change can be split. Without memoizing, there is no telling how slow this test case would have taken to finish executing. Not only that, but this is just one of the 30 or so test cases on HackerRank, so having a flexible and robust solution is definitely needed to pass every test case. Figure 3 is my Python implementation of the recursive function. You'll notice that the memo is passed into every subproblem so we can keep up with which subproblems he have covered.

Example Test Case

Figure 2: Example Test Case

Python Code Solution

Figure 3: Python Code Solution

AoC: Day 6

Dynamic Programming Memoization

One of my favorite AoC problems this year. This problem is not dependent on any of the previous problems that have come out in 2019, so I decided to post it since the explanation won't be so drawn out. For both parts of this problem, one approach to is with memoization and dynamic programming, which is what I'll be using.

Part 1

For both parts of this problem, one approach to is with memoization and dynamic programming. For the first part, one can see in Figure 1 that two hashmaps are made: one for storing {orbiting planet : central planet}, and the other storing {orbiting planet : distance to central planet}.

The next step is to establish a basic recursive function that will traverse the planets. While traversing, the distance to each planet will be recorded, and the memo will be used so that it does not need to traverse to the COM planet every single time. If implemented correctly, findind the

Part 2

Unfortunately, a bit of refactoring needed to be done to make my previous code to work for part 2. The distanceToCom function is still used, but a bit more of tweeking needed to be done to get the distance between two planets. Figure 2 shows the extra code added/modified.

The gist of the second part was to get the total distance from COM for both planets, find their furthest shared central planet, and then subtract the distance difference between the two. I wish I had a more flexible implementation in part 1 for this, but in the end it worked out fine.

Part 1 Python Implementation

Figure 1: Part 1 Python Code

Part 2 Python Implementation

Figure 2: Part 2 Python Code


Dynamic Programming Memoization

Solving for the nth Fibonacci number is one of the most popular recursion problems. There are a few of ways that I want to approach this problem: brute force, memoization, and with the LRU cache Python decorator.

Figure 1 illustrates the three methods I previously mentioned. The LRU caching method is probably the easiest to understand. It will detect if there are subproblems that it can store (memoization) when the function is called recursively. It should be as fast as the hard-coded memoized approach.

The second function in Figure 1 uses hard-coded memoization to find the nth Fibonacci number. This is very similar to the standard brute force method, but there is a hash map saving our previously computed subproblems.

The third function is the standard brute force method. There isn't anything special about it, and it is insanely inefficient. One can see in Figure 2 the results of calling these for finding the 40th Fibonacci number (in seconds). Both the LRU cache and memoization method are magnitudes faster than the brute force method. This makes since due to the nature of the problem calling the same subproblems so many times.

LRU Cache, Memoization, and Brute Force Approaches

Figure 1: LRU Cache, Memoization, and Brute Force Approaches

Results of When Finding the 40th Fibonacci Number

Figure 2: Results of Figure 1 When Finding the 40th Fibonacci Number

Mouse Macros

Growing up, I have played my fair share of video games. In particular, the RPG genre is one I find myself playing time and time again. One common theme of these types of games is the need for repetitive actions. Whether it's 10 actions or 10,000 actions, my inner engineer screams at me to automate.

There is one RPG in particular that I have spent a large amount of time playing. I will not specify its name as automating game clicks and/or macroing is against the rules of the game. My itch to automate and the challenge of doing so without getting caught and banned led me to building macroing tools to do things for me in the game. Each of these tools were built using C#.

Simple Mouse Clicker

Its name describes exactly what it does - simple mouse clicking. This is the most trivial of the macro tools I made, and yet one of the tools I use the most. This program only works for activites in the game where I need to click in one spot every so often.

What makes this different from a standard auto mouse clicker are two things: the ability to set a random range to click in, and a built-in randomness in between MOUSEDOWN and MOUSEUP events. The random number that is generated for both of these features is pulled from the System.Security.Cryptography library to ensure better randomness over the built-in random() function.

Simple Mouse Clicker

Color Clicker

This program is a little bit more involved than the standard simple mouse clicker above. This was used in the scenarios where I was unsure of the random interval required or if the room for error in the game was smaller. This program will poll for when a certain amount of pixels around the cursor are a certain RGB value. When the requirement meets the settings specified in the GUI, then the program will click.

As the complexity of the program increases, so does the customizability. This program uses the same cryptographic library mentioned before to pull better random numbers for the MOUSEDOWN and MOUSEUP events. One can also manage the timing offsets and delays, the color thresholds and offsets, and clicks to perform.

This is the program I have used the least, as the amount of scenarios that fit perfectly for it are very few. However, it has worked very well in those rare cases.

Color Clicker

Record Player

This is the most in-depth and customizable program that I made for macroing. Put simply, it's a mouse recorder that also provides the user the ability to add multiple layers of randomness to their recordings.

This program will play until it runs for a certain period of time or until it plays a certain amount of recordings. Users can scale and manipulate the mouse movement, mouse click, and key clicking speeds of a recording (ex. 0.9-1.6x). In addition, delays can be added in-between records, and the records can be played in a random order.

Users have the ability to save their recordings. This aids in a quicker setup of the program. Records are saved as a .RPRECORD file. Mouse clicks, movements, keyboard key clicks, and the respective timing of each are stored in plain text. This allows one to do their own low-level editting to tune a recording to their liking.

The ability to incorporate mouse clicks, movements, and keyboard key clicks allows this tool to solve many different problems. It is no coincidence that it is the macro tool that I have used the most.

Record Player