Introduction
This is a portfolio of my projects (GitHub, Codeberg), presented in chronological order.
I provide comments on:
- What the project accomplishes
- When it was written
- How it functions
- And why it uses certain logic
Not all of my projects are discussed on this page. So stay tuned for more!
Summary
Jump to the project which interests you the most.
- jamesdavidson.xyz
- You are here!
- dotfiles
- Configuration files and scripts for Debian GNU/Linux systems
- Guild Wars 2 Pip Calculator
- Estimate the time it will take complete divisions in the World vs World game mode
- Hire Car Maintenance Inc
- A graphical user interface application for hire car companies
- Mastermind
- A code-breaking game for two players
- Map Symbols
- Match the Ordnance Survey map symbol shown to the corresponding button
jamesdavidson.xyz (2022-2024)
Synopsis
The project uses the Hugo static site generator.
The Gokarna theme is licensed under the GNU General Public License v3.0.
Content is licensed under the Creative Commons Attribution-NoDerivatives 4.0 International License. With the exception of the Linux Lab, which uses the GNU Free Documentation License, Version 1.3; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
Retrospective
Framework
I decided to use the Hugo framework for three reasons:
- To abstract away the design process
- Simplify content creation
- Adopt a mature platform (with good documentation)
A content management system such as WordPress is feature-rich, but complex. I don’t need a graphical user interface or WYSIWYG editor, only a theme. The fewer dependencies and less code complexity, the better.
Theme
I settled on Gokarna, a theme which is minimal, responsive and themeable.
I’m now a contributor to the project, seeing pull requests merged upstream:
- Increased Google Lighthouse score to 100 across all audits
- Re-wrote documentation for conciseness, and relevance to first-time users
- Containerised Python script for consistency, and CI/CD usage
… And introduced the following features:
- Programmatically add copyright notices to content
- Link to the next and previous blog post
- Bootstrap page metadata
Credits
Thanks to Yash Mehrotra and Avijit Gupta for developing Gokarna, and recognising my contributions in the README
.
dotfiles (2018-2021)
Synopsis
dotfiles was the latest incarnation of my ‘configuration files and scripts for Debian GNU/Linux systems’.
It was designed to accompany a network install of Debian with all tasksel
items de-selected.
The project encompasses two years of development in 2020 and 2021, though prior incarnations were available in 2018 and 2019 respectively.
It is licensed using the GNU Public Licence version 3 only.
Retrospective
dotfiles was discontinued after I moved from Debian to openSUSE Tumbleweed.
dotfiles was a moving target throughout development, as I changed tools, improved my understanding of the operating system, best practices within it, et cetera.
Branching
I learned to use three types of branches for dotfiles: main, development, and <feature>.
main
Once a milestone had been met, and the files had been tested, a release would be tagged. The tag would then be pushed to main.
development
Add complete features (see below) and bug fixes as atomic commits, ensuring they are trivial to revert.
<feature>
Features were merged into the development branch using the
--squash
option.In the past, I had experienced broken files after committing incomplete features to the development branch. This was problematic, as I lived on the development branch.
Adopting feature branches largely cured this faux pas.
Code quality
I endeavoured to make files easy to understand, portable across machines, and use programmatic logic.
As a case study, I will refer to this Polybar launch script from the ArchWiki.
The script performs a naive check to see if the polybar
process has been killed:
# Terminate already running bar instances
killall -q polybar
# Wait until the processes have been shut down
while pgrep -u $UID -x polybar >/dev/null; do sleep 1; done
What does this script do, and how can it be improved?
- Perform a command to search for the string
polybar
amongst processes running on the system- Use a bash-specific variable to check that the process was launched by the current user
- If the command exits successfully (i.e. the process is still running), wait for one second before issuing the same command again
- When the command eventually fails, assume that this means the string was not found, and that
polybar
is no longer running
if pgrep --euid "$(id --user --name)" --exact polybar
then
# Kill existing polybar processes
killall --quiet polybar
# Wait for the processes to die
wait $!
fi
- Improve readability by using GNU long options
- Check the user id by using a POSIX-compliant command
- Programmatically wait for the previous command to finish executing
Using the wait
built-in solves the problems present in the do-while
loop. The if
statement can be exited immediately, and there is no reliance on nebulous parsing of another program’s output.
There are many reasons not to parse human-readable output to a script, for example if pgrep
:
- Experiences API or ABI changes
- Is not installed on the system
- Has been modified by the distribution maintainer
Credits
dotfiles was integral to my learning process for GNU/Linux.
I’m grateful to every single person who collaborated on the documentation I scoured to make dotfiles better.
Guild Wars 2 Pip Calculator (2018)
Synopsis
For context, Guild Wars 2 is a Massively Multiplayer Online Roleplaying Game (MMORPG).
A reward system was introduced to the game, which awarded the player with ‘pips’ at five-minute intervals. The more pips a player receives per interval, the faster they can complete a reward tier.
In real-time, the calculator estimates how long it would take a player to complete reward tiers.
I was motivated to develop the tool as:
I wanted to use the functionality, and be able to share it with friends
It turns out that doing these calculations manually is boring. Who knew?
A similar tool had not yet been publicly announced
The project had its first commit in September 2018, though it was functional from an earlier date.
Since that time, at least two comparable tools have been made available. See the Guild Wars 2 Wiki and LimitlessFX.
Much like Map Symbols, this project was written using HTML, CSS and JavaScript.
It is licensed using the Apache License 2.0.
Demonstration
Try it, directly in the browser.
Calculate Pips |
---|
Retrospective
Appearance
Pip Calculator is functional, but not beautiful.
It is naively responsive, using the viewport
meta tag, and max-width
body property.
Functionality
The user enters a number of pips, optionally selects a tier to stop at, and is presented with the results.
Input is sanitised:
isNumberKey()
: The keys pressed must be between 0 and 9isNumberAllowed()
: The value must be between 3 and 19
To ensure hours and minutes are displayed with or without plurals as appropriate, the getCaseSwitch()
function is used to determine which strings should be used, using the values of hours
and minutes
.
Flaws
The total time given is not equal to the additive time of each tier.
Tiers are presented with floored hours and rounded minutes. However, the decimal values of each tier are retained when adding timeToTier
to totalTime
.
Only after every tier is calculated does totalTime
have its hours floored and minutes rounded. This results in the total time being longer.
Credits
After playing Guild Wars 2 for thousands of hours, I have something to show for it professionally. Thanks, ArenaNet!
Hire Car Maintenance Inc (2017/18)
Synopsis
Written in the 2017/18 academic year, using C# and .NET WinForms.
Hire Car Maintenance Inc serves as an introduction to object-oriented programming.
It is licensed using the Apache License 2.0.
Retrospective
input.txt
is parsed to create classes and objects at runtime. Changes made using the interface are saved persistently.
The interface was designed using Windows Forms Designer.
As seen above, the user is able to:
- Search for companies and cars
- Add, remove or edit companies and cars
Credits
Once again, I had the pleasure of learning from Liz Stuart.
Mastermind (2017/18)
Synopsis
Written in the 2017/18 academic year using C#. Compatible with .NET and Mono.
Mastermind is a code-breaking game for two players.
It is licensed using the Apache License 2.0.
Retrospective
There were two stipulations for the design of this project:
- Write a console application, not a graphical user interface
- Avoid features of C# which are not available in C
The user defines the number of positions and colours, then plays against a randomly generated pattern.
The program is resilient to input errors, checking whether values are numeric and within bounds.
The code was developed under the scrutiny of the module leader, who defined what functionality was and was not acceptable. As a result, some C-specific code and quirks are used.
Map Symbols (2016)
Synopsis
My first project, written in the Autumn semester of the 2016/17 academic year. It employs HTML, CSS and JavaScript.
The goal of the game is to match the Ordnance Survey map symbol shown to the corresponding button.
It is licensed using the Apache License 2.0.
Demonstration
Why not play from the browser and see for yourself?
Play Map Symbols |
---|
Retrospective
To win the game, the user must have five correct answers on the scoreboard.
The symbol shown must be pseudo-randomly generated
The
Math.Random()
function is used to assign a number between1
and10
toNum
, which is used to select a symbol fromimgArray
.To avoid a symbol being repeated immediately, the value of
Num
is assigned toPreviousNum
. If the values in both variables are equal,RandNum()
assigns a new number toNum
, untilNum
andPreviousNum
are no longer equal.A star must be “turned on” when a correct answer is given
A new game begins with all five stars “turned off”. The game is won when they are all “turned on”.
Each button fires an
onClick()
event to theCheckAnswer()
function, which passes theid
variable.The values of
id
andNum
are compared:- If they are equal, the answer is correct
- Else, the answer is incorrect
A corresponding sound and message should be used whenever an answer is given
Example of a correct answer:
Example of an incorrect answer:
The sound functionality was provided by the deprecated
<bgsound>
element, but now uses the modern<audio>
element to emulate the same behaviour.
Credits
The respective module was taught by Mark Dixon and Liz Stuart, whose approach to teaching made learning to program a joy.