Portfolio

I’ve written a number of programs. Most of them have been for my own use. Here are some samples of my coding ability. Of course, I own the rights to distribute all of these projects.

Contents

Applications and System Administration Tools

Sleep Inhibitor

Language

Python 3

Type

Application

Description

Some time ago, the Ubuntu developers decided that all machines should automatically sleep after a given timeout, and this wasn’t made configurable. So, I found a sleep inhibitor app called Caffeine which runs an AppIndicator to control whether sleep is permitted or not. However, the author of that app decided to change it so that it only prevents sleep when an app is running in fullscreen mode and to remove all other functionality. Frustrated, I decided to write my own.

This indicator is simple: You can toggle whether the computer is allowed to sleep or not and you can determine what happens when running on battery. It’s manually controlled because automatic tools can’t read my mind and know what I want them to do.

Compatibility

This app needs a somewhat modern *NIX system with a recent-ish GTK, python-appindicator3 and running a graphical display. It also depends on xdotool and xprintidle. I’ve only tested it on Ubuntu.

View the code

Sleep Inhibitor

tn (SSH Server Manager)

Language

Ruby

Type

Application

Description

This tool makes it quick and easy to use SSH and SCP commands with multiple hosts, particularly if those hosts have long names or hostname and/or username details are difficult to remember or cumbersome to type.

Once configured, each hostname will have a user-chosen abbreviation, and one host can optionally be declared to be default, allowing it to be omitted altogether. Any additional options to be passed to ssh or scp can be specified and will be passed along. The configuration file allows for options to be passed by default to all hosts.

Examples

Using tn:

# Establishes an SSH connection to the default host
tn

# Establishes an SSH connection to the host with the abbreviation “foo”.
tn foo

# Uses SCP to transfer the file “foo” to the default directory of the
# default host
tn scp foo __HOST__:

For documentation, run tn --help. You’ll first get instructions for setting up the config file. Once that’s done, run tn --help again for usage instructions.

Of my system administration tools, this is the one that I use the most.

Compatibility

This tool depends on a system with OpenSSH installed. It might not work well outside of a UNIX-like environment.

View the code

tn

Network Monitor

Language

Python

Type

Application

Description

At various times, I’ve had to use unreliable network hardware that I had no way of fixing or replacing. I created this tool to monitor the network and give a visual and audible alert when the network went down so I could take manual corrective action.

Network Monitor was originally a series of Bash scripts. However, when I needed to make it work in Windows, I decided to port it to Python, clean it up, add some features, and make it more general.

To use it, open a terminal and simply run network_monitor.py. For help, you can pass the --help option. For code documentation, see the source or import it into an interactive Python 3 session and run help(network_monitor).

Compatibility

This program requires Python 3. It has been tested on Ubuntu Linux and Windows 7 and 10. I presume it will work on MacOS, but I haven’t tested it.

View the code

network_monitor.py

Font Lister: A Tool for Synchronizing Fonts Installed on Different Ubuntu Machines

Language

Python

Type

Utility

Description

Consider the following scenario: You have multiple Ubuntu machines (other OSes that use the APT package management system might work as well, but they haven’t been tested). You need to have a common set of fonts on all the machines and you want each machine to have every font installed on at least one other machine. Furthermore, each machine has write access to a common shared directory.

If the above scenario describes your situation, then this tool can help. Using it is a two-step process:

  1. Invoke this tool on each machine, passing the --write option and a target directory (which will be created if it doesn’t exist). The best target is one that all the machines concerned can write to. This will produce a file in the target directory named after the machine’s hostname which contains a list of all the font packages installed on the system (except for a few; see the source for details).

  2. Invoke this tool a second time on each machine, passing the --read option. It will print a list of font packages that need to be installed in order to bring the machine up to date. The easiest way to do this is to make the output the input to apt-get. See the example below.

Example

This example assumes the following:

  • Each machine is accessible via SSH
  • font_lister.py is already available on each machine’s $PATH
  • The common shared directory is available to each machine on the path /media/shared/font_lister
  • The machine hostnames are foo, bar, and baz

