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)

An aerial photograph of Gokarna's Paradise Beach, taken during the daytime. Beachgoers and boats can be seen amongst rocks, trees, and sand.

Photo by Raman Choudhary on Unsplash

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.

View the source code.

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)

Artwork depicting the Linux mascot, Tux

Tux Flat is licensed under the GNU General Public License v2.0 or later.

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.

View the source code.

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)

A screenshot of Guild Wars 2, depicting three player characters

© 2021 NCSOFT Corporation. All rights reserved. NCSOFT, ArenaNet, the interlocking NC logo, Aion, Lineage II, Guild Wars, Guild Wars 2: Heart of Thorns, Guild Wars 2: Path of Fire, Blade & Soul, and all associated logos, designs, and composite marks are trademarks or registered trademarks of NCSOFT Corporation. All other trademarks are the property of their respective owners.

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:

  1. 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?

  2. 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.

View the source code.

Demonstration

Try it, directly in the browser.

Calculate Pips
Screenshot of the Pip Calculator

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 9
  • isNumberAllowed(): 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)

An Avis hire car parked on a road near water and snowy Norweigan mountains.

Photo by Abhishek Umrao on Unsplash

Synopsis

Written in the 2017/18 academic year, using C# and .NET WinForms.

View the source code.

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.

Screenshot demonstration of Hire Car Maintenance Inc

As seen above, the user is able to:

  • Search for companies and cars
  • Add, remove or edit companies and cars

Screenshot demonstration of the search bar functionality in Hire Car Maintenance Inc

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.

View the source code.

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

Screenshot demonstration of playing Mastermind

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)

Photograph depicting Ordnance Survey maps

Photo by Drew Collins on Unsplash

Synopsis

My first project, written in the Autumn semester of the 2016/17 academic year. It employs HTML, CSS and JavaScript.

View the source code.

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
Screenshot demonstration of 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 between 1 and 10 to Num, which is used to select a symbol from imgArray.

    To avoid a symbol being repeated immediately, the value of Num is assigned to PreviousNum. If the values in both variables are equal, RandNum() assigns a new number to Num, until Num and PreviousNum 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 the CheckAnswer() function, which passes the id variable.

    The values of id and Num 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:

    The message “Well done!” is displayed

    Example of an incorrect answer:

    The message “The correct answer is…” is displayed

    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.