This implementation could probably be more efficient, but I opted for clarity and simplicity where possible.