You might throw together a Bash script similar to the following:

#!/bin/bash
machines="foo bar baz"
for i in $machines; do
  ssh "$i" font_lister.py --write /media/shared/font_lister
done
for i in $machines; do
  ssh "$i" 'bash -c "sudo apt-get install $(font_lister.py --read /media/shared/font_lister)"'
done

Compatibility

This program has only been tested with Python 2. It will not work without modification in Python 3. Also, in case it wasn’t already clear from the description, this tool requires an OS that uses APT package management. It has only been tested in Ubuntu.

View the code

font_lister.py

Toggle Swap

Language

Bash shell script

Type

Utility

Description

Consider this scenario: You’ve been using all your RAM and a lot of your swap. For me, this frequently happens on old systems. Then, you quit some of the memory-hungry programs. Eventually, Linux will move stuff from swap into RAM as it’s accessed. However, if you also have a slow disk, you can experience ongoing slowdowns as the system slowly moves data from swap into the now-available RAM. I’ve often preferred to pay the performance penalty all at once at a time of my choosing, since the system’s automatic swap management isn’t always optimal for my purposes.

Of course, the way to do this is to run sudo swapoff -a; sudo swapon -a. The problem here is that if there’s insufficient free RAM, doing so will cause all sorts of problems and leave the system unresponsive.

I’ve written a script that I call toggle_swap that has worked for me for years. It checks for enough free RAM before actually disabling the swap. (As I was writing the script, I found that determining whether there was sufficient free RAM was more involved than simply running free.) Although I wrote it a long time ago, I still use it whenever the need arises.

Caveats

This is a script written for my own use which assumes a certain amount of knowledge. It’s certainly possible to defeat the script: Running it, then starting another memory-hungry program will defeat its safety checks. I haven’t made any attempt to address this, since I know not to do this.

Compatibility

I use this script on Ubuntu Linux. Though I haven’t tested it, I presume that it will work on just about any Linux system, and possibly many non-Linux *NIX systems, as well. As long as it has sudo, swapon, swapoff, and the standard *NIX tools, it should theoretically work.

View the code

toggle_swap

File Insurance

Language

Bash (shell)

Type

Utility

Description

These scripts were written in response to a serious bug in a piece of software I once used extensively. The program would occasionally crash while saving. The crashes would irrecoverably corrupt the files being saved, resulting in total data loss. Bug reports to the developer weren’t addressed. At that time, I didn’t have a continuous backup system, so after losing important data one time too many, I whipped up these scripts.

  • file-insurance monitors a PID and one or more files. Every 5 minutes until the PID terminates, it makes a copy of the files it is monitoring and timestamps them. If the copy is identical to the most recent one, it is discarded. Call it with --help for usage instructions.

  • file-insurance-cleanup is intended to be run manually once it is known that all is well with the data. It deletes the backups created by file-insurance except the most recent one. Call it with --help for usage instructions.

  • start-program-with-file-insurance launches the program specified on the command line, passing it all filename arguments given. Then, it starts file-insurance and arranges for it to monitor those files.

Compatibility

This program is a Bash script. Therefore, it naturally depends on a system with Bash (such as Linux or MacOS). It also expects to be running in an XTerm-compatible terminal. Thus, Windows’ cmd.exe is unlikely to work.

View the code

file-insurance

Web Development Projects

Time Calculator

Language

Javascript (with HTML and CSS)

Type

Application

Description

Doing math with times isn’t as simple as doing math with regular numbers because times use a different base. Time Calculator simplifies this problem. It provides:

  • An intuitive, calculator-like interface
  • Support for multiple calculations
  • Limited support for multiplication and division (WARNING: Read the multiplication and division section of help before using those functions—or risk incorrect results.)
  • Memory functions
Interesting Tidbit

The first version of Time Calculator was written in Java back in 2000. I re-wrote it in Javascript in 2001 and posted it online. At that time, it was the only such calculator available (except for desktop applications that had to be downloaded and installed). Today, Time Calculator is no longer the only such tool, but it consistently ranks high in Google and in my opinion it is better than its competitors in terms of usability. It is by far the most popular page on this site.

Compatibility

Time Calculator works on every modern browser and OS combination I’ve tested. There are a few irregularities in some older browsers (especially Internet Explorer), but nothing that breaks the calculator.

View the code

Time Calculator

Student Records

Language

PHP using the CodeIgniter framework (with MySQL, Javascript, jQuery, and CSS)

Type

Application

Description

Student Records is a simple class records app. I created it out of dissatisfaction with my school’s paper-based records system, where the papers were a poor reflection of reality. It grew to provide an interface for all the classroom-management stuff I needed.

I wrote it in PHP and CodeIgniter because I needed to get it written quickly and writing a webapp seemed to be the fastest way considering my prior experience. And I really like the CodeIgniter framework, because the learning curve is much lower than any other competing framework I’ve evaluated.

See the README file in the source tarball for some important caveats.

Compatibility

This app is designed to run on the user’s local machine (not a remote server). However, that machine needs to have the following properly installed and configured:

  • PHP 5
  • Apache 2 with mod_rewrite and support for .htaccess files
  • MySQL 5

View the code

Student Records

Short Demos and Toys

Vigenère Cipher

Language

Ruby

Type

Library

Description

This is a library to implement the Vigenère Cipher. I wrote it for a programming contest where it was the winning entry.

It includes methods to encode, decode, set your own key, create a random key, and set text either by passing it in or reading it from a file. See the code comments for specifics.

If the library is executed directly, a demonstration will run.

Compatibility

If you want to use a random key, and you don’t supply a seed, this library depends on a UNIX-like system (such as Linux). If you don’t need that particular feature, you should be able to use any system with a Ruby 1.8 or 1.9 interpreter. This library is untested with Ruby 2.0.

View the code

vigenere.rb

Dice and Yahtzees

Language

Python

Type

Library

Description

After watching a video about the probability of rolling a yahtzee (all five dice have the same number) in a single roll, I decided to do my own experiments. I implemented fully featured classes for dice and cups, along with a couple of methods to find yahtzees.

This module isn’t really intended to be used as a standalone program. Instead, the canonical way to use it is interactively via the Python interactive command line. In the following example, a single-roll yahtzee of ones occurred after 1,415 rolls:

[user@host]$ python3
Python 3.4.0 (default, Jun 19 2015, 14:18:46)
[GCC 4.8.2] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import dice
>>> cup = dice.Cup(num=5)
>>> cup
[<4>, <5>, <2>, <6>, <4>]
>>> cup.roll_until_yahtzee()
(1415, [<1>, <1>, <1>, <1>, <1>])
>>>

Compatibility

This module is only compatible with Python 3. It will not work in prior versions.

View the code

dice.py

Sieve of Eratosthenes

Language

Python

Type

Library

Description

This is a module to implement the Sieve of Eratosthenes, an ancient algorithm for finding prime numbers. I wrote it just for fun.

There are three functions: one that lists all primes up to a given integer, one that tests whether a given integer is prime, and one that returns a given integer’s prime factors. The Python docstrings document the module.

If the library is executed directly, a demonstration will run.

Compatibility

This module has only been tested in Python 2. No attempt has been made to make it compatible with Python 3.

View the code

eratosthenes.py

Phone Number Word Finder

Language

Ruby

Type

Toy

Description

This is a little command-line tool to find words corresponding to a given phone number. For example, if your phone number is 832-3278, you can learn that you could give it out as 832-FAST or TEA-EAST, among other possibilities.

It is meant to run interactively from the command line. Help is available upon startup.

Compatibility

This module has only been tested in Ruby 1.9 on Ubuntu Linux. It will probably run fine on any system with Ruby 1.9, but the dictionary paths may need to be adjusted. For best results, the Ubuntu/Debian package scowl should be installed, though it isn’t essential.

View the code

phone-numbers.rb